mirror of
https://github.com/stablyai/orca.git
synced 2026-10-31 00:57:45 +00:00
refactor(sources): row-less sources and host-less surfaces name their host (#27290)
* refactor(sources): row-less sources and host-less surfaces name their host Linear and Jira clients take a RowLessSource: a task-source context, an explicit host, or defaultScopeSource(settings) when no Tasks source is chosen, so raw settings no longer compile. defaultScopeHost joins defaultCreationHost as the second sanctioned reader of the default-host setting (both behind one private read, both ratchet seeds), and the status-bar account switchers, settings navigation and the settings host picker's initial default use it. Skill discovery routes by the owner id its install terminal resolves, and the workspace-board Linear sync by the workspace owner. * fix(lint): count the default scope source and assign-then-return readers defaultScopeSource is a sanctioned read of the default host, so its call sites count. A function that assigns a reader's result to a local and returns that local is a reader too, which keeps the skill-discovery hook counted. --------- Co-authored-by: m4air <m4air@Mac.localdomain>
This commit is contained in:
@@ -4,9 +4,12 @@
|
||||
# the default host, through defaultCreationHost. Everything else routes by the owner.
|
||||
# Prune after removing reads: pnpm check:owner-routing-ratchet --prune
|
||||
2 src/renderer/src/App.tsx
|
||||
3 src/renderer/src/app-shell/use-app-shell-services.ts
|
||||
5 src/renderer/src/app-shell/use-app-shell-services.ts
|
||||
9 src/renderer/src/components/JiraIssueWorkspace.tsx
|
||||
1 src/renderer/src/components/Landing.tsx
|
||||
1 src/renderer/src/components/LinearIssueWorkspace.tsx
|
||||
2 src/renderer/src/components/LinearIssueTextEditor.tsx
|
||||
3 src/renderer/src/components/LinearIssueWorkspace.tsx
|
||||
3 src/renderer/src/components/LinearItemDrawer.tsx
|
||||
1 src/renderer/src/components/NativeChatResumeOnRestartGroups.tsx
|
||||
1 src/renderer/src/components/activity/ActivityPrototypePage.tsx
|
||||
1 src/renderer/src/components/activity/activity-scope-filter-controls.tsx
|
||||
@@ -22,15 +25,27 @@
|
||||
1 src/renderer/src/components/automations/use-automations-page-destination-form.ts
|
||||
2 src/renderer/src/components/automations/use-automations-page-setup-state.ts
|
||||
1 src/renderer/src/components/browser-pane/ReopenBrowserPageOnServerButton.tsx
|
||||
1 src/renderer/src/components/browser-pane/assemble-chrome/browser-egress-indicator.tsx
|
||||
1 src/renderer/src/components/browser-pane/assemble-chrome/browser-page-viewport-overlays.tsx
|
||||
1 src/renderer/src/components/browser-pane/assemble-chrome/browser-workspace-pane.tsx
|
||||
1 src/renderer/src/components/browser-pane/assemble-chrome/ssh-routed-browser-page-gate.tsx
|
||||
1 src/renderer/src/components/browser-pane/browser-reopen-on-server.ts
|
||||
1 src/renderer/src/components/browser-pane/stream-remote/remote-browser-page-pane.tsx
|
||||
1 src/renderer/src/components/browser-pane/stream-remote/use-remote-browser-page-lifecycle.ts
|
||||
1 src/renderer/src/components/browser-pane/stream-remote/use-remote-browser-page-stream.ts
|
||||
1 src/renderer/src/components/browser-pane/stream-remote/use-remote-browser-stream-activation.ts
|
||||
2 src/renderer/src/components/browser-pane/use-ssh-workspace-browser-route.ts
|
||||
1 src/renderer/src/components/browser-pane/workspace-doc/HtmlDocPreview.tsx
|
||||
1 src/renderer/src/components/browser-pane/workspace-doc/doc-preview-document-actions.ts
|
||||
1 src/renderer/src/components/browser-pane/workspace-doc/workspace-doc-page-pane.tsx
|
||||
2 src/renderer/src/components/cmd-j/quick-action-context.ts
|
||||
2 src/renderer/src/components/dashboard/dashboard-card-terminal-input.ts
|
||||
1 src/renderer/src/components/dashboard/launch-dashboard-agent.ts
|
||||
1 src/renderer/src/components/dashboard/use-agent-row-conversation-name.ts
|
||||
2 src/renderer/src/components/editor/EditorContent.tsx
|
||||
1 src/renderer/src/components/editor/EditorDiffFileSurface.tsx
|
||||
1 src/renderer/src/components/editor/EditorEditFileSurface.tsx
|
||||
1 src/renderer/src/components/editor/EditorMarkdownFileSurface.tsx
|
||||
1 src/renderer/src/components/editor/MonacoGutterContextMenu.tsx
|
||||
1 src/renderer/src/components/editor/combined-diff/CombinedDiffViewer.tsx
|
||||
4 src/renderer/src/components/editor/combined-diff/load-sections/fetch-combined-diff-section.ts
|
||||
@@ -41,10 +56,11 @@
|
||||
1 src/renderer/src/components/editor/markdown-preview-link-actions.ts
|
||||
1 src/renderer/src/components/editor/markdown-preview-system-link-action.ts
|
||||
1 src/renderer/src/components/editor/restored-editor-workspace-runtime-owner.ts
|
||||
2 src/renderer/src/components/editor/rich-markdown-editor-click-routing.ts
|
||||
4 src/renderer/src/components/editor/useEditorPanelContentState.ts
|
||||
5 src/renderer/src/components/editor/useEditorPanelDiffContentLoader.ts
|
||||
1 src/renderer/src/components/editor/useEditorPanelFileContentLoader.ts
|
||||
1 src/renderer/src/components/editor/useMarkdownDocuments.ts
|
||||
2 src/renderer/src/components/editor/useMarkdownDocuments.ts
|
||||
2 src/renderer/src/components/feature-wall/ConnectIntegrationsList.tsx
|
||||
1 src/renderer/src/components/feature-wall/FeatureWallBrowserAction.tsx
|
||||
1 src/renderer/src/components/feature-wall/FeatureWallSetupChecklist.tsx
|
||||
@@ -54,27 +70,49 @@
|
||||
1 src/renderer/src/components/floating-terminal/use-floating-terminal-panel-controller.ts
|
||||
1 src/renderer/src/components/floating-terminal/use-floating-terminal-panel-store-state.ts
|
||||
1 src/renderer/src/components/jira-connect-dialog.tsx
|
||||
1 src/renderer/src/components/jira-user-picker.tsx
|
||||
1 src/renderer/src/components/landing-preflight-runtime.ts
|
||||
1 src/renderer/src/components/linear-api-key-dialog.tsx
|
||||
3 src/renderer/src/components/linear-issue-project-selector.tsx
|
||||
2 src/renderer/src/components/linear-issue-sub-issues.tsx
|
||||
2 src/renderer/src/components/linear-issue-workspace-detail-state.ts
|
||||
2 src/renderer/src/components/linear-item-drawer-comment-footer.tsx
|
||||
6 src/renderer/src/components/linear-item-drawer-edit-controller.tsx
|
||||
1 src/renderer/src/components/linear-item-drawer-edit-section.tsx
|
||||
2 src/renderer/src/components/native-chat-resume-modal.test-support.tsx
|
||||
1 src/renderer/src/components/native-chat-resume-tree.test-support.ts
|
||||
1 src/renderer/src/components/native-chat/NativeChatAgentMessageSenders.tsx
|
||||
1 src/renderer/src/components/native-chat/NativeChatComposer.tsx
|
||||
1 src/renderer/src/components/native-chat/NativeChatResolvedView.tsx
|
||||
1 src/renderer/src/components/native-chat/NativeChatVisualFrame.tsx
|
||||
1 src/renderer/src/components/native-chat/StructuredAgentSessionAttentionBridge.tsx
|
||||
1 src/renderer/src/components/native-chat/StructuredAgentSessionPaneOverlayLayer.tsx
|
||||
1 src/renderer/src/components/native-chat/StructuredAgentSessionStatusBridge.tsx
|
||||
5 src/renderer/src/components/native-chat/native-chat-agent-message-sender-label.ts
|
||||
2 src/renderer/src/components/native-chat/native-chat-attachment-upload.ts
|
||||
1 src/renderer/src/components/native-chat/native-chat-file-link.ts
|
||||
1 src/renderer/src/components/native-chat/native-chat-http-link-source-owner.ts
|
||||
3 src/renderer/src/components/native-chat/native-chat-http-link-source-owner.ts
|
||||
2 src/renderer/src/components/native-chat/native-chat-runtime-owner.ts
|
||||
2 src/renderer/src/components/native-chat/native-chat-session-option-discovery.ts
|
||||
1 src/renderer/src/components/native-chat/native-chat-skill-discovery-context.ts
|
||||
1 src/renderer/src/components/native-chat/use-native-chat-file-drops.ts
|
||||
1 src/renderer/src/components/native-chat/use-native-chat-link-actions.ts
|
||||
1 src/renderer/src/components/native-chat/use-native-chat-session-options.ts
|
||||
2 src/renderer/src/components/native-chat/use-native-chat-workspace-file-drop.ts
|
||||
1 src/renderer/src/components/new-workspace/use-jira-source-connection.ts
|
||||
2 src/renderer/src/components/new-workspace/use-linear-source-connection.ts
|
||||
1 src/renderer/src/components/new-workspace/use-smart-workspace-secondary-searches.ts
|
||||
4 src/renderer/src/components/new-workspace/use-linear-source-connection.ts
|
||||
1 src/renderer/src/components/new-workspace/use-smart-workspace-name-field-controller.ts
|
||||
2 src/renderer/src/components/new-workspace/use-smart-workspace-secondary-searches.ts
|
||||
2 src/renderer/src/components/new-workspace/use-work-item-source-foundation.ts
|
||||
1 src/renderer/src/components/new-workspace/use-work-item-source-search.ts
|
||||
1 src/renderer/src/components/quick-open-file-list-test-harness.ts
|
||||
3 src/renderer/src/components/repo/CreateFromPicker.tsx
|
||||
1 src/renderer/src/components/right-sidebar/ChecksPanel.tsx
|
||||
4 src/renderer/src/components/right-sidebar/ChecksPanel.tsx
|
||||
2 src/renderer/src/components/right-sidebar/FileExplorer.tsx
|
||||
1 src/renderer/src/components/right-sidebar/FileExplorerFilesTreePane.tsx
|
||||
1 src/renderer/src/components/right-sidebar/FolderWorkspacePrChecksRow.tsx
|
||||
1 src/renderer/src/components/right-sidebar/ai-vault-original-pane-actions.ts
|
||||
1 src/renderer/src/components/right-sidebar/ai-vault-session-resume-in-chat-workspace.ts
|
||||
3 src/renderer/src/components/right-sidebar/checks-panel-hosted-review-click-routing.ts
|
||||
1 src/renderer/src/components/right-sidebar/checks-panel/use-checks-panel-controller-state.tsx
|
||||
1 src/renderer/src/components/right-sidebar/checks-panel/use-checks-panel-create-review.tsx
|
||||
@@ -90,21 +128,24 @@
|
||||
2 src/renderer/src/components/right-sidebar/source-control/ai/use-ai.ts
|
||||
5 src/renderer/src/components/right-sidebar/source-control/commit/use-bulk-actions.ts
|
||||
1 src/renderer/src/components/right-sidebar/source-control/commit/use-commit-action.ts
|
||||
2 src/renderer/src/components/right-sidebar/source-control/commit/use-commit-flows.ts
|
||||
2 src/renderer/src/components/right-sidebar/source-control/commit/use-commit-message-generation.ts
|
||||
1 src/renderer/src/components/right-sidebar/source-control/commit/use-discard-confirmation.ts
|
||||
7 src/renderer/src/components/right-sidebar/source-control/commit/use-entry-mutations.ts
|
||||
1 src/renderer/src/components/right-sidebar/source-control/listing/entry-context-menu.tsx
|
||||
2 src/renderer/src/components/right-sidebar/source-control/listing/use-file-listing.ts
|
||||
3 src/renderer/src/components/right-sidebar/source-control/listing/use-file-listing.ts
|
||||
2 src/renderer/src/components/right-sidebar/source-control/listing/use-submodule-status.ts
|
||||
1 src/renderer/src/components/right-sidebar/source-control/listing/use-worktree-context.ts
|
||||
1 src/renderer/src/components/right-sidebar/source-control/panel/use-panel-foundation.ts
|
||||
2 src/renderer/src/components/right-sidebar/source-control/panel/use-panel-model.ts
|
||||
3 src/renderer/src/components/right-sidebar/source-control/panel/use-panel-model.ts
|
||||
2 src/renderer/src/components/right-sidebar/source-control/panel/use-panel-state.ts
|
||||
1 src/renderer/src/components/right-sidebar/source-control/review/create-pr-intent-run-snapshot.ts
|
||||
1 src/renderer/src/components/right-sidebar/source-control/review/use-create-pr-intent-commit-message.ts
|
||||
1 src/renderer/src/components/right-sidebar/source-control/review/use-create-pr-intent-flows.ts
|
||||
1 src/renderer/src/components/right-sidebar/source-control/review/use-create-pr-intent-probes.ts
|
||||
1 src/renderer/src/components/right-sidebar/source-control/review/use-create-pr-intent-review.ts
|
||||
2 src/renderer/src/components/right-sidebar/source-control/review/use-pull-request-generation.ts
|
||||
1 src/renderer/src/components/right-sidebar/source-control/review/use-review-flows.ts
|
||||
1 src/renderer/src/components/right-sidebar/source-control/sync/git-history-commit-context-menu.tsx
|
||||
1 src/renderer/src/components/right-sidebar/source-control/sync/use-base-ref-default.ts
|
||||
1 src/renderer/src/components/right-sidebar/source-control/sync/use-branch-compare.ts
|
||||
@@ -119,10 +160,11 @@
|
||||
1 src/renderer/src/components/right-sidebar/use-file-explorer-ignored-paths.ts
|
||||
2 src/renderer/src/components/right-sidebar/use-file-explorer-tree-pane-state.ts
|
||||
3 src/renderer/src/components/right-sidebar/use-git-status-upstream-ref-watch.ts
|
||||
1 src/renderer/src/components/right-sidebar/useCreatePullRequestDialogFields.ts
|
||||
4 src/renderer/src/components/right-sidebar/useFileSearchPanel.ts
|
||||
1 src/renderer/src/components/right-sidebar/useFileSearchRunner.ts
|
||||
1 src/renderer/src/components/right-sidebar/useFileSearchScope.ts
|
||||
2 src/renderer/src/components/right-sidebar/useGitStatusPolling.ts
|
||||
2 src/renderer/src/components/right-sidebar/useFileSearchRunner.ts
|
||||
2 src/renderer/src/components/right-sidebar/useFileSearchScope.ts
|
||||
3 src/renderer/src/components/right-sidebar/useGitStatusPolling.ts
|
||||
3 src/renderer/src/components/settings/BaseRefPicker.tsx
|
||||
2 src/renderer/src/components/settings/BrowserPane.tsx
|
||||
1 src/renderer/src/components/settings/CliSkillRuntimeSetup.tsx
|
||||
@@ -135,8 +177,9 @@
|
||||
1 src/renderer/src/components/settings/RepositoryHooksSection.tsx
|
||||
1 src/renderer/src/components/settings/RepositoryIconPicker.tsx
|
||||
4 src/renderer/src/components/settings/RuntimeEnvironmentsPane.tsx
|
||||
1 src/renderer/src/components/settings/Settings.tsx
|
||||
2 src/renderer/src/components/settings/Settings.tsx
|
||||
1 src/renderer/src/components/settings/SettingsSetupGuidePane.tsx
|
||||
1 src/renderer/src/components/settings/SettingsSidebar.tsx
|
||||
1 src/renderer/src/components/settings/ShortcutsPane.tsx
|
||||
2 src/renderer/src/components/settings/TasksPane.tsx
|
||||
1 src/renderer/src/components/settings/WorkspaceDirectorySetting.tsx
|
||||
@@ -166,27 +209,37 @@
|
||||
3 src/renderer/src/components/sidebar/LinearAgentSkillSetupPrompt.tsx
|
||||
1 src/renderer/src/components/sidebar/SavedHostScopeWidenGate.tsx
|
||||
1 src/renderer/src/components/sidebar/SetupGuideSidebarEntry.tsx
|
||||
1 src/renderer/src/components/sidebar/SetupScriptPromptCard.tsx
|
||||
1 src/renderer/src/components/sidebar/SidebarAgentsList.tsx
|
||||
1 src/renderer/src/components/sidebar/SidebarSettingsHelpMenu.tsx
|
||||
1 src/renderer/src/components/sidebar/SidebarTaskNavButton.tsx
|
||||
1 src/renderer/src/components/sidebar/WorkspaceAttachmentSearch.tsx
|
||||
1 src/renderer/src/components/sidebar/WorkspaceKanbanDrawer.tsx
|
||||
1 src/renderer/src/components/sidebar/WorktreeCardPorts.tsx
|
||||
2 src/renderer/src/components/sidebar/WorktreeList.tsx
|
||||
1 src/renderer/src/components/sidebar/WorktreeRowOpenInSubMenu.tsx
|
||||
1 src/renderer/src/components/sidebar/WorktreeVisibilityDialog.tsx
|
||||
1 src/renderer/src/components/sidebar/add-repo-runtime-owner.ts
|
||||
2 src/renderer/src/components/sidebar/delete-worktree-flow.ts
|
||||
1 src/renderer/src/components/sidebar/linear-agent-skill-runtime.ts
|
||||
2 src/renderer/src/components/sidebar/rendered-sidebar-worktree-order.ts
|
||||
1 src/renderer/src/components/sidebar/setup-script-prompt-render-state.ts
|
||||
2 src/renderer/src/components/sidebar/sidebar-host-options.ts
|
||||
1 src/renderer/src/components/sidebar/sidebar-project-drop.ts
|
||||
2 src/renderer/src/components/sidebar/use-add-repo-host-selection.ts
|
||||
1 src/renderer/src/components/sidebar/use-delete-worktree-status-hydration.ts
|
||||
2 src/renderer/src/components/sidebar/use-delete-worktree-status-hydration.ts
|
||||
1 src/renderer/src/components/sidebar/use-sidebar-host-scope-options.ts
|
||||
1 src/renderer/src/components/sidebar/use-visible-workspace-kanban-worktree-ids.ts
|
||||
1 src/renderer/src/components/sidebar/use-workspace-kanban-board-projection.ts
|
||||
1 src/renderer/src/components/sidebar/use-workspace-reference-details.ts
|
||||
1 src/renderer/src/components/sidebar/use-worktree-card-controller.ts
|
||||
1 src/renderer/src/components/sidebar/use-worktree-card-review-details.ts
|
||||
1 src/renderer/src/components/sidebar/useAddRepoCloneFlow.ts
|
||||
1 src/renderer/src/components/sidebar/useCreateRepo.ts
|
||||
2 src/renderer/src/components/sidebar/useSidebarProjectDrop.ts
|
||||
1 src/renderer/src/components/sidebar/visible-worktree-options-from-state.ts
|
||||
2 src/renderer/src/components/sidebar/visible-worktrees.ts
|
||||
3 src/renderer/src/components/sidebar/workspace-board-task-status-sync.ts
|
||||
1 src/renderer/src/components/sidebar/workspace-options-menu-items.tsx
|
||||
2 src/renderer/src/components/sidebar/workspace-reference-details.ts
|
||||
1 src/renderer/src/components/sidebar/workspace-reference-refresh-targets.ts
|
||||
@@ -195,52 +248,94 @@
|
||||
2 src/renderer/src/components/sidebar/worktree-list/listing/use-filters.ts
|
||||
2 src/renderer/src/components/sidebar/worktree-list/listing/use-folder-path-statuses.ts
|
||||
1 src/renderer/src/components/sidebar/worktree-list/listing/use-section-rows.ts
|
||||
1 src/renderer/src/components/sidebar/worktree-list/rows/ProjectGroupDialogs.tsx
|
||||
1 src/renderer/src/components/sidebar/worktree-list/viewport/VirtualizedWorktreeViewport.tsx
|
||||
1 src/renderer/src/components/sidebar/worktree-visibility-host-target.ts
|
||||
1 src/renderer/src/components/skills/SkillsPage.tsx
|
||||
7 src/renderer/src/components/status-bar/ClaudeSwitcherMenu.tsx
|
||||
1 src/renderer/src/components/status-bar/CodexSwitcherMenu.tsx
|
||||
1 src/renderer/src/components/status-bar/PortsStatusSegment.tsx
|
||||
1 src/renderer/src/components/status-bar/SshStatusSegment.tsx
|
||||
1 src/renderer/src/components/status-bar/StatusBarSurface.tsx
|
||||
1 src/renderer/src/components/status-bar/ports-status-popover-rows.tsx
|
||||
2 src/renderer/src/components/status-bar/provider-account-sync-key.ts
|
||||
1 src/renderer/src/components/status-bar/status-bar-claude-accounts.ts
|
||||
1 src/renderer/src/components/status-bar/status-bar-codex-accounts.ts
|
||||
1 src/renderer/src/components/status-bar/usage-provider-settings-target.ts
|
||||
7 src/renderer/src/components/status-bar/use-codex-switcher-controller.ts
|
||||
1 src/renderer/src/components/status-bar/use-status-bar-controller.ts
|
||||
1 src/renderer/src/components/status-bar/use-workspace-space-git-refresh-action.ts
|
||||
2 src/renderer/src/components/status-bar/use-workspace-space-git-refresh-action.ts
|
||||
1 src/renderer/src/components/status-bar/use-workspace-space-manager-panel.ts
|
||||
1 src/renderer/src/components/status-bar/workspace-space-decision-details.ts
|
||||
1 src/renderer/src/components/tab-bar/QuickLaunchButton.tsx
|
||||
1 src/renderer/src/components/tab-bar/TabBar.tsx
|
||||
1 src/renderer/src/components/tab-bar/TabBarItemRow.tsx
|
||||
3 src/renderer/src/components/tab-bar/tab-bar-windows-shell-launch-test-harness.ts
|
||||
3 src/renderer/src/components/tab-bar/use-tab-bar-runtime-model.ts
|
||||
4 src/renderer/src/components/tab-bar/use-tab-bar-runtime-model.ts
|
||||
2 src/renderer/src/components/tab-bar/web-runtime-tab-move-mirror.ts
|
||||
1 src/renderer/src/components/tab-bar/windows-shell-menu-visibility.ts
|
||||
2 src/renderer/src/components/tab-group/useTabGroupActivationCommands.ts
|
||||
5 src/renderer/src/components/tab-group/useTabGroupCreationCommands.ts
|
||||
1 src/renderer/src/components/task-page/TaskPage.tsx
|
||||
1 src/renderer/src/components/tab-group/workspace-tab-close-commands.ts
|
||||
1 src/renderer/src/components/task-page-jira-status-order.ts
|
||||
2 src/renderer/src/components/task-page-linear-issue-model.tsx
|
||||
11 src/renderer/src/components/task-page/TaskPage.tsx
|
||||
2 src/renderer/src/components/task-page/jira/IssueAssigneeField.tsx
|
||||
1 src/renderer/src/components/task-page/linear/Filters.tsx
|
||||
1 src/renderer/src/components/terminal-pane/TerminalPaneSurface.tsx
|
||||
1 src/renderer/src/components/terminal-pane/pending-split-close-test-fixture.ts
|
||||
1 src/renderer/src/components/terminal-pane/pty-connection/agent-idle-working-handlers.ts
|
||||
1 src/renderer/src/components/terminal-pane/pty-connection/cold-restore-resume-startup.ts
|
||||
1 src/renderer/src/components/terminal-pane/pty-connection/direct-ssh-retry-status.ts
|
||||
1 src/renderer/src/components/terminal-pane/pty-connection/interrupt-input-intent.ts
|
||||
1 src/renderer/src/components/terminal-pane/pty-connection/pane-agent-identity.ts
|
||||
1 src/renderer/src/components/terminal-pane/retire-unbound-runtime-terminal-pane.ts
|
||||
1 src/renderer/src/components/terminal-pane/terminal-ctrl-arrow-conpty.ts
|
||||
2 src/renderer/src/components/terminal-pane/terminal-drop-runtime-owner.ts
|
||||
1 src/renderer/src/components/terminal-pane/terminal-fit-restore.ts
|
||||
1 src/renderer/src/components/terminal-pane/terminal-input-host-platform.ts
|
||||
2 src/renderer/src/components/terminal-pane/terminal-input-host-platform.ts
|
||||
1 src/renderer/src/components/terminal-pane/terminal-keyboard-hook.ts
|
||||
1 src/renderer/src/components/terminal-pane/terminal-keyboard-runtime.ts
|
||||
1 src/renderer/src/components/terminal-pane/terminal-link-open-hints.ts
|
||||
2 src/renderer/src/components/terminal-pane/terminal-pane-close-admission.ts
|
||||
1 src/renderer/src/components/terminal-pane/terminal-pane-menu-paste.ts
|
||||
1 src/renderer/src/components/terminal-pane/terminal-pane-mount-preparation.ts
|
||||
1 src/renderer/src/components/terminal-pane/terminal-pane-manager-options.ts
|
||||
2 src/renderer/src/components/terminal-pane/terminal-pane-menu-paste.ts
|
||||
3 src/renderer/src/components/terminal-pane/terminal-pane-mount-preparation.ts
|
||||
1 src/renderer/src/components/terminal-pane/terminal-pane-paste-execution.ts
|
||||
1 src/renderer/src/components/terminal-pane/terminal-pane-paste-listeners.ts
|
||||
1 src/renderer/src/components/terminal-pane/use-terminal-pane-controller.ts
|
||||
2 src/renderer/src/components/terminal-pane/use-terminal-pane-close-actions.ts
|
||||
2 src/renderer/src/components/terminal-pane/use-terminal-pane-controller.ts
|
||||
1 src/renderer/src/components/terminal-pane/use-terminal-pane-lifecycle.ts
|
||||
1 src/renderer/src/components/terminal-pane/use-terminal-pane-mount-lifecycle.ts
|
||||
1 src/renderer/src/components/terminal-pane/use-terminal-pane-paste-listeners.ts
|
||||
1 src/renderer/src/components/terminal-workspace-model.ts
|
||||
1 src/renderer/src/components/terminal/terminal-tab-create.ts
|
||||
1 src/renderer/src/components/terminal/terminal-tab-actions.ts
|
||||
4 src/renderer/src/components/terminal/terminal-tab-bulk-actions.ts
|
||||
2 src/renderer/src/components/terminal/terminal-tab-create.ts
|
||||
2 src/renderer/src/components/use-new-linear-issue-projects.ts
|
||||
4 src/renderer/src/components/use-task-page-jira-creation-metadata.ts
|
||||
4 src/renderer/src/components/use-task-page-jira-issue-creation.ts
|
||||
2 src/renderer/src/components/use-task-page-jira-list-effects.ts
|
||||
2 src/renderer/src/components/use-task-page-jira-list-state.ts
|
||||
4 src/renderer/src/components/use-task-page-linear-board.ts
|
||||
6 src/renderer/src/components/use-task-page-linear-creation-state.ts
|
||||
4 src/renderer/src/components/use-task-page-linear-issue-creation.ts
|
||||
2 src/renderer/src/components/use-task-page-linear-project-creation.ts
|
||||
2 src/renderer/src/components/use-task-page-provider-metadata.ts
|
||||
2 src/renderer/src/components/use-task-page-source-availability.ts
|
||||
2 src/renderer/src/components/use-task-page-store-bindings.ts
|
||||
2 src/renderer/src/components/use-terminal-activation-actions.ts
|
||||
2 src/renderer/src/components/use-terminal-bulk-close-actions.ts
|
||||
1 src/renderer/src/components/use-terminal-controller.ts
|
||||
8 src/renderer/src/components/use-terminal-create-actions.ts
|
||||
1 src/renderer/src/components/use-terminal-watcher-effects.ts
|
||||
2 src/renderer/src/components/use-worktree-jump-palette-controller.ts
|
||||
1 src/renderer/src/components/use-worktree-jump-palette-create-action.ts
|
||||
2 src/renderer/src/components/use-worktree-jump-palette-filter.ts
|
||||
3 src/renderer/src/components/use-worktree-jump-palette-quick-actions.ts
|
||||
2 src/renderer/src/components/use-worktree-jump-palette-store-state.ts
|
||||
1 src/renderer/src/components/use-worktree-jump-palette-task-url.ts
|
||||
1 src/renderer/src/components/worktree-jump-palette-create-worktree.ts
|
||||
1 src/renderer/src/hooks/composer-state/attachment-drop-state.ts
|
||||
1 src/renderer/src/hooks/composer-state/composer-attachment-drop-state.ts
|
||||
1 src/renderer/src/hooks/composer-state/composer-navigation-actions.ts
|
||||
@@ -252,7 +347,8 @@
|
||||
1 src/renderer/src/hooks/composer-state/provider-runtime-sync.ts
|
||||
1 src/renderer/src/hooks/composer-state/quick-creation-execution.ts
|
||||
1 src/renderer/src/hooks/composer-state/workspace-identity-state.ts
|
||||
2 src/renderer/src/hooks/editor-external-watch-targets.ts
|
||||
1 src/renderer/src/hooks/editor-external-watch-target-rows.ts
|
||||
3 src/renderer/src/hooks/editor-external-watch-targets.ts
|
||||
1 src/renderer/src/hooks/ipc-events-close-routing-test-harness.ts
|
||||
1 src/renderer/src/hooks/ipc-events-terminal-create-test-harness.ts
|
||||
6 src/renderer/src/hooks/ipc-events-test-harness.ts
|
||||
@@ -261,29 +357,41 @@
|
||||
1 src/renderer/src/hooks/ipc-events/runtime-environment-subscription-selection.ts
|
||||
1 src/renderer/src/hooks/ipc-events/settings-sidebar-ipc-bridge.ts
|
||||
2 src/renderer/src/hooks/ipc-events/tab-lifecycle-ipc-bridge.ts
|
||||
3 src/renderer/src/hooks/use-active-skill-discovery-runtime-target.ts
|
||||
1 src/renderer/src/hooks/ipc-events/terminal-request-ipc-bridge.ts
|
||||
2 src/renderer/src/hooks/use-active-skill-discovery-runtime-target.ts
|
||||
1 src/renderer/src/hooks/use-terminal-quick-command-hosts.ts
|
||||
1 src/renderer/src/hooks/useActiveProjectSkillRuntime.ts
|
||||
2 src/renderer/src/hooks/useAgentDetectionTarget.ts
|
||||
1 src/renderer/src/hooks/useEditorExternalWatch.ts
|
||||
1 src/renderer/src/hooks/useInstalledAgentSkills.ts
|
||||
1 src/renderer/src/hooks/useIpcEvents.ts
|
||||
1 src/renderer/src/hooks/useIssueMetadata.ts
|
||||
4 src/renderer/src/hooks/useIssueMetadata.ts
|
||||
1 src/renderer/src/hooks/useLinearProviderConnected.ts
|
||||
7 src/renderer/src/hooks/useSettingsNavigationMetadata.ts
|
||||
1 src/renderer/src/hooks/useUnreadDockBadge.ts
|
||||
2 src/renderer/src/hooks/useWindowsTerminalCapabilityOwnerKey.ts
|
||||
3 src/renderer/src/lib/activate-ai-vault-structured-session.ts
|
||||
4 src/renderer/src/lib/activate-ai-vault-structured-session.ts
|
||||
1 src/renderer/src/lib/active-agent-note-send.ts
|
||||
1 src/renderer/src/lib/active-agent-note-target.ts
|
||||
1 src/renderer/src/lib/agent-background-session-launch-host.ts
|
||||
1 src/renderer/src/lib/agent-detection-target-inventory.ts
|
||||
1 src/renderer/src/lib/agent-hibernation-coordinator-test-fixture.ts
|
||||
3 src/renderer/src/lib/agent-hibernation-coordinator.ts
|
||||
2 src/renderer/src/lib/agent-launch-route-input.ts
|
||||
1 src/renderer/src/lib/agent-message-send.ts
|
||||
1 src/renderer/src/lib/ai-vault-resume-platform.ts
|
||||
1 src/renderer/src/lib/ai-vault-tab-title-requests.ts
|
||||
2 src/renderer/src/lib/ai-vault-tab-title-sync-inputs.ts
|
||||
1 src/renderer/src/lib/client-creation-action-error.ts
|
||||
3 src/renderer/src/lib/client-creation-action-policy.ts
|
||||
1 src/renderer/src/lib/codex-account-restart-startup.ts
|
||||
1 src/renderer/src/lib/default-creation-host.ts # the sanctioned reader of the default host
|
||||
1 src/renderer/src/lib/doc-preview-grants.ts
|
||||
1 src/renderer/src/lib/empty-workspace-default-agent-chat.ts
|
||||
3 src/renderer/src/lib/ensure-hooks-confirmed.ts
|
||||
1 src/renderer/src/lib/execute-open-editor-path-move.ts
|
||||
1 src/renderer/src/lib/execution-host-facts.ts
|
||||
3 src/renderer/src/lib/execute-open-editor-path-move.ts
|
||||
1 src/renderer/src/lib/execution-host-display-label.ts
|
||||
2 src/renderer/src/lib/execution-host-facts.ts
|
||||
6 src/renderer/src/lib/file-preview.ts
|
||||
2 src/renderer/src/lib/folder-workspace-runtime-owner.ts
|
||||
1 src/renderer/src/lib/github-pr-start-point.ts
|
||||
@@ -293,29 +401,42 @@
|
||||
1 src/renderer/src/lib/launch-agent-background-session.ts
|
||||
1 src/renderer/src/lib/launch-agent-execution-context.ts
|
||||
2 src/renderer/src/lib/launch-agent-in-new-tab.ts
|
||||
1 src/renderer/src/lib/launch-agent-web-host-tab.ts
|
||||
2 src/renderer/src/lib/launch-agent-web-host-tab.ts
|
||||
2 src/renderer/src/lib/launch-ai-vault-session.ts
|
||||
1 src/renderer/src/lib/launch-structured-agent-session.ts
|
||||
1 src/renderer/src/lib/launch-work-item-direct-preflight.ts
|
||||
2 src/renderer/src/lib/launch-work-item-direct.ts
|
||||
1 src/renderer/src/lib/launch-worktree-background-terminals.ts
|
||||
1 src/renderer/src/lib/linear-issue-url-lookup.ts
|
||||
2 src/renderer/src/lib/local-preflight-context.ts
|
||||
3 src/renderer/src/lib/open-agent-message-sender.ts
|
||||
2 src/renderer/src/lib/provider-runtime-context.ts
|
||||
2 src/renderer/src/lib/remap-open-editor-tabs-for-path-change.ts
|
||||
1 src/renderer/src/lib/remote-workspace-drop-test-fixtures.ts
|
||||
4 src/renderer/src/lib/repo-runtime-owner.ts
|
||||
2 src/renderer/src/lib/resolve-owner.ts
|
||||
2 src/renderer/src/lib/resume-sleeping-agent-session.ts
|
||||
1 src/renderer/src/lib/runtime-session-mirror-owners.ts
|
||||
1 src/renderer/src/lib/runtime-session-mirror-targets.ts
|
||||
1 src/renderer/src/lib/runtime-workspace-file-route.ts
|
||||
1 src/renderer/src/lib/single-runtime-legacy-owner.ts
|
||||
1 src/renderer/src/lib/structured-agent-session-tab-activation.ts
|
||||
1 src/renderer/src/lib/sleeping-agent-session-launch.ts
|
||||
1 src/renderer/src/lib/sleeping-record-execution-host-scope.ts
|
||||
1 src/renderer/src/lib/structured-agent-session-launch.ts
|
||||
1 src/renderer/src/lib/structured-agent-session-provisional-tab.ts
|
||||
4 src/renderer/src/lib/structured-agent-session-tab-activation.ts
|
||||
1 src/renderer/src/lib/tab-number-shortcuts.ts
|
||||
1 src/renderer/src/lib/terminal-close-route.ts
|
||||
1 src/renderer/src/lib/terminal-tab-owner-activation.ts
|
||||
4 src/renderer/src/lib/terminal-worktree-route.ts
|
||||
5 src/renderer/src/lib/terminal-worktree-route.ts
|
||||
3 src/renderer/src/lib/unread-badge-count-selector.ts
|
||||
2 src/renderer/src/lib/web-runtime-worktree-terminal-after-wake.ts
|
||||
1 src/renderer/src/lib/workspace-browser-tab-close.ts
|
||||
4 src/renderer/src/lib/workspace-browser-tab-open.ts
|
||||
5 src/renderer/src/lib/workspace-browser-tab-open.ts
|
||||
1 src/renderer/src/lib/workspace-file-drag-source.ts
|
||||
1 src/renderer/src/lib/workspace-tab-commands.ts
|
||||
1 src/renderer/src/lib/workspace-tab-palette-activation.ts
|
||||
1 src/renderer/src/lib/workspace-terminal-host-authority.ts
|
||||
3 src/renderer/src/lib/workspace-terminal-host-authority.ts
|
||||
1 src/renderer/src/lib/worktree-activation-pty-inventory.ts
|
||||
3 src/renderer/src/lib/worktree-activation.ts
|
||||
1 src/renderer/src/lib/worktree-creation-agent-seeds.ts
|
||||
@@ -323,11 +444,14 @@
|
||||
1 src/renderer/src/lib/worktree-creation-flow-startup.ts
|
||||
1 src/renderer/src/lib/worktree-creation-flow.ts
|
||||
1 src/renderer/src/lib/worktree-creation-hook-preparation.ts
|
||||
1 src/renderer/src/lib/worktree-operation-route.ts
|
||||
1 src/renderer/src/lib/worktree-initial-terminal-seeding.ts
|
||||
1 src/renderer/src/lib/worktree-jump-navigation.ts
|
||||
2 src/renderer/src/lib/worktree-operation-route.ts
|
||||
1 src/renderer/src/lib/worktree-row-open-in-owner.ts
|
||||
3 src/renderer/src/lib/worktree-runtime-owner.ts
|
||||
6 src/renderer/src/lib/worktree-runtime-owner.ts
|
||||
1 src/renderer/src/lib/worktree-sort-order-host-split.ts
|
||||
1 src/renderer/src/runtime/close-mirrored-editor-tab.ts
|
||||
1 src/renderer/src/runtime/local-structured-session-tabs-sync/snapshot-apply.ts
|
||||
1 src/renderer/src/runtime/runtime-client-target.ts
|
||||
2 src/renderer/src/runtime/runtime-git-client-context.ts
|
||||
5 src/renderer/src/runtime/runtime-git-diff-client.ts
|
||||
@@ -339,12 +463,15 @@
|
||||
17 src/renderer/src/runtime/runtime-jira-client.ts
|
||||
2 src/renderer/src/runtime/runtime-jira-summary-client.ts
|
||||
1 src/renderer/src/runtime/runtime-jira-target.ts
|
||||
4 src/renderer/src/runtime/runtime-jira-user-fields-client.ts
|
||||
5 src/renderer/src/runtime/runtime-jira-user-fields-client.ts
|
||||
8 src/renderer/src/runtime/runtime-linear-client.ts
|
||||
5 src/renderer/src/runtime/runtime-linear-issue-mutations.ts
|
||||
6 src/renderer/src/runtime/runtime-linear-issue-mutations.ts
|
||||
12 src/renderer/src/runtime/runtime-linear-project-client.ts
|
||||
3 src/renderer/src/runtime/runtime-repo-client.ts
|
||||
3 src/renderer/src/runtime/structured-agent-session-owner.ts
|
||||
1 src/renderer/src/runtime/structured-conversation-name.ts
|
||||
5 src/renderer/src/runtime/use-runtime-session-mirror-environment-key.ts
|
||||
1 src/renderer/src/runtime/use-worktree-runtime-target.ts
|
||||
2 src/renderer/src/runtime/web-runtime-browser-creation.ts
|
||||
1 src/renderer/src/runtime/web-runtime-initial-terminal-bootstrap-dispatch.ts
|
||||
1 src/renderer/src/runtime/web-runtime-session-tab-lifecycle.ts
|
||||
@@ -356,41 +483,45 @@
|
||||
1 src/renderer/src/runtime/web-session-tabs-sync/active-session-subscription.ts
|
||||
2 src/renderer/src/runtime/web-session-tabs-sync/global-session-subscription.ts
|
||||
1 src/renderer/src/runtime/web-session-tabs-sync/tracking-decisions.ts
|
||||
2 src/renderer/src/runtime/web-session-tabs-sync/use-web-session-tabs-sync.ts
|
||||
3 src/renderer/src/runtime/web-session-tabs-sync/use-web-session-tabs-sync.ts
|
||||
2 src/renderer/src/store/folder-workspaces/folder-path-status-actions.ts
|
||||
2 src/renderer/src/store/folder-workspaces/folder-workspace-catalog-actions.ts
|
||||
5 src/renderer/src/store/folder-workspaces/folder-workspace-mutations.ts
|
||||
6 src/renderer/src/store/folder-workspaces/folder-workspace-mutations.ts
|
||||
1 src/renderer/src/store/folder-workspaces/folder-workspace-routing.ts
|
||||
1 src/renderer/src/store/github/repository-routing.ts
|
||||
1 src/renderer/src/store/github/visible-hosted-review-refresh-targets.ts
|
||||
2 src/renderer/src/store/github/visible-hosted-review-refresh-targets.ts
|
||||
2 src/renderer/src/store/github/work-item-aggregate-actions.ts
|
||||
3 src/renderer/src/store/github/work-item-fetch-actions.ts
|
||||
2 src/renderer/src/store/github/work-item-routing.ts
|
||||
7 src/renderer/src/store/index.ts
|
||||
9 src/renderer/src/store/index.ts
|
||||
6 src/renderer/src/store/project-groups/nested-repository-operations.ts
|
||||
2 src/renderer/src/store/project-groups/project-group-catalog-actions.ts
|
||||
7 src/renderer/src/store/project-groups/project-group-mutations.ts
|
||||
10 src/renderer/src/store/project-groups/project-group-mutations.ts
|
||||
1 src/renderer/src/store/projects/project-host-routing.ts
|
||||
1 src/renderer/src/store/projects/project-update.ts
|
||||
2 src/renderer/src/store/repos/all-host-repo-catalog-actions.ts
|
||||
1 src/renderer/src/store/repos/owner-routing.ts
|
||||
1 src/renderer/src/store/repos/converted-ssh-browser-pages.ts
|
||||
2 src/renderer/src/store/repos/owner-routing.ts
|
||||
2 src/renderer/src/store/repos/repo-add-actions.ts
|
||||
2 src/renderer/src/store/repos/repo-catalog-actions.ts
|
||||
2 src/renderer/src/store/repos/repo-removal.ts
|
||||
2 src/renderer/src/store/repos/repo-update.ts
|
||||
3 src/renderer/src/store/repos/repo-update.ts
|
||||
2 src/renderer/src/store/repos/runtime-repo-catalog-actions.ts
|
||||
2 src/renderer/src/store/repos/safe-auto-fork-sync.ts
|
||||
1 src/renderer/src/store/slices/browser-slice-test-harness.ts
|
||||
14 src/renderer/src/store/slices/browser/browser-cookie-import-actions.ts
|
||||
1 src/renderer/src/store/slices/browser/browser-close-actions.ts
|
||||
16 src/renderer/src/store/slices/browser/browser-cookie-import-actions.ts
|
||||
1 src/renderer/src/store/slices/browser/browser-host-actions.ts
|
||||
7 src/renderer/src/store/slices/browser/browser-host-state.ts
|
||||
1 src/renderer/src/store/slices/browser/browser-page-conversion-actions.ts
|
||||
12 src/renderer/src/store/slices/browser/browser-profile-import-actions.ts
|
||||
11 src/renderer/src/store/slices/browser/browser-profile-list-actions.ts
|
||||
6 src/renderer/src/store/slices/browser/browser-tab-actions.ts
|
||||
10 src/renderer/src/store/slices/browser/browser-host-state.ts
|
||||
2 src/renderer/src/store/slices/browser/browser-page-conversion-actions.ts
|
||||
1 src/renderer/src/store/slices/browser/browser-page-focus-actions.ts
|
||||
14 src/renderer/src/store/slices/browser/browser-profile-import-actions.ts
|
||||
14 src/renderer/src/store/slices/browser/browser-profile-list-actions.ts
|
||||
7 src/renderer/src/store/slices/browser/browser-tab-actions.ts
|
||||
1 src/renderer/src/store/slices/browser/browser-tab-focus-actions.ts
|
||||
1 src/renderer/src/store/slices/browser/create-browser-slice.ts
|
||||
1 src/renderer/src/store/slices/browser/paired-browser-tab-creator.ts
|
||||
3 src/renderer/src/store/slices/diff-comment-persistence.ts
|
||||
5 src/renderer/src/store/slices/diff-comment-persistence.ts
|
||||
2 src/renderer/src/store/slices/editor-slice-test-harness.ts
|
||||
4 src/renderer/src/store/slices/editor/actions/git-remote-push-pull.ts
|
||||
1 src/renderer/src/store/slices/editor/actions/git-remote-status.ts
|
||||
@@ -402,63 +533,80 @@
|
||||
1 src/renderer/src/store/slices/editor/create-editor-slice.ts
|
||||
1 src/renderer/src/store/slices/github-cache-key.ts
|
||||
1 src/renderer/src/store/slices/hosted-review-cache-identity.ts
|
||||
1 src/renderer/src/store/slices/jira-collection-read-actions.ts
|
||||
13 src/renderer/src/store/slices/jira-connection-actions.ts
|
||||
4 src/renderer/src/store/slices/jira-issue-read-actions.ts
|
||||
5 src/renderer/src/store/slices/jira-read-coordination.ts
|
||||
3 src/renderer/src/store/slices/linear/linear-custom-view-detail-actions.ts
|
||||
3 src/renderer/src/store/slices/linear/linear-custom-view-issue-actions.ts
|
||||
3 src/renderer/src/store/slices/linear/linear-custom-view-list-actions.ts
|
||||
3 src/renderer/src/store/slices/linear/linear-custom-view-project-actions.ts
|
||||
3 src/renderer/src/store/slices/linear/linear-issue-detail-actions.ts
|
||||
6 src/renderer/src/store/slices/linear/linear-issue-list-actions.ts
|
||||
3 src/renderer/src/store/slices/linear/linear-project-detail-actions.ts
|
||||
3 src/renderer/src/store/slices/linear/linear-project-issue-actions.ts
|
||||
3 src/renderer/src/store/slices/linear/linear-project-list-actions.ts
|
||||
13 src/renderer/src/store/slices/linear/linear-slice-connection-actions.ts
|
||||
4 src/renderer/src/store/slices/linear/linear-slice-scope.ts
|
||||
3 src/renderer/src/store/slices/linear/linear-slice-status-actions.ts
|
||||
3 src/renderer/src/store/slices/linear/linear-team-actions.ts
|
||||
5 src/renderer/src/store/slices/jira-collection-read-actions.ts
|
||||
31 src/renderer/src/store/slices/jira-connection-actions.ts
|
||||
8 src/renderer/src/store/slices/jira-issue-read-actions.ts
|
||||
6 src/renderer/src/store/slices/jira-read-coordination.ts
|
||||
3 src/renderer/src/store/slices/jira.ts
|
||||
1 src/renderer/src/store/slices/linear-slice-test-harness.ts
|
||||
11 src/renderer/src/store/slices/linear.ts
|
||||
5 src/renderer/src/store/slices/linear/linear-custom-view-detail-actions.ts
|
||||
5 src/renderer/src/store/slices/linear/linear-custom-view-issue-actions.ts
|
||||
6 src/renderer/src/store/slices/linear/linear-custom-view-list-actions.ts
|
||||
5 src/renderer/src/store/slices/linear/linear-custom-view-project-actions.ts
|
||||
1 src/renderer/src/store/slices/linear/linear-invalidation-actions.ts
|
||||
2 src/renderer/src/store/slices/linear/linear-issue-cache-actions.ts
|
||||
6 src/renderer/src/store/slices/linear/linear-issue-detail-actions.ts
|
||||
9 src/renderer/src/store/slices/linear/linear-issue-list-actions.ts
|
||||
5 src/renderer/src/store/slices/linear/linear-project-detail-actions.ts
|
||||
5 src/renderer/src/store/slices/linear/linear-project-issue-actions.ts
|
||||
6 src/renderer/src/store/slices/linear/linear-project-list-actions.ts
|
||||
33 src/renderer/src/store/slices/linear/linear-slice-connection-actions.ts
|
||||
5 src/renderer/src/store/slices/linear/linear-slice-scope.ts
|
||||
9 src/renderer/src/store/slices/linear/linear-slice-status-actions.ts
|
||||
6 src/renderer/src/store/slices/linear/linear-team-actions.ts
|
||||
2 src/renderer/src/store/slices/preflight.ts
|
||||
1 src/renderer/src/store/slices/project-group-owner-routing.ts
|
||||
1 src/renderer/src/store/slices/repo-host-identity.ts
|
||||
1 src/renderer/src/store/slices/repo-reorder-host-split.ts
|
||||
10 src/renderer/src/store/slices/repos.ts
|
||||
1 src/renderer/src/store/slices/runtime-status.ts
|
||||
1 src/renderer/src/store/slices/settings-owner-hydration-publication.ts
|
||||
2 src/renderer/src/store/slices/settings-owner-hydration-publication.ts
|
||||
5 src/renderer/src/store/slices/settings.ts
|
||||
6 src/renderer/src/store/slices/store-test-helpers.ts
|
||||
8 src/renderer/src/store/slices/store-test-helpers.ts
|
||||
1 src/renderer/src/store/slices/tabs/tabs-close-actions.ts
|
||||
2 src/renderer/src/store/slices/tabs/tabs-host-mirroring.ts
|
||||
2 src/renderer/src/store/slices/terminal-tab-retirement.ts
|
||||
1 src/renderer/src/store/slices/worktree-visibility-owner-settings.ts
|
||||
3 src/renderer/src/store/slices/worktree-visibility-settings-write.ts
|
||||
3 src/renderer/src/store/slices/worktrees-slice-test-harness.ts
|
||||
12 src/renderer/src/store/slices/worktrees.ts
|
||||
2 src/renderer/src/store/slices/worktrees/create/create-worktree.ts
|
||||
15 src/renderer/src/store/slices/worktrees.ts
|
||||
3 src/renderer/src/store/slices/worktrees/create/create-worktree.ts
|
||||
1 src/renderer/src/store/slices/worktrees/create/created-worktree-state-merge.ts
|
||||
2 src/renderer/src/store/slices/worktrees/create/prefetch-worktree-create-base.ts
|
||||
2 src/renderer/src/store/slices/worktrees/listing/detected-worktree-provider-request.ts
|
||||
6 src/renderer/src/store/slices/worktrees/listing/detected-worktree-refresh.ts
|
||||
7 src/renderer/src/store/slices/worktrees/listing/detected-worktree-refresh.ts
|
||||
4 src/renderer/src/store/slices/worktrees/listing/fetch-all-worktrees.ts
|
||||
2 src/renderer/src/store/slices/worktrees/listing/fetch-detected-worktrees.ts
|
||||
5 src/renderer/src/store/slices/worktrees/listing/fetch-worktrees.ts
|
||||
1 src/renderer/src/store/slices/worktrees/listing/known-ssh-worktree-fetch.ts
|
||||
1 src/renderer/src/store/slices/worktrees/listing/worktree-host-ownership.ts
|
||||
2 src/renderer/src/store/slices/worktrees/listing/worktree-owner-settings.ts
|
||||
4 src/renderer/src/store/slices/worktrees/listing/fetch-detected-worktrees.ts
|
||||
7 src/renderer/src/store/slices/worktrees/listing/fetch-worktrees.ts
|
||||
1 src/renderer/src/store/slices/worktrees/listing/fetched-worktree-merge.ts
|
||||
2 src/renderer/src/store/slices/worktrees/listing/known-ssh-worktree-fetch.ts
|
||||
2 src/renderer/src/store/slices/worktrees/listing/worktree-host-ownership.ts
|
||||
3 src/renderer/src/store/slices/worktrees/listing/worktree-owner-settings.ts
|
||||
2 src/renderer/src/store/slices/worktrees/metadata/hosted-review-push-target-ensure.ts
|
||||
4 src/renderer/src/store/slices/worktrees/metadata/hosted-review-push-target.ts
|
||||
4 src/renderer/src/store/slices/worktrees/metadata/update-worktree-meta.ts
|
||||
5 src/renderer/src/store/slices/worktrees/metadata/update-worktree-meta.ts
|
||||
3 src/renderer/src/store/slices/worktrees/metadata/worktree-lineage-actions.ts
|
||||
7 src/renderer/src/store/slices/worktrees/metadata/worktree-lineage-refresh.ts
|
||||
3 src/renderer/src/store/slices/worktrees/metadata/worktree-lineage-host-merge.ts
|
||||
8 src/renderer/src/store/slices/worktrees/metadata/worktree-lineage-refresh.ts
|
||||
1 src/renderer/src/store/slices/worktrees/metadata/worktree-meta-persist.ts
|
||||
1 src/renderer/src/store/slices/worktrees/session/worktree-terminal-reference.ts
|
||||
1 src/renderer/src/store/slices/worktrees/session/worktree-slice-lookups.ts
|
||||
3 src/renderer/src/store/slices/worktrees/session/worktree-terminal-reference.ts
|
||||
1 src/renderer/src/store/slices/worktrees/teardown/force-delete-preserved-branch.ts
|
||||
1 src/renderer/src/store/slices/worktrees/teardown/missing-worktree-terminal-teardown.ts
|
||||
1 src/renderer/src/store/slices/worktrees/teardown/purge-stale-runtime-host-state.ts
|
||||
2 src/renderer/src/store/slices/worktrees/teardown/remove-worktree.ts
|
||||
1 src/renderer/src/store/slices/worktrees/teardown/worktree-purge-state.ts
|
||||
2 src/renderer/src/store/terminals/terminal-active-workspace-creation.ts
|
||||
1 src/renderer/src/store/terminals/terminal-pane-hibernation.ts
|
||||
1 src/renderer/src/store/terminals/terminal-shutdown.ts
|
||||
1 src/renderer/src/store/terminals/terminal-tab-attention.ts
|
||||
1 src/renderer/src/store/terminals/terminal-tab-close-providers.ts
|
||||
1 src/renderer/src/store/terminals/terminal-workspace-routing.ts
|
||||
1 src/renderer/src/web/preload-api/web-app-api.ts
|
||||
3 src/renderer/src/web/preload-api/web-preference-normalization.ts
|
||||
16 src/renderer/src/web/preload-api/web-preferences-store.ts
|
||||
6 src/renderer/src/web/preload-api/web-settings-api.ts
|
||||
1 src/renderer/src/web/web-preload-api.ts
|
||||
22 src/renderer/src/web/preload-api/web-preferences-store.ts
|
||||
13 src/renderer/src/web/preload-api/web-settings-api.ts
|
||||
9 src/renderer/src/web/preload-api/web-ui-api.ts
|
||||
3 src/renderer/src/web/preload-api/web-workspace-session-api.ts
|
||||
3 src/renderer/src/web/web-preload-api.ts
|
||||
|
||||
@@ -10,13 +10,8 @@
|
||||
1 src/renderer/src/components/settings/RepositoryIconPicker.tsx
|
||||
1 src/renderer/src/components/setup-guide/setup-guide-progress-readiness.ts
|
||||
1 src/renderer/src/components/sidebar/add-repo-runtime-owner.ts
|
||||
1 src/renderer/src/components/status-bar/ClaudeSwitcherMenu.tsx
|
||||
1 src/renderer/src/components/status-bar/use-codex-switcher-controller.ts
|
||||
1 src/renderer/src/hooks/composer-state/provider-runtime-sync.ts
|
||||
1 src/renderer/src/hooks/composer-state/quick-creation-execution.ts
|
||||
1 src/renderer/src/hooks/use-active-skill-discovery-runtime-target.ts
|
||||
1 src/renderer/src/hooks/useIssueMetadata.ts
|
||||
1 src/renderer/src/hooks/useSettingsNavigationMetadata.ts
|
||||
1 src/renderer/src/lib/github-pr-start-point.ts
|
||||
1 src/renderer/src/lib/worktree-creation-flow-startup.ts
|
||||
1 src/renderer/src/runtime/runtime-git-client-context.ts
|
||||
@@ -26,8 +21,6 @@
|
||||
10 src/renderer/src/runtime/runtime-git-sync-client.ts
|
||||
9 src/renderer/src/runtime/runtime-git-working-tree-client.ts
|
||||
3 src/renderer/src/runtime/runtime-hooks-client.ts
|
||||
1 src/renderer/src/runtime/runtime-jira-target.ts
|
||||
1 src/renderer/src/runtime/runtime-linear-client.ts
|
||||
3 src/renderer/src/runtime/runtime-repo-client.ts
|
||||
1 src/renderer/src/store/folder-workspaces/folder-path-status-actions.ts
|
||||
2 src/renderer/src/store/folder-workspaces/folder-workspace-catalog-actions.ts
|
||||
|
||||
@@ -18,7 +18,14 @@ const IMPORT_EXPORT_LIST = /\b(?:import|export)\s+(?:type\s+)?\{[^}]*\}/g
|
||||
// Calls and value uses (`.map(helper)`); definitions and type queries are not routing.
|
||||
const FOCUS_ROUTING_USE = new RegExp(`(?<!(?:function|typeof)\\s+)\\b${HELPERS}\\b`, 'g')
|
||||
// Seed readers; every function that reads the setting or calls a reader joins them by discovery.
|
||||
const SEED_FOCUS_READERS = [...HELPER_NAMES.split('|'), 'defaultCreationHost']
|
||||
// The sanctioned readers are seeds too: their bodies reach the setting through a private helper.
|
||||
const SEED_FOCUS_READERS = [
|
||||
...HELPER_NAMES.split('|'),
|
||||
'defaultCreationHost',
|
||||
'defaultScopeHost',
|
||||
'defaultScopeSource',
|
||||
'rowLessSourceTarget'
|
||||
]
|
||||
const FOCUS_SCAN_ROOTS = [SCAN_ROOT, 'src/shared']
|
||||
|
||||
/** Imports and re-exports are not uses; an aliased one is reported by {@link hasFocusRoutingAlias}. */
|
||||
@@ -77,9 +84,9 @@ export function topLevelDeclarations(sourceText) {
|
||||
// skipped: slice creators and hooks return bags of actions, which pulls in the whole store.
|
||||
const VALUE_STATEMENT_START = /\breturn\s+(?!\(?\s*\{)|=>\s*(?!\(?\s*\{)/g
|
||||
|
||||
function valueStatements(body) {
|
||||
function statementsFrom(body, start) {
|
||||
const statements = []
|
||||
for (const match of body.matchAll(VALUE_STATEMENT_START)) {
|
||||
for (const match of body.matchAll(start)) {
|
||||
let depth = 0
|
||||
let end = match.index + match[0].length
|
||||
for (; end < body.length; end += 1) {
|
||||
@@ -95,9 +102,21 @@ function valueStatements(body) {
|
||||
break
|
||||
}
|
||||
}
|
||||
statements.push(body.slice(match.index, end))
|
||||
statements.push({ name: match[1], text: body.slice(match.index, end) })
|
||||
}
|
||||
return statements.join('\n')
|
||||
return statements
|
||||
}
|
||||
|
||||
// `const id = reader(…)` counts only when `id` is then returned (assign-then-return).
|
||||
const LOCAL_ASSIGNMENT_START = /\b(?:const|let)\s+([\w$]+)\s*(?::[^=\n]*)?=(?![=>])/g
|
||||
|
||||
function valueStatements(body) {
|
||||
const returned = statementsFrom(body, VALUE_STATEMENT_START).map(({ text }) => text)
|
||||
const returnedIds = new Set(returned.join('\n').match(/[\w$]+/g))
|
||||
const assigned = statementsFrom(body, LOCAL_ASSIGNMENT_START)
|
||||
.filter(({ name }) => returnedIds.has(name))
|
||||
.map(({ text }) => text)
|
||||
return [...returned, ...assigned].join('\n')
|
||||
}
|
||||
|
||||
const IMPORT_STATEMENT =
|
||||
|
||||
@@ -183,6 +183,39 @@ describe('countFocusSettingReads', () => {
|
||||
}
|
||||
})
|
||||
|
||||
it('discovers a reader assigned to a local that is then returned', () => {
|
||||
const readers = discoverFocusReaders(
|
||||
new Map([
|
||||
[
|
||||
'src/renderer/src/focus.ts',
|
||||
'export function focusedId(s) {\n return s.activeRuntimeEnvironmentId\n}\n'
|
||||
],
|
||||
[
|
||||
'src/renderer/src/hook.ts',
|
||||
[
|
||||
"import { focusedId } from './focus'",
|
||||
'export function useTarget(s) {',
|
||||
' const id = focusedId(s)',
|
||||
' const unrelated = focusedId(s)',
|
||||
' return id ? { id } : null',
|
||||
'}',
|
||||
'export function sideEffectOnly(s) {',
|
||||
' const id = focusedId(s)',
|
||||
' log(id)',
|
||||
' return null',
|
||||
'}'
|
||||
].join('\n')
|
||||
]
|
||||
])
|
||||
)
|
||||
expect(readers.namesFor('src/renderer/src/hook.ts').has('useTarget')).toBe(true)
|
||||
expect(readers.namesFor('src/renderer/src/hook.ts').has('sideEffectOnly')).toBe(false)
|
||||
})
|
||||
|
||||
it('counts the default scope source as a read', () => {
|
||||
expect(countFocusSettingReads('linearConnect(defaultScopeSource(get().settings), key)')).toBe(1)
|
||||
})
|
||||
|
||||
it('counts destructuring reads', () => {
|
||||
expect(countFocusSettingReads('const { activeRuntimeEnvironmentId } = s')).toBe(1)
|
||||
expect(
|
||||
|
||||
@@ -31,6 +31,7 @@ import { translate } from '@/i18n/i18n'
|
||||
import { JiraIssueMetadataBar, JiraIssueWorkspaceHeader } from './jira-issue-workspace-chrome'
|
||||
import { JiraIssueCommentComposer, JiraIssueWorkspaceContent } from './jira-issue-workspace-content'
|
||||
import { getJiraIssueWorkspaceActions } from './jira-issue-workspace-actions'
|
||||
import { defaultScopeSource } from '@/lib/default-creation-host'
|
||||
|
||||
type JiraIssueWorkspaceProps = {
|
||||
issue: JiraIssue | null
|
||||
@@ -46,7 +47,7 @@ export default function JiraIssueWorkspace({
|
||||
sourceContext
|
||||
}: JiraIssueWorkspaceProps): React.JSX.Element {
|
||||
const settings = useAppStore((s) => s.settings)
|
||||
const providerSettings = sourceContext ?? settings
|
||||
const providerSettings = sourceContext ?? defaultScopeSource(settings)
|
||||
const patchJiraIssue = useAppStore((s) => s.patchJiraIssue)
|
||||
const [fullIssue, setFullIssue] = useState<JiraIssue | null>(null)
|
||||
const [issueLoading, setIssueLoading] = useState(false)
|
||||
|
||||
@@ -20,6 +20,7 @@ import {
|
||||
resolveLinearIssueTextDraftState
|
||||
} from './linear-issue-text-draft-state'
|
||||
import { translate } from '@/i18n/i18n'
|
||||
import { defaultScopeSource } from '@/lib/default-creation-host'
|
||||
|
||||
type LinearIssueTextEditorProps = {
|
||||
issue: LinearIssue
|
||||
@@ -37,7 +38,7 @@ export function LinearIssueTextEditor({
|
||||
sourceContext
|
||||
}: LinearIssueTextEditorProps): React.JSX.Element {
|
||||
const settings = useAppStore((s) => s.settings)
|
||||
const providerSettings = sourceContext ?? settings
|
||||
const providerSettings = sourceContext ?? defaultScopeSource(settings)
|
||||
const patchLinearIssue = useAppStore((s) => s.patchLinearIssue)
|
||||
const [draftState, setDraftState] = useState(() => createLinearIssueTextDraftState(issue))
|
||||
const [savingField, setSavingField] = useState<LinearIssueTextField | null>(null)
|
||||
|
||||
@@ -17,6 +17,7 @@ import { LinearIssueSubIssues } from './linear-issue-sub-issues'
|
||||
import { useLinearIssueWorkspaceDetail } from './linear-issue-workspace-detail-state'
|
||||
import { LinearIssueWorkspaceHeader } from './linear-issue-workspace-header'
|
||||
import { LinearIssueWorkspaceSidebar } from './linear-issue-workspace-sidebar'
|
||||
import { defaultScopeSource } from '@/lib/default-creation-host'
|
||||
|
||||
type LinearIssueWorkspaceProps = {
|
||||
issue: LinearIssue | null
|
||||
@@ -49,7 +50,7 @@ function LinearIssueWorkspaceIssue({
|
||||
requestKey
|
||||
}: LinearIssueWorkspaceIssueProps): React.JSX.Element {
|
||||
const settings = useAppStore((state) => state.settings)
|
||||
const providerSettings = sourceContext ?? settings
|
||||
const providerSettings = sourceContext ?? defaultScopeSource(settings)
|
||||
const allWorktrees = useAllWorktrees()
|
||||
const folderWorkspaces = useAppStore((state) => state.folderWorkspaces)
|
||||
const attachmentWorkspaces = useMemo(
|
||||
|
||||
@@ -16,6 +16,7 @@ import {
|
||||
type LinearLocalComment
|
||||
} from '@/components/linear-item-drawer-types'
|
||||
import { renderLinearItemDrawerSheet } from '@/components/linear-item-drawer-sheet'
|
||||
import { defaultScopeSource } from '@/lib/default-creation-host'
|
||||
|
||||
export { LinearIssueEditSection } from '@/components/linear-item-drawer-edit-section'
|
||||
export { LinearIssueCommentFooter } from '@/components/linear-item-drawer-comment-footer'
|
||||
@@ -37,7 +38,7 @@ export default function LinearItemDrawer({
|
||||
const hasEditedRef = useRef(false)
|
||||
const optimisticCommentsRef = useRef<LinearComment[]>([])
|
||||
const settings = useAppStore((s) => s.settings)
|
||||
const providerSettings = sourceContext ?? settings
|
||||
const providerSettings = sourceContext ?? defaultScopeSource(settings)
|
||||
const allWorktrees = useAllWorktrees()
|
||||
const folderWorkspaces = useAppStore((s) => s.folderWorkspaces)
|
||||
const attachmentWorkspaces = useMemo(
|
||||
|
||||
@@ -3,11 +3,9 @@ import { LoaderCircle } from 'lucide-react'
|
||||
|
||||
import { Input } from '@/components/ui/input'
|
||||
import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover'
|
||||
import { jiraSearchUsers } from '@/runtime/runtime-jira-client'
|
||||
import { jiraSearchUsers, type RuntimeJiraSettings } from '@/runtime/runtime-jira-client'
|
||||
import { translate } from '@/i18n/i18n'
|
||||
import type { GlobalSettings } from '../../../shared/global-settings-types'
|
||||
import type { JiraUser } from '../../../shared/jira-types'
|
||||
import type { TaskSourceContext } from '../../../shared/task-source-context'
|
||||
|
||||
const USER_SEARCH_DEBOUNCE_MS = 250
|
||||
|
||||
@@ -60,7 +58,7 @@ export function JiraUserPicker({
|
||||
fixedOptions,
|
||||
searchUsers
|
||||
}: {
|
||||
providerSettings: TaskSourceContext | GlobalSettings | null
|
||||
providerSettings: RuntimeJiraSettings
|
||||
siteId?: string | null
|
||||
value: string
|
||||
selectedUser: JiraUser | null
|
||||
|
||||
@@ -12,6 +12,7 @@ import { useAppStore } from '@/store'
|
||||
import type { LinearIssue } from '../../../shared/linear/issue-types'
|
||||
import type { LinearProjectSummary } from '../../../shared/linear/project-types'
|
||||
import type { TaskSourceContext } from '../../../shared/task-source-context'
|
||||
import { defaultScopeSource } from '@/lib/default-creation-host'
|
||||
|
||||
export function LinearIssueProjectSelector({
|
||||
issue,
|
||||
@@ -23,7 +24,7 @@ export function LinearIssueProjectSelector({
|
||||
sourceContext?: TaskSourceContext | null
|
||||
}): React.JSX.Element {
|
||||
const settings = useAppStore((state) => state.settings)
|
||||
const providerSettings = sourceContext ?? settings
|
||||
const providerSettings = sourceContext ?? defaultScopeSource(settings)
|
||||
const patchLinearIssue = useAppStore((state) => state.patchLinearIssue)
|
||||
const [open, setOpen] = useState(false)
|
||||
const [query, setQuery] = useState('')
|
||||
|
||||
@@ -11,6 +11,7 @@ import { linearCreateSubIssue } from '@/runtime/runtime-linear-issue-mutations'
|
||||
import { useAppStore } from '@/store'
|
||||
import type { LinearIssue, LinearIssueChildSummary } from '../../../shared/linear/issue-types'
|
||||
import type { TaskSourceContext } from '../../../shared/task-source-context'
|
||||
import { defaultScopeSource } from '@/lib/default-creation-host'
|
||||
|
||||
function mergeLinearSubIssues(
|
||||
serverSubIssues: LinearIssueChildSummary[] | undefined,
|
||||
@@ -34,7 +35,7 @@ export function LinearIssueSubIssues({
|
||||
sourceContext?: TaskSourceContext | null
|
||||
}): React.JSX.Element {
|
||||
const settings = useAppStore((state) => state.settings)
|
||||
const providerSettings = sourceContext ?? settings
|
||||
const providerSettings = sourceContext ?? defaultScopeSource(settings)
|
||||
const fetchLinearIssue = useAppStore((state) => state.fetchLinearIssue)
|
||||
const [open, setOpen] = useState(false)
|
||||
const [title, setTitle] = useState('')
|
||||
|
||||
@@ -15,6 +15,7 @@ import { linearAddIssueComment } from '@/runtime/runtime-linear-issue-mutations'
|
||||
import { translate } from '@/i18n/i18n'
|
||||
import type { TaskSourceContext } from '../../../shared/task-source-context'
|
||||
import type { LinearLocalComment } from '@/components/linear-item-drawer-types'
|
||||
import { defaultScopeSource } from '@/lib/default-creation-host'
|
||||
|
||||
export function LinearIssueCommentFooter({
|
||||
issueId,
|
||||
@@ -30,7 +31,7 @@ export function LinearIssueCommentFooter({
|
||||
sourceContext?: TaskSourceContext | null
|
||||
}): React.JSX.Element {
|
||||
const settings = useAppStore((s) => s.settings)
|
||||
const providerSettings = sourceContext ?? settings
|
||||
const providerSettings = sourceContext ?? defaultScopeSource(settings)
|
||||
const submitShortcutLabel = getScreenSubmitShortcutLabel()
|
||||
const [body, setBody] = useState('')
|
||||
const [submitting, setSubmitting] = useState(false)
|
||||
|
||||
@@ -12,6 +12,7 @@ import { linearUpdateIssue } from '@/runtime/runtime-linear-issue-mutations'
|
||||
import { translate } from '@/i18n/i18n'
|
||||
import { formatLinearEstimateInput } from '@/components/linear-item-drawer-edit-controls'
|
||||
import type { LinearIssueEditSectionProps } from '@/components/linear-item-drawer-types'
|
||||
import { defaultScopeSource } from '@/lib/default-creation-host'
|
||||
|
||||
export function useLinearIssueEditController({
|
||||
issue,
|
||||
@@ -24,7 +25,7 @@ export function useLinearIssueEditController({
|
||||
const [estimatePopoverOpen, setEstimatePopoverOpen] = useState(false)
|
||||
const patchLinearIssue = useAppStore((s) => s.patchLinearIssue)
|
||||
const settings = useAppStore((s) => s.settings)
|
||||
const providerSettings = sourceContext ?? settings
|
||||
const providerSettings = sourceContext ?? defaultScopeSource(settings)
|
||||
const { isPending, run } = useImmediateMutation()
|
||||
|
||||
const {
|
||||
|
||||
@@ -32,6 +32,7 @@ import {
|
||||
removeSettingsProjectFromAllHosts
|
||||
} from './settings-project-list'
|
||||
import { resolveSettingsHostScope, type SettingsHostChoice } from './settings-host-scope'
|
||||
import { defaultScopeHost } from '@/lib/default-creation-host'
|
||||
|
||||
export function useSettingsStoreModel() {
|
||||
const settings = useAppStore((s) => s.settings)
|
||||
@@ -148,7 +149,9 @@ export function useSettingsStoreModel() {
|
||||
// Why: session-only (deliberately not persisted) unlock — Option-click the Experimental page title reveals the hidden group.
|
||||
const [hiddenExperimentalUnlocked, setHiddenExperimentalUnlocked] = useState(false)
|
||||
const [settingsHostChoice, setSettingsHostChoice] = useState<SettingsHostChoice | null>(null)
|
||||
const defaultRuntimeEnvironmentId = settings?.activeRuntimeEnvironmentId
|
||||
const defaultScope = defaultScopeHost(settings)
|
||||
const defaultRuntimeEnvironmentId =
|
||||
defaultScope.kind === 'environment' ? defaultScope.environmentId : null
|
||||
// Why: keyed on ids so status-only catalog updates keep the scope (and its loads) stable.
|
||||
const savedEnvironmentIdsKey = runtimeEnvironments.map((environment) => environment.id).join('\n')
|
||||
// Why: the web client's only host is its server, so it never offers a choice.
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { useCallback } from 'react'
|
||||
import { toast } from 'sonner'
|
||||
import { useAppStore } from '@/store'
|
||||
import { getSettingsForWorktreeRuntimeOwner } from '@/lib/worktree-runtime-owner'
|
||||
import { runtimeTargetForWorkspaceOwner } from '@/lib/resolve-owner'
|
||||
import { translate } from '@/i18n/i18n'
|
||||
import type { WorkspaceStatus, Worktree } from '../../../../shared/worktree/types'
|
||||
import {
|
||||
@@ -131,7 +131,10 @@ export function useWorkspaceBoardTaskStatusSync(args: {
|
||||
targetStatus: request.targetStatus,
|
||||
worktreesById: args.worktreesById,
|
||||
getSettingsForWorktree: (worktreeId) =>
|
||||
getSettingsForWorktreeRuntimeOwner(useAppStore.getState(), worktreeId),
|
||||
// Why: a workspace no row places on a server is this computer's.
|
||||
runtimeTargetForWorkspaceOwner(useAppStore.getState(), { workspaceId: worktreeId }) ?? {
|
||||
kind: 'local'
|
||||
},
|
||||
getLatestWorkspaceStatus: (worktreeId) =>
|
||||
useAppStore.getState().getKnownWorktreeById(worktreeId)?.workspaceStatus
|
||||
})
|
||||
|
||||
@@ -85,7 +85,7 @@ function setup(overrides: Partial<Worktree> = {}) {
|
||||
worktreeIds: [item.id],
|
||||
targetStatus: target,
|
||||
worktreesById: new Map([[item.id, item]]),
|
||||
settings: { activeRuntimeEnvironmentId: 'runtime-1' },
|
||||
settings: { kind: 'environment', environmentId: 'runtime-1' },
|
||||
getLatestWorkspaceStatus: () => target.id,
|
||||
deps: { getIssue, teamStates, updateIssue }
|
||||
})
|
||||
@@ -99,17 +99,17 @@ describe('syncWorkspaceBoardTaskStatuses', () => {
|
||||
await expect(run()).resolves.toEqual({ updated: 1, skipped: 0, failed: 0, messages: [] })
|
||||
|
||||
expect(getIssue).toHaveBeenCalledWith(
|
||||
{ activeRuntimeEnvironmentId: 'runtime-1' },
|
||||
{ kind: 'environment', environmentId: 'runtime-1' },
|
||||
'ORC-1',
|
||||
'workspace-1'
|
||||
)
|
||||
expect(teamStates).toHaveBeenCalledWith(
|
||||
{ activeRuntimeEnvironmentId: 'runtime-1' },
|
||||
{ kind: 'environment', environmentId: 'runtime-1' },
|
||||
'team-1',
|
||||
'workspace-1'
|
||||
)
|
||||
expect(updateIssue).toHaveBeenCalledWith(
|
||||
{ activeRuntimeEnvironmentId: 'runtime-1' },
|
||||
{ kind: 'environment', environmentId: 'runtime-1' },
|
||||
'issue-1',
|
||||
{ stateId: 'state-review' },
|
||||
'workspace-1'
|
||||
@@ -126,15 +126,15 @@ describe('syncWorkspaceBoardTaskStatuses', () => {
|
||||
worktreeIds: [item.id],
|
||||
targetStatus: target,
|
||||
worktreesById: new Map([[item.id, item]]),
|
||||
settings: null,
|
||||
settings: { kind: 'local' },
|
||||
getLatestWorkspaceStatus: () => target.id,
|
||||
deps: { getIssue, teamStates, updateIssue }
|
||||
})
|
||||
|
||||
expect(getIssue).toHaveBeenCalledWith(null, 'ORC-1', undefined)
|
||||
expect(teamStates).toHaveBeenCalledWith(null, 'team-1', 'issue-workspace')
|
||||
expect(getIssue).toHaveBeenCalledWith({ kind: 'local' }, 'ORC-1', undefined)
|
||||
expect(teamStates).toHaveBeenCalledWith({ kind: 'local' }, 'team-1', 'issue-workspace')
|
||||
expect(updateIssue).toHaveBeenCalledWith(
|
||||
null,
|
||||
{ kind: 'local' },
|
||||
'issue-1',
|
||||
{ stateId: 'state-review' },
|
||||
'issue-workspace'
|
||||
@@ -152,7 +152,8 @@ describe('syncWorkspaceBoardTaskStatuses', () => {
|
||||
const teamStates = vi.fn().mockResolvedValue([state()])
|
||||
const updateIssue = vi.fn<() => Promise<LinearMutationResult>>().mockResolvedValue({ ok: true })
|
||||
const getSettingsForWorktree = vi.fn((worktreeId: string) => ({
|
||||
activeRuntimeEnvironmentId: worktreeId.startsWith('repo-a') ? 'runtime-a' : 'runtime-b'
|
||||
kind: 'environment' as const,
|
||||
environmentId: worktreeId.startsWith('repo-a') ? 'runtime-a' : 'runtime-b'
|
||||
}))
|
||||
|
||||
await syncWorkspaceBoardTaskStatuses({
|
||||
@@ -162,7 +163,7 @@ describe('syncWorkspaceBoardTaskStatuses', () => {
|
||||
[first.id, first],
|
||||
[second.id, second]
|
||||
]),
|
||||
settings: { activeRuntimeEnvironmentId: 'focused-runtime' },
|
||||
settings: { kind: 'environment', environmentId: 'focused-runtime' },
|
||||
getSettingsForWorktree,
|
||||
getLatestWorkspaceStatus: () => target.id,
|
||||
deps: { getIssue, teamStates, updateIssue }
|
||||
@@ -172,51 +173,51 @@ describe('syncWorkspaceBoardTaskStatuses', () => {
|
||||
expect(getSettingsForWorktree).toHaveBeenCalledWith(second.id)
|
||||
expect(getIssue).toHaveBeenNthCalledWith(
|
||||
1,
|
||||
{ activeRuntimeEnvironmentId: 'runtime-a' },
|
||||
{ kind: 'environment', environmentId: 'runtime-a' },
|
||||
'ORC-1',
|
||||
'workspace-1'
|
||||
)
|
||||
expect(getIssue).toHaveBeenNthCalledWith(
|
||||
2,
|
||||
{ activeRuntimeEnvironmentId: 'runtime-b' },
|
||||
{ kind: 'environment', environmentId: 'runtime-b' },
|
||||
'ORC-2',
|
||||
'workspace-1'
|
||||
)
|
||||
expect(updateIssue).toHaveBeenNthCalledWith(
|
||||
1,
|
||||
{ activeRuntimeEnvironmentId: 'runtime-a' },
|
||||
{ kind: 'environment', environmentId: 'runtime-a' },
|
||||
'issue-1',
|
||||
{ stateId: 'state-review' },
|
||||
'workspace-1'
|
||||
)
|
||||
expect(updateIssue).toHaveBeenNthCalledWith(
|
||||
2,
|
||||
{ activeRuntimeEnvironmentId: 'runtime-b' },
|
||||
{ kind: 'environment', environmentId: 'runtime-b' },
|
||||
'issue-2',
|
||||
{ stateId: 'state-review' },
|
||||
'workspace-1'
|
||||
)
|
||||
})
|
||||
|
||||
it('preserves null settings from the moved worktree resolver', async () => {
|
||||
it('uses this computer when the moved worktree resolver names it', async () => {
|
||||
const { item, target, getIssue, teamStates, updateIssue } = setup()
|
||||
const getSettingsForWorktree = vi.fn(() => null)
|
||||
const getSettingsForWorktree = vi.fn(() => ({ kind: 'local' as const }))
|
||||
|
||||
await syncWorkspaceBoardTaskStatuses({
|
||||
worktreeIds: [item.id],
|
||||
targetStatus: target,
|
||||
worktreesById: new Map([[item.id, item]]),
|
||||
settings: { activeRuntimeEnvironmentId: 'focused-runtime' },
|
||||
settings: { kind: 'environment', environmentId: 'focused-runtime' },
|
||||
getSettingsForWorktree,
|
||||
getLatestWorkspaceStatus: () => target.id,
|
||||
deps: { getIssue, teamStates, updateIssue }
|
||||
})
|
||||
|
||||
expect(getSettingsForWorktree).toHaveBeenCalledWith(item.id)
|
||||
expect(getIssue).toHaveBeenCalledWith(null, 'ORC-1', 'workspace-1')
|
||||
expect(teamStates).toHaveBeenCalledWith(null, 'team-1', 'workspace-1')
|
||||
expect(getIssue).toHaveBeenCalledWith({ kind: 'local' }, 'ORC-1', 'workspace-1')
|
||||
expect(teamStates).toHaveBeenCalledWith({ kind: 'local' }, 'team-1', 'workspace-1')
|
||||
expect(updateIssue).toHaveBeenCalledWith(
|
||||
null,
|
||||
{ kind: 'local' },
|
||||
'issue-1',
|
||||
{ stateId: 'state-review' },
|
||||
'workspace-1'
|
||||
@@ -230,7 +231,7 @@ describe('syncWorkspaceBoardTaskStatuses', () => {
|
||||
worktreeIds: [item.id],
|
||||
targetStatus: target,
|
||||
worktreesById: new Map([[item.id, item]]),
|
||||
settings: null,
|
||||
settings: { kind: 'local' },
|
||||
getLatestWorkspaceStatus: () => target.id,
|
||||
deps: { getIssue, teamStates, updateIssue }
|
||||
})
|
||||
@@ -286,7 +287,7 @@ describe('syncWorkspaceBoardTaskStatuses', () => {
|
||||
worktreeIds: [item.id],
|
||||
targetStatus: target,
|
||||
worktreesById: new Map([[item.id, item]]),
|
||||
settings: null,
|
||||
settings: { kind: 'local' },
|
||||
getLatestWorkspaceStatus: () => 'done',
|
||||
deps: { getIssue, teamStates, updateIssue }
|
||||
})
|
||||
@@ -312,7 +313,7 @@ describe('syncWorkspaceBoardTaskStatuses', () => {
|
||||
worktreeIds: [item.id],
|
||||
targetStatus: targetStatus(),
|
||||
worktreesById: new Map([[item.id, item]]),
|
||||
settings: null,
|
||||
settings: { kind: 'local' },
|
||||
getLatestWorkspaceStatus: () => 'in-review',
|
||||
deps: { getIssue, teamStates, updateIssue }
|
||||
})
|
||||
@@ -323,7 +324,7 @@ describe('syncWorkspaceBoardTaskStatuses', () => {
|
||||
worktreeIds: [item.id],
|
||||
targetStatus: targetStatus({ id: 'done', label: 'Done' }),
|
||||
worktreesById: new Map([[item.id, item]]),
|
||||
settings: null,
|
||||
settings: { kind: 'local' },
|
||||
getLatestWorkspaceStatus: () => 'done',
|
||||
deps: { getIssue, teamStates, updateIssue }
|
||||
})
|
||||
@@ -336,14 +337,14 @@ describe('syncWorkspaceBoardTaskStatuses', () => {
|
||||
|
||||
expect(updateIssue).toHaveBeenNthCalledWith(
|
||||
1,
|
||||
null,
|
||||
{ kind: 'local' },
|
||||
'issue-1',
|
||||
{ stateId: 'state-review' },
|
||||
'workspace-1'
|
||||
)
|
||||
expect(updateIssue).toHaveBeenNthCalledWith(
|
||||
2,
|
||||
null,
|
||||
{ kind: 'local' },
|
||||
'issue-1',
|
||||
{ stateId: 'state-done' },
|
||||
'workspace-1'
|
||||
|
||||
@@ -177,9 +177,10 @@ async function syncLinearWorktreeStatus(
|
||||
return skipped(result)
|
||||
}
|
||||
|
||||
const settings = args.getSettingsForWorktree
|
||||
// Why: no source has always meant this computer.
|
||||
const settings = (args.getSettingsForWorktree
|
||||
? args.getSettingsForWorktree(worktreeId)
|
||||
: args.settings
|
||||
: args.settings) ?? { kind: 'local' }
|
||||
const linkedWorkspaceId = worktree.linkedLinearIssueWorkspaceId ?? undefined
|
||||
|
||||
try {
|
||||
|
||||
@@ -8,7 +8,7 @@ import {
|
||||
import { useAppStore } from '../../store'
|
||||
import type { ClaudeRateLimitAccountsState } from '../../../../shared/managed-account-types'
|
||||
import type { ProviderRateLimits } from '../../../../shared/rate-limit-types'
|
||||
import { getActiveRuntimeTarget } from '@/runtime/runtime-rpc-client'
|
||||
import { defaultScopeHost } from '@/lib/default-creation-host'
|
||||
import {
|
||||
fetchProviderAccountsSnapshot,
|
||||
selectClaudeProviderAccount
|
||||
@@ -81,7 +81,8 @@ export function ClaudeSwitcherMenu({
|
||||
const settings = useAppStore((s) => s.settings)
|
||||
const runtimeEnvironments = useAppStore((s) => s.runtimeEnvironments)
|
||||
const hasActiveRuntimeEnvironment = Boolean(settings?.activeRuntimeEnvironmentId?.trim())
|
||||
const runtimeTarget = useMemo(() => getActiveRuntimeTarget(settings), [settings])
|
||||
// Why: the status bar has no host picker; it shows the default scope host's accounts.
|
||||
const runtimeTarget = useMemo(() => defaultScopeHost(settings), [settings])
|
||||
const providerAccountHostLabel = hasActiveRuntimeEnvironment
|
||||
? (runtimeEnvironments.find(
|
||||
(environment) => environment.id === settings?.activeRuntimeEnvironmentId?.trim()
|
||||
|
||||
@@ -2,7 +2,7 @@ import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
|
||||
import type { CodexRateLimitAccountsState } from '../../../../shared/managed-account-types'
|
||||
import type { ProviderRateLimits } from '../../../../shared/rate-limit-types'
|
||||
import { useAppStore } from '../../store'
|
||||
import { getActiveRuntimeTarget } from '@/runtime/runtime-rpc-client'
|
||||
import { defaultScopeHost } from '@/lib/default-creation-host'
|
||||
import {
|
||||
fetchProviderAccountsSnapshot,
|
||||
selectCodexProviderAccount
|
||||
@@ -68,7 +68,8 @@ export function useCodexSwitcherController(codex: ProviderRateLimits) {
|
||||
const settings = useAppStore((s) => s.settings)
|
||||
const runtimeEnvironments = useAppStore((s) => s.runtimeEnvironments)
|
||||
const hasActiveRuntimeEnvironment = Boolean(settings?.activeRuntimeEnvironmentId?.trim())
|
||||
const runtimeTarget = useMemo(() => getActiveRuntimeTarget(settings), [settings])
|
||||
// Why: the status bar has no host picker; it shows the default scope host's accounts.
|
||||
const runtimeTarget = useMemo(() => defaultScopeHost(settings), [settings])
|
||||
const providerAccountHostLabel = hasActiveRuntimeEnvironment
|
||||
? (runtimeEnvironments.find(
|
||||
(environment) => environment.id === settings?.activeRuntimeEnvironmentId?.trim()
|
||||
|
||||
@@ -159,7 +159,9 @@ describe('Jira issue status grouping', () => {
|
||||
throw new Error('Expected one Jira project scope')
|
||||
}
|
||||
|
||||
await expect(loadTaskPageJiraProjectStatusOrder(null, 'runtime:old', scope)).resolves.toEqual({
|
||||
await expect(
|
||||
loadTaskPageJiraProjectStatusOrder({ kind: 'local' }, 'runtime:old', scope)
|
||||
).resolves.toEqual({
|
||||
statusIdsByColumn: []
|
||||
})
|
||||
expect(warn).toHaveBeenCalledWith('[jira] Failed to load project status order:', error)
|
||||
|
||||
@@ -18,6 +18,7 @@ import {
|
||||
getLinearStateMarkerStyle
|
||||
} from '@/components/linear-state-pill-style'
|
||||
import { LoaderCircle, ChevronDown } from 'lucide-react'
|
||||
import { defaultScopeSource } from '@/lib/default-creation-host'
|
||||
export type LinearProjectTab = 'overview' | 'issues'
|
||||
export type LinearGroupSection = {
|
||||
key: string
|
||||
@@ -84,7 +85,7 @@ export function LinearStateCell({
|
||||
sourceContext?: TaskSourceContext | null
|
||||
}): React.JSX.Element {
|
||||
const settings = useAppStore((s) => s.settings)
|
||||
const providerSettings = sourceContext ?? settings
|
||||
const providerSettings = sourceContext ?? defaultScopeSource(settings)
|
||||
const patchLinearIssue = useAppStore((s) => s.patchLinearIssue)
|
||||
const states = useTeamStates(issue.team.id, providerSettings, issue.workspaceId)
|
||||
const [open, setOpen] = useState(false)
|
||||
|
||||
@@ -31,7 +31,12 @@ it('drops old provider candidates before another host with identical project IDs
|
||||
fireEvent.click(screen.getByRole('button', { name: 'Assignee' }))
|
||||
await screen.findByRole('button', { name: 'Local user' })
|
||||
expect(screen.getByRole('button', { name: 'Assign to me (Local me)' })).toBeTruthy()
|
||||
expect(search).toHaveBeenCalledWith(null, 'PRJ', '', 'same-site')
|
||||
expect(search).toHaveBeenCalledWith(
|
||||
{ kind: 'default-scope', settings: null },
|
||||
'PRJ',
|
||||
'',
|
||||
'same-site'
|
||||
)
|
||||
|
||||
search.mockReturnValueOnce(new Promise(() => {}))
|
||||
rerender(
|
||||
|
||||
@@ -6,6 +6,7 @@ import { hasJiraAssigneeCreateField } from '@/components/task-page-jira-create-f
|
||||
import { getJiraProjectSelectionKey } from '@/components/task-page-jira-project-selection'
|
||||
import { jiraListAssignableUsersForProject } from '@/runtime/runtime-jira-client'
|
||||
import { translate } from '@/i18n/i18n'
|
||||
import { defaultScopeSource } from '@/lib/default-creation-host'
|
||||
|
||||
export function TaskPageJiraIssueAssigneeField({
|
||||
model
|
||||
@@ -34,7 +35,7 @@ export function TaskPageJiraIssueAssigneeField({
|
||||
setNewJiraIssueAssignee,
|
||||
newJiraIssueSubmitting
|
||||
} = model
|
||||
const providerSettings = jiraTaskSourceContext ?? settings
|
||||
const providerSettings = jiraTaskSourceContext ?? defaultScopeSource(settings)
|
||||
const projectKey = newJiraIssueTargetProject?.key
|
||||
const projectSiteId = newJiraIssueTargetProject?.siteId
|
||||
const searchAssignableUsers = useCallback(
|
||||
|
||||
@@ -8,6 +8,7 @@ import { Plus, LoaderCircle, RefreshCw, Search, X } from 'lucide-react'
|
||||
import LinearIssueAttributeFilterDropdowns from '@/components/linear-issue-attribute-filter-dropdowns'
|
||||
import { Input } from '@/components/ui/input'
|
||||
import { shouldSuppressEnterSubmit } from '@/lib/new-workspace-enter-guard'
|
||||
import { defaultScopeSource } from '@/lib/default-creation-host'
|
||||
export function TaskPageLinearFilters({
|
||||
model
|
||||
}: {
|
||||
@@ -215,7 +216,7 @@ export function TaskPageLinearFilters({
|
||||
selectedTeamIds={[...linearTeamSelection]}
|
||||
availableTeams={linearTeamOptions}
|
||||
teamsSettled={availableTeams.length > 0}
|
||||
settings={linearTaskSourceContext ?? settings}
|
||||
settings={linearTaskSourceContext ?? defaultScopeSource(settings)}
|
||||
/>
|
||||
) : null}
|
||||
<div className="relative min-w-0 flex-1 basis-64">
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
import { useEffect, useState } from 'react'
|
||||
import type { GlobalSettings } from '../../../shared/global-settings-types'
|
||||
import type { LinearProjectSummary } from '../../../shared/linear/project-types'
|
||||
import type { TaskSourceContext } from '../../../shared/task-source-context'
|
||||
import { defaultScopeSource } from '@/lib/default-creation-host'
|
||||
import { linearListProjects } from '@/runtime/runtime-linear-project-client'
|
||||
|
||||
/** Projects offered by the new Linear issue dialog for its target team. */
|
||||
export function useNewLinearIssueProjects(args: {
|
||||
open: boolean
|
||||
targetTeam: { workspaceId?: string | null } | null
|
||||
selectedLinearWorkspaceId: string
|
||||
linearTaskSourceContext: TaskSourceContext | null
|
||||
settings: Pick<GlobalSettings, 'activeRuntimeEnvironmentId'> | null
|
||||
}) {
|
||||
const { open, targetTeam, selectedLinearWorkspaceId, linearTaskSourceContext, settings } = args
|
||||
const [newLinearIssueProjects, setNewLinearIssueProjects] = useState<LinearProjectSummary[]>([])
|
||||
const [newLinearIssueProjectsLoading, setNewLinearIssueProjectsLoading] = useState(false)
|
||||
useEffect(() => {
|
||||
let cancelled = false
|
||||
if (!open || !targetTeam) {
|
||||
setNewLinearIssueProjects([])
|
||||
setNewLinearIssueProjectsLoading(false)
|
||||
return
|
||||
}
|
||||
setNewLinearIssueProjectsLoading(true)
|
||||
const targetWorkspaceId =
|
||||
targetTeam.workspaceId ||
|
||||
(selectedLinearWorkspaceId !== 'all' ? selectedLinearWorkspaceId : null)
|
||||
// Why: with no Tasks source chosen, the list comes from the default scope host.
|
||||
const source = linearTaskSourceContext ?? defaultScopeSource(settings)
|
||||
linearListProjects(source, undefined, 100, targetWorkspaceId)
|
||||
.then((p) => {
|
||||
if (!cancelled) {
|
||||
setNewLinearIssueProjects(p.items)
|
||||
}
|
||||
})
|
||||
.catch(() => {})
|
||||
.finally(() => {
|
||||
if (!cancelled) {
|
||||
setNewLinearIssueProjectsLoading(false)
|
||||
}
|
||||
})
|
||||
return () => {
|
||||
// Why: project lists are workspace-scoped; stale responses must not populate the composer after a team/workspace switch.
|
||||
cancelled = true
|
||||
}
|
||||
}, [open, targetTeam, linearTaskSourceContext, settings, selectedLinearWorkspaceId])
|
||||
return {
|
||||
newLinearIssueProjects,
|
||||
setNewLinearIssueProjects,
|
||||
newLinearIssueProjectsLoading,
|
||||
setNewLinearIssueProjectsLoading
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@ import { useEffect } from 'react'
|
||||
import { jiraListIssueTypes, jiraListCreateFields } from '@/runtime/runtime-jira-client'
|
||||
import { toast } from 'sonner'
|
||||
import { translate } from '@/i18n/i18n'
|
||||
import { defaultScopeSource } from '@/lib/default-creation-host'
|
||||
export function useTaskPageJiraCreationMetadata(model: TaskPageJiraCreationStateModel) {
|
||||
const {
|
||||
settings,
|
||||
@@ -29,7 +30,7 @@ export function useTaskPageJiraCreationMetadata(model: TaskPageJiraCreationState
|
||||
setAvailableJiraIssueTypes([])
|
||||
setJiraIssueTypesLoading(true)
|
||||
void jiraListIssueTypes(
|
||||
jiraTaskSourceContext ?? settings,
|
||||
jiraTaskSourceContext ?? defaultScopeSource(settings),
|
||||
newJiraIssueTargetProject.id,
|
||||
newJiraIssueTargetProject.siteId
|
||||
)
|
||||
@@ -84,7 +85,7 @@ export function useTaskPageJiraCreationMetadata(model: TaskPageJiraCreationState
|
||||
setJiraCreateFieldsError(null)
|
||||
setNewJiraIssueCustomFieldValues({})
|
||||
void jiraListCreateFields(
|
||||
jiraTaskSourceContext ?? settings,
|
||||
jiraTaskSourceContext ?? defaultScopeSource(settings),
|
||||
newJiraIssueTargetProject.id,
|
||||
newJiraIssueTargetType.id,
|
||||
newJiraIssueTargetProject.siteId
|
||||
|
||||
@@ -7,6 +7,7 @@ import {
|
||||
import { jiraCreateIssue, jiraGetIssue } from '@/runtime/runtime-jira-client'
|
||||
import { toast } from 'sonner'
|
||||
import { translate } from '@/i18n/i18n'
|
||||
import { defaultScopeSource } from '@/lib/default-creation-host'
|
||||
export function useTaskPageJiraIssueCreation(model: TaskPageLinearIssueCreationModel) {
|
||||
const {
|
||||
settings,
|
||||
@@ -53,7 +54,7 @@ export function useTaskPageJiraIssueCreation(model: TaskPageLinearIssueCreationM
|
||||
setNewJiraIssueSubmitting(true)
|
||||
const submitProviderRuntimeContextKey = providerRuntimeContextKey
|
||||
try {
|
||||
const result = await jiraCreateIssue(jiraTaskSourceContext ?? settings, {
|
||||
const result = await jiraCreateIssue(jiraTaskSourceContext ?? defaultScopeSource(settings), {
|
||||
siteId: newJiraIssueTargetProject.siteId,
|
||||
projectId: newJiraIssueTargetProject.id,
|
||||
issueTypeId: newJiraIssueTargetType.id,
|
||||
@@ -93,7 +94,7 @@ export function useTaskPageJiraIssueCreation(model: TaskPageLinearIssueCreationM
|
||||
setNewJiraIssueAssignee(null)
|
||||
setJiraRefreshNonce((n) => n + 1)
|
||||
void jiraGetIssue(
|
||||
jiraTaskSourceContext ?? settings,
|
||||
jiraTaskSourceContext ?? defaultScopeSource(settings),
|
||||
result.key,
|
||||
newJiraIssueTargetProject.siteId
|
||||
)
|
||||
|
||||
@@ -8,6 +8,7 @@ import {
|
||||
import { createTaskPageJiraLoadFailureState } from '@/components/task-page-jira-load-state'
|
||||
import { searchTaskPageJiraIssues } from '@/components/task-page-jira-search'
|
||||
import { JIRA_ITEM_LIMIT, TASK_SEARCH_DEBOUNCE_MS } from './task-page-source-context'
|
||||
import { defaultScopeSource } from '@/lib/default-creation-host'
|
||||
export function useTaskPageJiraListEffects(model: TaskPageLinearCollectionEffectsModel) {
|
||||
const {
|
||||
settings,
|
||||
@@ -107,7 +108,7 @@ export function useTaskPageJiraListEffects(model: TaskPageLinearCollectionEffect
|
||||
projectScope
|
||||
)
|
||||
void loadTaskPageJiraProjectStatusOrder(
|
||||
jiraTaskSourceContext ?? settings,
|
||||
jiraTaskSourceContext ?? defaultScopeSource(settings),
|
||||
jiraTaskSourceScopeKey,
|
||||
projectScope
|
||||
).then((order) => {
|
||||
|
||||
@@ -10,6 +10,7 @@ import type {
|
||||
JiraPrioritiesBySite
|
||||
} from './jira-issue-sorter'
|
||||
import { jiraListPriorities } from '@/runtime/runtime-jira-client'
|
||||
import { defaultScopeSource } from '@/lib/default-creation-host'
|
||||
export function useTaskPageJiraListState(model: TaskPageLinearViewStateModel) {
|
||||
const { settings, jiraConnected, selectedJiraSiteId, taskSource, jiraTaskSourceContext } = model
|
||||
// Jira tab state
|
||||
@@ -51,7 +52,7 @@ export function useTaskPageJiraListState(model: TaskPageLinearViewStateModel) {
|
||||
try {
|
||||
return [
|
||||
siteId,
|
||||
await jiraListPriorities(jiraTaskSourceContext ?? settings, siteId)
|
||||
await jiraListPriorities(jiraTaskSourceContext ?? defaultScopeSource(settings), siteId)
|
||||
] as const
|
||||
} catch {
|
||||
return [siteId, [] as JiraPriority[]] as const
|
||||
|
||||
@@ -17,6 +17,7 @@ import {
|
||||
findLinearWorkflowStateForStatus,
|
||||
getLinearStatusSectionState
|
||||
} from './task-page-linear-issue-model'
|
||||
import { defaultScopeSource } from '@/lib/default-creation-host'
|
||||
export function useTaskPageLinearBoard(model: TaskPageLinearListProjectionModel) {
|
||||
const {
|
||||
settings,
|
||||
@@ -114,7 +115,7 @@ export function useTaskPageLinearBoard(model: TaskPageLinearListProjectionModel)
|
||||
}
|
||||
try {
|
||||
const states = await linearTeamStates(
|
||||
linearTaskSourceContext ?? settings,
|
||||
linearTaskSourceContext ?? defaultScopeSource(settings),
|
||||
issue.team.id,
|
||||
issue.workspaceId
|
||||
)
|
||||
@@ -151,7 +152,7 @@ export function useTaskPageLinearBoard(model: TaskPageLinearListProjectionModel)
|
||||
})
|
||||
applyFallbackState(nextState)
|
||||
const result = await linearUpdateIssue(
|
||||
linearTaskSourceContext ?? settings,
|
||||
linearTaskSourceContext ?? defaultScopeSource(settings),
|
||||
issue.id,
|
||||
{
|
||||
stateId: workflowState.id
|
||||
|
||||
@@ -2,10 +2,10 @@ import type { TaskPageJiraListProjectionModel } from './use-task-page-jira-list-
|
||||
import { useState, useMemo, useEffect, type SetStateAction } from 'react'
|
||||
import { useTeamMembers, useTeamLabels, useTeamStates } from '@/hooks/useIssueMetadata'
|
||||
import { useTaskCreationDraftRetention } from '@/components/use-task-creation-draft-retention'
|
||||
import type { LinearProjectSummary } from '../../../shared/linear/project-types'
|
||||
import { linearListProjects } from '@/runtime/runtime-linear-project-client'
|
||||
import { useNewLinearIssueProjects } from './use-new-linear-issue-projects'
|
||||
import { useContextualTour } from '@/components/contextual-tours/use-contextual-tour'
|
||||
import { writeNewLinearIssueDraft, writeNewLinearProjectDraft } from './task-page-draft-storage'
|
||||
import { defaultScopeSource } from '@/lib/default-creation-host'
|
||||
export function useTaskPageLinearCreationState(model: TaskPageJiraListProjectionModel) {
|
||||
const {
|
||||
settings,
|
||||
@@ -39,12 +39,12 @@ export function useTaskPageLinearCreationState(model: TaskPageJiraListProjection
|
||||
)
|
||||
const newLinearProjectMembers = useTeamMembers(
|
||||
newLinearProjectOpen ? (newLinearProjectTargetTeam?.id ?? null) : null,
|
||||
settings,
|
||||
defaultScopeSource(settings),
|
||||
newLinearProjectTargetTeam?.workspaceId
|
||||
)
|
||||
const newLinearProjectLabels = useTeamLabels(
|
||||
newLinearProjectOpen ? (newLinearProjectTargetTeam?.id ?? null) : null,
|
||||
settings,
|
||||
defaultScopeSource(settings),
|
||||
newLinearProjectTargetTeam?.workspaceId
|
||||
)
|
||||
const setNewLinearProjectTeamId = (id: string | null): void => {
|
||||
@@ -86,43 +86,18 @@ export function useTaskPageLinearCreationState(model: TaskPageJiraListProjection
|
||||
() => availableTeams.find((t) => t.id === newLinearIssueTeamId) ?? availableTeams[0] ?? null,
|
||||
[availableTeams, newLinearIssueTeamId]
|
||||
)
|
||||
const [newLinearIssueProjects, setNewLinearIssueProjects] = useState<LinearProjectSummary[]>([])
|
||||
const [newLinearIssueProjectsLoading, setNewLinearIssueProjectsLoading] = useState(false)
|
||||
useEffect(() => {
|
||||
let cancelled = false
|
||||
if (!newLinearIssueOpen || !linearConnected || !newLinearIssueTargetTeam) {
|
||||
setNewLinearIssueProjects([])
|
||||
setNewLinearIssueProjectsLoading(false)
|
||||
return
|
||||
}
|
||||
setNewLinearIssueProjectsLoading(true)
|
||||
const targetWorkspaceId =
|
||||
newLinearIssueTargetTeam.workspaceId ||
|
||||
(selectedLinearWorkspaceId !== 'all' ? selectedLinearWorkspaceId : null)
|
||||
linearListProjects(linearTaskSourceContext ?? settings, undefined, 100, targetWorkspaceId)
|
||||
.then((p) => {
|
||||
if (!cancelled) {
|
||||
setNewLinearIssueProjects(p.items)
|
||||
}
|
||||
})
|
||||
.catch(() => {})
|
||||
.finally(() => {
|
||||
if (!cancelled) {
|
||||
setNewLinearIssueProjectsLoading(false)
|
||||
}
|
||||
})
|
||||
return () => {
|
||||
// Why: project lists are workspace-scoped; stale responses must not populate the composer after a team/workspace switch.
|
||||
cancelled = true
|
||||
}
|
||||
}, [
|
||||
linearConnected,
|
||||
newLinearIssueOpen,
|
||||
newLinearIssueTargetTeam,
|
||||
const {
|
||||
newLinearIssueProjects,
|
||||
setNewLinearIssueProjects,
|
||||
newLinearIssueProjectsLoading,
|
||||
setNewLinearIssueProjectsLoading
|
||||
} = useNewLinearIssueProjects({
|
||||
open: newLinearIssueOpen && linearConnected,
|
||||
targetTeam: newLinearIssueTargetTeam,
|
||||
selectedLinearWorkspaceId,
|
||||
linearTaskSourceContext,
|
||||
settings,
|
||||
selectedLinearWorkspaceId
|
||||
])
|
||||
settings
|
||||
})
|
||||
const setNewLinearIssueTeamId = (value: SetStateAction<string | null>): void => {
|
||||
const id = typeof value === 'function' ? value(newLinearIssueTeamId) : value
|
||||
setNewLinearIssueTeamIdState(id)
|
||||
@@ -139,17 +114,17 @@ export function useTaskPageLinearCreationState(model: TaskPageJiraListProjection
|
||||
}
|
||||
const newLinearStates = useTeamStates(
|
||||
linearConnected ? newLinearIssueTargetTeam?.id || null : null,
|
||||
settings,
|
||||
defaultScopeSource(settings),
|
||||
newLinearIssueTargetTeam?.workspaceId
|
||||
)
|
||||
const newLinearMembers = useTeamMembers(
|
||||
linearConnected ? newLinearIssueTargetTeam?.id || null : null,
|
||||
settings,
|
||||
defaultScopeSource(settings),
|
||||
newLinearIssueTargetTeam?.workspaceId
|
||||
)
|
||||
const newLinearLabels = useTeamLabels(
|
||||
linearConnected ? newLinearIssueTargetTeam?.id || null : null,
|
||||
settings,
|
||||
defaultScopeSource(settings),
|
||||
newLinearIssueTargetTeam?.workspaceId
|
||||
)
|
||||
useEffect(() => {
|
||||
|
||||
@@ -4,6 +4,7 @@ import { toast } from 'sonner'
|
||||
import { translate } from '@/i18n/i18n'
|
||||
import { linearCreateIssue, linearGetIssue } from '@/runtime/runtime-linear-issue-mutations'
|
||||
import { useAppStore } from '@/store'
|
||||
import { defaultScopeSource } from '@/lib/default-creation-host'
|
||||
export function useTaskPageLinearIssueCreation(model: TaskPageLinearProjectCreationModel) {
|
||||
const {
|
||||
settings,
|
||||
@@ -57,17 +58,20 @@ export function useTaskPageLinearIssueCreation(model: TaskPageLinearProjectCreat
|
||||
setNewLinearIssueSubmitting(true)
|
||||
const submitProviderRuntimeContextKey = providerRuntimeContextKey
|
||||
try {
|
||||
const result = await linearCreateIssue(linearTaskSourceContext ?? settings, {
|
||||
teamId: newLinearIssueTargetTeam.id,
|
||||
title,
|
||||
description: newLinearIssueBody || undefined,
|
||||
workspaceId: newLinearIssueTargetTeam.workspaceId,
|
||||
stateId: newLinearIssueStateId || undefined,
|
||||
priority: newLinearIssuePriority,
|
||||
assigneeId: newLinearIssueAssigneeId || undefined,
|
||||
projectId: newLinearIssueProjectId || null,
|
||||
labelIds: newLinearIssueLabelIds.length > 0 ? newLinearIssueLabelIds : undefined
|
||||
})
|
||||
const result = await linearCreateIssue(
|
||||
linearTaskSourceContext ?? defaultScopeSource(settings),
|
||||
{
|
||||
teamId: newLinearIssueTargetTeam.id,
|
||||
title,
|
||||
description: newLinearIssueBody || undefined,
|
||||
workspaceId: newLinearIssueTargetTeam.workspaceId,
|
||||
stateId: newLinearIssueStateId || undefined,
|
||||
priority: newLinearIssuePriority,
|
||||
assigneeId: newLinearIssueAssigneeId || undefined,
|
||||
projectId: newLinearIssueProjectId || null,
|
||||
labelIds: newLinearIssueLabelIds.length > 0 ? newLinearIssueLabelIds : undefined
|
||||
}
|
||||
)
|
||||
if (submitProviderRuntimeContextKey !== providerRuntimeContextKeyRef.current) {
|
||||
return
|
||||
}
|
||||
@@ -105,7 +109,7 @@ export function useTaskPageLinearIssueCreation(model: TaskPageLinearProjectCreat
|
||||
|
||||
// Why: auto-select the new issue so the user sees exactly what was filed (mirrors the GitHub create-issue flow).
|
||||
void linearGetIssue(
|
||||
linearTaskSourceContext ?? settings,
|
||||
linearTaskSourceContext ?? defaultScopeSource(settings),
|
||||
result.id,
|
||||
newLinearIssueTargetTeam.workspaceId
|
||||
)
|
||||
|
||||
@@ -3,6 +3,7 @@ import { useCallback } from 'react'
|
||||
import { linearCreateProject } from '@/runtime/runtime-linear-project-client'
|
||||
import { toast } from 'sonner'
|
||||
import { translate } from '@/i18n/i18n'
|
||||
import { defaultScopeSource } from '@/lib/default-creation-host'
|
||||
export function useTaskPageLinearProjectCreation(model: TaskPageGitHubIssueCreationModel) {
|
||||
const {
|
||||
settings,
|
||||
@@ -47,19 +48,22 @@ export function useTaskPageLinearProjectCreation(model: TaskPageGitHubIssueCreat
|
||||
}
|
||||
setNewLinearProjectSubmitting(true)
|
||||
try {
|
||||
const result = await linearCreateProject(linearTaskSourceContext ?? settings, {
|
||||
name,
|
||||
description: newLinearProjectDescription.trim() || undefined,
|
||||
content: newLinearProjectContent.trim() || undefined,
|
||||
teamIds: [newLinearProjectTargetTeam.id],
|
||||
workspaceId: newLinearProjectTargetTeam.workspaceId,
|
||||
leadId: newLinearProjectLeadId || undefined,
|
||||
memberIds: newLinearProjectMemberIds.length > 0 ? newLinearProjectMemberIds : undefined,
|
||||
labelIds: newLinearProjectLabelIds.length > 0 ? newLinearProjectLabelIds : undefined,
|
||||
priority: newLinearProjectPriority,
|
||||
startDate: newLinearProjectStartDate || undefined,
|
||||
targetDate: newLinearProjectTargetDate || undefined
|
||||
})
|
||||
const result = await linearCreateProject(
|
||||
linearTaskSourceContext ?? defaultScopeSource(settings),
|
||||
{
|
||||
name,
|
||||
description: newLinearProjectDescription.trim() || undefined,
|
||||
content: newLinearProjectContent.trim() || undefined,
|
||||
teamIds: [newLinearProjectTargetTeam.id],
|
||||
workspaceId: newLinearProjectTargetTeam.workspaceId,
|
||||
leadId: newLinearProjectLeadId || undefined,
|
||||
memberIds: newLinearProjectMemberIds.length > 0 ? newLinearProjectMemberIds : undefined,
|
||||
labelIds: newLinearProjectLabelIds.length > 0 ? newLinearProjectLabelIds : undefined,
|
||||
priority: newLinearProjectPriority,
|
||||
startDate: newLinearProjectStartDate || undefined,
|
||||
targetDate: newLinearProjectTargetDate || undefined
|
||||
}
|
||||
)
|
||||
if (!result.ok) {
|
||||
toast.error(
|
||||
result.error ||
|
||||
|
||||
@@ -3,6 +3,7 @@ import { useState, useEffect } from 'react'
|
||||
import type { LinearTeam } from '../../../shared/linear/workspace-types'
|
||||
import type { JiraProject } from '../../../shared/jira-types'
|
||||
import { jiraListProjects } from '@/runtime/runtime-jira-client'
|
||||
import { defaultScopeSource } from '@/lib/default-creation-host'
|
||||
export function useTaskPageProviderMetadata(model: TaskPageResumeRestorationModel) {
|
||||
const {
|
||||
settings,
|
||||
@@ -75,7 +76,7 @@ export function useTaskPageProviderMetadata(model: TaskPageResumeRestorationMode
|
||||
let cancelled = false
|
||||
setAvailableJiraProjects([])
|
||||
setJiraProjectsLoading(true)
|
||||
void jiraListProjects(jiraTaskSourceContext ?? settings, selectedJiraSiteId)
|
||||
void jiraListProjects(jiraTaskSourceContext ?? defaultScopeSource(settings), selectedJiraSiteId)
|
||||
.then((projects) => {
|
||||
if (!cancelled) {
|
||||
setAvailableJiraProjects(projects)
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
import { useMemo } from 'react'
|
||||
import { getSingleFocusedRuntimeEnvironmentId } from '@/lib/single-runtime-legacy-owner'
|
||||
import { getActiveRuntimeTarget, type RuntimeClientTarget } from '@/runtime/runtime-rpc-client'
|
||||
import {
|
||||
runtimeTargetForOwnerEnvironment,
|
||||
type RuntimeClientTarget
|
||||
} from '@/runtime/runtime-client-target'
|
||||
import { useAppStore } from '@/store'
|
||||
|
||||
/** Distinguishes "not known yet" from "known to be the local host", without
|
||||
@@ -36,9 +39,7 @@ export function useActiveSkillDiscoveryRuntimeTarget(): RuntimeClientTarget | nu
|
||||
})
|
||||
return useMemo(
|
||||
() =>
|
||||
ownerKey === UNRESOLVED
|
||||
? null
|
||||
: getActiveRuntimeTarget({ activeRuntimeEnvironmentId: parseOwnerKey(ownerKey) }),
|
||||
ownerKey === UNRESOLVED ? null : runtimeTargetForOwnerEnvironment(parseOwnerKey(ownerKey)),
|
||||
[ownerKey]
|
||||
)
|
||||
}
|
||||
|
||||
@@ -200,7 +200,7 @@ describe('useIssueMetadata hooks', () => {
|
||||
function StatesProbe(): null {
|
||||
renders += 1
|
||||
// Fresh settings object each render — the storm trigger.
|
||||
const metadata = useTeamStates('team-1', { activeRuntimeEnvironmentId: null }, 'ws-1')
|
||||
const metadata = useTeamStates('team-1', { kind: 'local' }, 'ws-1')
|
||||
states = metadata.data
|
||||
return null
|
||||
}
|
||||
@@ -220,7 +220,7 @@ describe('useIssueMetadata hooks', () => {
|
||||
|
||||
function StatesProbe(): null {
|
||||
renders += 1
|
||||
const metadata = useTeamStates('team-1', { activeRuntimeEnvironmentId: null }, 'ws-1')
|
||||
const metadata = useTeamStates('team-1', { kind: 'local' }, 'ws-1')
|
||||
error = metadata.error
|
||||
return null
|
||||
}
|
||||
@@ -254,11 +254,7 @@ describe('useIssueMetadata hooks', () => {
|
||||
})
|
||||
|
||||
function MultiProbe(): null {
|
||||
const metadata = useTeamsStates(
|
||||
['team-fe', 'team-be'],
|
||||
{ activeRuntimeEnvironmentId: null },
|
||||
'ws-1'
|
||||
)
|
||||
const metadata = useTeamsStates(['team-fe', 'team-be'], { kind: 'local' }, 'ws-1')
|
||||
states = metadata.data as { id: string; name: string }[]
|
||||
return null
|
||||
}
|
||||
|
||||
@@ -1,17 +1,15 @@
|
||||
import { useEffect, useMemo, useRef, useState } from 'react'
|
||||
import { getActiveRuntimeTarget } from '@/runtime/runtime-rpc-client'
|
||||
import {
|
||||
linearTeamLabels,
|
||||
linearTeamMembers,
|
||||
linearTeamStates
|
||||
} from '@/runtime/runtime-linear-project-client'
|
||||
import type { RuntimeLinearSettings } from '@/runtime/runtime-linear-client'
|
||||
import { getLinearRuntimeTarget, type RuntimeLinearSettings } from '@/runtime/runtime-linear-client'
|
||||
import type {
|
||||
LinearLabel,
|
||||
LinearMember,
|
||||
LinearWorkflowState
|
||||
} from '../../../shared/linear/workspace-types'
|
||||
import { getTaskSourceRuntimeSettings } from '../../../shared/task-source-context'
|
||||
import { unionLinearMetadataById } from '../components/linear-issue-attribute-filter-team-ids'
|
||||
import {
|
||||
clearMetadataRequestStore,
|
||||
@@ -28,14 +26,15 @@ const linearStateStore = createMetadataRequestStore<LinearWorkflowState[]>()
|
||||
const linearLabelStore = createMetadataRequestStore<LinearLabel[]>()
|
||||
const linearMemberStore = createMetadataRequestStore<LinearMember[]>()
|
||||
|
||||
// Why: an omitted source has always meant this computer.
|
||||
const THIS_COMPUTER: RuntimeLinearSettings = { kind: 'local' }
|
||||
|
||||
function linearMetadataCacheKey(
|
||||
teamId: string,
|
||||
settings: RuntimeLinearSettings,
|
||||
settings: RuntimeLinearSettings | undefined,
|
||||
workspaceId?: string | null
|
||||
): string {
|
||||
const runtimeSettings =
|
||||
settings && 'kind' in settings ? getTaskSourceRuntimeSettings(settings) : settings
|
||||
const target = getActiveRuntimeTarget(runtimeSettings)
|
||||
const target = getLinearRuntimeTarget(settings ?? THIS_COMPUTER)
|
||||
const workspaceKey = workspaceId ?? 'selected'
|
||||
return target.kind === 'environment'
|
||||
? `runtime:${target.environmentId}:${workspaceKey}:${teamId}`
|
||||
@@ -189,21 +188,19 @@ const loadTeamStates = (
|
||||
teamId: string,
|
||||
workspaceId: string | null | undefined
|
||||
): Promise<LinearWorkflowState[]> =>
|
||||
linearTeamStates(settings, teamId, workspaceId).then((states) => states as LinearWorkflowState[])
|
||||
linearTeamStates(settings ?? THIS_COMPUTER, teamId, workspaceId)
|
||||
|
||||
const loadTeamLabels = (
|
||||
settings: RuntimeLinearSettings | undefined,
|
||||
teamId: string,
|
||||
workspaceId: string | null | undefined
|
||||
): Promise<LinearLabel[]> =>
|
||||
linearTeamLabels(settings, teamId, workspaceId).then((labels) => labels as LinearLabel[])
|
||||
): Promise<LinearLabel[]> => linearTeamLabels(settings ?? THIS_COMPUTER, teamId, workspaceId)
|
||||
|
||||
const loadTeamMembers = (
|
||||
settings: RuntimeLinearSettings | undefined,
|
||||
teamId: string,
|
||||
workspaceId: string | null | undefined
|
||||
): Promise<LinearMember[]> =>
|
||||
linearTeamMembers(settings, teamId, workspaceId).then((members) => members as LinearMember[])
|
||||
): Promise<LinearMember[]> => linearTeamMembers(settings ?? THIS_COMPUTER, teamId, workspaceId)
|
||||
|
||||
export function useTeamsStates(
|
||||
teamIds: readonly string[],
|
||||
|
||||
@@ -18,7 +18,7 @@ import {
|
||||
isWindowsTerminalCapabilityHost,
|
||||
useWindowsTerminalCapabilities
|
||||
} from '@/lib/windows-terminal-capabilities'
|
||||
import { getActiveRuntimeTarget } from '@/runtime/runtime-rpc-client'
|
||||
import { defaultScopeHost } from '@/lib/default-creation-host'
|
||||
import { useAppStore } from '@/store'
|
||||
import { useProjectHostSetupProjection } from '@/store/selectors'
|
||||
import type { ProjectGroupingModel } from '@/components/sidebar/worktree-list/grouping/project-grouping'
|
||||
@@ -130,7 +130,8 @@ export function useSettingsNavigationMetadata(): SettingsNavSection[] {
|
||||
const windowsTerminalCapabilityOwnerKey = useWindowsTerminalCapabilityOwnerKey(
|
||||
settings?.activeRuntimeEnvironmentId
|
||||
)
|
||||
const runtimeTarget = getActiveRuntimeTarget(settings)
|
||||
// Why: navigation is shared with the palette, which has no host picker.
|
||||
const runtimeTarget = defaultScopeHost(settings)
|
||||
const capabilityLoadTarget = isWebClient ? { kind: 'local' as const } : runtimeTarget
|
||||
const windowsTerminalCapabilities = useWindowsTerminalCapabilities(
|
||||
isWindows || isWebClient || runtimeTarget.kind === 'environment',
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import { defaultCreationHost } from './default-creation-host'
|
||||
import {
|
||||
defaultCreationHost,
|
||||
defaultScopeHost,
|
||||
defaultScopeSource,
|
||||
rowLessSourceTarget
|
||||
} from './default-creation-host'
|
||||
|
||||
describe('defaultCreationHost', () => {
|
||||
it('is this computer unless a server is chosen', () => {
|
||||
@@ -11,3 +16,23 @@ describe('defaultCreationHost', () => {
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('row-less sources', () => {
|
||||
it('starts on the default host until a source or host is named', () => {
|
||||
const settings = { activeRuntimeEnvironmentId: 'env-a' }
|
||||
expect(defaultScopeHost(settings)).toEqual({ kind: 'environment', environmentId: 'env-a' })
|
||||
expect(rowLessSourceTarget(defaultScopeSource(settings))).toEqual({
|
||||
kind: 'environment',
|
||||
environmentId: 'env-a'
|
||||
})
|
||||
expect(rowLessSourceTarget({ kind: 'local' })).toEqual({ kind: 'local' })
|
||||
expect(
|
||||
rowLessSourceTarget({
|
||||
kind: 'task-source',
|
||||
provider: 'linear',
|
||||
projectId: 'p',
|
||||
hostId: 'runtime:env-b'
|
||||
})
|
||||
).toEqual({ kind: 'environment', environmentId: 'env-b' })
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,13 +1,45 @@
|
||||
import type { GlobalSettings } from '../../../shared/global-settings-types'
|
||||
import type { TaskSourceContext } from '../../../shared/task-source-context'
|
||||
import type { RuntimeClientTarget } from '@/runtime/runtime-client-target'
|
||||
import { taskSourceRuntimeTarget } from './task-source-runtime-target'
|
||||
|
||||
type DefaultHostSettings = Pick<GlobalSettings, 'activeRuntimeEnvironmentId'> | null | undefined
|
||||
|
||||
// The one read of the setting; the exported readers below are the sanctioned ways to reach it.
|
||||
function readDefaultHost(settings: DefaultHostSettings): RuntimeClientTarget {
|
||||
const environmentId = settings?.activeRuntimeEnvironmentId?.trim()
|
||||
return environmentId ? { kind: 'environment', environmentId } : { kind: 'local' }
|
||||
}
|
||||
|
||||
/**
|
||||
* The "Default host for new projects" setting. Only a creation flow with no source row reads it;
|
||||
* everything else routes by the resource's owner.
|
||||
*/
|
||||
export function defaultCreationHost(
|
||||
settings: Pick<GlobalSettings, 'activeRuntimeEnvironmentId'> | null | undefined
|
||||
): RuntimeClientTarget {
|
||||
const environmentId = settings?.activeRuntimeEnvironmentId?.trim()
|
||||
return environmentId ? { kind: 'environment', environmentId } : { kind: 'local' }
|
||||
export function defaultCreationHost(settings: DefaultHostSettings): RuntimeClientTarget {
|
||||
return readDefaultHost(settings)
|
||||
}
|
||||
|
||||
/**
|
||||
* Initial host of a row-less source (Linear, Jira, the status-bar account switchers) or a settings
|
||||
* scope, until the page's own host picker overrides it.
|
||||
*/
|
||||
export function defaultScopeHost(settings: DefaultHostSettings): RuntimeClientTarget {
|
||||
return readDefaultHost(settings)
|
||||
}
|
||||
|
||||
/** "No source chosen yet": a row-less source that runs on the default scope host. */
|
||||
export type DefaultScopeSource = { kind: 'default-scope'; settings: DefaultHostSettings }
|
||||
|
||||
export function defaultScopeSource(settings: DefaultHostSettings): DefaultScopeSource {
|
||||
return { kind: 'default-scope', settings }
|
||||
}
|
||||
|
||||
/** A row-less source: its task-source context, an explicit host, or the default scope host. */
|
||||
export type RowLessSource = TaskSourceContext | RuntimeClientTarget | DefaultScopeSource
|
||||
|
||||
export function rowLessSourceTarget(source: RowLessSource): RuntimeClientTarget {
|
||||
if (source.kind === 'task-source') {
|
||||
return taskSourceRuntimeTarget(source)
|
||||
}
|
||||
return source.kind === 'default-scope' ? readDefaultHost(source.settings) : source
|
||||
}
|
||||
|
||||
@@ -33,7 +33,8 @@ export async function lookupLinearIssueUrl({
|
||||
knownStatus,
|
||||
sourceContext,
|
||||
fetchLinearIssue,
|
||||
readLinearStatus = linearStatus
|
||||
// Why: no source context has always read this computer's Linear status.
|
||||
readLinearStatus = (context) => linearStatus(context ?? { kind: 'local' })
|
||||
}: {
|
||||
intent: LinearIssueUrlIntent
|
||||
knownStatus: Pick<
|
||||
|
||||
@@ -177,7 +177,9 @@ describe('runtime Jira client search bounds', () => {
|
||||
})
|
||||
|
||||
it('rejects oversized local Jira search before IPC', async () => {
|
||||
await expect(jiraSearchIssues(null, 'secret-token-value'.repeat(1024), 30)).resolves.toEqual([])
|
||||
await expect(
|
||||
jiraSearchIssues({ kind: 'local' }, 'secret-token-value'.repeat(1024), 30)
|
||||
).resolves.toEqual([])
|
||||
|
||||
expect(jiraSearchIssuesLocal).not.toHaveBeenCalled()
|
||||
expect(runtimeCall).not.toHaveBeenCalled()
|
||||
@@ -186,7 +188,7 @@ describe('runtime Jira client search bounds', () => {
|
||||
it('rejects oversized runtime Jira assignee search before RPC', async () => {
|
||||
await expect(
|
||||
jiraListAssignableUsers(
|
||||
{ activeRuntimeEnvironmentId: 'env-1' },
|
||||
{ kind: 'environment', environmentId: 'env-1' },
|
||||
'ORCA-1',
|
||||
'x'.repeat(9 * 1024),
|
||||
'site-1'
|
||||
@@ -200,7 +202,7 @@ describe('runtime Jira client search bounds', () => {
|
||||
it('routes local Jira user search through IPC', async () => {
|
||||
jiraSearchUsersLocal.mockResolvedValue([{ accountId: 'account-1', displayName: 'Ada' }])
|
||||
|
||||
await expect(jiraSearchUsers(null, 'Ada', 'site-1')).resolves.toEqual([
|
||||
await expect(jiraSearchUsers({ kind: 'local' }, 'Ada', 'site-1')).resolves.toEqual([
|
||||
{ accountId: 'account-1', displayName: 'Ada' }
|
||||
])
|
||||
|
||||
@@ -222,7 +224,7 @@ describe('runtime Jira client search bounds', () => {
|
||||
})
|
||||
|
||||
await expect(
|
||||
jiraSearchUsers({ activeRuntimeEnvironmentId: 'env-1' }, 'Ada', 'site-1')
|
||||
jiraSearchUsers({ kind: 'environment', environmentId: 'env-1' }, 'Ada', 'site-1')
|
||||
).resolves.toEqual([{ accountId: 'account-1', displayName: 'Ada' }])
|
||||
expect(runtimeCall).toHaveBeenNthCalledWith(
|
||||
1,
|
||||
@@ -241,9 +243,9 @@ describe('runtime Jira client search bounds', () => {
|
||||
it('degrades remote Jira user search when the host lacks the capability', async () => {
|
||||
runtimeCall.mockResolvedValue(createRuntimeStatusWithoutJiraUserFieldsCapability())
|
||||
|
||||
await expect(jiraSearchUsers({ activeRuntimeEnvironmentId: 'env-1' }, 'Ada')).resolves.toEqual(
|
||||
[]
|
||||
)
|
||||
await expect(
|
||||
jiraSearchUsers({ kind: 'environment', environmentId: 'env-1' }, 'Ada')
|
||||
).resolves.toEqual([])
|
||||
expect(runtimeCall).toHaveBeenCalledTimes(1)
|
||||
expect(runtimeCall).not.toHaveBeenCalledWith(
|
||||
expect.objectContaining({ method: 'jira.searchUsers' })
|
||||
@@ -255,7 +257,7 @@ describe('runtime Jira client search bounds', () => {
|
||||
|
||||
await expect(
|
||||
jiraCreateIssue(
|
||||
{ activeRuntimeEnvironmentId: 'env-1' },
|
||||
{ kind: 'environment', environmentId: 'env-1' },
|
||||
{
|
||||
projectId: 'project-1',
|
||||
issueTypeId: 'type-1',
|
||||
@@ -285,7 +287,7 @@ describe('runtime Jira client search bounds', () => {
|
||||
|
||||
await expect(
|
||||
jiraCreateIssue(
|
||||
{ activeRuntimeEnvironmentId: 'env-1' },
|
||||
{ kind: 'environment', environmentId: 'env-1' },
|
||||
{ projectId: 'project-1', issueTypeId: 'type-1', title: 'Issue' }
|
||||
)
|
||||
).resolves.toMatchObject({ ok: true, key: 'ORCA-1' })
|
||||
@@ -309,7 +311,7 @@ describe('runtime Jira client search bounds', () => {
|
||||
|
||||
await expect(
|
||||
jiraCreateIssue(
|
||||
{ activeRuntimeEnvironmentId: 'env-1' },
|
||||
{ kind: 'environment', environmentId: 'env-1' },
|
||||
{
|
||||
projectId: 'project-1',
|
||||
issueTypeId: 'type-1',
|
||||
@@ -338,13 +340,13 @@ describe('runtime Jira client search bounds', () => {
|
||||
|
||||
it('uses project-scoped search locally and rejects oversized queries before IPC', async () => {
|
||||
jiraProjectUsersLocal.mockResolvedValue([])
|
||||
await jiraListAssignableUsersForProject(null, '100', 'Ada', 'site-1')
|
||||
await jiraListAssignableUsersForProject({ kind: 'local' }, '100', 'Ada', 'site-1')
|
||||
expect(jiraProjectUsersLocal).toHaveBeenCalledWith({
|
||||
projectIdOrKey: '100',
|
||||
query: 'Ada',
|
||||
siteId: 'site-1'
|
||||
})
|
||||
await jiraListAssignableUsersForProject(null, '100', 'x'.repeat(20_000), 'site-1')
|
||||
await jiraListAssignableUsersForProject({ kind: 'local' }, '100', 'x'.repeat(20_000), 'site-1')
|
||||
expect(jiraProjectUsersLocal).toHaveBeenCalledTimes(1)
|
||||
})
|
||||
|
||||
@@ -355,7 +357,7 @@ describe('runtime Jira client search bounds', () => {
|
||||
: { id: 'rpc-1', ok: true, result: [], _meta: { runtimeId: 'remote-runtime' } }
|
||||
)
|
||||
await jiraListAssignableUsersForProject(
|
||||
{ activeRuntimeEnvironmentId: 'env-1' },
|
||||
{ kind: 'environment', environmentId: 'env-1' },
|
||||
'100',
|
||||
'Ada',
|
||||
'site-1'
|
||||
@@ -372,7 +374,7 @@ describe('runtime Jira client search bounds', () => {
|
||||
runtimeCall.mockReset().mockResolvedValue(createRuntimeStatusWithoutJiraUserFieldsCapability())
|
||||
await expect(
|
||||
jiraListAssignableUsersForProject(
|
||||
{ activeRuntimeEnvironmentId: 'env-1' },
|
||||
{ kind: 'environment', environmentId: 'env-1' },
|
||||
'100',
|
||||
'Ada',
|
||||
'site-1'
|
||||
@@ -408,10 +410,10 @@ describe('runtime Jira client search bounds', () => {
|
||||
)
|
||||
|
||||
await expect(
|
||||
jiraGetIssue({ activeRuntimeEnvironmentId: 'env-1' }, 'ORCA-1', 'site-1')
|
||||
jiraGetIssue({ kind: 'environment', environmentId: 'env-1' }, 'ORCA-1', 'site-1')
|
||||
).resolves.toMatchObject({ key: 'ORCA-1' })
|
||||
await expect(
|
||||
jiraIssueComments({ activeRuntimeEnvironmentId: 'env-1' }, 'ORCA-1', 'site-1')
|
||||
jiraIssueComments({ kind: 'environment', environmentId: 'env-1' }, 'ORCA-1', 'site-1')
|
||||
).resolves.toMatchObject([{ id: 'comment-1' }])
|
||||
|
||||
expect(runtimeSubscribe).toHaveBeenNthCalledWith(
|
||||
|
||||
@@ -1,24 +1,8 @@
|
||||
import type { GlobalSettings } from '../../../shared/global-settings-types'
|
||||
import {
|
||||
getTaskSourceRuntimeSettings,
|
||||
type TaskSourceContext
|
||||
} from '../../../shared/task-source-context'
|
||||
import { getActiveRuntimeTarget } from './runtime-rpc-client'
|
||||
import type { RuntimeClientTarget } from './runtime-client-target'
|
||||
import { rowLessSourceTarget, type RowLessSource } from '@/lib/default-creation-host'
|
||||
|
||||
export type RuntimeJiraSettings =
|
||||
| Pick<GlobalSettings, 'activeRuntimeEnvironmentId'>
|
||||
| TaskSourceContext
|
||||
| null
|
||||
| undefined
|
||||
export type RuntimeJiraSettings = RowLessSource
|
||||
|
||||
function isTaskSourceRuntimeSettings(settings: RuntimeJiraSettings): settings is TaskSourceContext {
|
||||
return settings !== null && settings !== undefined && 'kind' in settings
|
||||
}
|
||||
|
||||
export function getJiraRuntimeTarget(
|
||||
settings: RuntimeJiraSettings
|
||||
): ReturnType<typeof getActiveRuntimeTarget> {
|
||||
return getActiveRuntimeTarget(
|
||||
isTaskSourceRuntimeSettings(settings) ? getTaskSourceRuntimeSettings(settings) : settings
|
||||
)
|
||||
export function getJiraRuntimeTarget(source: RuntimeJiraSettings): RuntimeClientTarget {
|
||||
return rowLessSourceTarget(source)
|
||||
}
|
||||
|
||||
@@ -106,22 +106,23 @@ describe('runtime linear client', () => {
|
||||
})
|
||||
linearCreateProjectLocal.mockResolvedValue({ ok: true, project: { id: 'project-1' } })
|
||||
|
||||
await expect(linearStatus({ activeRuntimeEnvironmentId: null })).resolves.toEqual({
|
||||
await expect(linearStatus({ kind: 'local' })).resolves.toEqual({
|
||||
connected: false,
|
||||
viewer: null
|
||||
})
|
||||
await expect(
|
||||
linearSearchIssues({ activeRuntimeEnvironmentId: null }, 'bug', 10)
|
||||
).resolves.toEqual([{ id: 'issue-1' }])
|
||||
await expect(
|
||||
linearListIssues({ activeRuntimeEnvironmentId: null }, 'all', 72, 'workspace-1')
|
||||
).resolves.toEqual({ items: [{ id: 'issue-2' }], hasMore: true })
|
||||
await expect(linearSearchIssues({ kind: 'local' }, 'bug', 10)).resolves.toEqual([
|
||||
{ id: 'issue-1' }
|
||||
])
|
||||
await expect(linearListIssues({ kind: 'local' }, 'all', 72, 'workspace-1')).resolves.toEqual({
|
||||
items: [{ id: 'issue-2' }],
|
||||
hasMore: true
|
||||
})
|
||||
await linearCreateSubIssue(
|
||||
{ activeRuntimeEnvironmentId: null },
|
||||
{ kind: 'local' },
|
||||
{ parentIssueId: 'issue-1', teamId: 'team-1', title: 'Child task' }
|
||||
)
|
||||
await linearCreateProject(
|
||||
{ activeRuntimeEnvironmentId: null },
|
||||
{ kind: 'local' },
|
||||
{ name: 'Roadmap', teamIds: ['team-1'], workspaceId: 'workspace-1' }
|
||||
)
|
||||
|
||||
@@ -152,23 +153,19 @@ describe('runtime linear client', () => {
|
||||
it('wraps legacy local Linear issue list arrays as collection results', async () => {
|
||||
linearListIssuesLocal.mockResolvedValue([{ id: 'legacy-issue' }])
|
||||
|
||||
await expect(
|
||||
linearListIssues({ activeRuntimeEnvironmentId: null }, 'assigned', 20)
|
||||
).resolves.toEqual({ items: [{ id: 'legacy-issue' }] })
|
||||
await expect(linearListIssues({ kind: 'local' }, 'assigned', 20)).resolves.toEqual({
|
||||
items: [{ id: 'legacy-issue' }]
|
||||
})
|
||||
})
|
||||
|
||||
it('rejects oversized local Linear search queries before IPC', async () => {
|
||||
await expect(
|
||||
linearSearchIssues(
|
||||
{ activeRuntimeEnvironmentId: null },
|
||||
'secret-token-value'.repeat(1024),
|
||||
10
|
||||
)
|
||||
linearSearchIssues({ kind: 'local' }, 'secret-token-value'.repeat(1024), 10)
|
||||
).resolves.toEqual([])
|
||||
|
||||
await expect(
|
||||
linearListProjects({ activeRuntimeEnvironmentId: null }, 'x'.repeat(9 * 1024), 10)
|
||||
).resolves.toEqual({ items: [] })
|
||||
await expect(linearListProjects({ kind: 'local' }, 'x'.repeat(9 * 1024), 10)).resolves.toEqual({
|
||||
items: []
|
||||
})
|
||||
|
||||
expect(linearSearchIssuesLocal).not.toHaveBeenCalled()
|
||||
expect(linearListProjectsLocal).not.toHaveBeenCalled()
|
||||
@@ -179,7 +176,7 @@ describe('runtime linear client', () => {
|
||||
delete (window.api.linear as { listProjects?: unknown }).listProjects
|
||||
|
||||
await expect(
|
||||
linearListProjects({ activeRuntimeEnvironmentId: null }, 'roadmap', 10, 'workspace-1')
|
||||
linearListProjects({ kind: 'local' }, 'roadmap', 10, 'workspace-1')
|
||||
).resolves.toEqual({ items: [] })
|
||||
})
|
||||
|
||||
@@ -192,47 +189,25 @@ describe('runtime linear client', () => {
|
||||
linearListCustomViewIssuesLocal.mockResolvedValueOnce({ items: [{ id: 'issue-2' }] })
|
||||
linearListCustomViewProjectsLocal.mockResolvedValueOnce({ items: [{ id: 'project-2' }] })
|
||||
|
||||
await linearListProjects({ activeRuntimeEnvironmentId: null }, 'roadmap', 10, 'workspace-1', {
|
||||
await linearListProjects({ kind: 'local' }, 'roadmap', 10, 'workspace-1', {
|
||||
force: true
|
||||
})
|
||||
await linearGetProject({ activeRuntimeEnvironmentId: null }, 'project-1', 'workspace-1', {
|
||||
await linearGetProject({ kind: 'local' }, 'project-1', 'workspace-1', {
|
||||
force: true
|
||||
})
|
||||
await linearListProjectIssues({ kind: 'local' }, 'project-1', 10, 'workspace-1', {
|
||||
force: true
|
||||
})
|
||||
await linearListCustomViews({ kind: 'local' }, 'project', 10, 'workspace-1', { force: true })
|
||||
await linearGetCustomView({ kind: 'local' }, 'view-1', 'project', 'workspace-1', {
|
||||
force: true
|
||||
})
|
||||
await linearListCustomViewIssues({ kind: 'local' }, 'view-1', 10, 'workspace-1', {
|
||||
force: true
|
||||
})
|
||||
await linearListCustomViewProjects({ kind: 'local' }, 'view-2', 10, 'workspace-1', {
|
||||
force: true
|
||||
})
|
||||
await linearListProjectIssues(
|
||||
{ activeRuntimeEnvironmentId: null },
|
||||
'project-1',
|
||||
10,
|
||||
'workspace-1',
|
||||
{ force: true }
|
||||
)
|
||||
await linearListCustomViews(
|
||||
{ activeRuntimeEnvironmentId: null },
|
||||
'project',
|
||||
10,
|
||||
'workspace-1',
|
||||
{ force: true }
|
||||
)
|
||||
await linearGetCustomView(
|
||||
{ activeRuntimeEnvironmentId: null },
|
||||
'view-1',
|
||||
'project',
|
||||
'workspace-1',
|
||||
{ force: true }
|
||||
)
|
||||
await linearListCustomViewIssues(
|
||||
{ activeRuntimeEnvironmentId: null },
|
||||
'view-1',
|
||||
10,
|
||||
'workspace-1',
|
||||
{ force: true }
|
||||
)
|
||||
await linearListCustomViewProjects(
|
||||
{ activeRuntimeEnvironmentId: null },
|
||||
'view-2',
|
||||
10,
|
||||
'workspace-1',
|
||||
{ force: true }
|
||||
)
|
||||
|
||||
expect(linearListProjectsLocal).toHaveBeenCalledWith({
|
||||
query: 'roadmap',
|
||||
@@ -299,10 +274,10 @@ describe('runtime linear client', () => {
|
||||
_meta: { runtimeId: 'runtime-1' }
|
||||
})
|
||||
|
||||
await linearStatus({ activeRuntimeEnvironmentId: 'env-1' })
|
||||
await linearSearchIssues({ activeRuntimeEnvironmentId: 'env-1' }, 'bug', 10, 'all')
|
||||
await linearStatus({ kind: 'environment', environmentId: 'env-1' })
|
||||
await linearSearchIssues({ kind: 'environment', environmentId: 'env-1' }, 'bug', 10, 'all')
|
||||
await expect(
|
||||
linearListIssues({ activeRuntimeEnvironmentId: 'env-1' }, 'all', 72, 'workspace-1')
|
||||
linearListIssues({ kind: 'environment', environmentId: 'env-1' }, 'all', 72, 'workspace-1')
|
||||
).resolves.toEqual({ items: [{ id: 'issue-2' }], hasMore: true })
|
||||
|
||||
expect(runtimeEnvironmentCall).toHaveBeenNthCalledWith(1, {
|
||||
@@ -337,7 +312,7 @@ describe('runtime linear client', () => {
|
||||
})
|
||||
|
||||
await expect(
|
||||
linearListIssues({ activeRuntimeEnvironmentId: 'env-1' }, 'assigned', 20)
|
||||
linearListIssues({ kind: 'environment', environmentId: 'env-1' }, 'assigned', 20)
|
||||
).resolves.toEqual({ items: [{ id: 'legacy-issue' }] })
|
||||
|
||||
expect(runtimeEnvironmentCall).toHaveBeenCalledWith({
|
||||
@@ -366,7 +341,7 @@ describe('runtime linear client', () => {
|
||||
)
|
||||
|
||||
await expect(
|
||||
linearListIssues({ activeRuntimeEnvironmentId: 'env-1' }, 'all', 20, 'workspace-1', {
|
||||
linearListIssues({ kind: 'environment', environmentId: 'env-1' }, 'all', 20, 'workspace-1', {
|
||||
stateIds: ['state-1'],
|
||||
priorities: [],
|
||||
assignee: null,
|
||||
@@ -390,7 +365,7 @@ describe('runtime linear client', () => {
|
||||
})
|
||||
|
||||
await expect(
|
||||
linearListIssues({ activeRuntimeEnvironmentId: 'env-1' }, 'all', 20, 'workspace-1', {
|
||||
linearListIssues({ kind: 'environment', environmentId: 'env-1' }, 'all', 20, 'workspace-1', {
|
||||
stateIds: [],
|
||||
priorities: [2],
|
||||
assignee: null,
|
||||
@@ -425,7 +400,7 @@ describe('runtime linear client', () => {
|
||||
})
|
||||
|
||||
await expect(
|
||||
linearListIssues({ activeRuntimeEnvironmentId: 'env-1' }, 'assigned', 20)
|
||||
linearListIssues({ kind: 'environment', environmentId: 'env-1' }, 'assigned', 20)
|
||||
).resolves.toEqual({ items: [] })
|
||||
})
|
||||
|
||||
@@ -487,17 +462,17 @@ describe('runtime linear client', () => {
|
||||
})
|
||||
|
||||
await linearCreateIssue(
|
||||
{ activeRuntimeEnvironmentId: 'env-1' },
|
||||
{ kind: 'environment', environmentId: 'env-1' },
|
||||
{ teamId: 'team-1', title: 'Fix bug', workspaceId: 'workspace-1' }
|
||||
)
|
||||
await linearUpdateIssue(
|
||||
{ activeRuntimeEnvironmentId: 'env-1' },
|
||||
{ kind: 'environment', environmentId: 'env-1' },
|
||||
'issue-1',
|
||||
{ estimate: 5, priority: 2 },
|
||||
'workspace-1'
|
||||
)
|
||||
await linearCreateSubIssue(
|
||||
{ activeRuntimeEnvironmentId: 'env-1' },
|
||||
{ kind: 'environment', environmentId: 'env-1' },
|
||||
{
|
||||
parentIssueId: 'issue-1',
|
||||
teamId: 'team-1',
|
||||
@@ -506,10 +481,15 @@ describe('runtime linear client', () => {
|
||||
projectId: 'project-1'
|
||||
}
|
||||
)
|
||||
await linearListTeams({ activeRuntimeEnvironmentId: 'env-1' }, 'all')
|
||||
await linearListProjects({ activeRuntimeEnvironmentId: 'env-1' }, 'roadmap', 10, 'workspace-1')
|
||||
await linearListTeams({ kind: 'environment', environmentId: 'env-1' }, 'all')
|
||||
await linearListProjects(
|
||||
{ kind: 'environment', environmentId: 'env-1' },
|
||||
'roadmap',
|
||||
10,
|
||||
'workspace-1'
|
||||
)
|
||||
await linearCreateProject(
|
||||
{ activeRuntimeEnvironmentId: 'env-1' },
|
||||
{ kind: 'environment', environmentId: 'env-1' },
|
||||
{
|
||||
name: 'Roadmap',
|
||||
description: 'Summary',
|
||||
@@ -518,7 +498,7 @@ describe('runtime linear client', () => {
|
||||
priority: 2
|
||||
}
|
||||
)
|
||||
await linearSelectWorkspace({ activeRuntimeEnvironmentId: 'env-1' }, 'workspace-1')
|
||||
await linearSelectWorkspace({ kind: 'environment', environmentId: 'env-1' }, 'workspace-1')
|
||||
|
||||
expect(runtimeEnvironmentCall).toHaveBeenNthCalledWith(1, {
|
||||
selector: 'env-1',
|
||||
@@ -619,39 +599,44 @@ describe('runtime linear client', () => {
|
||||
_meta: { runtimeId: 'runtime-1' }
|
||||
})
|
||||
|
||||
await linearGetProject({ activeRuntimeEnvironmentId: 'env-1' }, 'project-1', 'workspace-1', {
|
||||
force: true
|
||||
})
|
||||
await linearGetProject(
|
||||
{ kind: 'environment', environmentId: 'env-1' },
|
||||
'project-1',
|
||||
'workspace-1',
|
||||
{
|
||||
force: true
|
||||
}
|
||||
)
|
||||
await linearListProjectIssues(
|
||||
{ activeRuntimeEnvironmentId: 'env-1' },
|
||||
{ kind: 'environment', environmentId: 'env-1' },
|
||||
'project-1',
|
||||
10,
|
||||
'workspace-1',
|
||||
{ force: true }
|
||||
)
|
||||
await linearListCustomViews(
|
||||
{ activeRuntimeEnvironmentId: 'env-1' },
|
||||
{ kind: 'environment', environmentId: 'env-1' },
|
||||
'project',
|
||||
10,
|
||||
'workspace-1',
|
||||
{ force: true }
|
||||
)
|
||||
await linearGetCustomView(
|
||||
{ activeRuntimeEnvironmentId: 'env-1' },
|
||||
{ kind: 'environment', environmentId: 'env-1' },
|
||||
'view-1',
|
||||
'project',
|
||||
'workspace-1',
|
||||
{ force: true }
|
||||
)
|
||||
await linearListCustomViewIssues(
|
||||
{ activeRuntimeEnvironmentId: 'env-1' },
|
||||
{ kind: 'environment', environmentId: 'env-1' },
|
||||
'view-1',
|
||||
10,
|
||||
'workspace-1',
|
||||
{ force: true }
|
||||
)
|
||||
await linearListCustomViewProjects(
|
||||
{ activeRuntimeEnvironmentId: 'env-1' },
|
||||
{ kind: 'environment', environmentId: 'env-1' },
|
||||
'view-2',
|
||||
10,
|
||||
'workspace-1',
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import type { GlobalSettings } from '../../../shared/global-settings-types'
|
||||
import type { LinearIssue } from '../../../shared/linear/issue-types'
|
||||
import type { LinearProjectDetail } from '../../../shared/linear/project-types'
|
||||
import type {
|
||||
@@ -7,15 +6,9 @@ import type {
|
||||
LinearViewer,
|
||||
LinearWorkspaceSelection
|
||||
} from '../../../shared/linear/workspace-types'
|
||||
import {
|
||||
callRuntimeRpc,
|
||||
getActiveRuntimeTarget,
|
||||
runtimeEnvironmentSupportsCapability
|
||||
} from './runtime-rpc-client'
|
||||
import {
|
||||
getTaskSourceRuntimeSettings,
|
||||
type TaskSourceContext
|
||||
} from '../../../shared/task-source-context'
|
||||
import { callRuntimeRpc, runtimeEnvironmentSupportsCapability } from './runtime-rpc-client'
|
||||
import type { RuntimeClientTarget } from './runtime-client-target'
|
||||
import { rowLessSourceTarget, type RowLessSource } from '@/lib/default-creation-host'
|
||||
import { isRuntimeProviderSearchQueryWithinLimit } from './runtime-provider-search-bounds'
|
||||
import type { LinearIssueAttributeFilter } from '../../../shared/linear/issue-attribute-filter'
|
||||
import {
|
||||
@@ -24,11 +17,7 @@ import {
|
||||
} from '../../../shared/linear/issue-attribute-filter'
|
||||
import { LINEAR_ISSUE_ATTRIBUTE_FILTER_RUNTIME_CAPABILITY } from '../../../shared/protocol-version'
|
||||
|
||||
export type RuntimeLinearSettings =
|
||||
| Pick<GlobalSettings, 'activeRuntimeEnvironmentId'>
|
||||
| TaskSourceContext
|
||||
| null
|
||||
| undefined
|
||||
export type RuntimeLinearSettings = RowLessSource
|
||||
|
||||
// Why: mixed-version remotes must not look like an empty filtered result. The
|
||||
// Linear store swallows most read failures; this typed error is rethrown so UI
|
||||
@@ -62,20 +51,8 @@ export function linearReadForce(options?: LinearReadOptions): { force: true } |
|
||||
return options?.force ? { force: true } : {}
|
||||
}
|
||||
|
||||
function isTaskSourceRuntimeSettings(
|
||||
settings: RuntimeLinearSettings
|
||||
): settings is TaskSourceContext {
|
||||
return settings !== null && settings !== undefined && 'kind' in settings
|
||||
}
|
||||
|
||||
export function getLinearRuntimeTarget(
|
||||
settings: RuntimeLinearSettings
|
||||
): ReturnType<typeof getActiveRuntimeTarget> {
|
||||
// Why: task source context makes provider ownership explicit; legacy callers
|
||||
// still pass focused runtime settings until Tasks finishes migrating.
|
||||
return getActiveRuntimeTarget(
|
||||
isTaskSourceRuntimeSettings(settings) ? getTaskSourceRuntimeSettings(settings) : settings
|
||||
)
|
||||
export function getLinearRuntimeTarget(source: RuntimeLinearSettings): RuntimeClientTarget {
|
||||
return rowLessSourceTarget(source)
|
||||
}
|
||||
|
||||
function normalizeLinearIssueCollectionResult(
|
||||
|
||||
@@ -22,6 +22,7 @@ import {
|
||||
jiraStatusUpdate,
|
||||
nextJiraStatusReadGeneration
|
||||
} from './jira-read-coordination'
|
||||
import { defaultScopeSource } from '@/lib/default-creation-host'
|
||||
|
||||
type JiraConnectionActions = Pick<
|
||||
JiraSlice,
|
||||
@@ -62,7 +63,7 @@ export function createJiraConnectionActions(
|
||||
set({ jiraStatusChecked: false })
|
||||
}
|
||||
try {
|
||||
const status = await jiraStatus(get().settings)
|
||||
const status = await jiraStatus(defaultScopeSource(get().settings))
|
||||
if (
|
||||
mutationGeneration !== currentJiraMutationGeneration() ||
|
||||
!isCurrentJiraStatusRead(statusReadGeneration) ||
|
||||
@@ -100,7 +101,7 @@ export function createJiraConnectionActions(
|
||||
const requestGeneration = beginJiraMutation()
|
||||
const contextKey = getProviderRuntimeContextKey(get().settings)
|
||||
try {
|
||||
const result = await jiraConnect(get().settings, args)
|
||||
const result = await jiraConnect(defaultScopeSource(get().settings), args)
|
||||
if (
|
||||
result.ok &&
|
||||
isCurrentJiraMutation(requestGeneration) &&
|
||||
@@ -132,14 +133,14 @@ export function createJiraConnectionActions(
|
||||
const requestGeneration = beginJiraMutation()
|
||||
const contextKey = getProviderRuntimeContextKey(get().settings)
|
||||
try {
|
||||
const result = await jiraTestConnection(get().settings, siteId)
|
||||
const result = await jiraTestConnection(defaultScopeSource(get().settings), siteId)
|
||||
if (
|
||||
!isCurrentJiraMutation(requestGeneration) ||
|
||||
!isCurrentJiraRuntimeContext(contextKey, get().settings)
|
||||
) {
|
||||
return result
|
||||
}
|
||||
const status = await jiraStatus(get().settings)
|
||||
const status = await jiraStatus(defaultScopeSource(get().settings))
|
||||
if (
|
||||
isCurrentJiraMutation(requestGeneration) &&
|
||||
isCurrentJiraRuntimeContext(contextKey, get().settings)
|
||||
@@ -155,7 +156,7 @@ export function createJiraConnectionActions(
|
||||
selectJiraSite: async (siteId) => {
|
||||
const requestGeneration = beginJiraMutation()
|
||||
const contextKey = getProviderRuntimeContextKey(get().settings)
|
||||
const status = await jiraSelectSite(get().settings, siteId)
|
||||
const status = await jiraSelectSite(defaultScopeSource(get().settings), siteId)
|
||||
if (
|
||||
!isCurrentJiraMutation(requestGeneration) ||
|
||||
getProviderRuntimeContextKey(get().settings) !== contextKey
|
||||
@@ -169,7 +170,7 @@ export function createJiraConnectionActions(
|
||||
disconnectJira: async (siteId) => {
|
||||
const requestGeneration = beginJiraMutation()
|
||||
const contextKey = getProviderRuntimeContextKey(get().settings)
|
||||
await jiraDisconnect(get().settings, siteId)
|
||||
await jiraDisconnect(defaultScopeSource(get().settings), siteId)
|
||||
if (
|
||||
!isCurrentJiraMutation(requestGeneration) ||
|
||||
!isCurrentJiraRuntimeContext(contextKey, get().settings)
|
||||
@@ -177,7 +178,7 @@ export function createJiraConnectionActions(
|
||||
return
|
||||
}
|
||||
clearJiraInflightRequests()
|
||||
const status = await jiraStatus(get().settings)
|
||||
const status = await jiraStatus(defaultScopeSource(get().settings))
|
||||
if (
|
||||
!isCurrentJiraMutation(requestGeneration) ||
|
||||
!isCurrentJiraRuntimeContext(contextKey, get().settings)
|
||||
|
||||
@@ -13,6 +13,8 @@ import {
|
||||
} from '../../../../shared/task-source-context'
|
||||
import { getProviderRuntimeContextKey } from '@/lib/provider-runtime-context'
|
||||
import { parseJiraStatusError } from '../../../../shared/jira-status-error'
|
||||
import { defaultScopeSource } from '@/lib/default-creation-host'
|
||||
import type { RowLessSource } from '@/lib/default-creation-host'
|
||||
|
||||
const CACHE_TTL = 60_000
|
||||
const MAX_CACHE_ENTRIES = 500
|
||||
@@ -29,7 +31,7 @@ export type SharedJiraSummaryRequest = InflightJiraReadRequest<JiraIssue | null>
|
||||
}
|
||||
|
||||
export type JiraReadScope = {
|
||||
settings: AppState['settings'] | TaskSourceContext | null
|
||||
settings: RowLessSource
|
||||
contextKey: string
|
||||
cachePrefix: string | null
|
||||
explicitSource: boolean
|
||||
@@ -195,7 +197,8 @@ export function getJiraReadScope(
|
||||
): JiraReadScope {
|
||||
if (!sourceContext) {
|
||||
return {
|
||||
settings,
|
||||
// Why: no Tasks source chosen yet; the default scope host is the row-less source's host.
|
||||
settings: defaultScopeSource(settings),
|
||||
contextKey: getProviderRuntimeContextKey(settings),
|
||||
cachePrefix: null,
|
||||
explicitSource: false
|
||||
@@ -214,11 +217,15 @@ export function scopedJiraCacheKey(scope: JiraReadScope, key: string): string {
|
||||
return scope.cachePrefix ? `${scope.cachePrefix}::${key}` : key
|
||||
}
|
||||
|
||||
function jiraConnectionRevisionContextKey(
|
||||
settings: AppState['settings'] | TaskSourceContext | null
|
||||
): string {
|
||||
function jiraConnectionRevisionContextKey(source: RowLessSource): string {
|
||||
return getProviderRuntimeContextKey(
|
||||
settings && 'kind' in settings ? getTaskSourceRuntimeSettings(settings) : settings
|
||||
source.kind === 'default-scope'
|
||||
? source.settings
|
||||
: source.kind === 'task-source'
|
||||
? getTaskSourceRuntimeSettings(source)
|
||||
: {
|
||||
activeRuntimeEnvironmentId: source.kind === 'environment' ? source.environmentId : null
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -150,7 +150,11 @@ describe('createLinearSlice invalidation', () => {
|
||||
expect(store.getState().linearListCache).toEqual({})
|
||||
expect(store.getState().linearProjectIssueCache).toEqual({})
|
||||
expect(store.getState().linearCustomViewIssueCache).toEqual({})
|
||||
expect(linearGetIssue).toHaveBeenCalledWith(null, 'issue-id', 'workspace-1')
|
||||
expect(linearGetIssue).toHaveBeenCalledWith(
|
||||
{ kind: 'default-scope', settings: null },
|
||||
'issue-id',
|
||||
'workspace-1'
|
||||
)
|
||||
})
|
||||
|
||||
it('connect invalidates cached Linear rows and waits for refreshed status', async () => {
|
||||
|
||||
@@ -133,9 +133,15 @@ describe('createLinearSlice caching', () => {
|
||||
hasMore: true
|
||||
})
|
||||
|
||||
expect(linearListProjectIssues).toHaveBeenCalledWith(null, 'project-1', 120, 'workspace-1', {
|
||||
force: undefined
|
||||
})
|
||||
expect(linearListProjectIssues).toHaveBeenCalledWith(
|
||||
{ kind: 'default-scope', settings: null },
|
||||
'project-1',
|
||||
120,
|
||||
'workspace-1',
|
||||
{
|
||||
force: undefined
|
||||
}
|
||||
)
|
||||
expect(
|
||||
store.getState().linearProjectIssueCache['workspace-1::project-issues::project-1::120']?.data
|
||||
).toMatchObject({ items: [{ id: 'LIN-120' }] })
|
||||
@@ -234,9 +240,15 @@ describe('createLinearSlice caching', () => {
|
||||
hasMore: true
|
||||
})
|
||||
|
||||
expect(linearListCustomViewIssues).toHaveBeenCalledWith(null, 'view-1', 120, 'workspace-1', {
|
||||
force: undefined
|
||||
})
|
||||
expect(linearListCustomViewIssues).toHaveBeenCalledWith(
|
||||
{ kind: 'default-scope', settings: null },
|
||||
'view-1',
|
||||
120,
|
||||
'workspace-1',
|
||||
{
|
||||
force: undefined
|
||||
}
|
||||
)
|
||||
expect(
|
||||
store.getState().linearCustomViewIssueCache['workspace-1::custom-view-issues::view-1::120']
|
||||
?.data
|
||||
@@ -315,9 +327,15 @@ describe('createLinearSlice caching', () => {
|
||||
store.getState().fetchLinearCustomView('view-1', 'workspace-1', 'project', { force: true })
|
||||
).resolves.toMatchObject({ id: 'view-1' })
|
||||
|
||||
expect(linearGetCustomView).toHaveBeenCalledWith(null, 'view-1', 'project', 'workspace-1', {
|
||||
force: true
|
||||
})
|
||||
expect(linearGetCustomView).toHaveBeenCalledWith(
|
||||
{ kind: 'default-scope', settings: null },
|
||||
'view-1',
|
||||
'project',
|
||||
'workspace-1',
|
||||
{
|
||||
force: true
|
||||
}
|
||||
)
|
||||
await vi.waitFor(() => {
|
||||
expect(store.getState().linearStatus.credentialError).toBeUndefined()
|
||||
})
|
||||
|
||||
@@ -17,6 +17,7 @@ import {
|
||||
} from './linear-slice-request-state'
|
||||
import { isCurrentLinearRuntimeContext } from './linear-slice-scope'
|
||||
import { linearStatusScopeSignature } from './linear-cache'
|
||||
import { defaultScopeSource } from '@/lib/default-creation-host'
|
||||
|
||||
export function createLinearConnectionActions(
|
||||
set: LinearSliceSet,
|
||||
@@ -34,16 +35,14 @@ export function createLinearConnectionActions(
|
||||
const requestGeneration = beginLinearMutation()
|
||||
const contextKey = getProviderRuntimeContextKey(get().settings)
|
||||
try {
|
||||
const result = (await linearTestConnection(get().settings, workspaceId)) as
|
||||
| { ok: true; viewer: LinearViewer }
|
||||
| { ok: false; error: string }
|
||||
const result = await linearTestConnection(defaultScopeSource(get().settings), workspaceId)
|
||||
if (
|
||||
!isCurrentLinearMutation(requestGeneration) ||
|
||||
!isCurrentLinearRuntimeContext(contextKey, get().settings)
|
||||
) {
|
||||
return result
|
||||
}
|
||||
const status = await linearStatus(get().settings)
|
||||
const status = await linearStatus(defaultScopeSource(get().settings))
|
||||
if (
|
||||
isCurrentLinearMutation(requestGeneration) &&
|
||||
isCurrentLinearRuntimeContext(contextKey, get().settings)
|
||||
@@ -83,7 +82,7 @@ export function createLinearConnectionActions(
|
||||
const requestGeneration = beginLinearMutation()
|
||||
const contextKey = getProviderRuntimeContextKey(get().settings)
|
||||
try {
|
||||
const result = await linearConnect(get().settings, apiKey)
|
||||
const result = await linearConnect(defaultScopeSource(get().settings), apiKey)
|
||||
if (
|
||||
result.ok &&
|
||||
isCurrentLinearMutation(requestGeneration) &&
|
||||
@@ -103,7 +102,7 @@ export function createLinearConnectionActions(
|
||||
linearCustomViewIssueCache: {},
|
||||
linearCustomViewProjectCache: {}
|
||||
})
|
||||
const status = await linearStatus(get().settings)
|
||||
const status = await linearStatus(defaultScopeSource(get().settings))
|
||||
if (
|
||||
!isCurrentLinearMutation(requestGeneration) ||
|
||||
!isCurrentLinearRuntimeContext(contextKey, get().settings)
|
||||
@@ -140,7 +139,7 @@ export function createLinearConnectionActions(
|
||||
selectLinearWorkspace: async (workspaceId) => {
|
||||
const requestGeneration = beginLinearMutation()
|
||||
const contextKey = getProviderRuntimeContextKey(get().settings)
|
||||
const status = await linearSelectWorkspace(get().settings, workspaceId)
|
||||
const status = await linearSelectWorkspace(defaultScopeSource(get().settings), workspaceId)
|
||||
if (
|
||||
!isCurrentLinearMutation(requestGeneration) ||
|
||||
!isCurrentLinearRuntimeContext(contextKey, get().settings)
|
||||
@@ -169,7 +168,7 @@ export function createLinearConnectionActions(
|
||||
disconnectLinear: async () => {
|
||||
const requestGeneration = beginLinearMutation()
|
||||
const contextKey = getProviderRuntimeContextKey(get().settings)
|
||||
await linearDisconnect(get().settings)
|
||||
await linearDisconnect(defaultScopeSource(get().settings))
|
||||
if (
|
||||
!isCurrentLinearMutation(requestGeneration) ||
|
||||
!isCurrentLinearRuntimeContext(contextKey, get().settings)
|
||||
@@ -198,14 +197,14 @@ export function createLinearConnectionActions(
|
||||
disconnectLinearWorkspace: async (workspaceId) => {
|
||||
const requestGeneration = beginLinearMutation()
|
||||
const contextKey = getProviderRuntimeContextKey(get().settings)
|
||||
await linearDisconnectWorkspace(get().settings, workspaceId)
|
||||
await linearDisconnectWorkspace(defaultScopeSource(get().settings), workspaceId)
|
||||
if (
|
||||
!isCurrentLinearMutation(requestGeneration) ||
|
||||
!isCurrentLinearRuntimeContext(contextKey, get().settings)
|
||||
) {
|
||||
return
|
||||
}
|
||||
const status = await linearStatus(get().settings)
|
||||
const status = await linearStatus(defaultScopeSource(get().settings))
|
||||
if (
|
||||
!isCurrentLinearMutation(requestGeneration) ||
|
||||
!isCurrentLinearRuntimeContext(contextKey, get().settings)
|
||||
|
||||
@@ -11,6 +11,8 @@ import {
|
||||
} from '../../../../../shared/linear/issue-attribute-filter'
|
||||
import { getProviderRuntimeContextKey } from '@/lib/provider-runtime-context'
|
||||
import { getLinearCacheGeneration, getLinearMutationGeneration } from './linear-slice-request-state'
|
||||
import { defaultScopeSource } from '@/lib/default-creation-host'
|
||||
import type { RowLessSource } from '@/lib/default-creation-host'
|
||||
|
||||
export function normalizeListAttributeFilter(
|
||||
attributeFilter?: LinearIssueAttributeFilter | null
|
||||
@@ -22,7 +24,7 @@ export function normalizeListAttributeFilter(
|
||||
}
|
||||
|
||||
export type LinearReadScope = {
|
||||
settings: AppState['settings'] | TaskSourceContext | null
|
||||
settings: RowLessSource
|
||||
contextKey: string
|
||||
cachePrefix: string | null
|
||||
explicitSource: boolean
|
||||
@@ -55,7 +57,8 @@ export function getLinearReadScope(
|
||||
): LinearReadScope {
|
||||
if (!sourceContext) {
|
||||
return {
|
||||
settings,
|
||||
// Why: no Tasks source chosen yet; the default scope host is the row-less source's host.
|
||||
settings: defaultScopeSource(settings),
|
||||
contextKey: getProviderRuntimeContextKey(settings),
|
||||
cachePrefix: null,
|
||||
explicitSource: false
|
||||
|
||||
@@ -12,6 +12,7 @@ import {
|
||||
} from './linear-slice-request-state'
|
||||
import { linearStatusScopeSignature } from './linear-cache'
|
||||
import { isCurrentLinearRuntimeContext } from './linear-slice-scope'
|
||||
import { defaultScopeSource } from '@/lib/default-creation-host'
|
||||
|
||||
export function createLinearStatusActions(
|
||||
set: LinearSliceSet,
|
||||
@@ -30,7 +31,7 @@ export function createLinearStatusActions(
|
||||
|
||||
const mutationGeneration = getLinearMutationGeneration()
|
||||
const statusReadGeneration = nextLinearStatusReadGeneration()
|
||||
const request = linearStatus(get().settings)
|
||||
const request = linearStatus(defaultScopeSource(get().settings))
|
||||
.then((status) => {
|
||||
if (
|
||||
mutationGeneration !== getLinearMutationGeneration() ||
|
||||
|
||||
Reference in New Issue
Block a user