diff --git a/.claude/rules/ui.md b/.claude/rules/ui.md index 3914dbe3..8b362d79 100644 --- a/.claude/rules/ui.md +++ b/.claude/rules/ui.md @@ -25,6 +25,8 @@ The UI has 4 main tabs: **Exchanges**, **Dashboard**, **Runtime**, **Deployments - `ui/src/auth/auth-store.ts` — Zustand: accessToken, user, roles, login/logout - `ui/src/api/environment-store.ts` — Zustand: selected environment (localStorage) - `ui/src/components/ContentTabs.tsx` — main tab switcher +- `ui/src/components/EnvironmentSwitcherButton.tsx` + `EnvironmentSwitcherModal.tsx` — explicit env picker (button in TopBar; DS `Modal`-based list). Replaces the retired `EnvironmentSelector` (All-Envs dropdown). When `envRecords.length > 0` and the stored `selectedEnv` no longer matches any env, `LayoutShell` opens the modal in `forced` mode (non-dismissible). Switcher pulls env records from `useEnvironments()` (admin endpoint; readable by VIEWER+). +- `ui/src/components/env-colors.ts` + `ui/src/styles/env-colors.css` — 8-swatch preset palette for the per-environment color indicator. Tokens `--env-color-slate/red/amber/green/teal/blue/purple/pink` are defined for both light and dark themes. `envColorVar(name)` falls back to `slate` for unknown values. `LayoutShell` renders a 3px fixed top bar in the current env's color (z-index 900, below DS modals). - `ui/src/components/ExecutionDiagram/` — interactive trace view (canvas) - `ui/src/components/ProcessDiagram/` — ELK-rendered route diagram - `ui/src/hooks/useScope.ts` — TabKey type, scope inference diff --git a/ui/src/api/queries/admin/environments.ts b/ui/src/api/queries/admin/environments.ts index c32888c0..e3c8310e 100644 --- a/ui/src/api/queries/admin/environments.ts +++ b/ui/src/api/queries/admin/environments.ts @@ -9,6 +9,7 @@ export interface Environment { enabled: boolean; defaultContainerConfig: Record; jarRetentionCount: number | null; + color: string; createdAt: string; } @@ -22,6 +23,7 @@ export interface UpdateEnvironmentRequest { displayName: string; production: boolean; enabled: boolean; + color?: string; } export function useEnvironments() { diff --git a/ui/src/components/EnvironmentSelector.module.css b/ui/src/components/EnvironmentSelector.module.css deleted file mode 100644 index 2d3518ac..00000000 --- a/ui/src/components/EnvironmentSelector.module.css +++ /dev/null @@ -1,4 +0,0 @@ -/* Layout wrapper — DS Select handles its own appearance */ -.select { - min-width: 100px; -} diff --git a/ui/src/components/EnvironmentSelector.tsx b/ui/src/components/EnvironmentSelector.tsx deleted file mode 100644 index 2230e654..00000000 --- a/ui/src/components/EnvironmentSelector.tsx +++ /dev/null @@ -1,30 +0,0 @@ -import { useMemo } from 'react'; -import { Select } from '@cameleer/design-system'; -import styles from './EnvironmentSelector.module.css'; - -interface EnvironmentSelectorProps { - environments: string[]; - value: string | undefined; - onChange: (env: string | undefined) => void; -} - -export function EnvironmentSelector({ environments, value, onChange }: EnvironmentSelectorProps) { - if (environments.length === 0) return null; - - const options = useMemo( - () => [ - { value: '', label: 'All Envs' }, - ...environments.map((env) => ({ value: env, label: env })), - ], - [environments], - ); - - return ( -