Files
sencho/frontend/src/components/EditorLayout/mobile-treatments.ts
T
Anso 8302048bc4 test(mobile): declare per-view mobile treatment and harden the visual gate (#1332)
* test(mobile): single-source map for per-view mobile treatment

Declare how every top-level view behaves on a phone in one place:
MOBILE_TREATMENTS is a Record<ActiveView, ...>, so adding a new view without
classifying it (bespoke / responsive / desktop-only / detail) fails the type
check. BESPOKE_MOBILE_VIEWS is derived from it instead of hand-maintained, and
a unit test keeps the two in lockstep and pins the current bespoke set so a
change is deliberate. EditorLayout consumes the derived set; behavior is
unchanged.

* ci(visual): run the desktop-unchanged gate in its own job

Split the visual-regression spec into a dedicated Playwright "visual" project,
excluded from the default chromium project the functional E2E job runs, so a
missing or platform-mismatched baseline can no longer fail every PR.

Add a Visual Regression workflow: a compare job gates PRs into main against
committed baselines (and skips with a warning until they are seeded), and a
manual seed job regenerates the baselines on the Linux runner and commits them
to a feature branch (refusing main). Baselines are platform-specific, so they
must be produced on the runner rather than locally.

Drop the stack-detail view from the gate: a fresh CI app has no stack to open
and its live log stream is not deterministic; the shell plus the four content
views still catch a desktop base-class regression.
2026-06-07 14:56:49 -04:00

41 lines
1.8 KiB
TypeScript

import type { ActiveView } from './hooks/useViewNavigationState';
// How a top-level view behaves below the md breakpoint.
// bespoke a dedicated phone screen (masthead-led, in components/mobile/)
// responsive the desktop view reflowed via max-md: utilities, no bespoke layout
// desktop-only a heavy authoring/terminal surface that stays desktop-first
// detail the full-screen stack-detail surface (the editor view)
export type MobileTreatment = 'bespoke' | 'responsive' | 'desktop-only' | 'detail';
// Single source of truth for the mobile treatment of every top-level view.
//
// The `Record<ActiveView, ...>` shape is the guard: adding a new `ActiveView`
// without classifying it here fails `tsc`, so no view can ship without a
// deliberate decision about its phone behavior. `mobile-treatments.test.ts`
// ties the 'bespoke' entries to `BESPOKE_MOBILE_VIEWS` and to the bespoke
// screens actually wired in EditorLayout, so the declaration cannot drift from
// the implementation.
export const MOBILE_TREATMENTS: Record<ActiveView, MobileTreatment> = {
dashboard: 'bespoke',
fleet: 'bespoke',
'scheduled-ops': 'bespoke',
settings: 'bespoke',
editor: 'detail',
resources: 'responsive',
templates: 'responsive',
'global-observability': 'responsive',
'auto-updates': 'responsive',
'audit-log': 'responsive',
'host-console': 'desktop-only',
};
// The content surfaces that render a bespoke phone screen instead of the
// reflowed desktop workspace. Derived from MOBILE_TREATMENTS so it cannot drift
// from the declared treatments. EditorLayout drops the global TopBar for these
// and renders their masthead-led screen.
export const BESPOKE_MOBILE_VIEWS: ReadonlySet<ActiveView> = new Set(
(Object.keys(MOBILE_TREATMENTS) as ActiveView[]).filter(
view => MOBILE_TREATMENTS[view] === 'bespoke',
),
);