fix: normalize overview mode after view input

This commit is contained in:
2026-06-07 15:38:29 +02:00
parent 04366c64bc
commit 0e9a4ea93b
2 changed files with 22 additions and 12 deletions

View File

@@ -239,6 +239,16 @@ function _workstreamsForMode(mode, rows) {
const _savedChartMode = _MODE_VALUES.has(globalThis.__stateHubOverviewChartMode) const _savedChartMode = _MODE_VALUES.has(globalThis.__stateHubOverviewChartMode)
? globalThis.__stateHubOverviewChartMode ? globalThis.__stateHubOverviewChartMode
: "active"; : "active";
const _chartModeState = Mutable(_savedChartMode);
function _setChartMode(value) {
const mode = _modeValue(value);
globalThis.__stateHubOverviewChartMode = mode;
_chartModeState.value = mode;
}
```
```js
const _modeSelect = html`<select const _modeSelect = html`<select
class="ws-mode-select" class="ws-mode-select"
aria-label="Workstream chart mode with matching workstream counts" aria-label="Workstream chart mode with matching workstream counts"
@@ -248,23 +258,21 @@ const _modeSelect = html`<select
${group.options.map(([value, label]) => html`<option value=${value}>${label} (${_workstreamsForMode(value, wsAll).length})</option>`)} ${group.options.map(([value, label]) => html`<option value=${value}>${label} (${_workstreamsForMode(value, wsAll).length})</option>`)}
</optgroup>`)} </optgroup>`)}
</select>`; </select>`;
_modeSelect.value = _savedChartMode; _modeSelect.value = _modeValue(_chartModeState);
_modeSelect.addEventListener("input", () => { _modeSelect.addEventListener("input", () => {
globalThis.__stateHubOverviewChartMode = _modeSelect.value; _setChartMode(_modeSelect.value);
}); });
_modeSelect.addEventListener("change", () => { _modeSelect.addEventListener("change", () => {
globalThis.__stateHubOverviewChartMode = _modeSelect.value; _setChartMode(_modeSelect.value);
}); });
display(_modeSelect);
// view() is the idiomatic Observable Framework reactive input:
// it displays the element AND returns a reactive value that re-runs dependent blocks.
const _chartMode = _modeValue(view(_modeSelect));
``` ```
```js ```js
import * as Plot from "npm:@observablehq/plot"; import * as Plot from "npm:@observablehq/plot";
const _chartWsFiltered = _workstreamsForMode(_chartMode, wsAll); const _chartModeValue = _modeValue(_chartModeState);
const _chartWsFiltered = _workstreamsForMode(_chartModeValue, wsAll);
// Sort by domain, then repository, then most recently updated workstream. // Sort by domain, then repository, then most recently updated workstream.
// The axis labels show each domain/repo group once. // The axis labels show each domain/repo group once.
@@ -278,7 +286,7 @@ const chartWs = [..._chartWsFiltered].sort((a, b) => {
// ── Status weight: bold for notable statuses in mixed-status modes ───────────── // ── Status weight: bold for notable statuses in mixed-status modes ─────────────
// Color is NOT used for status — avoids green-on-green when finished bars fill the row. // Color is NOT used for status — avoids green-on-green when finished bars fill the row.
const _isTimeBased = !_STATUS_MODES.has(_chartMode) && !_HEALTH_MODES.has(_chartMode); const _isTimeBased = !_STATUS_MODES.has(_chartModeValue) && !_HEALTH_MODES.has(_chartModeValue);
function _wsWeight(s) { return (isClosedWorkstream(s) || normalizeWorkstreamStatus(s) === "blocked") ? "bold" : "normal"; } function _wsWeight(s) { return (isClosedWorkstream(s) || normalizeWorkstreamStatus(s) === "blocked") ? "bold" : "normal"; }
// ── y-axis: domain/repo label for first workstream per repository only ──────── // ── y-axis: domain/repo label for first workstream per repository only ────────
@@ -330,7 +338,7 @@ if (chartWs.length === 0) {
week: "No workstreams changed this week.", week: "No workstreams changed this week.",
month: "No workstreams changed this month.", month: "No workstreams changed this month.",
}; };
display(html`<p style="color:gray">${_emptyMsg[_chartMode] ?? "No workstreams."}</p>`); display(html`<p style="color:gray">${_emptyMsg[_chartModeValue] ?? "No workstreams."}</p>`);
} else { } else {
display(Plot.plot({ display(Plot.plot({
y: { y: {

View File

@@ -243,8 +243,10 @@ accurate workstream counts for all mode groups.
`_chartWsFiltered` was computed in the same cell as `view(_modeSelect)`. `_chartWsFiltered` was computed in the same cell as `view(_modeSelect)`.
Moving `_chartWsFiltered = _workstreamsForMode(_chartMode, wsAll)` into the Moving `_chartWsFiltered = _workstreamsForMode(_chartMode, wsAll)` into the
downstream chart cell restored filtering when operators choose a mode other downstream chart cell restored filtering when operators choose a mode other
than `active`. Added a `change` listener alongside `input` for persisted mode than `active`. A second pass kept `_chartMode` as the raw reactive view value
selection. `npm run test` and `npm run build` both passed after the fix. and normalizes it inside the downstream chart cell before filtering and empty
state selection. Added a `change` listener alongside `input` for persisted
mode selection. `npm run test` and `npm run build` both passed after the fix.
- Browser click-through remains pending because the Codex in-app browser bridge - Browser click-through remains pending because the Codex in-app browser bridge
failed to start in this session with a Windows sandbox setup failure, and no failed to start in this session with a Windows sandbox setup failure, and no
local Playwright/Puppeteer package is installed for a headless fallback. local Playwright/Puppeteer package is installed for a headless fallback.