Rename Java packages from com.cameleer3 to com.cameleer, module directories from cameleer3-* to cameleer-*, and all references throughout workflows, Dockerfiles, docs, migrations, and pom.xml. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
6.4 KiB
Status: COMPLETED — All 5 phases executed on 2026-04-09.
UI Consistency Fix — Design Spec
Date: 2026-04-09
Goal: Bring the cameleer-server UI to consistent design system usage — eliminate CSS duplication, hardcoded colors, inline styles, and native HTML where DS components exist.
Source: UI-CONSISTENCY-AUDIT.md (same repo, same date)
Approach: Fix by Category
Extract shared patterns first (unblocks everything), then sweep all files per issue type. Phases are independent after Phase 1 and can run in parallel.
Phase 1: Extract Shared CSS Modules
1a. Table Section Pattern
Create ui/src/styles/table-section.module.css containing:
.tableSection,.tableHeader,.tableTitle,.tableMeta,.tableRight
Update these 5 files to import from shared module instead of local definitions:
pages/DashboardTab/DashboardTab.module.csspages/Admin/AuditLogPage.module.csspages/Admin/ClickHouseAdminPage.module.csspages/Routes/RoutesMetrics.module.csspages/Routes/RouteDetail.module.css
1b. Log Panel Pattern
Create ui/src/styles/log-panel.module.css containing:
.logCard,.logHeader,.logToolbar,.logSearchWrap,.logSearchInput,.logSearchClear,.logClearFilters,.logEmpty,.sortBtn,.refreshBtn,.headerActions
Update AgentHealth.module.css and AgentInstance.module.css to import shared.
1c. Rate Color Classes
Create ui/src/styles/rate-colors.module.css:
.rateGood,.rateWarn,.rateBad,.rateNeutral
Update DashboardTab, RouteDetail, RoutesMetrics.
1d. Tap Modal Dedup
Remove duplicate tap modal CSS from RouteDetail.module.css — it already uses the TapConfigModal component which has its own CSS module.
1e. Refresh Indicator Dedup
Move .refreshIndicator, .refreshDot, .refreshText, @keyframes pulse to shared module. Update DashboardTab and RoutesMetrics.
1f. Other Small Dedup
.chartCard— shared between AgentInstance and RouteDetail.section— shared between AppConfigDetailPage and OidcConfigPage.metaGrid/.metaLabel/.metaValue— shared between AboutMeDialog and UserManagement
Phase 2: Fix Hardcoded Colors in CSS
For each CSS module file:
- Replace naked hex values with design system variables
- Strip hex fallbacks from
var(--token, #hex)->var(--token) - Fix undefined variable names:
--accent->--amber--bg-base->--bg-body--surface->--bg-surface--bg-surface-raised->--bg-raised
- For tint colors without DS tokens (e.g.,
#FDF2F0error background), check if DS provides equivalents. If not, define them as local CSS custom properties at the component level usingcolor-mix()from DS base colors.
Files to fix (priority order):
ExecutionDiagram/ExecutionDiagram.module.css(~57 violations)ProcessDiagram/ProcessDiagram.module.css(~20 violations)Dashboard/Dashboard.module.css(4 violations including naked#5db866)DashboardTab/DashboardTab.module.css(rgba shadow)RoutesMetrics/RoutesMetrics.module.css(rgba shadow)AppsTab/AppsTab.module.css(--accent+ rgba)AgentHealth/AgentHealth.module.css(#fff)LoginPage.module.css,ContentTabs.module.css,EnvironmentSelector.module.css(undefined vars)
Phase 3: Fix Hardcoded Colors in TSX
Create ui/src/utils/theme-colors.ts:
// Reads CSS custom properties from the document root at call time.
// Use for SVG attributes where var() isn't supported in JS string contexts.
export function cssVar(name: string): string {
return getComputedStyle(document.documentElement).getPropertyValue(name).trim();
}
Then replace all hex literals in ProcessDiagram components:
DiagramNode.tsx(~20 values)CompoundNode.tsx(~8 values)DiagramEdge.tsx(~3 values)ConfigBadge.tsx(~3 values)ErrorSection.tsx(~2 values)NodeToolbar.tsx(~2 values)Minimap.tsx(~3 values)ProcessDiagram.tsx(~2 values)
Note: SVG fill and stroke attributes DO support var() in modern browsers. Where the color is a static attribute (not computed in JS), use fill="var(--success)" directly. Only use cssVar() where the value must be a JS string (e.g., in computed color logic).
Also fix TSX color references in:
pages/Dashboard/Dashboard.tsx(hardcoded#3D7C47)components/LayoutShell.tsx(inlinecolor: 'var(--error)'-> CSS class)
Leave data-visualization computed hsl() values (Treemap, PunchcardHeatmap, DiagramNode heatmap) — these are intentional gradients.
Phase 4: Eliminate Inline Styles
4a. Create Missing CSS Modules
pages/Admin/AdminLayout.module.css— extract the single inline layout stylepages/Admin/DatabaseAdminPage.module.css— extract all inline layout/typographyauth/OidcCallback.module.css— extract full-page layout
4b. Extract Shared Components
- Create
components/PageLoader.tsx— replaces the 3 copy-pasted<Spinner>+ flex + padding patterns in router.tsx, RuntimePage, DashboardPage
4c. Move Static Inline Styles to CSS Modules
Priority files (most violations):
AppsTab.tsx— fixed-width inputs -> size classes, visually-hidden pattern, table cell layoutsLayoutShell.tsx— StarredList stylesEnvironmentsPage.tsx— save/cancel button rows, raw<select>stylingRouteDetail.tsx— heading styles, tab panel margins
Phase 5: Replace Native HTML with DS Components (time-permitting)
EnvironmentSelector.tsx— bare<select>-> DSSelectExecutionDiagram/tabs/LogTab.tsx— raw table -> DSLogViewerAppsTab.tsxsub-tab bars -> DSSegmentedTabsorTabsAppConfigDetailPage.tsx—<select>-> DSSelect,<input checkbox>-> DSToggle,<label>-> DSFormFieldAgentHealth.tsx— config bar<select>-> DSSelect, action<button>-> DSButton
Out of Scope
- Responsive design (zero
@mediaqueries) — separate initiative - Data visualization color scales (Treemap, PunchcardHeatmap) — intentional computed gradients
- ProcessDiagram SVG structural class names (
className="nodes") — semantic, acceptable - Adding new DS tokens to the design-system package — use
color-mix()locally if needed
Success Criteria
- Zero naked hex values in CSS modules
- Zero
var(--token, #fallback)patterns (strip fallbacks) - Zero undefined CSS variable names
- CSS class duplication reduced from ~22% to <5%
- All pages with >3 inline styles get a CSS module
- Shared
PageLoadercomponent replaces copy-pasted spinner pattern