diff --git a/frontend-modern/src/features/docker/DockerPageSurface.tsx b/frontend-modern/src/features/docker/DockerPageSurface.tsx index 90ee80bc4..c3bb4675d 100644 --- a/frontend-modern/src/features/docker/DockerPageSurface.tsx +++ b/frontend-modern/src/features/docker/DockerPageSurface.tsx @@ -1,21 +1,16 @@ -import { useLocation } from '@solidjs/router'; import ContainerIcon from 'lucide-solid/icons/container'; import { Show, createMemo } from 'solid-js'; import { WorkloadsSurface } from '@/components/Workloads/WorkloadsSurface'; import { useUnifiedResources } from '@/hooks/useUnifiedResources'; import { PlatformErrorState, - PlatformSectionTabs, PlatformTableEmptyState, } from '@/features/platformPage/sharedPlatformPage'; import { DockerHostsTable } from './DockerHostsTable'; import { DockerServicesTable } from './DockerServicesTable'; import { - DOCKER_TAB_SPECS, buildDockerPageModel, buildDockerContainerDefaultHiddenColumnIds, - buildVisibleDockerTabSpecs, - type DockerPageTabId, } from './dockerPageModel'; const DOCKER_RESOURCE_QUERY = 'type=agent,docker-host,app-container,docker-service'; @@ -27,12 +22,10 @@ const DOCKER_WORKLOAD_COLUMN_LABEL_OVERRIDES = { context: 'Host', disk: 'Writable layer', } as const; -const VALID_TABS = new Set(DOCKER_TAB_SPECS.map((tab) => tab.id)); const dockerIcon = () => ; export function DockerPageSurface() { - const location = useLocation(); const { resources, loading, error, refetch } = useUnifiedResources({ query: DOCKER_RESOURCE_QUERY, cacheKey: 'docker-workspace', @@ -42,24 +35,9 @@ export function DockerPageSurface() { const dockerWorkloadDefaultHiddenColumns = createMemo(() => buildDockerContainerDefaultHiddenColumnIds(model().containers), ); - const visibleTabs = createMemo(() => buildVisibleDockerTabSpecs(model())); - const visibleTabIds = createMemo( - () => new Set(visibleTabs().map((tab) => tab.id)), - ); - const activeTab = createMemo(() => { - const segment = location.pathname.split('/').filter(Boolean)[1] as DockerPageTabId | undefined; - if (!segment || !VALID_TABS.has(segment)) return 'overview'; - return visibleTabIds().has(segment) ? segment : 'overview'; - }); return (
- - 0} fallback={ @@ -90,44 +68,14 @@ export function DockerPageSurface() { /> } > - -
- - - 0}> - - -
-
- +
+ - - - - + 0}> + + +
diff --git a/frontend-modern/src/features/docker/__tests__/dockerPageModel.test.ts b/frontend-modern/src/features/docker/__tests__/dockerPageModel.test.ts index 7bb4433c7..40d67f145 100644 --- a/frontend-modern/src/features/docker/__tests__/dockerPageModel.test.ts +++ b/frontend-modern/src/features/docker/__tests__/dockerPageModel.test.ts @@ -1,10 +1,8 @@ import { describe, expect, it } from 'vitest'; import type { Resource } from '@/types/resource'; import { - DOCKER_TAB_SPECS, buildDockerContainerDefaultHiddenColumnIds, buildDockerPageModel, - buildVisibleDockerTabSpecs, hasDockerSwarmEvidence, } from '../dockerPageModel'; @@ -20,14 +18,6 @@ const makeResource = (resource: Partial & Pick { - it('declares the Docker section set with hosts, containers, and Swarm services', () => { - expect(DOCKER_TAB_SPECS.map((tab) => tab.id)).toEqual([ - 'overview', - 'containers', - 'services', - ]); - }); - it('buckets Docker hosts, containers, and Swarm services from canonical resources', () => { const model = buildDockerPageModel([ makeResource({ id: 'docker-host-1', type: 'agent' }), @@ -64,32 +54,6 @@ describe('dockerPageModel', () => { expect(model.resources).toEqual([]); }); - it('shows Docker subtabs only when canonical resource evidence exists', () => { - expect( - buildVisibleDockerTabSpecs( - buildDockerPageModel([makeResource({ id: 'docker-host-1', type: 'agent' })]), - ).map((tab) => tab.id), - ).toEqual(['overview']); - - expect( - buildVisibleDockerTabSpecs( - buildDockerPageModel([ - makeResource({ id: 'docker-host-1', type: 'agent' }), - makeResource({ id: 'ctr-1', type: 'app-container' }), - ]), - ).map((tab) => tab.id), - ).toEqual(['overview', 'containers']); - - expect( - buildVisibleDockerTabSpecs( - buildDockerPageModel([ - makeResource({ id: 'docker-host-1', type: 'agent' }), - makeResource({ id: 'svc-1', type: 'docker-service' }), - ]), - ).map((tab) => tab.id), - ).toEqual(['overview', 'services']); - }); - it('hides Docker container I/O columns by default when the snapshot has no I/O telemetry', () => { expect( buildDockerContainerDefaultHiddenColumnIds([ diff --git a/frontend-modern/src/features/docker/dockerPageModel.ts b/frontend-modern/src/features/docker/dockerPageModel.ts index 9f81b3139..d35c4c25b 100644 --- a/frontend-modern/src/features/docker/dockerPageModel.ts +++ b/frontend-modern/src/features/docker/dockerPageModel.ts @@ -1,20 +1,6 @@ import { resolveResourcePlatformType } from '@/utils/sourcePlatforms'; import type { Resource, ResourceType } from '@/types/resource'; -export type DockerPageTabId = 'overview' | 'containers' | 'services'; - -export type DockerTabSpec = { - id: DockerPageTabId; - label: string; - path: string; -}; - -export const DOCKER_TAB_SPECS: readonly DockerTabSpec[] = [ - { id: 'overview', label: 'Hosts', path: '/docker/overview' }, - { id: 'containers', label: 'Containers', path: '/docker/containers' }, - { id: 'services', label: 'Swarm services', path: '/docker/services' }, -] as const; - const DOCKER_HOST_TYPES = new Set(['agent', 'docker-host']); const DOCKER_CONTAINER_TYPES = new Set(['app-container']); const DOCKER_SERVICE_TYPES = new Set(['docker-service']); @@ -108,15 +94,3 @@ export function buildDockerPageModel(resources: Resource[]): DockerPageModel { }; } -export function buildVisibleDockerTabSpecs(model: DockerPageModel): DockerTabSpec[] { - const visible = new Set(['overview']); - - if (model.containers.length > 0) { - visible.add('containers'); - } - if (model.services.length > 0) { - visible.add('services'); - } - - return DOCKER_TAB_SPECS.filter((tab) => visible.has(tab.id)); -} diff --git a/tests/integration/tests/68-platform-pages-shell.spec.ts b/tests/integration/tests/68-platform-pages-shell.spec.ts index 6e4a057f9..8ee94e3d7 100644 --- a/tests/integration/tests/68-platform-pages-shell.spec.ts +++ b/tests/integration/tests/68-platform-pages-shell.spec.ts @@ -51,14 +51,6 @@ type PlatformPageCase = { }; const PLATFORM_PAGES: readonly PlatformPageCase[] = [ - { - id: 'docker', - rootPath: '/docker', - testId: 'docker-page', - ariaLabel: 'Docker sections', - tabPaths: ['/docker/overview', '/docker/containers', '/docker/services'], - populatedTabPaths: ['/docker/overview', '/docker/containers', '/docker/services'], - }, { id: 'kubernetes', rootPath: '/kubernetes', @@ -165,6 +157,20 @@ test.describe('Platform pages shell', () => { }); } + test('docker page renders as a single unified surface without sub-tabs', async ({ + page, + }, testInfo) => { + test.skip(testInfo.project.name.startsWith('mobile-'), 'Desktop shell smoke'); + + await stubEmptyResources(page); + await page.goto('/docker/overview', { waitUntil: 'domcontentloaded' }); + + const pageRoot = page.getByTestId('docker-page'); + await expect(pageRoot).toBeVisible({ timeout: 30_000 }); + + await expect(page.getByRole('navigation', { name: 'Docker sections' })).toHaveCount(0); + }); + test('every platform sub-tab exposes v5-style operator controls', async ({ page, }, testInfo) => { @@ -178,8 +184,6 @@ test.describe('Platform pages shell', () => { // own canonical FilterBar via `showFilterToolbar`. const cases: ReadonlyArray<{ path: string; testId: string }> = [ { path: '/docker/overview', testId: 'docker-page' }, - { path: '/docker/containers', testId: 'docker-page' }, - { path: '/docker/services', testId: 'docker-page' }, { path: '/kubernetes/overview', testId: 'kubernetes-page' }, { path: '/kubernetes/nodes', testId: 'kubernetes-page' }, { path: '/kubernetes/pods', testId: 'kubernetes-page' },