318 lines
15 KiB
Go
318 lines
15 KiB
Go
package models
|
|
|
|
import (
|
|
"encoding/json"
|
|
"time"
|
|
)
|
|
|
|
const (
|
|
MCPTaskAgentProfileDefaultCurrentTask = "current_task"
|
|
MCPTaskAgentProfileDefaultWorkspaceDefault = "workspace_default"
|
|
LspStatusLocationToolbar = "toolbar"
|
|
LspStatusLocationStatusBar = "status_bar"
|
|
)
|
|
|
|
// NormalizeMCPTaskAgentProfileDefault returns the canonical MCP task agent
|
|
// profile default: workspace_default is accepted as-is, anything else is
|
|
// coerced to current_task.
|
|
func NormalizeMCPTaskAgentProfileDefault(value string) string {
|
|
if value == MCPTaskAgentProfileDefaultWorkspaceDefault {
|
|
return value
|
|
}
|
|
return MCPTaskAgentProfileDefaultCurrentTask
|
|
}
|
|
|
|
// NormalizeLspStatusLocation returns the canonical LSP status location:
|
|
// status_bar is accepted as-is, anything else is coerced to toolbar.
|
|
func NormalizeLspStatusLocation(value string) string {
|
|
if value == LspStatusLocationStatusBar {
|
|
return value
|
|
}
|
|
return LspStatusLocationToolbar
|
|
}
|
|
|
|
const (
|
|
StartupPageTaskOverview = "task_overview"
|
|
StartupPageLastTask = "last_task"
|
|
)
|
|
|
|
// NormalizeStartupPage returns the canonical startup page: last_task is
|
|
// accepted as-is, anything else is coerced to task_overview.
|
|
func NormalizeStartupPage(value string) string {
|
|
if value == StartupPageLastTask {
|
|
return value
|
|
}
|
|
return StartupPageTaskOverview
|
|
}
|
|
|
|
const (
|
|
LastSeenDisplayAbsolute = "absolute"
|
|
LastSeenDisplayRelative = "relative"
|
|
)
|
|
|
|
// NormalizeLastSeenDisplay returns the canonical last-seen display mode:
|
|
// relative is accepted as-is, anything else is coerced to absolute.
|
|
func NormalizeLastSeenDisplay(value string) string {
|
|
if value == LastSeenDisplayRelative {
|
|
return value
|
|
}
|
|
return LastSeenDisplayAbsolute
|
|
}
|
|
|
|
const (
|
|
// RoleAdmin unlocks user management and system settings mutation when
|
|
// authentication is enabled. It does NOT grant visibility into other
|
|
// users' workspaces (hard privacy isolation).
|
|
RoleAdmin = "admin"
|
|
// RoleMember is a regular authenticated user.
|
|
RoleMember = "member"
|
|
// RoleGuest reaches only workspaces it is an explicit member of. It is
|
|
// never assigned by migration; an admin grants it deliberately.
|
|
RoleGuest = "guest"
|
|
|
|
// StatusActive marks a user that may log in.
|
|
StatusActive = "active"
|
|
// StatusDisabled marks a user whose access is revoked; all sessions and
|
|
// API tokens are invalidated when this status is set.
|
|
StatusDisabled = "disabled"
|
|
)
|
|
|
|
// NormalizeRole returns the canonical org role. Admin and guest are accepted
|
|
// as-is; anything else (including empty and unknown values) becomes member,
|
|
// which is the role every pre-guest account already had.
|
|
func NormalizeRole(value string) string {
|
|
switch value {
|
|
case RoleAdmin:
|
|
return RoleAdmin
|
|
case RoleGuest:
|
|
return RoleGuest
|
|
default:
|
|
return RoleMember
|
|
}
|
|
}
|
|
|
|
type User struct {
|
|
ID string `json:"id"`
|
|
Email string `json:"email"`
|
|
DisplayName string `json:"display_name"`
|
|
Role string `json:"role"`
|
|
Status string `json:"status"`
|
|
// OrgID is the user's tenant. Empty means the account predates
|
|
// organizations or the tenancy migration has not run.
|
|
OrgID string `json:"org_id,omitempty"`
|
|
// IsOperator marks the instance operator tier: managing organizations,
|
|
// feature toggles and instance configuration. It grants NO access inside
|
|
// any organization, including the operator's own.
|
|
IsOperator bool `json:"is_operator,omitempty"`
|
|
CreatedAt time.Time `json:"created_at"`
|
|
UpdatedAt time.Time `json:"updated_at"`
|
|
}
|
|
|
|
type UserSettings struct {
|
|
UserID string `json:"user_id"`
|
|
WorkspaceID string `json:"workspace_id"`
|
|
KanbanViewMode string `json:"kanban_view_mode"`
|
|
StartupPage string `json:"startup_page"`
|
|
WorkflowFilterID string `json:"workflow_filter_id"`
|
|
RepositoryIDs []string `json:"repository_ids"`
|
|
TasksListSort string `json:"tasks_list_sort"`
|
|
TasksListGroup string `json:"tasks_list_group"`
|
|
TasksListShowDetails bool `json:"tasks_list_show_details"`
|
|
InitialSetupComplete bool `json:"initial_setup_complete"`
|
|
PreferredShell string `json:"preferred_shell"`
|
|
DefaultEditorID string `json:"default_editor_id"`
|
|
EnablePreviewOnClick bool `json:"enable_preview_on_click"`
|
|
ChatSubmitKey string `json:"chat_submit_key"` // "enter" | "cmd_enter"
|
|
ReviewAutoMarkOnScroll bool `json:"review_auto_mark_on_scroll"`
|
|
ConfirmTaskArchive bool `json:"confirm_task_archive"`
|
|
PreventAutoStartAgentOnOpen bool `json:"prevent_auto_start_agent_on_open"`
|
|
UnreadDivider bool `json:"unread_divider"`
|
|
AgentGeneratedTaskTitles bool `json:"agent_generated_task_titles"`
|
|
MCPTaskAgentProfileDefault string `json:"mcp_task_agent_profile_default"`
|
|
ShowAnchoredPromptBar bool `json:"show_anchored_prompt_bar"` // desktop-only sticky last-prompt bar
|
|
ShowScrollToLastPrompt bool `json:"show_scroll_to_last_prompt"`
|
|
ShowScrollToStart bool `json:"show_scroll_to_start"`
|
|
ShowTranscriptAutoScrollControl bool `json:"show_transcript_auto_scroll_control"`
|
|
ShowTodoListPanel bool `json:"show_todo_list_panel"`
|
|
ShowTodoListPanelOnlyWhenNotEmpty bool `json:"show_todo_list_panel_only_when_not_empty"`
|
|
ShowReleaseNotification bool `json:"show_release_notification"`
|
|
ReleaseNotesLastSeenVersion string `json:"release_notes_last_seen_version"`
|
|
LspAutoStartLanguages []string `json:"lsp_auto_start_languages"`
|
|
LspAutoInstallLanguages []string `json:"lsp_auto_install_languages"`
|
|
LspServerConfigs map[string]map[string]interface{} `json:"lsp_server_configs"`
|
|
LspStatusLocation string `json:"lsp_status_location"`
|
|
SavedLayouts []SavedLayout `json:"saved_layouts"`
|
|
SidebarViews []SidebarView `json:"sidebar_views"`
|
|
SidebarActiveViewID string `json:"sidebar_active_view_id"`
|
|
SidebarDraft *SidebarViewDraft `json:"sidebar_draft"`
|
|
ThreadViews []ThreadView `json:"thread_views"`
|
|
ThreadActiveViewID string `json:"thread_active_view_id"`
|
|
ThreadViewDraft *ThreadViewDraft `json:"thread_view_draft"`
|
|
SidebarTaskPrefs SidebarTaskPrefs `json:"sidebar_task_prefs"`
|
|
SidebarTaskColorAutomation SidebarTaskColorAutomation `json:"sidebar_task_color_automation"`
|
|
SidebarTaskColors map[string]*string `json:"sidebar_task_colors"`
|
|
TaskCreateLastUsed TaskCreateLastUsed `json:"task_create_last_used"`
|
|
JiraSavedViews json.RawMessage `json:"jira_saved_views"`
|
|
JiraTaskPresets json.RawMessage `json:"jira_task_presets"`
|
|
GitHubSavedPresets json.RawMessage `json:"github_saved_presets"`
|
|
GitHubDefaultQueryPresets json.RawMessage `json:"github_default_query_presets"`
|
|
GitLabSavedPresets json.RawMessage `json:"gitlab_saved_presets"`
|
|
AzureDevOpsBrowsePreferences json.RawMessage `json:"azure_devops_browse_preferences"`
|
|
DefaultUtilityAgentID string `json:"default_utility_agent_id"` // Default inference agent for utility agents
|
|
DefaultUtilityModel string `json:"default_utility_model"` // Default model for utility agents
|
|
DefaultUtilityAgentProfileID string `json:"default_utility_agent_profile_id"`
|
|
KeyboardShortcuts map[string]interface{} `json:"keyboard_shortcuts"` // User-configured keyboard shortcut overrides
|
|
TerminalLinkBehavior string `json:"terminal_link_behavior"` // "new_tab" | "browser_panel"
|
|
TerminalFontFamily string `json:"terminal_font_family"`
|
|
TerminalFontSize int `json:"terminal_font_size"`
|
|
ChangesPanelLayout string `json:"changes_panel_layout"` // "flat" | "tree"
|
|
LastSeenDisplay string `json:"last_seen_display"` // "absolute" | "relative"
|
|
SystemMetricsDisplay SystemMetricsDisplaySettings `json:"system_metrics_display"`
|
|
AppStatusBarEnabled bool `json:"app_status_bar_enabled"`
|
|
ResolveSessionHostnames bool `json:"resolve_session_hostnames"`
|
|
AppStatusBarOrder AppStatusBarOrder `json:"app_status_bar_order"`
|
|
QuickChatTabOrderByWorkspace map[string][]string `json:"quick_chat_tab_order_by_workspace"`
|
|
KanbanHiddenStepIDs map[string][]string `json:"kanban_hidden_step_ids"`
|
|
WorkflowIDsWithAutoHideEmptySteps []string `json:"workflow_ids_with_auto_hide_empty_steps"`
|
|
Revision int64 `json:"revision"`
|
|
CreatedAt time.Time `json:"created_at"`
|
|
UpdatedAt time.Time `json:"updated_at"`
|
|
}
|
|
|
|
type SystemMetricsDisplaySettings struct {
|
|
ShowInTopbar bool `json:"show_in_topbar"`
|
|
Simplified bool `json:"simplified"`
|
|
}
|
|
|
|
type AppStatusBarOrder struct {
|
|
LeftItemIDs []string `json:"left_item_ids"`
|
|
RightItemIDs []string `json:"right_item_ids"`
|
|
}
|
|
|
|
// SavedLayout represents a user-saved dockview layout configuration.
|
|
type SavedLayout struct {
|
|
ID string `json:"id"`
|
|
Name string `json:"name"`
|
|
IsDefault bool `json:"is_default"`
|
|
Layout json.RawMessage `json:"layout"`
|
|
CreatedAt string `json:"created_at"`
|
|
}
|
|
|
|
// SidebarView represents a user-saved sidebar filter/sort/group preset.
|
|
// The payload is stored and returned as-is; the server does not interpret
|
|
// clause values beyond passing them through.
|
|
type SidebarView struct {
|
|
ID string `json:"id"`
|
|
Name string `json:"name"`
|
|
Filters []SidebarViewClause `json:"filters"`
|
|
Sort SidebarViewSort `json:"sort"`
|
|
Group string `json:"group"`
|
|
CollapsedGroups []string `json:"collapsed_groups"`
|
|
TaskRow *SidebarTaskRowPresentation `json:"task_row,omitempty"`
|
|
}
|
|
|
|
type SidebarViewClause struct {
|
|
ID string `json:"id"`
|
|
Dimension string `json:"dimension"`
|
|
Op string `json:"op"`
|
|
Value json.RawMessage `json:"value"`
|
|
}
|
|
|
|
type SidebarViewSort struct {
|
|
Key string `json:"key"`
|
|
Direction string `json:"direction"`
|
|
}
|
|
|
|
type SidebarViewDraft struct {
|
|
BaseViewID string `json:"base_view_id"`
|
|
Filters []SidebarViewClause `json:"filters"`
|
|
Sort SidebarViewSort `json:"sort"`
|
|
Group string `json:"group"`
|
|
TaskRow *SidebarTaskRowPresentation `json:"task_row,omitempty"`
|
|
}
|
|
|
|
// SidebarTaskRowPresentation controls the optional metadata and trailing
|
|
// presentation for a task row in a saved sidebar view.
|
|
type SidebarTaskRowPresentation struct {
|
|
DetailsEnabled bool `json:"details_enabled"`
|
|
DetailOrder []string `json:"detail_order"`
|
|
VisibleDetails []string `json:"visible_details"`
|
|
Trailing string `json:"trailing"`
|
|
}
|
|
|
|
// DefaultSidebarTaskRowPresentation returns the presentation used by the
|
|
// original sidebar layout.
|
|
func DefaultSidebarTaskRowPresentation() *SidebarTaskRowPresentation {
|
|
return &SidebarTaskRowPresentation{
|
|
DetailsEnabled: true,
|
|
DetailOrder: []string{"relative_time", "repository", "pull_request_number"},
|
|
VisibleDetails: []string{"relative_time", "repository", "pull_request_number"},
|
|
Trailing: "git_changes",
|
|
}
|
|
}
|
|
|
|
type SidebarTaskPrefs struct {
|
|
PinnedTaskIDs []string `json:"pinned_task_ids"`
|
|
OrderedTaskIDs []string `json:"ordered_task_ids"`
|
|
SubtaskOrderByParentID map[string][]string `json:"subtask_order_by_parent_id"`
|
|
}
|
|
|
|
type TaskCreateLastUsed struct {
|
|
RepositoryID string `json:"repository_id"`
|
|
Branch string `json:"branch"`
|
|
AgentProfileID string `json:"agent_profile_id"`
|
|
ExecutorProfileID string `json:"executor_profile_id"`
|
|
WorkflowIDsByWorkspace map[string]string `json:"workflow_ids_by_workspace"`
|
|
}
|
|
|
|
// AgentProfileRecentUseContext identifies an operational selector whose
|
|
// profile order is remembered independently from user settings.
|
|
type AgentProfileRecentUseContext string
|
|
|
|
const (
|
|
AgentProfileRecentUseTaskCreate AgentProfileRecentUseContext = "task_create"
|
|
AgentProfileRecentUseTaskSession AgentProfileRecentUseContext = "task_session"
|
|
AgentProfileRecentUseQuickChat AgentProfileRecentUseContext = "quick_chat"
|
|
AgentProfileRecentUseConfigChat AgentProfileRecentUseContext = "config_chat"
|
|
)
|
|
|
|
const (
|
|
AgentProfileRecentUseMaxProfiles = 10
|
|
AgentProfileRecentUseMaxContexts = 4
|
|
AgentProfileRecentUseMaxProfileIDBytes = 255
|
|
)
|
|
|
|
// SupportedAgentProfileRecentUseContexts returns the closed set of contexts
|
|
// that may be persisted for a user.
|
|
func SupportedAgentProfileRecentUseContexts() []AgentProfileRecentUseContext {
|
|
return []AgentProfileRecentUseContext{
|
|
AgentProfileRecentUseTaskCreate,
|
|
AgentProfileRecentUseTaskSession,
|
|
AgentProfileRecentUseQuickChat,
|
|
AgentProfileRecentUseConfigChat,
|
|
}
|
|
}
|
|
|
|
// IsAgentProfileRecentUseContext reports whether context is supported.
|
|
func IsAgentProfileRecentUseContext(context AgentProfileRecentUseContext) bool {
|
|
switch context {
|
|
case AgentProfileRecentUseTaskCreate,
|
|
AgentProfileRecentUseTaskSession,
|
|
AgentProfileRecentUseQuickChat,
|
|
AgentProfileRecentUseConfigChat:
|
|
return true
|
|
default:
|
|
return false
|
|
}
|
|
}
|
|
|
|
// AgentProfileRecentUse is the persisted move-to-front history for one user
|
|
// and operational selector context.
|
|
type AgentProfileRecentUse struct {
|
|
UserID string `json:"user_id"`
|
|
Context AgentProfileRecentUseContext `json:"context"`
|
|
ProfileIDs []string `json:"profile_ids"`
|
|
Revision int64 `json:"revision"`
|
|
UpdatedAt time.Time `json:"updated_at"`
|
|
}
|