diff --git a/frontend-modern/src/components/Settings/reportingResourceTypes.ts b/frontend-modern/src/components/Settings/reportingResourceTypes.ts deleted file mode 100644 index d2150f6374..0000000000 --- a/frontend-modern/src/components/Settings/reportingResourceTypes.ts +++ /dev/null @@ -1 +0,0 @@ -export { toReportingResourceType, type ReportingResourceType } from '@/utils/reportingResourceTypes'; diff --git a/frontend-modern/src/components/shared/TypeColumn.guardrails.test.ts b/frontend-modern/src/components/shared/TypeColumn.guardrails.test.ts index 4485f8a8e7..31a897b7ef 100644 --- a/frontend-modern/src/components/shared/TypeColumn.guardrails.test.ts +++ b/frontend-modern/src/components/shared/TypeColumn.guardrails.test.ts @@ -1,6 +1,5 @@ import { describe, expect, it } from 'vitest'; import guestRowModelSource from '@/components/Workloads/guestRowModel.tsx?raw'; -import responsiveSource from '@/types/responsive.ts?raw'; import typeColumnDefinitionSource from '@/utils/typeColumnDefinition.ts?raw'; import typeColumnContractSource from '@/utils/typeColumnContract.ts?raw'; @@ -12,7 +11,6 @@ const sourceFiles = import.meta.glob(['../../**/*.ts', '../../**/*.tsx'], { const INLINE_TYPE_COLUMN_PATTERN = /\{\s*id:\s*'type',\s*label:\s*'Type'[\s\S]*?toggleable:\s*true[\s\S]*?\}/g; -const RESPONSIVE_TYPE_BLOCK_PATTERN = /type:\s*\{[\s\S]*?\n\s*\},/; describe('type column guardrails', () => { it('keeps the canonical Type column definition in the shared helper', () => { @@ -35,27 +33,6 @@ describe('type column guardrails', () => { expect(typeColumnDefinitionSource).not.toContain("label: 'Type'"); expect(typeColumnDefinitionSource).not.toContain("width: '60px'"); expect(typeColumnDefinitionSource).not.toContain("sortKey: 'type'"); - expect(responsiveSource).toContain('TYPE_COLUMN_ID'); - expect(responsiveSource).toContain('TYPE_COLUMN_LABEL'); - expect(responsiveSource).toContain('TYPE_COLUMN_PRIORITY'); - expect(responsiveSource).toContain('TYPE_COLUMN_SORTABLE'); - expect(responsiveSource).toContain('TYPE_COLUMN_MIN_WIDTH'); - expect(responsiveSource).toContain('TYPE_COLUMN_MAX_WIDTH'); - expect(responsiveSource).toContain('TYPE_COLUMN_ALIGN'); - const responsiveTypeBlock = responsiveSource.match(RESPONSIVE_TYPE_BLOCK_PATTERN)?.[0] ?? ''; - expect(responsiveTypeBlock).toContain('TYPE_COLUMN_ID'); - expect(responsiveTypeBlock).toContain('TYPE_COLUMN_LABEL'); - expect(responsiveTypeBlock).toContain('TYPE_COLUMN_PRIORITY'); - expect(responsiveTypeBlock).toContain('TYPE_COLUMN_SORTABLE'); - expect(responsiveTypeBlock).toContain('TYPE_COLUMN_MIN_WIDTH'); - expect(responsiveTypeBlock).toContain('TYPE_COLUMN_MAX_WIDTH'); - expect(responsiveTypeBlock).toContain('TYPE_COLUMN_ALIGN'); - expect(responsiveTypeBlock).not.toContain("id: 'type'"); - expect(responsiveTypeBlock).not.toContain("label: 'Type'"); - expect(responsiveTypeBlock).not.toContain("priority: 'essential'"); - expect(responsiveTypeBlock).not.toContain('sortable: true'); - expect(responsiveTypeBlock).not.toContain("minWidth: '60px'"); - expect(responsiveTypeBlock).not.toContain("maxWidth: '80px'"); }); it('routes runtime Type columns through the shared helper', () => { @@ -124,7 +101,7 @@ describe('type column guardrails', () => { ]); }); - it('limits direct type column contract imports to the shared helper, responsive schema, and label presentation util', () => { + it('limits direct type column contract imports to the shared helper and label presentation util', () => { const runtimeEntries = Object.entries(sourceFiles).filter( ([path]) => !path.endsWith('.test.ts') && !path.endsWith('.test.tsx'), ); @@ -137,7 +114,6 @@ describe('type column guardrails', () => { .sort(); expect(directContractImportUsers).toEqual([ - '../../types/responsive.ts', '../../utils/typeColumnDefinition.ts', '../../utils/typeColumnPresentation.ts', ]); diff --git a/frontend-modern/src/types/responsive.ts b/frontend-modern/src/types/responsive.ts deleted file mode 100644 index 4dd91bccef..0000000000 --- a/frontend-modern/src/types/responsive.ts +++ /dev/null @@ -1,358 +0,0 @@ -import type { Component, JSX } from 'solid-js'; -import type { ColumnPriority, Breakpoint } from '@/hooks/useBreakpoint'; -import { - TYPE_COLUMN_ALIGN, - TYPE_COLUMN_ID, - TYPE_COLUMN_LABEL, - TYPE_COLUMN_MAX_WIDTH, - TYPE_COLUMN_MIN_WIDTH, - TYPE_COLUMN_PRIORITY, - TYPE_COLUMN_SORTABLE, -} from '@/utils/typeColumnContract'; - -/** - * Configuration for a responsive table column - */ -export interface ColumnConfig { - /** Unique identifier for the column, typically matches a property key */ - id: string; - - /** Display label for the column header */ - label: string; - - /** Priority determines at which breakpoint the column becomes visible */ - priority: ColumnPriority; - - /** Icon component to show in header on mobile (optional) */ - icon?: Component<{ class?: string }>; - - /** Whether the column is sortable */ - sortable?: boolean; - - /** Sort key - defaults to id if sortable is true */ - sortKey?: string; - - /** Minimum width for the column (CSS value, e.g., '100px', '10%') */ - minWidth?: string; - - /** Maximum width for the column (CSS value) */ - maxWidth?: string; - - /** Fixed width for the column (CSS value) - used with table-layout: fixed */ - width?: string; - - /** Flex grow factor for grid layout (default: 1) */ - flex?: number; - - /** Text alignment */ - align?: 'left' | 'center' | 'right'; - - /** Whether this column should be sticky (typically for name columns) */ - sticky?: boolean; - - /** Custom CSS class for the column */ - className?: string; - - /** Custom CSS class for the header */ - headerClassName?: string; - - /** Custom CSS class for cells */ - cellClassName?: string; -} - -/** - * Extended column config with render functions - */ -export interface ColumnConfigWithRender extends ColumnConfig { - /** - * Render function for mobile view (compact) - * If not provided, falls back to renderDesktop - */ - renderMobile?: (item: T, index: number) => JSX.Element; - - /** - * Render function for desktop view (full) - * Required if renderMobile is provided - */ - renderDesktop?: (item: T, index: number) => JSX.Element; - - /** - * Simple render function for both mobile and desktop - * Use this for columns that don't need different mobile/desktop rendering - */ - render?: (item: T, index: number) => JSX.Element; - - /** - * Get sort value from item (for custom sorting) - */ - getSortValue?: (item: T) => string | number | null | undefined; -} - -/** - * Common metric column configuration for CPU, Memory, Disk metrics - */ -export interface MetricColumnConfig { - type: 'cpu' | 'memory' | 'disk'; - getValue: (item: unknown) => number; - getLabel?: (item: unknown) => string; - getSublabel?: (item: unknown) => string | undefined; - getResourceId?: (item: unknown) => string; -} - -/** - * Sort state for a table - */ -export interface SortState { - key: string | null; - direction: 'asc' | 'desc'; -} - -/** - * Grid template configuration for responsive tables - */ -export interface GridTemplateConfig { - /** Column configurations */ - columns: ColumnConfig[]; - - /** Current breakpoint for visibility calculations */ - breakpoint: Breakpoint; - - /** Whether to include sticky column handling */ - hasStickyColumn?: boolean; -} - -/** - * Props for responsive table header - */ -export interface ResponsiveHeaderProps { - /** Column configuration */ - column: ColumnConfig; - - /** Current sort state */ - sortState?: SortState; - - /** Sort handler */ - onSort?: (key: string) => void; - - /** Whether currently on mobile */ - isMobile?: boolean; -} - -/** - * Props for responsive metric cell - */ -export interface ResponsiveMetricCellProps { - /** Metric value (0-100 percentage) */ - value: number; - - /** Metric type for theming */ - type: 'cpu' | 'memory' | 'disk'; - - /** Primary label (usually formatted percentage) */ - label?: string; - - /** Secondary label (e.g., "4.2GB / 8GB") */ - sublabel?: string; - - /** Resource ID for sparkline tracking */ - resourceId?: string; - - /** Whether the resource is running/online */ - isRunning?: boolean; - - /** Whether currently on mobile */ - isMobile?: boolean; - - /** Fallback content when not running */ - fallback?: JSX.Element; -} - -/** - * Standard column definitions that can be reused across tables - */ -export const STANDARD_COLUMNS = { - /** Name/identifier column - always visible, typically sticky on mobile */ - name: { - id: 'name', - label: 'Name', - priority: 'essential' as ColumnPriority, - sortable: true, - sticky: true, - minWidth: '150px', - flex: 1.5, - }, - - /** Type badge column (VM/LXC, Container/Service, etc.) */ - type: { - id: TYPE_COLUMN_ID, - label: TYPE_COLUMN_LABEL, - priority: TYPE_COLUMN_PRIORITY as ColumnPriority, - sortable: TYPE_COLUMN_SORTABLE, - minWidth: TYPE_COLUMN_MIN_WIDTH, - maxWidth: TYPE_COLUMN_MAX_WIDTH, - align: TYPE_COLUMN_ALIGN, - }, - - /** VMID column */ - vmid: { - id: 'vmid', - label: 'VMID', - priority: 'essential' as ColumnPriority, - sortable: true, - minWidth: '60px', - maxWidth: '80px', - align: 'center' as const, - }, - - /** Status column */ - status: { - id: 'status', - label: 'Status', - priority: 'primary' as ColumnPriority, - sortable: true, - minWidth: '70px', - maxWidth: '100px', - align: 'center' as const, - }, - - /** Uptime column */ - uptime: { - id: 'uptime', - label: 'Uptime', - priority: 'secondary' as ColumnPriority, - sortable: true, - minWidth: '80px', - maxWidth: '100px', - }, - - /** CPU metric column */ - cpu: { - id: 'cpu', - label: 'CPU', - priority: 'essential' as ColumnPriority, - sortable: true, - minWidth: '100px', - flex: 1.5, - align: 'center' as const, - }, - - /** Memory metric column */ - memory: { - id: 'memory', - label: 'Memory', - priority: 'essential' as ColumnPriority, - sortable: true, - minWidth: '100px', - flex: 1.5, - align: 'center' as const, - }, - - /** Disk metric column */ - disk: { - id: 'disk', - label: 'Disk', - priority: 'essential' as ColumnPriority, - sortable: true, - minWidth: '100px', - flex: 1.5, - align: 'center' as const, - }, - - /** Disk read I/O column */ - diskRead: { - id: 'diskRead', - label: 'D Read', - priority: 'detailed' as ColumnPriority, - sortable: true, - minWidth: '100px', - flex: 1, - }, - - /** Disk write I/O column */ - diskWrite: { - id: 'diskWrite', - label: 'D Write', - priority: 'detailed' as ColumnPriority, - sortable: true, - minWidth: '100px', - flex: 1, - }, - - /** Network in column */ - networkIn: { - id: 'networkIn', - label: 'Net In', - priority: 'detailed' as ColumnPriority, - sortable: true, - minWidth: '100px', - flex: 1, - }, - - /** Network out column */ - networkOut: { - id: 'networkOut', - label: 'Net Out', - priority: 'detailed' as ColumnPriority, - sortable: true, - minWidth: '100px', - flex: 1, - }, - - /** Temperature column */ - temperature: { - id: 'temperature', - label: 'Temp', - priority: 'supplementary' as ColumnPriority, - sortable: true, - minWidth: '45px', - maxWidth: '65px', - align: 'center' as const, - }, - - /** Node column (for grouped views) */ - node: { - id: 'node', - label: 'Node', - priority: 'supplementary' as ColumnPriority, - sortable: true, - minWidth: '100px', - }, - - /** Storage column */ - storage: { - id: 'storage', - label: 'Storage', - priority: 'supplementary' as ColumnPriority, - sortable: true, - minWidth: '100px', - }, - - /** Size column */ - size: { - id: 'size', - label: 'Size', - priority: 'secondary' as ColumnPriority, - sortable: true, - minWidth: '80px', - align: 'right' as const, - }, - - /** Time/date column */ - time: { - id: 'time', - label: 'Time', - priority: 'primary' as ColumnPriority, - sortable: true, - minWidth: '120px', - }, - - /** Actions column (expand buttons, etc.) */ - actions: { - id: 'actions', - label: '', - priority: 'essential' as ColumnPriority, - sortable: false, - minWidth: '32px', - maxWidth: '48px', - }, -} satisfies Record; diff --git a/frontend-modern/src/utils/__tests__/frontendResourceTypeBoundaries.test.ts b/frontend-modern/src/utils/__tests__/frontendResourceTypeBoundaries.test.ts index 9545575d55..3dcc01f98a 100644 --- a/frontend-modern/src/utils/__tests__/frontendResourceTypeBoundaries.test.ts +++ b/frontend-modern/src/utils/__tests__/frontendResourceTypeBoundaries.test.ts @@ -3,7 +3,6 @@ import appSource from '@/App.tsx?raw'; import resourceTypeCompatSource from '@/utils/resourceTypeCompat.ts?raw'; import discoveryTypesSource from '@/types/discovery.ts?raw'; import resourceLinksSource from '@/routing/resourceLinks.ts?raw'; -import reportingResourceTypesSource from '@/components/Settings/reportingResourceTypes.ts?raw'; import reportingResourceTypesUtilSource from '@/utils/reportingResourceTypes.ts?raw'; import chartsApiSource from '@/api/charts.ts?raw'; import investigateAlertButtonSource from '@/components/Alerts/InvestigateAlertButton.tsx?raw'; @@ -544,11 +543,9 @@ describe('frontend resource type boundaries', () => { expect(resourceLinksSource).not.toContain("normalized === 'k8s'"); expect(sourcePlatformsSource).toContain('export const normalizeSourcePlatformQueryValue'); - expect(reportingResourceTypesSource).toContain('@/utils/reportingResourceTypes'); expect(reportingResourceTypesUtilSource).toContain('export function toReportingResourceType'); expect(reportingResourceTypesUtilSource).toContain("case 'k8s-cluster'"); expect(reportingResourceTypesUtilSource).toContain("return 'k8s';"); - expect(reportingResourceTypesSource).not.toContain("case 'host'"); expect(chartsApiSource).toContain('export function toMetricsHistoryAPIResourceType'); expect(chartsApiSource).toContain('export function asMetricsHistoryResourceType');