Remove the unreachable Workloads chart visibility toggle (#2734)

The Workloads View disclosure rendered `ChartVisibilityToggleButton`
only inside `<Show when={props.onChartsToggle}>`, and no surface passes
`onChartsToggle` or `chartsCollapsed` since the workload summary chart
section was deleted with the summary components. The button had no other
production consumer.

This removes:
- the `Summary` block and import in `WorkloadsFilter.tsx`, and the
`chartsCollapsed` / `onChartsToggle` props in `workloadsFilterModel.ts`
- `ChartVisibilityToggleButton` and its icon import in
`shared/FilterToolbar.tsx`
- the `chart-visibility-toggle-button` rule and
`chart-visibility-local-toggle-labels` pattern guard in
`scripts/shared-template-registry.json`
- the unit tests for the button and the WorkloadsFilter charts describe

The guardrail case that required the primitive now keeps the exact
retired registry ids, export and props out. It deliberately does not
block unrelated future chart controls: a returning summary section is a
product decision that should register its own primitive.

Contract prose: `frontend-primitives.md` (View-disclosure list, the
FilterToolbar rule, the registry paragraph, the FilterBar view-options
list), `performance-and-scalability.md` (the workload chart-visibility
sentence) and `unified-resources.md` rule 12 now say no chart show/hide
control exists instead of describing the deleted one.

Verification:
- frontend `src/features`, `src/components/shared`,
`src/components/Workloads`, `src/utils` suites on pulse-dev: 783 files
passed, one load-induced 5s timeout in `AgentsMachinesTable.test.tsx`
that passes alone (32/32) and does not reference these symbols; tsc,
prettier and the shared-template audit pass
- browser: production builds of this change and of main's three runtime
files, served against the 50-node mock rig, Proxmox and vSphere
overviews at 1440x900 and 390x844 (phone via Filters > View). The View
preferences disclosure shows identical headings, controls and pressed
states before and after, with no Summary heading, no Charts button, no
horizontal overflow and no console errors. The after bundle no longer
carries the `Show charts` copy.
This commit is contained in:
rcourtman
2026-10-08 03:11:57 +01:00
committed by GitHub
11 changed files with 82 additions and 214 deletions
@@ -730,8 +730,8 @@ history, and must not discard the saved note.
Platform-owned workload controls extend the shared `WorkloadsFilter` view
options rather than creating page-local toolbar shells. Persistent presentation
choices compose the shared `ViewOptionsDisclosure` instead of occupying the
primary filter rail: layout, metric style, chart visibility, memory basis, and
columns remain discoverable behind one `View` trigger. The history range stays
primary filter rail: layout, metric style, row hover, memory basis, inventory
totals, and columns remain discoverable behind one `View` trigger. The history range stays
inline in both metric modes because bars now expose an intent-driven row
history lens and Trends keeps the same charts persistent. In Bars the range
renders only at desktop widths while Row hover is set to `History`, the mode
@@ -2655,12 +2655,17 @@ not a replacement status card, CTA band, or page-local nested card.
breakpoint, so Workloads, Storage, Infrastructure, and
future dense toolbars do not strand Filter/Columns/Reset actions as an
isolated second-row fragment. Shared `FilterToolbarPanel` owns
default filter-popover geometry, and `FilterToolbar` owns the shared chart
visibility display action: Workloads, Storage, Infrastructure, and future
summary-bearing pages must use `ChartVisibilityToggleButton` so the
affordance exposes one `Show charts` / `Hide charts` pressed-state contract
instead of rebuilding a one-option segmented control or an in-summary
collapse chevron page by page. Feature state hooks under
default filter-popover geometry. The workload summary chart section that the
shared chart show/hide action toggled is deleted and no other page exposes
one, so the shared toolbar carries no chart show/hide action: the
`ChartVisibilityToggleButton` primitive, its
`chart-visibility-toggle-button` rule, and its
`chart-visibility-local-toggle-labels` pattern guard are retired, and
`SharedPrimitives.guardrails.test.ts` keeps them out. A summary section that
returns through a governed product decision must register one shared
show/hide primitive with an explicit pressed state rather than a page-local
one-option segmented control or in-summary collapse chevron.
Feature state hooks under
`frontend-modern/src/features/` own route-backed query state, selected item
state, and data-window selection for their product surfaces; shared
primitives and reusable presentation helpers may own viewport-safe chrome,
@@ -5821,11 +5826,6 @@ compose that primitive instead of copying rounded-full active selector styling.
`ResourcePicker` report-domain filters are part of that boundary: the picker
owns the reportable resource categories and labels, but the type selector shell
must come from `FilterButtonGroup`.
Chart visibility display actions are registry-backed too.
`ChartVisibilityToggleButton` owns the `Show charts` / `Hide charts` label,
pressed-state, title, icon, and toolbar action styling for summary-bearing
filter surfaces. Pages must compose that primitive instead of recreating local
chart visibility buttons or one-option segmented controls.
Column visibility controls are registry-backed too. `ColumnPicker` owns the
column chooser trigger, panel title, reset action, empty-state copy, hidden
count badge, dropdown width, and outside-click lifecycle through the shared
@@ -6015,7 +6015,7 @@ of `PageControls`. Each page declares a `FilterDef[]` catalog (label, options,
value, defaultValue, group); `FilterBar` renders chips for active filters and
exposes the rest behind a "+ Filter" menu, with type-ahead at both the menu
and chip popovers (`AddFilterMenu` and `FilterChip`). Low-frequency view options
(grouping segmented control, charts toggle, columns picker, sort key) compose
(grouping segmented control, columns picker, sort key) compose
the shared `ViewOptionsDisclosure` through `FilterBar`'s `viewOptions` prop
instead of remaining as permanent toolbar controls. `FilterBar` owns the View
trigger and inline disclosure; feature consumers pass only panel content and
@@ -2852,12 +2852,12 @@ as a full-width responsive checkbox row inside the View disclosure instead of
opening a nested absolute panel or a tall single-column desktop list. On
Proxmox, the non-default Host basis must remain visible in the workload memory
column header after the View disclosure closes. No workload summary chart
section renders today, so the chart-visibility control in
`frontend-modern/src/components/Workloads/WorkloadsFilter.tsx` stays hidden
(no surface passes `onChartsToggle`). If a summary section returns, that
control must expose explicit `Show charts` / `Hide charts` pressed state, and
hiding charts must remove the summary section rather than leaving an empty
collapsed summary band on screen.
section renders today, and `WorkloadsFilter` carries no chart-visibility
control or `onChartsToggle` / `chartsCollapsed` props. A summary section that
returns through a governed product decision must bring its own visibility
control with explicit `Show charts` / `Hide charts` pressed state, and hiding
charts must remove the summary section rather than leaving an empty collapsed
summary band on screen.
The Workloads-owned filter-config assembly now lives in
`frontend-modern/src/components/Workloads/useWorkloadsState.ts`, so future
filter runtime changes must extend through those owners instead of
@@ -2603,10 +2603,12 @@ application resource-provider or WebSocket lifecycle.
in place through that shared runtime and the root app-shell restore path,
instead of looking like a page refresh or remount.
12. Keep summary-chart visibility a display preference, not a unified-resource
filter. Platform/runtime pages may hide or restore chart sections through
shared presentation controls, but those controls must not mutate resource
identity, table membership, source scope, or summary-hover state. The
retired top-level `/infrastructure` page, its summary chart strip, and its
filter. The workload and infrastructure summary chart sections are
retired and no platform page exposes a chart show/hide control today. If a
governed product decision brings one back, hiding or restoring it must not
mutate resource identity, table membership, source scope, or summary-hover
state. The retired top-level
`/infrastructure` page, its summary chart strip, and its
saved-view/route-state machinery must not be reintroduced for this purpose.
15. Keep operator-local resource search on the operator's own names.
Resource-policy redaction is a transmission boundary (`docs/PRIVACY.md`),
@@ -0,0 +1,39 @@
{
"version": 1,
"base_sha": "fd36869223864faae2dd0969a758cde6232f011c",
"verified_at": "2026-10-07T23:02:23Z",
"result": "passed",
"changed_paths": [
"frontend-modern/src/components/Workloads/WorkloadsFilter.tsx",
"frontend-modern/src/components/Workloads/workloadsFilterModel.ts",
"frontend-modern/src/components/shared/FilterToolbar.tsx"
],
"content_sha256": {
"frontend-modern/src/components/Workloads/WorkloadsFilter.tsx": "54f320df506ff23e31ebfb05c927d4ba1bf3760620962200dd19fad72636eeeb",
"frontend-modern/src/components/Workloads/workloadsFilterModel.ts": "09e9c57fc2358564c5f929f06ac28daced329ef961dff3c52df9554f9359c0c2",
"frontend-modern/src/components/shared/FilterToolbar.tsx": "8b7d3b4ffd7218042a2c24384f4175ffb0c9d2080f2a02cbca801b48b097bed6"
},
"routes": ["/proxmox/overview", "/vmware/overview"],
"viewports": [
{
"width": 1440,
"height": 900
},
{
"width": 390,
"height": 844
}
],
"states": [
"Production vite builds of the change (after) and of main's three runtime files (before) served by vite preview on pulse-dev, proxied to the 50-node mock perf rig; the after bundle carries no 'Show charts' copy, the before bundle does",
"Proxmox overview, 929 guests: Workloads View preferences disclosure open on desktop (Layout, Metrics, Row hover, Memory relative to, Inventory totals, Table) and phone (Layout, Metrics, Memory relative to, Inventory totals, Table)",
"vSphere overview: View preferences disclosure open on desktop (Layout, Metrics, Row hover, Inventory totals, Table) and phone (Layout, Metrics, Inventory totals, Table)",
"Before and after identical in every case: same section headings, same controls and pressed states, no Summary heading, no Charts / Show charts / Hide charts button, no horizontal page overflow, no console or page errors"
],
"interactions": [
"Signed in to the dev rig, opened /proxmox/overview and /vmware/overview at each viewport",
"Desktop: clicked View to open the inline View preferences disclosure",
"Phone: opened Filters, then View, to reach the same disclosure",
"Captured every visible heading, button and pressed state inside the disclosure plus page-wide Charts buttons and Summary labels, then diffed before against after"
]
}
@@ -3249,21 +3249,6 @@
"scripts/shared-template-audit.mjs"
]
},
{
"id": "chart-visibility-toggle-button",
"category": "display-toggle",
"summary": "Summary-bearing filter surfaces must compose ChartVisibilityToggleButton for chart show/hide display actions instead of recreating one-off chart toggle buttons.",
"canonical": {
"path": "src/components/shared/FilterToolbar.tsx",
"export": "ChartVisibilityToggleButton"
},
"requiredConsumers": [{ "path": "src/components/Workloads/WorkloadsFilter.tsx" }],
"proof": [
"src/components/shared/SharedPrimitives.guardrails.test.ts",
"src/components/shared/FilterToolbar.test.tsx",
"scripts/shared-template-audit.mjs"
]
},
{
"id": "column-picker-shell",
"category": "column-picker",
@@ -4795,25 +4780,6 @@
"scripts/shared-template-audit.mjs"
]
},
{
"id": "chart-visibility-local-toggle-labels",
"category": "display-toggle",
"summary": "Summary-bearing surfaces must not copy the Show charts / Hide charts display-toggle labels owned by ChartVisibilityToggleButton.",
"canonical": {
"path": "src/components/shared/FilterToolbar.tsx",
"export": "ChartVisibilityToggleButton"
},
"scopes": ["src/components/Workloads", "src/features", "src/pages"],
"extensions": [".tsx"],
"allPatterns": ["Show charts", "Hide charts"],
"legacyReason": "Retired migration debt. Chart visibility display actions must use ChartVisibilityToggleButton; local show/hide chart toggle copies are not allowed.",
"allowedPaths": [],
"ignoredPaths": ["src/components/Workloads/__tests__/WorkloadsFilter.test.tsx"],
"proof": [
"src/components/shared/SharedPrimitives.guardrails.test.ts",
"scripts/shared-template-audit.mjs"
]
},
{
"id": "column-picker-local-column-chooser",
"category": "column-picker",
@@ -10,11 +10,7 @@ import {
type FilterDef,
type FilterSelectOption,
} from '@/components/shared/FilterBar';
import {
ChartVisibilityToggleButton,
FilterActionButton,
FilterSegmentedControl,
} from '@/components/shared/FilterToolbar';
import { FilterActionButton, FilterSegmentedControl } from '@/components/shared/FilterToolbar';
import { GroupedTableModeSegmentedControl } from '@/components/shared/GroupedTableModeSegmentedControl';
import { useBreakpoint } from '@/hooks/useBreakpoint';
import { usePersistentSignal } from '@/hooks/usePersistentSignal';
@@ -426,19 +422,6 @@ export const WorkloadsFilter: Component<WorkloadsFilterProps> = (props) => {
</div>
</Show>
<Show when={props.onChartsToggle}>
<div>
<div class="mb-1.5 text-[10px] font-semibold uppercase tracking-wide text-muted">
Summary
</div>
<ChartVisibilityToggleButton
class="inline-flex!"
collapsed={props.chartsCollapsed?.() ?? false}
onToggle={() => props.onChartsToggle?.()}
/>
</div>
</Show>
<Show when={props.columnVisibility}>
{(visibility) => (
<div>
@@ -931,37 +931,6 @@ describe('WorkloadsFilter', () => {
});
});
describe('charts toggle', () => {
it('renders the Charts button when onChartsToggle is provided', () => {
render(() => (
<WorkloadsFilter
{...makeProps({
chartsCollapsed: vi.fn(() => false),
onChartsToggle: vi.fn(),
})}
/>
));
expect(screen.queryByRole('button', { name: 'Hide charts' })).not.toBeInTheDocument();
expect(
within(openViewPreferences()).getByRole('button', { name: 'Hide charts' }),
).toBeInTheDocument();
});
it('labels the Charts button as a show action when charts are collapsed', () => {
render(() => (
<WorkloadsFilter
{...makeProps({
chartsCollapsed: vi.fn(() => true),
onChartsToggle: vi.fn(),
})}
/>
));
expect(
within(openViewPreferences()).getByRole('button', { name: 'Show charts' }),
).toBeInTheDocument();
});
});
describe('column picker', () => {
it('renders ColumnPicker when columnVisibility is provided', () => {
render(() => (
@@ -75,8 +75,6 @@ export interface WorkloadsFilterProps {
namespaceFilter?: WorkloadsToolbarFilterConfig;
clusterFilter?: WorkloadsToolbarFilterConfig;
containerRuntimeFilter?: WorkloadsToolbarFilterConfig;
chartsCollapsed?: () => boolean;
onChartsToggle?: () => void;
metricDisplayMode?: () => WorkloadsMetricDisplayMode;
setMetricDisplayMode?: (value: WorkloadsMetricDisplayMode) => void;
metricHoverMode?: () => WorkloadsMetricHoverMode;
@@ -2,7 +2,6 @@ import { cleanup, render, screen, waitFor } from '@solidjs/testing-library';
import { For, createSignal } from 'solid-js';
import { afterEach, describe, expect, it, vi } from 'vitest';
import {
ChartVisibilityToggleButton,
FilterHeader,
FilterPopoverTrigger,
FilterToolbarPanel,
@@ -124,34 +123,6 @@ describe('FilterHeader', () => {
).toBe(false);
});
it('keeps chart visibility as an explicit display toggle action', () => {
const [collapsed, setCollapsed] = createSignal(false);
const onToggle = vi.fn(() => setCollapsed((current) => !current));
render(() => (
<ChartVisibilityToggleButton
collapsed={collapsed()}
onToggle={onToggle}
data-testid="charts-toggle"
/>
));
const hideButton = screen.getByRole('button', { name: 'Hide charts' });
expect(hideButton).toHaveTextContent('Charts');
expect(hideButton).toHaveAttribute('aria-pressed', 'true');
expect(hideButton).toHaveAttribute('title', 'Hide charts');
expect(hideButton).toHaveClass('hidden');
expect(hideButton).toHaveClass('lg:inline-flex');
hideButton.click();
const showButton = screen.getByRole('button', { name: 'Show charts' });
expect(onToggle).toHaveBeenCalledTimes(1);
expect(showButton).toHaveTextContent('Charts');
expect(showButton).toHaveAttribute('aria-pressed', 'false');
expect(showButton).toHaveAttribute('title', 'Show charts');
});
it('keeps shared toggle behavior on shell, runtime, and model owners', () => {
expect(toggleSource).toContain('useToggleState');
expect(toggleSource).toContain('getToggleTrackClass');
@@ -1,5 +1,4 @@
import { Component, For, JSX, Show, splitProps } from 'solid-js';
import BarChartIcon from 'lucide-solid/icons/bar-chart';
import ChevronDownIcon from 'lucide-solid/icons/chevron-down';
import ListFilterIcon from 'lucide-solid/icons/list-filter';
import { FormSelect } from './FormSelect';
@@ -410,33 +409,6 @@ export const FilterPopoverTrigger: Component<FilterPopoverTriggerProps> = (props
);
};
interface ChartVisibilityToggleButtonProps extends Omit<
JSX.ButtonHTMLAttributes<HTMLButtonElement>,
'aria-label' | 'aria-pressed' | 'children' | 'onClick' | 'title'
> {
collapsed: boolean;
onToggle: () => void;
}
export const ChartVisibilityToggleButton: Component<ChartVisibilityToggleButtonProps> = (props) => {
const [local, buttonProps] = splitProps(props, ['collapsed', 'onToggle', 'class']);
const label = () => (local.collapsed ? 'Show charts' : 'Hide charts');
return (
<FilterActionButton
{...buttonProps}
class={`hidden lg:inline-flex ${local.class ?? ''}`.trim()}
active={!local.collapsed}
aria-label={label()}
aria-pressed={!local.collapsed}
title={label()}
onClick={() => local.onToggle()}
>
<BarChartIcon class="h-3 w-3" />
Charts
</FilterActionButton>
);
};
interface FilterToolbarPanelProps extends JSX.HTMLAttributes<HTMLDivElement> {
children: JSX.Element;
widthClass?: string;
@@ -1573,56 +1573,25 @@ describe('shared primitive guardrails', () => {
expect(storagePoolsTableSource).not.toContain('HEADER_SORT_BUTTON');
});
it('keeps chart visibility display actions on the shared toolbar toggle', () => {
it('keeps the retired summary chart-visibility toggle out of the shared toolbar', () => {
// The workload summary chart section this toggle controlled is deleted and
// no other page exposes a chart show/hide control. A returning summary
// section is a governed product decision that must register its own
// primitive.
const registry = JSON.parse(sharedTemplateRegistrySource) as {
rules?: Array<{
id: string;
canonical?: { path?: string; export?: string };
requiredConsumers?: Array<{ path?: string }>;
}>;
patternGuards?: Array<{
id: string;
canonical?: { path?: string; export?: string };
allPatterns?: string[];
scopes?: string[];
pathIncludes?: string[];
pathExcludes?: string[];
allowedPaths?: string[];
ignoredPaths?: string[];
}>;
rules?: Array<{ id: string; canonical?: { export?: string } }>;
patternGuards?: Array<{ id: string; canonical?: { export?: string } }>;
};
const registeredRule = registry.rules?.find(
(rule) => rule.id === 'chart-visibility-toggle-button',
);
const registeredGuard = registry.patternGuards?.find(
(guard) => guard.id === 'chart-visibility-local-toggle-labels',
);
const retiredIds = ['chart-visibility-toggle-button', 'chart-visibility-local-toggle-labels'];
for (const entry of [...(registry.rules ?? []), ...(registry.patternGuards ?? [])]) {
expect(retiredIds).not.toContain(entry.id);
expect(entry.canonical?.export).not.toBe('ChartVisibilityToggleButton');
}
expect(registeredRule?.canonical?.path).toBe('src/components/shared/FilterToolbar.tsx');
expect(registeredRule?.canonical?.export).toBe('ChartVisibilityToggleButton');
expect(registeredRule?.requiredConsumers?.map((consumer) => consumer.path)).toEqual([
'src/components/Workloads/WorkloadsFilter.tsx',
]);
expect(registeredGuard?.canonical?.path).toBe('src/components/shared/FilterToolbar.tsx');
expect(registeredGuard?.canonical?.export).toBe('ChartVisibilityToggleButton');
expect(registeredGuard?.allPatterns).toEqual(['Show charts', 'Hide charts']);
expect(registeredGuard?.allowedPaths ?? []).toHaveLength(0);
expect(registeredGuard?.ignoredPaths).toEqual([
'src/components/Workloads/__tests__/WorkloadsFilter.test.tsx',
]);
expect(registeredGuard?.scopes).toEqual(
expect.arrayContaining(['src/components/Workloads', 'src/features', 'src/pages']),
);
expect(filterToolbarSource).toContain('export const ChartVisibilityToggleButton');
expect(filterToolbarSource).toContain("local.collapsed ? 'Show charts' : 'Hide charts'");
expect(filterToolbarSource).toContain('active={!local.collapsed}');
expect(filterToolbarSource).toContain('aria-pressed={!local.collapsed}');
expect(filterToolbarSource).toContain('title={label()}');
expect(workloadsFilterSource).toContain('ChartVisibilityToggleButton');
expect(workloadsFilterSource).not.toContain('Show charts');
expect(workloadsFilterSource).not.toContain('Hide charts');
expect(filterToolbarSource).not.toContain('ChartVisibilityToggleButton');
expect(workloadsFilterSource).not.toContain('ChartVisibilityToggleButton');
expect(workloadsFilterSource).not.toContain('onChartsToggle');
expect(workloadsFilterSource).not.toContain('chartsCollapsed');
});
it('keeps grouped/list table-mode controls on one shared presentation contract', () => {
@@ -8684,7 +8653,6 @@ describe('shared primitive guardrails', () => {
expect(workloadsFilterSource).toContain('trailingControls={');
expect(workloadsFilterSource).not.toContain('ViewOptionsMenu');
expect(workloadsFilterSource).toContain('GroupedTableModeSegmentedControl');
expect(workloadsFilterSource).toContain('ChartVisibilityToggleButton');
expect(workloadsFilterSource).toContain('<ColumnPicker');
expect(workloadsFilterSource).toContain('onClearAll={handleClearAll}');
expect(workloadsFilterSource).toContain('showClearAll={showClearAll}');