Collapse duplicate Storage / Physical Disks switch on Proxmox storage
Some checks are pending
Build and Test / Secret Scan (push) Waiting to run
Build and Test / Frontend & Backend (push) Waiting to run

The Proxmox storage tab rendered two separate switches between the
"Storage" and "Physical Disks" views: a Subtabs strip at the top of
StoragePageControls and a segmented control inside the
StorageContentCard header, both bound to the same view state. The
Subtabs label "Storage" also collided with the section nav label one
level above, making the IA read as Proxmox / Storage / Storage.

Drop the Subtabs strip from StoragePageControls and rely on the
segmented control in the table card, matching Pulse's pattern for
binary view-mode choices (Bars/Trends, Grouped/List). Update the
storage page boundary test to forbid Subtabs / StorageViewSwitcher
from creeping back into StoragePageControls.
This commit is contained in:
rcourtman 2026-05-28 10:01:02 +01:00
parent be2f6324f0
commit 5181c489bf
2 changed files with 6 additions and 23 deletions

View file

@ -1,13 +1,11 @@
import { Component, JSX, Show, createMemo } from 'solid-js';
import { FilterBar, type FilterDef } from '@/components/shared/FilterBar';
import { Subtabs } from '@/components/shared/Subtabs';
import { useBreakpoint } from '@/hooks/useBreakpoint';
import { STORAGE_KEYS } from '@/utils/localStorage';
import {
DEFAULT_PHYSICAL_DISK_FACET_FILTER,
type PhysicalDiskFilterOption,
} from '@/features/storageBackups/diskPresentation';
import { STORAGE_VIEW_OPTIONS } from '@/features/storageBackups/storagePagePresentation';
import {
getNextStorageSortDirection,
getStorageSortDirectionIconClass,
@ -81,27 +79,10 @@ type StoragePageControlsProps = {
savedViewsKey?: string;
};
const VIEW_TABS = STORAGE_VIEW_OPTIONS as { value: string; label: string }[];
const storageStatusDot = (className: string) => (
<span class={`h-2 w-2 rounded-full ${className}`} />
);
type StorageViewSwitcherProps = {
view: () => StorageView;
setView: (value: StorageView) => void;
class?: string;
};
export const StorageViewSwitcher: Component<StorageViewSwitcherProps> = (props) => (
<Subtabs
class={props.class}
value={props.view()}
onChange={(value) => props.setView(value as StorageView)}
ariaLabel="Storage view"
tabs={VIEW_TABS}
/>
);
export const StoragePageControls: Component<StoragePageControlsProps> = (props) => {
const { isMobile } = useBreakpoint();
const isPoolsView = () => props.view() === 'pools';
@ -287,8 +268,6 @@ export const StoragePageControls: Component<StoragePageControlsProps> = (props)
return (
<Show when={!props.kioskMode()}>
<div class="flex flex-col gap-2">
<StorageViewSwitcher view={props.view} setView={props.setView} />
<FilterBar
role="group"
ariaLabel={props.filterAriaLabel ?? 'Storage filters'}

View file

@ -1453,8 +1453,6 @@ describe('frontend resource type boundaries', () => {
expect(storageFilterStateSource).toContain('PHYSICAL_DISK_ALL_GROUPS_FILTER_LABEL');
expect(storagePageSource).toContain('StorageContentCard');
expect(storagePageControlsSource).toContain('FilterBar');
expect(storagePageControlsSource).toContain('Subtabs');
expect(storagePageControlsSource).toContain('STORAGE_VIEW_OPTIONS');
expect(storagePageControlsSource).toContain('hasActiveStorageFilters');
expect(storagePageControlsSource).toContain('DEFAULT_STORAGE_SORT_OPTIONS');
expect(storagePageControlsSource).toContain('getNextStorageSortDirection');
@ -1463,6 +1461,12 @@ describe('frontend resource type boundaries', () => {
expect(storagePageControlsSource).not.toContain('StorageControls');
expect(storagePageControlsSource).not.toContain('useStoragePageControlsModel');
expect(storagePageControlsSource).not.toContain('focus:ring-blue-500');
// StoragePageControls used to render a Subtabs strip for "Storage /
// Physical Disks" alongside the segmented control inside the
// StorageContentCard header, producing two switches bound to the same
// view state. The view switch lives only on the table card now.
expect(storagePageControlsSource).not.toContain('Subtabs');
expect(storagePageControlsSource).not.toContain('StorageViewSwitcher');
expect(storageFilterPresentationSource).toContain('export const getStorageSortDirectionTitle');
expect(storageFilterPresentationSource).toContain(
'export const getStorageSortDirectionIconClass',