From 9c7be3d42a29f10ca2ea831f49415bb91083be12 Mon Sep 17 00:00:00 2001 From: Neil <4138956+nwparker@users.noreply.github.com> Date: Sat, 14 Nov 2026 11:03:20 -0800 Subject: [PATCH] refactor(renderer): organize status bar owners (#42456) --- config/focus-setting-read-baseline.txt | 22 +- config/host-list-render-baseline.txt | 4 +- config/react-compiler-bailout-baseline.txt | 24 +- config/recurring-timer-baseline.txt | 4 +- config/renderer-layout-writer-baseline.txt | 2 +- .../src/components/agent/icons/AgentIcon.tsx | 2 +- .../render-tree/MarkdownPreviewSizeGate.tsx | 2 +- .../OrchestrationPage.tsx | 2 +- .../agents-orchestration/StatusesPage.tsx | 2 +- .../UsageAccountsCard.tsx | 2 +- .../agents-orchestration/UsagePage.tsx | 2 +- .../BrowserAgentVerificationPane.tsx | 2 +- .../BrowserStoryboardWindow.tsx | 2 +- .../task-storyboard/TasksAnimatedVisual.tsx | 2 +- .../WorkbenchTerminalPanes.tsx | 2 +- .../WorkspacesAnimatedVisual.tsx | 2 +- .../FloatingTerminalIconContextMenu.tsx | 2 +- .../use-native-chat-host-outage-notice.ts | 2 +- ...ChatStructuredSession.host-outage.test.tsx | 190 ----------- .../usage/NativeChatAccountUsageCard.tsx | 11 +- .../usage/NativeChatUsageLimitActions.tsx | 4 +- .../claude/accounts-pane-claude-section.tsx | 2 +- .../codex/accounts-pane-codex-section.tsx | 2 +- .../AntigravityTerminalAccountRows.tsx | 2 +- .../accounts-pane-gemini-section.tsx | 2 +- .../accounts-pane-opencode-section.tsx | 2 +- .../accounts/usage/MiniMaxAccountsSection.tsx | 2 +- .../AppearanceWindowSidebarSection.tsx | 2 +- .../StatusBarUsageFormatSetting.tsx | 4 +- .../ManageSessionsSection.tsx | 2 +- .../shared/kill-all-terminal-surfaces.ts | 4 +- .../src/components/stats/GrokUsagePane.tsx | 2 +- .../status-bar/CaffeinateStatusSegment.tsx | 2 +- .../status-bar/PetStatusSegment.tsx | 2 +- .../src/components/status-bar/StatusBar.tsx | 26 -- .../status-bar/StatusBarSurface.tsx | 46 +-- .../StatusBarUsageChangeNotices.test.tsx | 126 -------- .../account-switch-row-keyboard.test.tsx | 60 ---- .../{ => accounts}/AccountSwitchList.tsx | 4 +- .../AccountSwitchRowItem.fixture.tsx | 6 +- .../{ => accounts}/AccountSwitchRowItem.tsx | 0 .../{ => accounts}/ClaudeSwitcherForOwner.tsx | 10 +- .../{ => accounts}/ClaudeSwitcherMenu.tsx | 4 +- .../{ => accounts}/CodexResetCredits.tsx | 2 +- .../CodexSwitcherMenu.fixture.tsx | 10 +- .../{ => accounts}/CodexSwitcherMenu.tsx | 11 +- .../ProviderAccountChatButton.tsx | 4 +- .../{ => accounts}/ProviderIdentityCard.tsx | 8 +- .../codex-restart-status-summary.ts | 0 .../{ => accounts}/codex-sign-in-action.ts | 4 +- .../codex-switcher-projection.ts | 8 +- .../provider-account-sync-key.ts | 2 +- .../provider-icons.tsx} | 2 +- .../status-bar-claude-accounts.ts | 4 +- .../status-bar-codex-accounts.ts | 4 +- .../status-bar-runtime-targets.ts | 10 +- .../use-claude-switcher-state.ts | 2 +- .../use-codex-switcher-controller.ts | 9 +- .../use-provider-account-list.ts | 2 +- .../codex-restart-status-keyboard.test.tsx | 49 --- .../StatusBarAccountControls.tsx | 4 +- .../StatusBarVisibilityMenu.tsx | 8 +- .../status-bar-agent-gating.ts | 4 +- .../status-bar-context-menu-policy.ts | 0 .../{ => composition}/status-bar-density.ts | 0 .../status-bar-provider-visibility.ts | 6 +- .../status-bar-usage-collapse.ts | 0 .../status-bar-usage-sections.ts | 10 +- .../use-available-status-bar-toggles.ts | 4 +- .../use-status-bar-controller.ts | 21 +- .../PortsStatusSegment.tsx | 6 +- .../RuntimeHostStatusRow.tsx | 4 +- .../SshHostFindPopover.tsx | 4 +- .../SshStatusSegment.tsx | 20 +- .../SshTargetStatusRow.tsx | 8 +- .../ports-status-popover-rows.tsx | 4 +- .../remote-host-connection-status.ts | 12 +- .../runtime-environment-explicit-connect.ts | 6 +- .../runtime-host-resources.ts | 9 +- .../ssh-status-menu-rows.ts | 4 +- .../ssh-status-segment-copy.ts | 0 .../use-runtime-host-resources.ts | 0 .../{ => plugins}/PluginStatusBarItems.tsx | 0 .../{ => plugins}/PluginsStatusSegment.tsx | 0 .../resource-pty-virtualization.test.tsx | 300 ------------------ ...rce-session-removal-render-budget.test.tsx | 47 --- .../ResourceUsageStatusSegment.tsx | 18 +- .../{ => resources}/hosted-review-label.ts | 6 +- .../daemon-session-inventory-invalidation.ts | 0 .../resource-session-inventory-cache.ts | 6 +- .../inventory}/resource-session-inventory.ts | 2 +- .../use-resource-session-inventory.ts | 2 +- .../resource-manager-terminal-copy.ts | 0 .../popover}/resource-memory-metric-copy.ts | 4 +- .../popover}/resource-usage-kill-dialog.tsx | 2 +- .../popover}/resource-usage-metrics.tsx | 4 +- .../popover}/resource-usage-popover-body.tsx | 7 +- ...resource-usage-popover-summary.fixture.tsx | 6 +- .../resource-usage-popover-summary.tsx | 2 +- .../popover}/resource-usage-resource-tree.tsx | 4 +- .../popover}/resource-usage-session-rows.tsx | 15 +- .../resource-usage-status-trigger.tsx | 2 +- .../pty}/ResourcePtyDetails.tsx | 0 .../{ => resources/pty}/ResourcePtyList.tsx | 0 .../{ => resources/pty}/ResourcePtyPanel.tsx | 2 +- .../{ => resources/pty}/ResourcePtyRow.tsx | 0 .../pty}/resource-pty-view-model.ts | 23 +- .../pty}/use-resource-pty-actions.ts | 4 +- .../resource-usage-open-slices.ts | 10 +- .../resource-usage-space-scan-ready.ts | 0 .../resource-manager-worktree-target.test.ts | 2 +- .../resource-manager-worktree-target.ts | 2 +- ...resource-session-kill-confirmation.test.ts | 2 +- .../resource-session-kill-confirmation.ts | 4 +- .../resource-session-navigation.ts | 2 +- .../use-resource-usage-actions.ts | 22 +- .../use-resource-memory-snapshot.ts | 4 +- .../use-resource-usage-derived-model.test.tsx | 80 +---- .../use-resource-usage-derived-model.ts | 26 +- .../use-resource-usage-status-controller.ts | 24 +- .../use-resource-view-visible.ts | 0 .../merge-snapshot-and-sessions.ts} | 8 +- .../resource-session-bindings.test.ts | 2 +- .../resource-session-bindings.ts | 4 +- .../resource-session-labels.ts | 8 +- .../resource-usage-folder-merge.test.ts | 6 +- .../resource-usage-merge-types.ts | 10 +- .../resource-workspace-host.ts | 6 +- .../RemoteServerUpdateStatusSegment.tsx | 2 +- .../SkillUpdateStatusSegment.tsx | 6 +- .../UpdateStatusSegment.test.tsx | 8 +- .../{ => updates}/UpdateStatusSegment.tsx | 4 +- .../AntigravityUsageMenu.fixture.tsx | 4 +- .../{ => usage}/AntigravityUsageMenu.tsx | 8 +- .../{ => usage}/InlineProviderUsage.tsx | 16 +- .../{ => usage}/ProviderDetailsMenu.tsx | 12 +- .../{ => usage}/StatusBarProviderSegment.tsx | 35 +- .../StatusBarUsageChangeNoticeCard.tsx | 0 .../StatusBarUsageChangeNotices.tsx | 2 +- .../{ => usage}/StatusBarUsageEmptyCta.tsx | 4 +- .../UsagePercentageDisplayChangeNotice.tsx | 6 +- .../{ => usage}/UsageRosterPanel.tsx | 14 +- .../rate-limit-user-facing-error-catalog-a.ts | 0 .../rate-limit-user-facing-error-catalog-b.ts | 0 .../rate-limit-user-facing-error-catalog.ts | 0 .../rate-limit-user-facing-error-types.ts | 0 .../errors}/rate-limit-user-facing-error.ts | 0 .../{ => usage}/owner-not-set-up-copy.ts | 2 +- .../{ => usage}/owner-usage-rate-limits.ts | 8 +- .../provider-extra-usage-section.tsx | 10 +- .../provider-segment-monthly-window.test.tsx | 6 +- .../provider-usage-panel.tsx} | 30 +- .../rate-limit-window-localized-label.ts | 4 +- .../{ => usage}/usage-error-copy.ts | 6 +- .../{ => usage}/usage-format-template.ts | 8 +- .../{ => usage}/usage-grouped-pools.tsx | 6 +- .../{ => usage}/usage-percentage-label.ts | 2 +- .../{ => usage}/usage-pool-label.ts | 4 +- .../usage-provider-settings-target.ts | 4 +- .../{ => usage}/usage-roster-formatting.ts | 0 .../{ => usage}/usage-roster-row-state.ts | 2 +- .../{ => usage}/usage-unit-label.tsx | 8 +- .../use-owner-usage-rate-limits.test.tsx | 33 +- .../use-owner-usage-rate-limits.ts | 6 +- .../use-resource-memory-snapshot.test.tsx | 122 ------- .../use-resource-pty-actions.test.tsx | 219 ------------- .../WorkspaceSpaceCompactPanel.tsx | 8 +- .../WorkspaceSpaceManagerPanel.tsx | 4 +- ...use-workspace-space-decision-projection.ts | 8 +- .../use-workspace-space-git-refresh-action.ts | 10 +- .../workspace-space-decision-details.ts | 36 +-- .../workspace-space-decision-hover-card.tsx | 11 +- .../workspace-space-decision-inputs.ts | 6 +- .../workspace-space-decision-labels.ts | 6 +- .../workspace-space-git-status-order.ts | 4 +- .../workspace-space-issue-freshness.tsx | 4 +- .../workspace-space-status-badge.tsx | 8 +- .../use-workspace-space-manager-bindings.ts | 8 +- .../use-workspace-space-manager-panel.ts | 24 +- .../use-workspace-space-manager-projection.ts | 14 +- .../workspace-space-delete-selection.ts | 4 +- .../workspace-space-manager-state-types.ts | 4 +- .../manager}/workspace-space-presentation.ts | 18 +- .../workspace-space-state-resolution.ts | 4 +- .../workspace-space-visit-activity.ts | 4 +- .../workspace-space-breakdown-list.tsx | 15 +- .../overview}/workspace-space-layout.ts | 0 .../workspace-space-manager-overview.tsx | 11 +- .../overview}/workspace-space-metrics.tsx | 2 +- .../overview}/workspace-space-treemap.tsx | 8 +- .../table}/workspace-space-changes.tsx | 20 +- .../table}/workspace-space-manager-table.tsx | 6 +- .../table}/workspace-space-open-change.ts | 15 +- .../workspace-space-selection-controls.tsx | 2 +- .../table}/workspace-space-table-layout.ts | 0 .../workspace-space-worktree-actions.tsx | 10 +- .../table}/workspace-space-worktree-row.tsx | 28 +- .../workspace-space-format.ts | 4 +- .../workspace-space-manager-toolbar.tsx | 12 +- .../workspace-space-manager-view.tsx | 6 +- .../SpaceWindowStatePublisher.tsx | 6 +- .../workspace-space/WorkspaceSpacePage.tsx | 4 +- .../src/lib/agent-catalog/agent-catalog.ts | 2 +- .../runtime/hosts/wsl/wsl-host-user-start.ts | 2 +- .../web-preload-resource-visibility.test.tsx | 2 +- 205 files changed, 640 insertions(+), 1843 deletions(-) delete mode 100644 src/renderer/src/components/native-chat/surfaces/integration/NativeChatStructuredSession.host-outage.test.tsx delete mode 100644 src/renderer/src/components/status-bar/StatusBarUsageChangeNotices.test.tsx delete mode 100644 src/renderer/src/components/status-bar/account-switch-row-keyboard.test.tsx rename src/renderer/src/components/status-bar/{ => accounts}/AccountSwitchList.tsx (95%) rename src/renderer/src/components/status-bar/{ => accounts}/AccountSwitchRowItem.fixture.tsx (91%) rename src/renderer/src/components/status-bar/{ => accounts}/AccountSwitchRowItem.tsx (100%) rename src/renderer/src/components/status-bar/{ => accounts}/ClaudeSwitcherForOwner.tsx (97%) rename src/renderer/src/components/status-bar/{ => accounts}/ClaudeSwitcherMenu.tsx (91%) rename src/renderer/src/components/status-bar/{ => accounts}/CodexResetCredits.tsx (97%) rename src/renderer/src/components/status-bar/{ => accounts}/CodexSwitcherMenu.fixture.tsx (94%) rename src/renderer/src/components/status-bar/{ => accounts}/CodexSwitcherMenu.tsx (95%) rename src/renderer/src/components/status-bar/{ => accounts}/ProviderAccountChatButton.tsx (93%) rename src/renderer/src/components/status-bar/{ => accounts}/ProviderIdentityCard.tsx (81%) rename src/renderer/src/components/status-bar/{ => accounts}/codex-restart-status-summary.ts (100%) rename src/renderer/src/components/status-bar/{ => accounts}/codex-sign-in-action.ts (95%) rename src/renderer/src/components/status-bar/{ => accounts}/codex-switcher-projection.ts (74%) rename src/renderer/src/components/status-bar/{ => accounts}/provider-account-sync-key.ts (97%) rename src/renderer/src/components/status-bar/{icons.tsx => accounts/provider-icons.tsx} (99%) rename src/renderer/src/components/status-bar/{ => accounts}/status-bar-claude-accounts.ts (97%) rename src/renderer/src/components/status-bar/{ => accounts}/status-bar-codex-accounts.ts (97%) rename src/renderer/src/components/status-bar/{ => accounts}/status-bar-runtime-targets.ts (87%) rename src/renderer/src/components/status-bar/{ => accounts}/use-claude-switcher-state.ts (96%) rename src/renderer/src/components/status-bar/{ => accounts}/use-codex-switcher-controller.ts (96%) rename src/renderer/src/components/status-bar/{ => accounts}/use-provider-account-list.ts (97%) delete mode 100644 src/renderer/src/components/status-bar/codex-restart-status-keyboard.test.tsx rename src/renderer/src/components/status-bar/{ => composition}/StatusBarAccountControls.tsx (96%) rename src/renderer/src/components/status-bar/{ => composition}/StatusBarVisibilityMenu.tsx (98%) rename src/renderer/src/components/status-bar/{ => composition}/status-bar-agent-gating.ts (77%) rename src/renderer/src/components/status-bar/{ => composition}/status-bar-context-menu-policy.ts (100%) rename src/renderer/src/components/status-bar/{ => composition}/status-bar-density.ts (100%) rename src/renderer/src/components/status-bar/{ => composition}/status-bar-provider-visibility.ts (96%) rename src/renderer/src/components/status-bar/{ => composition}/status-bar-usage-collapse.ts (100%) rename src/renderer/src/components/status-bar/{ => composition}/status-bar-usage-sections.ts (85%) rename src/renderer/src/components/status-bar/{ => composition}/use-available-status-bar-toggles.ts (76%) rename src/renderer/src/components/status-bar/{ => composition}/use-status-bar-controller.ts (94%) rename src/renderer/src/components/status-bar/{ => host-connections}/PortsStatusSegment.tsx (98%) rename src/renderer/src/components/status-bar/{ => host-connections}/RuntimeHostStatusRow.tsx (98%) rename src/renderer/src/components/status-bar/{ => host-connections}/SshHostFindPopover.tsx (95%) rename src/renderer/src/components/status-bar/{ => host-connections}/SshStatusSegment.tsx (93%) rename src/renderer/src/components/status-bar/{ => host-connections}/SshTargetStatusRow.tsx (92%) rename src/renderer/src/components/status-bar/{ => host-connections}/ports-status-popover-rows.tsx (98%) rename src/renderer/src/components/status-bar/{ => host-connections}/remote-host-connection-status.ts (90%) rename src/renderer/src/components/status-bar/{ => host-connections}/runtime-environment-explicit-connect.ts (92%) rename src/renderer/src/components/status-bar/{ => host-connections}/runtime-host-resources.ts (95%) rename src/renderer/src/components/status-bar/{ => host-connections}/ssh-status-menu-rows.ts (91%) rename src/renderer/src/components/status-bar/{ => host-connections}/ssh-status-segment-copy.ts (100%) rename src/renderer/src/components/status-bar/{ => host-connections}/use-runtime-host-resources.ts (100%) rename src/renderer/src/components/status-bar/{ => plugins}/PluginStatusBarItems.tsx (100%) rename src/renderer/src/components/status-bar/{ => plugins}/PluginsStatusSegment.tsx (100%) delete mode 100644 src/renderer/src/components/status-bar/resource-pty-virtualization.test.tsx delete mode 100644 src/renderer/src/components/status-bar/resource-session-removal-render-budget.test.tsx rename src/renderer/src/components/status-bar/{ => resources}/ResourceUsageStatusSegment.tsx (92%) rename src/renderer/src/components/status-bar/{ => resources}/hosted-review-label.ts (76%) rename src/renderer/src/components/status-bar/{ => resources/inventory}/daemon-session-inventory-invalidation.ts (100%) rename src/renderer/src/components/status-bar/{ => resources/inventory}/resource-session-inventory-cache.ts (96%) rename src/renderer/src/components/status-bar/{ => resources/inventory}/resource-session-inventory.ts (95%) rename src/renderer/src/components/status-bar/{ => resources/inventory}/use-resource-session-inventory.ts (94%) rename src/renderer/src/components/status-bar/{ => resources/popover}/resource-manager-terminal-copy.ts (100%) rename src/renderer/src/components/status-bar/{ => resources/popover}/resource-memory-metric-copy.ts (94%) rename src/renderer/src/components/status-bar/{ => resources/popover}/resource-usage-kill-dialog.tsx (96%) rename src/renderer/src/components/status-bar/{ => resources/popover}/resource-usage-metrics.tsx (97%) rename src/renderer/src/components/status-bar/{ => resources/popover}/resource-usage-popover-body.tsx (97%) rename src/renderer/src/components/status-bar/{ => resources/popover}/resource-usage-popover-summary.fixture.tsx (93%) rename src/renderer/src/components/status-bar/{ => resources/popover}/resource-usage-popover-summary.tsx (98%) rename src/renderer/src/components/status-bar/{ => resources/popover}/resource-usage-resource-tree.tsx (97%) rename src/renderer/src/components/status-bar/{ => resources/popover}/resource-usage-session-rows.tsx (94%) rename src/renderer/src/components/status-bar/{ => resources/popover}/resource-usage-status-trigger.tsx (97%) rename src/renderer/src/components/status-bar/{ => resources/pty}/ResourcePtyDetails.tsx (100%) rename src/renderer/src/components/status-bar/{ => resources/pty}/ResourcePtyList.tsx (100%) rename src/renderer/src/components/status-bar/{ => resources/pty}/ResourcePtyPanel.tsx (98%) rename src/renderer/src/components/status-bar/{ => resources/pty}/ResourcePtyRow.tsx (100%) rename src/renderer/src/components/status-bar/{ => resources/pty}/resource-pty-view-model.ts (90%) rename src/renderer/src/components/status-bar/{ => resources/pty}/use-resource-pty-actions.ts (97%) rename src/renderer/src/components/status-bar/{ => resources}/resource-usage-open-slices.ts (89%) rename src/renderer/src/components/status-bar/{ => resources}/resource-usage-space-scan-ready.ts (100%) rename src/renderer/src/components/status-bar/{ => resources/session-actions}/resource-manager-worktree-target.test.ts (87%) rename src/renderer/src/components/status-bar/{ => resources/session-actions}/resource-manager-worktree-target.ts (87%) rename src/renderer/src/components/status-bar/{ => resources/session-actions}/resource-session-kill-confirmation.test.ts (88%) rename src/renderer/src/components/status-bar/{ => resources/session-actions}/resource-session-kill-confirmation.ts (56%) rename src/renderer/src/components/status-bar/{ => resources/session-actions}/resource-session-navigation.ts (93%) rename src/renderer/src/components/status-bar/{ => resources/session-actions}/use-resource-usage-actions.ts (90%) rename src/renderer/src/components/status-bar/{ => resources}/use-resource-memory-snapshot.ts (93%) rename src/renderer/src/components/status-bar/{ => resources}/use-resource-usage-derived-model.test.tsx (63%) rename src/renderer/src/components/status-bar/{ => resources}/use-resource-usage-derived-model.ts (89%) rename src/renderer/src/components/status-bar/{ => resources}/use-resource-usage-status-controller.ts (91%) rename src/renderer/src/components/status-bar/{ => resources}/use-resource-view-visible.ts (100%) rename src/renderer/src/components/status-bar/{mergeSnapshotAndSessions.ts => resources/workspace-attribution/merge-snapshot-and-sessions.ts} (97%) rename src/renderer/src/components/status-bar/{ => resources/workspace-attribution}/resource-session-bindings.test.ts (92%) rename src/renderer/src/components/status-bar/{ => resources/workspace-attribution}/resource-session-bindings.ts (96%) rename src/renderer/src/components/status-bar/{ => resources/workspace-attribution}/resource-session-labels.ts (92%) rename src/renderer/src/components/status-bar/{ => resources/workspace-attribution}/resource-usage-folder-merge.test.ts (90%) rename src/renderer/src/components/status-bar/{ => resources/workspace-attribution}/resource-usage-merge-types.ts (88%) rename src/renderer/src/components/status-bar/{ => resources/workspace-attribution}/resource-workspace-host.ts (83%) rename src/renderer/src/components/status-bar/{ => updates}/RemoteServerUpdateStatusSegment.tsx (98%) rename src/renderer/src/components/status-bar/{ => updates}/SkillUpdateStatusSegment.tsx (92%) rename src/renderer/src/components/status-bar/{ => updates}/UpdateStatusSegment.test.tsx (94%) rename src/renderer/src/components/status-bar/{ => updates}/UpdateStatusSegment.tsx (96%) rename src/renderer/src/components/status-bar/{ => usage}/AntigravityUsageMenu.fixture.tsx (94%) rename src/renderer/src/components/status-bar/{ => usage}/AntigravityUsageMenu.tsx (92%) rename src/renderer/src/components/status-bar/{ => usage}/InlineProviderUsage.tsx (93%) rename src/renderer/src/components/status-bar/{ => usage}/ProviderDetailsMenu.tsx (91%) rename src/renderer/src/components/status-bar/{ => usage}/StatusBarProviderSegment.tsx (92%) rename src/renderer/src/components/status-bar/{ => usage}/StatusBarUsageChangeNoticeCard.tsx (100%) rename src/renderer/src/components/status-bar/{ => usage}/StatusBarUsageChangeNotices.tsx (97%) rename src/renderer/src/components/status-bar/{ => usage}/StatusBarUsageEmptyCta.tsx (98%) rename src/renderer/src/components/status-bar/{ => usage}/UsagePercentageDisplayChangeNotice.tsx (91%) rename src/renderer/src/components/status-bar/{ => usage}/UsageRosterPanel.tsx (95%) rename src/renderer/src/components/status-bar/{usage-errors => usage/errors}/rate-limit-user-facing-error-catalog-a.ts (100%) rename src/renderer/src/components/status-bar/{usage-errors => usage/errors}/rate-limit-user-facing-error-catalog-b.ts (100%) rename src/renderer/src/components/status-bar/{usage-errors => usage/errors}/rate-limit-user-facing-error-catalog.ts (100%) rename src/renderer/src/components/status-bar/{usage-errors => usage/errors}/rate-limit-user-facing-error-types.ts (100%) rename src/renderer/src/components/status-bar/{usage-errors => usage/errors}/rate-limit-user-facing-error.ts (100%) rename src/renderer/src/components/status-bar/{ => usage}/owner-not-set-up-copy.ts (96%) rename src/renderer/src/components/status-bar/{ => usage}/owner-usage-rate-limits.ts (97%) rename src/renderer/src/components/status-bar/{ => usage}/provider-extra-usage-section.tsx (93%) rename src/renderer/src/components/status-bar/{ => usage}/provider-segment-monthly-window.test.tsx (93%) rename src/renderer/src/components/status-bar/{tooltip.tsx => usage/provider-usage-panel.tsx} (94%) rename src/renderer/src/components/status-bar/{ => usage}/rate-limit-window-localized-label.ts (88%) rename src/renderer/src/components/status-bar/{ => usage}/usage-error-copy.ts (97%) rename src/renderer/src/components/status-bar/{ => usage}/usage-format-template.ts (93%) rename src/renderer/src/components/status-bar/{ => usage}/usage-grouped-pools.tsx (92%) rename src/renderer/src/components/status-bar/{ => usage}/usage-percentage-label.ts (94%) rename src/renderer/src/components/status-bar/{ => usage}/usage-pool-label.ts (95%) rename src/renderer/src/components/status-bar/{ => usage}/usage-provider-settings-target.ts (89%) rename src/renderer/src/components/status-bar/{ => usage}/usage-roster-formatting.ts (100%) rename src/renderer/src/components/status-bar/{ => usage}/usage-roster-row-state.ts (96%) rename src/renderer/src/components/status-bar/{ => usage}/usage-unit-label.tsx (81%) rename src/renderer/src/components/status-bar/{ => usage}/use-owner-usage-rate-limits.test.tsx (76%) rename src/renderer/src/components/status-bar/{ => usage}/use-owner-usage-rate-limits.ts (97%) delete mode 100644 src/renderer/src/components/status-bar/use-resource-memory-snapshot.test.tsx delete mode 100644 src/renderer/src/components/status-bar/use-resource-pty-actions.test.tsx rename src/renderer/src/components/status-bar/{ => workspace-storage}/WorkspaceSpaceCompactPanel.tsx (97%) rename src/renderer/src/components/status-bar/{ => workspace-storage}/WorkspaceSpaceManagerPanel.tsx (59%) rename src/renderer/src/components/status-bar/{ => workspace-storage/decisions}/use-workspace-space-decision-projection.ts (91%) rename src/renderer/src/components/status-bar/{ => workspace-storage/decisions}/use-workspace-space-git-refresh-action.ts (89%) rename src/renderer/src/components/status-bar/{ => workspace-storage/decisions}/workspace-space-decision-details.ts (82%) rename src/renderer/src/components/status-bar/{ => workspace-storage/decisions}/workspace-space-decision-hover-card.tsx (93%) rename src/renderer/src/components/status-bar/{ => workspace-storage/decisions}/workspace-space-decision-inputs.ts (90%) rename src/renderer/src/components/status-bar/{ => workspace-storage/decisions}/workspace-space-decision-labels.ts (94%) rename src/renderer/src/components/status-bar/{ => workspace-storage/decisions}/workspace-space-git-status-order.ts (83%) rename src/renderer/src/components/status-bar/{ => workspace-storage/decisions}/workspace-space-issue-freshness.tsx (93%) rename src/renderer/src/components/status-bar/{ => workspace-storage/decisions}/workspace-space-status-badge.tsx (91%) rename src/renderer/src/components/status-bar/{ => workspace-storage/manager}/use-workspace-space-manager-bindings.ts (94%) rename src/renderer/src/components/status-bar/{ => workspace-storage/manager}/use-workspace-space-manager-panel.ts (86%) rename src/renderer/src/components/status-bar/{ => workspace-storage/manager}/use-workspace-space-manager-projection.ts (92%) rename src/renderer/src/components/status-bar/{ => workspace-storage/manager}/workspace-space-delete-selection.ts (87%) rename src/renderer/src/components/status-bar/{ => workspace-storage/manager}/workspace-space-manager-state-types.ts (63%) rename src/renderer/src/components/status-bar/{ => workspace-storage/manager}/workspace-space-presentation.ts (91%) rename src/renderer/src/components/status-bar/{ => workspace-storage/manager}/workspace-space-state-resolution.ts (87%) rename src/renderer/src/components/status-bar/{ => workspace-storage/manager}/workspace-space-visit-activity.ts (77%) rename src/renderer/src/components/status-bar/{ => workspace-storage/overview}/workspace-space-breakdown-list.tsx (93%) rename src/renderer/src/components/status-bar/{ => workspace-storage/overview}/workspace-space-layout.ts (100%) rename src/renderer/src/components/status-bar/{ => workspace-storage/overview}/workspace-space-manager-overview.tsx (94%) rename src/renderer/src/components/status-bar/{ => workspace-storage/overview}/workspace-space-metrics.tsx (98%) rename src/renderer/src/components/status-bar/{ => workspace-storage/overview}/workspace-space-treemap.tsx (95%) rename src/renderer/src/components/status-bar/{ => workspace-storage/table}/workspace-space-changes.tsx (85%) rename src/renderer/src/components/status-bar/{ => workspace-storage/table}/workspace-space-manager-table.tsx (97%) rename src/renderer/src/components/status-bar/{ => workspace-storage/table}/workspace-space-open-change.ts (83%) rename src/renderer/src/components/status-bar/{ => workspace-storage/table}/workspace-space-selection-controls.tsx (97%) rename src/renderer/src/components/status-bar/{ => workspace-storage/table}/workspace-space-table-layout.ts (100%) rename src/renderer/src/components/status-bar/{ => workspace-storage/table}/workspace-space-worktree-actions.tsx (90%) rename src/renderer/src/components/status-bar/{ => workspace-storage/table}/workspace-space-worktree-row.tsx (88%) rename src/renderer/src/components/status-bar/{ => workspace-storage}/workspace-space-format.ts (96%) rename src/renderer/src/components/status-bar/{ => workspace-storage}/workspace-space-manager-toolbar.tsx (94%) rename src/renderer/src/components/status-bar/{ => workspace-storage}/workspace-space-manager-view.tsx (65%) diff --git a/config/focus-setting-read-baseline.txt b/config/focus-setting-read-baseline.txt index 570ecc3cff4..610ce97ff88 100644 --- a/config/focus-setting-read-baseline.txt +++ b/config/focus-setting-read-baseline.txt @@ -137,18 +137,18 @@ 1 src/renderer/src/components/skills/SkillsPage.tsx 1 src/renderer/src/components/skills/setup/linear-agent-skill-install-cta.tsx 1 src/renderer/src/components/source-control/BaseRefPicker.tsx -1 src/renderer/src/components/status-bar/ClaudeSwitcherMenu.tsx -1 src/renderer/src/components/status-bar/CodexSwitcherMenu.tsx -1 src/renderer/src/components/status-bar/SshStatusSegment.tsx +1 src/renderer/src/components/status-bar/accounts/ClaudeSwitcherMenu.tsx +1 src/renderer/src/components/status-bar/accounts/CodexSwitcherMenu.tsx +1 src/renderer/src/components/status-bar/host-connections/SshStatusSegment.tsx 1 src/renderer/src/components/status-bar/StatusBarSurface.tsx -2 src/renderer/src/components/status-bar/provider-account-sync-key.ts -1 src/renderer/src/components/status-bar/usage-provider-settings-target.ts -1 src/renderer/src/components/status-bar/use-claude-switcher-state.ts -2 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 -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 +2 src/renderer/src/components/status-bar/accounts/provider-account-sync-key.ts +1 src/renderer/src/components/status-bar/usage/usage-provider-settings-target.ts +1 src/renderer/src/components/status-bar/accounts/use-claude-switcher-state.ts +2 src/renderer/src/components/status-bar/accounts/use-codex-switcher-controller.ts +1 src/renderer/src/components/status-bar/composition/use-status-bar-controller.ts +1 src/renderer/src/components/status-bar/workspace-storage/decisions/use-workspace-space-git-refresh-action.ts +1 src/renderer/src/components/status-bar/workspace-storage/manager/use-workspace-space-manager-panel.ts +1 src/renderer/src/components/status-bar/workspace-storage/decisions/workspace-space-decision-details.ts 1 src/renderer/src/components/tab-bar/TabBar.tsx 2 src/renderer/src/components/tab-bar/use-tab-bar-runtime-model.ts 1 src/renderer/src/components/tab-bar/web-runtime-tab-move-mirror.ts diff --git a/config/host-list-render-baseline.txt b/config/host-list-render-baseline.txt index 8cceee047a8..31af020654b 100644 --- a/config/host-list-render-baseline.txt +++ b/config/host-list-render-baseline.txt @@ -9,7 +9,7 @@ 1 src/renderer/src/components/settings/quick-commands/QuickCommandsToolbar.tsx 1 src/renderer/src/components/settings/repository/hosts/RepositoryHostSetupsSection.tsx 1 src/renderer/src/components/sidebar/host-admission/ssh/AddRemoteHostSshConfigPicker.tsx -4 src/renderer/src/components/status-bar/SshStatusSegment.tsx -1 src/renderer/src/components/status-bar/resource-usage-popover-body.tsx +4 src/renderer/src/components/status-bar/host-connections/SshStatusSegment.tsx +1 src/renderer/src/components/status-bar/resources/popover/resource-usage-popover-body.tsx 1 src/renderer/src/components/tab-bar/TabBarQuickCommandAddActions.tsx 2 src/renderer/src/components/terminal-pane/quick-commands/TerminalQuickCommandsSubmenu.tsx diff --git a/config/react-compiler-bailout-baseline.txt b/config/react-compiler-bailout-baseline.txt index 0fa425d339b..77213de1849 100644 --- a/config/react-compiler-bailout-baseline.txt +++ b/config/react-compiler-bailout-baseline.txt @@ -550,18 +550,18 @@ 1 src/renderer/src/components/ssh-host-recovery/SshHostMoveAnywayAction.tsx 2 src/renderer/src/components/star-nag/StarNagAgentValueMomentObserver.tsx 1 src/renderer/src/components/stats/ShareUsageButton.tsx -2 src/renderer/src/components/status-bar/ClaudeSwitcherForOwner.tsx -1 src/renderer/src/components/status-bar/PortsStatusSegment.tsx -1 src/renderer/src/components/status-bar/RuntimeHostStatusRow.tsx -2 src/renderer/src/components/status-bar/SshTargetStatusRow.tsx -1 src/renderer/src/components/status-bar/icons.tsx -3 src/renderer/src/components/status-bar/status-bar-density.ts -2 src/renderer/src/components/status-bar/use-codex-switcher-controller.ts -1 src/renderer/src/components/status-bar/use-owner-usage-rate-limits.ts -1 src/renderer/src/components/status-bar/use-provider-account-list.ts -1 src/renderer/src/components/status-bar/use-resource-usage-actions.ts -1 src/renderer/src/components/status-bar/use-resource-view-visible.ts -1 src/renderer/src/components/status-bar/use-status-bar-controller.ts +2 src/renderer/src/components/status-bar/accounts/ClaudeSwitcherForOwner.tsx +1 src/renderer/src/components/status-bar/host-connections/PortsStatusSegment.tsx +1 src/renderer/src/components/status-bar/host-connections/RuntimeHostStatusRow.tsx +2 src/renderer/src/components/status-bar/host-connections/SshTargetStatusRow.tsx +1 src/renderer/src/components/status-bar/accounts/provider-icons.tsx +3 src/renderer/src/components/status-bar/composition/status-bar-density.ts +2 src/renderer/src/components/status-bar/accounts/use-codex-switcher-controller.ts +1 src/renderer/src/components/status-bar/usage/use-owner-usage-rate-limits.ts +1 src/renderer/src/components/status-bar/accounts/use-provider-account-list.ts +1 src/renderer/src/components/status-bar/resources/session-actions/use-resource-usage-actions.ts +1 src/renderer/src/components/status-bar/resources/use-resource-view-visible.ts +1 src/renderer/src/components/status-bar/composition/use-status-bar-controller.ts 2 src/renderer/src/components/tab-bar/TabBar.tsx 2 src/renderer/src/components/tab-bar/TabBarCreateEntry.tsx 1 src/renderer/src/components/tab-bar/TabStripScrollIndicator.tsx diff --git a/config/recurring-timer-baseline.txt b/config/recurring-timer-baseline.txt index 7a71fe7cf94..c7ed80ccedd 100644 --- a/config/recurring-timer-baseline.txt +++ b/config/recurring-timer-baseline.txt @@ -76,8 +76,8 @@ 1 src/renderer/src/components/sidebar/SeveredTerminalDaemonBanner.tsx 1 src/renderer/src/components/sidebar/StalledTerminalDaemonBanner.tsx 1 src/renderer/src/components/sidebar/workspace-card/activity/prompt-cache-countdown-clock.ts -1 src/renderer/src/components/status-bar/use-resource-memory-snapshot.ts -1 src/renderer/src/components/status-bar/use-runtime-host-resources.ts +1 src/renderer/src/components/status-bar/resources/use-resource-memory-snapshot.ts +1 src/renderer/src/components/status-bar/host-connections/use-runtime-host-resources.ts 1 src/renderer/src/components/tab-bar/tab-strip-drag-scroll.ts 1 src/renderer/src/components/terminal-pane/pty-transport/delivery/terminal-delivery-watchdog.ts 1 src/renderer/src/components/terminal-pane/pty-transport/remote-runtime/recovery/RemoteRuntimeRecoveryCard.tsx diff --git a/config/renderer-layout-writer-baseline.txt b/config/renderer-layout-writer-baseline.txt index a37b85ca88d..96e85d35294 100644 --- a/config/renderer-layout-writer-baseline.txt +++ b/config/renderer-layout-writer-baseline.txt @@ -10,7 +10,7 @@ 1 src/renderer/src/components/sidebar/workspace-card/activity/use-worktree-activity-statuses.ts 4 src/renderer/src/components/sidebar/workspace-card/activity/worktree-card-send-target-inputs.ts 4 src/renderer/src/components/sidebar/worktree-list/listing/use-agent-send-target.ts -1 src/renderer/src/components/status-bar/workspace-space-decision-inputs.ts +1 src/renderer/src/components/status-bar/workspace-storage/decisions/workspace-space-decision-inputs.ts 2 src/renderer/src/components/tab-bar/terminal-tab-activity-status.ts 3 src/renderer/src/components/tab-bar/use-tab-bar-runtime-model-worktree-write-probe.ts 1 src/renderer/src/components/tab-group/useTabGroupWorkspaceModel.ts diff --git a/src/renderer/src/components/agent/icons/AgentIcon.tsx b/src/renderer/src/components/agent/icons/AgentIcon.tsx index 38189616d4d..228b1240335 100644 --- a/src/renderer/src/components/agent/icons/AgentIcon.tsx +++ b/src/renderer/src/components/agent/icons/AgentIcon.tsx @@ -1,6 +1,6 @@ import type React from 'react' import { getAgentCatalog, getAgentLabel } from '../../../lib/agent-catalog/agent-catalog' -import { ClaudeIcon, DroidIcon, OpenAIIcon } from '@/components/status-bar/icons' +import { ClaudeIcon, DroidIcon, OpenAIIcon } from '@/components/status-bar/accounts/provider-icons' import type { TerminalAgent } from '../../../../../shared/agent-status/identity/terminal-agent' import { AgentLetterIcon, diff --git a/src/renderer/src/components/editor/markdown-preview/render-tree/MarkdownPreviewSizeGate.tsx b/src/renderer/src/components/editor/markdown-preview/render-tree/MarkdownPreviewSizeGate.tsx index ee429475a37..75caf1f1211 100644 --- a/src/renderer/src/components/editor/markdown-preview/render-tree/MarkdownPreviewSizeGate.tsx +++ b/src/renderer/src/components/editor/markdown-preview/render-tree/MarkdownPreviewSizeGate.tsx @@ -1,7 +1,7 @@ import { useTranslate } from '@/i18n/use-translate' import { isClipboardTextByteLengthOverLimit } from '../../../../../../shared/clipboard-text' import { LARGE_MARKDOWN_PREVIEW_MAX_BYTES } from '../document-worker/markdown-preview-document-types' -import '../../../status-bar/workspace-space-format' +import '../../../status-bar/workspace-storage/workspace-space-format' import { formatBytes } from '../../../../../../shared/format-bytes' export function MarkdownPreviewSizeGate({ diff --git a/src/renderer/src/components/feature-wall/agents-orchestration/OrchestrationPage.tsx b/src/renderer/src/components/feature-wall/agents-orchestration/OrchestrationPage.tsx index 1e55f0091a4..902bd570364 100644 --- a/src/renderer/src/components/feature-wall/agents-orchestration/OrchestrationPage.tsx +++ b/src/renderer/src/components/feature-wall/agents-orchestration/OrchestrationPage.tsx @@ -1,7 +1,7 @@ import { useCallback, useEffect, useRef, useState } from 'react' import type { JSX } from 'react' import { ChevronDown, Workflow } from 'lucide-react' -import { ClaudeIcon, OpenAIIcon } from '../../status-bar/icons' +import { ClaudeIcon, OpenAIIcon } from '../../status-bar/accounts/provider-icons' import { BUBBLE_FLIGHT_MS, BUBBLE_GAP_MS, diff --git a/src/renderer/src/components/feature-wall/agents-orchestration/StatusesPage.tsx b/src/renderer/src/components/feature-wall/agents-orchestration/StatusesPage.tsx index 2df05860436..8ec58a2a703 100644 --- a/src/renderer/src/components/feature-wall/agents-orchestration/StatusesPage.tsx +++ b/src/renderer/src/components/feature-wall/agents-orchestration/StatusesPage.tsx @@ -4,7 +4,7 @@ import { Wrench } from 'lucide-react' import { AgentStateDot } from '@/components/AgentStateDot' import { getAgentCatalog, type AgentCatalogEntry } from '@/lib/agent-catalog/agent-catalog' import { AgentIcon } from '@/components/agent/icons/AgentIcon' -import { ClaudeIcon, OpenAIIcon } from '../../status-bar/icons' +import { ClaudeIcon, OpenAIIcon } from '../../status-bar/accounts/provider-icons' import { installWindowVisibilityInterval } from '@/lib/window-activity/window-visibility-interval' import { cn } from '@/lib/class-names' import { useTranslate } from '@/i18n/use-translate' diff --git a/src/renderer/src/components/feature-wall/agents-orchestration/UsageAccountsCard.tsx b/src/renderer/src/components/feature-wall/agents-orchestration/UsageAccountsCard.tsx index 172233a8cf7..215d26545d1 100644 --- a/src/renderer/src/components/feature-wall/agents-orchestration/UsageAccountsCard.tsx +++ b/src/renderer/src/components/feature-wall/agents-orchestration/UsageAccountsCard.tsx @@ -4,7 +4,7 @@ import { Loader2, Plus } from 'lucide-react' import { toast } from 'sonner' import { useAppStore } from '@/store/index' import { Button } from '@/components/ui/button' -import { ClaudeIcon, OpenAIIcon } from '@/components/status-bar/icons' +import { ClaudeIcon, OpenAIIcon } from '@/components/status-bar/accounts/provider-icons' import { cn } from '@/lib/class-names' import { readIpcErrorMessage } from '@/runtime/errors/ipc-error' import { useMountedRef } from '@/hooks/useMountedRef' diff --git a/src/renderer/src/components/feature-wall/agents-orchestration/UsagePage.tsx b/src/renderer/src/components/feature-wall/agents-orchestration/UsagePage.tsx index 7007b208afa..7cff1cac31e 100644 --- a/src/renderer/src/components/feature-wall/agents-orchestration/UsagePage.tsx +++ b/src/renderer/src/components/feature-wall/agents-orchestration/UsagePage.tsx @@ -1,6 +1,6 @@ import { useEffect, useState } from 'react' import type { JSX } from 'react' -import { ClaudeIcon, OpenAIIcon } from '../../status-bar/icons' +import { ClaudeIcon, OpenAIIcon } from '../../status-bar/accounts/provider-icons' import { cn } from '@/lib/class-names' import { useTranslate } from '@/i18n/use-translate' diff --git a/src/renderer/src/components/feature-wall/browser-storyboard/BrowserAgentVerificationPane.tsx b/src/renderer/src/components/feature-wall/browser-storyboard/BrowserAgentVerificationPane.tsx index ed786100487..1b09cc2eed9 100644 --- a/src/renderer/src/components/feature-wall/browser-storyboard/BrowserAgentVerificationPane.tsx +++ b/src/renderer/src/components/feature-wall/browser-storyboard/BrowserAgentVerificationPane.tsx @@ -1,5 +1,5 @@ import type { JSX, ReactNode } from 'react' -import { ClaudeIcon } from '@/components/status-bar/icons' +import { ClaudeIcon } from '@/components/status-bar/accounts/provider-icons' import { translate } from '@/i18n/i18n' import { useTranslate, type Translate } from '@/i18n/use-translate' import { cn } from '@/lib/class-names' diff --git a/src/renderer/src/components/feature-wall/browser-storyboard/BrowserStoryboardWindow.tsx b/src/renderer/src/components/feature-wall/browser-storyboard/BrowserStoryboardWindow.tsx index fa47370da49..01517029d4c 100644 --- a/src/renderer/src/components/feature-wall/browser-storyboard/BrowserStoryboardWindow.tsx +++ b/src/renderer/src/components/feature-wall/browser-storyboard/BrowserStoryboardWindow.tsx @@ -1,5 +1,5 @@ import type { JSX, ReactNode } from 'react' -import { ClaudeIcon } from '@/components/status-bar/icons' +import { ClaudeIcon } from '@/components/status-bar/accounts/provider-icons' import { useTranslate } from '@/i18n/use-translate' import { cn } from '@/lib/class-names' import { FeatureWallClickRing } from '../storyboard-interaction/FeatureWallClickRing' diff --git a/src/renderer/src/components/feature-wall/task-storyboard/TasksAnimatedVisual.tsx b/src/renderer/src/components/feature-wall/task-storyboard/TasksAnimatedVisual.tsx index 1a6f03f833b..7293fba8a9d 100644 --- a/src/renderer/src/components/feature-wall/task-storyboard/TasksAnimatedVisual.tsx +++ b/src/renderer/src/components/feature-wall/task-storyboard/TasksAnimatedVisual.tsx @@ -2,7 +2,7 @@ import { useEffect, useLayoutEffect, useRef, useState } from 'react' import type { JSX } from 'react' import { ArrowRight, CircleDot } from 'lucide-react' import { AgentStateDot } from '@/components/AgentStateDot' -import { ClaudeIcon } from '../../status-bar/icons' +import { ClaudeIcon } from '../../status-bar/accounts/provider-icons' import { FeatureWallClickRing } from '../storyboard-interaction/FeatureWallClickRing' import { translate } from '@/i18n/i18n' import { useTranslate } from '@/i18n/use-translate' diff --git a/src/renderer/src/components/feature-wall/workbench-storyboard/WorkbenchTerminalPanes.tsx b/src/renderer/src/components/feature-wall/workbench-storyboard/WorkbenchTerminalPanes.tsx index 6de68e014e7..f99c4dbfe4a 100644 --- a/src/renderer/src/components/feature-wall/workbench-storyboard/WorkbenchTerminalPanes.tsx +++ b/src/renderer/src/components/feature-wall/workbench-storyboard/WorkbenchTerminalPanes.tsx @@ -1,7 +1,7 @@ import type { JSX, ReactNode } from 'react' import { useTranslate } from '@/i18n/use-translate' import { cn } from '@/lib/class-names' -import { ClaudeIcon, OpenAIIcon } from '../../status-bar/icons' +import { ClaudeIcon, OpenAIIcon } from '../../status-bar/accounts/provider-icons' import type { WORKBENCH_RUN_QUEUE, WorkbenchTerminalLine diff --git a/src/renderer/src/components/feature-wall/workspace-storyboard/WorkspacesAnimatedVisual.tsx b/src/renderer/src/components/feature-wall/workspace-storyboard/WorkspacesAnimatedVisual.tsx index f20c7fda96b..685c4992aa3 100644 --- a/src/renderer/src/components/feature-wall/workspace-storyboard/WorkspacesAnimatedVisual.tsx +++ b/src/renderer/src/components/feature-wall/workspace-storyboard/WorkspacesAnimatedVisual.tsx @@ -2,7 +2,7 @@ import { useEffect, useMemo, useState } from 'react' import type { JSX } from 'react' import { AgentStateDot } from '@/components/AgentStateDot' import { installWindowVisibilityInterval } from '@/lib/window-activity/window-visibility-interval' -import { ClaudeIcon, OpenCodeGoIcon } from '../../status-bar/icons' +import { ClaudeIcon, OpenCodeGoIcon } from '../../status-bar/accounts/provider-icons' type AgentKind = 'claude' | 'codex' | 'opencode' diff --git a/src/renderer/src/components/floating-terminal/FloatingTerminalIconContextMenu.tsx b/src/renderer/src/components/floating-terminal/FloatingTerminalIconContextMenu.tsx index 12a6bd7a864..d28315e1bd7 100644 --- a/src/renderer/src/components/floating-terminal/FloatingTerminalIconContextMenu.tsx +++ b/src/renderer/src/components/floating-terminal/FloatingTerminalIconContextMenu.tsx @@ -7,7 +7,7 @@ import { DropdownMenuSeparator, DropdownMenuTrigger } from '@/components/ui/dropdown-menu' -import { useAppStore } from '@/store' +import { useAppStore } from '@/store/index' import type { FloatingTerminalTriggerLocation } from '../../../../shared/ui-chrome-types' import { useTranslate } from '@/i18n/use-translate' import { useUiLanguageRevision } from '@/i18n/use-ui-language-revision' diff --git a/src/renderer/src/components/native-chat/host-access/use-native-chat-host-outage-notice.ts b/src/renderer/src/components/native-chat/host-access/use-native-chat-host-outage-notice.ts index c3781e768b3..bc369a6fe44 100644 --- a/src/renderer/src/components/native-chat/host-access/use-native-chat-host-outage-notice.ts +++ b/src/renderer/src/components/native-chat/host-access/use-native-chat-host-outage-notice.ts @@ -1,5 +1,5 @@ import { useState } from 'react' -import { connectRuntimeHostAndReloadProjects } from '@/components/status-bar/runtime-environment-explicit-connect' +import { connectRuntimeHostAndReloadProjects } from '@/components/status-bar/host-connections/runtime-environment-explicit-connect' import { useMountedRef } from '@/hooks/useMountedRef' import { useTranslate } from '@/i18n/use-translate' import { startWslHostAndReloadProjects } from '@/runtime/hosts/wsl/wsl-host-user-start' diff --git a/src/renderer/src/components/native-chat/surfaces/integration/NativeChatStructuredSession.host-outage.test.tsx b/src/renderer/src/components/native-chat/surfaces/integration/NativeChatStructuredSession.host-outage.test.tsx deleted file mode 100644 index ccd1740e451..00000000000 --- a/src/renderer/src/components/native-chat/surfaces/integration/NativeChatStructuredSession.host-outage.test.tsx +++ /dev/null @@ -1,190 +0,0 @@ -// @vitest-environment happy-dom - -import '@testing-library/jest-dom/vitest' -import { act, cleanup, fireEvent, render, screen } from '@testing-library/react' -import { afterEach, beforeEach, expect, it, vi } from 'vitest' -import type { RuntimeEnvironmentStatus } from '../../../../../../shared/remote-runtime/host-status/runtime-host-status' -import type { AgentJournalRenderItem } from '../../../../../../shared/agent-session/journal/agent-session-journal-types' - -const { mocks, moduleFactories, resetStructuredSessionMocks } = await vi.hoisted(async () => - (await import('./NativeChatStructuredSession.test-harness')).createStructuredSessionMocks() -) -const reconnectHost = vi.hoisted(() => vi.fn<(environmentId: string) => Promise>()) - -vi.mock('../../../../runtime/native-chat/requests/structured-agent-session-call', () => - moduleFactories.structuredAgentSessionCall() -) -vi.mock('../../../../runtime/native-chat/requests/structured-agent-session-subscriptions', () => - moduleFactories.structuredAgentSessionSubscriptions() -) -vi.mock('../../session/structured/use-structured-agent-session', () => - moduleFactories.useStructuredAgentSession() -) -vi.mock('../../appearance/use-native-chat-font-size', () => moduleFactories.useNativeChatFontSize()) -vi.mock('../../links/actions/use-native-chat-file-link-context', () => - moduleFactories.useNativeChatFileLinkContext() -) -vi.mock('../../links/actions/use-native-chat-file-link-click', () => - moduleFactories.useNativeChatFileLinkClick() -) -vi.mock('../../NativeChatMessageList', () => moduleFactories.nativeChatMessageList()) -vi.mock('../../composer/NativeChatComposer', () => moduleFactories.nativeChatComposer()) -vi.mock('../../prompts/NativeChatApprovalCard', () => moduleFactories.nativeChatApprovalCard()) -vi.mock('../../prompts/NativeChatQuestionCard', () => moduleFactories.nativeChatQuestionCard()) -vi.mock('@/components/status-bar/runtime-environment-explicit-connect', () => ({ - connectRuntimeHostAndReloadProjects: reconnectHost -})) - -import { useAppStore } from '@/store' -import { NativeChatStructuredSession } from '../../NativeChatStructuredSession' - -const initialState = useAppStore.getState() -let sequence = 0 - -function hostStatus( - verification: 'verified' | 'unavailable' | 'blocked', - transport: 'ready' | 'disconnected', - retired?: true -): RuntimeEnvironmentStatus { - const status = - verification === 'verified' - ? { - runtimeId: 'runtime-1', - rendererGraphEpoch: 1, - graphStatus: 'ready' as const, - authoritativeWindowId: 1, - desktopWindowStatus: 'available' as const, - liveTabCount: 0, - liveLeafCount: 0 - } - : null - return { - snapshot: { - environmentId: 'remote-host', - pairingRevision: 1, - sequence: ++sequence, - checkedAt: 1, - status, - verification, - transport, - ...(retired ? { retired } : {}) - }, - status, - checkedAt: 1 - } -} - -function setHost(status: RuntimeEnvironmentStatus): void { - act(() => { - useAppStore.setState({ runtimeStatusByEnvironmentId: new Map([['remote-host', status]]) }) - }) -} - -function paneElement(): React.JSX.Element { - return ( - - ) -} - -function renderPane() { - return render(paneElement()) -} - -function promptItem(kind: 'approval' | 'question'): AgentJournalRenderItem { - const options = [{ id: 'allow', label: 'Approve' }] - const resolution = { - state: 'pending' as const, - selectedOptionId: null, - resolvedBy: null, - resolvedAt: null - } - return { - itemId: 'host-outage-prompt', - revision: 1, - sequence: 1, - observedAt: 1, - body: - kind === 'approval' - ? { - kind, - title: 'Run the plan?', - detail: null, - subject: { kind: 'plan', text: 'x' }, - options, - resolution - } - : { kind, question: 'Run the plan?', options, resolution } - } -} - -beforeEach(() => { - vi.useFakeTimers({ toFake: ['setTimeout', 'clearTimeout'] }) - useAppStore.setState({ - runtimeEnvironments: [ - { - id: 'remote-host', - name: 'Build box', - createdAt: 1, - updatedAt: 1, - lastUsedAt: null, - runtimeId: null, - endpoints: [{ id: 'ws', kind: 'websocket', label: 'ws', endpoint: 'ws://host' }], - preferredEndpointId: 'ws' - } - ], - runtimeStatusByEnvironmentId: new Map([['remote-host', hostStatus('verified', 'ready')]]) - }) -}) - -afterEach(() => { - cleanup() - vi.useRealTimers() - resetStructuredSessionMocks() - reconnectHost.mockReset() - useAppStore.setState({ - runtimeEnvironments: initialState.runtimeEnvironments, - runtimeStatusByEnvironmentId: initialState.runtimeStatusByEnvironmentId - }) -}) - -it.each(['approval', 'question'] as const)( - 'keeps the host row and pending Reconnect when a %s takes the composer slot', - async (kind) => { - let finish: () => void = () => {} - reconnectHost.mockImplementation( - () => - new Promise((resolve) => { - finish = () => resolve(false) - }) - ) - const pane = renderPane() - setHost(hostStatus('blocked', 'disconnected', true)) - fireEvent.click(screen.getByRole('button', { name: 'Reconnect' })) - mocks.promptItems = [promptItem(kind)] - pane.rerender(paneElement()) - - expect(screen.queryByTestId('structured-composer')).toBeNull() - expect(document.querySelector(`[data-native-chat-${kind}-card-mock]`)).toBeTruthy() - expect(screen.getAllByText('Build box is offline')).toHaveLength(1) - expect(screen.getByRole('listitem')).toHaveAttribute('data-notice-kind', 'host') - expect(screen.getByRole('button', { name: 'Reconnect' })).toBeDisabled() - expect(screen.queryByRole('button', { name: 'Dismiss' })).toBeNull() - const region = screen.getByRole('list') - - await act(async () => { - finish() - }) - expect(screen.getByRole('button', { name: 'Reconnect' })).toBeEnabled() - setHost(hostStatus('verified', 'ready')) - expect(screen.queryByText('Build box is offline')).toBeNull() - expect(screen.getByRole('list')).toBe(region) - expect(region).toHaveAttribute('aria-live', 'polite') - } -) diff --git a/src/renderer/src/components/native-chat/usage/NativeChatAccountUsageCard.tsx b/src/renderer/src/components/native-chat/usage/NativeChatAccountUsageCard.tsx index 3f097bedf7f..c0d82523ae7 100644 --- a/src/renderer/src/components/native-chat/usage/NativeChatAccountUsageCard.tsx +++ b/src/renderer/src/components/native-chat/usage/NativeChatAccountUsageCard.tsx @@ -5,7 +5,7 @@ import { Button } from '@/components/ui/button' import { Card } from '@/components/ui/card' import { translate } from '@/i18n/i18n' import { useTranslate, type Translate } from '@/i18n/use-translate' -import { useAppStore } from '@/store' +import { useAppStore } from '@/store/index' import { callRuntimeRpc } from '@/runtime/rpc/calls/runtime-rpc-call' import type { AgentSessionAccountUsage, @@ -15,9 +15,12 @@ import type { CodexRateLimitResetOutcome } from '../../../../../shared/rate-limi import type { RuntimeClientTarget } from '../../../../../shared/runtime-client-target' import { normalizeUsagePercentageDisplay } from '../../../../../shared/usage-percentage-display' import { getProviderDisplayName } from '../../../../../shared/usage-provider-windows' -import { ProviderIdentityCard } from '../../status-bar/ProviderIdentityCard' -import { CodexResetConfirmation, CodexResetCredits } from '../../status-bar/CodexResetCredits' -import { formatResetCreditExpiry, ProviderIcon } from '../../status-bar/tooltip' +import { ProviderIdentityCard } from '../../status-bar/accounts/ProviderIdentityCard' +import { + CodexResetConfirmation, + CodexResetCredits +} from '../../status-bar/accounts/CodexResetCredits' +import { formatResetCreditExpiry, ProviderIcon } from '../../status-bar/usage/provider-usage-panel' type UsageResult = Extract diff --git a/src/renderer/src/components/native-chat/usage/NativeChatUsageLimitActions.tsx b/src/renderer/src/components/native-chat/usage/NativeChatUsageLimitActions.tsx index f7e24f25f3f..753665dffd0 100644 --- a/src/renderer/src/components/native-chat/usage/NativeChatUsageLimitActions.tsx +++ b/src/renderer/src/components/native-chat/usage/NativeChatUsageLimitActions.tsx @@ -17,8 +17,8 @@ import { useStructuredChatTabConversationName } from '@/runtime/native-chat/nami import { AgentSessionContinuationDialog } from '@/components/agent-session-continuation/AgentSessionContinuationDialog' import { buildAgentSessionContinuationPrompt } from '@/lib/agent-session/context/agent-session-continuation' import type { AgentSessionContinuationRequest } from '@/lib/agent-session/context/agent-session-continuation' -import { ClaudeSwitcherMenu } from '@/components/status-bar/ClaudeSwitcherMenu' -import { ProviderAccountChatButton } from '@/components/status-bar/ProviderAccountChatButton' +import { ClaudeSwitcherMenu } from '@/components/status-bar/accounts/ClaudeSwitcherMenu' +import { ProviderAccountChatButton } from '@/components/status-bar/accounts/ProviderAccountChatButton' import { isTuiAgent } from '../../../../../shared/agent-launch/catalog/tui-agent-config' import { callStructuredAgentSession } from '@/runtime/native-chat/requests/structured-agent-session-call' import { executionHostIdForStructuredTarget } from '@/runtime/native-chat/session-ownership/structured-agent-session-owner' diff --git a/src/renderer/src/components/settings/accounts/claude/accounts-pane-claude-section.tsx b/src/renderer/src/components/settings/accounts/claude/accounts-pane-claude-section.tsx index 9ad23092a2b..8a1a2903978 100644 --- a/src/renderer/src/components/settings/accounts/claude/accounts-pane-claude-section.tsx +++ b/src/renderer/src/components/settings/accounts/claude/accounts-pane-claude-section.tsx @@ -6,7 +6,7 @@ import { Badge } from '../../../ui/badge' import { Button } from '../../../ui/button' import { ButtonGroup } from '../../../ui/button-group' import { Label } from '../../../ui/label' -import { ClaudeIcon } from '../../../status-bar/icons' +import { ClaudeIcon } from '../../../status-bar/accounts/provider-icons' import { SearchableSetting } from '../../section-layout/SearchableSetting' import { ClaudeOAuthUsageSetting } from './claude-oauth-usage-setting' import { ClaudeRunningSessionSwitchSetting } from './claude-running-session-switch-setting' diff --git a/src/renderer/src/components/settings/accounts/codex/accounts-pane-codex-section.tsx b/src/renderer/src/components/settings/accounts/codex/accounts-pane-codex-section.tsx index 9d225a2e59d..76200aec55d 100644 --- a/src/renderer/src/components/settings/accounts/codex/accounts-pane-codex-section.tsx +++ b/src/renderer/src/components/settings/accounts/codex/accounts-pane-codex-section.tsx @@ -5,7 +5,7 @@ import { selectCodexProviderAccount } from '@/runtime/provider-accounts/observat import { Badge } from '../../../ui/badge' import { Button } from '../../../ui/button' import { Label } from '../../../ui/label' -import { OpenAIIcon } from '../../../status-bar/icons' +import { OpenAIIcon } from '../../../status-bar/accounts/provider-icons' import { CodexLoginLinkNotice } from './CodexLoginLinkNotice' import { SearchableSetting } from '../../section-layout/SearchableSetting' import { ACCOUNTS_SECTION_IDS, getAccountsCodexSearchEntries } from '../accounts-search' diff --git a/src/renderer/src/components/settings/accounts/providers/AntigravityTerminalAccountRows.tsx b/src/renderer/src/components/settings/accounts/providers/AntigravityTerminalAccountRows.tsx index 0881e71841c..c3d3eb8d867 100644 --- a/src/renderer/src/components/settings/accounts/providers/AntigravityTerminalAccountRows.tsx +++ b/src/renderer/src/components/settings/accounts/providers/AntigravityTerminalAccountRows.tsx @@ -5,7 +5,7 @@ import { useTranslate, type Translate } from '@/i18n/use-translate' import type { AntigravityAccountState } from '../../../../../../shared/antigravity-account-types' import type { ProviderRateLimits } from '../../../../../../shared/rate-limit-types' import { openAppHttpLinkFromAnchor } from '@/lib/browser/navigation/app-http-link-open' -import { formatTimeAgo } from '../../../status-bar/tooltip' +import { formatTimeAgo } from '../../../status-bar/usage/provider-usage-panel' import { Badge } from '../../../ui/badge' import { Button } from '../../../ui/button' import { Tooltip, TooltipContent, TooltipTrigger } from '../../../ui/tooltip' diff --git a/src/renderer/src/components/settings/accounts/providers/accounts-pane-gemini-section.tsx b/src/renderer/src/components/settings/accounts/providers/accounts-pane-gemini-section.tsx index 7f3125d44ee..7d3b3c3c70d 100644 --- a/src/renderer/src/components/settings/accounts/providers/accounts-pane-gemini-section.tsx +++ b/src/renderer/src/components/settings/accounts/providers/accounts-pane-gemini-section.tsx @@ -2,7 +2,7 @@ import { translate } from '../../../../i18n/i18n' import type { Translate } from '../../../../i18n/use-translate' import { Label } from '../../../ui/label' import { Switch } from '../../../ui/switch' -import { GeminiIcon } from '../../../status-bar/icons' +import { GeminiIcon } from '../../../status-bar/accounts/provider-icons' import { SearchableSetting } from '../../section-layout/SearchableSetting' import { SettingsGroup } from '../../section-layout/SettingsGroup' import type { AccountsPaneSectionModel } from '../accounts-pane-types' diff --git a/src/renderer/src/components/settings/accounts/providers/accounts-pane-opencode-section.tsx b/src/renderer/src/components/settings/accounts/providers/accounts-pane-opencode-section.tsx index 251606f4ca9..0ec66bb6cff 100644 --- a/src/renderer/src/components/settings/accounts/providers/accounts-pane-opencode-section.tsx +++ b/src/renderer/src/components/settings/accounts/providers/accounts-pane-opencode-section.tsx @@ -2,7 +2,7 @@ import { translate } from '../../../../i18n/i18n' import type { Translate } from '../../../../i18n/use-translate' import { Button } from '../../../ui/button' import { Label } from '../../../ui/label' -import { OpenCodeGoIcon } from '../../../status-bar/icons' +import { OpenCodeGoIcon } from '../../../status-bar/accounts/provider-icons' import { SearchableSetting } from '../../section-layout/SearchableSetting' import { SettingsGroup } from '../../section-layout/SettingsGroup' import { DebouncedSettingsTextInput } from '../../form-controls/DebouncedSettingsTextInput' diff --git a/src/renderer/src/components/settings/accounts/usage/MiniMaxAccountsSection.tsx b/src/renderer/src/components/settings/accounts/usage/MiniMaxAccountsSection.tsx index 561c70fad8a..dfeb9391c8a 100644 --- a/src/renderer/src/components/settings/accounts/usage/MiniMaxAccountsSection.tsx +++ b/src/renderer/src/components/settings/accounts/usage/MiniMaxAccountsSection.tsx @@ -4,7 +4,7 @@ import { cn } from '@/lib/class-names' import type { FeatureInteractionId } from '../../../../../../shared/feature-interaction-catalog' import type { ProviderRateLimits } from '../../../../../../shared/rate-limit-types' import { Label } from '../../../ui/label' -import { MiniMaxIcon } from '../../../status-bar/icons' +import { MiniMaxIcon } from '../../../status-bar/accounts/provider-icons' import { SearchableSetting } from '../../section-layout/SearchableSetting' import { DebouncedSettingsTextInput } from '../../form-controls/DebouncedSettingsTextInput' import { MiniMaxCredentials, miniMaxStorageHelp } from './accounts-pane-minimax-credentials' diff --git a/src/renderer/src/components/settings/appearance/AppearanceWindowSidebarSection.tsx b/src/renderer/src/components/settings/appearance/AppearanceWindowSidebarSection.tsx index 1446f84b5aa..21357ce48ef 100644 --- a/src/renderer/src/components/settings/appearance/AppearanceWindowSidebarSection.tsx +++ b/src/renderer/src/components/settings/appearance/AppearanceWindowSidebarSection.tsx @@ -12,7 +12,7 @@ import { SettingsSegmentedControl, SettingsSwitchRow } from '../form-controls/SettingsFormControls' -import { useAvailableStatusBarToggles } from '../../status-bar/use-available-status-bar-toggles' +import { useAvailableStatusBarToggles } from '../../status-bar/composition/use-available-status-bar-toggles' import { getLayoutEntries, getFollowSymlinkedDirectoriesEntry } from './appearance-search' import { getSidebarEntries, diff --git a/src/renderer/src/components/settings/appearance/StatusBarUsageFormatSetting.tsx b/src/renderer/src/components/settings/appearance/StatusBarUsageFormatSetting.tsx index 90e535a6e69..3ead6bde77a 100644 --- a/src/renderer/src/components/settings/appearance/StatusBarUsageFormatSetting.tsx +++ b/src/renderer/src/components/settings/appearance/StatusBarUsageFormatSetting.tsx @@ -4,13 +4,13 @@ import type { ProviderRateLimits } from '../../../../../shared/rate-limit-types' import type { StatusBarUsageFormat } from '../../../../../shared/status-bar-usage-format' import { normalizeUsagePercentageDisplay } from '../../../../../shared/usage-percentage-display' import { useIntlLocale, useTranslate } from '@/i18n/use-translate' -import { useAppStore } from '../../../store' +import { useAppStore } from '../../../store/index' import { Button } from '../../ui/button' import { Input } from '../../ui/input' import { buildUsageFormatValues, renderUsageFormatTemplate -} from '../../status-bar/usage-format-template' +} from '../../status-bar/usage/usage-format-template' import { getStatusBarUsageFormatEntry } from './appearance-status-bar-usage-format-search' import { SettingsRow } from '../form-controls/SettingsFormControls' diff --git a/src/renderer/src/components/settings/terminal/session-management/ManageSessionsSection.tsx b/src/renderer/src/components/settings/terminal/session-management/ManageSessionsSection.tsx index 73e5e8d6639..d1d38fedbd1 100644 --- a/src/renderer/src/components/settings/terminal/session-management/ManageSessionsSection.tsx +++ b/src/renderer/src/components/settings/terminal/session-management/ManageSessionsSection.tsx @@ -13,7 +13,7 @@ import { ManageSessionsTable } from './ManageSessionsTable' import { notifyDaemonSessionInventoryInvalidated, subscribeDaemonSessionInventoryInvalidated -} from '../../../status-bar/daemon-session-inventory-invalidation' +} from '../../../status-bar/resources/inventory/daemon-session-inventory-invalidation' import { MANAGE_SESSIONS_SECTION_ID } from './open-terminal-manage-sessions' import { TerminalTccAttributionNotice } from '../../developer-permissions/TerminalTccAttributionNotice' import { translate } from '@/i18n/i18n' diff --git a/src/renderer/src/components/shared/kill-all-terminal-surfaces.ts b/src/renderer/src/components/shared/kill-all-terminal-surfaces.ts index 911946e6401..0e8e41f00cf 100644 --- a/src/renderer/src/components/shared/kill-all-terminal-surfaces.ts +++ b/src/renderer/src/components/shared/kill-all-terminal-surfaces.ts @@ -1,4 +1,4 @@ -import { useAppStore } from '@/store' +import { useAppStore } from '@/store/index' import type { AppState } from '@/store/types' import { closeTerminalTab, @@ -10,7 +10,7 @@ import { type TerminalTabRetirementState } from '@/store/terminals/retirement/terminal-tab-retirement' import { reserveTerminalRetirementTeardowns } from '@/store/terminals/retirement/terminal-retirement-teardown-reservation' -import { notifyDaemonSessionInventoryInvalidated } from '../status-bar/daemon-session-inventory-invalidation' +import { notifyDaemonSessionInventoryInvalidated } from '../status-bar/resources/inventory/daemon-session-inventory-invalidation' const CLOSE_BATCH_SIZE = 2 diff --git a/src/renderer/src/components/stats/GrokUsagePane.tsx b/src/renderer/src/components/stats/GrokUsagePane.tsx index 3b67160d5e2..5180eced8fa 100644 --- a/src/renderer/src/components/stats/GrokUsagePane.tsx +++ b/src/renderer/src/components/stats/GrokUsagePane.tsx @@ -1,7 +1,7 @@ import { useState } from 'react' import { CalendarClock, ExternalLink, RefreshCw, Sparkles } from 'lucide-react' import { useIntlLocale, useTranslate } from '@/i18n/use-translate' -import { useAppStore } from '../../store' +import { useAppStore } from '../../store/index' import { Button } from '../ui/button' import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '../ui/tooltip' import { StatCard } from './StatCard' diff --git a/src/renderer/src/components/status-bar/CaffeinateStatusSegment.tsx b/src/renderer/src/components/status-bar/CaffeinateStatusSegment.tsx index ce8071e9726..fa871e15a64 100644 --- a/src/renderer/src/components/status-bar/CaffeinateStatusSegment.tsx +++ b/src/renderer/src/components/status-bar/CaffeinateStatusSegment.tsx @@ -24,7 +24,7 @@ import { normalizeComputerAwakeMode, type ComputerAwakeStatus } from '../../../../shared/computer-awake-mode' -import { STATUS_BAR_CONTEXT_MENU_EXEMPT_PROPS } from './status-bar-context-menu-policy' +import { STATUS_BAR_CONTEXT_MENU_EXEMPT_PROPS } from './composition/status-bar-context-menu-policy' const INACTIVE_STATUS: ComputerAwakeStatus = { mode: 'off', diff --git a/src/renderer/src/components/status-bar/PetStatusSegment.tsx b/src/renderer/src/components/status-bar/PetStatusSegment.tsx index 5edcb4f0cd8..81ecbf69798 100644 --- a/src/renderer/src/components/status-bar/PetStatusSegment.tsx +++ b/src/renderer/src/components/status-bar/PetStatusSegment.tsx @@ -13,7 +13,7 @@ import { DropdownMenuSubTrigger, DropdownMenuTrigger } from '@/components/ui/dropdown-menu' -import { useAppStore } from '../../store' +import { useAppStore } from '../../store/index' import { BUNDLED_PET, BUNDLED_PETS, findBundledPet, isBundledPetId } from '../pet/pet-models' import { PET_SIZE_MAX, PET_SIZE_MIN } from '../../../../shared/pet-types' import { useTranslate } from '@/i18n/use-translate' diff --git a/src/renderer/src/components/status-bar/StatusBar.tsx b/src/renderer/src/components/status-bar/StatusBar.tsx index 0dd665c939c..96054756e62 100644 --- a/src/renderer/src/components/status-bar/StatusBar.tsx +++ b/src/renderer/src/components/status-bar/StatusBar.tsx @@ -1,30 +1,4 @@ import React from 'react' import { StatusBarSurface } from './StatusBarSurface' -export { - buildCodexStatusSwitchGroups, - getCodexStatusActiveId, - normalizeCodexStatusRuntimeTarget, - resolveCodexStatusAccountState -} from './status-bar-codex-accounts' -export { - buildClaudeStatusSwitchGroups, - getClaudeStatusActiveId, - normalizeClaudeStatusRuntimeTarget, - resolveClaudeStatusAccountState -} from './status-bar-claude-accounts' -export { - getStatusBarPreferredWslDistro, - type ClaudeStatusSwitchGroup, - type ClaudeStatusSwitchTarget, - type CodexStatusRuntimeTarget, - type CodexStatusSwitchGroup, - type CodexStatusSwitchTarget -} from './status-bar-runtime-targets' -export { ClaudeSwitcherMenu } from './ClaudeSwitcherMenu' -export { CodexSwitcherMenu } from './CodexSwitcherMenu' -export { InlineUsageBars } from './InlineProviderUsage' -export { ProviderDetailsMenu } from './ProviderDetailsMenu' -export { ProviderSegment } from './StatusBarProviderSegment' - export const StatusBar = React.memo(StatusBarSurface) diff --git a/src/renderer/src/components/status-bar/StatusBarSurface.tsx b/src/renderer/src/components/status-bar/StatusBarSurface.tsx index 785b795ff0d..bcfff96bcd2 100644 --- a/src/renderer/src/components/status-bar/StatusBarSurface.tsx +++ b/src/renderer/src/components/status-bar/StatusBarSurface.tsx @@ -9,51 +9,55 @@ import { DropdownMenuTrigger } from '@/components/ui/dropdown-menu' import { useTranslate } from '@/i18n/use-translate' -import { UsageRosterPanel } from './UsageRosterPanel' +import { UsageRosterPanel } from './usage/UsageRosterPanel' import { STATUS_BAR_CONTEXT_MENU_EXEMPT_PROPS, shouldOpenStatusBarContextMenu -} from './status-bar-context-menu-policy' -import { StatusBarUsageEmptyCta } from './StatusBarUsageEmptyCta' -import { StatusBarUsageChangeNotices } from './StatusBarUsageChangeNotices' -import { UpdateStatusSegment } from './UpdateStatusSegment' -import { SkillUpdateStatusSegment } from './SkillUpdateStatusSegment' +} from './composition/status-bar-context-menu-policy' +import { StatusBarUsageEmptyCta } from './usage/StatusBarUsageEmptyCta' +import { StatusBarUsageChangeNotices } from './usage/StatusBarUsageChangeNotices' +import { UpdateStatusSegment } from './updates/UpdateStatusSegment' +import { SkillUpdateStatusSegment } from './updates/SkillUpdateStatusSegment' import { NativeChatResumeStatusSegment } from './NativeChatResumeStatusSegment' import { CaffeinateStatusSegment } from './CaffeinateStatusSegment' -import { PluginsStatusSegment } from './PluginsStatusSegment' -import { PluginStatusBarItems } from './PluginStatusBarItems' -import { RemoteServerUpdateStatusSegment } from './RemoteServerUpdateStatusSegment' +import { PluginsStatusSegment } from './plugins/PluginsStatusSegment' +import { PluginStatusBarItems } from './plugins/PluginStatusBarItems' +import { RemoteServerUpdateStatusSegment } from './updates/RemoteServerUpdateStatusSegment' import { TOGGLE_FLOATING_TERMINAL_EVENT } from '@/components/floating-terminal/floating-terminal' import { FloatingTerminalIconContextMenu } from '@/components/floating-terminal/FloatingTerminalIconContextMenu' -import { ClaudeSwitcherMenu } from './ClaudeSwitcherMenu' -import { CodexSwitcherMenu } from './CodexSwitcherMenu' -import { ProviderDetailsMenu } from './ProviderDetailsMenu' -import { AntigravityUsageMenu } from './AntigravityUsageMenu' +import { ClaudeSwitcherMenu } from './accounts/ClaudeSwitcherMenu' +import { CodexSwitcherMenu } from './accounts/CodexSwitcherMenu' +import { ProviderDetailsMenu } from './usage/ProviderDetailsMenu' +import { AntigravityUsageMenu } from './usage/AntigravityUsageMenu' import { CLOSE_ALL_CONTEXT_MENUS_EVENT } from '@/lib/overlay-interaction/close-all-context-menus' -import { ProviderSegment, UsageOverflowChip, getUsageTone } from './StatusBarProviderSegment' +import { ProviderSegment, UsageOverflowChip, getUsageTone } from './usage/StatusBarProviderSegment' import { UsageUnitLabel, getUsageUnitLabelState, usageChipShowsPercentage -} from './usage-unit-label' -import { useStatusBarController } from './use-status-bar-controller' -import { isOwnerNotSetUpPlaceholder } from './owner-usage-rate-limits' -import { StatusBarVisibilityMenu } from './StatusBarVisibilityMenu' +} from './usage/usage-unit-label' +import { useStatusBarController } from './composition/use-status-bar-controller' +import { isOwnerNotSetUpPlaceholder } from './usage/owner-usage-rate-limits' +import { StatusBarVisibilityMenu } from './composition/StatusBarVisibilityMenu' import { isPairedWebClientWindow } from '@/app-shell/chrome/desktop-window-chrome' const PetStatusSegment = lazyWithRetry(() => import('./PetStatusSegment').then((module) => ({ default: module.PetStatusSegment })) ) const ResourceUsageStatusSegment = lazyWithRetry(() => - import('./ResourceUsageStatusSegment').then((module) => ({ + import('./resources/ResourceUsageStatusSegment').then((module) => ({ default: module.ResourceUsageStatusSegment })) ) const PortsStatusSegment = lazyWithRetry(() => - import('./PortsStatusSegment').then((module) => ({ default: module.PortsStatusSegment })) + import('./host-connections/PortsStatusSegment').then((module) => ({ + default: module.PortsStatusSegment + })) ) const SshStatusSegment = lazyWithRetry(() => - import('./SshStatusSegment').then((module) => ({ default: module.SshStatusSegment })) + import('./host-connections/SshStatusSegment').then((module) => ({ + default: module.SshStatusSegment + })) ) export type StatusBarProps = { diff --git a/src/renderer/src/components/status-bar/StatusBarUsageChangeNotices.test.tsx b/src/renderer/src/components/status-bar/StatusBarUsageChangeNotices.test.tsx deleted file mode 100644 index e2fde79ad73..00000000000 --- a/src/renderer/src/components/status-bar/StatusBarUsageChangeNotices.test.tsx +++ /dev/null @@ -1,126 +0,0 @@ -// @vitest-environment happy-dom - -import { act, type ReactNode } from 'react' -import { createRoot, type Root } from 'react-dom/client' -import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' -import { - DropdownMenu, - DropdownMenuContent, - DropdownMenuTrigger -} from '@/components/ui/dropdown-menu' -import { StatusBarUsageChangeNotices } from './StatusBarUsageChangeNotices' - -const state = { - persistedUIReady: true, - statusBarCompactChangeNoticeDismissed: false, - dismissStatusBarCompactChangeNotice: vi.fn(), - statusBarUsageMode: 'compact', - statusBarVisible: true, - activeModal: 'none', - usagePercentageDisplayChangeNoticeDismissed: true, - dismissUsagePercentageDisplayChangeNotice: vi.fn() -} - -vi.mock('@/store', () => ({ - useAppStore: (selector: (store: typeof state) => unknown) => selector(state) -})) - -describe('status bar usage change notices', () => { - let container: HTMLDivElement - let root: Root - - beforeEach(() => { - vi.useFakeTimers() - vi.stubGlobal('IS_REACT_ACT_ENVIRONMENT', true) - vi.stubGlobal( - 'ResizeObserver', - class { - observe(): void {} - unobserve(): void {} - disconnect(): void {} - } - ) - vi.spyOn(HTMLElement.prototype, 'getBoundingClientRect').mockReturnValue({ - x: 24, - y: 700, - top: 700, - left: 24, - bottom: 724, - right: 200, - width: 176, - height: 24, - toJSON: () => ({}) - }) - Object.assign(state, { - persistedUIReady: true, - statusBarCompactChangeNoticeDismissed: false, - statusBarUsageMode: 'compact', - statusBarVisible: true, - activeModal: 'none', - usagePercentageDisplayChangeNoticeDismissed: true - }) - state.dismissStatusBarCompactChangeNotice.mockReset() - container = document.createElement('div') - document.body.appendChild(container) - root = createRoot(container) - }) - - afterEach(() => { - act(() => root.unmount()) - container.remove() - vi.useRealTimers() - vi.restoreAllMocks() - vi.unstubAllGlobals() - }) - - function render( - hasVisibleUsageMeters = true, - children: ReactNode = - ): void { - act(() => { - root.render( - - {children} - - ) - }) - } - - function settle(): void { - act(() => vi.advanceTimersByTime(1_800)) - } - - it.each(['verbose', 'compact'])('preserves the open menu and focus when choosing %s', (mode) => { - const menu = ( - - - - - - - - - ) - render(true, menu) - settle() - const trigger = container.querySelector('button') - const content = document.querySelector('[role="menu"]') - const selector = content?.querySelector('button') - expect(selector).toBeTruthy() - selector?.focus() - act(() => selector?.click()) - render(true, menu) - - expect(document.querySelector('[role="status"]')).toBeNull() - expect(container.querySelector('button')).toBe(trigger) - expect(document.querySelector('[role="menu"]')).toBe(content) - expect(document.activeElement).toBe(selector) - }) -}) diff --git a/src/renderer/src/components/status-bar/account-switch-row-keyboard.test.tsx b/src/renderer/src/components/status-bar/account-switch-row-keyboard.test.tsx deleted file mode 100644 index b51ce414459..00000000000 --- a/src/renderer/src/components/status-bar/account-switch-row-keyboard.test.tsx +++ /dev/null @@ -1,60 +0,0 @@ -// @vitest-environment happy-dom -import { cleanup, fireEvent, render, screen, waitFor } from '@testing-library/react' -import { afterEach, expect, it, vi } from 'vitest' -import { - DropdownMenu, - DropdownMenuContent, - DropdownMenuTrigger -} from '@/components/ui/dropdown-menu' -import { AccountSwitchList } from './AccountSwitchList' -import { AccountSwitchRowItem } from './AccountSwitchRowItem' -import { InlineUsageSignInAction } from './InlineProviderUsage' - -afterEach(cleanup) - -it('keeps switching and signing in independent through keyboard and pointer selection', async () => { - const switchAccount = vi.fn() - const signIn = vi.fn() - render( - - Accounts - - - { - event.preventDefault() - switchAccount() - }} - action={ - - } - /> - - - - ) - const account = await screen.findByRole('menuitem', { name: 'account@example.com' }) - account.focus() - fireEvent.keyDown(account, { key: 'Enter' }) - expect(switchAccount).toHaveBeenCalledTimes(1) - expect(signIn).not.toHaveBeenCalled() - - fireEvent.keyDown(account, { key: 'ArrowDown' }) - const signInAction = screen.getByRole('menuitem', { name: 'Sign in: account@example.com' }) - await waitFor(() => expect(document.activeElement).toBe(signInAction)) - fireEvent.keyDown(signInAction, { key: 'Enter' }) - expect(signIn).toHaveBeenCalledTimes(1) - expect(switchAccount).toHaveBeenCalledTimes(1) - - fireEvent.click(signInAction) - expect(signIn).toHaveBeenCalledTimes(2) - expect(switchAccount).toHaveBeenCalledTimes(1) - expect(screen.getByRole('menu')).toBeTruthy() -}) diff --git a/src/renderer/src/components/status-bar/AccountSwitchList.tsx b/src/renderer/src/components/status-bar/accounts/AccountSwitchList.tsx similarity index 95% rename from src/renderer/src/components/status-bar/AccountSwitchList.tsx rename to src/renderer/src/components/status-bar/accounts/AccountSwitchList.tsx index 4b37da91f32..86076773503 100644 --- a/src/renderer/src/components/status-bar/AccountSwitchList.tsx +++ b/src/renderer/src/components/status-bar/accounts/AccountSwitchList.tsx @@ -6,8 +6,8 @@ import { DropdownMenuSeparator } from '@/components/ui/dropdown-menu' import { useTranslate } from '@/i18n/use-translate' -import { useAppStore } from '../../store' -import { normalizeUsagePercentageDisplay } from '../../../../shared/usage-percentage-display' +import { useAppStore } from '../../../store/index' +import { normalizeUsagePercentageDisplay } from '../../../../../shared/usage-percentage-display' export function AccountSwitchList({ heading, diff --git a/src/renderer/src/components/status-bar/AccountSwitchRowItem.fixture.tsx b/src/renderer/src/components/status-bar/accounts/AccountSwitchRowItem.fixture.tsx similarity index 91% rename from src/renderer/src/components/status-bar/AccountSwitchRowItem.fixture.tsx rename to src/renderer/src/components/status-bar/accounts/AccountSwitchRowItem.fixture.tsx index ec2054129df..ff60f15e5ab 100644 --- a/src/renderer/src/components/status-bar/AccountSwitchRowItem.fixture.tsx +++ b/src/renderer/src/components/status-bar/accounts/AccountSwitchRowItem.fixture.tsx @@ -1,6 +1,6 @@ -import { defineFixture } from '../../component-fixtures/component-fixture' +import { defineFixture } from '../../../component-fixtures/component-fixture' import { setRendererUiLanguage } from '@/i18n/i18n' -import type { ProviderRateLimits } from '../../../../shared/rate-limit-types' +import type { ProviderRateLimits } from '../../../../../shared/rate-limit-types' import { DropdownMenu, DropdownMenuContent, @@ -8,7 +8,7 @@ import { } from '@/components/ui/dropdown-menu' import { AccountSwitchList } from './AccountSwitchList' import { AccountSwitchRowItem } from './AccountSwitchRowItem' -import { InlineUsageBars } from './InlineProviderUsage' +import { InlineUsageBars } from '../usage/InlineProviderUsage' function accountRows(provider: 'codex' | 'claude', width = 520, language: 'en' | 'ru' = 'en') { const limits: ProviderRateLimits = { diff --git a/src/renderer/src/components/status-bar/AccountSwitchRowItem.tsx b/src/renderer/src/components/status-bar/accounts/AccountSwitchRowItem.tsx similarity index 100% rename from src/renderer/src/components/status-bar/AccountSwitchRowItem.tsx rename to src/renderer/src/components/status-bar/accounts/AccountSwitchRowItem.tsx diff --git a/src/renderer/src/components/status-bar/ClaudeSwitcherForOwner.tsx b/src/renderer/src/components/status-bar/accounts/ClaudeSwitcherForOwner.tsx similarity index 97% rename from src/renderer/src/components/status-bar/ClaudeSwitcherForOwner.tsx rename to src/renderer/src/components/status-bar/accounts/ClaudeSwitcherForOwner.tsx index 12ce13b66e5..e43d475ca91 100644 --- a/src/renderer/src/components/status-bar/ClaudeSwitcherForOwner.tsx +++ b/src/renderer/src/components/status-bar/accounts/ClaudeSwitcherForOwner.tsx @@ -3,7 +3,7 @@ import type { ClaudeSwitcherMenuProps } from './ClaudeSwitcherMenu' import { useProviderAccountList } from './use-provider-account-list' import { providerChatAccountControl } from './ProviderAccountChatButton' import React, { useCallback, useRef, useState } from 'react' -import { useAppStore } from '../../store' +import { useAppStore } from '../../../store/index' import type { AccountOwner } from '@/runtime/provider-accounts/ownership/wsl-host-account-owner' import { runtimeTargetEnvironmentId } from '@/runtime/rpc/targets/runtime-client-target' import { @@ -11,7 +11,7 @@ import { emptyClaudeAccountsState } from '@/runtime/provider-accounts/observations/runtime-provider-accounts-client' import { toast } from 'sonner' -import { getClaudeAccountErrorDescription } from '../../lib/provider-accounts/provider-account-action-errors' +import { getClaudeAccountErrorDescription } from '../../../lib/provider-accounts/provider-account-action-errors' import { useTranslate } from '@/i18n/use-translate' import { getWindowsTerminalCapabilityOwnerKey, @@ -33,15 +33,15 @@ import { resolveClaudeStatusAccountState } from './status-bar-claude-accounts' import { handleRunningClaudeSessionsAfterSwitch } from '@/lib/provider-accounts/claude-account-switch-sessions' -import { AccountRuntimeToggle } from './StatusBarAccountControls' +import { AccountRuntimeToggle } from '../composition/StatusBarAccountControls' import { InlineUsageBars, InlineUsageSignInAction, InlineUsageSkeleton -} from './InlineProviderUsage' +} from '../usage/InlineProviderUsage' import { AccountSwitchSection, AccountSwitchSignedOutHeading } from './AccountSwitchList' import { AccountSwitchRowItem } from './AccountSwitchRowItem' -import { ProviderDetailsMenu } from './ProviderDetailsMenu' +import { ProviderDetailsMenu } from '../usage/ProviderDetailsMenu' import { signInToClaudeAccount } from '@/lib/provider-accounts/claude-account-sign-in' // Retain account switch/reset drill-in even though the footer now opens UsageRosterPanel. diff --git a/src/renderer/src/components/status-bar/ClaudeSwitcherMenu.tsx b/src/renderer/src/components/status-bar/accounts/ClaudeSwitcherMenu.tsx similarity index 91% rename from src/renderer/src/components/status-bar/ClaudeSwitcherMenu.tsx rename to src/renderer/src/components/status-bar/accounts/ClaudeSwitcherMenu.tsx index cad014d605c..2f01d0b09de 100644 --- a/src/renderer/src/components/status-bar/ClaudeSwitcherMenu.tsx +++ b/src/renderer/src/components/status-bar/accounts/ClaudeSwitcherMenu.tsx @@ -1,7 +1,7 @@ import type React from 'react' -import type { ProviderRateLimits } from '../../../../shared/rate-limit-types' +import type { ProviderRateLimits } from '../../../../../shared/rate-limit-types' import type { ChatAccountAction } from './ProviderAccountChatButton' -import { useAppStore } from '../../store' +import { useAppStore } from '../../../store/index' import { defaultScopeHost } from '@/runtime/hosts/selection/default-creation-host' import { useActiveAccountOwner } from '@/runtime/provider-accounts/ownership/use-active-account-owner' import { ClaudeSwitcherForOwner } from './ClaudeSwitcherForOwner' diff --git a/src/renderer/src/components/status-bar/CodexResetCredits.tsx b/src/renderer/src/components/status-bar/accounts/CodexResetCredits.tsx similarity index 97% rename from src/renderer/src/components/status-bar/CodexResetCredits.tsx rename to src/renderer/src/components/status-bar/accounts/CodexResetCredits.tsx index 37fe6183971..6fff762109e 100644 --- a/src/renderer/src/components/status-bar/CodexResetCredits.tsx +++ b/src/renderer/src/components/status-bar/accounts/CodexResetCredits.tsx @@ -11,7 +11,7 @@ import { DialogTitle } from '@/components/ui/dialog' import { useTranslate } from '@/i18n/use-translate' -import { STATUS_BAR_CONTEXT_MENU_EXEMPT_PROPS } from './status-bar-context-menu-policy' +import { STATUS_BAR_CONTEXT_MENU_EXEMPT_PROPS } from '../composition/status-bar-context-menu-policy' export function CodexResetCredits({ resetCreditCount, diff --git a/src/renderer/src/components/status-bar/CodexSwitcherMenu.fixture.tsx b/src/renderer/src/components/status-bar/accounts/CodexSwitcherMenu.fixture.tsx similarity index 94% rename from src/renderer/src/components/status-bar/CodexSwitcherMenu.fixture.tsx rename to src/renderer/src/components/status-bar/accounts/CodexSwitcherMenu.fixture.tsx index 5e66fb95cbb..be3555ac432 100644 --- a/src/renderer/src/components/status-bar/CodexSwitcherMenu.fixture.tsx +++ b/src/renderer/src/components/status-bar/accounts/CodexSwitcherMenu.fixture.tsx @@ -1,12 +1,12 @@ -import { defineFixture } from '../../component-fixtures/component-fixture' -import { getDefaultSettings } from '../../../../shared/constants' -import type { CodexManagedAccount } from '../../../../shared/managed-account-types' -import { createEmptyRateLimitState } from '../../../../shared/rate-limit-state-factory' +import { defineFixture } from '../../../component-fixtures/component-fixture' +import { getDefaultSettings } from '../../../../../shared/constants' +import type { CodexManagedAccount } from '../../../../../shared/managed-account-types' +import { createEmptyRateLimitState } from '../../../../../shared/rate-limit-state-factory' import type { InactiveAccountUsage, ProviderRateLimits, RateLimitWindow -} from '../../../../shared/rate-limit-types' +} from '../../../../../shared/rate-limit-types' import { makeTab } from '@/store/terminals/testing/terminal-tab.test-fixture' import { CodexSwitcherMenu } from './CodexSwitcherMenu' import { diff --git a/src/renderer/src/components/status-bar/CodexSwitcherMenu.tsx b/src/renderer/src/components/status-bar/accounts/CodexSwitcherMenu.tsx similarity index 95% rename from src/renderer/src/components/status-bar/CodexSwitcherMenu.tsx rename to src/renderer/src/components/status-bar/accounts/CodexSwitcherMenu.tsx index ad5b0d15543..8d7ba78b183 100644 --- a/src/renderer/src/components/status-bar/CodexSwitcherMenu.tsx +++ b/src/renderer/src/components/status-bar/accounts/CodexSwitcherMenu.tsx @@ -1,16 +1,19 @@ import React from 'react' import { CodexResetCredits, CodexResetConfirmation } from './CodexResetCredits' import { DropdownMenuItem, DropdownMenuLabel } from '@/components/ui/dropdown-menu' -import type { ProviderRateLimits } from '../../../../shared/rate-limit-types' +import type { ProviderRateLimits } from '../../../../../shared/rate-limit-types' import { useTranslate } from '@/i18n/use-translate' -import { AccountRuntimeToggle, CodexRestartStatusPrompt } from './StatusBarAccountControls' +import { + AccountRuntimeToggle, + CodexRestartStatusPrompt +} from '../composition/StatusBarAccountControls' import { InlineUsageBars, InlineUsageSignInAction, InlineUsageSkeleton, isUnavailableInactiveUsage -} from './InlineProviderUsage' -import { ProviderDetailsMenu } from './ProviderDetailsMenu' +} from '../usage/InlineProviderUsage' +import { ProviderDetailsMenu } from '../usage/ProviderDetailsMenu' import { AccountSwitchSection } from './AccountSwitchList' import { AccountSwitchRowItem } from './AccountSwitchRowItem' import { useCodexSwitcherController } from './use-codex-switcher-controller' diff --git a/src/renderer/src/components/status-bar/ProviderAccountChatButton.tsx b/src/renderer/src/components/status-bar/accounts/ProviderAccountChatButton.tsx similarity index 93% rename from src/renderer/src/components/status-bar/ProviderAccountChatButton.tsx rename to src/renderer/src/components/status-bar/accounts/ProviderAccountChatButton.tsx index 573db6a4def..e44b98e7b60 100644 --- a/src/renderer/src/components/status-bar/ProviderAccountChatButton.tsx +++ b/src/renderer/src/components/status-bar/accounts/ProviderAccountChatButton.tsx @@ -1,8 +1,8 @@ import type { ComponentProps } from 'react' import { Button } from '@/components/ui/button' import { useTranslate } from '@/i18n/use-translate' -import { useAppStore } from '@/store' -import type { RuntimeClientTarget } from '../../../../shared/runtime-client-target' +import { useAppStore } from '@/store/index' +import type { RuntimeClientTarget } from '../../../../../shared/runtime-client-target' export type ChatAccountAction = { target: RuntimeClientTarget; canSwitch: () => Promise } diff --git a/src/renderer/src/components/status-bar/ProviderIdentityCard.tsx b/src/renderer/src/components/status-bar/accounts/ProviderIdentityCard.tsx similarity index 81% rename from src/renderer/src/components/status-bar/ProviderIdentityCard.tsx rename to src/renderer/src/components/status-bar/accounts/ProviderIdentityCard.tsx index d253dfd68fb..eec5cb2c8d5 100644 --- a/src/renderer/src/components/status-bar/ProviderIdentityCard.tsx +++ b/src/renderer/src/components/status-bar/accounts/ProviderIdentityCard.tsx @@ -1,10 +1,10 @@ import React from 'react' import { Card } from '@/components/ui/card' -import type { ProviderRateLimits } from '../../../../shared/rate-limit-types' -import type { UsagePercentageDisplay } from '../../../../shared/usage-percentage-display' +import type { ProviderRateLimits } from '../../../../../shared/rate-limit-types' +import type { UsagePercentageDisplay } from '../../../../../shared/usage-percentage-display' import { useTranslate } from '@/i18n/use-translate' -import { getProviderDisplayName } from '../../../../shared/usage-provider-windows' -import { formatTimeAgo, ProviderIcon, ProviderPanel } from './tooltip' +import { getProviderDisplayName } from '../../../../../shared/usage-provider-windows' +import { formatTimeAgo, ProviderIcon, ProviderPanel } from '../usage/provider-usage-panel' export function ProviderIdentityCard({ p, diff --git a/src/renderer/src/components/status-bar/codex-restart-status-summary.ts b/src/renderer/src/components/status-bar/accounts/codex-restart-status-summary.ts similarity index 100% rename from src/renderer/src/components/status-bar/codex-restart-status-summary.ts rename to src/renderer/src/components/status-bar/accounts/codex-restart-status-summary.ts diff --git a/src/renderer/src/components/status-bar/codex-sign-in-action.ts b/src/renderer/src/components/status-bar/accounts/codex-sign-in-action.ts similarity index 95% rename from src/renderer/src/components/status-bar/codex-sign-in-action.ts rename to src/renderer/src/components/status-bar/accounts/codex-sign-in-action.ts index 34c8c314a14..215024ea03c 100644 --- a/src/renderer/src/components/status-bar/codex-sign-in-action.ts +++ b/src/renderer/src/components/status-bar/accounts/codex-sign-in-action.ts @@ -1,7 +1,7 @@ import type { Dispatch, MutableRefObject, SetStateAction } from 'react' import { toast } from 'sonner' -import type { CodexRateLimitAccountsState } from '../../../../shared/managed-account-types' -import type { AppState } from '../../store/types' +import type { CodexRateLimitAccountsState } from '../../../../../shared/managed-account-types' +import type { AppState } from '../../../store/types' import { translate } from '@/i18n/i18n' import { markLiveCodexSessionsForRestart, diff --git a/src/renderer/src/components/status-bar/codex-switcher-projection.ts b/src/renderer/src/components/status-bar/accounts/codex-switcher-projection.ts similarity index 74% rename from src/renderer/src/components/status-bar/codex-switcher-projection.ts rename to src/renderer/src/components/status-bar/accounts/codex-switcher-projection.ts index 187d8321aae..ad18686a787 100644 --- a/src/renderer/src/components/status-bar/codex-switcher-projection.ts +++ b/src/renderer/src/components/status-bar/accounts/codex-switcher-projection.ts @@ -1,8 +1,6 @@ -import type { ProviderRateLimits } from '../../../../shared/rate-limit-types' -import { formatResetCreditExpiry } from './tooltip' -import type { Translate } from '../../i18n/use-translate' - -export { getCodexAccountSyncKey } from './provider-account-sync-key' +import type { ProviderRateLimits } from '../../../../../shared/rate-limit-types' +import { formatResetCreditExpiry } from '../usage/provider-usage-panel' +import type { Translate } from '../../../i18n/use-translate' export function getCodexResetProjection( codex: ProviderRateLimits, diff --git a/src/renderer/src/components/status-bar/provider-account-sync-key.ts b/src/renderer/src/components/status-bar/accounts/provider-account-sync-key.ts similarity index 97% rename from src/renderer/src/components/status-bar/provider-account-sync-key.ts rename to src/renderer/src/components/status-bar/accounts/provider-account-sync-key.ts index ba7c3f50e22..157fac12907 100644 --- a/src/renderer/src/components/status-bar/provider-account-sync-key.ts +++ b/src/renderer/src/components/status-bar/accounts/provider-account-sync-key.ts @@ -1,6 +1,6 @@ import { sameProviderAccountData } from '@/runtime/provider-accounts/observations/observed-provider-accounts' import type { ClaudeAccountSettings } from './status-bar-claude-accounts' -import type { GlobalSettings } from '../../../../shared/global-settings-types' +import type { GlobalSettings } from '../../../../../shared/global-settings-types' // Cache by settings identity because Zustand reevaluates selectors on every store write and roster serialization is expensive. const claudeKeyBySettings = new WeakMap() diff --git a/src/renderer/src/components/status-bar/icons.tsx b/src/renderer/src/components/status-bar/accounts/provider-icons.tsx similarity index 99% rename from src/renderer/src/components/status-bar/icons.tsx rename to src/renderer/src/components/status-bar/accounts/provider-icons.tsx index baab70777a0..24952734625 100644 --- a/src/renderer/src/components/status-bar/icons.tsx +++ b/src/renderer/src/components/status-bar/accounts/provider-icons.tsx @@ -1,5 +1,5 @@ import React from 'react' -import minimaxIconUrl from '../../../../../resources/minimax-icon.svg?url' +import minimaxIconUrl from '../../../../../../resources/minimax-icon.svg?url' export function OpenAIIcon({ size = 14, diff --git a/src/renderer/src/components/status-bar/status-bar-claude-accounts.ts b/src/renderer/src/components/status-bar/accounts/status-bar-claude-accounts.ts similarity index 97% rename from src/renderer/src/components/status-bar/status-bar-claude-accounts.ts rename to src/renderer/src/components/status-bar/accounts/status-bar-claude-accounts.ts index 2043f554e5b..6ca7e5a9cb8 100644 --- a/src/renderer/src/components/status-bar/status-bar-claude-accounts.ts +++ b/src/renderer/src/components/status-bar/accounts/status-bar-claude-accounts.ts @@ -1,5 +1,5 @@ -import type { GlobalSettings } from '../../../../shared/global-settings-types' -import type { ClaudeRateLimitAccountsState } from '../../../../shared/managed-account-types' +import type { GlobalSettings } from '../../../../../shared/global-settings-types' +import type { ClaudeRateLimitAccountsState } from '../../../../../shared/managed-account-types' import { translate } from '@/i18n/i18n' import { getCodexStatusRuntimeKey, diff --git a/src/renderer/src/components/status-bar/status-bar-codex-accounts.ts b/src/renderer/src/components/status-bar/accounts/status-bar-codex-accounts.ts similarity index 97% rename from src/renderer/src/components/status-bar/status-bar-codex-accounts.ts rename to src/renderer/src/components/status-bar/accounts/status-bar-codex-accounts.ts index 8eb742a28ef..0f851432709 100644 --- a/src/renderer/src/components/status-bar/status-bar-codex-accounts.ts +++ b/src/renderer/src/components/status-bar/accounts/status-bar-codex-accounts.ts @@ -1,5 +1,5 @@ -import type { GlobalSettings } from '../../../../shared/global-settings-types' -import type { CodexRateLimitAccountsState } from '../../../../shared/managed-account-types' +import type { GlobalSettings } from '../../../../../shared/global-settings-types' +import type { CodexRateLimitAccountsState } from '../../../../../shared/managed-account-types' import { translate } from '@/i18n/i18n' import { getCodexAccountDisplayDetail, diff --git a/src/renderer/src/components/status-bar/status-bar-runtime-targets.ts b/src/renderer/src/components/status-bar/accounts/status-bar-runtime-targets.ts similarity index 87% rename from src/renderer/src/components/status-bar/status-bar-runtime-targets.ts rename to src/renderer/src/components/status-bar/accounts/status-bar-runtime-targets.ts index a929f660280..ae1fad38f37 100644 --- a/src/renderer/src/components/status-bar/status-bar-runtime-targets.ts +++ b/src/renderer/src/components/status-bar/accounts/status-bar-runtime-targets.ts @@ -1,9 +1,9 @@ -import type { GlobalSettings } from '../../../../shared/global-settings-types' -import type { RateLimitRuntimeTarget } from '../../../../shared/rate-limit-types' -import { resolveLocalAccountRuntimeTarget } from '../../../../shared/local-account-runtime' -import { getRendererAppPlatform } from '../../app-shell/platform/renderer-app-platform' +import type { GlobalSettings } from '../../../../../shared/global-settings-types' +import type { RateLimitRuntimeTarget } from '../../../../../shared/rate-limit-types' +import { resolveLocalAccountRuntimeTarget } from '../../../../../shared/local-account-runtime' +import { getRendererAppPlatform } from '../../../app-shell/platform/renderer-app-platform' import { translate } from '@/i18n/i18n' -import { getHostRuntimeLabel } from '../../lib/provider-accounts/account-runtime-label' +import { getHostRuntimeLabel } from '../../../lib/provider-accounts/account-runtime-label' export type CodexStatusRuntimeTarget = { runtime: 'host' | 'wsl' diff --git a/src/renderer/src/components/status-bar/use-claude-switcher-state.ts b/src/renderer/src/components/status-bar/accounts/use-claude-switcher-state.ts similarity index 96% rename from src/renderer/src/components/status-bar/use-claude-switcher-state.ts rename to src/renderer/src/components/status-bar/accounts/use-claude-switcher-state.ts index 44d8d26c79b..d62b81f958f 100644 --- a/src/renderer/src/components/status-bar/use-claude-switcher-state.ts +++ b/src/renderer/src/components/status-bar/accounts/use-claude-switcher-state.ts @@ -1,4 +1,4 @@ -import { useAppStore } from '../../store' +import { useAppStore } from '../../../store/index' import type { ChatAccountAction } from './ProviderAccountChatButton' import { getClaudeAccountSettings, diff --git a/src/renderer/src/components/status-bar/use-codex-switcher-controller.ts b/src/renderer/src/components/status-bar/accounts/use-codex-switcher-controller.ts similarity index 96% rename from src/renderer/src/components/status-bar/use-codex-switcher-controller.ts rename to src/renderer/src/components/status-bar/accounts/use-codex-switcher-controller.ts index 145243ffd32..eab5357ea39 100644 --- a/src/renderer/src/components/status-bar/use-codex-switcher-controller.ts +++ b/src/renderer/src/components/status-bar/accounts/use-codex-switcher-controller.ts @@ -1,7 +1,7 @@ import { useCallback, useEffect, 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 type { CodexRateLimitAccountsState } from '../../../../../shared/managed-account-types' +import type { ProviderRateLimits } from '../../../../../shared/rate-limit-types' +import { useAppStore } from '../../../store/index' import { defaultScopeHost } from '@/runtime/hosts/selection/default-creation-host' import { useActiveAccountOwner } from '@/runtime/provider-accounts/ownership/use-active-account-owner' import { runtimeTargetEnvironmentId } from '@/runtime/rpc/targets/runtime-client-target' @@ -18,7 +18,8 @@ import { getWindowsTerminalCapabilityOwnerKey, useWindowsTerminalCapabilities } from '@/runtime/hosts/capabilities/windows-terminal-capabilities' -import { getCodexAccountSyncKey, getCodexResetProjection } from './codex-switcher-projection' +import { getCodexResetProjection } from './codex-switcher-projection' +import { getCodexAccountSyncKey } from './provider-account-sync-key' import { getCodexStatusRuntimeKey, getStatusBarPreferredWslDistro, diff --git a/src/renderer/src/components/status-bar/use-provider-account-list.ts b/src/renderer/src/components/status-bar/accounts/use-provider-account-list.ts similarity index 97% rename from src/renderer/src/components/status-bar/use-provider-account-list.ts rename to src/renderer/src/components/status-bar/accounts/use-provider-account-list.ts index f833ba141df..0aa47284275 100644 --- a/src/renderer/src/components/status-bar/use-provider-account-list.ts +++ b/src/renderer/src/components/status-bar/accounts/use-provider-account-list.ts @@ -5,7 +5,7 @@ import { type ProviderAccountsSnapshot } from '@/runtime/provider-accounts/observations/runtime-provider-accounts-client' import { observedProviderAccounts } from '@/runtime/provider-accounts/observations/observed-provider-accounts' -import type { RuntimeClientTarget } from '../../../../shared/runtime-client-target' +import type { RuntimeClientTarget } from '../../../../../shared/runtime-client-target' const noSubscription = () => () => {} const noSnapshot = () => null diff --git a/src/renderer/src/components/status-bar/codex-restart-status-keyboard.test.tsx b/src/renderer/src/components/status-bar/codex-restart-status-keyboard.test.tsx deleted file mode 100644 index 569096d5b7c..00000000000 --- a/src/renderer/src/components/status-bar/codex-restart-status-keyboard.test.tsx +++ /dev/null @@ -1,49 +0,0 @@ -// @vitest-environment happy-dom -import { cleanup, fireEvent, render, screen, waitFor } from '@testing-library/react' -import { afterEach, describe, expect, it, vi } from 'vitest' -import { - DropdownMenu, - DropdownMenuContent, - DropdownMenuItem, - DropdownMenuTrigger -} from '@/components/ui/dropdown-menu' -import { CodexRestartStatusPrompt } from './StatusBarAccountControls' - -const { state } = vi.hoisted(() => ({ - state: { - tabsByWorktree: { workspace: [{ id: 'tab-1' }] }, - ptyIdsByTabId: { 'tab-1': ['pty-1'] }, - codexRestartNoticeByPtyId: { - 'pty-1': { previousAccountLabel: 'old', nextAccountLabel: 'new' } - }, - queuePaneAccountRestarts: vi.fn() - } -})) - -vi.mock('../../store', () => ({ - useAppStore: (selector: (value: typeof state) => unknown) => selector(state) -})) - -afterEach(cleanup) - -describe('Codex restart banner keyboard action', () => { - it('reaches the restart action with arrow keys and activates it once with Enter', async () => { - render( - - Accounts - - Previous action - - - - ) - const previous = await screen.findByRole('menuitem', { name: 'Previous action' }) - previous.focus() - fireEvent.keyDown(previous, { key: 'ArrowDown' }) - const restart = screen.getByRole('menuitem', { name: 'Restart Session' }) - await waitFor(() => expect(document.activeElement).toBe(restart)) - fireEvent.keyDown(restart, { key: 'Enter' }) - expect(state.queuePaneAccountRestarts).toHaveBeenCalledExactlyOnceWith(['pty-1'], 'codex') - expect(screen.getByRole('menuitem', { name: 'Restart Session' })).toBeTruthy() - }) -}) diff --git a/src/renderer/src/components/status-bar/StatusBarAccountControls.tsx b/src/renderer/src/components/status-bar/composition/StatusBarAccountControls.tsx similarity index 96% rename from src/renderer/src/components/status-bar/StatusBarAccountControls.tsx rename to src/renderer/src/components/status-bar/composition/StatusBarAccountControls.tsx index 8603544747c..9dc20b5d737 100644 --- a/src/renderer/src/components/status-bar/StatusBarAccountControls.tsx +++ b/src/renderer/src/components/status-bar/composition/StatusBarAccountControls.tsx @@ -2,8 +2,8 @@ import { TriangleAlert } from 'lucide-react' import React, { useMemo } from 'react' import { Button } from '@/components/ui/button' import { DropdownMenuItem } from '@/components/ui/dropdown-menu' -import { useAppStore } from '../../store' -import { summarizeCodexRestartStatus } from './codex-restart-status-summary' +import { useAppStore } from '../../../store/index' +import { summarizeCodexRestartStatus } from '../accounts/codex-restart-status-summary' import { useTranslate } from '@/i18n/use-translate' export function CodexRestartStatusPrompt(): React.JSX.Element | null { diff --git a/src/renderer/src/components/status-bar/StatusBarVisibilityMenu.tsx b/src/renderer/src/components/status-bar/composition/StatusBarVisibilityMenu.tsx similarity index 98% rename from src/renderer/src/components/status-bar/StatusBarVisibilityMenu.tsx rename to src/renderer/src/components/status-bar/composition/StatusBarVisibilityMenu.tsx index 45f619e118d..9d5531e1eb0 100644 --- a/src/renderer/src/components/status-bar/StatusBarVisibilityMenu.tsx +++ b/src/renderer/src/components/status-bar/composition/StatusBarVisibilityMenu.tsx @@ -7,7 +7,13 @@ import { DropdownMenuTrigger } from '@/components/ui/dropdown-menu' import { AgentIcon } from '@/components/agent/icons/AgentIcon' -import { ClaudeIcon, GeminiIcon, MiniMaxIcon, OpenAIIcon, OpenCodeGoIcon } from './icons' +import { + ClaudeIcon, + GeminiIcon, + MiniMaxIcon, + OpenAIIcon, + OpenCodeGoIcon +} from '../accounts/provider-icons' import { useTranslate } from '@/i18n/use-translate' import { isStatusBarItemAvailable } from './status-bar-agent-gating' import type { StatusBarController } from './use-status-bar-controller' diff --git a/src/renderer/src/components/status-bar/status-bar-agent-gating.ts b/src/renderer/src/components/status-bar/composition/status-bar-agent-gating.ts similarity index 77% rename from src/renderer/src/components/status-bar/status-bar-agent-gating.ts rename to src/renderer/src/components/status-bar/composition/status-bar-agent-gating.ts index 1aba45e96d2..b2bb321c292 100644 --- a/src/renderer/src/components/status-bar/status-bar-agent-gating.ts +++ b/src/renderer/src/components/status-bar/composition/status-bar-agent-gating.ts @@ -1,5 +1,5 @@ -import type { TuiAgent } from '../../../../shared/agent-launch/catalog/tui-agent' -import type { StatusBarItem } from '../../../../shared/ui-chrome-types' +import type { TuiAgent } from '../../../../../shared/agent-launch/catalog/tui-agent' +import type { StatusBarItem } from '../../../../../shared/ui-chrome-types' // Hide missing CLI items and toggles after detection; unknown detection preserves them to avoid cold-start flicker. const CLI_GATED_ITEMS: ReadonlySet = new Set([ diff --git a/src/renderer/src/components/status-bar/status-bar-context-menu-policy.ts b/src/renderer/src/components/status-bar/composition/status-bar-context-menu-policy.ts similarity index 100% rename from src/renderer/src/components/status-bar/status-bar-context-menu-policy.ts rename to src/renderer/src/components/status-bar/composition/status-bar-context-menu-policy.ts diff --git a/src/renderer/src/components/status-bar/status-bar-density.ts b/src/renderer/src/components/status-bar/composition/status-bar-density.ts similarity index 100% rename from src/renderer/src/components/status-bar/status-bar-density.ts rename to src/renderer/src/components/status-bar/composition/status-bar-density.ts diff --git a/src/renderer/src/components/status-bar/status-bar-provider-visibility.ts b/src/renderer/src/components/status-bar/composition/status-bar-provider-visibility.ts similarity index 96% rename from src/renderer/src/components/status-bar/status-bar-provider-visibility.ts rename to src/renderer/src/components/status-bar/composition/status-bar-provider-visibility.ts index 00695c7c033..0b76a328cb5 100644 --- a/src/renderer/src/components/status-bar/status-bar-provider-visibility.ts +++ b/src/renderer/src/components/status-bar/composition/status-bar-provider-visibility.ts @@ -1,6 +1,6 @@ -import type { ProviderRateLimits } from '../../../../shared/rate-limit-types' -import type { GlobalSettings } from '../../../../shared/global-settings-types' -import { hasUsageData } from '../../../../shared/usage-provider-windows' +import type { ProviderRateLimits } from '../../../../../shared/rate-limit-types' +import type { GlobalSettings } from '../../../../../shared/global-settings-types' +import { hasUsageData } from '../../../../../shared/usage-provider-windows' export type UsageProviderSettings = Pick< GlobalSettings, diff --git a/src/renderer/src/components/status-bar/status-bar-usage-collapse.ts b/src/renderer/src/components/status-bar/composition/status-bar-usage-collapse.ts similarity index 100% rename from src/renderer/src/components/status-bar/status-bar-usage-collapse.ts rename to src/renderer/src/components/status-bar/composition/status-bar-usage-collapse.ts diff --git a/src/renderer/src/components/status-bar/status-bar-usage-sections.ts b/src/renderer/src/components/status-bar/composition/status-bar-usage-sections.ts similarity index 85% rename from src/renderer/src/components/status-bar/status-bar-usage-sections.ts rename to src/renderer/src/components/status-bar/composition/status-bar-usage-sections.ts index 9b9e2701101..f4afd0b3e01 100644 --- a/src/renderer/src/components/status-bar/status-bar-usage-sections.ts +++ b/src/renderer/src/components/status-bar/composition/status-bar-usage-sections.ts @@ -1,10 +1,10 @@ -import type { ProviderRateLimits, RateLimitWindow } from '../../../../shared/rate-limit-types' -import type { StatusBarUsageMode } from '../../../../shared/status-bar-usage-mode' -import { isCursorUsageBucket } from '../../../../shared/cursor-usage-buckets' +import type { ProviderRateLimits, RateLimitWindow } from '../../../../../shared/rate-limit-types' +import type { StatusBarUsageMode } from '../../../../../shared/status-bar-usage-mode' +import { isCursorUsageBucket } from '../../../../../shared/cursor-usage-buckets' import { translate } from '@/i18n/i18n' import type { Translate } from '@/i18n/use-translate' -import { formatRateLimitWindowChipLabel } from '../../../../shared/rate-limit-window-label' -import { getUsageHeadlineSection } from './UsageRosterPanel' +import { formatRateLimitWindowChipLabel } from '../../../../../shared/rate-limit-window-label' +import { getUsageHeadlineSection } from '../usage/UsageRosterPanel' export type StatusBarUsageSection = { key: string diff --git a/src/renderer/src/components/status-bar/use-available-status-bar-toggles.ts b/src/renderer/src/components/status-bar/composition/use-available-status-bar-toggles.ts similarity index 76% rename from src/renderer/src/components/status-bar/use-available-status-bar-toggles.ts rename to src/renderer/src/components/status-bar/composition/use-available-status-bar-toggles.ts index b282cae497f..502d36318be 100644 --- a/src/renderer/src/components/status-bar/use-available-status-bar-toggles.ts +++ b/src/renderer/src/components/status-bar/composition/use-available-status-bar-toggles.ts @@ -1,5 +1,5 @@ -import { useAppStore } from '../../store' -import type { StatusBarItem } from '../../../../shared/ui-chrome-types' +import { useAppStore } from '../../../store/index' +import type { StatusBarItem } from '../../../../../shared/ui-chrome-types' import { isStatusBarItemAvailable } from './status-bar-agent-gating' /** Keep CLI toggles visible until detection proves their agent missing. */ diff --git a/src/renderer/src/components/status-bar/use-status-bar-controller.ts b/src/renderer/src/components/status-bar/composition/use-status-bar-controller.ts similarity index 94% rename from src/renderer/src/components/status-bar/use-status-bar-controller.ts rename to src/renderer/src/components/status-bar/composition/use-status-bar-controller.ts index 9141d96d067..cb5a8bd6f0e 100644 --- a/src/renderer/src/components/status-bar/use-status-bar-controller.ts +++ b/src/renderer/src/components/status-bar/composition/use-status-bar-controller.ts @@ -1,21 +1,24 @@ import { useCallback, useEffect, useRef, useState } from 'react' import { useShortcutLabel } from '@/hooks/useShortcutLabel' -import { useAppStore } from '../../store/index' -import { selectFloatingWorkspaceHasUnread } from '../../store/workspaces/floating/floating-workspace-unread-selector' -import type { ProviderRateLimits } from '../../../../shared/rate-limit-types' -import { normalizeUsagePercentageDisplay } from '../../../../shared/usage-percentage-display' -import { normalizeStatusBarUsageMode } from '../../../../shared/status-bar-usage-mode' +import { useAppStore } from '../../../store/index' +import { selectFloatingWorkspaceHasUnread } from '../../../store/workspaces/floating/floating-workspace-unread-selector' +import type { ProviderRateLimits } from '../../../../../shared/rate-limit-types' +import { normalizeUsagePercentageDisplay } from '../../../../../shared/usage-percentage-display' +import { normalizeStatusBarUsageMode } from '../../../../../shared/status-bar-usage-mode' import { isStatusBarItemAvailable } from './status-bar-agent-gating' import { getVisibleUsageProvider, isUsageEmptyState } from './status-bar-provider-visibility' import { getUsageProviderAccountsSectionId, usageRowSignInOpensSettings -} from './usage-provider-settings-target' -import { useStatusBarMenuFocusHandoff } from './ProviderDetailsMenu' +} from '../usage/usage-provider-settings-target' +import { useStatusBarMenuFocusHandoff } from '../usage/ProviderDetailsMenu' import { CLOSE_ALL_CONTEXT_MENUS_EVENT } from '@/lib/overlay-interaction/close-all-context-menus' import { useStatusBarDensity } from './status-bar-density' -import { getUsageOwnerHostScope, useOwnerUsageRateLimits } from './use-owner-usage-rate-limits' -import { isOwnerNotSetUpPlaceholder } from './owner-usage-rate-limits' +import { + getUsageOwnerHostScope, + useOwnerUsageRateLimits +} from '../usage/use-owner-usage-rate-limits' +import { isOwnerNotSetUpPlaceholder } from '../usage/owner-usage-rate-limits' import { useTranslate } from '@/i18n/use-translate' export function useStatusBarController(floatingTerminalOpen: boolean) { diff --git a/src/renderer/src/components/status-bar/PortsStatusSegment.tsx b/src/renderer/src/components/status-bar/host-connections/PortsStatusSegment.tsx similarity index 98% rename from src/renderer/src/components/status-bar/PortsStatusSegment.tsx rename to src/renderer/src/components/status-bar/host-connections/PortsStatusSegment.tsx index 5cae8cd1c9b..4a640d27662 100644 --- a/src/renderer/src/components/status-bar/PortsStatusSegment.tsx +++ b/src/renderer/src/components/status-bar/host-connections/PortsStatusSegment.tsx @@ -2,20 +2,20 @@ import React, { useCallback, useMemo, useState } from 'react' import { Plug, ChevronDown, ChevronRight, LoaderCircle } from 'lucide-react' import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover' import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip' -import { useAppStore } from '@/store' +import { useAppStore } from '@/store/index' import { refreshWorkspacePortScanForTarget } from '@/lib/workspace-ports/workspace-port-scan-refresh' import { useWorktreeRuntimeTarget } from '@/runtime/rpc/targets/use-worktree-runtime-target' import { getUnavailableWorkspacePortHosts, type WorkspacePortHostRef } from '@/lib/workspace-ports/workspace-port-host-availability' -import { getLocalExecutionHostLabel } from '../../../../shared/execution-host' +import { getLocalExecutionHostLabel } from '../../../../../shared/execution-host' import { getExternalWorkspacePorts, getWorkspacePortGroups } from '@/lib/workspace-ports/workspace-port-groups' import { SelectedTextCopyMenu } from '@/components/SelectedTextCopyMenu' -import { STATUS_BAR_CONTEXT_MENU_EXEMPT_PROPS } from './status-bar-context-menu-policy' +import { STATUS_BAR_CONTEXT_MENU_EXEMPT_PROPS } from '../composition/status-bar-context-menu-policy' import { PortRow, WorkspaceGroupRows } from './ports-status-popover-rows' import { useTranslate } from '@/i18n/use-translate' diff --git a/src/renderer/src/components/status-bar/RuntimeHostStatusRow.tsx b/src/renderer/src/components/status-bar/host-connections/RuntimeHostStatusRow.tsx similarity index 98% rename from src/renderer/src/components/status-bar/RuntimeHostStatusRow.tsx rename to src/renderer/src/components/status-bar/host-connections/RuntimeHostStatusRow.tsx index 7ac8d2d96a9..625d9fb8ce7 100644 --- a/src/renderer/src/components/status-bar/RuntimeHostStatusRow.tsx +++ b/src/renderer/src/components/status-bar/host-connections/RuntimeHostStatusRow.tsx @@ -14,8 +14,8 @@ import '@/runtime/hosts/connections/runtime-host-connection-state' import { isConnectedRuntimeHostState, type RuntimeHostConnectionState -} from '../../../../shared/remote-runtime/host-status/runtime-host-connection-state' -import type { RemoteRuntimeSharedConnectionDiagnostics } from '../../../../shared/remote-runtime/control/remote-runtime-shared-control-types' +} from '../../../../../shared/remote-runtime/host-status/runtime-host-connection-state' +import type { RemoteRuntimeSharedConnectionDiagnostics } from '../../../../../shared/remote-runtime/control/remote-runtime-shared-control-types' import type { RuntimeHostBlockedCopy, RuntimeHostBlockedRecovery diff --git a/src/renderer/src/components/status-bar/SshHostFindPopover.tsx b/src/renderer/src/components/status-bar/host-connections/SshHostFindPopover.tsx similarity index 95% rename from src/renderer/src/components/status-bar/SshHostFindPopover.tsx rename to src/renderer/src/components/status-bar/host-connections/SshHostFindPopover.tsx index b6dcddfcc09..6d46126acdc 100644 --- a/src/renderer/src/components/status-bar/SshHostFindPopover.tsx +++ b/src/renderer/src/components/status-bar/host-connections/SshHostFindPopover.tsx @@ -9,8 +9,8 @@ import { import { Popover, PopoverAnchor, PopoverContent } from '@/components/ui/popover' import { cn } from '@/lib/class-names' import { canConnectSshStatus } from '@/ssh/ssh-connection-recoverability' -import { STATUS_LABELS, statusColor } from '../settings/ssh/targets/SshTargetCard' -import { HostListOverflowNote } from '../host-picker/HostListOverflowNote' +import { STATUS_LABELS, statusColor } from '../../settings/ssh/targets/SshTargetCard' +import { HostListOverflowNote } from '../../host-picker/HostListOverflowNote' import { findSshHostMatches, type SshStatusMenuTarget } from './ssh-status-menu-rows' import { moreSshHostMatchesLabel, diff --git a/src/renderer/src/components/status-bar/SshStatusSegment.tsx b/src/renderer/src/components/status-bar/host-connections/SshStatusSegment.tsx similarity index 93% rename from src/renderer/src/components/status-bar/SshStatusSegment.tsx rename to src/renderer/src/components/status-bar/host-connections/SshStatusSegment.tsx index a9bcb03240c..67da36663fb 100644 --- a/src/renderer/src/components/status-bar/SshStatusSegment.tsx +++ b/src/renderer/src/components/status-bar/host-connections/SshStatusSegment.tsx @@ -8,27 +8,27 @@ import { DropdownMenuSeparator, DropdownMenuTrigger } from '@/components/ui/dropdown-menu' -import { useAppStore } from '../../store/index' +import { useAppStore } from '../../../store/index' import { translate } from '@/i18n/i18n' import { useTranslate } from '@/i18n/use-translate' -import { getHostDisplayLabelOverrides } from '../../../../shared/host-setting-overrides' +import { getHostDisplayLabelOverrides } from '../../../../../shared/host-setting-overrides' import { isOwnedSshTargetId, toRuntimeExecutionHostId, toSshExecutionHostId -} from '../../../../shared/execution-host' -import { buildExecutionHostRegistry } from '../../../../shared/execution-host/execution-host-registry' -import { pickerExecutionHosts } from '../../../../shared/execution-host/managed-orcad-execution-host' +} from '../../../../../shared/execution-host' +import { buildExecutionHostRegistry } from '../../../../../shared/execution-host/execution-host-registry' +import { pickerExecutionHosts } from '../../../../../shared/execution-host/managed-orcad-execution-host' import { isListedRemoteServer, runtimePairingRepairRoute -} from '../../../../shared/remote-runtime/host-catalog/runtime-environments' +} from '../../../../../shared/remote-runtime/host-catalog/runtime-environments' import { RuntimeHostStatusRow } from './RuntimeHostStatusRow' import { connectedHostCountLabel, moreSshHostsLabel } from './ssh-status-segment-copy' import { SshHostFindPopover } from './SshHostFindPopover' import { splitSshStatusMenuRows } from './ssh-status-menu-rows' import { SshTargetStatusRow } from './SshTargetStatusRow' -import { syncSshConfigTargetsPassively } from '../../runtime/hosts/ssh/ssh-config-passive-sync' +import { syncSshConfigTargetsPassively } from '../../../runtime/hosts/ssh/ssh-config-passive-sync' import { connectRuntimeHostAndReloadProjects } from './runtime-environment-explicit-connect' import { runtimeHostBlockedCopy, @@ -39,9 +39,9 @@ import { } from './remote-host-connection-status' import type { RuntimeHostBlockedRecovery } from './remote-host-connection-status' import { runtimeHostConnectionStateForEntry } from '@/runtime/hosts/connections/runtime-host-connection-state' -import { isConnectedRuntimeHostState } from '../../../../shared/remote-runtime/host-status/runtime-host-connection-state' -import { RuntimeRepairDialog } from '../runtime-access/RuntimeRepairDialog' -import type { SshConnectionStatus } from '../../../../shared/ssh-types' +import { isConnectedRuntimeHostState } from '../../../../../shared/remote-runtime/host-status/runtime-host-connection-state' +import { RuntimeRepairDialog } from '../../runtime-access/RuntimeRepairDialog' +import type { SshConnectionStatus } from '../../../../../shared/ssh-types' export function SshStatusSegment({ compact, diff --git a/src/renderer/src/components/status-bar/SshTargetStatusRow.tsx b/src/renderer/src/components/status-bar/host-connections/SshTargetStatusRow.tsx similarity index 92% rename from src/renderer/src/components/status-bar/SshTargetStatusRow.tsx rename to src/renderer/src/components/status-bar/host-connections/SshTargetStatusRow.tsx index a31211ebeac..8a9da115ce4 100644 --- a/src/renderer/src/components/status-bar/SshTargetStatusRow.tsx +++ b/src/renderer/src/components/status-bar/host-connections/SshTargetStatusRow.tsx @@ -5,9 +5,9 @@ import { toastSshConnectFailure } from '@/ssh/ssh-connect-failure-toast' import { translate } from '@/i18n/i18n' import { useTranslate } from '@/i18n/use-translate' import { useMountedRef } from '@/hooks/useMountedRef' -import { useAppStore } from '../../store' -import { STATUS_LABELS, statusColor } from '../settings/ssh/targets/SshTargetCard' -import { formatSshUserFacingError } from '../settings/ssh/targets/ssh-user-facing-error' +import { useAppStore } from '../../../store/index' +import { STATUS_LABELS, statusColor } from '../../settings/ssh/targets/SshTargetCard' +import { formatSshUserFacingError } from '../../settings/ssh/targets/ssh-user-facing-error' import { canConnectSshStatus } from '@/ssh/ssh-connection-recoverability' import { sshConnectVerb } from '@/ssh/ssh-connect-verb' import { @@ -16,7 +16,7 @@ import { isSshConnectInFlight, useSshConnectInFlight } from '@/ssh/ssh-connect-in-flight' -import type { SshConnectionStatus } from '../../../../shared/ssh-types' +import type { SshConnectionStatus } from '../../../../../shared/ssh-types' export async function connectSshTargetFromStatusMenu(targetId: string): Promise { if (isSshConnectInFlight(targetId)) { diff --git a/src/renderer/src/components/status-bar/ports-status-popover-rows.tsx b/src/renderer/src/components/status-bar/host-connections/ports-status-popover-rows.tsx similarity index 98% rename from src/renderer/src/components/status-bar/ports-status-popover-rows.tsx rename to src/renderer/src/components/status-bar/host-connections/ports-status-popover-rows.tsx index e647529f5be..73e83300d2c 100644 --- a/src/renderer/src/components/status-bar/ports-status-popover-rows.tsx +++ b/src/renderer/src/components/status-bar/host-connections/ports-status-popover-rows.tsx @@ -18,8 +18,8 @@ import { import type { WorkspacePortGroup } from '@/lib/workspace-ports/workspace-port-groups' import { useLocalhostLabelRouteForPort } from '@/lib/workspace-ports/workspace-port-localhost-label-selector' import { useWorktreeRuntimeTarget } from '@/runtime/rpc/targets/use-worktree-runtime-target' -import { useAppStore } from '@/store' -import type { WorkspacePort } from '../../../../shared/workspace-ports' +import { useAppStore } from '@/store/index' +import type { WorkspacePort } from '../../../../../shared/workspace-ports' import { translate } from '@/i18n/i18n' import { useTranslate } from '@/i18n/use-translate' diff --git a/src/renderer/src/components/status-bar/remote-host-connection-status.ts b/src/renderer/src/components/status-bar/host-connections/remote-host-connection-status.ts similarity index 90% rename from src/renderer/src/components/status-bar/remote-host-connection-status.ts rename to src/renderer/src/components/status-bar/host-connections/remote-host-connection-status.ts index b311957e90f..6342d8d5471 100644 --- a/src/renderer/src/components/status-bar/remote-host-connection-status.ts +++ b/src/renderer/src/components/status-bar/host-connections/remote-host-connection-status.ts @@ -1,17 +1,17 @@ import { translate } from '@/i18n/i18n' import type { Translate } from '@/i18n/use-translate' -import type { SshConnectionStatus } from '../../../../shared/ssh-types' -import type { RemoteRuntimeSharedConnectionDiagnostics } from '../../../../shared/remote-runtime/control/remote-runtime-shared-control-types' -import type { RuntimeHostBlockedReason } from '../../../../shared/remote-runtime/host-status/runtime-host-status' -import type { RuntimePairingRepairRoute } from '../../../../shared/remote-runtime/host-catalog/runtime-environments' -import type { RuntimeCompatVerdict } from '../../../../shared/protocol-compat' +import type { SshConnectionStatus } from '../../../../../shared/ssh-types' +import type { RemoteRuntimeSharedConnectionDiagnostics } from '../../../../../shared/remote-runtime/control/remote-runtime-shared-control-types' +import type { RuntimeHostBlockedReason } from '../../../../../shared/remote-runtime/host-status/runtime-host-status' +import type { RuntimePairingRepairRoute } from '../../../../../shared/remote-runtime/host-catalog/runtime-environments' +import type { RuntimeCompatVerdict } from '../../../../../shared/protocol-compat' import { describeRuntimeCompatBlock } from '@/runtime/hosts/display/runtime-host-copy' import '@/runtime/hosts/connections/runtime-host-connection-state' import { runtimeStatusForOverall, type HostStatus, type RuntimeHostConnectionState -} from '../../../../shared/remote-runtime/host-status/runtime-host-connection-state' +} from '../../../../../shared/remote-runtime/host-status/runtime-host-connection-state' import { isConnectingSshStatus } from '@/ssh/ssh-connection-recoverability' /** 'blocked' is a host that refused us (revoked pairing or incompatible versions). */ diff --git a/src/renderer/src/components/status-bar/runtime-environment-explicit-connect.ts b/src/renderer/src/components/status-bar/host-connections/runtime-environment-explicit-connect.ts similarity index 92% rename from src/renderer/src/components/status-bar/runtime-environment-explicit-connect.ts rename to src/renderer/src/components/status-bar/host-connections/runtime-environment-explicit-connect.ts index 975098b7b96..529023541ff 100644 --- a/src/renderer/src/components/status-bar/runtime-environment-explicit-connect.ts +++ b/src/renderer/src/components/status-bar/host-connections/runtime-environment-explicit-connect.ts @@ -1,10 +1,10 @@ import { toast } from 'sonner' -import type { ExecutionHostId } from '../../../../shared/execution-host' -import type { RuntimeStatus } from '../../../../shared/runtime-types' +import type { ExecutionHostId } from '../../../../../shared/execution-host' +import type { RuntimeStatus } from '../../../../../shared/runtime-session-contracts' import { refreshRuntimeProjectWorktreesAndLineage } from '@/hooks/runtime-project-refresh-scheduler' import { translate } from '@/i18n/i18n' import { unwrapRuntimeRpcResult } from '@/runtime/rpc/calls/runtime-rpc-result' -import { useAppStore } from '../../store' +import { useAppStore } from '../../../store/index' export async function connectRuntimeEnvironmentAndRecordStatus( environmentId: string, diff --git a/src/renderer/src/components/status-bar/runtime-host-resources.ts b/src/renderer/src/components/status-bar/host-connections/runtime-host-resources.ts similarity index 95% rename from src/renderer/src/components/status-bar/runtime-host-resources.ts rename to src/renderer/src/components/status-bar/host-connections/runtime-host-resources.ts index b7aa5b5f8e5..68806176563 100644 --- a/src/renderer/src/components/status-bar/runtime-host-resources.ts +++ b/src/renderer/src/components/status-bar/host-connections/runtime-host-resources.ts @@ -1,8 +1,11 @@ import { translate } from '@/i18n/i18n' import type { Translate } from '@/i18n/use-translate' -import { parseExecutionHostId, toRuntimeExecutionHostId } from '../../../../shared/execution-host' -import type { SessionMemory, WorktreeMemory } from '../../../../shared/process-stats-types' -import type { RuntimeHostResourceSample } from './resource-usage-merge-types' +import { + parseExecutionHostId, + toRuntimeExecutionHostId +} from '../../../../../shared/execution-host' +import type { SessionMemory, WorktreeMemory } from '../../../../../shared/process-stats-types' +import type { RuntimeHostResourceSample } from '../resources/workspace-attribution/resource-usage-merge-types' export type RuntimeHostResourceResult = | { status: 'sampled'; worktrees: WorktreeMemory[] } diff --git a/src/renderer/src/components/status-bar/ssh-status-menu-rows.ts b/src/renderer/src/components/status-bar/host-connections/ssh-status-menu-rows.ts similarity index 91% rename from src/renderer/src/components/status-bar/ssh-status-menu-rows.ts rename to src/renderer/src/components/status-bar/host-connections/ssh-status-menu-rows.ts index cf630c3c5bf..730b7f31a1e 100644 --- a/src/renderer/src/components/status-bar/ssh-status-menu-rows.ts +++ b/src/renderer/src/components/status-bar/host-connections/ssh-status-menu-rows.ts @@ -1,5 +1,5 @@ -import type { SshConnectionStatus } from '../../../../shared/ssh-types' -import { boundHostList, type BoundedHostList } from '../host-picker/bounded-host-list' +import type { SshConnectionStatus } from '../../../../../shared/ssh-types' +import { boundHostList, type BoundedHostList } from '../../host-picker/bounded-host-list' // Bound idle hosts because generated SSH configs can turn thousands of rows into gigabytes of DOM. export const SSH_STATUS_MENU_IDLE_ROW_LIMIT = 25 diff --git a/src/renderer/src/components/status-bar/ssh-status-segment-copy.ts b/src/renderer/src/components/status-bar/host-connections/ssh-status-segment-copy.ts similarity index 100% rename from src/renderer/src/components/status-bar/ssh-status-segment-copy.ts rename to src/renderer/src/components/status-bar/host-connections/ssh-status-segment-copy.ts diff --git a/src/renderer/src/components/status-bar/use-runtime-host-resources.ts b/src/renderer/src/components/status-bar/host-connections/use-runtime-host-resources.ts similarity index 100% rename from src/renderer/src/components/status-bar/use-runtime-host-resources.ts rename to src/renderer/src/components/status-bar/host-connections/use-runtime-host-resources.ts diff --git a/src/renderer/src/components/status-bar/PluginStatusBarItems.tsx b/src/renderer/src/components/status-bar/plugins/PluginStatusBarItems.tsx similarity index 100% rename from src/renderer/src/components/status-bar/PluginStatusBarItems.tsx rename to src/renderer/src/components/status-bar/plugins/PluginStatusBarItems.tsx diff --git a/src/renderer/src/components/status-bar/PluginsStatusSegment.tsx b/src/renderer/src/components/status-bar/plugins/PluginsStatusSegment.tsx similarity index 100% rename from src/renderer/src/components/status-bar/PluginsStatusSegment.tsx rename to src/renderer/src/components/status-bar/plugins/PluginsStatusSegment.tsx diff --git a/src/renderer/src/components/status-bar/resource-pty-virtualization.test.tsx b/src/renderer/src/components/status-bar/resource-pty-virtualization.test.tsx deleted file mode 100644 index 1e263c00efd..00000000000 --- a/src/renderer/src/components/status-bar/resource-pty-virtualization.test.tsx +++ /dev/null @@ -1,300 +0,0 @@ -// @vitest-environment happy-dom - -import type { ComponentProps } from 'react' -import { act, cleanup, fireEvent, render } from '@testing-library/react' -import userEvent from '@testing-library/user-event' -import { afterEach, beforeEach, expect, it, vi } from 'vitest' -import type { - PtyFencedTerminationOutcome, - PtyFencedTerminationRequest -} from '../../../../shared/terminal/pty/lifecycle/pty-fenced-termination' -import { TooltipProvider } from '@/components/ui/tooltip' -import { ResourcePtyPanel } from './ResourcePtyPanel' -import { useResourcePtyActions } from './use-resource-pty-actions' -import { useResourceSessionInventory } from './use-resource-session-inventory' - -import { makeRepo, makeWorktree } from '../worktree-jump/worktree-jump-palette-test-fixtures' - -vi.mock('@/i18n/i18n', () => ({ - getIntlLocale: () => 'en', - translate: (_key: string, fallback: string, values?: Record) => - Object.entries(values ?? {}).reduce( - (text, [key, value]) => text.replace(`{{${key}}}`, String(value)), - fallback - ) -})) - -const VIEWPORT_HEIGHT = 360 -const ROW_HEIGHT = 40 - -beforeEach(() => { - vi.stubGlobal( - 'ResizeObserver', - class { - observe() {} - unobserve() {} - disconnect() {} - } - ) - vi.spyOn(HTMLElement.prototype, 'offsetHeight', 'get').mockImplementation(function ( - this: HTMLElement - ) { - return this.hasAttribute('data-resource-pty-body') ? VIEWPORT_HEIGHT : ROW_HEIGHT - }) - vi.spyOn(Element.prototype, 'getBoundingClientRect').mockImplementation(function (this: Element) { - return new DOMRect( - 0, - 0, - 400, - this.hasAttribute('data-resource-pty-body') ? VIEWPORT_HEIGHT : ROW_HEIGHT - ) - }) -}) - -afterEach(() => { - cleanup() - vi.useRealTimers() - vi.restoreAllMocks() - vi.unstubAllGlobals() -}) - -function panelProps(count: number): ComponentProps { - return { - active: true, - inventory: { - sessionInventory: { - sessions: Array.from({ length: count }, (_, index) => ({ - id: `pty-${String(index).padStart(5, '0')}`, - incarnationId: 'A', - fencedTermination: true, - cwd: '/notes', - title: `Terminal ${index}`, - worktreeId: 'wt-1', - agentOwnership: 'absent' as const - })), - count - }, - observedAt: 1, - sessionsError: false, - loading: false, - refreshSessions: async () => {}, - clearSessionsError: () => {}, - invalidate: () => {}, - removeSession: () => {}, - removeSessions: () => {} - }, - actions: { - ending: new Set(), - errors: new Map(), - end: () => {}, - endMany: async () => {} - }, - onNavigate: () => {}, - bindings: { tabsByWorktree: {}, ptyIdsByTabId: {}, workspaceSessionReady: true }, - worktrees: [makeWorktree('wt-1', 'Notes', { lastActivityAt: 100 })], - repos: [makeRepo()], - projectGroups: [], - runtimePaneTitlesByTabId: {} - } -} - -it.each([1_000, 10_000])( - 'bounds mounted PTY rows for %i sessions and reaches the last row', - (count) => { - const props = panelProps(count) - const view = render( - - - - ) - const scroller = view.container.querySelector('[data-resource-pty-body]') - if (!scroller) { - throw new Error('PTY scroller missing') - } - const mountedRows = () => view.container.querySelectorAll('[data-resource-pty-row]') - expect(mountedRows().length).toBeGreaterThan(0) - expect(mountedRows().length).toBeLessThan(50) - expect(mountedRows()[0]?.getAttribute('data-resource-pty-row')).toContain('pty-00000') - expect(view.container.querySelector('[role="listitem"]')?.getAttribute('aria-setsize')).toBe( - String(count + 2) - ) - act(() => { - scroller.scrollTop = (count + 2) * ROW_HEIGHT - VIEWPORT_HEIGHT - fireEvent.scroll(scroller) - }) - expect(mountedRows().length).toBeGreaterThan(0) - expect(mountedRows().length).toBeLessThan(50) - expect( - mountedRows()[mountedRows().length - 1]?.getAttribute('data-resource-pty-row') - ).toContain(`pty-${String(count - 1).padStart(5, '0')}`) - } -) - -it('selects across virtualized rows, excludes unavailable PTYs, and drops replaced identities', () => { - const props = panelProps(1_000) - props.inventory.sessionInventory.sessions[1]!.fencedTermination = false - props.inventory.sessionInventory.sessions[2]!.exiting = true - props.actions.ending = new Set([JSON.stringify(['pty-00003', 'A'])]) - const endMany = vi.fn() - props.actions.endMany = endMany - const panel = (value: typeof props) => ( - - - - ) - const view = render(panel(props)) - const selectAll = view.getByRole('checkbox', { name: 'Select all terminals' }) - const first = view.getByRole('checkbox', { name: 'Select Terminal 0' }) - expect(view.getByRole('checkbox', { name: 'Select Terminal 1' }).hasAttribute('disabled')).toBe( - true - ) - expect(view.getByRole('checkbox', { name: 'Select Terminal 2' }).hasAttribute('disabled')).toBe( - true - ) - fireEvent.click(first) - expect(selectAll.getAttribute('aria-checked')).toBe('mixed') - fireEvent.click(selectAll) - fireEvent.click(view.getByRole('button', { name: 'End selected (997)' })) - expect(endMany).toHaveBeenCalledTimes(1) - expect(endMany.mock.calls[0]![0]).toHaveLength(997) - fireEvent.click(selectAll) - fireEvent.click(first) - view.rerender( - panel({ - ...props, - inventory: { - ...props.inventory, - sessionInventory: { - ...props.inventory.sessionInventory, - sessions: props.inventory.sessionInventory.sessions.map((session) => ({ - ...session, - incarnationId: 'B' - })) - } - } - }) - ) - expect(view.getByRole('button', { name: 'End selected (0)' }).hasAttribute('disabled')).toBe(true) -}) - -function LivePtyPanel({ - active, - props -}: { - active: boolean - props: ComponentProps -}) { - const inventory = useResourceSessionInventory(true, active, true) - const actions = useResourcePtyActions(inventory) - return ( - - - - - ) -} - -async function livePanel(count: number) { - const rect = new DOMRect(0, 0, 400, VIEWPORT_HEIGHT) - vi.spyOn(Element.prototype, 'getClientRects').mockReturnValue( - Object.assign([rect], { item: () => rect }) - ) - const props = panelProps(count) - const list = vi.fn().mockResolvedValue(props.inventory.sessionInventory.sessions) - const finishes: ((outcome: PtyFencedTerminationOutcome) => void)[] = [] - const kill = vi.fn< - (request: PtyFencedTerminationRequest) => Promise - >( - () => - new Promise((resolve) => { - finishes.push(resolve) - }) - ) - vi.stubGlobal('api', { - pty: { listSessions: list, killFenced: kill, onSpawned: () => () => {}, onExit: () => () => {} } - }) - const panel = (active: boolean) => - const view = render(panel(true)) - await act(async () => {}) - const body = view.container.querySelector('[data-resource-pty-body]') - if (!body) { - throw new Error('PTY scroller missing') - } - body.style.visibility = 'visible' - const finish = async (outcome: PtyFencedTerminationOutcome) => { - vi.useFakeTimers() - if (outcome.outcome === 'ended') { - const ended = new Set(kill.mock.calls.map(([request]) => request.id)) - list.mockResolvedValue( - props.inventory.sessionInventory.sessions.filter((session) => !ended.has(session.id)) - ) - } - await act(async () => { - finishes.splice(0).forEach((resolve) => resolve(outcome)) - await vi.advanceTimersByTimeAsync(100) - }) - } - return { - ...view, - body, - finish, - kill, - user: userEvent.setup(), - setActive: (active: boolean) => view.rerender(panel(active)) - } -} - -it.each(['ended', 'refused'] as const)( - 'hands keyboard End focus to the PTY body before disabling a virtualized row, then handles %s', - async (outcome) => { - const view = await livePanel(1_000) - act(() => { - view.body.scrollTop = 1_002 * ROW_HEIGHT - VIEWPORT_HEIGHT - fireEvent.scroll(view.body) - }) - const scrollTop = view.body.scrollTop - const end = view.getByRole('button', { name: 'End Terminal 999' }) - end.focus() - await view.user.keyboard('{Enter}') - expect(view.kill).toHaveBeenCalledTimes(1) - expect(end.hasAttribute('disabled')).toBe(true) - expect(document.activeElement).toBe(view.body) - expect(view.body.scrollTop).toBe(scrollTop) - await view.finish(outcome === 'ended' ? { outcome } : { outcome, reason: 'claimed' }) - expect(document.activeElement).toBe(view.body) - if (outcome === 'ended') { - expect(view.queryByRole('button', { name: 'End Terminal 999' })).toBeNull() - } else { - expect(end.hasAttribute('disabled')).toBe(false) - expect(view.getByRole('alert').textContent).toContain('An agent now owns this terminal') - } - } -) - -it.each([true, false])( - 'preserves focus moved elsewhere before End completes with panel active=%s', - async (active) => { - const view = await livePanel(1) - view.getByRole('button', { name: 'End Terminal 0' }).focus() - await view.user.keyboard('{Enter}') - const elsewhere = view.getByRole('button', { name: 'Elsewhere' }) - elsewhere.focus() - view.setActive(active) - await view.finish({ outcome: 'ended' }) - expect(document.activeElement).toBe(elsewhere) - } -) - -it('hands bulk End focus to the body before the selection becomes unavailable', async () => { - const view = await livePanel(2) - fireEvent.click(view.getByRole('checkbox', { name: 'Select all terminals' })) - const end = view.getByRole('button', { name: 'End selected (2)' }) - end.focus() - await view.user.keyboard('{Enter}') - expect(view.kill).toHaveBeenCalledTimes(2) - expect(end.hasAttribute('disabled')).toBe(true) - expect(document.activeElement).toBe(view.body) - await view.finish({ outcome: 'ended' }) - expect(view.queryByRole('button', { name: 'End selected (0)' })).toBeNull() - expect(document.activeElement).toBe(view.body) -}) diff --git a/src/renderer/src/components/status-bar/resource-session-removal-render-budget.test.tsx b/src/renderer/src/components/status-bar/resource-session-removal-render-budget.test.tsx deleted file mode 100644 index aac318fb064..00000000000 --- a/src/renderer/src/components/status-bar/resource-session-removal-render-budget.test.tsx +++ /dev/null @@ -1,47 +0,0 @@ -// @vitest-environment happy-dom -import { act, cleanup, renderHook } from '@testing-library/react' -import { afterEach, expect, it, vi } from 'vitest' -import { ResourceSessionInventoryCache } from './resource-session-inventory-cache' -import { useSyncExternalStore } from 'react' - -afterEach(() => { - cleanup() - vi.useRealTimers() -}) -it('updates known exits cheaply and commits zero times for 1,000 inactive unknown lifecycle events', async () => { - vi.useFakeTimers() - const list = vi.fn(async () => [ - { id: 'known', incarnationId: 'A', title: 'Shell', cwd: '/', agentOwnership: 'absent' as const } - ]) - const cache = new ResourceSessionInventoryCache(list, true) - cache.setActive(true) - await cache.refresh() - await vi.advanceTimersByTimeAsync(100) - cache.setActive(false) - let renders = 0 - const view = renderHook(() => { - renders++ - return useSyncExternalStore(cache.subscribe, cache.getSnapshot) - }) - const baseline = view.result.current.sessionInventory - const before = renders - const calls = list.mock.calls.length - for (let index = 0; index < 1_000; index++) { - act(() => { - cache.spawned({ id: `unknown-${index}`, incarnationId: 'A', hostId: 'local' }) - cache.exited({ code: 0, id: `unknown-${index}`, incarnationId: 'A', hostId: 'local' }) - }) - } - await act(async () => { - await vi.advanceTimersByTimeAsync(60_000) - }) - expect(renders - before).toBe(0) - expect(view.result.current.sessionInventory).toBe(baseline) - expect(list.mock.calls.length).toBe(calls) - act(() => cache.exited({ code: 0, id: 'known', incarnationId: 'A', hostId: 'local' })) - await act(async () => { - await vi.advanceTimersByTimeAsync(50) - }) - expect(view.result.current.sessionInventory.count).toBe(0) - expect(renders - before).toBe(1) -}) diff --git a/src/renderer/src/components/status-bar/ResourceUsageStatusSegment.tsx b/src/renderer/src/components/status-bar/resources/ResourceUsageStatusSegment.tsx similarity index 92% rename from src/renderer/src/components/status-bar/ResourceUsageStatusSegment.tsx rename to src/renderer/src/components/status-bar/resources/ResourceUsageStatusSegment.tsx index 0ef94873862..8d457578ce7 100644 --- a/src/renderer/src/components/status-bar/ResourceUsageStatusSegment.tsx +++ b/src/renderer/src/components/status-bar/resources/ResourceUsageStatusSegment.tsx @@ -2,27 +2,25 @@ import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs' import { Badge } from '@/components/ui/badge' import { Activity, Terminal } from 'lucide-react' import { useTranslate } from '@/i18n/use-translate' -import { ResourcePtyPanel } from './ResourcePtyPanel' +import { ResourcePtyPanel } from './pty/ResourcePtyPanel' import React from 'react' import { Popover, PopoverContent } from '@/components/ui/popover' -import { DaemonActionDialog } from '../shared/useDaemonActions' -import { STATUS_BAR_CONTEXT_MENU_EXEMPT_PROPS } from './status-bar-context-menu-policy' +import { DaemonActionDialog } from '../../shared/useDaemonActions' +import { STATUS_BAR_CONTEXT_MENU_EXEMPT_PROPS } from '../composition/status-bar-context-menu-policy' import { useResourceUsageStatusController } from './use-resource-usage-status-controller' -import { renderResourceUsageStatusTrigger } from './resource-usage-status-trigger' +import { renderResourceUsageStatusTrigger } from './popover/resource-usage-status-trigger' import { renderDaemonUnreachableBanner, renderResourceUsagePopoverHeader, renderResourceUsageSummary, renderSessionsOnlyErrorBanner -} from './resource-usage-popover-summary' +} from './popover/resource-usage-popover-summary' import { renderResourceUsagePopoverBody, renderResourceUsagePopoverFooter -} from './resource-usage-popover-body' -import { renderResourceUsageKillDialog } from './resource-usage-kill-dialog' -import { WorkspaceSpaceCompactPanel } from './WorkspaceSpaceCompactPanel' - -export { SessionRow, WorktreeRow } from './resource-usage-session-rows' +} from './popover/resource-usage-popover-body' +import { renderResourceUsageKillDialog } from './popover/resource-usage-kill-dialog' +import { WorkspaceSpaceCompactPanel } from '../workspace-storage/WorkspaceSpaceCompactPanel' export function ResourceUsageStatusSegment({ iconOnly diff --git a/src/renderer/src/components/status-bar/hosted-review-label.ts b/src/renderer/src/components/status-bar/resources/hosted-review-label.ts similarity index 76% rename from src/renderer/src/components/status-bar/hosted-review-label.ts rename to src/renderer/src/components/status-bar/resources/hosted-review-label.ts index d9de1f5fe24..5b80a505689 100644 --- a/src/renderer/src/components/status-bar/hosted-review-label.ts +++ b/src/renderer/src/components/status-bar/resources/hosted-review-label.ts @@ -1,6 +1,6 @@ -import type { ProviderCheckSummary } from '../../../../shared/github/pull-requests/pull-request-types' -import { getProviderChecksOutcome } from '../../../../shared/source-control/checks/provider-check-summary' -import type { HostedReviewProvider } from '../../../../shared/source-control/hosted-review/hosted-review-contracts' +import type { ProviderCheckSummary } from '../../../../../shared/github/pull-requests/pull-request-types' +import { getProviderChecksOutcome } from '../../../../../shared/source-control/checks/provider-check-summary' +import type { HostedReviewProvider } from '../../../../../shared/source-control/hosted-review/hosted-review-contracts' import { localizedHostedReviewCopy, resolveSupportedHostedReviewCopyProvider diff --git a/src/renderer/src/components/status-bar/daemon-session-inventory-invalidation.ts b/src/renderer/src/components/status-bar/resources/inventory/daemon-session-inventory-invalidation.ts similarity index 100% rename from src/renderer/src/components/status-bar/daemon-session-inventory-invalidation.ts rename to src/renderer/src/components/status-bar/resources/inventory/daemon-session-inventory-invalidation.ts diff --git a/src/renderer/src/components/status-bar/resource-session-inventory-cache.ts b/src/renderer/src/components/status-bar/resources/inventory/resource-session-inventory-cache.ts similarity index 96% rename from src/renderer/src/components/status-bar/resource-session-inventory-cache.ts rename to src/renderer/src/components/status-bar/resources/inventory/resource-session-inventory-cache.ts index f45b215c9ac..47841a3f822 100644 --- a/src/renderer/src/components/status-bar/resource-session-inventory-cache.ts +++ b/src/renderer/src/components/status-bar/resources/inventory/resource-session-inventory-cache.ts @@ -2,9 +2,9 @@ import { ptySessionIdentity, type PtyListedSession, type PtySessionLifecycle -} from '../../../../shared/terminal/pty/lifecycle/pty-listed-session' -import { isResourceViewInactive } from '../../../../shared/resource-view-admission' -import { isProvenProcessExit } from '../../../../shared/terminal/pty/lifecycle/terminal-exit-cause' +} from '../../../../../../shared/terminal/pty/lifecycle/pty-listed-session' +import { isResourceViewInactive } from '../../../../../../shared/resource-view-admission' +import { isProvenProcessExit } from '../../../../../../shared/terminal/pty/lifecycle/terminal-exit-cause' import { type DaemonSessionInventory, EMPTY_DAEMON_SESSION_INVENTORY, diff --git a/src/renderer/src/components/status-bar/resource-session-inventory.ts b/src/renderer/src/components/status-bar/resources/inventory/resource-session-inventory.ts similarity index 95% rename from src/renderer/src/components/status-bar/resource-session-inventory.ts rename to src/renderer/src/components/status-bar/resources/inventory/resource-session-inventory.ts index 4f7f5ba5946..d6eeed090dc 100644 --- a/src/renderer/src/components/status-bar/resource-session-inventory.ts +++ b/src/renderer/src/components/status-bar/resources/inventory/resource-session-inventory.ts @@ -1,4 +1,4 @@ -import type { PtyListedSession as DaemonSession } from '../../../../shared/terminal/pty/lifecycle/pty-listed-session' +import type { PtyListedSession as DaemonSession } from '../../../../../../shared/terminal/pty/lifecycle/pty-listed-session' /** Last-known daemon terminal inventory for the Resource Manager badge. */ export type DaemonSessionInventory = { diff --git a/src/renderer/src/components/status-bar/use-resource-session-inventory.ts b/src/renderer/src/components/status-bar/resources/inventory/use-resource-session-inventory.ts similarity index 94% rename from src/renderer/src/components/status-bar/use-resource-session-inventory.ts rename to src/renderer/src/components/status-bar/resources/inventory/use-resource-session-inventory.ts index 24954b57dae..a23d39004e5 100644 --- a/src/renderer/src/components/status-bar/use-resource-session-inventory.ts +++ b/src/renderer/src/components/status-bar/resources/inventory/use-resource-session-inventory.ts @@ -1,7 +1,7 @@ import { useCallback, useEffect, useState, useSyncExternalStore } from 'react' import { subscribeDaemonSessionInventoryInvalidated } from './daemon-session-inventory-invalidation' import { ResourceSessionInventoryCache } from './resource-session-inventory-cache' -import type { PtyListedSession } from '../../../../shared/terminal/pty/lifecycle/pty-listed-session' +import type { PtyListedSession } from '../../../../../../shared/terminal/pty/lifecycle/pty-listed-session' export function useResourceSessionInventory(ready: boolean, active = false, localOnly = false) { const [cache] = useState( diff --git a/src/renderer/src/components/status-bar/resource-manager-terminal-copy.ts b/src/renderer/src/components/status-bar/resources/popover/resource-manager-terminal-copy.ts similarity index 100% rename from src/renderer/src/components/status-bar/resource-manager-terminal-copy.ts rename to src/renderer/src/components/status-bar/resources/popover/resource-manager-terminal-copy.ts diff --git a/src/renderer/src/components/status-bar/resource-memory-metric-copy.ts b/src/renderer/src/components/status-bar/resources/popover/resource-memory-metric-copy.ts similarity index 94% rename from src/renderer/src/components/status-bar/resource-memory-metric-copy.ts rename to src/renderer/src/components/status-bar/resources/popover/resource-memory-metric-copy.ts index 3a9ac1cea5d..f745c2bb534 100644 --- a/src/renderer/src/components/status-bar/resource-memory-metric-copy.ts +++ b/src/renderer/src/components/status-bar/resources/popover/resource-memory-metric-copy.ts @@ -1,7 +1,7 @@ -import type { ProcessMemoryMetric } from '../../../../shared/process-stats-types' +import type { ProcessMemoryMetric } from '../../../../../../shared/process-stats-types' import { translate } from '@/i18n/i18n' import type { Translate } from '@/i18n/use-translate' -import { usageTextColorClass } from './usage-roster-formatting' +import { usageTextColorClass } from '../../usage/usage-roster-formatting' export type ResourceMemoryMetricCopy = { columnLabel: string diff --git a/src/renderer/src/components/status-bar/resource-usage-kill-dialog.tsx b/src/renderer/src/components/status-bar/resources/popover/resource-usage-kill-dialog.tsx similarity index 96% rename from src/renderer/src/components/status-bar/resource-usage-kill-dialog.tsx rename to src/renderer/src/components/status-bar/resources/popover/resource-usage-kill-dialog.tsx index 654e5103875..00b7e52b1ee 100644 --- a/src/renderer/src/components/status-bar/resource-usage-kill-dialog.tsx +++ b/src/renderer/src/components/status-bar/resources/popover/resource-usage-kill-dialog.tsx @@ -11,7 +11,7 @@ import { } from '@/components/ui/dialog' import { translate } from '@/i18n/i18n' import type { Translate } from '@/i18n/use-translate' -import type { UnifiedSessionRow } from './resource-usage-merge-types' +import type { UnifiedSessionRow } from '../workspace-attribution/resource-usage-merge-types' export function renderResourceUsageKillDialog( { diff --git a/src/renderer/src/components/status-bar/resource-usage-metrics.tsx b/src/renderer/src/components/status-bar/resources/popover/resource-usage-metrics.tsx similarity index 97% rename from src/renderer/src/components/status-bar/resource-usage-metrics.tsx rename to src/renderer/src/components/status-bar/resources/popover/resource-usage-metrics.tsx index 4d437cf6dfa..36cd5367370 100644 --- a/src/renderer/src/components/status-bar/resource-usage-metrics.tsx +++ b/src/renderer/src/components/status-bar/resources/popover/resource-usage-metrics.tsx @@ -2,8 +2,8 @@ import React, { memo, useMemo } from 'react' import { ChevronDown, ChevronRight } from 'lucide-react' import { cn } from '@/lib/class-names' import { useTranslate } from '@/i18n/use-translate' -import type { AppMemory, UsageValues } from '../../../../shared/process-stats-types' -import type { Metric } from './resource-usage-merge-types' +import type { AppMemory, UsageValues } from '../../../../../../shared/process-stats-types' +import type { Metric } from '../workspace-attribution/resource-usage-merge-types' export const METRIC_COLUMNS_CLS = 'flex items-center shrink-0 tabular-nums' export const CPU_COLUMN_CLS = 'w-12 text-right' diff --git a/src/renderer/src/components/status-bar/resource-usage-popover-body.tsx b/src/renderer/src/components/status-bar/resources/popover/resource-usage-popover-body.tsx similarity index 97% rename from src/renderer/src/components/status-bar/resource-usage-popover-body.tsx rename to src/renderer/src/components/status-bar/resources/popover/resource-usage-popover-body.tsx index b4990f19c30..c84e919849e 100644 --- a/src/renderer/src/components/status-bar/resource-usage-popover-body.tsx +++ b/src/renderer/src/components/status-bar/resources/popover/resource-usage-popover-body.tsx @@ -3,8 +3,11 @@ import { ChevronRight } from 'lucide-react' import { cn } from '@/lib/class-names' import { translate } from '@/i18n/i18n' import type { Translate } from '@/i18n/use-translate' -import type { MemorySnapshot } from '../../../../shared/process-stats-types' -import type { UnifiedProjectGroup, UnifiedSessionRow } from './resource-usage-merge-types' +import type { MemorySnapshot } from '../../../../../../shared/process-stats-types' +import type { + UnifiedProjectGroup, + UnifiedSessionRow +} from '../workspace-attribution/resource-usage-merge-types' import type { SortOption } from './resource-usage-resource-tree' import { ResourceTree } from './resource-usage-resource-tree' import { diff --git a/src/renderer/src/components/status-bar/resource-usage-popover-summary.fixture.tsx b/src/renderer/src/components/status-bar/resources/popover/resource-usage-popover-summary.fixture.tsx similarity index 93% rename from src/renderer/src/components/status-bar/resource-usage-popover-summary.fixture.tsx rename to src/renderer/src/components/status-bar/resources/popover/resource-usage-popover-summary.fixture.tsx index d95808cc75d..7c44324a16e 100644 --- a/src/renderer/src/components/status-bar/resource-usage-popover-summary.fixture.tsx +++ b/src/renderer/src/components/status-bar/resources/popover/resource-usage-popover-summary.fixture.tsx @@ -1,7 +1,7 @@ -import { defineFixture } from '../../component-fixtures/component-fixture' +import { defineFixture } from '../../../../component-fixtures/component-fixture' import { renderResourceUsageSummary } from './resource-usage-popover-summary' -import { ResourceUsageStatusSegment } from './ResourceUsageStatusSegment' -import type { MemorySnapshot } from '../../../../shared/process-stats-types' +import { ResourceUsageStatusSegment } from '../ResourceUsageStatusSegment' +import type { MemorySnapshot } from '../../../../../../shared/process-stats-types' import { getResourceMemoryMetricCopy, getResourceCommitMetricCopy diff --git a/src/renderer/src/components/status-bar/resource-usage-popover-summary.tsx b/src/renderer/src/components/status-bar/resources/popover/resource-usage-popover-summary.tsx similarity index 98% rename from src/renderer/src/components/status-bar/resource-usage-popover-summary.tsx rename to src/renderer/src/components/status-bar/resources/popover/resource-usage-popover-summary.tsx index da4edc8e978..f8fd17ebd77 100644 --- a/src/renderer/src/components/status-bar/resource-usage-popover-summary.tsx +++ b/src/renderer/src/components/status-bar/resources/popover/resource-usage-popover-summary.tsx @@ -5,7 +5,7 @@ import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip import { cn } from '@/lib/class-names' import { translate } from '@/i18n/i18n' import type { Translate } from '@/i18n/use-translate' -import type { DaemonActionsApi } from '../shared/useDaemonActions' +import type { DaemonActionsApi } from '../../../shared/useDaemonActions' import type { getResourceCommitMetricCopy, getResourceMemoryMetricCopy diff --git a/src/renderer/src/components/status-bar/resource-usage-resource-tree.tsx b/src/renderer/src/components/status-bar/resources/popover/resource-usage-resource-tree.tsx similarity index 97% rename from src/renderer/src/components/status-bar/resource-usage-resource-tree.tsx rename to src/renderer/src/components/status-bar/resources/popover/resource-usage-resource-tree.tsx index acbb55c3bac..32bbc962e17 100644 --- a/src/renderer/src/components/status-bar/resource-usage-resource-tree.tsx +++ b/src/renderer/src/components/status-bar/resources/popover/resource-usage-resource-tree.tsx @@ -1,13 +1,13 @@ import React, { useMemo } from 'react' import { ChevronDown, ChevronRight } from 'lucide-react' import { useTranslate } from '@/i18n/use-translate' -import { useWorktreeMap } from '../../store/slices/worktrees/listing/use-worktree-catalog' +import { useWorktreeMap } from '../../../../store/slices/worktrees/listing/use-worktree-catalog' import type { Metric, UnifiedProjectGroup, UnifiedSessionRow, UnifiedWorktreeRow -} from './resource-usage-merge-types' +} from '../workspace-attribution/resource-usage-merge-types' import { MetricPair, ROW_TRAILING_GUTTER_CLS } from './resource-usage-metrics' import { WorktreeRow } from './resource-usage-session-rows' diff --git a/src/renderer/src/components/status-bar/resource-usage-session-rows.tsx b/src/renderer/src/components/status-bar/resources/popover/resource-usage-session-rows.tsx similarity index 94% rename from src/renderer/src/components/status-bar/resource-usage-session-rows.tsx rename to src/renderer/src/components/status-bar/resources/popover/resource-usage-session-rows.tsx index 683f244e9ac..b8964899daf 100644 --- a/src/renderer/src/components/status-bar/resource-usage-session-rows.tsx +++ b/src/renderer/src/components/status-bar/resources/popover/resource-usage-session-rows.tsx @@ -3,13 +3,16 @@ import { ChevronDown, ChevronRight, Globe, Trash2, X } from 'lucide-react' import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip' import { cn } from '@/lib/class-names' import { useTranslate } from '@/i18n/use-translate' -import type { BrowserWorkspace } from '../../../../shared/browser-workspace-types' -import { ORPHAN_WORKTREE_ID } from '../../../../shared/constants' -import type { Worktree } from '../../../../shared/worktree/types' -import { UNATTRIBUTED_REPO_ID } from './mergeSnapshotAndSessions' -import type { UnifiedSessionRow, UnifiedWorktreeRow } from './resource-usage-merge-types' +import type { BrowserWorkspace } from '../../../../../../shared/browser-workspace-types' +import { ORPHAN_WORKTREE_ID } from '../../../../../../shared/constants' +import type { Worktree } from '../../../../../../shared/worktree/types' +import { UNATTRIBUTED_REPO_ID } from '../workspace-attribution/merge-snapshot-and-sessions' +import type { + UnifiedSessionRow, + UnifiedWorktreeRow +} from '../workspace-attribution/resource-usage-merge-types' import { MetricPair, ROW_TRAILING_GUTTER_CLS, Sparkline } from './resource-usage-metrics' -import { isResourceSessionActivationKey } from './resource-session-navigation' +import { isResourceSessionActivationKey } from '../session-actions/resource-session-navigation' export function SessionRow({ session, diff --git a/src/renderer/src/components/status-bar/resource-usage-status-trigger.tsx b/src/renderer/src/components/status-bar/resources/popover/resource-usage-status-trigger.tsx similarity index 97% rename from src/renderer/src/components/status-bar/resource-usage-status-trigger.tsx rename to src/renderer/src/components/status-bar/resources/popover/resource-usage-status-trigger.tsx index bd0f5517352..a47c32a73f2 100644 --- a/src/renderer/src/components/status-bar/resource-usage-status-trigger.tsx +++ b/src/renderer/src/components/status-bar/resources/popover/resource-usage-status-trigger.tsx @@ -5,7 +5,7 @@ import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip import { cn } from '@/lib/class-names' import { translate } from '@/i18n/i18n' import type { Translate } from '@/i18n/use-translate' -import { STATUS_BAR_CONTEXT_MENU_EXEMPT_PROPS } from './status-bar-context-menu-policy' +import { STATUS_BAR_CONTEXT_MENU_EXEMPT_PROPS } from '../../composition/status-bar-context-menu-policy' export function renderResourceUsageStatusTrigger( { diff --git a/src/renderer/src/components/status-bar/ResourcePtyDetails.tsx b/src/renderer/src/components/status-bar/resources/pty/ResourcePtyDetails.tsx similarity index 100% rename from src/renderer/src/components/status-bar/ResourcePtyDetails.tsx rename to src/renderer/src/components/status-bar/resources/pty/ResourcePtyDetails.tsx diff --git a/src/renderer/src/components/status-bar/ResourcePtyList.tsx b/src/renderer/src/components/status-bar/resources/pty/ResourcePtyList.tsx similarity index 100% rename from src/renderer/src/components/status-bar/ResourcePtyList.tsx rename to src/renderer/src/components/status-bar/resources/pty/ResourcePtyList.tsx diff --git a/src/renderer/src/components/status-bar/ResourcePtyPanel.tsx b/src/renderer/src/components/status-bar/resources/pty/ResourcePtyPanel.tsx similarity index 98% rename from src/renderer/src/components/status-bar/ResourcePtyPanel.tsx rename to src/renderer/src/components/status-bar/resources/pty/ResourcePtyPanel.tsx index 35447c9c230..f27b4c68729 100644 --- a/src/renderer/src/components/status-bar/ResourcePtyPanel.tsx +++ b/src/renderer/src/components/status-bar/resources/pty/ResourcePtyPanel.tsx @@ -9,7 +9,7 @@ import { type ResourcePtyRow } from './resource-pty-view-model' import { ResourcePtyList } from './ResourcePtyList' -import type { useResourceSessionInventory } from './use-resource-session-inventory' +import type { useResourceSessionInventory } from '../inventory/use-resource-session-inventory' import { canEndResourcePty, type useResourcePtyActions } from './use-resource-pty-actions' const EMPTY_PTY_ROWS: ReturnType = [] diff --git a/src/renderer/src/components/status-bar/ResourcePtyRow.tsx b/src/renderer/src/components/status-bar/resources/pty/ResourcePtyRow.tsx similarity index 100% rename from src/renderer/src/components/status-bar/ResourcePtyRow.tsx rename to src/renderer/src/components/status-bar/resources/pty/ResourcePtyRow.tsx diff --git a/src/renderer/src/components/status-bar/resource-pty-view-model.ts b/src/renderer/src/components/status-bar/resources/pty/resource-pty-view-model.ts similarity index 90% rename from src/renderer/src/components/status-bar/resource-pty-view-model.ts rename to src/renderer/src/components/status-bar/resources/pty/resource-pty-view-model.ts index edbfee34650..5239532fe84 100644 --- a/src/renderer/src/components/status-bar/resource-pty-view-model.ts +++ b/src/renderer/src/components/status-bar/resources/pty/resource-pty-view-model.ts @@ -1,25 +1,28 @@ import { ptySessionIdentity, type PtyListedSession -} from '../../../../shared/terminal/pty/lifecycle/pty-listed-session' -import type { Worktree } from '../../../../shared/worktree/types' -import type { Repo } from '../../../../shared/repo-types' -import type { ProjectGroup } from '../../../../shared/project-group-types' +} from '../../../../../../shared/terminal/pty/lifecycle/pty-listed-session' +import type { Worktree } from '../../../../../../shared/worktree/types' +import type { Repo } from '../../../../../../shared/repo-types' +import type { ProjectGroup } from '../../../../../../shared/project-group-types' import { getRepoExecutionHostId, getWorktreeExecutionHostId -} from '../../../../shared/execution-host' -import { projectGroupIdFromRepoId } from '../../../../shared/folder-workspaces/folder-workspace-worktree' -import { makePaneKey, isTerminalLeafId } from '../../../../shared/workspace-layout/stable-pane-id' -import { recentStamp } from '../../../../shared/sidebar-list/sorting/stamp-order' +} from '../../../../../../shared/execution-host' +import { projectGroupIdFromRepoId } from '../../../../../../shared/folder-workspaces/folder-workspace-worktree' +import { + makePaneKey, + isTerminalLeafId +} from '../../../../../../shared/workspace-layout/stable-pane-id' +import { recentStamp } from '../../../../../../shared/sidebar-list/sorting/stamp-order' import { buildResourceSessionBindingIndex, type ResourceSessionBindingInputs -} from './resource-session-bindings' +} from '../workspace-attribution/resource-session-bindings' import { deriveWorktreeNameFromWorktreeId, resolveDaemonSessionLabel -} from './resource-session-labels' +} from '../workspace-attribution/resource-session-labels' export type ResourcePtyRow = { session: PtyListedSession diff --git a/src/renderer/src/components/status-bar/use-resource-pty-actions.ts b/src/renderer/src/components/status-bar/resources/pty/use-resource-pty-actions.ts similarity index 97% rename from src/renderer/src/components/status-bar/use-resource-pty-actions.ts rename to src/renderer/src/components/status-bar/resources/pty/use-resource-pty-actions.ts index 9551eb0aba4..8b98f4117e2 100644 --- a/src/renderer/src/components/status-bar/use-resource-pty-actions.ts +++ b/src/renderer/src/components/status-bar/resources/pty/use-resource-pty-actions.ts @@ -1,7 +1,7 @@ import { useCallback, useEffect, useRef, useState } from 'react' -import type { PtyFencedTerminationRequest } from '../../../../shared/terminal/pty/lifecycle/pty-fenced-termination' +import type { PtyFencedTerminationRequest } from '../../../../../../shared/terminal/pty/lifecycle/pty-fenced-termination' import type { ResourcePtyRow } from './resource-pty-view-model' -import type { useResourceSessionInventory } from './use-resource-session-inventory' +import type { useResourceSessionInventory } from '../inventory/use-resource-session-inventory' import { useMountedRef } from '@/hooks/useMountedRef' import { translate } from '@/i18n/i18n' import type { Translate } from '@/i18n/use-translate' diff --git a/src/renderer/src/components/status-bar/resource-usage-open-slices.ts b/src/renderer/src/components/status-bar/resources/resource-usage-open-slices.ts similarity index 89% rename from src/renderer/src/components/status-bar/resource-usage-open-slices.ts rename to src/renderer/src/components/status-bar/resources/resource-usage-open-slices.ts index 46d4e000925..8a373c8b81e 100644 --- a/src/renderer/src/components/status-bar/resource-usage-open-slices.ts +++ b/src/renderer/src/components/status-bar/resources/resource-usage-open-slices.ts @@ -1,7 +1,9 @@ -import { selectWorktreesByRepo } from '../../store/workspaces/catalog/workspace-record-fields' -import type { AppState } from '../../store/types' -import { getIndexedAllWorktrees } from '../../store/slices/worktrees/listing/worktree-catalog-index' -import { selectFolderWorkspaces } from '@/store/workspaces/catalog/workspace-record-fields' +import { + selectWorktreesByRepo, + selectFolderWorkspaces +} from '../../../store/workspaces/catalog/workspace-record-fields' +import type { AppState } from '../../../store/types' +import { getIndexedAllWorktrees } from '../../../store/slices/worktrees/listing/worktree-catalog-index' const EMPTY_TABS_BY_WORKTREE: AppState['tabsByWorktree'] = {} const EMPTY_PTY_IDS_BY_TAB_ID: AppState['ptyIdsByTabId'] = {} diff --git a/src/renderer/src/components/status-bar/resource-usage-space-scan-ready.ts b/src/renderer/src/components/status-bar/resources/resource-usage-space-scan-ready.ts similarity index 100% rename from src/renderer/src/components/status-bar/resource-usage-space-scan-ready.ts rename to src/renderer/src/components/status-bar/resources/resource-usage-space-scan-ready.ts diff --git a/src/renderer/src/components/status-bar/resource-manager-worktree-target.test.ts b/src/renderer/src/components/status-bar/resources/session-actions/resource-manager-worktree-target.test.ts similarity index 87% rename from src/renderer/src/components/status-bar/resource-manager-worktree-target.test.ts rename to src/renderer/src/components/status-bar/resources/session-actions/resource-manager-worktree-target.test.ts index 17fa09a7340..28c51c6fe50 100644 --- a/src/renderer/src/components/status-bar/resource-manager-worktree-target.test.ts +++ b/src/renderer/src/components/status-bar/resources/session-actions/resource-manager-worktree-target.test.ts @@ -1,5 +1,5 @@ import { describe, expect, it } from 'vitest' -import type { ExecutionHostId } from '../../../../shared/execution-host' +import type { ExecutionHostId } from '../../../../../../shared/execution-host' import { resolveResourceManagerWorktreeTarget } from './resource-manager-worktree-target' const LOCAL = 'local' as ExecutionHostId diff --git a/src/renderer/src/components/status-bar/resource-manager-worktree-target.ts b/src/renderer/src/components/status-bar/resources/session-actions/resource-manager-worktree-target.ts similarity index 87% rename from src/renderer/src/components/status-bar/resource-manager-worktree-target.ts rename to src/renderer/src/components/status-bar/resources/session-actions/resource-manager-worktree-target.ts index 57ecb589775..efd7e30ff14 100644 --- a/src/renderer/src/components/status-bar/resource-manager-worktree-target.ts +++ b/src/renderer/src/components/status-bar/resources/session-actions/resource-manager-worktree-target.ts @@ -1,4 +1,4 @@ -import type { Worktree } from '../../../../shared/worktree/types' +import type { Worktree } from '../../../../../../shared/worktree/types' export type ResourceManagerWorktreeTarget = Pick diff --git a/src/renderer/src/components/status-bar/resource-session-kill-confirmation.test.ts b/src/renderer/src/components/status-bar/resources/session-actions/resource-session-kill-confirmation.test.ts similarity index 88% rename from src/renderer/src/components/status-bar/resource-session-kill-confirmation.test.ts rename to src/renderer/src/components/status-bar/resources/session-actions/resource-session-kill-confirmation.test.ts index ac3122c2ca7..46039a72f86 100644 --- a/src/renderer/src/components/status-bar/resource-session-kill-confirmation.test.ts +++ b/src/renderer/src/components/status-bar/resources/session-actions/resource-session-kill-confirmation.test.ts @@ -1,6 +1,6 @@ import { describe, expect, it } from 'vitest' import { requiresKillConfirmation } from './resource-session-kill-confirmation' -import type { UnifiedSessionRow } from './resource-usage-merge-types' +import type { UnifiedSessionRow } from '../workspace-attribution/resource-usage-merge-types' function row(overrides: Partial = {}): UnifiedSessionRow { return { diff --git a/src/renderer/src/components/status-bar/resource-session-kill-confirmation.ts b/src/renderer/src/components/status-bar/resources/session-actions/resource-session-kill-confirmation.ts similarity index 56% rename from src/renderer/src/components/status-bar/resource-session-kill-confirmation.ts rename to src/renderer/src/components/status-bar/resources/session-actions/resource-session-kill-confirmation.ts index 235e6431ea8..204a1af36da 100644 --- a/src/renderer/src/components/status-bar/resource-session-kill-confirmation.ts +++ b/src/renderer/src/components/status-bar/resources/session-actions/resource-session-kill-confirmation.ts @@ -1,5 +1,5 @@ -import { mayDestroyWithoutOwnerEvidence } from '../../../../shared/terminal/pty/lifecycle/pty-listed-session' -import type { UnifiedSessionRow } from './resource-usage-merge-types' +import { mayDestroyWithoutOwnerEvidence } from '../../../../../../shared/terminal/pty/lifecycle/pty-listed-session' +import type { UnifiedSessionRow } from '../workspace-attribution/resource-usage-merge-types' /** Skip confirmation only for unbound sessions with proven agent-owner absence; bound or unverifiable sessions must ask. */ export function requiresKillConfirmation(session: UnifiedSessionRow): boolean { diff --git a/src/renderer/src/components/status-bar/resource-session-navigation.ts b/src/renderer/src/components/status-bar/resources/session-actions/resource-session-navigation.ts similarity index 93% rename from src/renderer/src/components/status-bar/resource-session-navigation.ts rename to src/renderer/src/components/status-bar/resources/session-actions/resource-session-navigation.ts index 93aaf4f4365..50fb89bd07c 100644 --- a/src/renderer/src/components/status-bar/resource-session-navigation.ts +++ b/src/renderer/src/components/status-bar/resources/session-actions/resource-session-navigation.ts @@ -1,4 +1,4 @@ -import { parsePaneKey } from '../../../../shared/workspace-layout/stable-pane-id' +import { parsePaneKey } from '../../../../../../shared/workspace-layout/stable-pane-id' type TabLookup = Record diff --git a/src/renderer/src/components/status-bar/use-resource-usage-actions.ts b/src/renderer/src/components/status-bar/resources/session-actions/use-resource-usage-actions.ts similarity index 90% rename from src/renderer/src/components/status-bar/use-resource-usage-actions.ts rename to src/renderer/src/components/status-bar/resources/session-actions/use-resource-usage-actions.ts index 36d632d77fe..1e11b7249d7 100644 --- a/src/renderer/src/components/status-bar/use-resource-usage-actions.ts +++ b/src/renderer/src/components/status-bar/resources/session-actions/use-resource-usage-actions.ts @@ -1,4 +1,4 @@ -import { selectWorktreesByRepo } from '../../store/workspaces/catalog/workspace-record-fields' +import { selectWorktreesByRepo } from '../../../../store/workspaces/catalog/workspace-record-fields' import { useCallback, useState, @@ -12,20 +12,20 @@ import { } from '@/lib/workspace/activation/worktree-activation' import { activateTabAndFocusPane } from '@/lib/workspace/tabs/activate-tab-and-focus-pane' import { translate } from '@/i18n/i18n' -import { useAppStore } from '../../store' -import type { AppState } from '../../store/types' -import { getIndexedAllWorktrees } from '../../store/slices/worktrees/listing/worktree-catalog-index' -import { runWorktreeDelete } from '../sidebar/workspace-actions/deletion/delete-worktree-flow' -import { ORPHAN_WORKTREE_ID } from '../../../../shared/constants' -import { parseWorkspaceKey } from '../../../../shared/workspace-scope' -import { UNATTRIBUTED_REPO_ID } from './mergeSnapshotAndSessions' -import type { UnifiedSessionRow } from './resource-usage-merge-types' -import type { PtyListedSession as DaemonSession } from '../../../../shared/terminal/pty/lifecycle/pty-listed-session' +import { useAppStore } from '../../../../store/index' +import type { AppState } from '../../../../store/types' +import { getIndexedAllWorktrees } from '../../../../store/slices/worktrees/listing/worktree-catalog-index' +import { runWorktreeDelete } from '../../../sidebar/workspace-actions/deletion/delete-worktree-flow' +import { ORPHAN_WORKTREE_ID } from '../../../../../../shared/constants' +import { parseWorkspaceKey } from '../../../../../../shared/workspace-scope' +import { UNATTRIBUTED_REPO_ID } from '../workspace-attribution/merge-snapshot-and-sessions' +import type { UnifiedSessionRow } from '../workspace-attribution/resource-usage-merge-types' +import type { PtyListedSession as DaemonSession } from '../../../../../../shared/terminal/pty/lifecycle/pty-listed-session' import { type ResourceSessionBindingInputs, selectUnboundDaemonSessions -} from './resource-session-bindings' +} from '../workspace-attribution/resource-session-bindings' import { navigateResourceSessionToTab } from './resource-session-navigation' import { requiresKillConfirmation } from './resource-session-kill-confirmation' import { resolveResourceManagerWorktreeTarget } from './resource-manager-worktree-target' diff --git a/src/renderer/src/components/status-bar/use-resource-memory-snapshot.ts b/src/renderer/src/components/status-bar/resources/use-resource-memory-snapshot.ts similarity index 93% rename from src/renderer/src/components/status-bar/use-resource-memory-snapshot.ts rename to src/renderer/src/components/status-bar/resources/use-resource-memory-snapshot.ts index f0f1d8100eb..0aa4db0eac5 100644 --- a/src/renderer/src/components/status-bar/use-resource-memory-snapshot.ts +++ b/src/renderer/src/components/status-bar/resources/use-resource-memory-snapshot.ts @@ -1,6 +1,6 @@ import { useCallback, useEffect, useRef } from 'react' -import { useAppStore } from '../../store' -import { isResourceViewInactive } from '../../../../shared/resource-view-admission' +import { useAppStore } from '../../../store/index' +import { isResourceViewInactive } from '../../../../../shared/resource-view-admission' export function useResourceMemorySnapshot(active: boolean): () => Promise { const lifetime = useRef<{ diff --git a/src/renderer/src/components/status-bar/use-resource-usage-derived-model.test.tsx b/src/renderer/src/components/status-bar/resources/use-resource-usage-derived-model.test.tsx similarity index 63% rename from src/renderer/src/components/status-bar/use-resource-usage-derived-model.test.tsx rename to src/renderer/src/components/status-bar/resources/use-resource-usage-derived-model.test.tsx index 2aedfe57845..9dcb767f5dc 100644 --- a/src/renderer/src/components/status-bar/use-resource-usage-derived-model.test.tsx +++ b/src/renderer/src/components/status-bar/resources/use-resource-usage-derived-model.test.tsx @@ -1,11 +1,11 @@ // @vitest-environment happy-dom import { cleanup, renderHook } from '@testing-library/react' import { afterEach, describe, expect, it } from 'vitest' -import type { BrowserWorkspace } from '../../../../shared/browser-workspace-types' -import type { MemorySnapshot, WorktreeMemory } from '../../../../shared/process-stats-types' -import type { Worktree } from '../../../../shared/worktree/types' -import type { ProjectGroup } from '../../../../shared/project-group-types' -import type { PtyListedSession as DaemonSession } from '../../../../shared/terminal/pty/lifecycle/pty-listed-session' +import type { BrowserWorkspace } from '../../../../../shared/browser-workspace-types' +import type { MemorySnapshot, WorktreeMemory } from '../../../../../shared/process-stats-types' +import type { Worktree } from '../../../../../shared/worktree/types' +import type { ProjectGroup } from '../../../../../shared/project-group-types' +import type { PtyListedSession as DaemonSession } from '../../../../../shared/terminal/pty/lifecycle/pty-listed-session' import { useResourceUsageDerivedModel } from './use-resource-usage-derived-model' const local = { @@ -69,76 +69,6 @@ function derive( afterEach(cleanup) describe('Resource Manager folder ownership', () => { - it.each(['ssh:box', 'runtime:paired'] as const)( - 'keeps local samples when a sibling folder belongs to %s', - (hostId) => { - const sibling = { ...local, id: 'folder:remote', displayName: 'Remote notes', hostId } - const groups = derive( - [local, sibling], - [ - { - id: 'remote-session', - worktreeId: sibling.id, - cwd: '/notes', - title: 'Shell', - agentOwnership: 'present' - } - ] - ) - - expect(groups).toHaveLength(1) - expect(groups[0]).toMatchObject({ - cpu: 2, - memory: 2048, - hasRemoteChildren: hostId === 'ssh:box' - }) - expect(groups[0].worktrees[0]).toMatchObject({ - worktreeId: local.id, - worktreeName: local.displayName, - isRemote: false, - cpu: 2, - memory: 2048, - sessions: [{ sessionId: 'sampled', memory: 2048 }] - }) - if (hostId === 'ssh:box') { - expect(groups[0].worktrees[1]).toMatchObject({ - worktreeId: sibling.id, - isRemote: true, - cpu: null, - memory: null - }) - } else { - expect(groups[0].worktrees).toHaveLength(1) - } - } - ) - - it.each([false, true])( - 'preserves sampled ownership with duplicate folder ids (reverse=%s)', - (reverse) => { - const remote = { - ...local, - repoId: 'folder-workspace:remote', - displayName: 'Foreign notes', - hostId: 'runtime:paired' - } as Worktree - const groups = derive(reverse ? [remote, local] : [local, remote]) - - expect(groups).toHaveLength(1) - expect(groups[0]).toMatchObject({ - repoId: sampled.repoId, - repoName: sampled.repoName, - memory: 2048 - }) - expect(groups[0].worktrees[0]).toMatchObject({ - worktreeName: sampled.worktreeName, - isRemote: false, - memory: 2048, - history: sampled.history - }) - } - ) - it.each(['repo::/notes', 'folder:shared'])( 'keeps browser-only rows when %s exists on two hosts', (worktreeId) => { diff --git a/src/renderer/src/components/status-bar/use-resource-usage-derived-model.ts b/src/renderer/src/components/status-bar/resources/use-resource-usage-derived-model.ts similarity index 89% rename from src/renderer/src/components/status-bar/use-resource-usage-derived-model.ts rename to src/renderer/src/components/status-bar/resources/use-resource-usage-derived-model.ts index 7975ba6e01d..62e3b5b5b43 100644 --- a/src/renderer/src/components/status-bar/use-resource-usage-derived-model.ts +++ b/src/renderer/src/components/status-bar/resources/use-resource-usage-derived-model.ts @@ -1,31 +1,31 @@ import { useMemo } from 'react' -import type { AppState } from '../../store/types' -import type { MemorySnapshot } from '../../../../shared/process-stats-types' -import type { Worktree } from '../../../../shared/worktree/types' -import { getRepoExecutionHostId, parseExecutionHostId } from '../../../../shared/execution-host' -import { mergeSnapshotAndSessions } from './mergeSnapshotAndSessions' -import type { RuntimeHostResourceSample } from './resource-usage-merge-types' -import type { PtyListedSession as DaemonSession } from '../../../../shared/terminal/pty/lifecycle/pty-listed-session' +import type { AppState } from '../../../store/types' +import type { MemorySnapshot } from '../../../../../shared/process-stats-types' +import type { Worktree } from '../../../../../shared/worktree/types' +import { getRepoExecutionHostId, parseExecutionHostId } from '../../../../../shared/execution-host' +import { mergeSnapshotAndSessions } from './workspace-attribution/merge-snapshot-and-sessions' +import type { RuntimeHostResourceSample } from './workspace-attribution/resource-usage-merge-types' +import type { PtyListedSession as DaemonSession } from '../../../../../shared/terminal/pty/lifecycle/pty-listed-session' import { type ResourceSessionBindingInputs, countUnboundDaemonSessions -} from './resource-session-bindings' +} from './workspace-attribution/resource-session-bindings' import { getResourceManagerAriaLabel, getResourceManagerTooltipLines -} from './resource-manager-terminal-copy' +} from './popover/resource-manager-terminal-copy' import { getCommitPressureToneClass, getResourceCommitMetricCopy, getResourceMemoryMetricCopy -} from './resource-memory-metric-copy' -import { formatMemory } from './resource-usage-metrics' +} from './popover/resource-memory-metric-copy' +import { formatMemory } from './popover/resource-usage-metrics' import { findAmbiguousWorktreeIds, findDuplicateIds -} from '../../lib/workspace/ownership/unified-tab-host-ownership' -import { useTranslate } from '../../i18n/use-translate' +} from '../../../lib/workspace/ownership/unified-tab-host-ownership' +import { useTranslate } from '../../../i18n/use-translate' export function useResourceUsageDerivedModel({ open, diff --git a/src/renderer/src/components/status-bar/use-resource-usage-status-controller.ts b/src/renderer/src/components/status-bar/resources/use-resource-usage-status-controller.ts similarity index 91% rename from src/renderer/src/components/status-bar/use-resource-usage-status-controller.ts rename to src/renderer/src/components/status-bar/resources/use-resource-usage-status-controller.ts index ab213aae71f..07f41af2173 100644 --- a/src/renderer/src/components/status-bar/use-resource-usage-status-controller.ts +++ b/src/renderer/src/components/status-bar/resources/use-resource-usage-status-controller.ts @@ -1,11 +1,11 @@ import { useCallback, useMemo, useRef, useState } from 'react' import { useMountedRef } from '@/hooks/useMountedRef' -import { useAppStore } from '../../store' -import { useDaemonActions } from '../shared/useDaemonActions' -import type { UnifiedSessionRow } from './resource-usage-merge-types' -import type { ResourceSessionBindingInputs } from './resource-session-bindings' -import type { SortOption } from './resource-usage-resource-tree' -import { folderWorkspaceToWorktree } from '../../../../shared/folder-workspaces/folder-workspace-worktree' +import { useAppStore } from '../../../store/index' +import { useDaemonActions } from '../../shared/useDaemonActions' +import type { UnifiedSessionRow } from './workspace-attribution/resource-usage-merge-types' +import type { ResourceSessionBindingInputs } from './workspace-attribution/resource-session-bindings' +import type { SortOption } from './popover/resource-usage-resource-tree' +import { folderWorkspaceToWorktree } from '../../../../../shared/folder-workspaces/folder-workspace-worktree' import { getResourceUsageAllWorktrees, getResourceUsageBrowserTabsByWorktree, @@ -22,19 +22,19 @@ import { resolveResourceUsageSpaceScanReady, type ResourceUsageSpaceScanSnapshot } from './resource-usage-space-scan-ready' -import { useResourceSessionInventory } from './use-resource-session-inventory' -import { useResourceUsageActions } from './use-resource-usage-actions' +import { useResourceSessionInventory } from './inventory/use-resource-session-inventory' +import { useResourceUsageActions } from './session-actions/use-resource-usage-actions' import { useResourceUsageDerivedModel } from './use-resource-usage-derived-model' -import { useRuntimeHostResources } from './use-runtime-host-resources' +import { useRuntimeHostResources } from '../host-connections/use-runtime-host-resources' import { collectRuntimeResourceEnvironmentIds, getRuntimeHostResourceNotices, toRuntimeHostResourceSamples -} from './runtime-host-resources' -import { getRepoExecutionHostId } from '../../../../shared/execution-host' +} from '../host-connections/runtime-host-resources' +import { getRepoExecutionHostId } from '../../../../../shared/execution-host' import { useResourceViewVisible } from './use-resource-view-visible' -import { useResourcePtyActions } from './use-resource-pty-actions' +import { useResourcePtyActions } from './pty/use-resource-pty-actions' import { useResourceMemorySnapshot } from './use-resource-memory-snapshot' import { useTranslate } from '@/i18n/use-translate' diff --git a/src/renderer/src/components/status-bar/use-resource-view-visible.ts b/src/renderer/src/components/status-bar/resources/use-resource-view-visible.ts similarity index 100% rename from src/renderer/src/components/status-bar/use-resource-view-visible.ts rename to src/renderer/src/components/status-bar/resources/use-resource-view-visible.ts diff --git a/src/renderer/src/components/status-bar/mergeSnapshotAndSessions.ts b/src/renderer/src/components/status-bar/resources/workspace-attribution/merge-snapshot-and-sessions.ts similarity index 97% rename from src/renderer/src/components/status-bar/mergeSnapshotAndSessions.ts rename to src/renderer/src/components/status-bar/resources/workspace-attribution/merge-snapshot-and-sessions.ts index c192d4154d7..db4544ca2d1 100644 --- a/src/renderer/src/components/status-bar/mergeSnapshotAndSessions.ts +++ b/src/renderer/src/components/status-bar/resources/workspace-attribution/merge-snapshot-and-sessions.ts @@ -1,15 +1,15 @@ /** Merge local/paired-host samples and daemon sessions by project/workspace; unsampled metrics are null and paired rows are read-only. */ -import type { MemorySnapshot, WorktreeMemory } from '../../../../shared/process-stats-types' -import { parsePtySessionId } from '../../../../shared/terminal/pty/lifecycle/pty-session-id-format' -import { getRepoIdFromWorktreeId } from '../../../../shared/worktree/id' +import type { MemorySnapshot, WorktreeMemory } from '../../../../../../shared/process-stats-types' +import { parsePtySessionId } from '../../../../../../shared/terminal/pty/lifecycle/pty-session-id-format' +import { getRepoIdFromWorktreeId } from '../../../../../../shared/worktree/id' import type { MergeContext, UnifiedProjectGroup, UnifiedSessionRow, UnifiedWorktreeRow } from './resource-usage-merge-types' -import type { PtyListedSession as DaemonSession } from '../../../../shared/terminal/pty/lifecycle/pty-listed-session' +import type { PtyListedSession as DaemonSession } from '../../../../../../shared/terminal/pty/lifecycle/pty-listed-session' import { buildResourceSessionBindingIndex } from './resource-session-bindings' import { resolveResourceFolderWorkspace, diff --git a/src/renderer/src/components/status-bar/resource-session-bindings.test.ts b/src/renderer/src/components/status-bar/resources/workspace-attribution/resource-session-bindings.test.ts similarity index 92% rename from src/renderer/src/components/status-bar/resource-session-bindings.test.ts rename to src/renderer/src/components/status-bar/resources/workspace-attribution/resource-session-bindings.test.ts index 8a23bab376e..423d0e0245e 100644 --- a/src/renderer/src/components/status-bar/resource-session-bindings.test.ts +++ b/src/renderer/src/components/status-bar/resources/workspace-attribution/resource-session-bindings.test.ts @@ -1,5 +1,5 @@ import { describe, expect, it } from 'vitest' -import type { TerminalTab } from '../../../../shared/workspace-layout/terminal-tab-types' +import type { TerminalTab } from '../../../../../../shared/workspace-layout/terminal-tab-types' import { buildResourceSessionBindingIndex, selectUnboundDaemonSessions diff --git a/src/renderer/src/components/status-bar/resource-session-bindings.ts b/src/renderer/src/components/status-bar/resources/workspace-attribution/resource-session-bindings.ts similarity index 96% rename from src/renderer/src/components/status-bar/resource-session-bindings.ts rename to src/renderer/src/components/status-bar/resources/workspace-attribution/resource-session-bindings.ts index 5f65d3b9af4..035f7b6fbe7 100644 --- a/src/renderer/src/components/status-bar/resource-session-bindings.ts +++ b/src/renderer/src/components/status-bar/resources/workspace-attribution/resource-session-bindings.ts @@ -1,11 +1,11 @@ import type { TerminalLayoutSnapshot, TerminalTab -} from '../../../../shared/workspace-layout/terminal-tab-types' +} from '../../../../../../shared/workspace-layout/terminal-tab-types' import { mayDestroyWithoutOwnerEvidence, type PtyListedSession as DaemonSession -} from '../../../../shared/terminal/pty/lifecycle/pty-listed-session' +} from '../../../../../../shared/terminal/pty/lifecycle/pty-listed-session' export type ResourceSessionBindingInputs = { tabsByWorktree: Record diff --git a/src/renderer/src/components/status-bar/resource-session-labels.ts b/src/renderer/src/components/status-bar/resources/workspace-attribution/resource-session-labels.ts similarity index 92% rename from src/renderer/src/components/status-bar/resource-session-labels.ts rename to src/renderer/src/components/status-bar/resources/workspace-attribution/resource-session-labels.ts index 6d0678f70f6..657c59f0667 100644 --- a/src/renderer/src/components/status-bar/resource-session-labels.ts +++ b/src/renderer/src/components/status-bar/resources/workspace-attribution/resource-session-labels.ts @@ -1,9 +1,9 @@ -import type { SessionMemory } from '../../../../shared/process-stats-types' -import { parsePaneKey as parseStablePaneKey } from '../../../../shared/workspace-layout/stable-pane-id' -import { getWorktreePathBasenameFromId } from '../../../../shared/worktree/id' +import type { SessionMemory } from '../../../../../../shared/process-stats-types' +import { parsePaneKey as parseStablePaneKey } from '../../../../../../shared/workspace-layout/stable-pane-id' +import { getWorktreePathBasenameFromId } from '../../../../../../shared/worktree/id' import { translate } from '@/i18n/i18n' import type { MergeContext } from './resource-usage-merge-types' -import type { PtyListedSession as DaemonSession } from '../../../../shared/terminal/pty/lifecycle/pty-listed-session' +import type { PtyListedSession as DaemonSession } from '../../../../../../shared/terminal/pty/lifecycle/pty-listed-session' import type { ResourceSessionBindingIndex } from './resource-session-bindings' export function deriveWorktreeNameFromWorktreeId(worktreeId: string): string { diff --git a/src/renderer/src/components/status-bar/resource-usage-folder-merge.test.ts b/src/renderer/src/components/status-bar/resources/workspace-attribution/resource-usage-folder-merge.test.ts similarity index 90% rename from src/renderer/src/components/status-bar/resource-usage-folder-merge.test.ts rename to src/renderer/src/components/status-bar/resources/workspace-attribution/resource-usage-folder-merge.test.ts index 9d05e9e705a..b693ef3694c 100644 --- a/src/renderer/src/components/status-bar/resource-usage-folder-merge.test.ts +++ b/src/renderer/src/components/status-bar/resources/workspace-attribution/resource-usage-folder-merge.test.ts @@ -1,8 +1,8 @@ import { describe, expect, it } from 'vitest' -import type { MemorySnapshot, WorktreeMemory } from '../../../../shared/process-stats-types' -import type { Worktree } from '../../../../shared/worktree/types' +import type { MemorySnapshot, WorktreeMemory } from '../../../../../../shared/process-stats-types' +import type { Worktree } from '../../../../../../shared/worktree/types' import type { MergeContext } from './resource-usage-merge-types' -import { mergeSnapshotAndSessions } from './mergeSnapshotAndSessions' +import { mergeSnapshotAndSessions } from './merge-snapshot-and-sessions' const workspace = { id: 'folder:notes', diff --git a/src/renderer/src/components/status-bar/resource-usage-merge-types.ts b/src/renderer/src/components/status-bar/resources/workspace-attribution/resource-usage-merge-types.ts similarity index 88% rename from src/renderer/src/components/status-bar/resource-usage-merge-types.ts rename to src/renderer/src/components/status-bar/resources/workspace-attribution/resource-usage-merge-types.ts index 698c9636288..2e4a02c614d 100644 --- a/src/renderer/src/components/status-bar/resource-usage-merge-types.ts +++ b/src/renderer/src/components/status-bar/resources/workspace-attribution/resource-usage-merge-types.ts @@ -1,11 +1,11 @@ -import type { BrowserWorkspace } from '../../../../shared/browser-workspace-types' -import type { WorktreeMemory } from '../../../../shared/process-stats-types' +import type { BrowserWorkspace } from '../../../../../../shared/browser-workspace-types' +import type { WorktreeMemory } from '../../../../../../shared/process-stats-types' import type { TerminalLayoutSnapshot, TerminalTab -} from '../../../../shared/workspace-layout/terminal-tab-types' -import type { Worktree } from '../../../../shared/worktree/types' -import type { AgentOwnershipEvidence } from '../../../../shared/terminal/pty/lifecycle/pty-listed-session' +} from '../../../../../../shared/workspace-layout/terminal-tab-types' +import type { Worktree } from '../../../../../../shared/worktree/types' +import type { AgentOwnershipEvidence } from '../../../../../../shared/terminal/pty/lifecycle/pty-listed-session' /** Null means no process sample, commonly for SSH PTYs; render an em dash. */ export type Metric = number | null diff --git a/src/renderer/src/components/status-bar/resource-workspace-host.ts b/src/renderer/src/components/status-bar/resources/workspace-attribution/resource-workspace-host.ts similarity index 83% rename from src/renderer/src/components/status-bar/resource-workspace-host.ts rename to src/renderer/src/components/status-bar/resources/workspace-attribution/resource-workspace-host.ts index 66aeb101955..dcfa4249f7d 100644 --- a/src/renderer/src/components/status-bar/resource-workspace-host.ts +++ b/src/renderer/src/components/status-bar/resources/workspace-attribution/resource-workspace-host.ts @@ -1,6 +1,6 @@ -import { parseExecutionHostId } from '../../../../shared/execution-host' -import { parseWorkspaceKey } from '../../../../shared/workspace-scope' -import type { Worktree } from '../../../../shared/worktree/types' +import { parseExecutionHostId } from '../../../../../../shared/execution-host' +import { parseWorkspaceKey } from '../../../../../../shared/workspace-scope' +import type { Worktree } from '../../../../../../shared/worktree/types' import type { MergeContext } from './resource-usage-merge-types' /** Folder catalog row for host/name attribution; a duplicated id cannot choose a host, so it yields nothing. */ diff --git a/src/renderer/src/components/status-bar/RemoteServerUpdateStatusSegment.tsx b/src/renderer/src/components/status-bar/updates/RemoteServerUpdateStatusSegment.tsx similarity index 98% rename from src/renderer/src/components/status-bar/RemoteServerUpdateStatusSegment.tsx rename to src/renderer/src/components/status-bar/updates/RemoteServerUpdateStatusSegment.tsx index fdd4e1b2c3d..9c87a6fdf94 100644 --- a/src/renderer/src/components/status-bar/RemoteServerUpdateStatusSegment.tsx +++ b/src/renderer/src/components/status-bar/updates/RemoteServerUpdateStatusSegment.tsx @@ -1,7 +1,7 @@ import type React from 'react' import { AlertCircle, CheckCircle2, RefreshCw } from 'lucide-react' import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip' -import { useAppStore } from '@/store' +import { useAppStore } from '@/store/index' import { useTranslate } from '@/i18n/use-translate' export function RemoteServerUpdateStatusSegment({ diff --git a/src/renderer/src/components/status-bar/SkillUpdateStatusSegment.tsx b/src/renderer/src/components/status-bar/updates/SkillUpdateStatusSegment.tsx similarity index 92% rename from src/renderer/src/components/status-bar/SkillUpdateStatusSegment.tsx rename to src/renderer/src/components/status-bar/updates/SkillUpdateStatusSegment.tsx index 2e7f41a0ca1..b496f8dd905 100644 --- a/src/renderer/src/components/status-bar/SkillUpdateStatusSegment.tsx +++ b/src/renderer/src/components/status-bar/updates/SkillUpdateStatusSegment.tsx @@ -1,9 +1,9 @@ import { AlertCircle, CheckCircle2, Loader2 } from 'lucide-react' import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip' import { useTranslate } from '@/i18n/use-translate' -import { requestSkillFreshnessUpdateDialog } from '../skills/freshness/skill-freshness-update-dialog' -import { useLatestSkillUpdateRun } from '../skills/freshness/skill-update-run-store' -import { updatedSkillsLabel } from '../skills/freshness/skill-plan-op-copy' +import { requestSkillFreshnessUpdateDialog } from '../../skills/freshness/skill-freshness-update-dialog' +import { useLatestSkillUpdateRun } from '../../skills/freshness/skill-update-run-store' +import { updatedSkillsLabel } from '../../skills/freshness/skill-plan-op-copy' // Keep reporting after the update dialog closes; statusBarItems must not hide the remaining progress surface. export function SkillUpdateStatusSegment({ diff --git a/src/renderer/src/components/status-bar/UpdateStatusSegment.test.tsx b/src/renderer/src/components/status-bar/updates/UpdateStatusSegment.test.tsx similarity index 94% rename from src/renderer/src/components/status-bar/UpdateStatusSegment.test.tsx rename to src/renderer/src/components/status-bar/updates/UpdateStatusSegment.test.tsx index 3b4fd832f0f..6bf26b862b9 100644 --- a/src/renderer/src/components/status-bar/UpdateStatusSegment.test.tsx +++ b/src/renderer/src/components/status-bar/updates/UpdateStatusSegment.test.tsx @@ -1,10 +1,10 @@ // @vitest-environment happy-dom import { act, cleanup, fireEvent, render, screen } from '@testing-library/react' import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' -import type { UpdateStatus } from '../../../../shared/update-status-types' -import { useAppStore } from '../../store' -import { UpdateCard } from '../UpdateCard' -import { TooltipProvider } from '../ui/tooltip' +import type { UpdateStatus } from '../../../../../shared/update-status-types' +import { useAppStore } from '../../../store/index' +import { UpdateCard } from '../../UpdateCard' +import { TooltipProvider } from '../../ui/tooltip' import { UpdateStatusSegment } from './UpdateStatusSegment' const check = vi.fn() diff --git a/src/renderer/src/components/status-bar/UpdateStatusSegment.tsx b/src/renderer/src/components/status-bar/updates/UpdateStatusSegment.tsx similarity index 96% rename from src/renderer/src/components/status-bar/UpdateStatusSegment.tsx rename to src/renderer/src/components/status-bar/updates/UpdateStatusSegment.tsx index 1383f1f665d..fe15d1c4fd9 100644 --- a/src/renderer/src/components/status-bar/UpdateStatusSegment.tsx +++ b/src/renderer/src/components/status-bar/updates/UpdateStatusSegment.tsx @@ -1,9 +1,9 @@ import React from 'react' import { AlertCircle, CheckCircle2, Clock3, Download, Loader2 } from 'lucide-react' import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip' -import { useAppStore } from '../../store' +import { useAppStore } from '../../../store/index' import { useTranslate } from '@/i18n/use-translate' -import { getUpdateInstallBlockGuidance } from '../maintenance/update-card/update-install-block-guidance' +import { getUpdateInstallBlockGuidance } from '../../maintenance/update-card/update-install-block-guidance' // Always expose the collapsed update card so pending downloads and installs remain reachable. export function UpdateStatusSegment({ diff --git a/src/renderer/src/components/status-bar/AntigravityUsageMenu.fixture.tsx b/src/renderer/src/components/status-bar/usage/AntigravityUsageMenu.fixture.tsx similarity index 94% rename from src/renderer/src/components/status-bar/AntigravityUsageMenu.fixture.tsx rename to src/renderer/src/components/status-bar/usage/AntigravityUsageMenu.fixture.tsx index 6ab207501ff..5a28c45ccd1 100644 --- a/src/renderer/src/components/status-bar/AntigravityUsageMenu.fixture.tsx +++ b/src/renderer/src/components/status-bar/usage/AntigravityUsageMenu.fixture.tsx @@ -1,8 +1,8 @@ -import { defineFixture } from '../../component-fixtures/component-fixture' +import { defineFixture } from '../../../component-fixtures/component-fixture' import type { AntigravityAccountUsage, ProviderRateLimits -} from '../../../../shared/rate-limit-types' +} from '../../../../../shared/rate-limit-types' import { DropdownMenu, DropdownMenuContent, diff --git a/src/renderer/src/components/status-bar/AntigravityUsageMenu.tsx b/src/renderer/src/components/status-bar/usage/AntigravityUsageMenu.tsx similarity index 92% rename from src/renderer/src/components/status-bar/AntigravityUsageMenu.tsx rename to src/renderer/src/components/status-bar/usage/AntigravityUsageMenu.tsx index 21efc7ec13b..453a1104ffa 100644 --- a/src/renderer/src/components/status-bar/AntigravityUsageMenu.tsx +++ b/src/renderer/src/components/status-bar/usage/AntigravityUsageMenu.tsx @@ -4,12 +4,12 @@ import { useTranslate } from '@/i18n/use-translate' import type { AntigravityAccountUsage, ProviderRateLimits -} from '../../../../shared/rate-limit-types' -import { AccountSwitchList } from './AccountSwitchList' -import { AccountSwitchRowItem } from './AccountSwitchRowItem' +} from '../../../../../shared/rate-limit-types' +import { AccountSwitchList } from '../accounts/AccountSwitchList' +import { AccountSwitchRowItem } from '../accounts/AccountSwitchRowItem' import { InlineUsageBars } from './InlineProviderUsage' import { ProviderDetailsMenu } from './ProviderDetailsMenu' -import { formatTimeAgo } from './tooltip' +import { formatTimeAgo } from './provider-usage-panel' /** Antigravity details plus each saved account's last verified reading; agy is never switched to read one. */ export function AntigravityUsageMenu({ diff --git a/src/renderer/src/components/status-bar/InlineProviderUsage.tsx b/src/renderer/src/components/status-bar/usage/InlineProviderUsage.tsx similarity index 93% rename from src/renderer/src/components/status-bar/InlineProviderUsage.tsx rename to src/renderer/src/components/status-bar/usage/InlineProviderUsage.tsx index 65d865d91c3..7b933679b36 100644 --- a/src/renderer/src/components/status-bar/InlineProviderUsage.tsx +++ b/src/renderer/src/components/status-bar/usage/InlineProviderUsage.tsx @@ -2,16 +2,18 @@ import { Loader2 } from 'lucide-react' import React from 'react' import { Button } from '@/components/ui/button' import { DropdownMenuItem } from '@/components/ui/dropdown-menu' -import { useAppStore } from '../../store' -import type { ProviderRateLimits } from '../../../../shared/rate-limit-types' +import { useAppStore } from '../../../store/index' +import type { ProviderRateLimits } from '../../../../../shared/rate-limit-types' import { getDisplayedUsagePercentage, - normalizeUsagePercentageDisplay -} from '../../../../shared/usage-percentage-display' + normalizeUsagePercentageDisplay, + clampUsedPercent +} from '../../../../../shared/usage-percentage-display' import { useResetCountdownClock } from '@/hooks/useResetCountdownClock' -import { barColor, clampUsedPercent } from './tooltip' -import { formatWindowLabel } from '../../../../shared/rate-limit-window-label' -import { formatResetDuration } from '../../../../shared/rate-limit-reset-format' +import { barColor } from './provider-extra-usage-section' + +import { formatWindowLabel } from '../../../../../shared/rate-limit-window-label' +import { formatResetDuration } from '../../../../../shared/rate-limit-reset-format' import { formatBareUsagePercentage, formatUsagePercentageLabel } from './usage-percentage-label' import { getUsageRosterRowState } from './usage-roster-row-state' import { useIntlLocale, useTranslate } from '@/i18n/use-translate' diff --git a/src/renderer/src/components/status-bar/ProviderDetailsMenu.tsx b/src/renderer/src/components/status-bar/usage/ProviderDetailsMenu.tsx similarity index 91% rename from src/renderer/src/components/status-bar/ProviderDetailsMenu.tsx rename to src/renderer/src/components/status-bar/usage/ProviderDetailsMenu.tsx index 084b3a1c384..39a4a92a35e 100644 --- a/src/renderer/src/components/status-bar/ProviderDetailsMenu.tsx +++ b/src/renderer/src/components/status-bar/usage/ProviderDetailsMenu.tsx @@ -8,13 +8,13 @@ import { DropdownMenuSubTrigger, DropdownMenuTrigger } from '@/components/ui/dropdown-menu' -import { useAppStore } from '../../store' -import type { ProviderRateLimits } from '../../../../shared/rate-limit-types' -import { normalizeUsagePercentageDisplay } from '../../../../shared/usage-percentage-display' -import { ProviderPanel } from './tooltip' -import { ProviderIdentityCard } from './ProviderIdentityCard' +import { useAppStore } from '../../../store/index' +import type { ProviderRateLimits } from '../../../../../shared/rate-limit-types' +import { normalizeUsagePercentageDisplay } from '../../../../../shared/usage-percentage-display' +import { ProviderPanel } from './provider-usage-panel' +import { ProviderIdentityCard } from '../accounts/ProviderIdentityCard' import { ProviderLetterBadge, ProviderSegment } from './StatusBarProviderSegment' -import { STATUS_BAR_CONTEXT_MENU_EXEMPT_PROPS } from './status-bar-context-menu-policy' +import { STATUS_BAR_CONTEXT_MENU_EXEMPT_PROPS } from '../composition/status-bar-context-menu-policy' export function ProviderDetailsMenu({ provider, diff --git a/src/renderer/src/components/status-bar/StatusBarProviderSegment.tsx b/src/renderer/src/components/status-bar/usage/StatusBarProviderSegment.tsx similarity index 92% rename from src/renderer/src/components/status-bar/StatusBarProviderSegment.tsx rename to src/renderer/src/components/status-bar/usage/StatusBarProviderSegment.tsx index 916fb463058..a992ade2682 100644 --- a/src/renderer/src/components/status-bar/StatusBarProviderSegment.tsx +++ b/src/renderer/src/components/status-bar/usage/StatusBarProviderSegment.tsx @@ -1,5 +1,5 @@ -import { useAppStore } from '@/store' -import { resolveStatusBarUsageTemplate } from '../../../../shared/status-bar-usage-format' +import { useAppStore } from '@/store/index' +import { resolveStatusBarUsageTemplate } from '../../../../../shared/status-bar-usage-format' import { buildUsageFormatValues, renderUsageFormatTemplate } from './usage-format-template' import { AlertTriangle } from 'lucide-react' import React from 'react' @@ -7,30 +7,31 @@ import type { OwnerNotSetUpPlaceholder, ProviderRateLimits, RateLimitWindow -} from '../../../../shared/rate-limit-types' +} from '../../../../../shared/rate-limit-types' import { getDisplayedUsagePercentage, - type UsagePercentageDisplay -} from '../../../../shared/usage-percentage-display' -import type { StatusBarUsageMode } from '../../../../shared/status-bar-usage-mode' -import { formatCurrencyAmount } from '../../../../shared/currency-format' -import { formatCreditCount } from '../../../../shared/credit-count-format' + type UsagePercentageDisplay, + clampUsedPercent +} from '../../../../../shared/usage-percentage-display' +import type { StatusBarUsageMode } from '../../../../../shared/status-bar-usage-mode' +import { formatCurrencyAmount } from '../../../../../shared/currency-format' +import { formatCreditCount } from '../../../../../shared/credit-count-format' +import { ProviderIcon } from './provider-usage-panel' +import { USAGE_URGENT_PERCENT, USAGE_WARNING_PERCENT } from './provider-extra-usage-section' + import { - ProviderIcon, - USAGE_URGENT_PERCENT, - USAGE_WARNING_PERCENT, - clampUsedPercent, getProviderUsageErrorMessage, - getProviderUsageStatusLabel -} from './tooltip' -import { getProviderDisplayName } from '../../../../shared/usage-provider-windows' + getProviderUsageStatusLabel, + isClaudeUsageWaitingForClaude +} from './usage-error-copy' +import { getProviderDisplayName } from '../../../../../shared/usage-provider-windows' import { getOwnerNotSetUpLabelParts } from './owner-not-set-up-copy' -import { isClaudeUsageWaitingForClaude } from './usage-error-copy' + import { getTightestUsageSection, getUsageHeadlineSection } from './UsageRosterPanel' import { formatBareUsagePercentage, formatUsagePercentageLabel } from './usage-percentage-label' import { translate } from '@/i18n/i18n' import { useTranslate, useIntlLocale, type Translate } from '@/i18n/use-translate' -import { getStatusBarUsageSections } from './status-bar-usage-sections' +import { getStatusBarUsageSections } from '../composition/status-bar-usage-sections' import { GroupedPoolUsage } from './usage-grouped-pools' import { formatStatusBarSectionLabel, isGroupedUsagePool } from './usage-pool-label' import { useResetCountdownClock } from '@/hooks/useResetCountdownClock' diff --git a/src/renderer/src/components/status-bar/StatusBarUsageChangeNoticeCard.tsx b/src/renderer/src/components/status-bar/usage/StatusBarUsageChangeNoticeCard.tsx similarity index 100% rename from src/renderer/src/components/status-bar/StatusBarUsageChangeNoticeCard.tsx rename to src/renderer/src/components/status-bar/usage/StatusBarUsageChangeNoticeCard.tsx diff --git a/src/renderer/src/components/status-bar/StatusBarUsageChangeNotices.tsx b/src/renderer/src/components/status-bar/usage/StatusBarUsageChangeNotices.tsx similarity index 97% rename from src/renderer/src/components/status-bar/StatusBarUsageChangeNotices.tsx rename to src/renderer/src/components/status-bar/usage/StatusBarUsageChangeNotices.tsx index 48c50349639..386580a16f6 100644 --- a/src/renderer/src/components/status-bar/StatusBarUsageChangeNotices.tsx +++ b/src/renderer/src/components/status-bar/usage/StatusBarUsageChangeNotices.tsx @@ -3,7 +3,7 @@ import { Trans } from 'react-i18next' import { i18n } from '@/i18n/i18n' import { useTranslate } from '@/i18n/use-translate' import { Badge } from '@/components/ui/badge' -import { useAppStore } from '@/store' +import { useAppStore } from '@/store/index' import { StatusBarUsageChangeNoticeCard } from './StatusBarUsageChangeNoticeCard' import { useUsagePercentageDisplayChangeNotice } from './UsagePercentageDisplayChangeNotice' diff --git a/src/renderer/src/components/status-bar/StatusBarUsageEmptyCta.tsx b/src/renderer/src/components/status-bar/usage/StatusBarUsageEmptyCta.tsx similarity index 98% rename from src/renderer/src/components/status-bar/StatusBarUsageEmptyCta.tsx rename to src/renderer/src/components/status-bar/usage/StatusBarUsageEmptyCta.tsx index 782fea7c99e..0f4358addcb 100644 --- a/src/renderer/src/components/status-bar/StatusBarUsageEmptyCta.tsx +++ b/src/renderer/src/components/status-bar/usage/StatusBarUsageEmptyCta.tsx @@ -4,8 +4,8 @@ import { Button } from '@/components/ui/button' import { EyeOffDismissButton } from '@/components/dismiss/EyeOffDismissButton' import { HoverCard, HoverCardContent, HoverCardTrigger } from '@/components/ui/hover-card' import { AgentIcon } from '@/components/agent/icons/AgentIcon' -import { useAppStore } from '../../store' -import { ClaudeIcon, GeminiIcon, OpenAIIcon, OpenCodeGoIcon } from './icons' +import { useAppStore } from '../../../store/index' +import { ClaudeIcon, GeminiIcon, OpenAIIcon, OpenCodeGoIcon } from '../accounts/provider-icons' import { useTranslate } from '@/i18n/use-translate' import { getUsageOwnerHostScope, type RemoteUsageOwner } from './use-owner-usage-rate-limits' diff --git a/src/renderer/src/components/status-bar/UsagePercentageDisplayChangeNotice.tsx b/src/renderer/src/components/status-bar/usage/UsagePercentageDisplayChangeNotice.tsx similarity index 91% rename from src/renderer/src/components/status-bar/UsagePercentageDisplayChangeNotice.tsx rename to src/renderer/src/components/status-bar/usage/UsagePercentageDisplayChangeNotice.tsx index d972f805ec1..03808129f98 100644 --- a/src/renderer/src/components/status-bar/UsagePercentageDisplayChangeNotice.tsx +++ b/src/renderer/src/components/status-bar/usage/UsagePercentageDisplayChangeNotice.tsx @@ -1,8 +1,8 @@ import type { ComponentProps, ReactNode } from 'react' import { useTranslate } from '@/i18n/use-translate' -import { useAppStore } from '@/store' -import { shouldShowUsagePercentageDisplayChangeNotice } from '../../../../shared/usage-percentage-display-change-notice' -import { USAGE_PERCENTAGE_DISPLAY_SETTING_ID } from '../settings/appearance/appearance-usage-percentage-search' +import { useAppStore } from '@/store/index' +import { shouldShowUsagePercentageDisplayChangeNotice } from '../../../../../shared/usage-percentage-display-change-notice' +import { USAGE_PERCENTAGE_DISPLAY_SETTING_ID } from '../../settings/appearance/appearance-usage-percentage-search' import { StatusBarUsageChangeNoticeCard } from './StatusBarUsageChangeNoticeCard' function openUsagePercentageSettings(): void { diff --git a/src/renderer/src/components/status-bar/UsageRosterPanel.tsx b/src/renderer/src/components/status-bar/usage/UsageRosterPanel.tsx similarity index 95% rename from src/renderer/src/components/status-bar/UsageRosterPanel.tsx rename to src/renderer/src/components/status-bar/usage/UsageRosterPanel.tsx index 8e64cc95d1e..e9240894e3b 100644 --- a/src/renderer/src/components/status-bar/UsageRosterPanel.tsx +++ b/src/renderer/src/components/status-bar/usage/UsageRosterPanel.tsx @@ -8,18 +8,20 @@ import { formatRateLimitWindowChipLabel, formatWindowLabel } from './rate-limit-window-localized-label' -import { CURSOR_MODELS_BUCKET_NAME } from '../../../../shared/cursor-usage-buckets' -import type { ProviderRateLimits, RateLimitWindow } from '../../../../shared/rate-limit-types' +import { CURSOR_MODELS_BUCKET_NAME } from '../../../../../shared/cursor-usage-buckets' +import type { ProviderRateLimits, RateLimitWindow } from '../../../../../shared/rate-limit-types' import { clampUsedPercent, getDisplayedUsagePercentage, type UsagePercentageDisplay -} from '../../../../shared/usage-percentage-display' -import { barColor, formatResetCountdown, getWindowSections, ProviderIcon } from './tooltip' -import { getProviderDisplayName } from '../../../../shared/usage-provider-windows' +} from '../../../../../shared/usage-percentage-display' +import { getWindowSections, ProviderIcon } from './provider-usage-panel' +import { barColor } from './provider-extra-usage-section' +import { formatResetCountdown } from '../../../../../shared/rate-limit-reset-format' +import { getProviderDisplayName } from '../../../../../shared/usage-provider-windows' import { formatPlanLabel, usageTextColorClass } from './usage-roster-formatting' import { getUsageRosterRowState, type UsageRosterRowState } from './usage-roster-row-state' -import type { StatusBarUsageMode } from '../../../../shared/status-bar-usage-mode' +import type { StatusBarUsageMode } from '../../../../../shared/status-bar-usage-mode' type ProviderId = ProviderRateLimits['provider'] export type UsageSection = { label: string; window: RateLimitWindow } diff --git a/src/renderer/src/components/status-bar/usage-errors/rate-limit-user-facing-error-catalog-a.ts b/src/renderer/src/components/status-bar/usage/errors/rate-limit-user-facing-error-catalog-a.ts similarity index 100% rename from src/renderer/src/components/status-bar/usage-errors/rate-limit-user-facing-error-catalog-a.ts rename to src/renderer/src/components/status-bar/usage/errors/rate-limit-user-facing-error-catalog-a.ts diff --git a/src/renderer/src/components/status-bar/usage-errors/rate-limit-user-facing-error-catalog-b.ts b/src/renderer/src/components/status-bar/usage/errors/rate-limit-user-facing-error-catalog-b.ts similarity index 100% rename from src/renderer/src/components/status-bar/usage-errors/rate-limit-user-facing-error-catalog-b.ts rename to src/renderer/src/components/status-bar/usage/errors/rate-limit-user-facing-error-catalog-b.ts diff --git a/src/renderer/src/components/status-bar/usage-errors/rate-limit-user-facing-error-catalog.ts b/src/renderer/src/components/status-bar/usage/errors/rate-limit-user-facing-error-catalog.ts similarity index 100% rename from src/renderer/src/components/status-bar/usage-errors/rate-limit-user-facing-error-catalog.ts rename to src/renderer/src/components/status-bar/usage/errors/rate-limit-user-facing-error-catalog.ts diff --git a/src/renderer/src/components/status-bar/usage-errors/rate-limit-user-facing-error-types.ts b/src/renderer/src/components/status-bar/usage/errors/rate-limit-user-facing-error-types.ts similarity index 100% rename from src/renderer/src/components/status-bar/usage-errors/rate-limit-user-facing-error-types.ts rename to src/renderer/src/components/status-bar/usage/errors/rate-limit-user-facing-error-types.ts diff --git a/src/renderer/src/components/status-bar/usage-errors/rate-limit-user-facing-error.ts b/src/renderer/src/components/status-bar/usage/errors/rate-limit-user-facing-error.ts similarity index 100% rename from src/renderer/src/components/status-bar/usage-errors/rate-limit-user-facing-error.ts rename to src/renderer/src/components/status-bar/usage/errors/rate-limit-user-facing-error.ts diff --git a/src/renderer/src/components/status-bar/owner-not-set-up-copy.ts b/src/renderer/src/components/status-bar/usage/owner-not-set-up-copy.ts similarity index 96% rename from src/renderer/src/components/status-bar/owner-not-set-up-copy.ts rename to src/renderer/src/components/status-bar/usage/owner-not-set-up-copy.ts index 33de581403a..8133da0605a 100644 --- a/src/renderer/src/components/status-bar/owner-not-set-up-copy.ts +++ b/src/renderer/src/components/status-bar/usage/owner-not-set-up-copy.ts @@ -1,4 +1,4 @@ -import type { OwnerNotSetUpPlaceholder } from '../../../../shared/rate-limit-types' +import type { OwnerNotSetUpPlaceholder } from '../../../../../shared/rate-limit-types' import { translate } from '@/i18n/i18n' import type { Translate } from '@/i18n/use-translate' diff --git a/src/renderer/src/components/status-bar/owner-usage-rate-limits.ts b/src/renderer/src/components/status-bar/usage/owner-usage-rate-limits.ts similarity index 97% rename from src/renderer/src/components/status-bar/owner-usage-rate-limits.ts rename to src/renderer/src/components/status-bar/usage/owner-usage-rate-limits.ts index e51f6e92eee..6ef40351537 100644 --- a/src/renderer/src/components/status-bar/owner-usage-rate-limits.ts +++ b/src/renderer/src/components/status-bar/usage/owner-usage-rate-limits.ts @@ -4,16 +4,16 @@ import type { RateLimitState, UsageRateLimitFailureKind, UsageRateLimitMetadata -} from '../../../../shared/rate-limit-types' -import { createEmptyRateLimitState } from '../../../../shared/rate-limit-state-factory' +} from '../../../../../shared/rate-limit-types' +import { createEmptyRateLimitState } from '../../../../../shared/rate-limit-state-factory' import { translate } from '@/i18n/i18n' import type { Translate } from '@/i18n/use-translate' import { createPendingProviderSnapshot, hasUsageProviderSettingsForProvider, isProviderConfigured -} from './status-bar-provider-visibility' -import { hasUsageData } from '../../../../shared/usage-provider-windows' +} from '../composition/status-bar-provider-visibility' +import { hasUsageData } from '../../../../../shared/usage-provider-windows' import { describeOwnerNotSetUp } from './owner-not-set-up-copy' /** Whose usage the status bar shows: this device, or the remote host that owns the accounts. */ diff --git a/src/renderer/src/components/status-bar/provider-extra-usage-section.tsx b/src/renderer/src/components/status-bar/usage/provider-extra-usage-section.tsx similarity index 93% rename from src/renderer/src/components/status-bar/provider-extra-usage-section.tsx rename to src/renderer/src/components/status-bar/usage/provider-extra-usage-section.tsx index 724f5f22672..ec1ef85a29b 100644 --- a/src/renderer/src/components/status-bar/provider-extra-usage-section.tsx +++ b/src/renderer/src/components/status-bar/usage/provider-extra-usage-section.tsx @@ -1,8 +1,8 @@ -import type { ExtraUsageBalance, ProviderRateLimits } from '../../../../shared/rate-limit-types' -import type { UsagePercentageDisplay } from '../../../../shared/usage-percentage-display' -import { clampUsedPercent } from '../../../../shared/usage-percentage-display' -import { formatCreditCount } from '../../../../shared/credit-count-format' -import { formatCurrencyAmount } from '../../../../shared/currency-format' +import type { ExtraUsageBalance, ProviderRateLimits } from '../../../../../shared/rate-limit-types' +import type { UsagePercentageDisplay } from '../../../../../shared/usage-percentage-display' +import { clampUsedPercent } from '../../../../../shared/usage-percentage-display' +import { formatCreditCount } from '../../../../../shared/credit-count-format' +import { formatCurrencyAmount } from '../../../../../shared/currency-format' import { translate } from '@/i18n/i18n' import { useTranslate, type Translate } from '@/i18n/use-translate' import { formatUsagePercentageLabel } from './usage-percentage-label' diff --git a/src/renderer/src/components/status-bar/provider-segment-monthly-window.test.tsx b/src/renderer/src/components/status-bar/usage/provider-segment-monthly-window.test.tsx similarity index 93% rename from src/renderer/src/components/status-bar/provider-segment-monthly-window.test.tsx rename to src/renderer/src/components/status-bar/usage/provider-segment-monthly-window.test.tsx index 641182d1d89..1f99c923bac 100644 --- a/src/renderer/src/components/status-bar/provider-segment-monthly-window.test.tsx +++ b/src/renderer/src/components/status-bar/usage/provider-segment-monthly-window.test.tsx @@ -1,6 +1,6 @@ import { renderToStaticMarkup } from 'react-dom/server' import { describe, expect, it, vi } from 'vitest' -import type { ProviderRateLimits, RateLimitWindow } from '../../../../shared/rate-limit-types' +import type { ProviderRateLimits, RateLimitWindow } from '../../../../../shared/rate-limit-types' vi.mock('@/i18n/i18n', () => ({ i18n: { language: 'en' }, @@ -17,7 +17,7 @@ vi.mock('@/components/agent/icons/AgentIcon', () => ({ AgentIcon: () => null })) -vi.mock('../../store', () => ({ +vi.mock('../../../store/index', () => ({ useAppStore: (selector: (state: { usagePercentageDisplay: 'used' | 'remaining' }) => unknown) => selector({ usagePercentageDisplay: 'used' }) })) @@ -46,7 +46,7 @@ describe('undefined provider window safety (crash d2c1da69 / bb74236c)', () => { } as unknown as ProviderRateLimits // `session` omitted -> undefined at runtime it('ProviderSegment renders without crashing when a provider window is undefined', async () => { - const { ProviderSegment } = await import('./StatusBar') + const { ProviderSegment } = await import('./StatusBarProviderSegment') expect(() => renderToStaticMarkup( diff --git a/src/renderer/src/components/status-bar/tooltip.tsx b/src/renderer/src/components/status-bar/usage/provider-usage-panel.tsx similarity index 94% rename from src/renderer/src/components/status-bar/tooltip.tsx rename to src/renderer/src/components/status-bar/usage/provider-usage-panel.tsx index b2a741d02ba..36276417e82 100644 --- a/src/renderer/src/components/status-bar/tooltip.tsx +++ b/src/renderer/src/components/status-bar/usage/provider-usage-panel.tsx @@ -1,10 +1,16 @@ -import type { ProviderRateLimits, RateLimitWindow } from '../../../../shared/rate-limit-types' +import type { ProviderRateLimits, RateLimitWindow } from '../../../../../shared/rate-limit-types' import { formatResetCountdown, formatResetDuration -} from '../../../../shared/rate-limit-reset-format' +} from '../../../../../shared/rate-limit-reset-format' import { AgentIcon } from '@/components/agent/icons/AgentIcon' -import { ClaudeIcon, GeminiIcon, MiniMaxIcon, OpenAIIcon, OpenCodeGoIcon } from './icons' +import { + ClaudeIcon, + GeminiIcon, + MiniMaxIcon, + OpenAIIcon, + OpenCodeGoIcon +} from '../accounts/provider-icons' import { translate } from '@/i18n/i18n' import { useTranslate } from '@/i18n/use-translate' import type { Translate } from '@/i18n/use-translate' @@ -12,29 +18,18 @@ import { getProviderDisplayName, getUsageWindowSections, type UsageWindowSection -} from '../../../../shared/usage-provider-windows' +} from '../../../../../shared/usage-provider-windows' import { getProviderUsageErrorMessage, getProviderUsageStatusLabel } from './usage-error-copy' import { clampUsedPercent, getDisplayedUsagePercentage, type UsagePercentageDisplay -} from '../../../../shared/usage-percentage-display' +} from '../../../../../shared/usage-percentage-display' import { formatUsagePercentageLabel } from './usage-percentage-label' import { useResetCountdownClock } from '@/hooks/useResetCountdownClock' import { recomputeOn } from '@/lib/recompute-on' import { barColor, ProviderExtraUsageSection } from './provider-extra-usage-section' -export { - barColor, - getExtraUsageLabel, - USAGE_URGENT_PERCENT, - USAGE_WARNING_PERCENT -} from './provider-extra-usage-section' - -export { clampUsedPercent } - -export { getProviderUsageErrorMessage, getProviderUsageStatusLabel } from './usage-error-copy' - export function formatTimeAgo(ts: number, t: Translate = translate): string { const diff = Date.now() - ts if (diff < 60_000) { @@ -50,9 +45,6 @@ export function formatTimeAgo(ts: number, t: Translate = translate): string { return t('auto.components.status.bar.tooltip.hoursAgo', '{{hours}}h ago', { hours }) } -// Preserve tooltip imports while sharing countdown formatting with mobile. -export { formatResetCountdown } - export function formatResetCreditExpiry( expiresAt: number | null | undefined, count: number, diff --git a/src/renderer/src/components/status-bar/rate-limit-window-localized-label.ts b/src/renderer/src/components/status-bar/usage/rate-limit-window-localized-label.ts similarity index 88% rename from src/renderer/src/components/status-bar/rate-limit-window-localized-label.ts rename to src/renderer/src/components/status-bar/usage/rate-limit-window-localized-label.ts index 4ac299f670a..dbfaa95b601 100644 --- a/src/renderer/src/components/status-bar/rate-limit-window-localized-label.ts +++ b/src/renderer/src/components/status-bar/usage/rate-limit-window-localized-label.ts @@ -1,6 +1,6 @@ import { translate } from '@/i18n/i18n' -import { formatResetDuration } from '../../../../shared/rate-limit-reset-format' -import { formatWindowLabel as formatSharedWindowLabel } from '../../../../shared/rate-limit-window-label' +import { formatResetDuration } from '../../../../../shared/rate-limit-reset-format' +import { formatWindowLabel as formatSharedWindowLabel } from '../../../../../shared/rate-limit-window-label' const WEEK_MINUTES = 60 * 24 * 7 diff --git a/src/renderer/src/components/status-bar/usage-error-copy.ts b/src/renderer/src/components/status-bar/usage/usage-error-copy.ts similarity index 97% rename from src/renderer/src/components/status-bar/usage-error-copy.ts rename to src/renderer/src/components/status-bar/usage/usage-error-copy.ts index c386e2115f9..e7d8a4e174e 100644 --- a/src/renderer/src/components/status-bar/usage-error-copy.ts +++ b/src/renderer/src/components/status-bar/usage/usage-error-copy.ts @@ -1,8 +1,8 @@ -import type { ProviderRateLimits } from '../../../../shared/rate-limit-types' +import type { ProviderRateLimits } from '../../../../../shared/rate-limit-types' import { translate } from '@/i18n/i18n' import type { Translate } from '@/i18n/use-translate' -import { formatRateLimitUserFacingError } from '@/components/status-bar/usage-errors/rate-limit-user-facing-error' -import { getProviderDisplayName } from '../../../../shared/usage-provider-windows' +import { formatRateLimitUserFacingError } from '@/components/status-bar/usage/errors/rate-limit-user-facing-error' +import { getProviderDisplayName } from '../../../../../shared/usage-provider-windows' import { describeOwnerNotSetUp, getOwnerNotSetUpLabel } from './owner-not-set-up-copy' function isUsageRateLimitError(p: ProviderRateLimits): boolean { diff --git a/src/renderer/src/components/status-bar/usage-format-template.ts b/src/renderer/src/components/status-bar/usage/usage-format-template.ts similarity index 93% rename from src/renderer/src/components/status-bar/usage-format-template.ts rename to src/renderer/src/components/status-bar/usage/usage-format-template.ts index 66cc5861213..05b6200e2ba 100644 --- a/src/renderer/src/components/status-bar/usage-format-template.ts +++ b/src/renderer/src/components/status-bar/usage/usage-format-template.ts @@ -1,10 +1,10 @@ -import type { ProviderRateLimits, RateLimitWindow } from '../../../../shared/rate-limit-types' -import { formatResetDuration } from '../../../../shared/rate-limit-reset-format' +import type { ProviderRateLimits, RateLimitWindow } from '../../../../../shared/rate-limit-types' +import { formatResetDuration } from '../../../../../shared/rate-limit-reset-format' import { getDisplayedUsagePercentage, type UsagePercentageDisplay -} from '../../../../shared/usage-percentage-display' -import { getProviderDisplayName } from '../../../../shared/usage-provider-windows' +} from '../../../../../shared/usage-percentage-display' +import { getProviderDisplayName } from '../../../../../shared/usage-provider-windows' import { formatPlanLabel } from './usage-roster-formatting' export type UsageFormatValues = Record diff --git a/src/renderer/src/components/status-bar/usage-grouped-pools.tsx b/src/renderer/src/components/status-bar/usage/usage-grouped-pools.tsx similarity index 92% rename from src/renderer/src/components/status-bar/usage-grouped-pools.tsx rename to src/renderer/src/components/status-bar/usage/usage-grouped-pools.tsx index d9399d6ccce..aef59b1b92f 100644 --- a/src/renderer/src/components/status-bar/usage-grouped-pools.tsx +++ b/src/renderer/src/components/status-bar/usage/usage-grouped-pools.tsx @@ -1,13 +1,13 @@ import React from 'react' -import type { RateLimitBucket } from '../../../../shared/rate-limit-types' -import type { UsagePercentageDisplay } from '../../../../shared/usage-percentage-display' +import type { RateLimitBucket } from '../../../../../shared/rate-limit-types' +import type { UsagePercentageDisplay } from '../../../../../shared/usage-percentage-display' import { formatPoolGroupLabel, formatPoolWindowLabel, type GroupedUsagePool } from './usage-pool-label' import { formatBareUsagePercentage } from './usage-percentage-label' -import { useTranslate } from '../../i18n/use-translate' +import { useTranslate } from '../../../i18n/use-translate' // Shortest window first; an unknown window (0) sorts last. Stable, so ties keep agy's order. function compareWindows(a: RateLimitBucket, b: RateLimitBucket): number { diff --git a/src/renderer/src/components/status-bar/usage-percentage-label.ts b/src/renderer/src/components/status-bar/usage/usage-percentage-label.ts similarity index 94% rename from src/renderer/src/components/status-bar/usage-percentage-label.ts rename to src/renderer/src/components/status-bar/usage/usage-percentage-label.ts index 742620f8d43..8670dd44519 100644 --- a/src/renderer/src/components/status-bar/usage-percentage-label.ts +++ b/src/renderer/src/components/status-bar/usage/usage-percentage-label.ts @@ -3,7 +3,7 @@ import type { Translate } from '@/i18n/use-translate' import { getDisplayedUsagePercentage, type UsagePercentageDisplay -} from '../../../../shared/usage-percentage-display' +} from '../../../../../shared/usage-percentage-display' export function formatUsagePercentageLabel( usedPercent: number, diff --git a/src/renderer/src/components/status-bar/usage-pool-label.ts b/src/renderer/src/components/status-bar/usage/usage-pool-label.ts similarity index 95% rename from src/renderer/src/components/status-bar/usage-pool-label.ts rename to src/renderer/src/components/status-bar/usage/usage-pool-label.ts index 7ee35ad6b5f..2a54395e0f4 100644 --- a/src/renderer/src/components/status-bar/usage-pool-label.ts +++ b/src/renderer/src/components/status-bar/usage/usage-pool-label.ts @@ -8,8 +8,8 @@ import type { ProviderRateLimits, RateLimitBucket, RateLimitWindow -} from '../../../../shared/rate-limit-types' -import { clampUsedPercent } from '../../../../shared/usage-percentage-display' +} from '../../../../../shared/rate-limit-types' +import { clampUsedPercent } from '../../../../../shared/usage-percentage-display' import { USAGE_URGENT_PERCENT } from './provider-extra-usage-section' export type GroupedUsagePool = RateLimitBucket & { group: string } diff --git a/src/renderer/src/components/status-bar/usage-provider-settings-target.ts b/src/renderer/src/components/status-bar/usage/usage-provider-settings-target.ts similarity index 89% rename from src/renderer/src/components/status-bar/usage-provider-settings-target.ts rename to src/renderer/src/components/status-bar/usage/usage-provider-settings-target.ts index 7423950576d..49189ecae95 100644 --- a/src/renderer/src/components/status-bar/usage-provider-settings-target.ts +++ b/src/renderer/src/components/status-bar/usage/usage-provider-settings-target.ts @@ -1,5 +1,5 @@ -import type { GlobalSettings } from '../../../../shared/global-settings-types' -import type { ProviderRateLimits } from '../../../../shared/rate-limit-types' +import type { GlobalSettings } from '../../../../../shared/global-settings-types' +import type { ProviderRateLimits } from '../../../../../shared/rate-limit-types' export function getUsageProviderAccountsSectionId( provider: ProviderRateLimits['provider'] diff --git a/src/renderer/src/components/status-bar/usage-roster-formatting.ts b/src/renderer/src/components/status-bar/usage/usage-roster-formatting.ts similarity index 100% rename from src/renderer/src/components/status-bar/usage-roster-formatting.ts rename to src/renderer/src/components/status-bar/usage/usage-roster-formatting.ts diff --git a/src/renderer/src/components/status-bar/usage-roster-row-state.ts b/src/renderer/src/components/status-bar/usage/usage-roster-row-state.ts similarity index 96% rename from src/renderer/src/components/status-bar/usage-roster-row-state.ts rename to src/renderer/src/components/status-bar/usage/usage-roster-row-state.ts index 8621204937d..fbeec53f97f 100644 --- a/src/renderer/src/components/status-bar/usage-roster-row-state.ts +++ b/src/renderer/src/components/status-bar/usage/usage-roster-row-state.ts @@ -1,6 +1,6 @@ import { translate } from '@/i18n/i18n' import type { Translate } from '@/i18n/use-translate' -import type { ProviderRateLimits } from '../../../../shared/rate-limit-types' +import type { ProviderRateLimits } from '../../../../../shared/rate-limit-types' import { getOwnerNotSetUpLabel, getOwnerNotSetUpNote } from './owner-not-set-up-copy' import { getProviderUsageStatusLabel } from './usage-error-copy' diff --git a/src/renderer/src/components/status-bar/usage-unit-label.tsx b/src/renderer/src/components/status-bar/usage/usage-unit-label.tsx similarity index 81% rename from src/renderer/src/components/status-bar/usage-unit-label.tsx rename to src/renderer/src/components/status-bar/usage/usage-unit-label.tsx index 9239ed539c0..2a05590558a 100644 --- a/src/renderer/src/components/status-bar/usage-unit-label.tsx +++ b/src/renderer/src/components/status-bar/usage/usage-unit-label.tsx @@ -1,9 +1,9 @@ import React from 'react' -import type { ProviderRateLimits } from '../../../../shared/rate-limit-types' -import type { StatusBarUsageMode } from '../../../../shared/status-bar-usage-mode' -import type { UsagePercentageDisplay } from '../../../../shared/usage-percentage-display' +import type { ProviderRateLimits } from '../../../../../shared/rate-limit-types' +import type { StatusBarUsageMode } from '../../../../../shared/status-bar-usage-mode' +import type { UsagePercentageDisplay } from '../../../../../shared/usage-percentage-display' import { useTranslate, type Translate } from '@/i18n/use-translate' -import { getStatusBarUsageSections } from './status-bar-usage-sections' +import { getStatusBarUsageSections } from '../composition/status-bar-usage-sections' export type UsageUnitLabelState = 'absent' | 'collapsed' | 'shown' diff --git a/src/renderer/src/components/status-bar/use-owner-usage-rate-limits.test.tsx b/src/renderer/src/components/status-bar/usage/use-owner-usage-rate-limits.test.tsx similarity index 76% rename from src/renderer/src/components/status-bar/use-owner-usage-rate-limits.test.tsx rename to src/renderer/src/components/status-bar/usage/use-owner-usage-rate-limits.test.tsx index ef28d8471f6..aef7ad2cf19 100644 --- a/src/renderer/src/components/status-bar/use-owner-usage-rate-limits.test.tsx +++ b/src/renderer/src/components/status-bar/usage/use-owner-usage-rate-limits.test.tsx @@ -1,9 +1,9 @@ // @vitest-environment happy-dom import { act, cleanup, renderHook } from '@testing-library/react' import { afterEach, beforeEach, describe, expect, it, vi, type Mock } from 'vitest' -import type { RuntimeClientTarget } from '../../../../shared/runtime-client-target' -import type { ProviderRateLimits } from '../../../../shared/rate-limit-types' -import { createEmptyRateLimitState } from '../../../../shared/rate-limit-state-factory' +import type { RuntimeClientTarget } from '../../../../../shared/runtime-client-target' +import type { ProviderRateLimits } from '../../../../../shared/rate-limit-types' +import { createEmptyRateLimitState } from '../../../../../shared/rate-limit-state-factory' import type { ProviderAccountsSnapshot } from '@/runtime/provider-accounts/observations/runtime-provider-accounts-client' type Handlers = { @@ -23,7 +23,7 @@ const mocks = vi.hoisted(() => { return state }) -vi.mock('../../runtime/provider-accounts/ownership/use-active-account-owner', () => ({ +vi.mock('../../../runtime/provider-accounts/ownership/use-active-account-owner', () => ({ useActiveAccountOwner: () => ({ target: mocks.owner, wslHostDistro: null }) })) vi.mock('@/runtime/rpc/calls/runtime-rpc-call', () => ({ @@ -40,7 +40,7 @@ vi.mock('@/runtime/provider-accounts/observations/runtime-provider-accounts-clie } } })) -vi.mock('../../store', () => ({ +vi.mock('../../../store/index', () => ({ useAppStore: (selector: (state: unknown) => unknown) => selector({ settings: null, runtimeEnvironments: [{ id: 'mini', name: 'Mac Mini' }] }) })) @@ -98,29 +98,6 @@ describe('useOwnerUsageRateLimits', () => { expect(result.current.rateLimits.claude?.session).toBeNull() }) - it('marks usage unverifiable when the stream closes after its first snapshot, then reconnects', () => { - vi.useFakeTimers() - try { - mocks.owner = { kind: 'environment', environmentId: 'mini' } - const { result } = renderHook(() => useOwnerUsageRateLimits(local)) - act(() => - mocks.watchers[0].handlers.onSnapshot( - snapshot(createEmptyRateLimitState({ codex: provider('codex', 30) })) - ) - ) - act(() => mocks.watchers[0].handlers.onClosedAfterSnapshot?.()) - expect(result.current.rateLimits.codex?.session).toBeNull() - expect(result.current.rateLimits.codex?.error).toContain('cannot reach Mac Mini') - act(() => { - vi.advanceTimersByTime(5_000) - }) - expect(mocks.watchers[0].closed).toBe(true) - expect(mocks.watchers).toHaveLength(2) - } finally { - vi.useRealTimers() - } - }) - it('ignores a refresh that completes after the owner changed', async () => { mocks.owner = { kind: 'environment', environmentId: 'mini' } let resolveRefresh: (value: ProviderAccountsSnapshot) => void = () => {} diff --git a/src/renderer/src/components/status-bar/use-owner-usage-rate-limits.ts b/src/renderer/src/components/status-bar/usage/use-owner-usage-rate-limits.ts similarity index 97% rename from src/renderer/src/components/status-bar/use-owner-usage-rate-limits.ts rename to src/renderer/src/components/status-bar/usage/use-owner-usage-rate-limits.ts index 70256b50b4f..fea44710553 100644 --- a/src/renderer/src/components/status-bar/use-owner-usage-rate-limits.ts +++ b/src/renderer/src/components/status-bar/usage/use-owner-usage-rate-limits.ts @@ -8,9 +8,9 @@ import { type ProviderAccountsSnapshot } from '@/runtime/provider-accounts/observations/runtime-provider-accounts-client' import { useActiveAccountOwner } from '@/runtime/provider-accounts/ownership/use-active-account-owner' -import type { RateLimitState } from '../../../../shared/rate-limit-types' -import type { RuntimeClientTarget } from '../../../../shared/runtime-client-target' -import { useAppStore } from '../../store' +import type { RateLimitState } from '../../../../../shared/rate-limit-types' +import type { RuntimeClientTarget } from '../../../../../shared/runtime-client-target' +import { useAppStore } from '../../../store/index' import { resolveOwnerUsageRateLimits, type OwnerUsageFailureReason, diff --git a/src/renderer/src/components/status-bar/use-resource-memory-snapshot.test.tsx b/src/renderer/src/components/status-bar/use-resource-memory-snapshot.test.tsx deleted file mode 100644 index 3ee05c41e68..00000000000 --- a/src/renderer/src/components/status-bar/use-resource-memory-snapshot.test.tsx +++ /dev/null @@ -1,122 +0,0 @@ -// @vitest-environment happy-dom -import { act, cleanup, renderHook } from '@testing-library/react' -import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' -import type { MemorySnapshot } from '../../../../shared/process-stats-types' -import { useAppStore } from '../../store' -import { createEmptyMemorySnapshot } from '../../web/preload-api/web-memory-api' -import { useResourceMemorySnapshot } from './use-resource-memory-snapshot' - -vi.mock('../../store', () => ({ useAppStore: { setState: vi.fn() } })) - -const snapshot = (collectedAt: number): MemorySnapshot => ({ - ...createEmptyMemorySnapshot(), - collectedAt -}) -const getSnapshot = vi.fn<() => Promise>() -const flush = () => act(async () => {}) -const setup = (active = true) => - renderHook(({ active }) => useResourceMemorySnapshot(active), { initialProps: { active } }) - -beforeEach(() => { - vi.useFakeTimers() - vi.mocked(useAppStore.setState).mockClear() - getSnapshot.mockReset().mockResolvedValue(snapshot(1)) - vi.stubGlobal('api', { memory: { getSnapshot } }) -}) -afterEach(() => { - cleanup() - vi.useRealTimers() - vi.unstubAllGlobals() -}) - -describe('Resource Manager memory observation', () => { - it('coalesces concurrent refreshes and only polls while active', async () => { - const pending = Promise.withResolvers() - getSnapshot.mockReturnValueOnce(pending.promise) - const { result, rerender } = setup(false) - await act(async () => { - await vi.advanceTimersByTimeAsync(60_000) - }) - expect(getSnapshot).not.toHaveBeenCalled() - rerender({ active: true }) - act(() => { - void result.current() - void result.current() - }) - expect(getSnapshot).toHaveBeenCalledExactlyOnceWith({ resourceManagerView: true }) - await act(async () => { - pending.resolve(snapshot(10)) - }) - expect(useAppStore.setState).toHaveBeenCalledExactlyOnceWith({ - memorySnapshot: snapshot(10), - memorySnapshotError: null - }) - await act(async () => { - await vi.advanceTimersByTimeAsync(2_000) - }) - expect(getSnapshot).toHaveBeenCalledTimes(2) - rerender({ active: false }) - await act(async () => { - await vi.advanceTimersByTimeAsync(60_000) - }) - expect(getSnapshot).toHaveBeenCalledTimes(2) - expect(vi.getTimerCount()).toBe(0) - }) - - it('discards hidden results and reconciles one new epoch without overlapping requests', async () => { - const old = Promise.withResolvers() - const current = Promise.withResolvers() - getSnapshot.mockReturnValueOnce(old.promise).mockReturnValueOnce(current.promise) - const { result, rerender } = setup() - rerender({ active: false }) - rerender({ active: true }) - act(() => { - void result.current() - void result.current() - }) - expect(getSnapshot).toHaveBeenCalledOnce() - await act(async () => { - old.resolve(snapshot(10)) - }) - expect(useAppStore.setState).not.toHaveBeenCalled() - expect(getSnapshot).toHaveBeenCalledTimes(2) - await act(async () => { - current.resolve(snapshot(20)) - }) - expect(useAppStore.setState).toHaveBeenCalledExactlyOnceWith({ - memorySnapshot: snapshot(20), - memorySnapshotError: null - }) - }) - - it('does not let an old native visibility veto cancel a newly visible epoch', async () => { - const old = Promise.withResolvers() - getSnapshot.mockReturnValueOnce(old.promise) - const { rerender } = setup() - rerender({ active: false }) - rerender({ active: true }) - await act(async () => { - old.reject(new Error('view_not_visible')) - }) - expect(getSnapshot).toHaveBeenCalledTimes(2) - expect(useAppStore.setState).toHaveBeenCalledExactlyOnceWith({ - memorySnapshot: snapshot(1), - memorySnapshotError: null - }) - }) - - it('permits refresh after a native veto without requiring a different visibility prop', async () => { - getSnapshot.mockRejectedValueOnce(new Error('view_not_visible')) - const { result } = setup() - await flush() - expect(useAppStore.setState).not.toHaveBeenCalled() - await act(async () => { - await result.current() - }) - expect(getSnapshot).toHaveBeenCalledTimes(2) - expect(useAppStore.setState).toHaveBeenCalledExactlyOnceWith({ - memorySnapshot: snapshot(1), - memorySnapshotError: null - }) - }) -}) diff --git a/src/renderer/src/components/status-bar/use-resource-pty-actions.test.tsx b/src/renderer/src/components/status-bar/use-resource-pty-actions.test.tsx deleted file mode 100644 index 17e043c45b1..00000000000 --- a/src/renderer/src/components/status-bar/use-resource-pty-actions.test.tsx +++ /dev/null @@ -1,219 +0,0 @@ -// @vitest-environment happy-dom -import { act, cleanup, renderHook } from '@testing-library/react' -import { afterEach, beforeEach, expect, it, vi } from 'vitest' -import type { PtyListedSession } from '../../../../shared/terminal/pty/lifecycle/pty-listed-session' -import type { - PtyFencedTerminationOutcome, - PtyFencedTerminationRequest -} from '../../../../shared/terminal/pty/lifecycle/pty-fenced-termination' -import { useResourcePtyActions } from './use-resource-pty-actions' -import { useResourceSessionInventory } from './use-resource-session-inventory' -import { buildResourcePtyRows } from './resource-pty-view-model' - -const session = (incarnationId = 'A'): PtyListedSession => ({ - id: 'one', - incarnationId, - fencedTermination: true, - agentOwnership: 'absent', - cwd: '/', - title: 'Shell' -}) -const row = (value: PtyListedSession) => - buildResourcePtyRows({ - sessions: [value], - bindings: { tabsByWorktree: {}, ptyIdsByTabId: {}, workspaceSessionReady: true }, - repos: [], - worktrees: [], - projectGroups: [], - runtimePaneTitlesByTabId: {} - })[0]! -const kill = vi.fn<(request: PtyFencedTerminationRequest) => Promise>() -const list = vi.fn<() => Promise>() -let emitExit: Parameters[0] -beforeEach(() => { - vi.useFakeTimers() - kill.mockReset() - list.mockReset().mockResolvedValue([session()]) - vi.stubGlobal('api', { - pty: { - killFenced: kill, - listSessions: list, - onSpawned: () => () => {}, - onExit: (listener: typeof emitExit) => { - emitExit = listener - return () => {} - } - } - }) -}) -afterEach(() => { - cleanup() - vi.restoreAllMocks() - vi.useRealTimers() - vi.unstubAllGlobals() -}) -function setup() { - return renderHook( - ({ active }) => { - const inventory = useResourceSessionInventory(true, active, true) - return { inventory, actions: useResourcePtyActions(inventory) } - }, - { initialProps: { active: true } } - ) -} - -it('starts immediately and retains the identity seen before replacement', async () => { - const { result } = setup() - await act(async () => {}) - let finish!: (value: PtyFencedTerminationOutcome) => void - kill.mockReturnValue( - new Promise((resolve) => { - finish = resolve - }) - ) - act(() => result.current.actions.end(row(session()))) - expect(kill).toHaveBeenCalledTimes(1) - list.mockResolvedValue([session('B')]) - act(() => { - void result.current.inventory.refreshSessions() - }) - await act(async () => { - await vi.advanceTimersByTimeAsync(100) - }) - await act(async () => finish({ outcome: 'refused', reason: 'replaced' })) - expect(kill).toHaveBeenCalledWith({ - id: 'one', - expectedIncarnationId: 'A', - requireNoAgentOwner: true, - requireUnattached: true - }) - expect(result.current.inventory.sessionInventory.sessions).toEqual([session('B')]) -}) - -it('shares four request slots across overlapping disjoint batches and direct End actions', async () => { - const sessions = Array.from({ length: 10 }, (_, index) => ({ ...session(), id: `pty-${index}` })) - list.mockResolvedValue(sessions) - const finishes: (() => void)[] = [] - let active = 0 - let maximumActive = 0 - kill.mockImplementation( - () => - new Promise((resolve) => { - active += 1 - maximumActive = Math.max(maximumActive, active) - finishes.push(() => { - active -= 1 - resolve({ outcome: 'ended' }) - }) - }) - ) - const { result, rerender } = setup() - await act(async () => {}) - rerender({ active: false }) - let first = Promise.resolve() - let second = Promise.resolve() - act(() => { - first = result.current.actions.endMany(sessions.slice(0, 5).map(row)) - second = result.current.actions.endMany(sessions.slice(5, 9).map(row)) - result.current.actions.end(row(sessions[9]!)) - }) - expect(kill).toHaveBeenCalledTimes(4) - expect(result.current.actions.ending.size).toBe(10) - await act(async () => finishes.splice(0).forEach((finish) => finish())) - expect(kill).toHaveBeenCalledTimes(8) - await act(async () => finishes.splice(0).forEach((finish) => finish())) - expect(kill).toHaveBeenCalledTimes(10) - await act(async () => { - finishes.splice(0).forEach((finish) => finish()) - await Promise.all([first, second]) - }) - expect(maximumActive).toBe(4) - expect(result.current.inventory.sessionInventory.count).toBe(0) - expect(result.current.actions.ending.size).toBe(0) -}) - -it('publishes progress without listing until overlapping termination batches drain', async () => { - const sessions = Array.from({ length: 12 }, (_, index) => ({ ...session(), id: `pty-${index}` })) - let remaining = sessions - list.mockImplementation(async () => remaining) - const finishes: (() => void)[] = [] - kill.mockImplementation( - ({ id }) => - new Promise((resolve, reject) => { - finishes.push(() => { - if (id === 'pty-0') { - resolve({ outcome: 'refused', reason: 'claimed' }) - } else if (id === 'pty-1') { - reject(new Error('Disconnected')) - } else { - remaining = remaining.filter((value) => value.id !== id) - resolve({ outcome: 'ended' }) - } - }) - }) - ) - const { result } = setup() - await act(async () => {}) - expect(list).toHaveBeenCalledTimes(1) - const settled = vi.fn() - let first = Promise.resolve() - let second = Promise.resolve() - act(() => { - first = result.current.actions.endMany(sessions.slice(0, 6).map(row)).then(settled) - second = result.current.actions.endMany(sessions.slice(6).map(row)) - }) - for (let wave = 0; wave < 2; wave += 1) { - await act(async () => finishes.splice(0).forEach((finish) => finish())) - await act(async () => { - await vi.advanceTimersByTimeAsync(150) - }) - expect(result.current.actions.ending.size).toBe(12 - (wave + 1) * 4) - expect(result.current.inventory.sessionInventory.count).toBe(14 - (wave + 1) * 4) - expect(result.current.actions.errors.size).toBe(2) - expect(list).toHaveBeenCalledTimes(1) - } - expect(settled).toHaveBeenCalledTimes(1) - const discovered = { ...session(), id: 'new-session' } - remaining = [...remaining, discovered] - await act(async () => { - finishes.splice(0).forEach((finish) => finish()) - await Promise.all([first, second]) - await vi.advanceTimersByTimeAsync(150) - }) - expect(list).toHaveBeenCalledTimes(2) - expect(result.current.inventory.sessionInventory.sessions).toEqual([ - sessions[0], - sessions[1], - discovered - ]) - expect(result.current.actions.ending.size).toBe(0) - expect(vi.getTimerCount()).toBe(0) -}) - -it('settles a completed invocation after unmount while another accepted request is still pending', async () => { - const sessions = [session(), { ...session(), id: 'two' }] - list.mockResolvedValue(sessions) - const finishes: (() => void)[] = [] - kill.mockImplementation( - () => new Promise((resolve) => finishes.push(() => resolve({ outcome: 'ended' }))) - ) - const { result, unmount } = setup() - await act(async () => {}) - let first = Promise.resolve() - let second = Promise.resolve() - act(() => { - first = result.current.actions.endMany([row(sessions[0]!)]) - second = result.current.actions.endMany([row(sessions[1]!)]) - }) - unmount() - await act(async () => { - finishes[0]!() - await first - }) - expect(vi.getTimerCount()).toBe(0) - await act(async () => { - finishes[1]!() - await second - }) - expect(vi.getTimerCount()).toBe(0) -}) diff --git a/src/renderer/src/components/status-bar/WorkspaceSpaceCompactPanel.tsx b/src/renderer/src/components/status-bar/workspace-storage/WorkspaceSpaceCompactPanel.tsx similarity index 97% rename from src/renderer/src/components/status-bar/WorkspaceSpaceCompactPanel.tsx rename to src/renderer/src/components/status-bar/workspace-storage/WorkspaceSpaceCompactPanel.tsx index 47ca2292d94..cddde004cb3 100644 --- a/src/renderer/src/components/status-bar/WorkspaceSpaceCompactPanel.tsx +++ b/src/renderer/src/components/status-bar/workspace-storage/WorkspaceSpaceCompactPanel.tsx @@ -1,14 +1,14 @@ import { useCallback } from 'react' import { AlertTriangle, HardDrive, Loader2, RefreshCw, X } from 'lucide-react' -import { useAppStore } from '../../store' -import { Badge } from '../ui/badge' -import { Button } from '../ui/button' +import { useAppStore } from '../../../store/index' +import { Badge } from '../../ui/badge' +import { Button } from '../../ui/button' import { - formatBytes, getWorkspaceSpaceProgressLabel, getWorkspaceSpaceScanningFallbackLabel, getWorkspaceSpaceScanTimeLabel } from './workspace-space-format' +import { formatBytes } from '../../../../../shared/format-bytes' import { useIntlLocale, useTranslate } from '@/i18n/use-translate' export function WorkspaceSpaceCompactPanel({ diff --git a/src/renderer/src/components/status-bar/WorkspaceSpaceManagerPanel.tsx b/src/renderer/src/components/status-bar/workspace-storage/WorkspaceSpaceManagerPanel.tsx similarity index 59% rename from src/renderer/src/components/status-bar/WorkspaceSpaceManagerPanel.tsx rename to src/renderer/src/components/status-bar/workspace-storage/WorkspaceSpaceManagerPanel.tsx index 11a6f3c5b96..4f9a6e7d8c0 100644 --- a/src/renderer/src/components/status-bar/WorkspaceSpaceManagerPanel.tsx +++ b/src/renderer/src/components/status-bar/workspace-storage/WorkspaceSpaceManagerPanel.tsx @@ -1,8 +1,6 @@ -import { useWorkspaceSpaceManagerPanel } from './use-workspace-space-manager-panel' +import { useWorkspaceSpaceManagerPanel } from './manager/use-workspace-space-manager-panel' import { WorkspaceSpaceManagerView } from './workspace-space-manager-view' -export { getWorkspaceDecisionDetails } from './workspace-space-decision-details' - export function WorkspaceSpaceManagerPanel(): React.JSX.Element { const model = useWorkspaceSpaceManagerPanel() return diff --git a/src/renderer/src/components/status-bar/use-workspace-space-decision-projection.ts b/src/renderer/src/components/status-bar/workspace-storage/decisions/use-workspace-space-decision-projection.ts similarity index 91% rename from src/renderer/src/components/status-bar/use-workspace-space-decision-projection.ts rename to src/renderer/src/components/status-bar/workspace-storage/decisions/use-workspace-space-decision-projection.ts index e7fcc587015..574cb2a0ff0 100644 --- a/src/renderer/src/components/status-bar/use-workspace-space-decision-projection.ts +++ b/src/renderer/src/components/status-bar/workspace-storage/decisions/use-workspace-space-decision-projection.ts @@ -5,10 +5,10 @@ import { getWorkspaceDecisionDetails, type WorkspaceDecisionDetails } from './workspace-space-decision-details' -import { getWorkspaceSpaceDeleteState } from './workspace-space-state-resolution' -import { getWorkspaceSpaceWorktreeIdentity } from './workspace-space-delete-selection' -import type { WorkspaceSpaceWorktree } from '../../../../shared/workspace-disk-space/workspace-space-types' -import type { useWorkspaceSpaceManagerBindings } from './use-workspace-space-manager-bindings' +import { getWorkspaceSpaceDeleteState } from '../manager/workspace-space-state-resolution' +import { getWorkspaceSpaceWorktreeIdentity } from '../manager/workspace-space-delete-selection' +import type { WorkspaceSpaceWorktree } from '../../../../../../shared/workspace-disk-space/workspace-space-types' +import type { useWorkspaceSpaceManagerBindings } from '../manager/use-workspace-space-manager-bindings' import { getWorktreeOnHostFromState } from '@/store/workspaces/selection/worktree-on-host-selector' type WorkspaceSpaceManagerBindings = ReturnType diff --git a/src/renderer/src/components/status-bar/use-workspace-space-git-refresh-action.ts b/src/renderer/src/components/status-bar/workspace-storage/decisions/use-workspace-space-git-refresh-action.ts similarity index 89% rename from src/renderer/src/components/status-bar/use-workspace-space-git-refresh-action.ts rename to src/renderer/src/components/status-bar/workspace-storage/decisions/use-workspace-space-git-refresh-action.ts index ebd5cd3f3ef..1c32bce1929 100644 --- a/src/renderer/src/components/status-bar/use-workspace-space-git-refresh-action.ts +++ b/src/renderer/src/components/status-bar/workspace-storage/decisions/use-workspace-space-git-refresh-action.ts @@ -1,11 +1,11 @@ import { useCallback } from 'react' import { ipcOrRuntimeTargetForHostId } from '@/runtime/rpc/targets/runtime-client-target' -import type { WorkspaceSpaceWorktree } from '../../../../shared/workspace-disk-space/workspace-space-types' -import { getWorkspaceSpaceWorktreeIdentity } from './workspace-space-delete-selection' -import { useAppStore } from '../../store' -import { findRepoForHost } from '../../store/repos/repo-host-identity' +import type { WorkspaceSpaceWorktree } from '../../../../../../shared/workspace-disk-space/workspace-space-types' +import { getWorkspaceSpaceWorktreeIdentity } from '../manager/workspace-space-delete-selection' +import { useAppStore } from '../../../../store/index' +import { findRepoForHost } from '../../../../store/repos/repo-host-identity' import { getRuntimeGitStatus } from '@/runtime/source-control/git/runtime-git-status-client' -import type { useWorkspaceSpaceManagerBindings } from './use-workspace-space-manager-bindings' +import type { useWorkspaceSpaceManagerBindings } from '../manager/use-workspace-space-manager-bindings' import { translate } from '@/i18n/i18n' type WorkspaceSpaceManagerBindings = ReturnType diff --git a/src/renderer/src/components/status-bar/workspace-space-decision-details.ts b/src/renderer/src/components/status-bar/workspace-storage/decisions/workspace-space-decision-details.ts similarity index 82% rename from src/renderer/src/components/status-bar/workspace-space-decision-details.ts rename to src/renderer/src/components/status-bar/workspace-storage/decisions/workspace-space-decision-details.ts index 3efe6b94c01..930b84f3357 100644 --- a/src/renderer/src/components/status-bar/workspace-space-decision-details.ts +++ b/src/renderer/src/components/status-bar/workspace-storage/decisions/workspace-space-decision-details.ts @@ -1,21 +1,21 @@ -import type { AgentStatusEntry } from '../../../../shared/agent-status/contracts/agent-status-types' -import type { MigrationUnsupportedPtyEntry } from '../../../../shared/agent-status/contracts/agent-status-ipc-payload' -import type { ExecutionHostId } from '../../../../shared/execution-host' -import type { HostedReviewProvider } from '../../../../shared/source-control/hosted-review/hosted-review-contracts' -import type { Repo } from '../../../../shared/repo-types' -import type { TerminalTab } from '../../../../shared/workspace-layout/terminal-tab-types' -import type { Worktree } from '../../../../shared/worktree/types' -import { isGitHubPRSuppressed } from '../../../../shared/worktree/hosted-review/github-pr-suppression' -import type { WorkspaceSpaceWorktree } from '../../../../shared/workspace-disk-space/workspace-space-types' -import '../sidebar/workspace-card/activity/worktree-card-empty-inputs' -import { branchDisplayName } from '../sidebar/workspace-card/identity/worktree-branch-display' -import { findRepoForHost } from '../../store/repos/repo-host-identity' -import { getHostedReviewCacheKey } from '../../store/slices/hosted-review/hosted-review-cache-identity' -import { issueCacheKey as getIssueCacheKey } from '../../store/github/cache/cache-identity' -import { countWorkspaceSpaceActiveAgents } from './workspace-space-presentation' -import { getWorkspaceSpaceWorktreeIdentity } from './workspace-space-delete-selection' -import { getWorkspaceSpaceBranchLabel } from './workspace-space-format' -import { formatHostedReviewLabel } from './hosted-review-label' +import type { AgentStatusEntry } from '../../../../../../shared/agent-status/contracts/agent-status-types' +import type { MigrationUnsupportedPtyEntry } from '../../../../../../shared/agent-status/contracts/agent-status-ipc-payload' +import type { ExecutionHostId } from '../../../../../../shared/execution-host' +import type { HostedReviewProvider } from '../../../../../../shared/source-control/hosted-review/hosted-review-contracts' +import type { Repo } from '../../../../../../shared/repo-types' +import type { TerminalTab } from '../../../../../../shared/workspace-layout/terminal-tab-types' +import type { Worktree } from '../../../../../../shared/worktree/types' +import { isGitHubPRSuppressed } from '../../../../../../shared/worktree/hosted-review/github-pr-suppression' +import type { WorkspaceSpaceWorktree } from '../../../../../../shared/workspace-disk-space/workspace-space-types' +import '../../../sidebar/workspace-card/activity/worktree-card-empty-inputs' +import { branchDisplayName } from '../../../sidebar/workspace-card/identity/worktree-branch-display' +import { findRepoForHost } from '../../../../store/repos/repo-host-identity' +import { getHostedReviewCacheKey } from '../../../../store/slices/hosted-review/hosted-review-cache-identity' +import { issueCacheKey as getIssueCacheKey } from '../../../../store/github/cache/cache-identity' +import { countWorkspaceSpaceActiveAgents } from '../manager/workspace-space-presentation' +import { getWorkspaceSpaceWorktreeIdentity } from '../manager/workspace-space-delete-selection' +import { getWorkspaceSpaceBranchLabel } from '../workspace-space-format' +import { formatHostedReviewLabel } from '../../resources/hosted-review-label' import { translate } from '@/i18n/i18n' import type { Translate } from '@/i18n/use-translate' diff --git a/src/renderer/src/components/status-bar/workspace-space-decision-hover-card.tsx b/src/renderer/src/components/status-bar/workspace-storage/decisions/workspace-space-decision-hover-card.tsx similarity index 93% rename from src/renderer/src/components/status-bar/workspace-space-decision-hover-card.tsx rename to src/renderer/src/components/status-bar/workspace-storage/decisions/workspace-space-decision-hover-card.tsx index 63ba315e0a1..378530f7d3d 100644 --- a/src/renderer/src/components/status-bar/workspace-space-decision-hover-card.tsx +++ b/src/renderer/src/components/status-bar/workspace-storage/decisions/workspace-space-decision-hover-card.tsx @@ -7,14 +7,15 @@ import { Terminal, Trash2 } from 'lucide-react' -import type { WorkspaceSpaceWorktree } from '../../../../shared/workspace-disk-space/workspace-space-types' +import type { WorkspaceSpaceWorktree } from '../../../../../../shared/workspace-disk-space/workspace-space-types' import { cn } from '@/lib/class-names' -import { Button } from '../ui/button' -import { HoverCardContent } from '../ui/hover-card' -import { formatBytes, getWorkspaceSpaceBranchLabel } from './workspace-space-format' +import { Button } from '../../../ui/button' +import { HoverCardContent } from '../../../ui/hover-card' +import { getWorkspaceSpaceBranchLabel } from '../workspace-space-format' +import { formatBytes } from '../../../../../../shared/format-bytes' import { useTranslate } from '@/i18n/use-translate' import type { WorkspaceDecisionDetails } from './workspace-space-decision-details' -import type { WorkspaceGitRefreshState } from './workspace-space-manager-state-types' +import type { WorkspaceGitRefreshState } from '../manager/workspace-space-manager-state-types' import { WorkspaceSpaceStatusBadge } from './workspace-space-status-badge' import { WorkspaceSpaceIssueFreshness } from './workspace-space-issue-freshness' import { diff --git a/src/renderer/src/components/status-bar/workspace-space-decision-inputs.ts b/src/renderer/src/components/status-bar/workspace-storage/decisions/workspace-space-decision-inputs.ts similarity index 90% rename from src/renderer/src/components/status-bar/workspace-space-decision-inputs.ts rename to src/renderer/src/components/status-bar/workspace-storage/decisions/workspace-space-decision-inputs.ts index 758d2b208ef..4dfa43d33b6 100644 --- a/src/renderer/src/components/status-bar/workspace-space-decision-inputs.ts +++ b/src/renderer/src/components/status-bar/workspace-storage/decisions/workspace-space-decision-inputs.ts @@ -1,7 +1,7 @@ -import type { TerminalTab } from '../../../../shared/workspace-layout/terminal-tab-types' -import type { WorkspaceSpaceWorktree } from '../../../../shared/workspace-disk-space/workspace-space-types' +import type { TerminalTab } from '../../../../../../shared/workspace-layout/terminal-tab-types' +import type { WorkspaceSpaceWorktree } from '../../../../../../shared/workspace-disk-space/workspace-space-types' import type { WorkspaceDecisionInputs } from './workspace-space-decision-details' -import { getPaneKeyTabId } from './workspace-space-presentation' +import { getPaneKeyTabId } from '../manager/workspace-space-presentation' type GroupedInputs = Pick< WorkspaceDecisionInputs, diff --git a/src/renderer/src/components/status-bar/workspace-space-decision-labels.ts b/src/renderer/src/components/status-bar/workspace-storage/decisions/workspace-space-decision-labels.ts similarity index 94% rename from src/renderer/src/components/status-bar/workspace-space-decision-labels.ts rename to src/renderer/src/components/status-bar/workspace-storage/decisions/workspace-space-decision-labels.ts index fbd0c0e3d4f..a8f2d15549a 100644 --- a/src/renderer/src/components/status-bar/workspace-space-decision-labels.ts +++ b/src/renderer/src/components/status-bar/workspace-storage/decisions/workspace-space-decision-labels.ts @@ -1,9 +1,9 @@ -import type { WorkspaceSpaceWorktree } from '../../../../shared/workspace-disk-space/workspace-space-types' +import type { WorkspaceSpaceWorktree } from '../../../../../../shared/workspace-disk-space/workspace-space-types' import { translate } from '@/i18n/i18n' import type { Translate } from '@/i18n/use-translate' -import { getWorkspaceSpaceStatusLabel } from './workspace-space-format' +import { getWorkspaceSpaceStatusLabel } from '../workspace-space-format' import type { WorkspaceDecisionDetails } from './workspace-space-decision-details' -import type { WorkspaceGitRefreshState } from './workspace-space-manager-state-types' +import type { WorkspaceGitRefreshState } from '../manager/workspace-space-manager-state-types' function formatActiveAgents(count: number, t: Translate = translate): string { return t( diff --git a/src/renderer/src/components/status-bar/workspace-space-git-status-order.ts b/src/renderer/src/components/status-bar/workspace-storage/decisions/workspace-space-git-status-order.ts similarity index 83% rename from src/renderer/src/components/status-bar/workspace-space-git-status-order.ts rename to src/renderer/src/components/status-bar/workspace-storage/decisions/workspace-space-git-status-order.ts index b9c0212cd82..bff50575d53 100644 --- a/src/renderer/src/components/status-bar/workspace-space-git-status-order.ts +++ b/src/renderer/src/components/status-bar/workspace-storage/decisions/workspace-space-git-status-order.ts @@ -1,5 +1,5 @@ -import type { WorkspaceSpaceWorktree } from '../../../../shared/workspace-disk-space/workspace-space-types' -import { getWorkspaceSpaceWorktreeIdentity } from './workspace-space-delete-selection' +import type { WorkspaceSpaceWorktree } from '../../../../../../shared/workspace-disk-space/workspace-space-types' +import { getWorkspaceSpaceWorktreeIdentity } from '../manager/workspace-space-delete-selection' export function getWorkspaceSpaceGitStatusRefreshCandidates( rows: readonly WorkspaceSpaceWorktree[], diff --git a/src/renderer/src/components/status-bar/workspace-space-issue-freshness.tsx b/src/renderer/src/components/status-bar/workspace-storage/decisions/workspace-space-issue-freshness.tsx similarity index 93% rename from src/renderer/src/components/status-bar/workspace-space-issue-freshness.tsx rename to src/renderer/src/components/status-bar/workspace-storage/decisions/workspace-space-issue-freshness.tsx index 97d0ece42b6..8d81783f552 100644 --- a/src/renderer/src/components/status-bar/workspace-space-issue-freshness.tsx +++ b/src/renderer/src/components/status-bar/workspace-storage/decisions/workspace-space-issue-freshness.tsx @@ -1,6 +1,6 @@ import { useEffect } from 'react' -import type { ExecutionHostId } from '../../../../shared/execution-host' -import { useAppStore } from '@/store' +import type { ExecutionHostId } from '../../../../../../shared/execution-host' +import { useAppStore } from '@/store/index' import { installWindowVisibilityInterval } from '@/lib/window-activity/window-visibility-interval' import { findWorktreeReviewOwner } from '@/store/github/refresh/worktree-refresh' diff --git a/src/renderer/src/components/status-bar/workspace-space-status-badge.tsx b/src/renderer/src/components/status-bar/workspace-storage/decisions/workspace-space-status-badge.tsx similarity index 91% rename from src/renderer/src/components/status-bar/workspace-space-status-badge.tsx rename to src/renderer/src/components/status-bar/workspace-storage/decisions/workspace-space-status-badge.tsx index a0ceb5d3b6e..a44f2648ab2 100644 --- a/src/renderer/src/components/status-bar/workspace-space-status-badge.tsx +++ b/src/renderer/src/components/status-bar/workspace-storage/decisions/workspace-space-status-badge.tsx @@ -1,10 +1,10 @@ import { Loader2 } from 'lucide-react' -import type { WorkspaceSpaceWorktree } from '../../../../shared/workspace-disk-space/workspace-space-types' -import { Badge } from '../ui/badge' -import { getWorkspaceSpaceStatusLabel } from './workspace-space-format' +import type { WorkspaceSpaceWorktree } from '../../../../../../shared/workspace-disk-space/workspace-space-types' +import { Badge } from '../../../ui/badge' +import { getWorkspaceSpaceStatusLabel } from '../workspace-space-format' import { useTranslate } from '@/i18n/use-translate' import type { WorkspaceDecisionDetails } from './workspace-space-decision-details' -import type { WorkspaceSpaceDeleteState } from './workspace-space-manager-state-types' +import type { WorkspaceSpaceDeleteState } from '../manager/workspace-space-manager-state-types' export function WorkspaceSpaceStatusBadge({ worktree, diff --git a/src/renderer/src/components/status-bar/use-workspace-space-manager-bindings.ts b/src/renderer/src/components/status-bar/workspace-storage/manager/use-workspace-space-manager-bindings.ts similarity index 94% rename from src/renderer/src/components/status-bar/use-workspace-space-manager-bindings.ts rename to src/renderer/src/components/status-bar/workspace-storage/manager/use-workspace-space-manager-bindings.ts index 73b655af9c4..7969b7c3ff7 100644 --- a/src/renderer/src/components/status-bar/use-workspace-space-manager-bindings.ts +++ b/src/renderer/src/components/status-bar/workspace-storage/manager/use-workspace-space-manager-bindings.ts @@ -1,8 +1,8 @@ import { useRef, useState } from 'react' -import type { GitStatusResult } from '../../../../shared/git/status/git-status-types' -import { useAppStore } from '../../store' -import { getIndexedRepoMap } from '../../store/repos/repository-catalog-index' -import { getIndexedWorktreeMap } from '../../store/slices/worktrees/listing/worktree-catalog-index' +import type { GitStatusResult } from '../../../../../../shared/git/status/git-status-types' +import { useAppStore } from '../../../../store/index' +import { getIndexedRepoMap } from '../../../../store/repos/repository-catalog-index' +import { getIndexedWorktreeMap } from '../../../../store/slices/worktrees/listing/worktree-catalog-index' import type { WorkspaceSpaceSortDirection, WorkspaceSpaceSortKey diff --git a/src/renderer/src/components/status-bar/use-workspace-space-manager-panel.ts b/src/renderer/src/components/status-bar/workspace-storage/manager/use-workspace-space-manager-panel.ts similarity index 86% rename from src/renderer/src/components/status-bar/use-workspace-space-manager-panel.ts rename to src/renderer/src/components/status-bar/workspace-storage/manager/use-workspace-space-manager-panel.ts index f9e841b6c11..dba47e3b7e5 100644 --- a/src/renderer/src/components/status-bar/use-workspace-space-manager-panel.ts +++ b/src/renderer/src/components/status-bar/workspace-storage/manager/use-workspace-space-manager-panel.ts @@ -1,25 +1,25 @@ import { useCallback } from 'react' import { toast } from 'sonner' -import type { WorkspaceSpaceWorktree } from '../../../../shared/workspace-disk-space/workspace-space-types' +import type { WorkspaceSpaceWorktree } from '../../../../../../shared/workspace-disk-space/workspace-space-types' import { toWorktreeRemovalTarget, type WorktreeRemovalTarget -} from '../../../../shared/worktree/removal/removal' -import { composeWorktreeHostIdentity } from '../../../../shared/worktree/host-qualified-identity' -import { useAppStore } from '../../store' -import { getWorktreeOnHostFromState } from '../../store/workspaces/selection/worktree-on-host-selector' -import { runWorktreeBatchDelete } from '../sidebar/workspace-actions/deletion/delete-worktree-flow' -import { dismissDeleteWorktreeFailureToast } from '../sidebar/workspace-actions/deletion/delete-worktree-failure-toast' -import { showWorkspaceListChangedToast } from '../sidebar/worktree-list/listing/stale-workspace-list-toast' -import { toWorktreeDeleteIdentities } from '../sidebar/workspace-actions/deletion/worktree-delete-request' +} from '../../../../../../shared/worktree/removal/removal' +import { composeWorktreeHostIdentity } from '../../../../../../shared/worktree/host-qualified-identity' +import { useAppStore } from '../../../../store/index' +import { getWorktreeOnHostFromState } from '../../../../store/workspaces/selection/worktree-on-host-selector' +import { runWorktreeBatchDelete } from '../../../sidebar/workspace-actions/deletion/delete-worktree-flow' +import { dismissDeleteWorktreeFailureToast } from '../../../sidebar/workspace-actions/deletion/delete-worktree-failure-toast' +import { showWorkspaceListChangedToast } from '../../../sidebar/worktree-list/listing/stale-workspace-list-toast' +import { toWorktreeDeleteIdentities } from '../../../sidebar/workspace-actions/deletion/worktree-delete-request' import { translate } from '@/i18n/i18n' import type { WorkspaceSpaceSortKey } from './workspace-space-presentation' import { useWorkspaceSpaceManagerBindings } from './use-workspace-space-manager-bindings' -import { useWorkspaceSpaceDecisionProjection } from './use-workspace-space-decision-projection' -import { useWorkspaceSpaceGitRefreshAction } from './use-workspace-space-git-refresh-action' +import { useWorkspaceSpaceDecisionProjection } from '../decisions/use-workspace-space-decision-projection' +import { useWorkspaceSpaceGitRefreshAction } from '../decisions/use-workspace-space-git-refresh-action' import { useWorkspaceSpaceManagerProjection } from './use-workspace-space-manager-projection' import { getWorkspaceSpaceWorktreeIdentity } from './workspace-space-delete-selection' -import { blockRemovalForUnsavedFiles } from '../sidebar/workspace-actions/deletion/removal-unsaved-files' +import { blockRemovalForUnsavedFiles } from '../../../sidebar/workspace-actions/deletion/removal-unsaved-files' export function useWorkspaceSpaceManagerPanel() { const bindings = useWorkspaceSpaceManagerBindings() diff --git a/src/renderer/src/components/status-bar/use-workspace-space-manager-projection.ts b/src/renderer/src/components/status-bar/workspace-storage/manager/use-workspace-space-manager-projection.ts similarity index 92% rename from src/renderer/src/components/status-bar/use-workspace-space-manager-projection.ts rename to src/renderer/src/components/status-bar/workspace-storage/manager/use-workspace-space-manager-projection.ts index 1db540dd5c7..0c68487dfe3 100644 --- a/src/renderer/src/components/status-bar/use-workspace-space-manager-projection.ts +++ b/src/renderer/src/components/status-bar/workspace-storage/manager/use-workspace-space-manager-projection.ts @@ -8,19 +8,19 @@ import { sortWorkspaceSpaceRows } from './workspace-space-presentation' import { withWorkspaceSpaceVisitActivity } from './workspace-space-visit-activity' -import { getWorkspaceSpaceGitStatusRefreshCandidates } from './workspace-space-git-status-order' +import { getWorkspaceSpaceGitStatusRefreshCandidates } from '../decisions/workspace-space-git-status-order' import { getSelectedDeletableWorkspaceRows, getVisibleDeletableWorkspaceIdentities, getWorkspaceSpaceWorktreeIdentity } from './workspace-space-delete-selection' -import type { WorkspaceSpaceWorktree } from '../../../../shared/workspace-disk-space/workspace-space-types' -import { ORCA_SIDEBAR_INPUTS_IS_MAIN } from '../../../../shared/sidebar-inputs-switch' -import { useAppStore } from '@/store' -import { getWorkspaceSpaceProgressLabel } from './workspace-space-format' +import type { WorkspaceSpaceWorktree } from '../../../../../../shared/workspace-disk-space/workspace-space-types' +import { ORCA_SIDEBAR_INPUTS_IS_MAIN } from '../../../../../../shared/sidebar-inputs-switch' +import { useAppStore } from '@/store/index' +import { getWorkspaceSpaceProgressLabel } from '../workspace-space-format' import type { useWorkspaceSpaceManagerBindings } from './use-workspace-space-manager-bindings' -import type { useWorkspaceSpaceDecisionProjection } from './use-workspace-space-decision-projection' -import type { useWorkspaceSpaceGitRefreshAction } from './use-workspace-space-git-refresh-action' +import type { useWorkspaceSpaceDecisionProjection } from '../decisions/use-workspace-space-decision-projection' +import type { useWorkspaceSpaceGitRefreshAction } from '../decisions/use-workspace-space-git-refresh-action' import { useTranslate } from '@/i18n/use-translate' const GIT_STATUS_REFRESH_CONCURRENCY = 6 diff --git a/src/renderer/src/components/status-bar/workspace-space-delete-selection.ts b/src/renderer/src/components/status-bar/workspace-storage/manager/workspace-space-delete-selection.ts similarity index 87% rename from src/renderer/src/components/status-bar/workspace-space-delete-selection.ts rename to src/renderer/src/components/status-bar/workspace-storage/manager/workspace-space-delete-selection.ts index e18465ea8e1..50bcafb3b9a 100644 --- a/src/renderer/src/components/status-bar/workspace-space-delete-selection.ts +++ b/src/renderer/src/components/status-bar/workspace-storage/manager/workspace-space-delete-selection.ts @@ -1,5 +1,5 @@ -import type { WorkspaceSpaceWorktree } from '../../../../shared/workspace-disk-space/workspace-space-types' -import { composeWorktreeHostIdentity } from '../../../../shared/worktree/host-qualified-identity' +import type { WorkspaceSpaceWorktree } from '../../../../../../shared/workspace-disk-space/workspace-space-types' +import { composeWorktreeHostIdentity } from '../../../../../../shared/worktree/host-qualified-identity' /** Host-partitioned scan rows can share workspace IDs; destructive selection must preserve the row’s host. */ diff --git a/src/renderer/src/components/status-bar/workspace-space-manager-state-types.ts b/src/renderer/src/components/status-bar/workspace-storage/manager/workspace-space-manager-state-types.ts similarity index 63% rename from src/renderer/src/components/status-bar/workspace-space-manager-state-types.ts rename to src/renderer/src/components/status-bar/workspace-storage/manager/workspace-space-manager-state-types.ts index f6b1378f87f..f625ace2fc1 100644 --- a/src/renderer/src/components/status-bar/workspace-space-manager-state-types.ts +++ b/src/renderer/src/components/status-bar/workspace-storage/manager/workspace-space-manager-state-types.ts @@ -1,5 +1,5 @@ -import type { WorktreeForceDeleteReason } from '../../../../shared/worktree/removal/removal' -import type { ExecutionHostId } from '../../../../shared/execution-host' +import type { WorktreeForceDeleteReason } from '../../../../../../shared/worktree/removal/removal' +import type { ExecutionHostId } from '../../../../../../shared/execution-host' export type WorkspaceSpaceDeleteState = { isDeleting: boolean diff --git a/src/renderer/src/components/status-bar/workspace-space-presentation.ts b/src/renderer/src/components/status-bar/workspace-storage/manager/workspace-space-presentation.ts similarity index 91% rename from src/renderer/src/components/status-bar/workspace-space-presentation.ts rename to src/renderer/src/components/status-bar/workspace-storage/manager/workspace-space-presentation.ts index 18d0fac5906..3e754afe91f 100644 --- a/src/renderer/src/components/status-bar/workspace-space-presentation.ts +++ b/src/renderer/src/components/status-bar/workspace-storage/manager/workspace-space-presentation.ts @@ -1,20 +1,20 @@ import { compareDisplayName } from '@/lib/workspace/display/worktree-display-name-order' -import { detectAgentStatusFromTitle } from '../../../../shared/agent-status/title/agent-title-status' +import { detectAgentStatusFromTitle } from '../../../../../../shared/agent-status/title/agent-title-status' import { isAgentStatusFresh, AGENT_STATUS_STALE_AFTER_MS -} from '../../../../shared/agent-status/contracts/agent-status-freshness' -import { tabHasLivePty } from '../../../../shared/tab-has-live-pty' +} from '../../../../../../shared/agent-status/contracts/agent-status-freshness' +import { tabHasLivePty } from '../../../../../../shared/tab-has-live-pty' -import type { AgentStatusEntry } from '../../../../shared/agent-status/contracts/agent-status-types' -import type { MigrationUnsupportedPtyEntry } from '../../../../shared/agent-status/contracts/agent-status-ipc-payload' -import { parsePaneKey } from '../../../../shared/workspace-layout/stable-pane-id' -import type { TerminalTab } from '../../../../shared/workspace-layout/terminal-tab-types' -import { isClipboardTextByteLengthOverLimit } from '../../../../shared/clipboard-text' +import type { AgentStatusEntry } from '../../../../../../shared/agent-status/contracts/agent-status-types' +import type { MigrationUnsupportedPtyEntry } from '../../../../../../shared/agent-status/contracts/agent-status-ipc-payload' +import { parsePaneKey } from '../../../../../../shared/workspace-layout/stable-pane-id' +import type { TerminalTab } from '../../../../../../shared/workspace-layout/terminal-tab-types' +import { isClipboardTextByteLengthOverLimit } from '../../../../../../shared/clipboard-text' import type { WorkspaceSpaceItem, WorkspaceSpaceWorktree -} from '../../../../shared/workspace-disk-space/workspace-space-types' +} from '../../../../../../shared/workspace-disk-space/workspace-space-types' import { getWorkspaceSpaceWorktreeIdentity } from './workspace-space-delete-selection' export type WorkspaceSpaceSortKey = 'size' | 'name' | 'repo' | 'activity' diff --git a/src/renderer/src/components/status-bar/workspace-space-state-resolution.ts b/src/renderer/src/components/status-bar/workspace-storage/manager/workspace-space-state-resolution.ts similarity index 87% rename from src/renderer/src/components/status-bar/workspace-space-state-resolution.ts rename to src/renderer/src/components/status-bar/workspace-storage/manager/workspace-space-state-resolution.ts index a482d1f2b80..2d72dde98d0 100644 --- a/src/renderer/src/components/status-bar/workspace-space-state-resolution.ts +++ b/src/renderer/src/components/status-bar/workspace-storage/manager/workspace-space-state-resolution.ts @@ -1,5 +1,5 @@ -import type { GitStatusResult } from '../../../../shared/git/status/git-status-types' -import type { WorkspaceSpaceWorktree } from '../../../../shared/workspace-disk-space/workspace-space-types' +import type { GitStatusResult } from '../../../../../../shared/git/status/git-status-types' +import type { WorkspaceSpaceWorktree } from '../../../../../../shared/workspace-disk-space/workspace-space-types' import { getWorkspaceSpaceWorktreeIdentity } from './workspace-space-delete-selection' import type { WorkspaceSpaceDeleteState } from './workspace-space-manager-state-types' diff --git a/src/renderer/src/components/status-bar/workspace-space-visit-activity.ts b/src/renderer/src/components/status-bar/workspace-storage/manager/workspace-space-visit-activity.ts similarity index 77% rename from src/renderer/src/components/status-bar/workspace-space-visit-activity.ts rename to src/renderer/src/components/status-bar/workspace-storage/manager/workspace-space-visit-activity.ts index 7d82df47b0d..a44815af1c4 100644 --- a/src/renderer/src/components/status-bar/workspace-space-visit-activity.ts +++ b/src/renderer/src/components/status-bar/workspace-storage/manager/workspace-space-visit-activity.ts @@ -1,5 +1,5 @@ -import type { WorkspaceSpaceWorktree } from '../../../../shared/workspace-disk-space/workspace-space-types' -import { getWorkspaceLastActiveAt } from '../../../../shared/workspace-last-active' +import type { WorkspaceSpaceWorktree } from '../../../../../../shared/workspace-disk-space/workspace-space-types' +import { getWorkspaceLastActiveAt } from '../../../../../../shared/workspace-last-active' import { getWorktreeVisitTimestamp } from '@/lib/workspace/activation/worktree-visit-recency' /** Rows with visits counted as activity (switch on; `visits` is undefined otherwise). */ diff --git a/src/renderer/src/components/status-bar/workspace-space-breakdown-list.tsx b/src/renderer/src/components/status-bar/workspace-storage/overview/workspace-space-breakdown-list.tsx similarity index 93% rename from src/renderer/src/components/status-bar/workspace-space-breakdown-list.tsx rename to src/renderer/src/components/status-bar/workspace-storage/overview/workspace-space-breakdown-list.tsx index e0549adc00f..b1532a72611 100644 --- a/src/renderer/src/components/status-bar/workspace-space-breakdown-list.tsx +++ b/src/renderer/src/components/status-bar/workspace-storage/overview/workspace-space-breakdown-list.tsx @@ -2,10 +2,11 @@ import { AlertTriangle, FolderSearch, Loader2 } from 'lucide-react' import type { WorkspaceSpaceItem, WorkspaceSpaceWorktree -} from '../../../../shared/workspace-disk-space/workspace-space-types' -import type { ExecutionHostId } from '../../../../shared/execution-host' -import { formatBytes, formatCompactCount } from './workspace-space-format' -import { getLargestWorkspaceSpaceItemSize } from './workspace-space-presentation' +} from '../../../../../../shared/workspace-disk-space/workspace-space-types' +import type { ExecutionHostId } from '../../../../../../shared/execution-host' +import { formatCompactCount } from '../workspace-space-format' +import { formatBytes } from '../../../../../../shared/format-bytes' +import { getLargestWorkspaceSpaceItemSize } from '../manager/workspace-space-presentation' import { useTranslate } from '@/i18n/use-translate' import { getRevealInFileManagerLabel, @@ -17,9 +18,9 @@ import { ContextMenuContent, ContextMenuItem, ContextMenuTrigger -} from '../ui/context-menu' -import { Popover, PopoverContent, PopoverTrigger } from '../ui/popover' -import { Button } from '../ui/button' +} from '../../../ui/context-menu' +import { Popover, PopoverContent, PopoverTrigger } from '../../../ui/popover' +import { Button } from '../../../ui/button' export function WorkspaceSpaceSizeBar({ value, diff --git a/src/renderer/src/components/status-bar/workspace-space-layout.ts b/src/renderer/src/components/status-bar/workspace-storage/overview/workspace-space-layout.ts similarity index 100% rename from src/renderer/src/components/status-bar/workspace-space-layout.ts rename to src/renderer/src/components/status-bar/workspace-storage/overview/workspace-space-layout.ts diff --git a/src/renderer/src/components/status-bar/workspace-space-manager-overview.tsx b/src/renderer/src/components/status-bar/workspace-storage/overview/workspace-space-manager-overview.tsx similarity index 94% rename from src/renderer/src/components/status-bar/workspace-space-manager-overview.tsx rename to src/renderer/src/components/status-bar/workspace-storage/overview/workspace-space-manager-overview.tsx index 48c151085b3..cbccdda560f 100644 --- a/src/renderer/src/components/status-bar/workspace-space-manager-overview.tsx +++ b/src/renderer/src/components/status-bar/workspace-storage/overview/workspace-space-manager-overview.tsx @@ -1,13 +1,14 @@ import { AlertTriangle, HardDrive, Loader2, RefreshCw, X } from 'lucide-react' -import { Button } from '../ui/button' -import { Popover, PopoverContent, PopoverTrigger } from '../ui/popover' -import { formatBytes, getWorkspaceSpaceScanningFallbackLabel } from './workspace-space-format' +import { Button } from '../../../ui/button' +import { Popover, PopoverContent, PopoverTrigger } from '../../../ui/popover' +import { getWorkspaceSpaceScanningFallbackLabel } from '../workspace-space-format' +import { formatBytes } from '../../../../../../shared/format-bytes' import { useTranslate } from '@/i18n/use-translate' import { Metric, UpdatedMetric } from './workspace-space-metrics' import { WorkspaceSpaceTreemap } from './workspace-space-treemap' import { WorkspaceSpaceBreakdownList } from './workspace-space-breakdown-list' -import { getWorkspaceSpaceWorktreeIdentity } from './workspace-space-delete-selection' -import type { useWorkspaceSpaceManagerPanel } from './use-workspace-space-manager-panel' +import { getWorkspaceSpaceWorktreeIdentity } from '../manager/workspace-space-delete-selection' +import type { useWorkspaceSpaceManagerPanel } from '../manager/use-workspace-space-manager-panel' type WorkspaceSpaceManagerModel = ReturnType diff --git a/src/renderer/src/components/status-bar/workspace-space-metrics.tsx b/src/renderer/src/components/status-bar/workspace-storage/overview/workspace-space-metrics.tsx similarity index 98% rename from src/renderer/src/components/status-bar/workspace-space-metrics.tsx rename to src/renderer/src/components/status-bar/workspace-storage/overview/workspace-space-metrics.tsx index c4da24bfda0..1c26d410a1d 100644 --- a/src/renderer/src/components/status-bar/workspace-space-metrics.tsx +++ b/src/renderer/src/components/status-bar/workspace-storage/overview/workspace-space-metrics.tsx @@ -4,7 +4,7 @@ import { useIntlLocale, useTranslate } from '@/i18n/use-translate' import { getWorkspaceSpaceScanDateTimeLabel, getWorkspaceSpaceScanTimeLabel -} from './workspace-space-format' +} from '../workspace-space-format' import { formatShortTimeAgo } from '@/lib/time-format/short-time-ago' export function Metric({ diff --git a/src/renderer/src/components/status-bar/workspace-space-treemap.tsx b/src/renderer/src/components/status-bar/workspace-storage/overview/workspace-space-treemap.tsx similarity index 95% rename from src/renderer/src/components/status-bar/workspace-space-treemap.tsx rename to src/renderer/src/components/status-bar/workspace-storage/overview/workspace-space-treemap.tsx index b5f418f11a0..f54bd70f208 100644 --- a/src/renderer/src/components/status-bar/workspace-space-treemap.tsx +++ b/src/renderer/src/components/status-bar/workspace-storage/overview/workspace-space-treemap.tsx @@ -1,11 +1,11 @@ import { useMemo } from 'react' import { Loader2, ZoomIn, ZoomOut } from 'lucide-react' -import type { WorkspaceSpaceWorktree } from '../../../../shared/workspace-disk-space/workspace-space-types' +import type { WorkspaceSpaceWorktree } from '../../../../../../shared/workspace-disk-space/workspace-space-types' import { cn } from '@/lib/class-names' -import { Button } from '../ui/button' -import { formatBytes } from './workspace-space-format' +import { Button } from '../../../ui/button' +import { formatBytes } from '../../../../../../shared/format-bytes' import { buildTreemapLayout, type TreemapRect } from './workspace-space-layout' -import { getWorkspaceSpaceWorktreeIdentity } from './workspace-space-delete-selection' +import { getWorkspaceSpaceWorktreeIdentity } from '../manager/workspace-space-delete-selection' import { useTranslate } from '@/i18n/use-translate' const TREEMAP_FILLS = [ diff --git a/src/renderer/src/components/status-bar/workspace-space-changes.tsx b/src/renderer/src/components/status-bar/workspace-storage/table/workspace-space-changes.tsx similarity index 85% rename from src/renderer/src/components/status-bar/workspace-space-changes.tsx rename to src/renderer/src/components/status-bar/workspace-storage/table/workspace-space-changes.tsx index 7d462d69988..83c3a745dad 100644 --- a/src/renderer/src/components/status-bar/workspace-space-changes.tsx +++ b/src/renderer/src/components/status-bar/workspace-storage/table/workspace-space-changes.tsx @@ -1,15 +1,15 @@ import { useMemo, useState } from 'react' import { ChevronRight } from 'lucide-react' -import type { GitStatusEntry } from '../../../../shared/git/status/git-status-types' -import type { WorkspaceSpaceWorktree } from '../../../../shared/workspace-disk-space/workspace-space-types' -import { FileTypeIcon } from '../FileTypeIcon' -import { VirtualizedList } from '../virtualized-list' -import { Badge } from '../ui/badge' -import { Input } from '../ui/input' -import { Popover, PopoverContent, PopoverTrigger } from '../ui/popover' -import { STATUS_COLORS } from '../../lib/source-control/paths/git-path-decoration' -import { STATUS_LABELS } from '../../../../shared/git/status/git-status-labels' -import { DiffLineCounts } from '../right-sidebar/source-control/listing/diff-line-counts' +import type { GitStatusEntry } from '../../../../../../shared/git/status/git-status-types' +import type { WorkspaceSpaceWorktree } from '../../../../../../shared/workspace-disk-space/workspace-space-types' +import { FileTypeIcon } from '../../../FileTypeIcon' +import { VirtualizedList } from '../../../virtualized-list' +import { Badge } from '../../../ui/badge' +import { Input } from '../../../ui/input' +import { Popover, PopoverContent, PopoverTrigger } from '../../../ui/popover' +import { STATUS_COLORS } from '../../../../lib/source-control/paths/git-path-decoration' +import { STATUS_LABELS } from '../../../../../../shared/git/status/git-status-labels' +import { DiffLineCounts } from '../../../right-sidebar/source-control/listing/diff-line-counts' import { openWorkspaceSpaceChange } from './workspace-space-open-change' import { useTranslate } from '@/i18n/use-translate' diff --git a/src/renderer/src/components/status-bar/workspace-space-manager-table.tsx b/src/renderer/src/components/status-bar/workspace-storage/table/workspace-space-manager-table.tsx similarity index 97% rename from src/renderer/src/components/status-bar/workspace-space-manager-table.tsx rename to src/renderer/src/components/status-bar/workspace-storage/table/workspace-space-manager-table.tsx index 5c1339ed413..eb2631a8f3c 100644 --- a/src/renderer/src/components/status-bar/workspace-space-manager-table.tsx +++ b/src/renderer/src/components/status-bar/workspace-storage/table/workspace-space-manager-table.tsx @@ -1,13 +1,13 @@ import { useState } from 'react' import { Loader2 } from 'lucide-react' -import { VirtualizedList } from '../virtualized-list' +import { VirtualizedList } from '../../../virtualized-list' import { activateAndRevealWorktree } from '@/lib/workspace/activation/worktree-activation' import { useTranslate } from '@/i18n/use-translate' import { cn } from '@/lib/class-names' import { CheckButton, SortIndicator } from './workspace-space-selection-controls' import { WorkspaceSpaceWorktreeRow } from './workspace-space-worktree-row' -import { getWorkspaceSpaceWorktreeIdentity } from './workspace-space-delete-selection' -import type { useWorkspaceSpaceManagerPanel } from './use-workspace-space-manager-panel' +import { getWorkspaceSpaceWorktreeIdentity } from '../manager/workspace-space-delete-selection' +import type { useWorkspaceSpaceManagerPanel } from '../manager/use-workspace-space-manager-panel' import { WORKSPACE_SPACE_TABLE_GRID_CLASS } from './workspace-space-table-layout' type WorkspaceSpaceManagerModel = ReturnType diff --git a/src/renderer/src/components/status-bar/workspace-space-open-change.ts b/src/renderer/src/components/status-bar/workspace-storage/table/workspace-space-open-change.ts similarity index 83% rename from src/renderer/src/components/status-bar/workspace-space-open-change.ts rename to src/renderer/src/components/status-bar/workspace-storage/table/workspace-space-open-change.ts index 2f58dc77108..1b1995d56f3 100644 --- a/src/renderer/src/components/status-bar/workspace-space-open-change.ts +++ b/src/renderer/src/components/status-bar/workspace-storage/table/workspace-space-open-change.ts @@ -1,15 +1,18 @@ import { toast } from 'sonner' -import { LOCAL_EXECUTION_HOST_ID, type ExecutionHostId } from '../../../../shared/execution-host' -import type { GitStatusEntry } from '../../../../shared/git/status/git-status-types' -import type { WorkspaceSpaceWorktree } from '../../../../shared/workspace-disk-space/workspace-space-types' -import type { WorkspaceSpaceChange } from '../../../../shared/workspace-disk-space/workspace-space-change' -import { useAppStore } from '@/store' +import { + LOCAL_EXECUTION_HOST_ID, + type ExecutionHostId +} from '../../../../../../shared/execution-host' +import type { GitStatusEntry } from '../../../../../../shared/git/status/git-status-types' +import type { WorkspaceSpaceWorktree } from '../../../../../../shared/workspace-disk-space/workspace-space-types' +import type { WorkspaceSpaceChange } from '../../../../../../shared/workspace-disk-space/workspace-space-change' +import { useAppStore } from '@/store/index' import { getWorktreeOnHostFromState } from '@/store/workspaces/selection/worktree-on-host-selector' import { repoMatchesHostIdentity } from '@/store/repos/repo-host-identity' import { activateAndRevealWorktree } from '@/lib/workspace/activation/worktree-activation' import { getRuntimeGitStatus } from '@/runtime/source-control/git/runtime-git-status-client' import { ipcOrRuntimeTargetForHostId } from '@/runtime/rpc/targets/runtime-client-target' -import { openUncommittedEntry } from '../right-sidebar/source-control/listing/open-uncommitted-entry' +import { openUncommittedEntry } from '../../../right-sidebar/source-control/listing/open-uncommitted-entry' import { translate } from '@/i18n/i18n' export function openWorkspaceSpaceChange( diff --git a/src/renderer/src/components/status-bar/workspace-space-selection-controls.tsx b/src/renderer/src/components/status-bar/workspace-storage/table/workspace-space-selection-controls.tsx similarity index 97% rename from src/renderer/src/components/status-bar/workspace-space-selection-controls.tsx rename to src/renderer/src/components/status-bar/workspace-storage/table/workspace-space-selection-controls.tsx index e32d19b4823..98f805499aa 100644 --- a/src/renderer/src/components/status-bar/workspace-space-selection-controls.tsx +++ b/src/renderer/src/components/status-bar/workspace-storage/table/workspace-space-selection-controls.tsx @@ -3,7 +3,7 @@ import { cn } from '@/lib/class-names' import type { WorkspaceSpaceSortDirection, WorkspaceSpaceSortKey -} from './workspace-space-presentation' +} from '../manager/workspace-space-presentation' export function CheckButton({ checked, diff --git a/src/renderer/src/components/status-bar/workspace-space-table-layout.ts b/src/renderer/src/components/status-bar/workspace-storage/table/workspace-space-table-layout.ts similarity index 100% rename from src/renderer/src/components/status-bar/workspace-space-table-layout.ts rename to src/renderer/src/components/status-bar/workspace-storage/table/workspace-space-table-layout.ts diff --git a/src/renderer/src/components/status-bar/workspace-space-worktree-actions.tsx b/src/renderer/src/components/status-bar/workspace-storage/table/workspace-space-worktree-actions.tsx similarity index 90% rename from src/renderer/src/components/status-bar/workspace-space-worktree-actions.tsx rename to src/renderer/src/components/status-bar/workspace-storage/table/workspace-space-worktree-actions.tsx index 06ed69e9ebb..f3132fc4cc9 100644 --- a/src/renderer/src/components/status-bar/workspace-space-worktree-actions.tsx +++ b/src/renderer/src/components/status-bar/workspace-storage/table/workspace-space-worktree-actions.tsx @@ -1,20 +1,20 @@ import { useState } from 'react' import { Ellipsis, FolderSearch, Trash2 } from 'lucide-react' -import type { WorkspaceSpaceWorktree } from '../../../../shared/workspace-disk-space/workspace-space-types' +import type { WorkspaceSpaceWorktree } from '../../../../../../shared/workspace-disk-space/workspace-space-types' import { useTranslate } from '@/i18n/use-translate' import { getRevealInFileManagerLabel, revealInFileManager } from '@/lib/files/os-open/reveal-in-file-manager' -import { Button } from '../ui/button' -import { ContextMenuItem } from '../ui/context-menu' +import { Button } from '../../../ui/button' +import { ContextMenuItem } from '../../../ui/context-menu' import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger -} from '../ui/dropdown-menu' -import { Tooltip, TooltipContent, TooltipTrigger } from '../ui/tooltip' +} from '../../../ui/dropdown-menu' +import { Tooltip, TooltipContent, TooltipTrigger } from '../../../ui/tooltip' type WorkspaceSpaceWorktreeActionProps = { worktree: WorkspaceSpaceWorktree diff --git a/src/renderer/src/components/status-bar/workspace-space-worktree-row.tsx b/src/renderer/src/components/status-bar/workspace-storage/table/workspace-space-worktree-row.tsx similarity index 88% rename from src/renderer/src/components/status-bar/workspace-space-worktree-row.tsx rename to src/renderer/src/components/status-bar/workspace-storage/table/workspace-space-worktree-row.tsx index be83881936c..012d8fac082 100644 --- a/src/renderer/src/components/status-bar/workspace-space-worktree-row.tsx +++ b/src/renderer/src/components/status-bar/workspace-storage/table/workspace-space-worktree-row.tsx @@ -1,32 +1,32 @@ import { AlertTriangle, GitBranch, Server, Trash2 } from 'lucide-react' import { useState } from 'react' -import type { WorkspaceSpaceWorktree } from '../../../../shared/workspace-disk-space/workspace-space-types' -import type { GitStatusEntry } from '../../../../shared/git/status/git-status-types' +import type { WorkspaceSpaceWorktree } from '../../../../../../shared/workspace-disk-space/workspace-space-types' +import type { GitStatusEntry } from '../../../../../../shared/git/status/git-status-types' import { cn } from '@/lib/class-names' -import { Badge } from '../ui/badge' -import { Button } from '../ui/button' -import { ContextMenu, ContextMenuContent, ContextMenuTrigger } from '../ui/context-menu' +import { Badge } from '../../../ui/badge' +import { Button } from '../../../ui/button' +import { ContextMenu, ContextMenuContent, ContextMenuTrigger } from '../../../ui/context-menu' import { isPortaledRowMenuClick, isRowActivationKey } from '@/lib/list-interaction/list-row-interaction' -import { HoverCard, HoverCardTrigger } from '../ui/hover-card' +import { HoverCard, HoverCardTrigger } from '../../../ui/hover-card' import { - formatBytes, getWorkspaceSpaceBranchLabel, getWorkspaceSpaceScanDateTimeLabel -} from './workspace-space-format' -import { isWorkspaceSpaceRowReadyToDelete } from './workspace-space-presentation' +} from '../workspace-space-format' +import { formatBytes } from '../../../../../../shared/format-bytes' +import { isWorkspaceSpaceRowReadyToDelete } from '../manager/workspace-space-presentation' import { useIntlLocale, useTranslate } from '@/i18n/use-translate' -import type { WorkspaceDecisionDetails } from './workspace-space-decision-details' +import type { WorkspaceDecisionDetails } from '../decisions/workspace-space-decision-details' import type { WorkspaceGitRefreshState, WorkspaceSpaceDeleteState -} from './workspace-space-manager-state-types' +} from '../manager/workspace-space-manager-state-types' import { CheckButton } from './workspace-space-selection-controls' -import { WorkspaceDecisionHoverCard } from './workspace-space-decision-hover-card' -import { WorkspaceSpaceStatusBadge } from './workspace-space-status-badge' -import { describeWorktreeDeleteError } from '../sidebar/workspace-actions/deletion/worktree-delete-error-display' +import { WorkspaceDecisionHoverCard } from '../decisions/workspace-space-decision-hover-card' +import { WorkspaceSpaceStatusBadge } from '../decisions/workspace-space-status-badge' +import { describeWorktreeDeleteError } from '../../../sidebar/workspace-actions/deletion/worktree-delete-error-display' import { formatShortTimeAgo } from '@/lib/time-format/short-time-ago' import { WorkspaceSpaceChanges } from './workspace-space-changes' import { WORKSPACE_SPACE_TABLE_GRID_CLASS } from './workspace-space-table-layout' diff --git a/src/renderer/src/components/status-bar/workspace-space-format.ts b/src/renderer/src/components/status-bar/workspace-storage/workspace-space-format.ts similarity index 96% rename from src/renderer/src/components/status-bar/workspace-space-format.ts rename to src/renderer/src/components/status-bar/workspace-storage/workspace-space-format.ts index d9fb9534fa6..62e1866217d 100644 --- a/src/renderer/src/components/status-bar/workspace-space-format.ts +++ b/src/renderer/src/components/status-bar/workspace-storage/workspace-space-format.ts @@ -2,14 +2,12 @@ import type { WorkspaceSpaceScanProgress, WorkspaceSpaceScanStatus, WorkspaceSpaceWorktree -} from '../../../../shared/workspace-disk-space/workspace-space-types' +} from '../../../../../shared/workspace-disk-space/workspace-space-types' import { formatUiRelativeTime } from '@/i18n/relative-time-format' import { translate } from '@/i18n/i18n' import type { Translate } from '@/i18n/use-translate' import { uiDateTimeFormat } from '@/i18n/ui-intl-formatters' -export { formatBytes } from '../../../../shared/format-bytes' - const FULL_DATE_TIME_OPTIONS: Intl.DateTimeFormatOptions = { dateStyle: 'medium', timeStyle: 'short' diff --git a/src/renderer/src/components/status-bar/workspace-space-manager-toolbar.tsx b/src/renderer/src/components/status-bar/workspace-storage/workspace-space-manager-toolbar.tsx similarity index 94% rename from src/renderer/src/components/status-bar/workspace-space-manager-toolbar.tsx rename to src/renderer/src/components/status-bar/workspace-storage/workspace-space-manager-toolbar.tsx index b5e1742dcf9..fc3abbe2223 100644 --- a/src/renderer/src/components/status-bar/workspace-space-manager-toolbar.tsx +++ b/src/renderer/src/components/status-bar/workspace-storage/workspace-space-manager-toolbar.tsx @@ -1,11 +1,11 @@ import { Check, Trash2 } from 'lucide-react' -import { Button } from '../ui/button' -import { Input } from '../ui/input' -import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '../ui/select' -import { formatBytes } from './workspace-space-format' +import { Button } from '../../ui/button' +import { Input } from '../../ui/input' +import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '../../ui/select' +import { formatBytes } from '../../../../../shared/format-bytes' import { useTranslate } from '@/i18n/use-translate' -import type { WorkspaceSpaceSortKey } from './workspace-space-presentation' -import type { useWorkspaceSpaceManagerPanel } from './use-workspace-space-manager-panel' +import type { WorkspaceSpaceSortKey } from './manager/workspace-space-presentation' +import type { useWorkspaceSpaceManagerPanel } from './manager/use-workspace-space-manager-panel' type WorkspaceSpaceManagerModel = ReturnType diff --git a/src/renderer/src/components/status-bar/workspace-space-manager-view.tsx b/src/renderer/src/components/status-bar/workspace-storage/workspace-space-manager-view.tsx similarity index 65% rename from src/renderer/src/components/status-bar/workspace-space-manager-view.tsx rename to src/renderer/src/components/status-bar/workspace-storage/workspace-space-manager-view.tsx index 642882fa137..326d562ad62 100644 --- a/src/renderer/src/components/status-bar/workspace-space-manager-view.tsx +++ b/src/renderer/src/components/status-bar/workspace-storage/workspace-space-manager-view.tsx @@ -1,7 +1,7 @@ -import type { useWorkspaceSpaceManagerPanel } from './use-workspace-space-manager-panel' -import { WorkspaceSpaceManagerOverview } from './workspace-space-manager-overview' +import type { useWorkspaceSpaceManagerPanel } from './manager/use-workspace-space-manager-panel' +import { WorkspaceSpaceManagerOverview } from './overview/workspace-space-manager-overview' import { WorkspaceSpaceManagerToolbar } from './workspace-space-manager-toolbar' -import { WorkspaceSpaceManagerTable } from './workspace-space-manager-table' +import { WorkspaceSpaceManagerTable } from './table/workspace-space-manager-table' type WorkspaceSpaceManagerModel = ReturnType diff --git a/src/renderer/src/components/workspace-space/SpaceWindowStatePublisher.tsx b/src/renderer/src/components/workspace-space/SpaceWindowStatePublisher.tsx index 5059a88447d..bd0a8d34c7e 100644 --- a/src/renderer/src/components/workspace-space/SpaceWindowStatePublisher.tsx +++ b/src/renderer/src/components/workspace-space/SpaceWindowStatePublisher.tsx @@ -1,13 +1,13 @@ import { useEffect } from 'react' -import { useAppStore } from '@/store' +import { useAppStore } from '@/store/index' import { activateAndRevealWorktree } from '@/lib/workspace/activation/worktree-activation' import { pickSpaceWindowState, spaceWindowStateChanged, type SpaceWindowState } from './space-window-state' -import { revealWorkspaceSpaceChange } from '../status-bar/workspace-space-open-change' -import { refreshLinkedIssueForWorktree } from '../status-bar/workspace-space-issue-freshness' +import { revealWorkspaceSpaceChange } from '../status-bar/workspace-storage/table/workspace-space-open-change' +import { refreshLinkedIssueForWorktree } from '../status-bar/workspace-storage/decisions/workspace-space-issue-freshness' export function SpaceWindowStatePublisher(): null { useEffect(() => { diff --git a/src/renderer/src/components/workspace-space/WorkspaceSpacePage.tsx b/src/renderer/src/components/workspace-space/WorkspaceSpacePage.tsx index 33180e395bc..3578bfe98fe 100644 --- a/src/renderer/src/components/workspace-space/WorkspaceSpacePage.tsx +++ b/src/renderer/src/components/workspace-space/WorkspaceSpacePage.tsx @@ -1,7 +1,7 @@ import { ArrowLeft } from 'lucide-react' import { Button } from '../ui/button' -import { WorkspaceSpaceManagerPanel } from '../status-bar/WorkspaceSpaceManagerPanel' -import { useAppStore } from '../../store' +import { WorkspaceSpaceManagerPanel } from '../status-bar/workspace-storage/WorkspaceSpaceManagerPanel' +import { useAppStore } from '../../store/index' import { useTranslate } from '@/i18n/use-translate' export default function WorkspaceSpacePage(): React.JSX.Element { diff --git a/src/renderer/src/lib/agent-catalog/agent-catalog.ts b/src/renderer/src/lib/agent-catalog/agent-catalog.ts index a4b2aefa8d5..baa2ce4299e 100644 --- a/src/renderer/src/lib/agent-catalog/agent-catalog.ts +++ b/src/renderer/src/lib/agent-catalog/agent-catalog.ts @@ -1,4 +1,4 @@ -import '@/components/status-bar/icons' +import '@/components/status-bar/accounts/provider-icons' import type { TuiAgent } from '../../../../shared/agent-launch/catalog/tui-agent' import type { TerminalAgent } from '../../../../shared/agent-status/identity/terminal-agent' import { formatAgentTypeLabel } from '../../../../shared/agent-status/presentation/agent-type-label' diff --git a/src/renderer/src/runtime/hosts/wsl/wsl-host-user-start.ts b/src/renderer/src/runtime/hosts/wsl/wsl-host-user-start.ts index 42efe3f6e07..bfff4a63336 100644 --- a/src/renderer/src/runtime/hosts/wsl/wsl-host-user-start.ts +++ b/src/renderer/src/runtime/hosts/wsl/wsl-host-user-start.ts @@ -33,7 +33,7 @@ export function startWslHostAndReloadProjects(environmentId: string): Promise {