From 5bf7daeb32fabe81af2504013c4781bf5b8b859f Mon Sep 17 00:00:00 2001 From: Steven Enamakel <31011319+senamakel@users.noreply.github.com> Date: Fri, 12 Jun 2026 01:05:22 -0700 Subject: [PATCH] refactor: rename tabs, flatten composer, polish UI (#3611) --- app/src/App.tsx | 22 +- app/src/AppRoutes.tsx | 24 +- app/src/components/BottomTabBar.tsx | 54 +-- .../__tests__/BottomTabBar.test.tsx | 42 +-- app/src/components/chat/ChatComposer.tsx | 230 ++++++------- .../components/chat/ComposerTokenStats.tsx | 84 +++++ .../intelligence/MemoryGraph.test.tsx | 47 ++- .../components/intelligence/MemoryGraph.tsx | 51 ++- .../intelligence/MemoryGraph.worker.test.tsx | 32 +- .../intelligence/PixiGraph.test.tsx | 2 +- .../intelligence/memoryGraphLayout.test.ts | 4 +- .../intelligence/memoryGraphLayout.ts | 51 ++- .../intelligence/pixiGraphRenderer.ts | 27 +- app/src/components/skills/MeetingBotsCard.tsx | 315 +++--------------- .../skills/__tests__/MeetingBotsCard.test.tsx | 184 ++-------- app/src/components/ui/BetaBanner.tsx | 23 ++ app/src/config/__tests__/navConfig.test.ts | 76 +---- app/src/config/navConfig.ts | 29 +- app/src/features/human/HumanPage.test.tsx | 43 --- app/src/features/human/HumanPage.tsx | 20 -- app/src/lib/i18n/ar.ts | 25 +- app/src/lib/i18n/bn.ts | 25 +- app/src/lib/i18n/de.ts | 25 +- app/src/lib/i18n/en.ts | 25 +- app/src/lib/i18n/es.ts | 25 +- app/src/lib/i18n/fr.ts | 25 +- app/src/lib/i18n/hi.ts | 25 +- app/src/lib/i18n/id.ts | 25 +- app/src/lib/i18n/it.ts | 25 +- app/src/lib/i18n/ko.ts | 25 +- app/src/lib/i18n/pl.ts | 25 +- app/src/lib/i18n/pt.ts | 25 +- app/src/lib/i18n/ru.ts | 25 +- app/src/lib/i18n/zh-CN.ts | 24 +- app/src/pages/Accounts.tsx | 57 +--- app/src/pages/Brain.tsx | 249 ++++---------- app/src/pages/Conversations.tsx | 38 +-- app/src/pages/Settings.tsx | 14 +- app/src/pages/Skills.tsx | 88 +++-- app/src/pages/WorkflowNew.tsx | 6 +- app/src/pages/__tests__/Brain.test.tsx | 119 +++---- .../__tests__/Conversations.render.test.tsx | 31 +- .../__tests__/Skills.channels-grid.test.tsx | 12 +- .../Skills.composio-catalog.test.tsx | 2 +- .../__tests__/Skills.mcp-coming-soon.test.tsx | 19 +- .../__tests__/Skills.meetings-tab.test.tsx | 18 +- .../Skills.third-party-gmail-sync.test.tsx | 2 +- ...ls.third-party-notion-debug-tools.test.tsx | 2 +- .../conversations/utils/threadFilter.test.ts | 47 +-- .../pages/conversations/utils/threadFilter.ts | 26 +- app/src/store/chatRuntimeSlice.ts | 32 +- app/src/utils/tauriCommands/memoryTree.ts | 2 +- .../specs/composio-triggers-flow.spec.ts | 6 +- .../specs/connector-gmail-composio.spec.ts | 10 +- .../connector-session-guard-matrix.spec.ts | 8 +- app/test/playwright/specs/gmail-flow.spec.ts | 10 +- .../specs/gmeet-connections-tab.spec.ts | 31 +- .../specs/navigation-settings-panels.spec.ts | 3 +- .../specs/navigation-smoothness.spec.ts | 13 +- app/test/playwright/specs/navigation.spec.ts | 7 +- .../settings-channels-permissions.spec.ts | 2 +- .../settings-feature-preferences.spec.ts | 2 +- .../specs/skill-execution-flow.spec.ts | 2 +- .../playwright/specs/skill-lifecycle.spec.ts | 5 +- .../playwright/specs/skills-registry.spec.ts | 24 +- .../specs/top-level-functional-flows.spec.ts | 10 +- 66 files changed, 1077 insertions(+), 1529 deletions(-) create mode 100644 app/src/components/chat/ComposerTokenStats.tsx create mode 100644 app/src/components/ui/BetaBanner.tsx diff --git a/app/src/App.tsx b/app/src/App.tsx index 125555b1e..f4b42bad9 100644 --- a/app/src/App.tsx +++ b/app/src/App.tsx @@ -1,7 +1,12 @@ import * as Sentry from '@sentry/react'; -import { useEffect } from 'react'; +import { useEffect, useRef } from 'react'; import { Provider } from 'react-redux'; -import { HashRouter as Router, useLocation, useNavigate } from 'react-router-dom'; +import { + HashRouter as Router, + useLocation, + useNavigate, + useNavigationType, +} from 'react-router-dom'; import { PersistGate } from 'redux-persist/integration/react'; import AppRoutes from './AppRoutes'; @@ -200,11 +205,22 @@ function AppShellDesktop() { // the core is ready (once per boot). Extracted to a hook so it's testable. useNotchBootSync(isBootstrapping); + const scrollRef = useRef(null); + const navType = useNavigationType(); + + useEffect(() => { + if (navType !== 'POP') { + scrollRef.current?.scrollTo(0, 0); + } + }, [location.pathname, navType]); + return (
-
+
diff --git a/app/src/AppRoutes.tsx b/app/src/AppRoutes.tsx index ae47e152b..cddfac0b3 100644 --- a/app/src/AppRoutes.tsx +++ b/app/src/AppRoutes.tsx @@ -7,7 +7,6 @@ import PublicRoute from './components/PublicRoute'; import HumanPage from './features/human/HumanPage'; import { getIsMobile } from './lib/platform'; import Accounts from './pages/Accounts'; -import Activity from './pages/Activity'; import Brain from './pages/Brain'; import AgentInsightsPreview from './pages/dev/AgentInsightsPreview'; import Home from './pages/Home'; @@ -88,20 +87,9 @@ const AppRoutes = () => { } /> - {/* Primary Activity surface — replaces /intelligence (Phase 3). */} - - - - } - /> - - {/* Back-compat: /intelligence → /activity (preserves ?tab= deep links). - Deep links such as ?tab=memory or ?tab=agents still resolve but fall - back to the tasks tab in prod (dev-only tabs are gated inside Activity). */} - } /> + {/* Back-compat: /activity and /intelligence → settings notifications hub. */} + } /> + } /> {/* Connections page lives at /connections (Phase 2 rename from /skills). The old /skills path is kept as a back-compat redirect so bookmarks @@ -177,7 +165,7 @@ const AppRoutes = () => { {/* Back-compat: /routines was an orphaned dead page (superseded by the Cron Jobs settings panel). Redirect to Activity → Automations so any surviving deep links land somewhere sensible. */} - } /> + } /> { } /> - {/* Workflows moved onto the Activity page (Automations tab). Keep the - old /workflows path working as a deep link into that tab. */} - } /> + } /> } /> diff --git a/app/src/components/BottomTabBar.tsx b/app/src/components/BottomTabBar.tsx index 3ef3202c2..b81109433 100644 --- a/app/src/components/BottomTabBar.tsx +++ b/app/src/components/BottomTabBar.tsx @@ -1,7 +1,7 @@ import { useEffect, useMemo, useRef, useState } from 'react'; import { useLocation, useNavigate } from 'react-router-dom'; -import { AVATAR_MENU_ITEMS, CENTER_TAB, NAV_TABS } from '../config/navConfig'; +import { AVATAR_MENU_ITEMS, NAV_TABS } from '../config/navConfig'; import { useT } from '../lib/i18n/I18nContext'; import { useCoreState } from '../providers/CoreStateProvider'; import { trackEvent } from '../services/analytics'; @@ -16,10 +16,8 @@ import { resolveUserName } from '../utils/userName'; // ── SVG icons, keyed by tab id ──────────────────────────────────────────────── -function TabIcon({ id, large = false }: { id: string; large?: boolean }) { - // Regular pill tabs render small (w-4); the raised center FAB renders large - // (w-6) so its glyph reads as the centerpiece. - const cls = large ? 'w-6 h-6' : 'w-4 h-4'; +function TabIcon({ id }: { id: string }) { + const cls = 'w-4 h-4'; switch (id) { case 'home': return ( @@ -95,8 +93,7 @@ function TabIcon({ id, large = false }: { id: string; large?: boolean }) { ); case 'brain': - // Two symmetric lobes — reads clearly as a brain. Rendered larger and - // white inside the raised center circle. + // Two symmetric lobes — reads clearly as a brain. return ( { ); }; - // The Assistant — a raised circular button rising out of the center of the - // bar. The bg-colored ring fakes a notch cut into the pill's top edge. - // `center-fab` marks the button (test/identification hook); it renders a - // static glow when active — no pulse. - // - // `-my-3` collapses the button's 48px (h-12) layout footprint so it no longer - // forces the nav row taller than the ~32px pill tabs — the bar height is - // driven by the tabs, while `-translate-y-4` still lifts the circle above the - // top edge. Without it the lower half of the raised circle left a dead band - // of empty bar height beneath the tabs. - const renderCenterButton = () => { - const active = isActive(CENTER_TAB.path); - const centerTab = { ...CENTER_TAB, label: t(CENTER_TAB.labelKey) }; - return ( - - ); - }; - - // Home is a normal pill tab now (no longer pinned/icon-only). The regular - // tabs split evenly around the centered Assistant button; only the avatar - // stays pinned to the far-right behind a divider: - // | home · human · brain ( 💬 ) connections · activity · settings | [ avatar ] - const leftTabs = tabs.slice(0, 3); - const rightTabs = tabs.slice(3); + // All tabs render as uniform pill buttons in a single row; the avatar + // stays pinned to the far-right behind a divider. return ( // pointer-events-none on the full-width shell so transparent areas (e.g. @@ -344,9 +306,7 @@ const BottomTabBar = () => { if (!e.currentTarget.contains(e.relatedTarget as Node)) setRevealed(false); }}>
diff --git a/app/src/components/__tests__/BottomTabBar.test.tsx b/app/src/components/__tests__/BottomTabBar.test.tsx index 118954efe..070dc8a60 100644 --- a/app/src/components/__tests__/BottomTabBar.test.tsx +++ b/app/src/components/__tests__/BottomTabBar.test.tsx @@ -1,14 +1,11 @@ /** * Tests for BottomTabBar — verifies that: - * - 6 tabs are rendered (no Rewards tab; Human restored), Activity label is present - * - Assistant tab is present (was "Chat", id stays 'chat', label now 'Assistant') - * - Walkthrough attributes reflect the new ids (tab-connections, tab-activity) + * - 6 tabs are rendered (no Rewards or Activity tab; Human restored; Chat is a regular tab) + * - Chat tab is present (id 'chat', label 'Chat') + * - Walkthrough attributes reflect the new ids (tab-connections) * - Avatar menu opens and shows Account / Billing / Rewards / Invites / Wallet * - Clicking an avatar menu item navigates or opens URL * - The bar is hidden on '/' and '/login' paths - * - * Human tab restored as a first-class entry (after the IA Phase 6 merge into - * Assistant); Chat keeps its "Assistant" label. */ import { configureStore } from '@reduxjs/toolkit'; import { fireEvent, render, screen } from '@testing-library/react'; @@ -167,14 +164,10 @@ describe('BottomTabBar', () => { agentProfilesApiMock.select.mockResolvedValue(testProfiles); }); - it('renders exactly 6 regular tab buttons (Assistant is rendered separately)', async () => { + it('renders exactly 6 regular tab buttons (Chat is a regular tab)', async () => { await renderBottomTabBar('/home'); - // Query only the regular pill tabs inside
)} - {/* Row 1: Textarea with inline ghost completion */} -
- {/* Ghost overlay for inline completion suffix */} -
- {inputValue} - {inlineCompletionSuffix} -
-