fix: render in-flight count as static white (remove blink pulse)
This commit is contained in:
@@ -19,8 +19,6 @@ type InflightState = {
|
|||||||
settings: InflightSettings;
|
settings: InflightSettings;
|
||||||
action?: KeyAction<InflightSettings>;
|
action?: KeyAction<InflightSettings>;
|
||||||
unsubscribe?: () => void;
|
unsubscribe?: () => void;
|
||||||
pulseTimer?: ReturnType<typeof setInterval>;
|
|
||||||
pulse: boolean;
|
|
||||||
history: number[];
|
history: number[];
|
||||||
sampler?: ReturnType<typeof setInterval>;
|
sampler?: ReturnType<typeof setInterval>;
|
||||||
};
|
};
|
||||||
@@ -34,7 +32,7 @@ export class InflightMonitor extends SingletonAction<InflightSettings> {
|
|||||||
private stateFor(action: KeyAction<InflightSettings>): InflightState {
|
private stateFor(action: KeyAction<InflightSettings>): InflightState {
|
||||||
let state = this.states.get(action.id);
|
let state = this.states.get(action.id);
|
||||||
if (!state) {
|
if (!state) {
|
||||||
state = { settings: {}, pulse: false, history: [] };
|
state = { settings: {}, history: [] };
|
||||||
this.states.set(action.id, state);
|
this.states.set(action.id, state);
|
||||||
}
|
}
|
||||||
return state;
|
return state;
|
||||||
@@ -57,7 +55,6 @@ export class InflightMonitor extends SingletonAction<InflightSettings> {
|
|||||||
state.unsubscribe?.();
|
state.unsubscribe?.();
|
||||||
if (state.sampler) clearInterval(state.sampler);
|
if (state.sampler) clearInterval(state.sampler);
|
||||||
state.sampler = undefined;
|
state.sampler = undefined;
|
||||||
this.clearPulse(state);
|
|
||||||
this.states.delete(ev.action.id);
|
this.states.delete(ev.action.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -89,26 +86,10 @@ export class InflightMonitor extends SingletonAction<InflightSettings> {
|
|||||||
state: trackerState,
|
state: trackerState,
|
||||||
count,
|
count,
|
||||||
offline,
|
offline,
|
||||||
pulse: state.pulse,
|
|
||||||
history: state.history,
|
history: state.history,
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
if (trackerState === "ready" && count > 0 && !state.pulseTimer) {
|
|
||||||
state.pulseTimer = setInterval(() => {
|
|
||||||
state.pulse = !state.pulse;
|
|
||||||
this.render(state);
|
|
||||||
}, 500);
|
|
||||||
} else if (!(trackerState === "ready" && count > 0) && state.pulseTimer) {
|
|
||||||
this.clearPulse(state);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private clearPulse(state: InflightState): void {
|
|
||||||
if (state.pulseTimer) clearInterval(state.pulseTimer);
|
|
||||||
state.pulseTimer = undefined;
|
|
||||||
state.pulse = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private sample(state: InflightState): void {
|
private sample(state: InflightState): void {
|
||||||
|
|||||||
+1
-3
@@ -19,7 +19,6 @@ export interface InflightRenderOptions {
|
|||||||
state?: ModelRuntimeState;
|
state?: ModelRuntimeState;
|
||||||
count: number;
|
count: number;
|
||||||
offline: boolean;
|
offline: boolean;
|
||||||
pulse: boolean;
|
|
||||||
history?: number[];
|
history?: number[];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -49,11 +48,10 @@ export function renderInflight(opts: InflightRenderOptions): string {
|
|||||||
const bg = opts.state === "ready" ? (isActive ? "#8b2626" : "#1e6b34") : opts.state === "loading" ? "#8a6d1d" : "#3a3a3a";
|
const bg = opts.state === "ready" ? (isActive ? "#8b2626" : "#1e6b34") : opts.state === "loading" ? "#8a6d1d" : "#3a3a3a";
|
||||||
const center = isActive ? `${opts.count}` : opts.state === "ready" ? "IDLE" : opts.state === "loading" ? "LOADING" : "OFF";
|
const center = isActive ? `${opts.count}` : opts.state === "ready" ? "IDLE" : opts.state === "loading" ? "LOADING" : "OFF";
|
||||||
const centerSize = isActive ? 24 : 16;
|
const centerSize = isActive ? 24 : 16;
|
||||||
const opacity = isActive && opts.pulse ? 0.55 : 1;
|
|
||||||
|
|
||||||
const parts: string[] = [
|
const parts: string[] = [
|
||||||
centerText(name, 12, 7, "normal", "#ffffff"),
|
centerText(name, 12, 7, "normal", "#ffffff"),
|
||||||
centerText(center, 40, centerSize, "bold", "#ffffff", opacity),
|
centerText(center, 40, centerSize, "bold", "#ffffff"),
|
||||||
];
|
];
|
||||||
|
|
||||||
if (opts.state === "ready") {
|
if (opts.state === "ready") {
|
||||||
|
|||||||
+13
-14
@@ -8,14 +8,14 @@ test("svgDataUrl wraps an SVG as a base64 data URL", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test("renderInflight: ready + count renders IDLE in green", () => {
|
test("renderInflight: ready + count renders IDLE in green", () => {
|
||||||
const svg = renderInflight({ modelName: "Qwen3.8-27B-NVFP4", state: "ready", count: 0, offline: false, pulse: false });
|
const svg = renderInflight({ modelName: "Qwen3.8-27B-NVFP4", state: "ready", count: 0, offline: false });
|
||||||
assert.match(svg, /IDLE/);
|
assert.match(svg, /IDLE/);
|
||||||
assert.match(svg, /#1e6b34/);
|
assert.match(svg, /#1e6b34/);
|
||||||
assert.doesNotMatch(svg, /ACTIVE/);
|
assert.doesNotMatch(svg, /ACTIVE/);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("renderInflight: ready + count>0 renders the count number on red", () => {
|
test("renderInflight: ready + count>0 renders the count number on red", () => {
|
||||||
const svg = renderInflight({ modelName: "Qwen3.8-27B-NVFP4", state: "ready", count: 2, offline: false, pulse: false });
|
const svg = renderInflight({ modelName: "Qwen3.8-27B-NVFP4", state: "ready", count: 2, offline: false });
|
||||||
assert.match(svg, /2/);
|
assert.match(svg, /2/);
|
||||||
assert.match(svg, /#8b2626/);
|
assert.match(svg, /#8b2626/);
|
||||||
assert.doesNotMatch(svg, /ACTIVE/);
|
assert.doesNotMatch(svg, /ACTIVE/);
|
||||||
@@ -23,40 +23,39 @@ test("renderInflight: ready + count>0 renders the count number on red", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test("renderInflight: idle state does not show a count number", () => {
|
test("renderInflight: idle state does not show a count number", () => {
|
||||||
const svg = renderInflight({ modelName: "A", state: "ready", count: 0, offline: false, pulse: false });
|
const svg = renderInflight({ modelName: "A", state: "ready", count: 0, offline: false });
|
||||||
assert.match(svg, /IDLE/);
|
assert.match(svg, /IDLE/);
|
||||||
assert.doesNotMatch(svg, /font-size="24"/);
|
assert.doesNotMatch(svg, /font-size="24"/);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("renderInflight: draws a count-trend spark when history has 2+ samples", () => {
|
test("renderInflight: draws a count-trend spark when history has 2+ samples", () => {
|
||||||
const svg = renderInflight({ modelName: "A", state: "ready", count: 1, offline: false, pulse: false, history: [0, 1, 2, 1] });
|
const svg = renderInflight({ modelName: "A", state: "ready", count: 1, offline: false, history: [0, 1, 2, 1] });
|
||||||
assert.match(svg, /<polyline/);
|
assert.match(svg, /<polyline/);
|
||||||
assert.match(svg, /<path/);
|
assert.match(svg, /<path/);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("renderInflight: no spark with fewer than 2 history samples", () => {
|
test("renderInflight: no spark with fewer than 2 history samples", () => {
|
||||||
const svg = renderInflight({ modelName: "A", state: "ready", count: 1, offline: false, pulse: false, history: [1] });
|
const svg = renderInflight({ modelName: "A", state: "ready", count: 1, offline: false, history: [1] });
|
||||||
assert.doesNotMatch(svg, /<polyline/);
|
assert.doesNotMatch(svg, /<polyline/);
|
||||||
const none = renderInflight({ modelName: "A", state: "ready", count: 1, offline: false, pulse: false });
|
const none = renderInflight({ modelName: "A", state: "ready", count: 1, offline: false });
|
||||||
assert.doesNotMatch(none, /<polyline/);
|
assert.doesNotMatch(none, /<polyline/);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("renderInflight: pulse toggles opacity while active", () => {
|
test("renderInflight: active count is static white (no blink opacity)", () => {
|
||||||
const a = renderInflight({ modelName: "A", state: "ready", count: 1, offline: false, pulse: false });
|
const svg = renderInflight({ modelName: "A", state: "ready", count: 1, offline: false });
|
||||||
const b = renderInflight({ modelName: "A", state: "ready", count: 1, offline: false, pulse: true });
|
assert.match(svg, />1</);
|
||||||
assert.notEqual(a, b);
|
assert.doesNotMatch(svg, /opacity="0.55"/);
|
||||||
assert.match(b, /opacity="0.55"/);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test("renderInflight: offline and no-model states", () => {
|
test("renderInflight: offline and no-model states", () => {
|
||||||
const offline = renderInflight({ modelName: "A", state: "ready", count: 0, offline: true, pulse: false });
|
const offline = renderInflight({ modelName: "A", state: "ready", count: 0, offline: true });
|
||||||
assert.match(offline, /OFFLINE/);
|
assert.match(offline, /OFFLINE/);
|
||||||
const noModel = renderInflight({ modelName: "unset", state: undefined, count: 0, offline: false, pulse: false });
|
const noModel = renderInflight({ modelName: "unset", state: undefined, count: 0, offline: false });
|
||||||
assert.match(noModel, /NO MODEL/);
|
assert.match(noModel, /NO MODEL/);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("renderInflight: loading renders LOADING in amber", () => {
|
test("renderInflight: loading renders LOADING in amber", () => {
|
||||||
const svg = renderInflight({ modelName: "A", state: "loading", count: 0, offline: false, pulse: false });
|
const svg = renderInflight({ modelName: "A", state: "loading", count: 0, offline: false });
|
||||||
assert.match(svg, /LOADING/);
|
assert.match(svg, /LOADING/);
|
||||||
assert.match(svg, /#8a6d1d/);
|
assert.match(svg, /#8a6d1d/);
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user