From 9cb698e736fad9789c8f5e805f1d823d97ce40bd Mon Sep 17 00:00:00 2001 From: rcourtman Date: Wed, 20 May 2026 17:08:27 +0100 Subject: [PATCH] Unify platform sub-page status toggles with overview compact pills MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PlatformTableToolbar was rendering FilterButtonGroup with the default variant (heavy bg-surface-alt box, border-heavy active state, fixed blue active color) on every platform sub-page — Replication, Ceph, Backups, Mail Gateway, Docker Hosts/Services, K8s Clusters/Nodes/ Deployments, TrueNAS Systems, vSphere Hosts. The Proxmox / Docker overview WorkloadsFilter, by contrast, uses the compact variant with per-option tone, so "Running" goes green, "Stopped" goes red, etc. Switch the shared toolbar to compact and enrich the shared status filter option arrays (PLATFORM_STATUS_FILTER_OPTIONS, PLATFORM_HEALTH_FILTER_OPTIONS) with tone + leading status dot. Same treatment for the bespoke filter arrays on Replication (Healthy / Failed / Pending / Disabled), Ceph (Healthy / Warning / Critical), and Backups archives + tasks (Protected / Verified / Unverified, OK / Failed / Running). Backups archives and tasks also flip from default to compact variant since they bypass PlatformTableToolbar. Settings panel FilterButtonGroup usages stay default — different context, intentionally heavier. --- .../features/platformPage/sharedPlatformPage.tsx | 15 +++++++++------ .../src/features/proxmox/ProxmoxBackupsTable.tsx | 16 ++++++++++------ .../src/features/proxmox/ProxmoxCephTable.tsx | 13 ++++++++----- .../features/proxmox/ProxmoxReplicationTable.tsx | 15 +++++++++------ 4 files changed, 36 insertions(+), 23 deletions(-) diff --git a/frontend-modern/src/features/platformPage/sharedPlatformPage.tsx b/frontend-modern/src/features/platformPage/sharedPlatformPage.tsx index 39c3ddf544..a6306d9638 100644 --- a/frontend-modern/src/features/platformPage/sharedPlatformPage.tsx +++ b/frontend-modern/src/features/platformPage/sharedPlatformPage.tsx @@ -132,18 +132,20 @@ export function PlatformErrorState(props: { // 'running' vs 'online', 'stopped' vs 'offline') collapse to one chip set. export type PlatformResourceStatusFilter = 'all' | 'online' | 'degraded' | 'offline'; +const statusDot = (className: string) => ; + export const PLATFORM_STATUS_FILTER_OPTIONS: FilterOption[] = [ { value: 'all', label: 'All' }, - { value: 'online', label: 'Online' }, - { value: 'degraded', label: 'Degraded' }, - { value: 'offline', label: 'Offline' }, + { value: 'online', label: 'Online', tone: 'success', leading: statusDot('bg-emerald-500') }, + { value: 'degraded', label: 'Degraded', tone: 'warning', leading: statusDot('bg-amber-500') }, + { value: 'offline', label: 'Offline', tone: 'danger', leading: statusDot('bg-red-500') }, ]; export const PLATFORM_HEALTH_FILTER_OPTIONS: FilterOption[] = [ { value: 'all', label: 'All' }, - { value: 'online', label: 'Healthy' }, - { value: 'degraded', label: 'Degraded' }, - { value: 'offline', label: 'Offline' }, + { value: 'online', label: 'Healthy', tone: 'success', leading: statusDot('bg-emerald-500') }, + { value: 'degraded', label: 'Degraded', tone: 'warning', leading: statusDot('bg-amber-500') }, + { value: 'offline', label: 'Offline', tone: 'danger', leading: statusDot('bg-red-500') }, ]; const ONLINE_STATUSES = new Set(['online', 'running']); @@ -289,6 +291,7 @@ export function PlatformTableToolbar(props: { /> { ); } +const statusDot = (className: string) => ; + const ARCHIVE_STATUS_FILTERS: FilterOption<'all' | 'protected' | 'verified' | 'unverified'>[] = [ { value: 'all', label: 'All' }, - { value: 'protected', label: 'Protected' }, - { value: 'verified', label: 'Verified' }, - { value: 'unverified', label: 'Unverified' }, + { value: 'protected', label: 'Protected', tone: 'info', leading: statusDot('bg-blue-500') }, + { value: 'verified', label: 'Verified', tone: 'success', leading: statusDot('bg-emerald-500') }, + { value: 'unverified', label: 'Unverified', tone: 'warning', leading: statusDot('bg-amber-500') }, ]; const TASK_STATUS_FILTERS: FilterOption<'all' | 'ok' | 'failed' | 'running'>[] = [ { value: 'all', label: 'All' }, - { value: 'ok', label: 'OK' }, - { value: 'failed', label: 'Failed' }, - { value: 'running', label: 'Running' }, + { value: 'ok', label: 'OK', tone: 'success', leading: statusDot('bg-emerald-500') }, + { value: 'failed', label: 'Failed', tone: 'danger', leading: statusDot('bg-red-500') }, + { value: 'running', label: 'Running', tone: 'info', leading: statusDot('bg-blue-500') }, ]; export const ProxmoxBackupsTable: Component<{ @@ -400,6 +402,7 @@ export const ProxmoxBackupsTable: Component<{ ; + +const STATUS_FILTER_OPTIONS: FilterOption[] = [ { value: 'all', label: 'All' }, - { value: 'healthy', label: 'Healthy' }, - { value: 'warning', label: 'Warning' }, - { value: 'critical', label: 'Critical' }, -] satisfies Array<{ value: CephStatusFilter; label: string }>; + { value: 'healthy', label: 'Healthy', tone: 'success', leading: statusDot('bg-emerald-500') }, + { value: 'warning', label: 'Warning', tone: 'warning', leading: statusDot('bg-amber-500') }, + { value: 'critical', label: 'Critical', tone: 'danger', leading: statusDot('bg-red-500') }, +]; function classify(resource: Resource): CephStatusFilter { const raw = (resource.ceph?.healthStatus ?? resource.status ?? '').toUpperCase(); diff --git a/frontend-modern/src/features/proxmox/ProxmoxReplicationTable.tsx b/frontend-modern/src/features/proxmox/ProxmoxReplicationTable.tsx index 153be3c42f..63bcf451da 100644 --- a/frontend-modern/src/features/proxmox/ProxmoxReplicationTable.tsx +++ b/frontend-modern/src/features/proxmox/ProxmoxReplicationTable.tsx @@ -23,6 +23,7 @@ import { } from '@/components/shared/Table'; import { apiFetch } from '@/utils/apiClient'; import { formatRelativeTime } from '@/utils/format'; +import type { FilterOption } from '@/components/shared/FilterButtonGroup'; import { PLATFORM_TABLE_BODY_CLASS, PLATFORM_TABLE_CARD_CLASS, @@ -42,13 +43,15 @@ import type { ReplicationJob, ReplicationJobsResponse } from '@/types/api'; type ReplicationStatusFilter = 'all' | 'healthy' | 'failed' | 'pending' | 'disabled'; -const STATUS_FILTER_OPTIONS = [ +const statusDot = (className: string) => ; + +const STATUS_FILTER_OPTIONS: FilterOption[] = [ { value: 'all', label: 'All' }, - { value: 'healthy', label: 'Healthy' }, - { value: 'failed', label: 'Failed' }, - { value: 'pending', label: 'Pending' }, - { value: 'disabled', label: 'Disabled' }, -] satisfies Array<{ value: ReplicationStatusFilter; label: string }>; + { value: 'healthy', label: 'Healthy', tone: 'success', leading: statusDot('bg-emerald-500') }, + { value: 'failed', label: 'Failed', tone: 'danger', leading: statusDot('bg-red-500') }, + { value: 'pending', label: 'Pending', tone: 'warning', leading: statusDot('bg-amber-500') }, + { value: 'disabled', label: 'Disabled', tone: 'muted', leading: statusDot('bg-slate-400') }, +]; interface ReplicationStatusIndicator { variant: StatusIndicatorVariant;