Skip to content

Commit dea2d3f

Browse files
authored
Merge pull request #105 from ethpandaops/fix/overrides
fix(overrides): ensure correct overrides generated from CC ui + lightmode
2 parents 2be76ad + 6862883 commit dea2d3f

File tree

14 files changed

+250
-43
lines changed

14 files changed

+250
-43
lines changed

pkg/cc/api_config.go

Lines changed: 32 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import (
1313
"github.com/ethpandaops/xcli/pkg/config"
1414
"github.com/ethpandaops/xcli/pkg/configtui"
1515
"github.com/ethpandaops/xcli/pkg/constants"
16+
"github.com/ethpandaops/xcli/pkg/seeddata"
1617
)
1718

1819
// maskedPassword is the placeholder shown for non-empty passwords.
@@ -56,8 +57,9 @@ type cbtOverridesResponse struct {
5657

5758
// modelEntryResponse is a model with enabled status.
5859
type modelEntryResponse struct {
59-
Name string `json:"name"`
60-
Enabled bool `json:"enabled"`
60+
Name string `json:"name"`
61+
OverrideKey string `json:"overrideKey"`
62+
Enabled bool `json:"enabled"`
6163
}
6264

6365
// cbtOverridesRequest is the request body for saving CBT overrides.
@@ -461,12 +463,18 @@ func (a *apiHandler) handleGetOverrides(
461463
}
462464

463465
for _, name := range externalNames {
464-
enabled := fileExists && !configtui.IsModelDisabled(overrides, name)
466+
overrideKey := name
467+
if db := seeddata.GetExternalModelDatabase(name, xatuCBTPath); db != "" {
468+
overrideKey = db + "." + name
469+
}
470+
471+
enabled := fileExists && !configtui.IsModelDisabled(overrides, overrideKey)
465472

466473
resp.ExternalModels = append(
467474
resp.ExternalModels, modelEntryResponse{
468-
Name: name,
469-
Enabled: enabled,
475+
Name: name,
476+
OverrideKey: overrideKey,
477+
Enabled: enabled,
470478
},
471479
)
472480
}
@@ -477,8 +485,9 @@ func (a *apiHandler) handleGetOverrides(
477485
resp.TransformationModels = append(
478486
resp.TransformationModels,
479487
modelEntryResponse{
480-
Name: name,
481-
Enabled: enabled,
488+
Name: name,
489+
OverrideKey: name,
490+
Enabled: enabled,
482491
},
483492
)
484493
}
@@ -527,9 +536,15 @@ func (a *apiHandler) handlePutOverrides(
527536
)
528537

529538
for _, m := range req.ExternalModels {
539+
overrideKey := m.OverrideKey
540+
if overrideKey == "" {
541+
overrideKey = m.Name
542+
}
543+
530544
externalModels = append(externalModels, configtui.ModelEntry{
531-
Name: m.Name,
532-
Enabled: m.Enabled,
545+
Name: m.Name,
546+
OverrideKey: overrideKey,
547+
Enabled: m.Enabled,
533548
})
534549
}
535550

@@ -538,9 +553,15 @@ func (a *apiHandler) handlePutOverrides(
538553
)
539554

540555
for _, m := range req.TransformationModels {
556+
overrideKey := m.OverrideKey
557+
if overrideKey == "" {
558+
overrideKey = m.Name
559+
}
560+
541561
transformModels = append(transformModels, configtui.ModelEntry{
542-
Name: m.Name,
543-
Enabled: m.Enabled,
562+
Name: m.Name,
563+
OverrideKey: overrideKey,
564+
Enabled: m.Enabled,
544565
})
545566
}
546567

pkg/cc/frontend/.storybook/preview.tsx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import type { Preview, ReactRenderer } from '@storybook/react-vite';
22
import { initialize, mswLoader } from 'msw-storybook-addon';
33
import { withThemeByClassName } from '@storybook/addon-themes';
4+
import { ThemeProvider } from '../src/hooks/useTheme';
45
import '../src/index.css';
56

67
// Initialize MSW
@@ -12,6 +13,11 @@ initialize({
1213
const preview: Preview = {
1314
loaders: [mswLoader],
1415
decorators: [
16+
Story => (
17+
<ThemeProvider>
18+
<Story />
19+
</ThemeProvider>
20+
),
1521
withThemeByClassName<ReactRenderer>({
1622
themes: {
1723
light: '',

pkg/cc/frontend/index.html

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,23 @@
11
<!doctype html>
2-
<html lang="en" class="dark">
2+
<html lang="en">
33
<head>
44
<meta charset="UTF-8" />
55
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
66
<title>xcli Command Center</title>
7+
<script>
8+
// Apply theme synchronously to prevent FOUC
9+
(function() {
10+
var t = localStorage.getItem('xcli-theme');
11+
var dark = t === 'dark' || (t !== 'light' && matchMedia('(prefers-color-scheme: dark)').matches);
12+
if (dark) document.documentElement.classList.add('dark');
13+
})();
14+
</script>
715
<link rel="preconnect" href="https://fonts.googleapis.com" />
816
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
917
<link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;600&display=swap" rel="stylesheet" />
1018
<link rel="icon" type="image/svg+xml" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><text y='.9em' font-size='90'>🍆</text></svg>" />
1119
</head>
12-
<body class="bg-surface text-gray-100 min-h-dvh">
20+
<body class="bg-bg text-text-primary min-h-dvh">
1321
<div id="root"></div>
1422
<script type="module" src="/src/main.tsx"></script>
1523
</body>

pkg/cc/frontend/src/components/CBTOverridesEditor/CBTOverridesEditor.tsx

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -309,7 +309,7 @@ export default function CBTOverridesEditor({ onToast, stack }: CBTOverridesEdito
309309
className={`flex items-center gap-1.5 rounded-xs px-3 py-1.5 text-xs/4 font-medium transition-colors ${
310310
showEnabledOnly
311311
? 'bg-accent/15 text-accent-light ring-1 ring-accent/25'
312-
: 'text-text-muted hover:bg-white/5 hover:text-text-secondary'
312+
: 'text-text-muted hover:bg-hover/5 hover:text-text-secondary'
313313
}`}
314314
>
315315
<svg className="size-3.5" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth={2}>
@@ -326,7 +326,7 @@ export default function CBTOverridesEditor({ onToast, stack }: CBTOverridesEdito
326326
className={`flex items-center gap-1.5 rounded-xs px-3 py-1.5 text-xs/4 font-medium transition-colors ${
327327
showEnvVars
328328
? 'bg-accent/15 text-accent-light ring-1 ring-accent/25'
329-
: 'text-text-muted hover:bg-white/5 hover:text-text-secondary'
329+
: 'text-text-muted hover:bg-hover/5 hover:text-text-secondary'
330330
}`}
331331
>
332332
<svg className="size-3.5" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth={2}>
@@ -495,7 +495,7 @@ export default function CBTOverridesEditor({ onToast, stack }: CBTOverridesEdito
495495
<button
496496
onClick={handleSave}
497497
disabled={saving}
498-
className="rounded-xs bg-accent px-4 py-1.5 text-sm/5 font-medium text-text-primary transition-colors hover:bg-accent-light disabled:opacity-50"
498+
className="rounded-xs bg-accent px-4 py-1.5 text-sm/5 font-medium text-on-accent transition-colors hover:bg-accent-light disabled:opacity-50"
499499
>
500500
{saving ? 'Saving...' : 'Save Overrides'}
501501
</button>
@@ -543,7 +543,7 @@ export default function CBTOverridesEditor({ onToast, stack }: CBTOverridesEdito
543543
</button>
544544
<button
545545
onClick={restartServices}
546-
className="rounded-xs bg-accent px-3 py-1.5 text-xs/4 font-medium text-text-primary transition-colors hover:bg-accent-light"
546+
className="rounded-xs bg-accent px-3 py-1.5 text-xs/4 font-medium text-on-accent transition-colors hover:bg-accent-light"
547547
>
548548
Restart
549549
</button>
@@ -596,14 +596,14 @@ function ModelColumn({
596596
<div className="flex items-center gap-1">
597597
<button
598598
onClick={onEnableAll}
599-
className="rounded-xs px-2 py-0.5 text-xs/4 font-medium text-text-muted transition-colors hover:bg-white/5 hover:text-success"
599+
className="rounded-xs px-2 py-0.5 text-xs/4 font-medium text-text-muted transition-colors hover:bg-hover/5 hover:text-success"
600600
>
601601
All
602602
</button>
603603
<span className="text-border">{'/'}</span>
604604
<button
605605
onClick={onDisableAll}
606-
className="rounded-xs px-2 py-0.5 text-xs/4 font-medium text-text-muted transition-colors hover:bg-white/5 hover:text-error"
606+
className="rounded-xs px-2 py-0.5 text-xs/4 font-medium text-text-muted transition-colors hover:bg-hover/5 hover:text-error"
607607
>
608608
None
609609
</button>
@@ -674,7 +674,7 @@ function ModelRow({
674674
return (
675675
<div
676676
className={`group flex items-center gap-3 border-b border-border/30 px-4 py-2 transition-colors last:border-b-0 ${
677-
isSelected ? 'bg-accent/5' : 'hover:bg-white/2'
677+
isSelected ? 'bg-accent/5' : 'hover:bg-hover/2'
678678
}`}
679679
>
680680
{/* Toggle */}

pkg/cc/frontend/src/components/Header/Header.tsx

Lines changed: 40 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { useState, useRef, useEffect } from 'react';
22
import type { ServiceInfo, InfraInfo } from '@/types';
3+
import { useTheme } from '@/hooks/useTheme';
34

45
interface HeaderProps {
56
services: ServiceInfo[];
@@ -30,6 +31,7 @@ export default function Header({
3031
}: HeaderProps) {
3132
const [dropdownOpen, setDropdownOpen] = useState(false);
3233
const dropdownRef = useRef<HTMLDivElement>(null);
34+
const { theme, cycleTheme } = useTheme();
3335

3436
const running = services.filter(s => s.status === 'running').length;
3537
const healthy = services.filter(s => s.health === 'healthy').length;
@@ -69,6 +71,8 @@ export default function Header({
6971
buttonClass += 'bg-success/10 text-success ring-1 ring-success/20 hover:bg-success/20';
7072
}
7173

74+
const themeTitle = theme === 'system' ? 'Theme: System' : theme === 'light' ? 'Theme: Light' : 'Theme: Dark';
75+
7276
return (
7377
<header className="flex items-center justify-between border-b border-border bg-surface px-5 py-2.5">
7478
<div className="flex items-center gap-3">
@@ -126,7 +130,7 @@ export default function Header({
126130
className={`flex w-full items-center gap-2 px-3 py-1.5 text-left text-xs/4 transition-colors ${
127131
stack === activeStack
128132
? 'bg-accent/10 font-medium text-accent-light'
129-
: 'text-text-secondary hover:bg-white/5'
133+
: 'text-text-secondary hover:bg-hover/5'
130134
}`}
131135
>
132136
{stack === activeStack && <span className="size-1.5 rounded-full bg-accent" />}
@@ -173,7 +177,7 @@ export default function Header({
173177

174178
<button
175179
onClick={onToggleNotifications}
176-
className={`rounded-xs p-1.5 transition-colors hover:bg-white/5 ${
180+
className={`rounded-xs p-1.5 transition-colors hover:bg-hover/5 ${
177181
notificationsEnabled ? 'text-warning' : 'text-text-muted hover:text-text-secondary'
178182
}`}
179183
title={notificationsEnabled ? 'Disable notifications' : 'Enable notifications'}
@@ -198,10 +202,43 @@ export default function Header({
198202
)}
199203
</button>
200204

205+
{/* Theme toggle */}
206+
<button
207+
onClick={cycleTheme}
208+
className="rounded-xs p-1.5 text-text-muted transition-colors hover:bg-hover/5 hover:text-text-secondary"
209+
title={themeTitle}
210+
>
211+
{theme === 'system' ? (
212+
<svg className="size-4" fill="none" viewBox="0 0 24 24" strokeWidth={1.5} stroke="currentColor">
213+
<path
214+
strokeLinecap="round"
215+
strokeLinejoin="round"
216+
d="M9 17.25v1.007a3 3 0 0 1-.879 2.122L7.5 21h9l-.621-.621A3 3 0 0 1 15 18.257V17.25m6-12V15a2.25 2.25 0 0 1-2.25 2.25H5.25A2.25 2.25 0 0 1 3 15V5.25A2.25 2.25 0 0 1 5.25 3h13.5A2.25 2.25 0 0 1 21 5.25Z"
217+
/>
218+
</svg>
219+
) : theme === 'light' ? (
220+
<svg className="size-4" fill="none" viewBox="0 0 24 24" strokeWidth={1.5} stroke="currentColor">
221+
<path
222+
strokeLinecap="round"
223+
strokeLinejoin="round"
224+
d="M12 3v2.25m6.364.386-1.591 1.591M21 12h-2.25m-.386 6.364-1.591-1.591M12 18.75V21m-4.773-4.227-1.591 1.591M5.25 12H3m4.227-4.773L5.636 5.636M15.75 12a3.75 3.75 0 1 1-7.5 0 3.75 3.75 0 0 1 7.5 0Z"
225+
/>
226+
</svg>
227+
) : (
228+
<svg className="size-4" fill="none" viewBox="0 0 24 24" strokeWidth={1.5} stroke="currentColor">
229+
<path
230+
strokeLinecap="round"
231+
strokeLinejoin="round"
232+
d="M21.752 15.002A9.72 9.72 0 0 1 18 15.75c-5.385 0-9.75-4.365-9.75-9.75 0-1.33.266-2.597.748-3.752A9.753 9.753 0 0 0 3 11.25C3 16.635 7.365 21 12.75 21a9.753 9.753 0 0 0 9.002-5.998Z"
233+
/>
234+
</svg>
235+
)}
236+
</button>
237+
201238
{onNavigateConfig && (
202239
<button
203240
onClick={onNavigateConfig}
204-
className="rounded-xs p-1.5 text-text-muted transition-colors hover:bg-white/5 hover:text-text-secondary"
241+
className="rounded-xs p-1.5 text-text-muted transition-colors hover:bg-hover/5 hover:text-text-secondary"
205242
title="Config Management"
206243
>
207244
<svg className="size-4" fill="none" viewBox="0 0 24 24" strokeWidth={1.5} stroke="currentColor">

pkg/cc/frontend/src/components/LabConfigEditor/LabConfigEditor.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ export default function LabConfigEditor({ onToast, onNavigateDashboard, stack }:
138138
}}
139139
className={`rounded-xs px-4 py-1.5 text-sm/5 font-medium transition-colors ${
140140
config.mode === m
141-
? 'bg-accent text-text-primary'
141+
? 'bg-accent text-on-accent'
142142
: 'bg-surface-lighter text-text-tertiary hover:text-text-primary'
143143
}`}
144144
>
@@ -346,7 +346,7 @@ export default function LabConfigEditor({ onToast, onNavigateDashboard, stack }:
346346
</button>
347347
<button
348348
onClick={handleConfirmRestart}
349-
className="rounded-xs bg-error px-3 py-1.5 text-xs/4 font-medium text-text-primary transition-colors hover:bg-error/80"
349+
className="rounded-xs bg-error px-3 py-1.5 text-xs/4 font-medium text-on-accent transition-colors hover:bg-error/80"
350350
>
351351
Save & Restart
352352
</button>
@@ -360,7 +360,7 @@ export default function LabConfigEditor({ onToast, onNavigateDashboard, stack }:
360360
<button
361361
onClick={handleSave}
362362
disabled={saving}
363-
className="rounded-xs bg-accent px-5 py-2 text-sm/5 font-medium text-text-primary transition-colors hover:bg-accent-light disabled:opacity-50"
363+
className="rounded-xs bg-accent px-5 py-2 text-sm/5 font-medium text-on-accent transition-colors hover:bg-accent-light disabled:opacity-50"
364364
>
365365
{saving ? 'Saving...' : 'Save & Regenerate'}
366366
</button>
@@ -446,7 +446,7 @@ function ClusterCard({
446446
onClick={() => onChange({ ...cluster, Mode: m })}
447447
className={`rounded-xs px-2.5 py-1 text-xs/4 font-medium transition-colors ${
448448
cluster.Mode === m
449-
? 'bg-accent text-text-primary'
449+
? 'bg-accent text-on-accent'
450450
: 'bg-surface-lighter text-text-muted hover:text-text-secondary'
451451
}`}
452452
>

pkg/cc/frontend/src/components/LogViewer/LogViewer.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ export default function LogViewer({ logs, activeTab, openTabs, onSelectTab, onCl
143143
e.stopPropagation();
144144
onCloseTab(tab);
145145
}}
146-
className="mr-1 rounded-xs p-0.5 text-text-disabled transition-colors hover:bg-white/10 hover:text-text-secondary"
146+
className="mr-1 rounded-xs p-0.5 text-text-disabled transition-colors hover:bg-hover/10 hover:text-text-secondary"
147147
title="Close tab"
148148
>
149149
<svg className="size-3" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth={2.5}>

pkg/cc/frontend/src/components/ServiceCard/ServiceCard.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ export default function ServiceCard({ service, selected, onSelect, stack }: Serv
7272
<div
7373
onClick={onSelect}
7474
className={`group relative cursor-pointer rounded-xs transition-colors ${
75-
selected ? 'bg-accent/10 ring-1 ring-accent/30' : 'hover:bg-white/3'
75+
selected ? 'bg-accent/10 ring-1 ring-accent/30' : 'hover:bg-hover/3'
7676
}`}
7777
>
7878
{loading && (
@@ -152,7 +152,7 @@ function ActionBtn({ label, onClick }: { label: string; onClick: () => void }) {
152152
e.stopPropagation();
153153
onClick();
154154
}}
155-
className="rounded-xs bg-white/5 px-2 py-0.5 text-xs/4 text-text-tertiary transition-colors hover:bg-white/10 hover:text-text-primary"
155+
className="rounded-xs bg-hover/5 px-2 py-0.5 text-xs/4 text-text-tertiary transition-colors hover:bg-hover/10 hover:text-text-primary"
156156
>
157157
{label}
158158
</button>

pkg/cc/frontend/src/components/ServiceConfigViewer/ServiceConfigViewer.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ export default function ServiceConfigViewer({ onToast, stack }: ServiceConfigVie
141141
className={`group flex items-center gap-2.5 rounded-xs px-3 py-2 text-left transition-colors ${
142142
isActive
143143
? 'bg-accent/15 text-text-primary'
144-
: 'text-text-tertiary hover:bg-white/5 hover:text-text-secondary'
144+
: 'text-text-tertiary hover:bg-hover/5 hover:text-text-secondary'
145145
}`}
146146
>
147147
<svg
@@ -194,7 +194,7 @@ export default function ServiceConfigViewer({ onToast, stack }: ServiceConfigVie
194194
setEditContent(fileContent.overrideContent ?? fileContent.content);
195195
setEditMode(true);
196196
}}
197-
className="flex items-center gap-1.5 rounded-xs px-2.5 py-1 text-xs/4 font-medium text-text-tertiary transition-colors hover:bg-white/5 hover:text-text-primary"
197+
className="flex items-center gap-1.5 rounded-xs px-2.5 py-1 text-xs/4 font-medium text-text-tertiary transition-colors hover:bg-hover/5 hover:text-text-primary"
198198
>
199199
<svg className="size-3" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth={2}>
200200
<path
@@ -226,7 +226,7 @@ export default function ServiceConfigViewer({ onToast, stack }: ServiceConfigVie
226226
<button
227227
onClick={handleSaveOverride}
228228
disabled={saving}
229-
className="rounded-xs bg-accent px-3 py-1 text-xs/4 font-medium text-text-primary transition-colors hover:bg-accent-light disabled:opacity-50"
229+
className="rounded-xs bg-accent px-3 py-1 text-xs/4 font-medium text-on-accent transition-colors hover:bg-accent-light disabled:opacity-50"
230230
>
231231
{saving ? 'Saving...' : 'Save Override'}
232232
</button>

0 commit comments

Comments
 (0)