Files
cameleer-server/.claude/rules/ui.md
hsiegeln 2835d08418
All checks were successful
CI / cleanup-branch (push) Has been skipped
CI / build (push) Successful in 2m6s
CI / docker (push) Successful in 1m18s
CI / deploy-feature (push) Has been skipped
CI / deploy (push) Successful in 38s
ui(env): explicit switcher button+modal, forced selection, 3px color bar
- Replace EnvironmentSelector "All Envs" dropdown with Button+Modal (DS Modal, forced on first-use).
- Add 8-swatch preset color picker in the Environment settings "Appearance" section; commits via useUpdateEnvironment.
- Render a 3px fixed top bar in the current env's color across every page (z-index 900, below DS modals).
- New env-colors tokens (--env-color-*, light + dark) and envColorVar() helper with slate fallback.
- Vitest coverage for button, modal, and color helpers (13 new specs).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 19:24:48 +02:00

8.5 KiB

paths
paths
ui/**

UI Structure

The UI has 4 main tabs: Exchanges, Dashboard, Runtime, Deployments.

  • Exchanges — route execution search and detail (ui/src/pages/Exchanges/)
  • Dashboard — metrics and stats with L1/L2/L3 drill-down (ui/src/pages/DashboardTab/)
  • Runtime — live agent status, logs, commands (ui/src/pages/RuntimeTab/). AgentHealth supports compact view (dense health-tinted cards) and expanded view (full GroupCard+DataTable per app). View mode persisted to localStorage.
  • Deployments — app management, JAR upload, deployment lifecycle (ui/src/pages/AppsTab/)
    • Config sub-tabs: Monitoring | Resources | Variables | Traces & Taps | Route Recording
    • Create app: full page at /apps/new (not a modal)
    • Deployment progress: ui/src/components/DeploymentProgress.tsx (7-stage step indicator)

Admin pages (ADMIN-only, under /admin/):

  • Sensitive Keys (ui/src/pages/Admin/SensitiveKeysPage.tsx) — global sensitive key masking config. Shows agent built-in defaults as outlined Badge reference, editable Tag pills for custom keys, amber-highlighted push-to-agents toggle. Keys add to (not replace) agent defaults. Per-app sensitive key additions managed via ApplicationConfigController API. Note: AppConfigDetailPage.tsx exists but is not routed in router.tsx.

Key UI Files

  • ui/src/router.tsx — React Router v6 routes
  • ui/src/config.ts — apiBaseUrl, basePath
  • 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
  • ui/src/components/StartupLogPanel.tsx — deployment startup log viewer (container logs from ClickHouse, polls 3s while STARTING)
  • ui/src/api/queries/logs.tsuseStartupLogs hook for container startup log polling, useLogs/useApplicationLogs for bounded log search (single page), useInfiniteApplicationLogs for streaming log views (cursor-paginated, server-side source/level filters)
  • ui/src/api/queries/agents.tsuseAgents for agent list, useInfiniteAgentEvents for cursor-paginated timeline stream
  • ui/src/hooks/useInfiniteStream.ts — tanstack useInfiniteQuery wrapper with top-gated auto-refetch, flattened items[], and refresh() invalidator
  • ui/src/components/InfiniteScrollArea.tsx — scrollable container with IntersectionObserver top/bottom sentinels. Streaming log/event views use this + useInfiniteStream. Bounded views (LogTab, StartupLogPanel) keep useLogs/useStartupLogs

Alerts

  • Sidebar section (buildAlertsTreeNodes in ui/src/components/sidebar-utils.ts) — Inbox, Rules, Silences.
  • Routes in ui/src/router.tsx: /alerts (redirect to inbox), /alerts/inbox, /alerts/rules, /alerts/rules/new, /alerts/rules/:id, /alerts/silences. No redirects for the retired /alerts/all and /alerts/history — stale URLs 404 per the clean-break policy.
  • Pages under ui/src/pages/Alerts/:
    • InboxPage.tsx — single filterable inbox. Filters: severity (multi), state (PENDING/FIRING/RESOLVED, default FIRING), Hide acked toggle (default on), Hide read toggle (default on). Row actions: Acknowledge, Mark read, Silence rule… (duration quick menu), Delete (OPERATOR+, soft-delete with undo toast wired to useRestoreAlert). Bulk toolbar (selection-driven): Acknowledge N · Mark N read · Silence rules · Delete N (ConfirmDialog; OPERATOR+).
    • SilenceRuleMenu.tsx — DS Dropdown-based duration picker (1h / 8h / 24h / Custom…). Used by the row-level and bulk silence actions. "Custom…" navigates to /alerts/silences?ruleId=<id>.
    • RulesListPage.tsx — CRUD + enable/disable toggle + env-promotion dropdown (pure UI prefill, no new endpoint).
    • RuleEditor/RuleEditorWizard.tsx — 5-step wizard (Scope / Condition / Trigger / Notify / Review). form-state.ts is the single source of truth (initialForm / toRequest / validateStep). Seven condition-form subcomponents under RuleEditor/condition-forms/ — including AgentLifecycleForm.tsx (multi-select event-type chips for the six-entry AgentLifecycleEventType allowlist + lookback-window input).
    • SilencesPage.tsx — matcher-based create + end-early. Reads ?ruleId= search param to prefill the Rule ID field (driven by InboxPage's "Silence rule… → Custom…" flow).
    • AlertRow.tsx shared list row; alerts-page.module.css shared styling.
  • Components:
    • NotificationBell.tsx — polls /alerts/unread-count every 30 s (paused when tab hidden via TanStack Query refetchIntervalInBackground: false).
    • AlertStateChip.tsx, SeverityBadge.tsx — shared state/severity indicators.
    • MustacheEditor/ — CodeMirror 6 editor with variable autocomplete + inline linter. Shared between rule title/message, webhook body/header overrides, and (future) Admin Outbound Connection editor (reduced-context mode for URL).
    • MustacheEditor/alert-variables.ts — variable registry aligned with NotificationContextBuilder.java. Add new leaves here whenever the backend context grows.
  • API queries under ui/src/api/queries/: alerts.ts, alertRules.ts, alertSilences.ts, alertNotifications.ts, alertMeta.ts. All env-scoped via useSelectedEnv from alertMeta.
  • CMD-K: buildAlertSearchData in LayoutShell.tsx registers alert and alertRule result categories. Badges convey severity + state. Palette navigates directly to the deep-link path — no sidebar-reveal state for alerts.
  • Sidebar accordion: entering /alerts/* collapses Applications + Admin + Starred (mirrors Admin accordion).
  • Top-nav: <NotificationBell /> is the first child of <TopBar>, sitting alongside SearchTrigger + status ButtonGroup + TimeRangeDropdown + AutoRefreshToggle.

UI Styling

  • Always use @cameleer/design-system CSS variables for colors (var(--amber), var(--error), var(--success), etc.) — never hardcode hex values. This applies to CSS modules, inline styles, and SVG fill/stroke attributes. SVG presentation attributes resolve var() correctly. All colors use CSS variables (no hardcoded hex).
  • Shared CSS modules in ui/src/styles/ (table-section, log-panel, rate-colors, refresh-indicator, chart-card, section-card) — import these instead of duplicating patterns.
  • Shared PageLoader component replaces copy-pasted spinner patterns.
  • Design system components used consistently: Select, Tabs, Toggle, Button, LogViewer, Label — prefer DS components over raw HTML elements. LogViewer renders optional source badges (container, app, agent) via LogEntry.source field (DS v0.1.49+).
  • Environment slugs are auto-computed from display name (read-only in UI).
  • Brand assets: @cameleer/design-system/assets/ provides camel-logo.svg (currentColor), cameleer-{16,32,48,192,512}.png, and cameleer-logo.png. Copied to ui/public/ for use as favicon (favicon-16.png, favicon-32.png) and logo (camel-logo.svg — login dialog 36px, sidebar 28x24px).
  • Sidebar generates /exchanges/ paths directly (no legacy /apps/ redirects). basePath is centralized in ui/src/config.ts; router.tsx imports it instead of re-reading <base> tag.
  • Global user preferences (environment selection) use Zustand stores with localStorage persistence — never URL search params. URL params are for page-specific state only (e.g. ?text= search query). Switching environment resets all filters and remounts pages.