From 29ce30b73e09cbfdf92e43cdf32d29c3753f7885 Mon Sep 17 00:00:00 2001 From: Cyrus Gray <144336577+graycyrus@users.noreply.github.com> Date: Fri, 12 Jun 2026 00:22:14 +0530 Subject: [PATCH] fix(settings): unify settings navigation + enforce panel UI contract (#3599) --- .github/workflows/pr-ci.yml | 19 + .../dashboard/CostDashboardPanel.tsx | 111 ++- app/src/components/settings/SettingsHome.tsx | 286 ++++--- .../settings/__tests__/SettingsHome.test.tsx | 97 ++- .../__tests__/settingsRouteRegistry.test.ts | 188 +++++ .../settings/controls/SettingsBadge.tsx | 36 + .../settings/controls/SettingsCheckbox.tsx | 52 ++ .../settings/controls/SettingsEmptyState.tsx | 17 + .../settings/controls/SettingsListItem.tsx | 50 ++ .../settings/controls/SettingsNumberField.tsx | 84 ++ .../settings/controls/SettingsRow.tsx | 67 ++ .../settings/controls/SettingsSection.tsx | 35 + .../settings/controls/SettingsSelect.tsx | 51 ++ .../settings/controls/SettingsStatusLine.tsx | 57 ++ .../settings/controls/SettingsSwitch.tsx | 52 ++ .../settings/controls/SettingsTextArea.tsx | 34 + .../settings/controls/SettingsTextField.tsx | 18 + .../controls/__tests__/controls.test.tsx | 180 ++++ app/src/components/settings/controls/index.ts | 35 + .../useSettingsNavigation.coverage.test.tsx | 235 ++++++ .../__tests__/useSettingsNavigation.test.tsx | 12 +- .../settings/hooks/useSettingsNavigation.ts | 443 +++++----- .../components/settings/panels/AIPanel.tsx | 591 +++++++------ .../components/settings/panels/AboutPanel.tsx | 208 +++-- .../settings/panels/AgentAccessPanel.tsx | 350 ++++---- .../settings/panels/AgentActivityPanel.tsx | 37 +- .../settings/panels/AgentChatPanel.tsx | 134 +-- .../settings/panels/AgentEditorPage.test.tsx | 96 +++ .../settings/panels/AgentEditorPage.tsx | 434 +++++----- .../settings/panels/AgentsPanel.tsx | 83 +- .../settings/panels/AppearancePanel.tsx | 103 +-- .../settings/panels/ApprovalHistoryPanel.tsx | 143 ++-- .../panels/AutocompleteDebugPanel.tsx | 504 +++++------ .../settings/panels/AutocompletePanel.tsx | 268 +++--- .../settings/panels/AutonomyPanel.tsx | 142 ++-- .../settings/panels/BillingPanel.tsx | 27 +- .../settings/panels/CompanionPanel.tsx | 184 +++-- .../settings/panels/ComposioPanel.tsx | 176 ++-- .../settings/panels/ComposioTriagePanel.tsx | 122 ++- .../settings/panels/CronJobsPanel.tsx | 89 +- .../settings/panels/DevWorkflowPanel.tsx | 264 +++--- .../settings/panels/DeveloperOptionsPanel.tsx | 575 +++---------- .../settings/panels/DevicesPanel.tsx | 166 ++-- .../settings/panels/EmbeddingsPanel.tsx | 320 +++---- .../settings/panels/EventLogPanel.tsx | 60 +- .../settings/panels/HeartbeatPanel.tsx | 17 +- .../settings/panels/LedgerUsagePanel.tsx | 17 +- .../settings/panels/LocalModelDebugPanel.tsx | 6 +- .../settings/panels/MascotPanel.tsx | 157 ++-- .../settings/panels/McpServerPanel.test.tsx | 25 + .../settings/panels/McpServerPanel.tsx | 170 ++-- .../settings/panels/MemoryDataPanel.tsx | 16 +- .../settings/panels/MemoryDebugPanel.tsx | 448 +++++----- .../settings/panels/MemorySyncPanel.tsx | 6 +- .../settings/panels/MigrationPanel.tsx | 167 ++-- .../settings/panels/ModelHealthPanel.tsx | 45 +- .../panels/NotificationRoutingPanel.tsx | 223 +++-- .../settings/panels/NotificationsPanel.tsx | 133 ++- .../panels/NotificationsTabbedPanel.tsx | 8 +- .../settings/panels/PermissionsPanel.tsx | 74 +- .../settings/panels/PersonaPanel.tsx | 192 ++--- .../settings/panels/PrivacyPanel.tsx | 278 +++---- .../settings/panels/RecoveryPhrasePanel.tsx | 58 +- .../settings/panels/SandboxSettingsPanel.tsx | 365 ++++---- .../panels/ScreenAwarenessDebugPanel.tsx | 274 +++--- .../panels/ScreenIntelligencePanel.tsx | 184 +++-- .../settings/panels/SearchPanel.tsx | 71 +- .../settings/panels/SecurityPanel.tsx | 151 ++-- .../settings/panels/TaskSourcesPanel.test.tsx | 48 ++ .../settings/panels/TaskSourcesPanel.tsx | 330 ++++---- .../components/settings/panels/TasksPanel.tsx | 4 +- .../settings/panels/TeamInvitesPanel.tsx | 209 +++-- .../settings/panels/TeamManagementPanel.tsx | 479 +++++------ .../settings/panels/TeamMembersPanel.tsx | 386 ++++----- .../components/settings/panels/TeamPanel.tsx | 270 +++--- .../panels/ToolPolicyDiagnosticsPanel.tsx | 11 +- .../settings/panels/ToolsPanel.test.tsx | 27 + .../components/settings/panels/ToolsPanel.tsx | 98 +-- .../settings/panels/VoiceDebugPanel.tsx | 288 +++---- .../components/settings/panels/VoicePanel.tsx | 782 +++++++++--------- .../settings/panels/WalletBalancesPanel.tsx | 72 +- .../settings/panels/WebhooksDebugPanel.tsx | 281 ++++--- .../settings/panels/WorkflowRunnerPanel.tsx | 2 +- .../__tests__/AgentAccessPanel.test.tsx | 20 +- .../panels/__tests__/AgentChatPanel.test.tsx | 191 +++++ .../__tests__/AutocompleteDebugPanel.test.tsx | 566 +++++++++++++ .../__tests__/AutocompletePanel.test.tsx | 138 +++- .../panels/__tests__/AutonomyPanel.test.tsx | 82 ++ .../__tests__/DeveloperOptionsPanel.test.tsx | 4 +- .../panels/__tests__/DevicesPanel.test.tsx | 28 +- .../panels/__tests__/EmbeddingsPanel.test.tsx | 709 ++++++++++++++++ .../__tests__/LocalModelDebugPanel.test.tsx | 184 ++++- .../panels/__tests__/MascotPanel.test.tsx | 76 +- .../__tests__/MemoryDebugPanel.test.tsx | 351 +++++++- .../__tests__/RecoveryPhrasePanel.test.tsx | 4 +- .../__tests__/SandboxSettingsPanel.test.tsx | 98 ++- .../ScreenAwarenessDebugPanel.test.tsx | 312 +++++++ .../ScreenIntelligencePanel.test.tsx | 157 +++- .../panels/__tests__/SecurityPanel.test.tsx | 237 ++++++ .../__tests__/TeamInvitesPanel.test.tsx | 218 ++++- .../__tests__/TeamManagementPanel.test.tsx | 251 ++++++ .../__tests__/TeamMembersPanel.test.tsx | 315 ++++++- .../panels/__tests__/TeamPanel.test.tsx | 289 ++++++- .../panels/__tests__/VoiceDebugPanel.test.tsx | 175 +++- .../panels/__tests__/VoicePanel.test.tsx | 379 +++++++++ .../__tests__/WebhooksDebugPanel.test.tsx | 317 ++++++- .../panels/autocomplete/AppFilterSection.tsx | 26 +- .../autocomplete/CompletionStyleSection.tsx | 70 +- .../panels/billing/AutoRechargeSection.tsx | 139 ++-- .../panels/billing/PayAsYouGoCard.tsx | 55 +- .../panels/billing/SubscriptionPlans.tsx | 55 +- .../__tests__/AutoRechargeSection.test.tsx | 294 +++++++ .../__tests__/SubscriptionPlans.test.tsx | 97 +++ .../panels/devices/PairPhoneModal.tsx | 108 ++- .../local-model/ModelDownloadSection.test.tsx | 119 +++ .../local-model/ModelDownloadSection.tsx | 217 ++--- .../local-model/ModelStatusSection.test.tsx | 145 +++- .../panels/local-model/ModelStatusSection.tsx | 181 ++-- .../settings/search/settingsSearchRegistry.ts | 572 ++----------- .../settings/settingsRouteRegistry.ts | 622 ++++++++++++++ app/src/pages/Intelligence.tsx | 40 +- app/src/pages/Settings.tsx | 45 +- app/src/pages/Webhooks.tsx | 138 ++-- app/src/pages/__tests__/Webhooks.test.tsx | 202 +++++ .../pages/settings/voice/PttSettingsPanel.tsx | 168 ++-- .../specs/autocomplete-flow.spec.ts | 4 +- .../specs/settings-advanced-config.spec.ts | 8 +- .../specs/settings-ai-skills.spec.ts | 2 +- .../settings-feature-preferences.spec.ts | 13 +- .../specs/settings-leaf-workflows.spec.ts | 2 +- 130 files changed, 14504 insertions(+), 7526 deletions(-) create mode 100644 app/src/components/settings/__tests__/settingsRouteRegistry.test.ts create mode 100644 app/src/components/settings/controls/SettingsBadge.tsx create mode 100644 app/src/components/settings/controls/SettingsCheckbox.tsx create mode 100644 app/src/components/settings/controls/SettingsEmptyState.tsx create mode 100644 app/src/components/settings/controls/SettingsListItem.tsx create mode 100644 app/src/components/settings/controls/SettingsNumberField.tsx create mode 100644 app/src/components/settings/controls/SettingsRow.tsx create mode 100644 app/src/components/settings/controls/SettingsSection.tsx create mode 100644 app/src/components/settings/controls/SettingsSelect.tsx create mode 100644 app/src/components/settings/controls/SettingsStatusLine.tsx create mode 100644 app/src/components/settings/controls/SettingsSwitch.tsx create mode 100644 app/src/components/settings/controls/SettingsTextArea.tsx create mode 100644 app/src/components/settings/controls/SettingsTextField.tsx create mode 100644 app/src/components/settings/controls/__tests__/controls.test.tsx create mode 100644 app/src/components/settings/controls/index.ts create mode 100644 app/src/components/settings/hooks/__tests__/useSettingsNavigation.coverage.test.tsx create mode 100644 app/src/components/settings/panels/__tests__/AgentChatPanel.test.tsx create mode 100644 app/src/components/settings/panels/__tests__/AutocompleteDebugPanel.test.tsx create mode 100644 app/src/components/settings/panels/__tests__/EmbeddingsPanel.test.tsx create mode 100644 app/src/components/settings/panels/__tests__/ScreenAwarenessDebugPanel.test.tsx create mode 100644 app/src/components/settings/panels/__tests__/SecurityPanel.test.tsx create mode 100644 app/src/components/settings/panels/__tests__/TeamManagementPanel.test.tsx create mode 100644 app/src/components/settings/panels/billing/__tests__/AutoRechargeSection.test.tsx create mode 100644 app/src/components/settings/panels/billing/__tests__/SubscriptionPlans.test.tsx create mode 100644 app/src/components/settings/settingsRouteRegistry.ts create mode 100644 app/src/pages/__tests__/Webhooks.test.tsx diff --git a/.github/workflows/pr-ci.yml b/.github/workflows/pr-ci.yml index 5fa1035fe..29d1ed79a 100644 --- a/.github/workflows/pr-ci.yml +++ b/.github/workflows/pr-ci.yml @@ -296,6 +296,14 @@ jobs: image: ghcr.io/tinyhumansai/openhuman_ci:rust-1.93.0 env: CARGO_INCREMENTAL: "0" + # Coverage-instrumented test binaries are dominated by DWARF debug info, + # which exhausts the runner disk and SIGBUSes the linker. Drop debug info + # entirely for this job — llvm-cov line/region coverage is read from the + # embedded __llvm_covmap/__llvm_covfun sections (filenames + line numbers + # included), NOT from DWARF, so coverage numbers are unaffected. This is + # the maximum-shrink setting; line-tables-only was still too large for the + # instrumented build. + CARGO_PROFILE_DEV_DEBUG: "0" steps: - name: Free disk space run: | @@ -410,7 +418,18 @@ jobs: timeout-minutes: 30 env: CARGO_INCREMENTAL: "0" + # Trim DWARF debug info so test-binary linking doesn't exhaust runner disk + # (SIGBUS). Tests don't need full debug info; backtraces keep file/line. + CARGO_PROFILE_DEV_DEBUG: line-tables-only steps: + - name: Free disk space + run: | + # Reclaim space on the build partition before compiling/linking the + # Rust test binaries (host toolcache is bind-mounted at /__t inside the + # container). Mirrors the rust-core-coverage cleanup. + rm -rf /__t/* || true + df -h /__w || true + - name: Checkout code uses: actions/checkout@v5 with: diff --git a/app/src/components/dashboard/CostDashboardPanel.tsx b/app/src/components/dashboard/CostDashboardPanel.tsx index 2a41b99a6..65631b0f3 100644 --- a/app/src/components/dashboard/CostDashboardPanel.tsx +++ b/app/src/components/dashboard/CostDashboardPanel.tsx @@ -8,7 +8,9 @@ import { } from '../../hooks/useCostDashboard'; import { useT } from '../../lib/i18n/I18nContext'; import SettingsHeader from '../settings/components/SettingsHeader'; +import { SettingsStatusLine } from '../settings/controls'; import { useSettingsNavigation } from '../settings/hooks/useSettingsNavigation'; +import Button from '../ui/Button'; import BudgetSummary from './BudgetSummary'; import CostBarChart from './CostBarChart'; import DashboardSkeleton from './DashboardSkeleton'; @@ -52,14 +54,14 @@ const CostDashboardPanel = () => { />
+
{t('settings.costDashboard.subtitle')}
+
{t('settings.costDashboard.modelBreakdownHint')}
+
{t('settings.costDashboard.categoryDistributionHint')}
+
{usageLog ? t('settings.costDashboard.usageLogHint') .replace('{days}', String(usageLog.days)) @@ -205,7 +204,7 @@ const CostDashboardPanel = () => {
| {t('settings.costDashboard.when')} | {t('settings.costDashboard.category')} | {t('settings.costDashboard.model')} | @@ -341,34 +340,34 @@ const UsageLogTable = ({ records, currency }: { records: CostUsageRecord[]; curr {records.map(record => (||||
|---|---|---|---|---|---|---|
|
-
+
{formatDateTime(record.timestamp)}
|
- + {record.category} |
-
+
{record.model}
-
+
{record.provider ?? t('settings.costDashboard.unknownProvider')}
|
{formatTokens(record.input_tokens)} | {formatTokens(record.output_tokens)} | - + {formatCurrency(record.cost_usd, currency)} | - + {shortId(record.session_id)} | diff --git a/app/src/components/settings/SettingsHome.tsx b/app/src/components/settings/SettingsHome.tsx index 5108667d0..974192e9c 100644 --- a/app/src/components/settings/SettingsHome.tsx +++ b/app/src/components/settings/SettingsHome.tsx @@ -144,6 +144,67 @@ const DataSyncIcon = ( ); +const AiIcon = ( + +); + +const AgentsIcon = ( + +); + +const FeaturesIcon = ( + +); + +const IntegrationsIcon = ( + +); + +const CryptoIcon = ( + +); + // --------------------------------------------------------------------------- // Group header (visual separator label above each settings card) // --------------------------------------------------------------------------- @@ -156,8 +217,8 @@ const GroupHeader = ({ label }: { label: string }) => ) : ( - // Empty label → a plain divider (the doc places Developer & Diagnostics and - // About after a divider, not under their own section headers). + // Empty label → a plain divider (Developer & Diagnostics and About sit + // after a divider, not under their own section headers). ); @@ -175,92 +236,131 @@ const SettingsHome = () => { const [searchQuery, setSearchQuery] = useState(''); const isSearching = searchQuery.trim().length > 0; - // --- 👤 Account group --- - const accountGroup: SettingsGroup = { - id: 'account', - label: t('settings.groups.account'), - items: [ - { - // The Account row opens the account hub (recovery phrase, team, - // connections, privacy, sign-out) — named after what it actually holds. - id: 'profile', - title: t('pages.settings.accountSection.title'), - description: t('pages.settings.accountSection.description'), - icon: AccountIcon, - onClick: () => navigateToSettings('account'), - }, - { - id: 'language', - title: t('settings.language'), - description: t('settings.languageDesc'), - icon: LanguageIcon, - rightElement: