From 2f2f0eb21e2ed9e17f07187e5af14fd8fcd5b787 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Mon, 21 Sep 2026 17:10:17 +0000 Subject: [PATCH] Move integrations and live trading into settings navigation Integrations and Live Trading no longer compete as sidebar peers with the account entry. Settings opens from a dedicated sidebar control; integrations live in the settings nav, and Live Trading is a discover banner above the account block in General. Co-authored-by: cynarAI --- apps/web/e2e/auth-lifecycle.spec.ts | 7 +- apps/web/e2e/golden.spec.ts | 9 +- apps/web/e2e/graphql-integrations.spec.ts | 4 +- apps/web/e2e/helpers.ts | 10 +- apps/web/e2e/integration-setup.spec.ts | 3 +- apps/web/e2e/mcp-oauth.spec.ts | 3 +- apps/web/e2e/settings-shell.spec.ts | 11 ++- apps/web/e2e/ui-appearance.spec.ts | 12 +-- apps/web/e2e/ui-locale.spec.ts | 3 +- apps/web/scripts/translations-de.json | 3 + apps/web/src/locales/de/messages.po | 15 ++- apps/web/src/locales/en/messages.po | 12 +++ apps/web/src/pages/AccountSettingsOverlay.tsx | 65 ++++++++++++- apps/web/src/pages/PluginsOverlay.tsx | 97 ++++++++++++------- apps/web/src/pages/SettingsOverlay.tsx | 44 ++++++++- apps/web/src/pages/Shell.tsx | 80 ++++----------- 16 files changed, 248 insertions(+), 130 deletions(-) diff --git a/apps/web/e2e/auth-lifecycle.spec.ts b/apps/web/e2e/auth-lifecycle.spec.ts index 7221059..6f41ce1 100644 --- a/apps/web/e2e/auth-lifecycle.spec.ts +++ b/apps/web/e2e/auth-lifecycle.spec.ts @@ -50,8 +50,8 @@ test("logout protects bot deep links and sign-in restores the session", async ({ const protectedBotPath = new URL(page.url()).pathname; await expect(page.getByPlaceholder("Message Chief")).toBeVisible(); - await page.getByRole("button", { name: new RegExp(userName, "i") }).click(); - await expect(page.getByRole("button", { name: "Settings", exact: true })).toBeVisible(); + await expect(page.getByTestId("settings-entry")).toBeVisible(); + await page.getByTestId("user-menu-trigger").click(); await expect(page.getByRole("button", { name: "Usage", exact: true })).toBeVisible(); await expect(page.getByRole("button", { name: "Log out" })).toBeVisible(); await expect( @@ -152,8 +152,7 @@ test("changes and recovers an email password", async ({ page }, testInfo) => { await completeOnboarding(page); await page.waitForURL(/\/app\/[^/]+$/); - await page.getByTestId("user-menu-trigger").click(); - await page.getByRole("button", { name: "Settings", exact: true }).click(); + await page.getByTestId("settings-entry").click(); const settings = page.getByTestId("user-settings"); await expect(settings).toBeVisible(); await expect(page.getByTestId("sidebar-search").locator("input")).toHaveAttribute( diff --git a/apps/web/e2e/golden.spec.ts b/apps/web/e2e/golden.spec.ts index 91fe500..ae3fa04 100644 --- a/apps/web/e2e/golden.spec.ts +++ b/apps/web/e2e/golden.spec.ts @@ -3,6 +3,7 @@ import { activeBotId, captureScreenshot, completeOnboarding, + openIntegrations, realSandboxTimeout, rpc, signup, @@ -134,7 +135,7 @@ test("takeover, routine, plugins, and export are reachable", async ({ page }, te await expect(page.getByText("Monday briefing")).toBeVisible(); await captureScreenshot(page, testInfo, "10-routine-created"); - await page.getByText("Integrations").click(); + await openIntegrations(page); await expect(page.getByPlaceholder("Search apps")).toBeVisible(); const featured = page.getByTestId("featured-connectors"); await expect(featured).toContainText( @@ -178,8 +179,8 @@ test("takeover, routine, plugins, and export are reachable", async ({ page }, te await expect(detail.getByLabel("Account label").nth(1)).toHaveValue("Work"); await captureScreenshot(page, testInfo, "11a2-multi-account-plugins"); - await page.getByRole("button", { name: "Close integrations" }).click(); - await page.getByText("Integrations").click(); + await page.getByRole("button", { name: "Close integrations settings" }).click(); + await openIntegrations(page); await expect(page.getByPlaceholder("Search apps")).toBeVisible(); const gmailTileAgain = page.getByTestId("connection-tile-gmail"); await expect(gmailTileAgain.getByRole("button", { name: "Added", exact: true })).toBeVisible(); @@ -296,7 +297,7 @@ test("takeover, routine, plugins, and export are reachable", async ({ page }, te ).toBeVisible(); await captureScreenshot(page, testInfo, "11d-provider-emulators"); - await page.getByRole("button", { name: "Close integrations" }).click(); + await page.getByRole("button", { name: "Close integrations settings" }).click(); await page.getByText("Chief").first().click(); const gear = page.getByRole("button", { name: "Show settings" }); diff --git a/apps/web/e2e/graphql-integrations.spec.ts b/apps/web/e2e/graphql-integrations.spec.ts index 69f2c47..902b032 100644 --- a/apps/web/e2e/graphql-integrations.spec.ts +++ b/apps/web/e2e/graphql-integrations.spec.ts @@ -1,5 +1,5 @@ import { expect, test } from "@playwright/test"; -import { captureScreenshot, completeOnboarding, signup } from "./helpers"; +import { captureScreenshot, completeOnboarding, openIntegrations, signup } from "./helpers"; test("advanced GraphQL install shows Add GraphQL in MCP, OpenAPI, GraphQL, Executor, Treg order", async ({ page, @@ -8,7 +8,7 @@ test("advanced GraphQL install shows Add GraphQL in MCP, OpenAPI, GraphQL, Execu await signup(page, `graphql-source-${stamp}@rakazo.test`, "password12", `GraphQL ${stamp}`); await completeOnboarding(page); - await page.getByText("Integrations").click(); + await openIntegrations(page); await expect(page.getByPlaceholder("Search apps")).toBeVisible(); await expect(page.getByRole("button", { name: "Add GraphQL", exact: true })).toBeHidden(); diff --git a/apps/web/e2e/helpers.ts b/apps/web/e2e/helpers.ts index 88c6721..10d3c1b 100644 --- a/apps/web/e2e/helpers.ts +++ b/apps/web/e2e/helpers.ts @@ -127,10 +127,9 @@ export async function createBotFromPicker( /** Open the user Settings overlay, optionally switching to a sidebar section. */ export async function openUserSettings( page: Page, - section?: "general" | "models" | "memory" | "voice" | "usage" | "computer" | "updates", + section?: "general" | "integrations" | "models" | "memory" | "voice" | "usage" | "computer" | "updates", ) { - await page.getByTestId("user-menu-trigger").click(); - await page.getByRole("button", { name: "Settings", exact: true }).click(); + await page.getByTestId("settings-entry").click(); const settings = page.getByTestId("user-settings"); await expect(settings).toBeVisible(); if (section && section !== "general") { @@ -139,6 +138,11 @@ export async function openUserSettings( return settings; } +/** Open Integrations inside the Settings overlay. */ +export async function openIntegrations(page: Page) { + return openUserSettings(page, "integrations"); +} + /** Create a named bot via RPC for test setup (skips the + picker). */ export async function createNamedBot( page: Page, diff --git a/apps/web/e2e/integration-setup.spec.ts b/apps/web/e2e/integration-setup.spec.ts index c0d6036..2a86cc8 100644 --- a/apps/web/e2e/integration-setup.spec.ts +++ b/apps/web/e2e/integration-setup.spec.ts @@ -245,8 +245,7 @@ test("configured server owners manage providers from settings", async ({ page }, await signup(page, `configured-owner-${Date.now()}@rakazo.test`, "password12", "Server Owner"); await expect(page.getByRole("heading", { name: "Server integrations" })).toBeHidden(); await completeOnboarding(page); - await page.getByTestId("user-menu-trigger").click(); - await page.getByRole("button", { name: "Settings", exact: true }).click(); + await page.getByTestId("settings-entry").click(); const settings = page.getByTestId("user-settings"); const link = settings.getByRole("link", { name: "Server integrations", exact: true }); await expect(link).toBeVisible(); diff --git a/apps/web/e2e/mcp-oauth.spec.ts b/apps/web/e2e/mcp-oauth.spec.ts index 00912c2..f913720 100644 --- a/apps/web/e2e/mcp-oauth.spec.ts +++ b/apps/web/e2e/mcp-oauth.spec.ts @@ -83,7 +83,8 @@ test("connects an MCP server through the OAuth popup callback", async ({ page }, }); }); - await page.getByText("Integrations", { exact: true }).click(); + await page.getByTestId("settings-entry").click(); + await page.getByTestId("settings-nav-integrations").click(); await page.getByTestId("integrations-advanced").evaluate((element) => { (element as HTMLDetailsElement).open = true; }); diff --git a/apps/web/e2e/settings-shell.spec.ts b/apps/web/e2e/settings-shell.spec.ts index ef16c6f..5d6bb05 100644 --- a/apps/web/e2e/settings-shell.spec.ts +++ b/apps/web/e2e/settings-shell.spec.ts @@ -9,12 +9,12 @@ test("settings shell is two-pane and deep-links Models Memory Voice Usage", asyn await signup(page, `settings-shell-${stamp}@rakazo.test`, "password12", userName); await completeOnboarding(page); + await expect(page.getByTestId("settings-entry")).toBeVisible(); await page.getByTestId("user-menu-trigger").click(); const menu = page.locator('[data-slot="popover-content"]'); - await expect(menu.getByRole("button", { name: "Settings", exact: true })).toBeVisible(); await expect(menu.getByRole("button", { name: "Usage", exact: true })).toBeVisible(); await expect(menu.getByRole("button", { name: "Log out", exact: true })).toBeVisible(); - await expect(menu.getByRole("button", { name: "Models", exact: true })).toHaveCount(0); + await expect(menu.getByRole("button", { name: "Settings", exact: true })).toHaveCount(0); await captureScreenshot(page, testInfo, "settings-account-menu-lean"); await page.keyboard.press("Escape"); @@ -25,9 +25,16 @@ test("settings shell is two-pane and deep-links Models Memory Voice Usage", asyn "page", ); await expect(settings.getByRole("heading", { name: "General", exact: true })).toBeVisible(); + await expect(settings.getByTestId("live-trading-banner")).toBeVisible(); await expect(settings.getByRole("heading", { name: "Account", exact: true })).toBeVisible(); await captureScreenshot(page, testInfo, "settings-shell-general"); + await settings.getByTestId("settings-nav-integrations").click(); + await expect(settings).toHaveAttribute("data-settings-section", "integrations"); + await expect(settings.getByRole("heading", { name: "Integrations", exact: true })).toBeVisible(); + await expect(settings.getByTestId("integrations-settings")).toBeVisible(); + await captureScreenshot(page, testInfo, "settings-shell-integrations"); + await settings.getByTestId("settings-nav-models").click(); await expect(settings).toHaveAttribute("data-settings-section", "models"); await expect(settings.getByRole("heading", { name: "Models", exact: true })).toBeVisible(); diff --git a/apps/web/e2e/ui-appearance.spec.ts b/apps/web/e2e/ui-appearance.spec.ts index 6dc69c7..f49095c 100644 --- a/apps/web/e2e/ui-appearance.spec.ts +++ b/apps/web/e2e/ui-appearance.spec.ts @@ -49,8 +49,7 @@ test("account settings appearance control switches to light mode", async ({ page await signup(page, `ui-appearance-${stamp}@rakazo.test`, "password12", "Appearance QA"); await completeOnboarding(page, testInfo); - await page.getByTestId("user-menu-trigger").click(); - await page.getByRole("button", { name: "Settings", exact: true }).click(); + await page.getByTestId("settings-entry").click(); const settings = page.getByTestId("user-settings"); await expect(settings).toBeVisible(); await expect(settings.getByRole("heading", { name: "Appearance", exact: true })).toBeVisible(); @@ -84,8 +83,7 @@ test("account settings appearance control switches to light mode", async ({ page await expect(inlinePath).toHaveCSS("color", "rgb(26, 26, 26)"); await captureScreenshot(page, testInfo, "inline-code-light"); - await page.getByTestId("user-menu-trigger").click(); - await page.getByRole("button", { name: "Settings", exact: true }).click(); + await page.getByTestId("settings-entry").click(); await expect(settings).toBeVisible(); await settings.getByTestId("ui-appearance-dark").click(); await expect(page.locator("html")).toHaveAttribute("data-theme", "dark"); @@ -114,9 +112,9 @@ test("sidebar bot rows hover with the same tone as the integrations row", async const chiefBg = await readChiefBg(); await captureScreenshot(page, testInfo, "sidebar-row-hover"); - const integrations = sidebar.getByRole("button", { name: "Integrations", exact: true }); - await integrations.hover(); + const settingsEntry = sidebar.getByTestId("settings-entry"); + await settingsEntry.hover(); await expect - .poll(() => integrations.evaluate((el) => getComputedStyle(el).backgroundColor)) + .poll(() => settingsEntry.evaluate((el) => getComputedStyle(el).backgroundColor)) .toBe(chiefBg); }); diff --git a/apps/web/e2e/ui-locale.spec.ts b/apps/web/e2e/ui-locale.spec.ts index 17cc4bf..b0ee4e1 100644 --- a/apps/web/e2e/ui-locale.spec.ts +++ b/apps/web/e2e/ui-locale.spec.ts @@ -77,8 +77,7 @@ test("account settings language picker includes Russian and persists it", async await signup(page, `ui-locale-ru-${stamp}@rakazo.test`, "password12", "Locale QA"); await completeOnboarding(page, testInfo); - await page.getByTestId("user-menu-trigger").click(); - await page.getByRole("button", { name: "Settings", exact: true }).click(); + await page.getByTestId("settings-entry").click(); const settings = page.getByTestId("user-settings"); await expect(settings).toBeVisible(); diff --git a/apps/web/scripts/translations-de.json b/apps/web/scripts/translations-de.json index 0c8ae69..48f3540 100644 --- a/apps/web/scripts/translations-de.json +++ b/apps/web/scripts/translations-de.json @@ -477,6 +477,9 @@ "Server URL": "Server-URL", "Set up voice to call": "Stimme für Anrufe einrichten", "Settings": "Einstellungen", + "Discover now": "Jetzt entdecken", + "Live Trading": "Live Trading", + "Close integrations settings": "Integrationen-Einstellungen schließen", "Settings: General": "Einstellungen: Allgemein", "Settings: Usage": "Einstellungen: Nutzung", "Setup help": "Einrichtungshilfe", diff --git a/apps/web/src/locales/de/messages.po b/apps/web/src/locales/de/messages.po index f95e8d8..e005369 100644 --- a/apps/web/src/locales/de/messages.po +++ b/apps/web/src/locales/de/messages.po @@ -200,9 +200,10 @@ msgstr "Aktionen für {0}" msgid "Actions for space" msgstr "" +#: src/pages/AccountSettingsOverlay.tsx:76 #: src/pages/RoutineEditor.tsx:297 msgid "Active" -msgstr "" +msgstr "Aktiv" #: src/pages/ModelSettingsOverlay.tsx:393 msgid "Active model" @@ -814,6 +815,10 @@ msgstr "Bildvorschau schließen" msgid "Close integrations" msgstr "Integrationen schließen" +#: src/pages/SettingsOverlay.tsx:108 +msgid "Close integrations settings" +msgstr "Integrationen-Einstellungen schließen" + #: src/pages/McpServersOverlay.tsx:258 msgid "Close MCP servers" msgstr "MCP-Server schließen" @@ -2098,6 +2103,10 @@ msgstr "" msgid "Listen" msgstr "" +#: src/pages/AccountSettingsOverlay.tsx:72 +msgid "Live Trading" +msgstr "Live Trading" + #: src/pages/ExternalConversationSettings.tsx:93 msgid "Listening" msgstr "" @@ -3864,6 +3873,10 @@ msgstr "Hilfe & Vibe-Passung" msgid "Trust us: there are many of us. Simple to start — Thermomix or hard math, same calm entry — with expert-depth specialists when you need them, not one mediocre everything-bot." msgstr "Vertrau uns: Es sind viele von uns. Einfach anfangen — Thermomix oder harte Mathe, gleicher ruhiger Einstieg — mit Experten-Spezialisten wenn du sie brauchst, kein mittelmäßiger Alleskönner." +#: src/pages/AccountSettingsOverlay.tsx:88 +msgid "Discover now" +msgstr "Jetzt entdecken" + #: src/components/onboarding/OnboardingDiscoveryShell.tsx:96 msgid "Discovery" msgstr "Entdeckung" diff --git a/apps/web/src/locales/en/messages.po b/apps/web/src/locales/en/messages.po index 8267028..399dc1c 100644 --- a/apps/web/src/locales/en/messages.po +++ b/apps/web/src/locales/en/messages.po @@ -814,6 +814,10 @@ msgstr "Close image preview" msgid "Close integrations" msgstr "Close integrations" +#: src/pages/SettingsOverlay.tsx:108 +msgid "Close integrations settings" +msgstr "Close integrations settings" + #: src/pages/McpServersOverlay.tsx:258 msgid "Close MCP servers" msgstr "Close MCP servers" @@ -2098,6 +2102,10 @@ msgstr "Link a chat app" msgid "Listen" msgstr "Listen" +#: src/pages/AccountSettingsOverlay.tsx:72 +msgid "Live Trading" +msgstr "Live Trading" + #: src/pages/ExternalConversationSettings.tsx:93 msgid "Listening" msgstr "Listening" @@ -3864,6 +3872,10 @@ msgstr "Help & vibe fit" msgid "Trust us: there are many of us. Simple to start — Thermomix or hard math, same calm entry — with expert-depth specialists when you need them, not one mediocre everything-bot." msgstr "Trust us: there are many of us. Simple to start — Thermomix or hard math, same calm entry — with expert-depth specialists when you need them, not one mediocre everything-bot." +#: src/pages/AccountSettingsOverlay.tsx:88 +msgid "Discover now" +msgstr "Discover now" + #: src/components/onboarding/OnboardingDiscoveryShell.tsx:96 msgid "Discovery" msgstr "Discovery" diff --git a/apps/web/src/pages/AccountSettingsOverlay.tsx b/apps/web/src/pages/AccountSettingsOverlay.tsx index d222a72..7130479 100644 --- a/apps/web/src/pages/AccountSettingsOverlay.tsx +++ b/apps/web/src/pages/AccountSettingsOverlay.tsx @@ -1,7 +1,7 @@ import { Trans, useLingui } from "@lingui/react/macro"; import type { AvatarStyle } from "@rakazo/contracts"; import { BotAvatar, Button, Field, FieldLabel, Input, Toggle } from "@rakazo/ui-web"; -import { ChevronDown } from "lucide-react"; +import { Activity, ChevronDown } from "lucide-react"; import { type KeyboardEvent as ReactKeyboardEvent, type RefObject, @@ -33,8 +33,66 @@ export type SettingsGeneralProps = { messagingEnabled?: boolean; onOpenMessaging?: () => void; isDeploymentOwner?: boolean; + tradingMode?: "live" | "paper"; + onDiscoverLiveTrading?: () => void; }; +export function LiveTradingBanner({ + tradingMode, + onDiscover, +}: { + tradingMode: "live" | "paper"; + onDiscover: () => void; +}) { + const isLive = tradingMode === "live"; + + return ( +
+
+
+ + + +
+

+ Live Trading +

+ {isLive ? ( +

+ Active +

+ ) : null} +
+
+ {!isLive ? ( + + ) : null} +
+
+ ); +} + export function GeneralSettingsPanels({ email, name, @@ -43,6 +101,8 @@ export function GeneralSettingsPanels({ messagingEnabled = false, onOpenMessaging, isDeploymentOwner = false, + tradingMode, + onDiscoverLiveTrading, }: SettingsGeneralProps) { const { t } = useLingui(); const [locale, setLocale] = useState(() => getActiveUiLocale()); @@ -78,6 +138,9 @@ export function GeneralSettingsPanels({ return (
+ {tradingMode && onDiscoverLiveTrading ? ( + + ) : null}

Account diff --git a/apps/web/src/pages/PluginsOverlay.tsx b/apps/web/src/pages/PluginsOverlay.tsx index 7a6c48a..5b61d49 100644 --- a/apps/web/src/pages/PluginsOverlay.tsx +++ b/apps/web/src/pages/PluginsOverlay.tsx @@ -73,10 +73,13 @@ export function PluginsOverlay({ onClose, onOpenMcp, activeBotId, + embedded = false, }: { onClose: () => void; onOpenMcp?: () => void; activeBotId?: string; + /** Render panel body only for the shared Settings shell. */ + embedded?: boolean; }) { const { t } = useLingui(); const [setupOpen, setSetupOpen] = useState(false); @@ -663,44 +666,27 @@ export function PluginsOverlay({ ); } - return ( - { - if (!open) onClose(); - }} - > - + { + setQuery(event.target.value); + setVisibleCount(CONNECTION_CATALOG_PAGE_SIZE); + }} + aria-label={t`Search apps`} + placeholder={t`Search apps`} + className="h-11 rounded-xl px-4 md:text-ui-body" + /> +

+ ) : null; + + const catalogBody = ( + <> +
- - - Integrations - - } - > - - - - - {!detailItem ? ( -
- { - setQuery(event.target.value); - setVisibleCount(CONNECTION_CATALOG_PAGE_SIZE); - }} - aria-label={t`Search apps`} - placeholder={t`Search apps`} - className="h-11 rounded-xl px-4 md:text-ui-body" - /> -
- ) : null} - -
+ + ); + + if (embedded) { + return ( +
+ {searchField} + {catalogBody} +
+ ); + } + + return ( + { + if (!open) onClose(); + }} + > + + + + Integrations + + } + > + + + + + {searchField} + + {catalogBody} ); diff --git a/apps/web/src/pages/SettingsOverlay.tsx b/apps/web/src/pages/SettingsOverlay.tsx index dc41e1c..97492ab 100644 --- a/apps/web/src/pages/SettingsOverlay.tsx +++ b/apps/web/src/pages/SettingsOverlay.tsx @@ -1,7 +1,17 @@ import { useLingui } from "@lingui/react/macro"; import type { AvatarStyle, SpaceMemoryConfig } from "@rakazo/contracts"; import { Button, Dialog, DialogClose, DialogContent, DialogTitle } from "@rakazo/ui-web"; -import { Brain, CloudDownload, Cpu, Gauge, Monitor, Settings, Volume2, XIcon } from "lucide-react"; +import { + Brain, + CloudDownload, + Cpu, + Gauge, + LayoutGrid, + Monitor, + Settings, + Volume2, + XIcon, +} from "lucide-react"; import { type ComponentType, useEffect, useRef, useState } from "react"; import { computersAreUnavailable } from "../components/ComputersUnavailableHint"; import { @@ -12,10 +22,12 @@ import { } from "./AccountSettingsOverlay"; import { MemorySettingsOverlay } from "./MemorySettingsOverlay"; import { ModelSettingsOverlay } from "./ModelSettingsOverlay"; +import { PluginsOverlay } from "./PluginsOverlay"; import { VoiceSettingsOverlay } from "./VoiceSettingsOverlay"; export type SettingsSection = | "general" + | "integrations" | "models" | "memory" | "voice" @@ -44,6 +56,10 @@ export function SettingsOverlay({ onMemoryConfigChange, onClose, onVoiceStatusMaybeChanged, + activeBotId, + onOpenMcp, + tradingMode, + onDiscoverLiveTrading, }: { email?: string | null; name: string; @@ -59,6 +75,10 @@ export function SettingsOverlay({ onMemoryConfigChange: (config: SpaceMemoryConfig | null) => void; onClose: () => void; onVoiceStatusMaybeChanged?: () => void | Promise; + activeBotId?: string; + onOpenMcp?: () => void; + tradingMode?: "live" | "paper"; + onDiscoverLiveTrading?: () => void; }) { const { t } = useLingui(); const panelRef = useRef(null); @@ -81,6 +101,7 @@ export function SettingsOverlay({ const navItems: NavItem[] = [ { id: "general", label: t`General`, icon: Settings }, + { id: "integrations", label: t`Integrations`, icon: LayoutGrid }, { id: "models", label: t`Models`, icon: Cpu }, { id: "memory", label: t`Memory`, icon: Brain }, { id: "voice", label: t`Voice`, icon: Volume2 }, @@ -100,7 +121,9 @@ export function SettingsOverlay({ ? t`Close memory settings` : section === "voice" ? t`Close voice settings` - : t`Close user settings`; + : section === "integrations" + ? t`Close integrations settings` + : t`Close user settings`; async function refreshVoiceStatus() { await onVoiceStatusMaybeChanged?.(); @@ -115,7 +138,7 @@ export function SettingsOverlay({ leaveSettings(onClose); } - const widePane = section === "models" || section === "voice"; + const widePane = section === "models" || section === "voice" || section === "integrations"; return ( leaveSettings(onOpenMessaging) : undefined } isDeploymentOwner={isDeploymentOwner} + tradingMode={tradingMode} + onDiscoverLiveTrading={onDiscoverLiveTrading} + /> + ) : null} + {section === "integrations" ? ( + leaveSettings(onOpenMcp) : undefined} /> ) : null} {section === "usage" ? ( diff --git a/apps/web/src/pages/Shell.tsx b/apps/web/src/pages/Shell.tsx index 416ccfb..1535989 100644 --- a/apps/web/src/pages/Shell.tsx +++ b/apps/web/src/pages/Shell.tsx @@ -93,7 +93,6 @@ import { Copy, ExternalLink, Gauge, - LayoutGrid, Lock, LogOut, Maximize2, @@ -266,9 +265,6 @@ const SettingsOverlay = lazy(() => const PeerMessagesOverlay = lazy(() => import("./PeerMessagesOverlay").then((module) => ({ default: module.PeerMessagesOverlay })), ); -const PluginsOverlay = lazy(() => - import("./PluginsOverlay").then((module) => ({ default: module.PluginsOverlay })), -); const McpServersOverlay = lazy(() => import("./McpServersOverlay").then((module) => ({ default: module.McpServersOverlay })), ); @@ -358,15 +354,14 @@ export function ShellPage() { return "live"; }); - const toggleTradingMode = useCallback(() => { - setTradingMode((prev) => { - const next = prev === "live" ? "paper" : "live"; - if (typeof window !== "undefined" && window.localStorage) { - window.localStorage.setItem("evoo_trading_mode", next); - } - return next; - }); - }, []); + const discoverLiveTrading = useCallback(() => { + setTradingMode("live"); + if (typeof window !== "undefined" && window.localStorage) { + window.localStorage.setItem("evoo_trading_mode", "live"); + } + setActiveNavPillar("heute"); + navigate("/app"); + }, [navigate]); useEffect(() => { if (botId) setActiveNavPillar("team"); @@ -539,7 +534,6 @@ export function ShellPage() { function updateSnapshot(update: (prev: ThreadSnapshot | null) => ThreadSnapshot | null) { commitSnapshot(update(snapshotRef.current)); } - const [pluginsOpen, setPluginsOpen] = useState(false); const [mcpOpen, setMcpOpen] = useState(false); const [settingsOpen, setSettingsOpen] = useState(false); const [settingsSection, setSettingsSection] = useState("general"); @@ -3666,35 +3660,16 @@ export function ShellPage() {
- @@ -3713,18 +3688,6 @@ export function ShellPage() { align="start" className="w-[calc(316px-1.5rem)] max-w-[calc(100vw-3rem)] gap-0 p-1 data-closed:animate-none" > -