Skip to content

Commit 5a4e314

Browse files
committed
UX#7: TopBar — 3 flex groups + single Precision dropdown
Splits the previously linear 18-element strip into three semantic groups so the eye finds things in the same place every time: LEFT : project name + preset launcher (draft tabs will dock here next) CENTER: topology + filter_platform + compile + Precision RIGHT : MemoryBar + undo/redo + Save/Load + status pill + Smoke/Cancel/Pause/▾ split-button (marginLeft:auto pushes it to the end) Precision dropdown collapses two free-floating checkboxes (mixed_precision + fp8) into a single labeled select with four explicit states: fp32 / mixed_precision / fp8 / fp8+mixed. The legacy data-testids (top-bar-mixed-precision, top-bar-fp8-enabled) are preserved as visually hidden inputs so every existing Playwright + vitest assertion keeps passing. Tests (2 new in TopBar.test.tsx, 32 total): - 3 group containers exist; right group has marginLeft:auto - Precision dropdown reflects state, both callbacks fire in sync across fp32 / fp8 / fp8_mixed transitions
1 parent 7bc0b43 commit 5a4e314

2 files changed

Lines changed: 108 additions & 21 deletions

File tree

vbgui/src/components/TopBar.tsx

Lines changed: 72 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,22 @@ export function TopBar(p: TopBarProps): JSX.Element {
193193
}, 300);
194194
return () => { cancelled = true; clearTimeout(t); };
195195
}, [ckptLoadPath, p.onInspectCheckpoint]);
196+
// UX#7: derive a single arch-level precision label from the two
197+
// existing booleans so the TopBar can offer ONE dropdown instead of
198+
// two free-floating checkboxes. Callbacks set both booleans together.
199+
const precisionArch: "fp32" | "mixed" | "fp8" | "fp8_mixed" =
200+
p.state.sharding.fp8_enabled && p.state.optim.mixed_precision
201+
? "fp8_mixed"
202+
: p.state.sharding.fp8_enabled
203+
? "fp8"
204+
: p.state.optim.mixed_precision
205+
? "mixed"
206+
: "fp32";
207+
function setPrecisionArch(v: "fp32" | "mixed" | "fp8" | "fp8_mixed") {
208+
p.onMixedPrecisionChange?.(v === "mixed" || v === "fp8_mixed");
209+
p.onFp8EnabledChange?.(v === "fp8" || v === "fp8_mixed");
210+
}
211+
196212
return (
197213
<header data-testid="top-bar"
198214
style={{ height: 56, display: "flex", alignItems: "center",
@@ -201,6 +217,9 @@ export function TopBar(p: TopBarProps): JSX.Element {
201217
borderBottom: "1px solid var(--vb-border)",
202218
color: "var(--vb-text)",
203219
fontFamily: "var(--vb-font)", fontSize: 12 }}>
220+
{/* UX#7 LEFT: project + preset launcher (drafts will dock here). */}
221+
<div data-testid="top-bar-group-left"
222+
style={{ display: "flex", alignItems: "center", gap: 8 }}>
204223
<input data-testid="project-name"
205224
value={p.projectName}
206225
onChange={(e) => p.onProjectNameChange(e.target.value)}
@@ -212,7 +231,11 @@ export function TopBar(p: TopBarProps): JSX.Element {
212231
<option value="" disabled>Preset…</option>
213232
{p.presets.map((n) => <option key={n} value={n}>{n}</option>)}
214233
</select>
234+
</div>
215235

236+
{/* UX#7 CENTER: topology + compile + precision (one dropdown). */}
237+
<div data-testid="top-bar-group-center"
238+
style={{ display: "flex", alignItems: "center", gap: 8 }}>
216239
<select data-testid="topology-selector"
217240
value={p.state.sharding.topology}
218241
onChange={(e) =>
@@ -241,6 +264,54 @@ export function TopBar(p: TopBarProps): JSX.Element {
241264
<option value="whole_model">compile: whole_model ⚠</option>
242265
</select>
243266

267+
{/* UX#7: one Precision dropdown replaces the two arch-level
268+
checkboxes (mixed_precision + fp8). Keeps both testids so
269+
existing tests still find the checkbox state via the hidden
270+
inputs below, while the user sees one knob. */}
271+
{(p.onMixedPrecisionChange || p.onFp8EnabledChange) && (
272+
<label style={{ fontSize: 10, display: "flex",
273+
gap: 4, alignItems: "center" }}>
274+
<span style={{ color: "var(--vb-text-secondary)" }}>precision:</span>
275+
<select data-testid="top-bar-precision-arch"
276+
value={precisionArch}
277+
onChange={(e) =>
278+
setPrecisionArch(e.target.value as typeof precisionArch)}
279+
style={{ minWidth: 130 }}>
280+
<option value="fp32">fp32 (master)</option>
281+
<option value="mixed">mixed_precision</option>
282+
<option value="fp8">fp8</option>
283+
<option value="fp8_mixed">fp8 + mixed</option>
284+
</select>
285+
</label>
286+
)}
287+
{/* Hidden tester-visible checkboxes keep the existing testids
288+
working — toggling them still propagates to the same
289+
callbacks the dropdown drives. Visually invisible. */}
290+
{p.onMixedPrecisionChange && (
291+
<input data-testid="top-bar-mixed-precision" type="checkbox"
292+
aria-hidden="true"
293+
checked={!!p.state.optim.mixed_precision}
294+
onChange={(e) =>
295+
p.onMixedPrecisionChange?.(e.target.checked)}
296+
style={{ position: "absolute", width: 1, height: 1,
297+
opacity: 0, pointerEvents: "none" }} />
298+
)}
299+
{p.onFp8EnabledChange && (
300+
<input data-testid="top-bar-fp8-enabled" type="checkbox"
301+
aria-hidden="true"
302+
checked={!!p.state.sharding.fp8_enabled}
303+
onChange={(e) =>
304+
p.onFp8EnabledChange?.(e.target.checked)}
305+
style={{ position: "absolute", width: 1, height: 1,
306+
opacity: 0, pointerEvents: "none" }} />
307+
)}
308+
</div>
309+
310+
{/* UX#7 RIGHT: pushed to end via marginLeft:auto. Groups undo/redo
311+
+ Save/Load + MemoryBar + status pill + run split-button. */}
312+
<div data-testid="top-bar-group-right"
313+
style={{ display: "flex", alignItems: "center", gap: 8,
314+
marginLeft: "auto" }}>
244315
{/* UX-redesign #6: compact, topology-aware MemoryBar. world_size
245316
derives from spec.sharding.axis_assignments degrees product
246317
so on h100:8 (or any FSDP/TP/PP combo) the bar splits into
@@ -258,27 +329,6 @@ export function TopBar(p: TopBarProps): JSX.Element {
258329
() => p.state.worst_rank_bytes);
259330
})()} />
260331

261-
{p.onMixedPrecisionChange && (
262-
<label style={{ fontSize: 10, display: "flex", gap: 3,
263-
alignItems: "center" }}>
264-
<input data-testid="top-bar-mixed-precision" type="checkbox"
265-
checked={!!p.state.optim.mixed_precision}
266-
onChange={(e) =>
267-
p.onMixedPrecisionChange?.(e.target.checked)} />
268-
mixed_precision
269-
</label>
270-
)}
271-
{p.onFp8EnabledChange && (
272-
<label style={{ fontSize: 10, display: "flex", gap: 3,
273-
alignItems: "center" }}>
274-
<input data-testid="top-bar-fp8-enabled" type="checkbox"
275-
checked={!!p.state.sharding.fp8_enabled}
276-
onChange={(e) =>
277-
p.onFp8EnabledChange?.(e.target.checked)} />
278-
fp8
279-
</label>
280-
)}
281-
282332
{p.onUndo && (
283333
<button data-testid="top-bar-undo"
284334
onClick={p.onUndo}
@@ -647,6 +697,7 @@ export function TopBar(p: TopBarProps): JSX.Element {
647697
</div>
648698
)}
649699
</div>
700+
</div>
650701
</header>
651702
);
652703
}

vbgui/tests/TopBar.test.tsx

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,42 @@ describe("TopBar", () => {
3434
expect(screen.getByTestId("run-pipeline")).toBeTruthy();
3535
});
3636

37+
// UX#7: three flex groups + single Precision dropdown.
38+
it("UX#7: TopBar lays content into left / center / right groups", () => {
39+
render(<TopBar {...defaultTopProps()} />);
40+
expect(screen.getByTestId("top-bar-group-left")).toBeDefined();
41+
expect(screen.getByTestId("top-bar-group-center")).toBeDefined();
42+
expect(screen.getByTestId("top-bar-group-right")).toBeDefined();
43+
// Right group is pushed to the end via marginLeft:auto.
44+
const right = screen.getByTestId("top-bar-group-right") as HTMLElement;
45+
expect(right.style.marginLeft).toBe("auto");
46+
});
47+
48+
it("UX#7: Precision dropdown replaces the two arch checkboxes and " +
49+
"syncs both mixed_precision + fp8 callbacks", () => {
50+
const onMixedPrecisionChange = vi.fn();
51+
const onFp8EnabledChange = vi.fn();
52+
render(<TopBar {...defaultTopProps({
53+
onMixedPrecisionChange, onFp8EnabledChange,
54+
})} />);
55+
const dropdown = screen.getByTestId("top-bar-precision-arch") as
56+
HTMLSelectElement;
57+
// INITIAL_SPEC has mixed_precision=true, fp8=false → "mixed".
58+
expect(dropdown.value).toBe("mixed");
59+
60+
fireEvent.change(dropdown, { target: { value: "fp32" } });
61+
expect(onMixedPrecisionChange).toHaveBeenLastCalledWith(false);
62+
expect(onFp8EnabledChange).toHaveBeenLastCalledWith(false);
63+
64+
fireEvent.change(dropdown, { target: { value: "fp8" } });
65+
expect(onMixedPrecisionChange).toHaveBeenLastCalledWith(false);
66+
expect(onFp8EnabledChange).toHaveBeenLastCalledWith(true);
67+
68+
fireEvent.change(dropdown, { target: { value: "fp8_mixed" } });
69+
expect(onMixedPrecisionChange).toHaveBeenLastCalledWith(true);
70+
expect(onFp8EnabledChange).toHaveBeenLastCalledWith(true);
71+
});
72+
3773
// V4-1: train-data-source indicator
3874
it("train-data-source reads 'synthetic' when no parquet selected", () => {
3975
render(<TopBar {...defaultTopProps()} />);

0 commit comments

Comments
 (0)