Skip to content

feat(shell): Refined UI step 2: top nav and icon cluster, Minimal/Full mode, Appearance settings, one brand mark (#18240) - #18373

Merged
mrveiss merged 19 commits into
mainfrom
issue-18240-shell
Oct 12, 2026
Merged

mrveiss merged 19 commits into
mainfrom
issue-18240-shell

Conversation

@mrveiss

@mrveiss mrveiss commented Oct 12, 2026 •

Copy link
Copy Markdown
Owner

Refs #18240
Refs #15469
Refs #17856
Refs #17959

Thinking Path

This is step 2 of the Refined UI redesign (umbrella #18237, step child #18240). It builds the shell from docs/design/2026-10-11-refined-ui-redesign.md §4.1-4.3: the top nav and icon cluster, a Minimal/Full interface mode that follows the account, and Settings › Appearance (preferred mode, plus themes deployed via the SLM). It also covers the brand mark from #15469 and retires config/routes.ts (#17856 row 7).

Owner rule: reuse the canonical implementation and never duplicate it. Before writing anything, every planned new piece was audited against the codebase by concept.

  • Dropped: a planned new theme grid. The existing ThemePresetPicker is extended instead.
  • Promoted to the kit: the SLM's useAnnounce, which both apps now use.
  • Reused: NavOverflowMenu, useSystemStatus, the kit BaseModal, usePreferences and useTheme.
  • Built new, only where nothing existed: BrandMark, BaseTooltip on the existing tooltip tokens, useUiMode, and the preferred-mode card.

Duplicates found on the way were merged:

  • There were two data-theme writers. Now there is one, and a guard enforces it.
  • Theme settings could be reached from two places. Now there is one.
  • theme_variant was saved only on the device. It now syncs with the account.

Owner decisions (2026-10-11/12):

Single-issue rationale

This is one build step of the Refined UI redesign (#18240), with its backend change and the #17959 tooling fix that blocked its push. Each linked issue stays open because an acceptance criterion outside this diff remains (the visual review, #18266's social preview, other #17856 rows, #17959 AC2/AC3), so nothing here is closed and nothing else of the same scope is waiting to batch with it.

What Changed

Backend, the one backend change: autobot-backend/api/users.py

  • UserPreferences gains three fields, anchored with \z:
    • ui_mode (minimal|full, default full);
    • ui_start (last|minimal|full, default last);
    • theme_variant, using the same id charset as theme_install._ID.
  • PATCH /users/me/preferences is now truly partial. It writes only model_fields_set, following the chat_folders.py precedent. A client that omits a field can no longer reset it. The response shape is unchanged.
  • Tests are in tests/api/test_user_preferences_partial_patch.py. They include the contrast pair: a PATCH that omits a field keeps it, and a PATCH that sends it changes it.
  • types/generated/api.ts was updated by hand, because the generator needs a built openapi.json.

Kit (libs/autobot-ui)

  • BrandMark and assets/brand/mark.svg replace three hand-made tiles: the main app header, the SLM sidebar and login, and the main app login. Both favicons and assets/logo.svg (previously the Vue scaffold) use the mark.
  • BaseTooltip is built on the existing --tooltip-* and --z-tooltip tokens. It opens on hover and focus and closes on Esc. You can move the pointer onto it (WCAG 1.4.13), and it is touch-safe.
  • useAnnounce is promoted from the SLM, which now re-exports it. LanguageSettingsPanel and ThemePresetPicker use it.

Shell (autobot-frontend)

  • App.vue goes from 1144 to 500 lines, and its size ceiling entry is deleted. The header moves to components/layout/: AppHeader, TopNavLinks, NavIconCluster, NavIconLink, UiModeToggle, ProfileMenu, MobileNavPanel and SystemStatusModal (on the kit BaseModal, replacing a hand-built overlay).

  • config/navItems.ts stays the one registry. It gains adv/overflow flags and icon-cluster entries, and the Platform admin link is gated by hasServiceManagement and opens in a new tab with rel="noopener noreferrer".

  • useUiMode is a singleton. It sets data-ui before mount, syncs with the account, and announces changes. The .adv/.only-min rules use no !important.

  • Settings › Appearance gains UiModeSettingsCard. ThemePresetPicker is extended with AdditionalThemesGroup, which shows SLM-deployed themes with a "Deployed via SLM" badge.

  • There is now one data-theme writer, useTheme. useUserStore.applyTheme/updateTheme and the ProfileModal theme UI are removed. Guard: repo_tests/single_attribute_writer_18240_test.py, which also covers data-ui.

  • inventory(canonical): 19 concepts with more than one definition and no existing issue — led by two secret stores whose docstrings each claim they cannot disagree about the key #17856 row 7: config/routes.ts is retired. It had 0 static or dynamic importers.

    routes.ts entry Where it is now
    dashboard, chat, knowledge/{browser,upload,manage,health}, tools, tools/terminal, secrets, settings Live in router/index.ts
    /monitoring, /monitoring/system Redirect to the SLM console's SystemMonitor
    /monitoring/analytics CodebaseAnalytics.vue, live
    /tools/files FileBrowser.vue exists; its mockup screen is built in step 5
    /tools/voice Voice lives in chat (VoiceConversationOverlay/Panel)
    /monitoring/rum Unbuilt screen, tracked as feat(slm): a real-user-monitoring (RUM) viewer for the data the backend already collects #18277
    /monitoring/validation Unbuilt screen, tracked as feat(slm): a validation dashboard screen for the mounted /validation-dashboard API #18278
  • i18n: every new string is in all 11 locales, append-only.

Tooling, #17959 (rides here because it blocked this push): a worktree's app tests resolved the main checkout's older @autobot/ui. The 25 layout tests that use the new kit exports failed in pre-push, though they pass against the in-tree kit.

  • New shared helper libs/autobot-ui/vite-resolve.ts. autobotUiResolve() aliases @autobot/ui to the in-tree index.ts and dedupes vue/@vueuse/core to the app's copy.
  • It is consumed by autobot-frontend/vite.config.js, autobot-slm-frontend/vite.config.ts and autobot-slm-frontend/vitest.config.ts.
  • tools/git-hooks/pre-push now claims libs/autobot-ui changes through both apps: vue-tsc, plus vitest related on the changed kit files. It no longer reports them "COULD NOT RUN (unclaimed trees)", so pushes after this merges no longer need AUTOBOT_PREPUSH_ALLOW_UNRUNNABLE. This push itself still used the flag, with the owner's approval: the shared installed hook in .git/hooks predates the fix and changes only after merge and reinstall. Every check that can run passed in pre-push: vue-tsc in both apps, vitest (in-tree kit) and pytest.
  • Hook tests: TestTheKitIsClaimedThroughTheApps, 5 tests that fail on the old hook.

User-visible changes:

  • The brand links Home. System status moved to the profile menu.
  • The Platform admin shield replaces the SLM text link.
  • Secrets and Preferences move into the icon cluster.
  • The Plugins icon, language switcher and theme toggle are gone from the nav.
  • Automation is under "More".
  • In Minimal mode a "Showing essentials · Show all features" strip appears.
  • The meta theme-color follows the theme's surface token.

Ratchets, all down:

  • File-size ceilings: 183698 → 181943 (App.vue and ThemePresetPicker ceiling entries removed).
  • css_rule_declarations 9378 → 9374, components_declaring_styles 379 → 378, hardcoded_zindex 51 → 50.
  • Raw palette 6808 → 6790; hardcoded colour 55 → 53.

Follow-ups filed under #18241:

Acceptance criteria

Issue Verdict Met (evidence) Open
#18240 Refs The toggle has aria-pressed (UiModeToggle.vue), a tooltip (BaseTooltip) and an aria-live announcement (kit useAnnounce). Mode and theme persist per user server-side (users.py, usePreferences.ts; partial-PATCH tests). The mapped #15469 box. Visual review of the nav and Settings.
#15469 Refs Canonical mark SVG with documented usage (libs/autobot-ui/src/assets/brand/mark.svg, README). Both favicons use the mark. assets/logo.svg no longer holds the Vue scaffold. The social preview PNG, split to #18266.
#17959 Refs AC1 is met: the layout tests pass under plain npx vitest run. Contrast: UiModeToggle.test.ts "pressing it enters Minimal…" fails against the main checkout's kit and passes in-tree. The pre-push hook now claims kit changes through the apps. AC2 is open: the dedupe setting is declared, but no test discriminates it. The kit folder has no node_modules of its own, so only one vue copy is reachable with or without dedupe. The candidate test passed either way, so it was removed rather than kept as false coverage. AC3 (production build unchanged) is argued, not measured: in CI the file: link resolves to the same index.ts, and no vite build was run.
#17856 Refs (row 7) config/routes.ts retired with zero-importer evidence, and every entry is accounted for in the table above. Every row other than 7. Rows 6 and 8 land in the #18241 API-client slice.

Verification

At 1ee0bd4ebc, after the rebase onto origin/main:

  • npm run type-check passed in autobot-frontend and autobot-slm-frontend: rc=0.
  • Targeted vitest (layout, ui-mode, preferences, theme, settings, nav coverage, command palette, css): 18 files, 118 tests passed.
  • Full autobot-frontend vitest: 3756 passed, 2 failed. Both failures (useProviderFallbackChip, AdvancedControlView) pass when run alone and are outside this change (test(frontend): four vitest files fail in the full run but pass in isolation #18254 family).
  • Kit vitest: 9 files, 89 tests passed (92 after the fixes).
  • pytest across 16 repo_tests guards and ratchets plus 2 backend files: 420 passed. reach_scope_claim_17844_test run alone: 10 passed.
  • lift_locale_translations.py --check: rc=0. pre-commit run --from-ref origin/main --to-ref HEAD: 0 failed.

After the review-fix commits (7eef154e9b, d1fc226c53, 27c59d0be9):

  • Type-check passed in both apps.
  • Kit vitest: 92 passed.
  • Six guard and ratchet files: 158 passed.
  • Layout, composables and stores vitest: 1807 passed, 1 failed. The failure, useAiAnalysis, passes 4/4 when run alone.

Notes:

Model Used

Claude Opus 5.5 (coordinating). Sonnet subagents planned, audited duplication, implemented phases A, B and C, ran verification and the review, and fixed its findings.

🤖 Generated with Claude Code

@coderabbitai

coderabbitai Bot commented Oct 12, 2026 •

Copy link
Copy Markdown
Contributor

Important

Review skipped

Too many files!

This PR contains 109 files, which is 9 over the limit of 100.

To get a review, reduce the PR to 100 files or fewer by splitting it into smaller PRs or changing its base branch.

Upgrade to a paid plan to raise the limit.

This review couldn't start because sufficient usage credits or metered capacity aren't available. Add credits or update usage-based reviews in the billing tab, then retry.

Check out review usage here.

⚙️ Run configuration
  • Configuration used: Repository: mrveiss/AutoBot-AI/.coderabbit.yaml
  • Review profile: ASSERTIVE
  • Plan: Advanced
  • Run ID: 8678c531-a3d3-4bb4-8c19-26fdca81ae45

📥 Commits

Reviewing files that changed from the base of the PR and between df211d3 and fbb50bf.


⛔ Files ignored due to path filters (5)
  • autobot-frontend/public/favicon.svg is excluded by !**/*.svg
  • autobot-frontend/src/assets/logo.svg is excluded by !**/*.svg
  • autobot-frontend/src/types/generated/api.ts is excluded by !**/generated/**
  • autobot-slm-frontend/public/favicon.svg is excluded by !**/*.svg
  • libs/autobot-ui/src/assets/brand/mark.svg is excluded by !**/*.svg

📒 Files selected for processing (109)
  • autobot-backend/api/users.py
  • autobot-backend/tests/api/test_user_preferences_partial_patch.py
  • autobot-frontend/index.html
  • autobot-frontend/src/App.vue
  • autobot-frontend/src/__tests__/nav-items-coverage.test.ts
  • autobot-frontend/src/assets/css/__tests__/uiMode.css.test.ts
  • autobot-frontend/src/assets/css/components.css
  • autobot-frontend/src/components/__tests__/CommandPalette.nav.test.ts
  • autobot-frontend/src/components/auth/LoginForm.vue
  • autobot-frontend/src/components/layout/AppHeader.stories.ts
  • autobot-frontend/src/components/layout/AppHeader.vue
  • autobot-frontend/src/components/layout/MobileNavPanel.stories.ts
  • autobot-frontend/src/components/layout/MobileNavPanel.vue
  • autobot-frontend/src/components/layout/NavIconCluster.stories.ts
  • autobot-frontend/src/components/layout/NavIconCluster.vue
  • autobot-frontend/src/components/layout/NavIconLink.stories.ts
  • autobot-frontend/src/components/layout/NavIconLink.vue
  • autobot-frontend/src/components/layout/NavItemIcon.stories.ts
  • autobot-frontend/src/components/layout/NavItemIcon.vue
  • autobot-frontend/src/components/layout/ProfileMenu.stories.ts
  • autobot-frontend/src/components/layout/ProfileMenu.vue
  • autobot-frontend/src/components/layout/SystemStatusModal.stories.ts
  • autobot-frontend/src/components/layout/SystemStatusModal.vue
  • autobot-frontend/src/components/layout/TopNavLinks.stories.ts
  • autobot-frontend/src/components/layout/TopNavLinks.vue
  • autobot-frontend/src/components/layout/UiModeToggle.stories.ts
  • autobot-frontend/src/components/layout/UiModeToggle.vue
  • autobot-frontend/src/components/layout/__tests__/AppHeader.test.ts
  • autobot-frontend/src/components/layout/__tests__/NavIconLink.test.ts
  • autobot-frontend/src/components/layout/__tests__/ProfileMenu.test.ts
  • autobot-frontend/src/components/layout/__tests__/SystemStatusModal.test.ts
  • autobot-frontend/src/components/layout/__tests__/UiModeToggle.test.ts
  • autobot-frontend/src/components/profile/ProfileModal.vue
  • autobot-frontend/src/components/settings/AdditionalThemesGroup.stories.ts
  • autobot-frontend/src/components/settings/AdditionalThemesGroup.test.ts
  • autobot-frontend/src/components/settings/AdditionalThemesGroup.vue
  • autobot-frontend/src/components/settings/LanguageSettingsPanel.vue
  • autobot-frontend/src/components/settings/ThemePresetPicker.vue
  • autobot-frontend/src/components/settings/UiModeSettingsCard.stories.ts
  • autobot-frontend/src/components/settings/UiModeSettingsCard.test.ts
  • autobot-frontend/src/components/settings/UiModeSettingsCard.vue
  • autobot-frontend/src/components/theme/EmberThemeToggle.vue
  • autobot-frontend/src/composables/__tests__/usePreferences.account.test.ts
  • autobot-frontend/src/composables/__tests__/useTheme.metaThemeColor.test.ts
  • autobot-frontend/src/composables/__tests__/useThemeVariant.test.ts
  • autobot-frontend/src/composables/__tests__/useUiMode.test.ts
  • autobot-frontend/src/composables/systemStatusContext.ts
  • autobot-frontend/src/composables/usePreferences.ts
  • autobot-frontend/src/composables/useTheme.ts
  • autobot-frontend/src/composables/useThemeVariant.ts
  • autobot-frontend/src/composables/useUiMode.ts
  • autobot-frontend/src/config/navItems.ts
  • autobot-frontend/src/config/routes.ts
  • autobot-frontend/src/i18n/locales/ar.json
  • autobot-frontend/src/i18n/locales/de.json
  • autobot-frontend/src/i18n/locales/en.json
  • autobot-frontend/src/i18n/locales/es.json
  • autobot-frontend/src/i18n/locales/fa.json
  • autobot-frontend/src/i18n/locales/fr.json
  • autobot-frontend/src/i18n/locales/he.json
  • autobot-frontend/src/i18n/locales/lv.json
  • autobot-frontend/src/i18n/locales/pl.json
  • autobot-frontend/src/i18n/locales/pt.json
  • autobot-frontend/src/i18n/locales/ur.json
  • autobot-frontend/src/stores/__tests__/useUserStore.signIn.test.ts
  • autobot-frontend/src/stores/useUserStore.ts
  • autobot-frontend/src/theme-variant-init.ts
  • autobot-frontend/src/views/SettingsView.vue
  • autobot-frontend/vite.config.js
  • autobot-slm-frontend/src/assets/styles/slm-scheme.css
  • autobot-slm-frontend/src/components/common/Sidebar.vue
  • autobot-slm-frontend/src/composables/useAccessibility.ts
  • autobot-slm-frontend/src/locales/ar.json
  • autobot-slm-frontend/src/locales/de.json
  • autobot-slm-frontend/src/locales/es.json
  • autobot-slm-frontend/src/locales/fa.json
  • autobot-slm-frontend/src/locales/fr.json
  • autobot-slm-frontend/src/locales/he.json
  • autobot-slm-frontend/src/locales/lv.json
  • autobot-slm-frontend/src/locales/pl.json
  • autobot-slm-frontend/src/locales/pt.json
  • autobot-slm-frontend/src/locales/ur.json
  • autobot-slm-frontend/src/views/LoginView.vue
  • autobot-slm-frontend/vite.config.ts
  • autobot-slm-frontend/vitest.config.ts
  • libs/autobot-ui/README.md
  • libs/autobot-ui/index.ts
  • libs/autobot-ui/src/__tests__/vite-resolve.test.ts
  • libs/autobot-ui/src/components/BaseTooltip.vue
  • libs/autobot-ui/src/components/BrandMark.vue
  • libs/autobot-ui/src/components/__tests__/BaseTooltip.test.ts
  • libs/autobot-ui/src/components/__tests__/BrandMark.test.ts
  • libs/autobot-ui/src/composables/__tests__/useAnnounce.test.ts
  • libs/autobot-ui/src/composables/useAnnounce.ts
  • libs/autobot-ui/src/tokens/adapter.css
  • libs/autobot-ui/src/tokens/contract.css
  • libs/autobot-ui/vite-resolve.ts
  • repo_tests/_hardcoded_colour_baseline.py
  • repo_tests/_raw_palette_baseline.py
  • repo_tests/_reach_policy.py
  • repo_tests/frontend_file_size_ratchet_baseline.py
  • repo_tests/frontend_file_size_ratchet_test.py
  • repo_tests/frontend_fragmentation_ratchet_test.py
  • repo_tests/one_brand_mark_and_announcer_18240_test.py
  • repo_tests/prepush_frontend_projects_17574_test.py
  • repo_tests/reach_scope_claim_17844_test.py
  • repo_tests/single_attribute_writer_18240_test.py
  • scripts/frontend_file_size_known_large.py
  • tools/git-hooks/pre-push

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

  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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

❤️ Share

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

@github-actions

Copy link
Copy Markdown
Contributor

Notice: 26 open PRs — past the runaway threshold (25)

This is not a request to defer this PR. The actual limit is the open-PR cap (AUTOBOT_OPEN_PR_CAP, default 40), enforced at pre-push against NEW branches only -- pushing more commits to this PR's own branch is never blocked by it.

This notice only means the count is high enough to be worth a glance for a runaway — something opening PRs in a loop, or a merge pipeline that has stalled so nothing is draining.

Currently open:

If the queue is draining normally, ignore this. Otherwise:

  1. Check whether CI is dispatching at all — see the ci-dispatch-watchdog status on these PRs
  2. Merge the ones whose CI has finished and review has passed: gh pr merge <number> --squash --delete-branch
  3. Look for a loop opening near-identical PRs

Warn-only runaway detector — .github/workflows/pr-queue-gate.yml. It never blocks a merge.

@github-actions

Copy link
Copy Markdown
Contributor

✅ SSOT Configuration Compliance: Passing

🎉 No new hardcoded values of either class — ssot and other both block.

Known backlog in pipeline-scripts/hardcoded_values_baseline.txt is suppressed and tracked in #14371.

@mrveiss

mrveiss commented Oct 12, 2026

Copy link
Copy Markdown
Owner Author

Delta review (Sonnet) at 5df8dea: approve. The deleted test asserted module-instance identity, which holds with a single node_modules/vue whether or not resolve.dedupe is set, so it could not fail. Nothing else guards the dedupe config now; filed #18381 for a real guard. Queued for the next merge train.

@mrveiss

mrveiss commented Oct 12, 2026

Copy link
Copy Markdown
Owner Author

Ejected from merge train #7 (#18401). This PR causes most of that train's red checks. Each is listed with its CI evidence:

  1. Every frontend build fails (Build Test, SLM Frontend Check, frontend-tests, colocated-stack, hardened-smoke-test):
    [UNLOADABLE_DEPENDENCY] Could not load ../libs/autobot-ui/index.ts/adapter (and /tokens), from src/main.ts:7-8 import "@autobot/ui/adapter".
    Cause: libs/autobot-ui/vite-resolve.ts autobotUiResolve() aliases '@autobot/ui' to index.ts. Vite's string alias also matches the @autobot/ui/… prefix, so the package's subpath exports (./tokens, ./adapter in libs/autobot-ui/package.json) are rewritten to index.ts/adapter.
    Fix: alias each export. Ideally derive them from package.json exports (one source), with the subpaths listed BEFORE the bare '@autobot/ui', or use an array alias with ^@autobot/ui$.
  2. Stylelint (changed CSS/Vue): 7 hardcoded hex colours. The files are libs/autobot-ui/src/components/BaseTooltip.vue, BrandMark.vue, src/tokens/adapter.css, src/App.vue, assets/css/components.css, assets/styles/slm-scheme.css, auth/LoginForm.vue, common/Sidebar.vue, layout/AppHeader.vue and layout/MobileNavPanel.vue. Lines include 349:31, 350:45, 443:36 and 445:38 in the reported file; the full list is in the Stylelint job.
  3. verify-generated-types / verify-types-run / autofix-types: autobot-frontend/src/types/generated/api.ts is stale. The PATCH /users/me/preferences docstring changed ("partial: omitted fields keep stored values"), so regenerate and commit.

Also on this PR from train-7: one_brand_mark_and_announcer_18240_test.py and single_attribute_writer_18240_test.py hand-match comment markers, which one_comment_stripper_17941_test refuses. The train fixed this by routing both through tools.lint._comment_syntax.code_lines, passing the file's own suffix and making the jsdoc self-test cases real /** */ blocks. Please carry that change.

After the fixes, the delta needs a re-review, then the PR joins the next train.

…nces, and PATCH /users/me/preferences writes only the fields it was sent (#18240)
… announcer in @autobot/ui, consumed by both apps (#18240)
…llows the account (#18240)

useUiMode owns data-ui on <html> (minimal|full) and the start preference
(last|minimal|full), writes through to localStorage, and resolves the opening
mode at login (ui_start === 'last' ? ui_mode : ui_start). theme-variant-init
sets data-ui before mount, the same CSP-safe pattern as the variant beside it.
html[data-ui="minimal"] .adv hides advanced chrome and .only-min shows only in
Minimal, both without !important (the selector is more specific than a display
utility).

usePreferences now sends and applies ui_mode, ui_start and theme_variant with the
appearance prefs. The endpoint is a partial PATCH since 0b2892a360, and the only
caller still sends every field it owns, so nothing is reset. An account
theme_variant of 'default' does not override a device that never chose one, so a
deployment pinning another build-time default keeps it.
…les (#18240)

nav.homeAria, vaultTip, preferencesTip, platformAdmin(+Aria/Tip), profileMenu,
nav.uiMode.*, settings.preferredMode.*, settings.additionalThemes.*,
ui.minimalNote and ui.minimalNoteAction, each really translated (ar, de, es, fa,
fr, he, lv, pl, pt, ur) and appended to its group; no existing key is touched.
settings.appearance.* from the plan is settings.additionalThemes.* because
settings.appearance is already a string key.

The SLM locales are regenerated by scripts/lift_locale_translations.py: its two
"Full" keys now lift a translation from the new settings.preferredMode.full.
nav.slmAdmin and nav.slmAdminTitle have no reference left in the app but stay,
append-only: the same lift derives the SLM's "SLM Admin" translation from them.
…18240)

UiModeSettingsCard (Settings > Appearance): two aria-pressed mode cards and a
Start-in radiogroup (Last used / Minimal / Full) over the same useUiMode state
the header toggle drives. ThemePresetPicker is extended, not duplicated, with an
Additional themes group (AdditionalThemesGroup) fed by the installed-theme
registry, each theme badged "Deployed via SLM" with a link to the SLM console;
EmberThemeToggle keeps the built-in variants only so no theme is offered twice.
ThemePresetPicker's inline sr-only announcer moves onto the kit useAnnounce,
which takes it from 611 to 587 lines, under the limit, so its ceiling is deleted.
SettingsView does not grow (784).
…er, UiModeToggle, ProfileMenu, MobileNavPanel and a BaseModal status panel (#18240)

Split the 290-line header and the hand-rolled status overlay out of App.vue
(1144 -> 499 lines, now under the 600 limit, so its grandfathered ceiling is
deleted). The brand is the kit BrandMark linking Home; the health dot is an
aria-hidden overlay and System status moved into the profile menu. Primary
links are Home, Chat, Knowledge, Company OS and Analytics (advanced); Automation
is pinned to the existing NavOverflowMenu. The right-hand cluster is
Secrets (advanced), Preferences, the Minimal/Full toggle and the Platform admin
shield (advanced, gated by service.management, opens the SLM console in a new
tab). Every icon has an i18n aria-label and a kit BaseTooltip. The active link
is a 2px accent underline.

config/navItems.ts stays the one registry: it gains the adv and overflow flags
and navIconItems; the profile menu loses Plugins (it lives in the SLM console
nav; INTENTIONALLY_HIDDEN records why), Secrets and Preferences; paletteNavItems
still derives from it. The mobile drawer renders the same registry. The SLM text
link, DarkModeToggle and LanguageSwitcher are no longer in the nav.

One shared useSystemStatus instance is provided by App.vue (composables/
systemStatusContext.ts) so the dot and the panel show one snapshot.

New strings are committed separately (feat(i18n)). nav.slmAdmin* stays
(the SLM locale lift derives from it). Ratchets only move down: App.vue's scoped
style, a LoginForm .logo-mark rule that had pushed distinct_class_names over its
baseline, and the raw status colours the header and panel used.
…ps it that way (#18240)

useUserStore.applyTheme/updateTheme and the profile modal's own theme buttons set
data-theme from a second preference (default light) that could disagree with
useTheme's persisted choice. They are removed, together with PreferencesPanel in
the profile modal (appearance settings live in Settings only). The meta
theme-color the store set from two hex values moves into useTheme and follows
the active theme's surface token instead.

repo_tests/single_attribute_writer_18240_test.py fails if anything but useTheme
writes data-theme, or anything but useUiMode (and its pre-mount copy in
theme-variant-init.ts) writes data-ui, with contrast pairs for the matcher and a
control that the scan sees each canonical writer.
Refs #17856 row 7

routeConfig, getAllRoutes, findRouteByPath, getNavigationMenus and RouteConfig
have zero importers: no static import, no dynamic import(), no require, no
import.meta.glob, no string path in a build/test/storybook/CI config; the only
mentions are two superseded plans under docs/superpowers. Router entries it
described are live in router/index.ts, or tracked: /monitoring and
/monitoring/system redirect to the SLM console, /monitoring/analytics is
CodebaseAnalytics, /tools/files is FileBrowser (mockup screen in step 5),
/tools/voice lives in chat voice, /monitoring/rum is #18277,
/monitoring/validation is #18278.
…overable and touch-safe, drop the double read on icon links (#18240)
…y at a fresh sign-in, never on session restore (#18240)
… first fresh-import test no longer times out under load (#18240)
@mrveiss

mrveiss commented Oct 12, 2026

Copy link
Copy Markdown
Owner Author

Delta review (Sonnet) at fbb50bf: approve. All three ejection causes are fixed:

  • Aliases: kitAliases() builds one anchored, escaped ^…$ regex per package.json export, so @autobot/ui-foo doesn't match. All 3 configs use array aliases with dedupe kept. vite-resolve.test.ts resolves the bare specifier, /tokens and /adapter through a real vite pluginContainer.
  • Stylelint: no <style> hex remains in a linted file. The #6366f1 fallbacks were dead, because --color-primary is always defined (design-tokens.css:35).
  • api.ts: matches the users.py docstrings.

The comment-stripper guard files are byte-identical to merge train 7's fix. The cold-import warm-up is scoped to 2 files, and per-test timeouts stay at the default.

LOWs:

  • usePreferences.account.test.ts also raises testTimeout to 30s. Use the same beforeAll warm-up, or note it in the body.
  • Sidebar.vue:49 has script-side hex strings, which the <style>-only lint doesn't see (out of scope).

Queued for the next merge train.

@mrveiss
mrveiss merged commit bf6c9aa into main Oct 12, 2026
4 checks passed
@mrveiss
mrveiss deleted the issue-18240-shell branch October 12, 2026 22:20
mrveiss added a commit that referenced this pull request Oct 12, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant