Skip to content

feat: redesign pane layout system (@superset/panes)#3088

Merged
saddlepaddle merged 11 commits into
mainfrom
saddlepaddle/billowy-culotte
Apr 1, 2026
Merged

feat: redesign pane layout system (@superset/panes)#3088
saddlepaddle merged 11 commits into
mainfrom
saddlepaddle/billowy-culotte

Conversation

@saddlepaddle
Copy link
Copy Markdown
Collaborator

@saddlepaddle saddlepaddle commented Apr 1, 2026

Summary

  • Redesigned the pane layout data model from a 3-tier hierarchy (Root → Group → Pane) to a simpler Tab → Split → Pane model
  • Renamed package from @superset/pane-layout to @superset/panes
  • New store with all actions (tab CRUD, pane CRUD, split/resize/equalize, openPane, replacePane)
  • N-ary weighted splits (FlexLayout-inspired) with react-resizable-panels for resize UI
  • React component tree: Workspace → TabBar → Tab → Pane with PaneHeader
  • Configurable pane header actions via PaneActionConfig (split + close with hotkey tooltips)
  • Slots API: renderTitle, renderHeaderExtras, renderToolbar (full eject) on PaneDefinition
  • PaneContext and TabContext types with enriched layout info (parentDirection, position)
  • 57 store tests passing
  • Wired up in desktop app's v2 workspace with proper pane registry, empty state, and command palette

Test plan

  • Open v2 workspace → empty state with action buttons renders
  • Click + → dropdown shows Terminal/Chat/Browser options
  • Add terminal tab → tab appears with pane header (icon + title + split/close)
  • Click split → new terminal pane appears (direction auto-picks based on layout)
  • Click close → pane closes, last pane closes tab
  • Resize split handles → weights update
  • Tab rename (double-click) → inline input works
  • Tab context menu → Rename/Close/Close Others/Close All
  • Hover pane header actions → tooltips with hotkey labels
  • bun test in packages/panes → 57 tests pass
  • bun run typecheck in packages/panes → clean

Summary by cubic

Redesigned the pane layout to a simpler Tab → Split → Pane model using the new @superset/panes package. Integrated into the desktop v2 workspace with weighted splits, resize, a streamlined Add Tab menu (with Show Preset Bar toggle), and a cleaner empty state.

  • New Features

    • N‑ary weighted splits via react-resizable-panels with resize/equalize.
    • Store with actions for tab/pane CRUD and split/resize/equalize; open/replace supported.
    • Slots on PaneDefinition and configurable headers via PaneActionConfig with hotkey tooltips.
    • Add Tab dropdown (Terminal, Chat, Browser) wired to the command palette; includes “Show Preset Bar”.
    • 57 store tests added.
  • Refactors

    • Removed legacy PaneViewer; empty state renamed to WorkspaceEmptyState.
    • Chat components moved under the pane registry and renamed to ChatPane.
    • Renamed @superset/pane-layout to @superset/panes; host-service CORS now respects DESKTOP_VITE_PORT for localhost/127.0.0.1; downgraded @mastra/core (1.17.0 → 1.16.0) and @pierre/diffs (1.1.7 → 1.1.3) to satisfy CI policy.

Written for commit 4d23d5f. Summary will update on new commits.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 1, 2026

Important

Review skipped

Too many files!

This PR contains 219 files, which is 69 over the limit of 150.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 00ff0ddd-6cfe-42e9-8805-a65dc6c3ab9a

📥 Commits

Reviewing files that changed from the base of the PR and between 2078a9e and 4d23d5f.

⛔ Files ignored due to path filters (1)
  • bun.lock is excluded by !**/*.lock
📒 Files selected for processing (219)
  • apps/desktop/package.json
  • apps/desktop/src/main/host-service/index.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/components/AddTabMenu/AddTabMenu.tsx
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/components/AddTabMenu/index.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/components/PaneViewer/PaneViewer.tsx
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/components/PaneViewer/components/PaneViewerEmptyState/index.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/components/PaneViewer/index.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/components/PaneViewer/pane-viewer.model.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/components/WorkspaceChat/index.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/components/WorkspaceEmptyState/WorkspaceEmptyState.tsx
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/components/WorkspaceEmptyState/index.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/components/WorkspaceFiles/index.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/components/WorkspaceTerminal/index.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/ChatPane/ChatPane.tsx
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/ChatPane/components/SessionSelector/SessionSelector.tsx
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/ChatPane/components/SessionSelector/components/SessionSelectorItem/SessionSelectorItem.tsx
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/ChatPane/components/SessionSelector/components/SessionSelectorItem/index.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/ChatPane/components/SessionSelector/index.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/ChatPane/components/WorkspaceChatInterface/ChatPaneInterface.tsx
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/ChatPane/components/WorkspaceChatInterface/components/ChatInputFooter/ChatInputFooter.tsx
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/ChatPane/components/WorkspaceChatInterface/components/ChatInputFooter/components/ChatComposerControls/ChatComposerControls.tsx
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/ChatPane/components/WorkspaceChatInterface/components/ChatInputFooter/components/ChatComposerControls/index.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/ChatPane/components/WorkspaceChatInterface/components/ChatInputFooter/components/ChatInputDropZone/ChatInputDropZone.tsx
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/ChatPane/components/WorkspaceChatInterface/components/ChatInputFooter/components/ChatInputDropZone/index.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/ChatPane/components/WorkspaceChatInterface/components/ChatInputFooter/components/ChatShortcuts/ChatShortcuts.tsx
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/ChatPane/components/WorkspaceChatInterface/components/ChatInputFooter/components/ChatShortcuts/index.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/ChatPane/components/WorkspaceChatInterface/components/ChatInputFooter/components/FileDropOverlay/FileDropOverlay.tsx
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/ChatPane/components/WorkspaceChatInterface/components/ChatInputFooter/components/FileDropOverlay/index.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/ChatPane/components/WorkspaceChatInterface/components/ChatInputFooter/components/LinkedIssuePill/LinkedIssuePill.tsx
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/ChatPane/components/WorkspaceChatInterface/components/ChatInputFooter/components/LinkedIssuePill/index.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/ChatPane/components/WorkspaceChatInterface/components/ChatInputFooter/components/LinkedIssues/LinkedIssues.tsx
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/ChatPane/components/WorkspaceChatInterface/components/ChatInputFooter/components/LinkedIssues/index.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/ChatPane/components/WorkspaceChatInterface/components/ChatInputFooter/components/SlashCommandPreview/SlashCommandPreview.tsx
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/ChatPane/components/WorkspaceChatInterface/components/ChatInputFooter/components/SlashCommandPreview/components/SlashCommandParamField/SlashCommandParamField.tsx
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/ChatPane/components/WorkspaceChatInterface/components/ChatInputFooter/components/SlashCommandPreview/components/SlashCommandParamField/index.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/ChatPane/components/WorkspaceChatInterface/components/ChatInputFooter/components/SlashCommandPreview/index.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/ChatPane/components/WorkspaceChatInterface/components/ChatInputFooter/components/SlashCommandPreview/slash-command-preview.model.test.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/ChatPane/components/WorkspaceChatInterface/components/ChatInputFooter/components/SlashCommandPreview/slash-command-preview.model.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/ChatPane/components/WorkspaceChatInterface/components/ChatInputFooter/hooks/useDocumentDrag/index.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/ChatPane/components/WorkspaceChatInterface/components/ChatInputFooter/hooks/useDocumentDrag/useDocumentDrag.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/ChatPane/components/WorkspaceChatInterface/components/ChatInputFooter/index.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/ChatPane/components/WorkspaceChatInterface/components/ChatInputFooter/types.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/ChatPane/components/WorkspaceChatInterface/components/ChatInputFooter/utils/getErrorMessage.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/ChatPane/components/WorkspaceChatInterface/components/ChatMessageList/ChatMessageList.test.tsx
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/ChatPane/components/WorkspaceChatInterface/components/ChatMessageList/ChatMessageList.tsx
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/ChatPane/components/WorkspaceChatInterface/components/ChatMessageList/ChatMessageList.types.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/ChatPane/components/WorkspaceChatInterface/components/ChatMessageList/components/AssistantMessage/AssistantMessage.tsx
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/ChatPane/components/WorkspaceChatInterface/components/ChatMessageList/components/AssistantMessage/index.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/ChatPane/components/WorkspaceChatInterface/components/ChatMessageList/components/AttachmentChip/AttachmentChip.tsx
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/ChatPane/components/WorkspaceChatInterface/components/ChatMessageList/components/AttachmentChip/index.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/ChatPane/components/WorkspaceChatInterface/components/ChatMessageList/components/ChatSearch/ChatSearch.tsx
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/ChatPane/components/WorkspaceChatInterface/components/ChatMessageList/components/ChatSearch/index.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/ChatPane/components/WorkspaceChatInterface/components/ChatMessageList/components/InterruptedFooter/InterruptedFooter.tsx
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/ChatPane/components/WorkspaceChatInterface/components/ChatMessageList/components/InterruptedFooter/index.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/ChatPane/components/WorkspaceChatInterface/components/ChatMessageList/components/MessageScrollbackRail/MessageScrollbackRail.tsx
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/ChatPane/components/WorkspaceChatInterface/components/ChatMessageList/components/MessageScrollbackRail/index.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/ChatPane/components/WorkspaceChatInterface/components/ChatMessageList/components/PendingApprovalMessage/PendingApprovalMessage.tsx
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/ChatPane/components/WorkspaceChatInterface/components/ChatMessageList/components/PendingApprovalMessage/index.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/ChatPane/components/WorkspaceChatInterface/components/ChatMessageList/components/PendingPlanApprovalMessage/PendingPlanApprovalMessage.tsx
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/ChatPane/components/WorkspaceChatInterface/components/ChatMessageList/components/PendingPlanApprovalMessage/index.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/ChatPane/components/WorkspaceChatInterface/components/ChatMessageList/components/PendingQuestionMessage/PendingQuestionMessage.tsx
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/ChatPane/components/WorkspaceChatInterface/components/ChatMessageList/components/PendingQuestionMessage/index.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/ChatPane/components/WorkspaceChatInterface/components/ChatMessageList/components/SubagentExecutionMessage/SubagentExecutionMessage.tsx
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/ChatPane/components/WorkspaceChatInterface/components/ChatMessageList/components/SubagentExecutionMessage/index.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/ChatPane/components/WorkspaceChatInterface/components/ChatMessageList/components/SubagentExecutionMessage/utils/toSubagentViewModels.test.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/ChatPane/components/WorkspaceChatInterface/components/ChatMessageList/components/SubagentExecutionMessage/utils/toSubagentViewModels.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/ChatPane/components/WorkspaceChatInterface/components/ChatMessageList/components/ThinkingMessage/ThinkingMessage.tsx
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/ChatPane/components/WorkspaceChatInterface/components/ChatMessageList/components/ThinkingMessage/index.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/ChatPane/components/WorkspaceChatInterface/components/ChatMessageList/components/ToolPreviewMessage/ToolPreviewMessage.tsx
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/ChatPane/components/WorkspaceChatInterface/components/ChatMessageList/components/ToolPreviewMessage/index.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/ChatPane/components/WorkspaceChatInterface/components/ChatMessageList/components/UserMessage/UserMessage.tsx
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/ChatPane/components/WorkspaceChatInterface/components/ChatMessageList/components/UserMessage/components/UserMessageActions/UserMessageActions.tsx
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/ChatPane/components/WorkspaceChatInterface/components/ChatMessageList/components/UserMessage/components/UserMessageActions/index.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/ChatPane/components/WorkspaceChatInterface/components/ChatMessageList/components/UserMessage/components/UserMessageAttachments/UserMessageAttachments.tsx
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/ChatPane/components/WorkspaceChatInterface/components/ChatMessageList/components/UserMessage/components/UserMessageAttachments/index.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/ChatPane/components/WorkspaceChatInterface/components/ChatMessageList/components/UserMessage/components/UserMessageEditor/UserMessageEditor.tsx
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/ChatPane/components/WorkspaceChatInterface/components/ChatMessageList/components/UserMessage/components/UserMessageEditor/index.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/ChatPane/components/WorkspaceChatInterface/components/ChatMessageList/components/UserMessage/components/UserMessageText/UserMessageText.tsx
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/ChatPane/components/WorkspaceChatInterface/components/ChatMessageList/components/UserMessage/components/UserMessageText/index.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/ChatPane/components/WorkspaceChatInterface/components/ChatMessageList/components/UserMessage/index.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/ChatPane/components/WorkspaceChatInterface/components/ChatMessageList/components/UserMessage/types.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/ChatPane/components/WorkspaceChatInterface/components/ChatMessageList/components/UserMessage/utils/getUserMessageDraft/getUserMessageDraft.test.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/ChatPane/components/WorkspaceChatInterface/components/ChatMessageList/components/UserMessage/utils/getUserMessageDraft/getUserMessageDraft.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/ChatPane/components/WorkspaceChatInterface/components/ChatMessageList/components/UserMessage/utils/getUserMessageDraft/index.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/ChatPane/components/WorkspaceChatInterface/components/ChatMessageList/hooks/useChatMessageSearch/index.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/ChatPane/components/WorkspaceChatInterface/components/ChatMessageList/hooks/useChatMessageSearch/useChatMessageSearch.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/ChatPane/components/WorkspaceChatInterface/components/ChatMessageList/index.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/ChatPane/components/WorkspaceChatInterface/components/ChatMessageList/utils/messageListHelpers.test.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/ChatPane/components/WorkspaceChatInterface/components/ChatMessageList/utils/messageListHelpers.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/ChatPane/components/WorkspaceChatInterface/components/McpControls/McpControls.tsx
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/ChatPane/components/WorkspaceChatInterface/components/McpControls/index.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/ChatPane/components/WorkspaceChatInterface/components/MentionPopover/MentionPopover.tsx
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/ChatPane/components/WorkspaceChatInterface/components/MentionPopover/index.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/ChatPane/components/WorkspaceChatInterface/components/ModelPicker/ModelPicker.tsx
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/ChatPane/components/WorkspaceChatInterface/components/ModelPicker/components/ModelProviderGroup/ModelProviderGroup.tsx
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/ChatPane/components/WorkspaceChatInterface/components/ModelPicker/components/ModelProviderGroup/components/AnthropicProviderHeading/AnthropicProviderHeading.tsx
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/ChatPane/components/WorkspaceChatInterface/components/ModelPicker/components/ModelProviderGroup/components/AnthropicProviderHeading/index.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/ChatPane/components/WorkspaceChatInterface/components/ModelPicker/components/ModelProviderGroup/components/OpenAIProviderHeading/OpenAIProviderHeading.tsx
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/ChatPane/components/WorkspaceChatInterface/components/ModelPicker/components/ModelProviderGroup/components/OpenAIProviderHeading/index.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/ChatPane/components/WorkspaceChatInterface/components/ModelPicker/components/ModelProviderGroup/index.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/ChatPane/components/WorkspaceChatInterface/components/ModelPicker/index.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/ChatPane/components/WorkspaceChatInterface/components/ModelPicker/utils/groupModelsByProvider/groupModelsByProvider.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/ChatPane/components/WorkspaceChatInterface/components/ModelPicker/utils/groupModelsByProvider/index.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/ChatPane/components/WorkspaceChatInterface/components/ModelPicker/utils/providerToLogo/index.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/ChatPane/components/WorkspaceChatInterface/components/ModelPicker/utils/providerToLogo/providerToLogo.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/ChatPane/components/WorkspaceChatInterface/hooks/useMcpUi/index.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/ChatPane/components/WorkspaceChatInterface/hooks/useMcpUi/useMcpUi.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/ChatPane/components/WorkspaceChatInterface/hooks/useOptimisticUpload/index.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/ChatPane/components/WorkspaceChatInterface/hooks/useOptimisticUpload/useOptimisticUpload.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/ChatPane/components/WorkspaceChatInterface/hooks/useSlashCommandExecutor/index.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/ChatPane/components/WorkspaceChatInterface/hooks/useSlashCommandExecutor/model-query.test.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/ChatPane/components/WorkspaceChatInterface/hooks/useSlashCommandExecutor/model-query.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/ChatPane/components/WorkspaceChatInterface/hooks/useSlashCommandExecutor/prompt-result.test.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/ChatPane/components/WorkspaceChatInterface/hooks/useSlashCommandExecutor/prompt-result.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/ChatPane/components/WorkspaceChatInterface/hooks/useSlashCommandExecutor/useSlashCommandExecutor.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/ChatPane/components/WorkspaceChatInterface/index.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/ChatPane/components/WorkspaceChatInterface/types.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/ChatPane/components/WorkspaceChatInterface/utils/optimisticUserMessage/index.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/ChatPane/components/WorkspaceChatInterface/utils/optimisticUserMessage/optimisticUserMessage.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/ChatPane/components/WorkspaceChatInterface/utils/sendMessage/index.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/ChatPane/components/WorkspaceChatInterface/utils/sendMessage/sendMessage.test.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/ChatPane/components/WorkspaceChatInterface/utils/sendMessage/sendMessage.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/ChatPane/components/WorkspaceChatInterface/utils/toRuntimeImages/index.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/ChatPane/components/WorkspaceChatInterface/utils/toRuntimeImages/toRuntimeImages.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/ChatPane/components/WorkspaceChatInterface/utils/transientUserTurn/index.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/ChatPane/components/WorkspaceChatInterface/utils/transientUserTurn/transientUserTurn.test.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/ChatPane/components/WorkspaceChatInterface/utils/transientUserTurn/transientUserTurn.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/ChatPane/components/WorkspaceChatInterface/utils/uploadFiles/index.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/ChatPane/components/WorkspaceChatInterface/utils/uploadFiles/uploadFiles.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/ChatPane/hooks/useWorkspaceChatController/index.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/ChatPane/hooks/useWorkspaceChatController/useWorkspaceChatController.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/ChatPane/hooks/useWorkspaceChatDisplay/index.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/ChatPane/hooks/useWorkspaceChatDisplay/useWorkspaceChatDisplay.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/ChatPane/index.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/FilesPane/FilesPane.tsx
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/FilesPane/components/WorkspaceFilePreview/WorkspaceFilePreview.tsx
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/FilesPane/components/WorkspaceFilePreview/components/WorkspaceFilePreviewContent/WorkspaceFilePreviewContent.tsx
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/FilesPane/components/WorkspaceFilePreview/components/WorkspaceFilePreviewContent/index.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/FilesPane/components/WorkspaceFilePreview/index.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/FilesPane/components/WorkspaceFilesSearchResultItem/WorkspaceFilesSearchResultItem.tsx
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/FilesPane/components/WorkspaceFilesSearchResultItem/index.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/FilesPane/components/WorkspaceFilesToolbar/WorkspaceFilesToolbar.tsx
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/FilesPane/components/WorkspaceFilesToolbar/index.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/FilesPane/components/WorkspaceFilesTreeItem/WorkspaceFilesTreeItem.tsx
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/FilesPane/components/WorkspaceFilesTreeItem/index.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/FilesPane/hooks/useWorkspaceFileSearch/index.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/FilesPane/hooks/useWorkspaceFileSearch/useWorkspaceFileSearch.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/FilesPane/index.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/TerminalPane/TerminalPane.tsx
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/TerminalPane/index.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/index.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/usePaneRegistry.tsx
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/useV2WorkspacePaneLayout/index.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/useV2WorkspacePaneLayout/useV2WorkspacePaneLayout.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/page.tsx
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/types.ts
  • apps/desktop/src/renderer/routes/_authenticated/hooks/useDashboardSidebarState/useDashboardSidebarState.ts
  • apps/desktop/src/renderer/routes/_authenticated/providers/CollectionsProvider/dashboardSidebarLocal/schema.ts
  • packages/chat/package.json
  • packages/host-service/src/runtime/pull-requests/pull-requests.ts
  • packages/pane-layout/src/core/store/index.ts
  • packages/pane-layout/src/core/store/store.test.ts
  • packages/pane-layout/src/core/store/store.ts
  • packages/pane-layout/src/core/store/utils/index.ts
  • packages/pane-layout/src/core/store/utils/utils.ts
  • packages/pane-layout/src/index.ts
  • packages/pane-layout/src/react/components/PaneWorkspace/PaneWorkspace.tsx
  • packages/pane-layout/src/react/components/PaneWorkspace/components/PaneContent/PaneContent.tsx
  • packages/pane-layout/src/react/components/PaneWorkspace/components/PaneGroup/PaneGroup.tsx
  • packages/pane-layout/src/react/components/PaneWorkspace/components/PaneGroup/index.ts
  • packages/pane-layout/src/react/components/PaneWorkspace/components/PaneNodeView/PaneNodeView.tsx
  • packages/pane-layout/src/react/components/PaneWorkspace/components/PaneNodeView/index.ts
  • packages/pane-layout/src/react/components/PaneWorkspace/components/PaneRootTabs/components/PaneRootTabItem/components/RootRenameInput/index.ts
  • packages/pane-layout/src/react/components/PaneWorkspace/components/PaneRootTabs/components/PaneRootTabItem/index.ts
  • packages/pane-layout/src/react/components/PaneWorkspace/components/PaneRootTabs/index.ts
  • packages/pane-layout/src/react/components/PaneWorkspace/components/PaneRootView/PaneRootView.tsx
  • packages/pane-layout/src/react/components/PaneWorkspace/components/PaneRootView/index.ts
  • packages/pane-layout/src/react/components/PaneWorkspace/components/PaneSplitHandle/PaneSplitHandle.tsx
  • packages/pane-layout/src/react/components/PaneWorkspace/components/PaneSplitHandle/index.ts
  • packages/pane-layout/src/react/components/PaneWorkspace/index.ts
  • packages/pane-layout/src/react/components/index.ts
  • packages/pane-layout/src/react/hooks/index.ts
  • packages/pane-layout/src/react/hooks/usePaneWorkspaceStore/index.ts
  • packages/pane-layout/src/react/hooks/usePaneWorkspaceStore/usePaneWorkspaceStore.ts
  • packages/pane-layout/src/react/index.ts
  • packages/pane-layout/src/react/types.ts
  • packages/pane-layout/src/types.ts
  • packages/panes/README.md
  • packages/panes/package.json
  • packages/panes/src/core/store/index.ts
  • packages/panes/src/core/store/store.test.ts
  • packages/panes/src/core/store/store.ts
  • packages/panes/src/core/store/utils/index.ts
  • packages/panes/src/core/store/utils/utils.test.ts
  • packages/panes/src/core/store/utils/utils.ts
  • packages/panes/src/index.ts
  • packages/panes/src/react/components/PaneHeaderActions/PaneHeaderActions.tsx
  • packages/panes/src/react/components/PaneHeaderActions/index.ts
  • packages/panes/src/react/components/Workspace/Workspace.tsx
  • packages/panes/src/react/components/Workspace/components/Tab/Tab.tsx
  • packages/panes/src/react/components/Workspace/components/Tab/components/Pane/Pane.tsx
  • packages/panes/src/react/components/Workspace/components/Tab/components/Pane/components/PaneContent/PaneContent.tsx
  • packages/panes/src/react/components/Workspace/components/Tab/components/Pane/components/PaneContent/index.ts
  • packages/panes/src/react/components/Workspace/components/Tab/components/Pane/components/PaneHeader/PaneHeader.tsx
  • packages/panes/src/react/components/Workspace/components/Tab/components/Pane/components/PaneHeader/index.ts
  • packages/panes/src/react/components/Workspace/components/Tab/components/Pane/index.ts
  • packages/panes/src/react/components/Workspace/components/Tab/index.ts
  • packages/panes/src/react/components/Workspace/components/TabBar/TabBar.tsx
  • packages/panes/src/react/components/Workspace/components/TabBar/components/TabItem/TabItem.tsx
  • packages/panes/src/react/components/Workspace/components/TabBar/components/TabItem/components/TabRenameInput/TabRenameInput.tsx
  • packages/panes/src/react/components/Workspace/components/TabBar/components/TabItem/components/TabRenameInput/index.ts
  • packages/panes/src/react/components/Workspace/components/TabBar/components/TabItem/index.ts
  • packages/panes/src/react/components/Workspace/components/TabBar/index.ts
  • packages/panes/src/react/components/Workspace/index.ts
  • packages/panes/src/react/index.ts
  • packages/panes/src/react/types.ts
  • packages/panes/src/types.ts
  • packages/panes/tsconfig.json
  • plans/panes-v2-data-model-redesign.md

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch saddlepaddle/billowy-culotte

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

8 issues found across 219 files

Note: This PR contains a large number of files. cubic only reviews up to 75 files per PR, so some files may not have been reviewed.

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/usePaneRegistry.tsx">

<violation number="1" location="apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/usePaneRegistry.tsx:15">
P2: Use a cross-platform basename helper (or `path.basename`) instead of splitting on "/" so Windows paths render correctly.

(Based on your team's feedback about using cross-platform path utilities instead of split.) [FEEDBACK_USED]</violation>
</file>

<file name="packages/panes/src/react/components/Workspace/Workspace.tsx">

<violation number="1" location="packages/panes/src/react/components/Workspace/Workspace.tsx:45">
P1: Handle `closeTab` promise rejections in bulk-close handlers instead of firing async calls without await/catch.

(Based on your team's feedback about handling async rejections with await/catch to avoid unhandled promise rejections.) [FEEDBACK_USED]</violation>
</file>

<file name="packages/panes/src/react/components/Workspace/components/TabBar/TabBar.tsx">

<violation number="1" location="packages/panes/src/react/components/Workspace/components/TabBar/TabBar.tsx:60">
P2: The add-tab button is rendered even when no add action exists, resulting in a visible but non-functional control.</violation>
</file>

<file name="plans/panes-v2-data-model-redesign.md">

<violation number="1" location="plans/panes-v2-data-model-redesign.md:432">
P2: The package rename step contains a no-op (`@superset/panes` → `@superset/panes`) and misses the real old package name, which can cause the migration to be implemented incorrectly.</violation>

<violation number="2" location="plans/panes-v2-data-model-redesign.md:434">
P2: The desktop import update step is a no-op and should reference the old package name as the source of the rename.</violation>

<violation number="3" location="plans/panes-v2-data-model-redesign.md:580">
P3: Verification steps still reference `packages/pane-layout` after the package rename, which makes the test command path inconsistent with the migration plan.</violation>

<violation number="4" location="plans/panes-v2-data-model-redesign.md:654">
P2: The README example uses `renderToolbarActions`, but the documented `PaneDefinition` interface only defines `renderToolbar`, so the sample API usage is incorrect.</violation>
</file>

<file name="packages/panes/src/react/components/Workspace/components/Tab/Tab.tsx">

<violation number="1" location="packages/panes/src/react/components/Workspace/components/Tab/Tab.tsx:79">
P3: Add a key to the fragment returned from the map so React can reconcile list items correctly (use a keyed Fragment instead of the shorthand).</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

onCloseTab={closeTab}
onCloseOtherTabs={(tabId) => {
for (const tab of tabs) {
if (tab.id !== tabId) closeTab(tab.id);
Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai Bot Apr 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1: Handle closeTab promise rejections in bulk-close handlers instead of firing async calls without await/catch.

(Based on your team's feedback about handling async rejections with await/catch to avoid unhandled promise rejections.)

View Feedback

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/panes/src/react/components/Workspace/Workspace.tsx, line 45:

<comment>Handle `closeTab` promise rejections in bulk-close handlers instead of firing async calls without await/catch.

(Based on your team's feedback about handling async rejections with await/catch to avoid unhandled promise rejections.) </comment>

<file context>
@@ -0,0 +1,74 @@
+				onCloseTab={closeTab}
+				onCloseOtherTabs={(tabId) => {
+					for (const tab of tabs) {
+						if (tab.id !== tabId) closeTab(tab.id);
+					}
+				}}
</file context>
Fix with Cubic

PaneViewerData,
} from "../../types";

function getFileTitle(filePath: string): string {
Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai Bot Apr 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Use a cross-platform basename helper (or path.basename) instead of splitting on "/" so Windows paths render correctly.

(Based on your team's feedback about using cross-platform path utilities instead of split.)

View Feedback

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/usePaneRegistry.tsx, line 15:

<comment>Use a cross-platform basename helper (or `path.basename`) instead of splitting on "/" so Windows paths render correctly.

(Based on your team's feedback about using cross-platform path utilities instead of split.) </comment>

<file context>
@@ -0,0 +1,96 @@
+	PaneViewerData,
+} from "../../types";
+
+function getFileTitle(filePath: string): string {
+	return filePath.split("/").pop() ?? filePath;
+}
</file context>
Fix with Cubic

</TooltipContent>
</Tooltip>
);
return button;
Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai Bot Apr 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: The add-tab button is rendered even when no add action exists, resulting in a visible but non-functional control.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/panes/src/react/components/Workspace/components/TabBar/TabBar.tsx, line 60:

<comment>The add-tab button is rendered even when no add action exists, resulting in a visible but non-functional control.</comment>

<file context>
@@ -59,50 +46,46 @@ function AddRootButtonCell<TPaneData>({
-			</TooltipContent>
-		</Tooltip>
-	);
+	return button;
 }
 
</file context>
Suggested change
return button;
return null;
Fix with Cubic


1. Rename `packages/pane-layout/` → `packages/panes/` and `@superset/panes` → `@superset/panes` in `package.json`
2. Delete all existing source files in `src/` (types, store, react components, tests)
3. Update the import in `apps/desktop/package.json` from `@superset/panes` to `@superset/panes`
Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai Bot Apr 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: The desktop import update step is a no-op and should reference the old package name as the source of the rename.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At plans/panes-v2-data-model-redesign.md, line 434:

<comment>The desktop import update step is a no-op and should reference the old package name as the source of the rename.</comment>

<file context>
@@ -0,0 +1,961 @@
+
+1. Rename `packages/pane-layout/` → `packages/panes/` and `@superset/panes` → `@superset/panes` in `package.json`
+2. Delete all existing source files in `src/` (types, store, react components, tests)
+3. Update the import in `apps/desktop/package.json` from `@superset/panes` to `@superset/panes`
+4. Stub `src/index.ts` so the build doesn't break
+
</file context>
Suggested change
3. Update the import in `apps/desktop/package.json` from `@superset/panes` to `@superset/panes`
3. Update the import in `apps/desktop/package.json` from `@superset/pane-layout` to `@superset/panes`
Fix with Cubic


### Phase 1: Rename + gut the package

1. Rename `packages/pane-layout/` → `packages/panes/` and `@superset/panes` → `@superset/panes` in `package.json`
Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai Bot Apr 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: The package rename step contains a no-op (@superset/panes@superset/panes) and misses the real old package name, which can cause the migration to be implemented incorrectly.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At plans/panes-v2-data-model-redesign.md, line 432:

<comment>The package rename step contains a no-op (`@superset/panes` → `@superset/panes`) and misses the real old package name, which can cause the migration to be implemented incorrectly.</comment>

<file context>
@@ -0,0 +1,961 @@
+
+### Phase 1: Rename + gut the package
+
+1. Rename `packages/pane-layout/` → `packages/panes/` and `@superset/panes` → `@superset/panes` in `package.json`
+2. Delete all existing source files in `src/` (types, store, react components, tests)
+3. Update the import in `apps/desktop/package.json` from `@superset/panes` to `@superset/panes`
</file context>
Suggested change
1. Rename `packages/pane-layout/``packages/panes/` and `@superset/panes``@superset/panes` in `package.json`
1. Rename `packages/pane-layout/``packages/panes/` and `@superset/pane-layout``@superset/panes` in `package.json`
Fix with Cubic

renderPane: (ctx) => <CodeEditor file={ctx.pane.data.filePath} />,
getTitle: (ctx) => ctx.pane.data.filePath.split("/").pop(),
getIcon: (ctx) => <FileIcon />,
renderToolbarActions: (ctx) => (
Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai Bot Apr 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: The README example uses renderToolbarActions, but the documented PaneDefinition interface only defines renderToolbar, so the sample API usage is incorrect.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At plans/panes-v2-data-model-redesign.md, line 654:

<comment>The README example uses `renderToolbarActions`, but the documented `PaneDefinition` interface only defines `renderToolbar`, so the sample API usage is incorrect.</comment>

<file context>
@@ -0,0 +1,961 @@
+    renderPane: (ctx) => <CodeEditor file={ctx.pane.data.filePath} />,
+    getTitle: (ctx) => ctx.pane.data.filePath.split("/").pop(),
+    getIcon: (ctx) => <FileIcon />,
+    renderToolbarActions: (ctx) => (
+      !ctx.pane.pinned && <PinButton onClick={() => ctx.actions.pin()} />
+    ),
</file context>
Suggested change
renderToolbarActions: (ctx) => (
renderToolbar: (ctx) => (
Fix with Cubic


## Verification

1. `bun test` in `packages/pane-layout` — all tests pass
Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai Bot Apr 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P3: Verification steps still reference packages/pane-layout after the package rename, which makes the test command path inconsistent with the migration plan.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At plans/panes-v2-data-model-redesign.md, line 580:

<comment>Verification steps still reference `packages/pane-layout` after the package rename, which makes the test command path inconsistent with the migration plan.</comment>

<file context>
@@ -0,0 +1,961 @@
+
+## Verification
+
+1. `bun test` in `packages/pane-layout` — all tests pass
+2. `bun run typecheck` — all packages type-check
+3. `bun run lint:fix` — clean lint
</file context>
Suggested change
1. `bun test` in `packages/pane-layout` — all tests pass
1. `bun test` in `packages/panes` — all tests pass
Fix with Cubic

{node.children.map((child, index) => {
const key = child.type === "pane" ? child.paneId : child.id;
return (
<>
Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai Bot Apr 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P3: Add a key to the fragment returned from the map so React can reconcile list items correctly (use a keyed Fragment instead of the shorthand).

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/panes/src/react/components/Workspace/components/Tab/Tab.tsx, line 79:

<comment>Add a key to the fragment returned from the map so React can reconcile list items correctly (use a keyed Fragment instead of the shorthand).</comment>

<file context>
@@ -0,0 +1,123 @@
+			{node.children.map((child, index) => {
+				const key = child.type === "pane" ? child.paneId : child.id;
+				return (
+					<>
+						{index > 0 && <ResizableHandle key={`handle-${key}`} />}
+						<ResizablePanel key={key} defaultSize={percentages[index]}>
</file context>
Fix with Cubic

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 1, 2026

🚀 Preview Deployment

🔗 Preview Links

Service Status Link
Neon Database (Neon) View Branch
Fly.io Electric (Fly.io) View App
Vercel API (Vercel) Open Preview
Vercel Web (Vercel) Open Preview
Vercel Marketing (Vercel) Open Preview
Vercel Admin (Vercel) Open Preview
Vercel Docs (Vercel) Open Preview

Preview updates automatically with new commits

…ease-age policy

@mastra/core 1.17.0 → 1.16.0 (released 2026-03-24)
@pierre/diffs 1.1.7 → 1.1.3 (released 2026-03-21)
@saddlepaddle saddlepaddle merged commit 4a2bcb1 into main Apr 1, 2026
13 of 14 checks passed
Kitenite added a commit that referenced this pull request Apr 19, 2026
…t link UI

- Unify DevicePicker / ProjectPickerPill / CompareBaseBranchPicker to a
  shared FORM_PICKER_TRIGGER_CLASS: no background, h-[22px], text-[11px]
  text-muted-foreground, size-3 icons, align="start" dropdowns. Bump the
  project trigger thumbnail to size-4; drop the leftover `!` override
  (twMerge handles it).

- DevicePicker: icon-only trigger (aria-label + title surface the name).

- Rewrite IssueLinkCommand / PRLinkCommand / GitHubIssueLinkCommand to
  one codepath each: accept a button as `children`, wrap it in
  PopoverTrigger, own their open state internally. No more shared
  plusMenuRef, no more external open/onOpenChange/anchorRef coordination,
  no manual onPointerDownOutside anchor-guard — Radix handles toggle and
  dismiss natively so clicking a trigger while its popover is open
  closes it like every other picker.

- v2 NewWorkspace PromptGroup: drop the three popover-open useStates +
  plusMenuRef + manual toggle handlers. AttachmentButtons becomes a
  layout shell that renders the three trigger elements as props; each
  wraps a shared LinkTrigger (tooltip + pill button).

- Chat (v1 + v2) + v1 NewWorkspace PromptGroup: remove the link-issue
  popover wiring (IssueLinkCommand usage, ChatShortcuts' onLinkIssue
  callback). PlusMenu in chat collapses from a dropdown with
  attach/link options to a plain attachment button.

- Temporarily disable v2 ChatPane render: it predates this PR and is
  missing ChatServiceProvider (introduced in PR #3088), so
  chatServiceTrpc has no context in TiptapPromptEditor. Replaced with a
  "Chat pane is temporarily disabled" placeholder; original render body
  commented out for quick restoration.
Kitenite added a commit that referenced this pull request Apr 19, 2026
- Drop "previously this did X" / "introduced in PR #3088" / commented-out
  renderPane block in v2 usePaneRegistry chat pane.
- Collapse JSDocs that only restated the function's name (ParentDirectoryPicker,
  AddRepositoryModals layout blurb, per-method docs on UseFolderFirstImportResult,
  persistLocalProject).
- Tighten the explanatory comments that still earn their keep (pending
  PROJECT_NOT_SETUP interceptor, PinAndSetupModal conflict state, store
  onSuccess / forceRepoint prop docs).
Kitenite added a commit that referenced this pull request Apr 20, 2026
* docs: v2 project create/import design + plan

Simplified redesign after PR review. Collapses the earlier three-signal
backing model (cloud + per-host cloud signal + local) into two signals
(cloud + local-only), removes the v2_host_projects cloud table and
Electric sync, drops per-row state decoration on the sidebar, and moves
backing checks to action time (workspace-create modal, error paths).

* feat(trpc): v2Projects.findByGitHubRemote + jwt-scoped create

Adds the cloud-side matcher used by host-service's folder-first import
flow: given a clone URL, returns candidate projects the user has access
to whose GitHub repo matches (case-insensitively). Named findByGitHubRemote
(not findByRemote) because the match is GitHub-specific.

v2Projects.create switches to jwtProcedure with an explicit
organizationId + repoCloneUrl, matching the shape host-service needs to
call from project.create. No existing callers.

parseGitHubRemote moves from packages/host-service to packages/shared so
both cloud tRPC and host-service consume the same implementation.

* feat(host-service): project.create / setup / list / findByPath / remove

Full create/import lifecycle in host-service:

- project.list — DB read of host-service.projects. Pure, no filesystem
  probing. Stale paths surface via operation errors, not proactive checks.
- project.findByPath — validate git root, read remote, forward to cloud
  v2Projects.findByGitHubRemote. Backs the folder-first import picker.
- project.create — discriminated-union mode (empty/clone/importLocal/
  template); Phase 1 ships clone + importLocal only, empty and template
  throw NOT_IMPLEMENTED.
- project.setup — discriminated-union mode (clone/import) with
  acknowledgeWorkspaceInvalidation gate on the re-point case.
- project.remove — local worktree + repo dir teardown.

Cloud backing (v2_host_projects) is intentionally absent: there is no
per-host cloud signal in this design. Backing is a local-only concept,
checked at action time.

Adds ProjectNotSetupCause to the error formatter so the renderer can
catch throws from workspace.create (next commit) and open the Pin & Set
Up modal inline.

* feat(desktop): add-repository modals at dashboard layout level

Three flows for getting projects onto this device:

- New project — clone a GitHub URL into a chosen parent directory.
  Drives project.create(mode=clone).
- Import existing folder — native picker → project.findByPath branches on
  candidate count. 0 → name + create (importLocal). 1, not set up here →
  auto-advance to project.setup. 1, already set up → destructive re-point
  confirmation. >1 → picker modal.
- Pin & set up — clone an existing cloud project onto this device.
  Drives project.setup(mode=clone), with forceRepoint entry for repair.

All three modals are mounted once at the dashboard layout level via
AddRepositoryModals, and opened through a small zustand store. Sidebar
header "Add repository" dropdown triggers New project / Import folder.

* feat(desktop): workspaces-tab Available section + folder-first import trigger

Lists cloud projects in the user's active org that aren't pinned
locally. Pin & set up per row runs project.setup. Header dropdown
("Add repository") mirrors the sidebar — "+ New project" +
"Import existing folder." Entry points route through the dashboard-level
AddRepositoryModals via the shared zustand store.

useAvailableV2Projects powers the section: antijoin
v2Projects ∖ v2SidebarProjects scoped to the active organization,
with the existing v2-workspaces search filter applied.

* feat(desktop): workspace-create inline setup + remote-device stub

- Host-service workspaceCreation.{create,checkout,adopt} throw
  PROJECT_NOT_SETUP (PRECONDITION_FAILED + cause { kind, projectId })
  when this host has no local project row. No more silent auto-clone
  into ~/.superset/repos/ — the user explicitly picks where to clone.

- Pending workspace-create page intercepts data.projectNotSetup on the
  error, opens the Pin & set up modal pre-filled with the project, and
  registers a one-shot onSuccess callback to retry the original intent
  once setup resolves. The pending row stays in "creating" through the
  modal so the UI doesn't flicker to failed.

- Clicking a remote-device workspace row lands on the new
  WorkspaceNotOnThisHostState stub: explains the workspace lives on
  another host, offers "Set up here" (opens Pin & set up for the
  project) or "Browse workspaces." V2 workspace page checks
  host.machineId via live query and renders the stub before mounting
  the pane tree, which would otherwise crash on a foreign worktree.

* Fix infinite import

* fix: pre-existing notification test, a11y labels, design doc shape

- notification-manager.test: update expected strings to match source
  (strings changed in #3039; test wasn't updated, CI was red on main too)
- DashboardSidebarHeader: aria-label="Add repository" on icon-only
  dropdown triggers so screen readers announce them (tooltips don't
  count as accessible names)
- docs/design/v2-project-create-import: correct v2Projects.create input
  shape (jwt-scoped { organizationId, name, slug, repoCloneUrl })

* feat(desktop): unify new-workspace pickers + link popovers, strip chat link UI

- Unify DevicePicker / ProjectPickerPill / CompareBaseBranchPicker to a
  shared FORM_PICKER_TRIGGER_CLASS: no background, h-[22px], text-[11px]
  text-muted-foreground, size-3 icons, align="start" dropdowns. Bump the
  project trigger thumbnail to size-4; drop the leftover `!` override
  (twMerge handles it).

- DevicePicker: icon-only trigger (aria-label + title surface the name).

- Rewrite IssueLinkCommand / PRLinkCommand / GitHubIssueLinkCommand to
  one codepath each: accept a button as `children`, wrap it in
  PopoverTrigger, own their open state internally. No more shared
  plusMenuRef, no more external open/onOpenChange/anchorRef coordination,
  no manual onPointerDownOutside anchor-guard — Radix handles toggle and
  dismiss natively so clicking a trigger while its popover is open
  closes it like every other picker.

- v2 NewWorkspace PromptGroup: drop the three popover-open useStates +
  plusMenuRef + manual toggle handlers. AttachmentButtons becomes a
  layout shell that renders the three trigger elements as props; each
  wraps a shared LinkTrigger (tooltip + pill button).

- Chat (v1 + v2) + v1 NewWorkspace PromptGroup: remove the link-issue
  popover wiring (IssueLinkCommand usage, ChatShortcuts' onLinkIssue
  callback). PlusMenu in chat collapses from a dropdown with
  attach/link options to a plain attachment button.

- Temporarily disable v2 ChatPane render: it predates this PR and is
  missing ChatServiceProvider (introduced in PR #3088), so
  chatServiceTrpc has no context in TiptapPromptEditor. Replaced with a
  "Chat pane is temporarily disabled" placeholder; original render body
  commented out for quick restoration.

* feat(desktop): host-scoped project picker with Available / Needs setup sections

The v2 new-workspace picker was listing every cloud project the user
had access to, regardless of whether it was set up on the selected
device. That produced the PROJECT_NOT_SETUP error path on submit —
reviewers flagged the pending-row-stuck-in-creating fallout as a P1.

Root-cause fix: split the project list by selected-host availability.

- `useHostProjectIds(hostTarget)` queries host-service `project.list`
  on the chosen device (local via activeHostUrl, remote via relay) and
  returns the set of set-up project IDs.
- PromptGroup splits `recentProjects` into `availableProjects` +
  `needSetupProjects` using that set; changing the device refetches.
- ProjectPickerPill renders two CommandGroup sections: Available (click
  selects) and Needs setup (click opens Pin & set up for that project).
- Pin & set up already invalidates `["project", "list", activeHostUrl]`
  on success, so after setup the project flips to Available — user
  picks it and continues normally.

While `project.list` is loading or errors, everything falls back to
Available — picker stays usable; any real failure surfaces via the
existing workspace-create error path.

* lint

* fix(desktop): IssueLinkCommand uncontrolled close + PlusMenu aria-label

- IssueLinkCommand: the refactored popover-trigger API made `open` and
  `onOpenChange` optional so callers (v2 PromptGroup) could let Radix
  manage state. But `handleSelect` only fired the optional controlled
  callback, so in uncontrolled mode the popover never closed after
  picking an issue. Track state ourselves via a controllable-state
  pattern: internal `useState` when the prop is absent, caller's value
  when passed. `setOpen` always writes through, so close-on-select
  works in both modes.

- PlusMenu: add aria-label="Add attachment" to the icon-only trigger.
  Radix Tooltip sets aria-describedby on the trigger, not
  aria-labelledby, so screen readers previously announced it as an
  unlabeled button.

* refactor(desktop): drop controlled-open props from IssueLinkCommand; extend aria-label fix

- IssueLinkCommand: only caller passes `onSelect + children`, so the
  optional open/onOpenChange pass-through was dead code. Simplify to
  always-internal state. Radix Popover has no imperative close from
  inside its content — owning state is the canonical shadcn/cmdk
  pattern, not scaffolding.

- AttachmentButtons (v2): add aria-label to the shared LinkTrigger (so
  Link issue / Link GitHub issue / Link pull request all announce a
  name) and to the paperclip. Same fix as PlusMenu — Radix Tooltip
  sets aria-describedby on the trigger, not aria-labelledby, so
  tooltip-only buttons read as unlabeled to screen readers.

* fix(trpc): scope v2Project.findByGitHubRemote + modal picker to active org

host-service is pinned to a single organization at boot (env.ORGANIZATION_ID);
its local projects table has no orgId column. Project discovery was leaking
across orgs:

- v2Project.findByGitHubRemote used ctx.organizationIds (plural, all
  accessible orgs). The folder-first picker would surface candidates from
  orgs the current host can't set up, producing a confusing NOT_FOUND when
  host-service then called v2Project.get with its own org.
- DashboardNewWorkspaceModalContent queried collections.v2Projects with no
  org filter. Same over-fetch, same downstream failure.

Align both with the rest of the codebase (v2Project.get / create,
useAvailableV2Projects, useWorkspaceHostOptions) which take/filter by an
explicit active orgId:

- findByGitHubRemote: add organizationId input, authorize it against
  ctx.organizationIds (same shape as get/create), filter candidates by it.
- host-service project.findByPath: pass ctx.organizationId through.
- DashboardNewWorkspaceModalContent: .where(eq(projects.organizationId,
  activeOrganizationId)) on the live query, matching useAvailableV2Projects.

* Lint

* fix(host-service): clone-then-cloud in project.createFromClone, rollback on cloud failure

Matches the local-first-then-cloud pattern already used by
workspace.create (workspace-creation.ts:860-918, which git-worktree-adds
first then registers cloud with a rollback on failure).

Previously createFromClone called v2Project.create before cloneRepoInto,
so any clone failure (network, bad URL, auth, dir collision) left a cloud
v2_projects row with nothing local backing it on any host. Retrying the
flow with corrected input accumulated more orphans.

Reorder: clone first, register cloud in try/catch, rmSync the freshly-
created clone if cloud-create or persistLocalProject throws.

* fix(host-service): move project.create visibility into GitHub-provisioning modes

Only empty + template modes provision a new GitHub repo and need to tell
the GitHub App whether it should be private or public. clone +
importLocal reuse an existing remote where visibility is already set —
the top-level field was required but ignored for those two paths.

Move `visibility: z.enum(["private", "public"])` into the empty and
template variants of the discriminated union. Drop it from clone/
importLocal callers. Update design doc to match.

* refactor(desktop): use Radix composition for link-command tooltips, drop dead chat-link wiring

Responds to saddlepaddle + Kitenite reviews on PR #3566.

- IssueLinkCommand / PRLinkCommand / GitHubIssueLinkCommand now own the
  Popover + Tooltip composition internally via
  `PopoverTrigger asChild > TooltipTrigger asChild`. Callers pass a plain
  PromptInputButton + a tooltipLabel prop. Removes the LinkTrigger
  forwardRef + `{...rest}` spread trick that was sneaking Popover props
  through an intermediate Tooltip wrapper.
- Delete the misleading JSDoc at IssueLinkCommand claiming Radix can't be
  closed imperatively — PopoverClose exists; the controlled-open pattern
  we use is just shadcn's canonical combobox.
- Drop orphaned `_issueLinkOpen` / `_addLinkedIssue` + the
  `setIssueLinkOpen` prop threaded through ChatShortcuts in both v1 and
  v2 chat, plus the same dead state in v1 NewWorkspaceModal PromptGroup.
- Retire the CHAT_LINK_ISSUE hotkey entry — its only consumer was the
  dead setIssueLinkOpen toggle.

* chore: trim past-state narration + what-describing comments

- Drop "previously this did X" / "introduced in PR #3088" / commented-out
  renderPane block in v2 usePaneRegistry chat pane.
- Collapse JSDocs that only restated the function's name (ParentDirectoryPicker,
  AddRepositoryModals layout blurb, per-method docs on UseFolderFirstImportResult,
  persistLocalProject).
- Tighten the explanatory comments that still earn their keep (pending
  PROJECT_NOT_SETUP interceptor, PinAndSetupModal conflict state, store
  onSuccess / forceRepoint prop docs).

* refactor(desktop): strip v2 discovery/recovery surface to MVP

Two rules for v1:
- Sidebar = pinned projects.
- Workspaces tab = every workspace in the user's active org.

Code deletes:
- V2AvailableProjectsSection, useAvailableV2Projects, useHostProjectIds.
- v2UsersHosts innerJoin in useAccessibleV2Workspaces — tab no longer
  drops rows when host access changes.
- Available-section wiring in V2WorkspacesList + v2-workspaces/page.tsx.
- Available / Needs-setup split in ProjectPickerPill and the
  openPinAndSetup bridge in PromptGroup. Also removes the wrong-host
  bug (cubic AF_o, saddlepaddle CXVQ) as dead code.
- PROJECT_NOT_SETUP recovery loop in the pending page — failure is a
  plain toast now.

Docs realigned:
- design/v2-project-create-import.md opens with the two rules and
  moves Available / inline setup / backing signals to an explicit
  "Out of scope for v1" block.
- plans/20260417-v2-project-create-import-impl.md mirrors the same
  deferrals; Phase-1 checklist is now all checked.

Net −537 lines. Typecheck + lint clean.

* refactor(desktop): open remote-host workspaces without gating

Previously any workspace whose hostMachineId didn't match the local
machine landed on a WorkspaceNotOnThisHostState stub. That hid the
workspace from the user entirely when the whole point is to let them
see it. Delete the gate, delete the stub component, and let the
workspace page render for any host. Operations that assume local
filesystem (terminal spawn, local git) fail at the point they run.

Also slims the page's live query — projectGithubOwner, projectName,
hostMachineId etc. were only fed into the stub.

Design doc + plan updated to reflect the no-gating posture.

Resolves saddlepaddle CTvC.

* refactor(desktop): extract FormPickerTrigger component

Addresses saddlepaddle CWlq — the shared style for the three top-of-modal
pickers (Device / Project / Branch) lived as a string constant in
types.ts, which is an odd place for a className and doesn't compose.

Promote it to a named FormPickerTrigger component that encapsulates the
base button styles and accepts extra className + native button props.
The three call sites lose their raw <button type="button"> +
backtick-composed classNames.

Drops FORM_PICKER_TRIGGER_CLASS from types.ts.

* refactor(desktop): remove dead PinAndSetupModal + async-hygiene sweep

PinAndSetupModal had zero remaining callers after the MVP cut — the
pending-page PROJECT_NOT_SETUP interceptor and the Available-section
"Pin & set up" button were the only two. Delete the whole modal,
its store action, useOpenPinAndSetupModal hook, PinAndSetupTarget
type, and the forceRepoint plumbing that existed only to support it.

Also addresses the async-hygiene nits on the surviving surfaces:
- useFolderFirstImport.start wraps selectDirectory.mutateAsync in
  try/catch → reportError (coderabbit nmS, cubic op5).
- ParentDirectoryPicker.handleBrowse wraps the same (cubic op8).
- AddRepositoryModals effect adds .catch on startRef.current()
  (cubic oqE).
- FolderFirstImportModal keys CandidatePickerContent on repoPath so
  selectedId resets per import (coderabbit nmM).

Docs + plan updated to reflect the removed modal + ENOENT recovery
deferral.

Net −205 lines. Typecheck + lint clean.

* refactor(host-service): reject re-pointing instead of confirming it

v1 has no re-point UX. project.setup now treats an existing row as:
- same resolved path → no-op success (idempotent; fixes the false
  CONFLICT that cubic/coderabbit flagged on same-path setup).
- different path → CONFLICT with the existing path in the message,
  no escape hatch. User must project.remove first if they genuinely
  want to move the project.

Drops `acknowledgeWorkspaceInvalidation` from the input, the ack
branch of the CONFLICT guard, and the setupFromClone/setupFromImport
helpers + SetupContext type in handlers.ts (the setup path is small
enough to inline).

Client drops the confirm-repoint state, confirmRepoint method,
ConfirmRepointContent component, and the conflict branch in
SetupInvokeResult — none of which have anything to retry against.

Also fixes the TOCTOU race in cloneRepoInto: replaces
existsSync + rmSync-on-error with mkdirSync (atomic claim) +
rmSync-on-error, so clone failure can't delete a directory this
process didn't create.

Resolves coderabbit nmb, nmd, and cubic oqN.

* fix(desktop): unify workspaces-tab empty state

The onboarding "No workspaces yet" check was reading already-filtered
pinned/others counts, so a search that matched nothing landed on the
onboarding copy instead of the clear-filters UI.

Collapse to a single !hasAnyMatches branch that picks copy + icon
based on hasActiveFilters. Drops the bogus hasAnyWorkspaces check.

Resolves cubic CrwE.

* revert queries

* Clean up dead code

* refactor(desktop): port v1 new-project UI into NewProjectModal

Replace the bespoke name + clone-URL + parent-picker form with v1's
new-project page layout: a Location row (text input + browse button),
three mode tiles (Clone/Empty/Template), and a per-mode form. Only
Clone is wired up; Empty + Template carry "(coming soon)" since v2
project.create throws NOT_IMPLEMENTED for them.

Location auto-populates to ~/.superset/projects via window.getHomeDir.
Project name is derived from the clone URL's last segment so the form
matches v1 (no explicit name field).

ParentDirectoryPicker deleted — the inline Input + folder button
replaces it and there's no other caller.

* feat(db/trpc): decouple v2 projects from GitHub App installs

v2Projects previously required a non-null githubRepositoryId, which
gated project creation on the org having installed the repo via the
GitHub App. Cloning any other repo (public, not installed, or non-
matching) failed at the cloud step after a successful local clone.

Changes:
- githubRepositoryId becomes nullable with ON DELETE SET NULL,
  matching v1's projects table.
- repoCloneUrl is added as the canonical source of truth for the
  remote URL. Also nullable so empty-mode / local-only projects
  without a remote can coexist.
- UNIQUE(organization_id, lower(repo_clone_url)) prevents two
  projects from claiming the same repo in one org. NULLs don't
  collide, so URL-less projects still work.
- v2Project.create accepts an optional repoCloneUrl, canonicalizes
  via parseGitHubRemote, and links a matching github_repositories
  row case-insensitively when one exists. Unique-violation (23505)
  surfaces as CONFLICT with per-constraint messaging.
- v2Project.findByGitHubRemote matches on v2Projects.repoCloneUrl
  directly instead of joining through the installation table, so
  unlinked projects are discoverable.
- v2Project.get drops the derived repoCloneUrl — consumers read the
  stored column or the joined githubRepository directly.

Migration 0034 bundles all five schema changes. Nullable-safe: no
backfill required for existing rows.

* No candidate thing

* feat(desktop): flag projects not set up on selected host in new-workspace modal

After picking a host in DevicePicker, each project in ProjectPickerPill
shows an amber warning triangle when that host doesn't have the project
set up locally. A matching "Project needs to be set up" note appears
next to the ⌘↵ hint when the currently-selected project needs setup,
so the user sees the blocker before submitting.

Setup state comes from a per-host project.list query (re-added to the
host-service router). The RPC is resolved through the standard
getHostServiceClientByUrl path — local uses activeHostUrl, remote/cloud
goes through the relay. If the host is unreachable we treat setup as
unknown and hide the indicator rather than falsely flagging everything.

Submit path is unchanged: picking a not-set-up project still fires
workspace.create, which throws PROJECT_NOT_SETUP and surfaces as the
existing toast. Inline setup UX is still deferred.

* chore: biome format fix + sync design doc to workspaces-tab filter

- git.ts: biome wants the ghMsg ternary wrapped; main's 27e243b added
  the catch block and the CI biome check caught it post-merge.
- design doc: the workspaces tab code filters to hosts the user is
  linked to via v2_users_hosts, not every workspace in the org. Update
  wording to match what shipped; note teammate workspaces on unshared
  hosts are not surfaced in v1.

* docs: move v2 project create/import plan to plans/done

Plan is shipped — move per AGENTS.md rule 7 and drop the rewrite/history
notes in both plan and design doc since the PR body is the canonical
record of what was cut.

* docs: drop rewrite/history notes from plan and design doc

Captured in PR body instead.

* chore: trim restating/navigational comments in project handlers
@Kitenite Kitenite deleted the saddlepaddle/billowy-culotte branch May 6, 2026 04:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant