@continuous-excellence/ze-great-dashboard-aws 0.18.0 → 0.18.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/client/assets/index-CJ25jkMk.js.map +1 -1
- package/dist/cli.js +8 -4
- package/dist/index.js +8 -4
- package/dist/lambda.mjs +8 -4
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index-CJ25jkMk.js","names":[],"sources":["../../../shared/dist/index.js","../../src/App.module.css","../../src/Diagnostics.module.css","../../src/Diagnostics.tsx","../../src/browser-storage.ts","../../src/diagnostics-summary.ts","../../src/diagnostics.ts","../../src/PanelFrame.module.css","../../src/PanelPlaceholder.tsx","../../src/HttpValuePanel.module.css","../../src/panel-layout.ts","../../src/PanelFrame.tsx","../../src/TimeAge.tsx","../../src/HttpValuePanel.tsx","../../src/falling-shapes.ts","../../src/PipelineAnimationDemoPanel.module.css","../../src/FallingShapesField.module.css","../../src/FallingShapesField.tsx","../../src/ReleaseTransitField.module.css","../../src/ReleaseTransitField.tsx","../../src/RunningField.module.css","../../src/StatusWeatherField.module.css","../../src/StatusWeatherField.tsx","../../src/PhasedProgressMarker.module.css","../../src/PhasedProgressMarker.tsx","../../src/TelemetryBloomField.module.css","../../src/TelemetryBloomField.tsx","../../src/RunningField.tsx","../../src/running-timing.ts","../../src/RunningFieldTiming.tsx","../../src/RunningProgress.module.css","../../src/RunningProgress.tsx","../../src/PipelineAnimationDemoPanel.tsx","../../src/PipelinePanel.module.css","../../src/panel-status.ts","../../src/pipeline-activity.ts","../../src/PipelinePanel.tsx","../../src/PullRequestHealthPanel.module.css","../../src/panel-formatting.ts","../../src/pull-request-health.ts","../../src/PullRequestHealthPanel.tsx","../../src/panel-registry.tsx","../../src/useClientUpdate.ts","../../src/panel-diagnostics.ts","../../src/panel-memory.ts","../../src/pipeline-reconciliation.ts","../../src/polling-schedule.ts","../../src/usePanelSignals.ts","../../src/App.tsx","../../src/ConfigError.module.css","../../src/ConfigError.tsx","../../src/main.tsx"],"sourcesContent":["// packages/shared/src/board-config.ts\nimport { z as z2 } from \"zod\";\n\n// packages/shared/src/duration.ts\nimport { z } from \"zod\";\nvar DURATION_PATTERN = /^(\\d+)(ms|s|m|h)$/;\nvar UNIT_MILLIS = {\n ms: 1,\n s: 1e3,\n m: 6e4,\n h: 36e5\n};\nfunction parseDuration(value) {\n const match = DURATION_PATTERN.exec(value);\n if (!match) return null;\n const [, rawAmount, rawUnit] = match;\n if (rawAmount === void 0 || rawUnit === void 0) return null;\n const amount = Number(rawAmount);\n if (amount <= 0) return null;\n return amount * UNIT_MILLIS[rawUnit];\n}\nvar durationSchema = z.string().refine((value) => parseDuration(value) !== null, {\n message: 'must be a positive duration like \"30s\", \"5m\", or \"1h\"'\n}).brand();\n\n// packages/shared/src/board-config.ts\nvar positionSchema = z2.union([\n z2.object({\n x: z2.number().int().min(0),\n y: z2.number().int().min(0),\n w: z2.number().int().min(1).max(12),\n h: z2.number().int().min(1)\n }),\n z2.object({ x: z2.literal(0), y: z2.literal(0), w: z2.literal(0), h: z2.literal(0) })\n]);\nvar panelDensities = [\"auto\", \"comfortable\", \"compact\"];\nvar panelDensitySchema = z2.enum(panelDensities);\nvar visibleRunningAnimations = [\n \"radial\",\n \"runway\",\n \"orbit\",\n \"signal-field\",\n \"telemetry-bloom\",\n \"release-transit\",\n \"status-weather\",\n \"falling-shapes\"\n];\nvar runningAnimationSchema = z2.enum([...visibleRunningAnimations, \"off\"]);\nvar panelSchema = z2.looseObject({\n /** Presentation-only wall label. `id` remains the stable proxy and allowlist address. */\n label: z2.string().min(1).optional(),\n id: z2.string().min(1),\n type: z2.string().min(1),\n source: z2.string().min(1).optional(),\n pipeline: z2.union([z2.string(), z2.number()]).optional(),\n /** Resolved public source branch, supplied by the board endpoint for client memory scoping. */\n branch: z2.string().min(1).optional(),\n /** Content-density bias; position still controls the panel's explicit grid placement. */\n density: panelDensitySchema.optional(),\n /** Advisory in v1 — a panel without a position renders in config order rather than not at all. */\n position: positionSchema.optional(),\n refresh: durationSchema.optional(),\n /** Active pipeline runs are checked more often than normal panels. */\n running_refresh: durationSchema.optional(),\n /** Polling cadence around the estimated completion boundary. */\n running_completion_refresh: durationSchema.optional(),\n /** Maximum length of the tighter completion polling burst. */\n running_completion_window: durationSchema.optional(),\n /** Optional active-run treatment. Omitted selects a visible treatment at random. */\n running_animation: runningAnimationSchema.optional(),\n /** Local animation-demo cycle duration; ignored by other panel types. */\n demo_run_duration: durationSchema.optional(),\n /** Local animation-demo focused-review duration; ignored by other panel types. */\n demo_review_duration: durationSchema.optional(),\n /** A deliberate override only. Adapters derive links; hand-written ones drift. */\n link: z2.url().optional(),\n /** Source-agnostic endpoint used by the http-value signal. */\n url: z2.url().optional(),\n /** Small, deliberate JSON path subset: $.version, $.deployment.version, or $.response.docs[0].latestVersion. */\n json_path: z2.string().regex(/^\\$(?:\\.[A-Za-z_][A-Za-z0-9_]*|\\[\\d+\\])*$/, \"must be a simple JSON path\").optional()\n}).superRefine((panel, ctx) => {\n if (\"display\" in panel) {\n ctx.addIssue({\n code: \"custom\",\n path: [\"display\"],\n message: \"display was removed; use density\"\n });\n }\n});\nvar githubAppSchema = z2.object({\n app_id_env: z2.string().min(1),\n private_key_env: z2.string().min(1),\n installation_id_env: z2.string().min(1)\n});\nvar sourceAuthenticationSchema = {\n /** Credentials are never in the config — only the name of the env var holding one. */\n token_env: z2.string().min(1).optional(),\n github_app: githubAppSchema.optional()\n};\nfunction exactlyOneGithubAuthenticationMode(source, ctx) {\n if (source.token_env && source.github_app)\n ctx.addIssue({ code: \"custom\", message: \"configure token_env or github_app, not both\" });\n}\nvar githubActionsSourceSchema = z2.looseObject({\n type: z2.literal(\"github-actions\"),\n repo: z2.string().regex(/^[^/\\s]+\\/[^/\\s]+$/, \"must be an owner/repository pair\"),\n /** The branch whose workflow health the dashboard represents. */\n branch: z2.string().min(1).optional(),\n ...sourceAuthenticationSchema\n}).superRefine(exactlyOneGithubAuthenticationMode);\nvar sourceSchema = z2.looseObject({ type: z2.string().min(1), ...sourceAuthenticationSchema }).superRefine(exactlyOneGithubAuthenticationMode);\nfunction credentialEnvironmentNames(source) {\n return [\n ...source.token_env ? [source.token_env] : [],\n ...source.github_app ? [\n source.github_app.app_id_env,\n source.github_app.private_key_env,\n source.github_app.installation_id_env\n ] : []\n ];\n}\nvar boardSchema = z2.object({\n refresh: durationSchema.optional(),\n running_refresh: durationSchema.optional(),\n running_completion_refresh: durationSchema.optional(),\n running_completion_window: durationSchema.optional(),\n panels: z2.array(panelSchema).min(1).superRefine((panels, ctx) => {\n const seen = /* @__PURE__ */ new Map();\n panels.forEach((panel, index) => {\n const firstIndex = seen.get(panel.id);\n if (firstIndex === void 0) {\n seen.set(panel.id, index);\n return;\n }\n ctx.addIssue({\n code: \"custom\",\n path: [index, \"id\"],\n message: `duplicate panel id \"${panel.id}\" (already used by panel at index ${firstIndex})`\n });\n });\n })\n});\nvar authSchema = z2.object({\n issuer: z2.url(),\n /** Absent in gateway mode — the gateway does the flow, the proxy still validates. */\n client_id: z2.string().min(1).optional(),\n allow: z2.object({\n groups: z2.array(z2.string().min(1)).optional(),\n subjects: z2.array(z2.string().min(1)).optional()\n }).optional()\n});\nvar boardConfigSchema = z2.object({\n sources: z2.record(z2.string().min(1), sourceSchema).default({}),\n boards: z2.record(z2.string().min(1), boardSchema),\n auth: authSchema.optional()\n});\nfunction resolveRefreshMillis(args) {\n const requested = args.panelOverrideMillis ?? args.boardDefaultMillis;\n return Math.max(requested, args.adapterFloorMillis);\n}\n\n// packages/shared/src/board-config-modeline.ts\nvar MODEL_LINE = /^# yaml-language-server:\\s*\\$schema=(\\S+)\\s*$/;\nvar SCHEMA_FILE = \"board-config.schema.json\";\nfunction schemaUrlForAssetPath(assetPath) {\n return `${assetPath.replace(/\\/+$/, \"\")}/${SCHEMA_FILE}`;\n}\nfunction readBoardSchemaModeline(source) {\n const line = source.split(/\\r?\\n/).find((candidate) => candidate.includes(\"yaml-language-server\"));\n if (!line) throw new Error(`Board configuration must include a ${SCHEMA_FILE} modeline`);\n const match = MODEL_LINE.exec(line);\n if (!match?.[1]) {\n throw new Error(\n `Malformed board schema modeline; expected \"# yaml-language-server: $schema=<URL>/${SCHEMA_FILE}\"`\n );\n }\n let url;\n try {\n url = new URL(match[1]);\n } catch {\n throw new Error(`Malformed board schema modeline; schema URL is not a valid URL: ${match[1]}`);\n }\n if (![\"http:\", \"https:\"].includes(url.protocol) || !url.pathname.endsWith(`/${SCHEMA_FILE}`)) {\n throw new Error(`Malformed board schema modeline; URL must end in /${SCHEMA_FILE}: ${match[1]}`);\n }\n return match[1];\n}\nfunction boardSchemaModeline(url) {\n return `# yaml-language-server: $schema=${url}`;\n}\nvar boardSchemaFileName = SCHEMA_FILE;\n\n// packages/shared/src/client-env.ts\nimport { z as z3 } from \"zod\";\nvar clientEnvSchema = z3.object({\n /** Where the immutable client assets live. The one variable that repoints the whole client. */\n assetPath: z3.string().min(1),\n /** Same-origin path the proxy is mounted at, so there is no CORS and no cookie problem. */\n proxyPath: z3.string().min(1),\n /** Which board this is, resolved server-side so the client parses no URLs. */\n board: z3.string().min(1),\n /** The client version being served, so two published versions are visibly distinguishable. */\n clientVersion: z3.string().min(1),\n /** Omitted entirely when unauthenticated — presence is what turns auth on. */\n auth: z3.object({\n issuer: z3.string().min(1),\n clientId: z3.string().min(1).optional()\n }).optional()\n});\nvar clientIdentitySchema = clientEnvSchema.pick({ assetPath: true, clientVersion: true });\nfunction readClientEnv(source = globalThis.window?.env) {\n const result = clientEnvSchema.safeParse(source);\n if (!result.success) {\n throw new Error(\n `window.env is missing or invalid \\u2014 the server did not inject usable configuration.\n${z3.prettifyError(result.error)}`\n );\n }\n return result.data;\n}\n\n// packages/shared/src/envelope.ts\nimport { z as z4 } from \"zod\";\nvar errorKindSchema = z4.enum([\n \"unreachable\",\n \"unauthorized\",\n \"not-found\",\n \"no-runs\",\n \"upstream-error\"\n]);\nvar envelopeErrorSchema = z4.object({\n kind: errorKindSchema,\n message: z4.string()\n});\nvar envelopeSchema = z4.discriminatedUnion(\"state\", [\n z4.object({\n panelId: z4.string().min(1),\n state: z4.literal(\"ok\"),\n /** From the upstream response `Date`. A cached value must never be shown without its age. */\n observedAt: z4.iso.datetime(),\n /** Adapter-derived. The authority for this panel; the dashboard itself asserts nothing. */\n link: z4.url().nullable(),\n signal: z4.unknown()\n }),\n z4.object({\n panelId: z4.string().min(1),\n state: z4.literal(\"error\"),\n /**\n * Populated even on error: knowing *when* a failure was observed is the difference between\n * \"broken just now\" and \"broken all morning\", and a panel that can't reach its source is\n * exactly when a viewer most wants to click through.\n */\n observedAt: z4.iso.datetime(),\n link: z4.url().nullable(),\n error: envelopeErrorSchema\n })\n]);\nvar pipelineActivitySchema = z4.object({\n kind: z4.enum([\"job\", \"stage\", \"step\"]),\n name: z4.string().min(1),\n parent: z4.string().min(1).optional()\n});\nvar pipelineStatusSchema = z4.object({\n type: z4.literal(\"pipeline-status\"),\n status: z4.enum([\"passed\", \"failed\", \"running\", \"cancelled\", \"unknown\"]),\n /** The source's unmodified status/result vocabulary, for an honest display. */\n rawStatus: z4.string(),\n name: z4.string().min(1),\n /** The branch represented by this status, when the upstream supplies or filters by one. */\n branch: z4.string().min(1).optional(),\n /** Elapsed execution time, supplied only after the upstream run has completed. */\n durationMs: z4.number().int().nonnegative().optional(),\n /** When an active run began, so the client can advance its elapsed display between polls. */\n runStartedAt: z4.iso.datetime().optional(),\n /** Stable source-run identity, when the adapter provides one. */\n sourceRunId: z4.string().min(1).optional(),\n /** Best-effort live work detail; adapters may describe a job, stage, or step. */\n activity: pipelineActivitySchema.optional(),\n /** Advisory duration from recent completed runs remembered by this browser. */\n estimatedDurationMs: z4.number().int().positive().optional(),\n /** When this workflow run was last updated by its source, distinct from our observation time. */\n sourceUpdatedAt: z4.iso.datetime().optional()\n});\nvar pullRequestHealthItemSchema = z4.object({\n label: z4.string().min(1),\n status: pipelineStatusSchema.shape.status,\n detail: z4.string().min(1),\n link: z4.url().nullable()\n});\nvar pullRequestHealthSchema = z4.object({\n type: z4.literal(\"pull-request-health\"),\n status: pipelineStatusSchema.shape.status,\n summary: z4.string().min(1),\n workflows: z4.array(pullRequestHealthItemSchema),\n pullRequests: z4.array(pullRequestHealthItemSchema)\n});\nvar httpValueSchema = z4.object({\n type: z4.literal(\"http-value\"),\n value: z4.union([z4.string(), z4.number(), z4.boolean()])\n});\n\n// packages/shared/src/layout.ts\nvar columnCount = 12;\nvar rowCount = 12;\nfunction analyzeBoardLayout(panels) {\n const issues = panels.flatMap((panel) => {\n if (!panel.position || isZeroPosition(panel.position) || isPositionInCanvas(panel.position))\n return [];\n return [\n {\n panelId: panel.id,\n kind: \"out-of-bounds\",\n position: panel.position,\n conflictsWith: []\n }\n ];\n });\n const overlapIssues = /* @__PURE__ */ new Map();\n for (let leftIndex = 0; leftIndex < panels.length; leftIndex++) {\n const left = panels[leftIndex];\n if (!left?.position || isZeroPosition(left.position)) continue;\n for (let rightIndex = leftIndex + 1; rightIndex < panels.length; rightIndex++) {\n const right = panels[rightIndex];\n if (!right?.position || isZeroPosition(right.position)) continue;\n if (!overlaps(left.position, right.position)) continue;\n const key = `${right.id}\\0overlap`;\n const issue = overlapIssues.get(key);\n if (issue) issue.conflictsWith.push(left.id);\n else {\n const nextIssue = {\n panelId: right.id,\n kind: \"overlap\",\n position: right.position,\n conflictsWith: [left.id]\n };\n overlapIssues.set(key, nextIssue);\n issues.push(nextIssue);\n }\n }\n }\n return { issues };\n}\nfunction normalizeBoardLayout(panels) {\n const positioned = panels.flatMap((panel) => {\n if (!panel.position || isZeroPosition(panel.position)) return [];\n return [{ ...panel.position, panelId: panel.id }];\n });\n if (positioned.length === 0) return panels.map((panel) => ({ ...panel }));\n const minX = Math.min(...positioned.map((rectangle) => rectangle.x));\n const minY = Math.min(...positioned.map((rectangle) => rectangle.y));\n const maxX = Math.max(...positioned.map((rectangle) => rectangle.x + rectangle.w));\n const maxY = Math.max(...positioned.map((rectangle) => rectangle.y + rectangle.h));\n const scaleX = maxX - minX > columnCount ? columnCount / (maxX - minX) : 1;\n const scaleY = maxY - minY > rowCount ? rowCount / (maxY - minY) : 1;\n const accepted = [];\n return panels.map((panel) => {\n const position = panel.position;\n if (!position || isZeroPosition(position)) return { ...panel };\n const desired = scaleRectangle(position, minX, minY, scaleX, scaleY);\n const legal = nearestLegalRectangle(desired, accepted);\n if (!legal) return { ...panel, position: zeroPosition };\n accepted.push({ ...legal, panelId: panel.id });\n return { ...panel, position: legal };\n });\n}\nfunction isZeroPosition(position) {\n return position?.x === 0 && position.y === 0 && position.w === 0 && position.h === 0;\n}\nvar zeroPosition = { x: 0, y: 0, w: 0, h: 0 };\nfunction isPositionInCanvas(position) {\n return !isZeroPosition(position) && position.x + position.w <= columnCount && position.y + position.h <= rowCount;\n}\nfunction overlaps(left, right) {\n return left.x < right.x + right.w && left.x + left.w > right.x && left.y < right.y + right.h && left.y + left.h > right.y;\n}\nfunction scaleRectangle(position, minX, minY, scaleX, scaleY) {\n const x = scaleCoordinate(position.x, minX, scaleX);\n const y = scaleCoordinate(position.y, minY, scaleY);\n const right = scaleCoordinate(position.x + position.w, minX, scaleX);\n const bottom = scaleCoordinate(position.y + position.h, minY, scaleY);\n return {\n x,\n y,\n w: Math.max(1, right - x),\n h: Math.max(1, bottom - y)\n };\n}\nfunction scaleCoordinate(value, origin, scale) {\n return Math.round((value - origin) * scale);\n}\nfunction nearestLegalRectangle(desired, accepted) {\n const candidates = [];\n for (let width = desired.w; width >= 1; width--) {\n for (let height = desired.h; height >= 1; height--) {\n const shrink = desired.w - width + (desired.h - height);\n for (let y = 0; y <= rowCount - height; y++) {\n for (let x = 0; x <= columnCount - width; x++) {\n const candidate2 = { x, y, w: width, h: height };\n if (accepted.some((rectangle) => overlaps(candidate2, rectangle))) continue;\n candidates.push({\n ...candidate2,\n shrink,\n distance: Math.abs(x - desired.x) + Math.abs(y - desired.y)\n });\n }\n }\n }\n }\n candidates.sort(\n (left, right) => left.shrink - right.shrink || left.distance - right.distance || left.y - right.y || left.x - right.x\n );\n const [candidate] = candidates;\n if (!candidate) return void 0;\n return { x: candidate.x, y: candidate.y, w: candidate.w, h: candidate.h };\n}\n\n// packages/shared/src/polling-policy.ts\nvar pollingDefaults = {\n refreshMillis: 6e4,\n runningRefreshMillis: 15e3,\n runningCompletionRefreshMillis: 5e3,\n runningCompletionWindowMillis: 12e4\n};\nfunction resolvePollingSettings(board, panel) {\n const duration = (value, fallback) => parseDuration(value ?? \"\") ?? fallback;\n const panelValue = (key, boardValue, fallback) => duration(panel[key], duration(board[boardValue], fallback));\n return {\n refreshMillis: panelValue(\"refresh\", \"refresh\", pollingDefaults.refreshMillis),\n runningRefreshMillis: panelValue(\n \"running_refresh\",\n \"running_refresh\",\n pollingDefaults.runningRefreshMillis\n ),\n runningCompletionRefreshMillis: panelValue(\n \"running_completion_refresh\",\n \"running_completion_refresh\",\n pollingDefaults.runningCompletionRefreshMillis\n ),\n runningCompletionWindowMillis: panelValue(\n \"running_completion_window\",\n \"running_completion_window\",\n pollingDefaults.runningCompletionWindowMillis\n )\n };\n}\nexport {\n analyzeBoardLayout,\n authSchema,\n boardConfigSchema,\n boardSchema,\n boardSchemaFileName,\n boardSchemaModeline,\n clientEnvSchema,\n clientIdentitySchema,\n credentialEnvironmentNames,\n durationSchema,\n envelopeSchema,\n errorKindSchema,\n githubActionsSourceSchema,\n githubAppSchema,\n httpValueSchema,\n isZeroPosition,\n normalizeBoardLayout,\n panelDensities,\n panelDensitySchema,\n panelSchema,\n parseDuration,\n pipelineActivitySchema,\n pipelineStatusSchema,\n pollingDefaults,\n positionSchema,\n pullRequestHealthSchema,\n readBoardSchemaModeline,\n readClientEnv,\n resolvePollingSettings,\n resolveRefreshMillis,\n runningAnimationSchema,\n schemaUrlForAssetPath,\n sourceSchema,\n visibleRunningAnimations\n};\n",".board {\n display: flex;\n flex-direction: column;\n gap: var(--gap);\n height: 100dvh;\n min-height: 0;\n padding: var(--gap);\n overflow-x: hidden;\n overflow-y: auto;\n}\n.header {\n display: flex;\n align-items: baseline;\n border-bottom: 1px solid var(--edge);\n padding-bottom: var(--gap);\n flex: 0 0 auto;\n}\n.title {\n margin: 0;\n font-size: 1.75em;\n font-weight: 650;\n letter-spacing: -0.01em;\n}\n.grid {\n display: grid;\n grid-template-columns: repeat(12, minmax(0, 1fr));\n grid-template-rows: repeat(12, minmax(0, 1fr));\n grid-auto-rows: minmax(0, 1fr);\n gap: var(--gap);\n flex: 1;\n min-height: 0;\n align-content: stretch;\n}\n.footerTools {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n}\n.layoutWarning {\n position: relative;\n}\n.layoutWarningButton {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: 0.2em;\n min-width: 2em;\n min-height: 2em;\n border: 1px solid var(--status-warning);\n border-radius: 50%;\n color: var(--status-warning);\n background: var(--surface-raised);\n font: inherit;\n cursor: pointer;\n}\n.layoutWarningButton:hover,\n.layoutWarningButton:focus-visible {\n background: var(--surface);\n}\n.layoutWarningDialog {\n position: absolute;\n z-index: 10;\n right: 0;\n bottom: calc(100% + 0.75rem);\n width: min(32rem, calc(100vw - 2 * var(--gap)));\n padding: 0.8rem;\n border: 1px solid var(--status-warning);\n border-radius: var(--radius);\n color: var(--ink-secondary);\n background: var(--surface-raised);\n box-shadow: 0 0.5rem 1.5rem rgb(0 0 0 / 35%);\n}\n.layoutWarningHeading {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 1rem;\n}\n.layoutWarningHeading strong {\n color: var(--status-warning);\n}\n.layoutWarningDialog p {\n margin: 0.6rem 0;\n}\n.layoutWarningDialog ul {\n margin: 0.35rem 0 0.75rem;\n padding-left: 1.25rem;\n font-family: ui-monospace, SFMono-Regular, Menlo, monospace;\n font-size: 0.85em;\n}\n.layoutWarningClose {\n border: 0;\n color: var(--ink-muted);\n background: transparent;\n font-size: 1.25em;\n line-height: 1;\n cursor: pointer;\n}\n.layoutWarningDownloads {\n display: grid;\n gap: 0.35rem;\n}\n.layoutWarningDownloads a {\n border: 1px solid var(--edge);\n border-radius: 0.25rem;\n background: var(--surface-raised);\n color: var(--ink-secondary);\n font: inherit;\n padding: 0.3em 0.55em;\n text-align: center;\n text-decoration: none;\n}\n.layoutWarningDownloads a:hover,\n.layoutWarningDownloads a:focus-visible {\n border-color: var(--ink-secondary);\n color: var(--ink-primary);\n}\n.layoutWarningNote {\n color: var(--ink-muted);\n font-size: 0.85em;\n}\n.footer {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n justify-content: space-between;\n gap: 0.5rem;\n color: var(--ink-muted);\n font-size: 0.75em;\n flex: 0 0 auto;\n}\n@media (max-width: 64rem) {\n .board {\n height: auto;\n min-height: 100dvh;\n overflow: visible;\n }\n .grid {\n grid-template-columns: 1fr;\n grid-auto-rows: auto;\n flex: 0 0 auto;\n min-height: auto;\n }\n .layoutWarningDialog {\n position: fixed;\n right: var(--gap);\n bottom: calc(var(--gap) + 3rem);\n }\n}\n",".diagnostics {\n position: relative;\n}\n\n.button {\n border: 1px solid var(--edge);\n border-radius: 0.25rem;\n background: var(--surface-raised);\n color: var(--ink-secondary);\n font: inherit;\n padding: 0.3em 0.55em;\n}\n\n.area {\n position: absolute;\n z-index: 1;\n right: 0;\n bottom: calc(100% + 0.5rem);\n width: min(24rem, 90vw);\n padding: 0.75rem;\n border: 1px solid var(--edge);\n border-radius: var(--radius);\n background: var(--surface-raised);\n box-shadow: 0 0.5rem 1.5rem #0008;\n}\n\n.area p {\n margin: 0 0 0.5rem;\n}\n\n.warning {\n color: var(--status-warning);\n}\n\n.panels {\n max-height: 12rem;\n overflow-y: auto;\n border-top: 1px solid var(--edge);\n margin: 0.5rem 0;\n padding-top: 0.5rem;\n}\n\n.actions {\n display: flex;\n gap: 0.5rem;\n}\n","import { useState, useSyncExternalStore } from 'react'\nimport styles from './Diagnostics.module.css'\nimport type { BrowserDiagnosticStore } from './diagnostics.ts'\n\nexport function Diagnostics({ log }: { log: BrowserDiagnosticStore }) {\n const [open, setOpen] = useState(false)\n useSyncExternalStore(log.subscribe, log.snapshot, log.snapshot)\n const count = log.count()\n const githubConsistencyIncidents = log.githubConsistencyIncidentCount()\n const summary = log.summary()\n const download = () => {\n const blob = new Blob([JSON.stringify(log.export(), null, 2)], { type: 'application/json' })\n const url = URL.createObjectURL(blob)\n const link = document.createElement('a')\n link.href = url\n link.download = `dashboard-diagnostics-${new Date().toISOString().replaceAll(':', '-')}.json`\n link.click()\n URL.revokeObjectURL(url)\n }\n const clear = () => {\n if (!window.confirm('Clear this browser’s retained dashboard diagnostics?')) return\n log.clear()\n }\n\n return (\n <section className={styles.diagnostics}>\n <button\n className={styles.button}\n type=\"button\"\n aria-expanded={open}\n onClick={() => setOpen(!open)}\n >\n Diagnostics ({count})\n {githubConsistencyIncidents > 0 && ` · GitHub consistency ${githubConsistencyIncidents}`}\n </button>\n {open && (\n <div className={styles.area}>\n <p>\n Client {log.clientVersion()} · assets {log.assetPath()}\n </p>\n <p>\n {summary.retained.eventCount} retained browser-local events across{' '}\n {summary.retained.sessionCount} session{summary.retained.sessionCount === 1 ? '' : 's'}\n {summary.retained.firstEventAt && summary.retained.lastEventAt\n ? ` (${formatWindow(summary.retained.firstEventAt, summary.retained.lastEventAt)})`\n : ''}\n . They are never uploaded.\n </p>\n {summary.retained.evidenceMayBeIncomplete && (\n <p className={styles.warning} role=\"alert\">\n Earlier evidence was pruned: {summary.retained.retention.eventsPrunedByCount} at the\n 2,000-event cap and {summary.retained.retention.eventsPrunedByAge} by the 7-day age\n limit. “No failures” applies only to the retained window.\n </p>\n )}\n <p>\n Update failures: {summary.failures.clientUpdate}; board fetch failures:{' '}\n {summary.failures.boardFetch}.\n </p>\n {log.githubConsistencyIncidentCount() > 0 && (\n <p className={styles.warning} role=\"alert\">\n GitHub API consistency incidents: {log.githubConsistencyIncidentCount()}. A response\n older than the last accepted run was rejected; download diagnostics to report it.\n </p>\n )}\n {summary.panels.length > 0 && (\n <div className={styles.panels}>\n {summary.panels.map((panel) => (\n <p key={panel.panelId}>\n <strong>{panel.panelId}</strong> — {panel.requests} requests\n {Object.keys(panel.httpStatuses).length\n ? `; HTTP ${Object.entries(panel.httpStatuses)\n .map(([status, count]) => `${status}×${count}`)\n .join(', ')}`\n : ''}\n ; parse/network failures {panel.parseFailures}/{panel.networkFailures}; visible\n changes {panel.visibleStateChanges}; latest{' '}\n {panel.latestRendered\n ? `${panel.latestRendered.state}${panel.latestRendered.status ? `/${panel.latestRendered.status}` : ''}`\n : 'not rendered'}\n .\n </p>\n ))}\n </div>\n )}\n <div className={styles.actions}>\n <button className={styles.button} type=\"button\" onClick={download}>\n Download\n </button>\n <button className={styles.button} type=\"button\" onClick={clear}>\n Clear\n </button>\n </div>\n </div>\n )}\n </section>\n )\n}\n\nfunction formatWindow(first: string, last: string) {\n return first === last ? first : `${first} to ${last}`\n}\n","export type BrowserStorageLike = Pick<Storage, 'getItem' | 'setItem'>\n\nexport function browserLocalStorage(): BrowserStorageLike | undefined {\n try {\n return window.localStorage\n } catch {\n return undefined\n }\n}\n\nexport function readBrowserJson<T>(\n storage: BrowserStorageLike | undefined,\n key: string,\n): T | undefined {\n try {\n const raw = storage?.getItem(key)\n return raw ? (JSON.parse(raw) as T) : undefined\n } catch {\n return undefined\n }\n}\n\nexport function writeBrowserJson(\n storage: BrowserStorageLike | undefined,\n key: string,\n value: unknown,\n) {\n try {\n storage?.setItem(key, JSON.stringify(value))\n } catch {\n // Browser storage is an optimization; callers retain their in-memory state.\n }\n}\n\nexport function removeBrowserValue(storage: Pick<Storage, 'removeItem'> | undefined, key: string) {\n try {\n storage?.removeItem(key)\n } catch {\n // Storage can be unavailable in private browsing or restricted frames.\n }\n}\n","import type {\n DiagnosticEvent,\n DiagnosticRetention,\n RenderedPanelDiagnostic,\n} from './diagnostics.ts'\n\nexport type PanelDiagnosticsSummary = {\n panelId: string\n requests: number\n httpStatuses: Record<string, number>\n parseFailures: number\n networkFailures: number\n visibleStateChanges: number\n latestRendered?: RenderedPanelDiagnostic\n}\n\nexport type DiagnosticsSummary = {\n githubConsistencyIncidents: number\n retained: {\n eventCount: number\n firstEventAt?: string\n lastEventAt?: string\n sessionCount: number\n retention: DiagnosticRetention\n evidenceMayBeIncomplete: boolean\n }\n failures: {\n clientUpdate: number\n boardFetch: number\n }\n panels: PanelDiagnosticsSummary[]\n}\n\n/** Summarizes retained browser evidence only; omitted history is disclosed through retention. */\nexport function summarizeDiagnostics(\n events: readonly DiagnosticEvent[],\n retention: DiagnosticRetention,\n githubConsistencyIncidents = 0,\n): DiagnosticsSummary {\n const panels = new Map<string, PanelDiagnosticsSummary>()\n const sessions = new Set<string>()\n let clientUpdate = 0\n let boardFetch = 0\n\n for (const event of events) {\n sessions.add(event.sessionId)\n if (event.kind === 'client-update-failure') clientUpdate++\n if (event.kind === 'board-fetch-failure' || event.kind === 'board-fetch-parse-failure')\n boardFetch++\n if (!('panelId' in event)) continue\n\n const panel = panels.get(event.panelId) ?? {\n panelId: event.panelId,\n requests: 0,\n httpStatuses: {},\n parseFailures: 0,\n networkFailures: 0,\n visibleStateChanges: 0,\n }\n if (event.kind === 'panel-fetch-start') panel.requests++\n if (event.kind === 'panel-fetch-response') {\n if (event.status !== undefined) {\n const status = String(event.status)\n panel.httpStatuses[status] = (panel.httpStatuses[status] ?? 0) + 1\n }\n }\n if (event.kind === 'panel-fetch-parse-failure') panel.parseFailures++\n if (event.kind === 'panel-fetch-failure') panel.networkFailures++\n if (event.kind === 'panel-rendered') {\n panel.visibleStateChanges++\n panel.latestRendered = event.rendered\n }\n panels.set(event.panelId, panel)\n }\n\n const timestamps = events.map((event) => event.at).sort()\n const discarded = retention.eventsPrunedByAge + retention.eventsPrunedByCount\n return {\n githubConsistencyIncidents,\n retained: {\n eventCount: events.length,\n firstEventAt: timestamps[0],\n lastEventAt: timestamps.at(-1),\n sessionCount: sessions.size,\n retention,\n evidenceMayBeIncomplete: discarded > 0,\n },\n failures: { clientUpdate, boardFetch },\n panels: [...panels.values()].sort((left, right) => left.panelId.localeCompare(right.panelId)),\n }\n}\n","import type { ClientEnv, Envelope } from '@ze-great-dashboard/shared'\nimport {\n type BrowserStorageLike,\n browserLocalStorage,\n readBrowserJson,\n removeBrowserValue,\n writeBrowserJson,\n} from './browser-storage.ts'\nimport { type DiagnosticsSummary, summarizeDiagnostics } from './diagnostics-summary.ts'\n\nconst storageKey = 'ze-great-dashboard.diagnostics.v1'\nexport const diagnosticsSchemaVersion = 1\nconst maximumEvents = 2_000\nconst maximumAgeMillis = 7 * 24 * 60 * 60 * 1_000\nconst diagnosticKinds = [\n 'session-start',\n 'client-update-check',\n 'client-update-failure',\n 'client-update-detected',\n 'board-fetch-start',\n 'board-fetch-response',\n 'board-fetch-parse-failure',\n 'board-fetch-failure',\n 'layout-analyzed',\n 'panel-fetch-start',\n 'panel-fetch-response',\n 'panel-fetch-parse-failure',\n 'panel-fetch-failure',\n 'panel-rendered',\n] as const\n\nexport type CacheMetadata = Partial<\n Record<'cacheControl' | 'etag' | 'lastModified' | 'date' | 'age', string>\n>\n\nexport type GithubConsistencyIncident = {\n at: string\n board: string\n panelId: string\n endpoint: string\n identity: { source: string; workflow: string; branch: string }\n accepted: { sourceUpdatedAt: string; status: string; link: string | null }\n regressed: { sourceUpdatedAt: string; status: string; link: string | null }\n response: { httpStatus?: number; date?: string; etag?: string; cacheControl?: string }\n}\n\ntype EventMetadata = {\n schemaVersion: typeof diagnosticsSchemaVersion\n at: string\n sessionId: string\n board: string\n}\n\nexport type RenderedPanelDiagnostic = {\n state: Envelope['state']\n status?: string\n link: string | null\n}\n\nexport type DiagnosticEventInput =\n | { kind: 'session-start' }\n | { kind: 'client-update-check'; path: string }\n | { kind: 'client-update-failure'; path: string; message: string }\n | {\n kind: 'client-update-detected'\n path: string\n current: { assetPath: string; clientVersion: string }\n next: { assetPath: string; clientVersion: string }\n }\n | { kind: 'board-fetch-start'; path: string }\n | {\n kind: 'board-fetch-response'\n path: string\n status?: number\n cache?: CacheMetadata\n boardSummary?: { panelCount: number; panelIds: string[] }\n }\n | { kind: 'board-fetch-parse-failure'; path: string; message: string }\n | { kind: 'board-fetch-failure'; path: string; message: string }\n | { kind: 'layout-analyzed'; issueCount: number; affectedPanelIds: string[] }\n | { kind: 'panel-fetch-start'; panelId: string; path: string }\n | {\n kind: 'panel-fetch-response'\n panelId: string\n path: string\n status?: number\n cache?: CacheMetadata\n envelope?: Envelope\n }\n | { kind: 'panel-fetch-parse-failure'; panelId: string; path: string; message: string }\n | { kind: 'panel-fetch-failure'; panelId: string; path: string; message: string }\n | {\n kind: 'panel-rendered'\n panelId: string\n path: string\n rendered: RenderedPanelDiagnostic\n }\n\nexport type DiagnosticEvent = DiagnosticEventInput extends infer Event\n ? Event extends DiagnosticEventInput\n ? Event & EventMetadata\n : never\n : never\n\n/** The only interface client features need in order to emit browser diagnostics. */\nexport interface DiagnosticSink {\n record(event: DiagnosticEventInput): void\n recordGithubConsistencyIncident(incident: Omit<GithubConsistencyIncident, 'at' | 'board'>): void\n}\n\ntype PersistedDiagnosticEvent = Omit<DiagnosticEvent, 'schemaVersion'> & { schemaVersion?: number }\nexport type DiagnosticRetention = {\n eventsPrunedByAge: number\n eventsPrunedByCount: number\n}\n\ntype StoredDiagnostics = {\n schemaVersion: number\n events: PersistedDiagnosticEvent[]\n retention?: Partial<DiagnosticRetention>\n githubConsistencyIncidents?: GithubConsistencyIncident[]\n}\n\ntype StorageLike = BrowserStorageLike & Pick<Storage, 'removeItem'>\n\n/** Browser-local diagnostic evidence. It deliberately has no server or shared-contract counterpart. */\nexport class BrowserDiagnosticStore implements DiagnosticSink {\n private events: DiagnosticEvent[] = []\n private retention: DiagnosticRetention = emptyRetention()\n private revision = 0\n private incidents: GithubConsistencyIncident[] = []\n private readonly listeners = new Set<() => void>()\n private readonly sessionId = crypto.randomUUID?.() ?? `${Date.now()}-${Math.random()}`\n\n constructor(\n private readonly env: ClientEnv,\n private readonly storage: StorageLike | undefined = browserLocalStorage() as\n | StorageLike\n | undefined,\n private readonly now: () => Date = () => new Date(),\n ) {\n this.events = this.read()\n this.record({ kind: 'session-start' })\n }\n\n recordGithubConsistencyIncident(incident: Omit<GithubConsistencyIncident, 'at' | 'board'>) {\n this.incidents.push({ ...incident, at: this.now().toISOString(), board: this.env.board })\n this.persist()\n this.revision++\n this.notify()\n }\n\n githubConsistencyIncidentCount = () => this.incidents.length\n\n record(event: DiagnosticEventInput) {\n const pruned = prune(\n [\n ...this.events,\n {\n ...event,\n schemaVersion: diagnosticsSchemaVersion,\n at: this.now().toISOString(),\n sessionId: this.sessionId,\n board: this.env.board,\n },\n ],\n this.now(),\n this.retention,\n )\n this.events = pruned.events\n this.retention = pruned.retention\n this.persist()\n this.revision++\n this.notify()\n }\n\n count = () => {\n return this.events.length\n }\n\n clientVersion = () => this.env.clientVersion\n\n assetPath = () => this.env.assetPath\n\n snapshot = () => this.revision\n\n summary = (): DiagnosticsSummary =>\n summarizeDiagnostics(this.events, this.retention, this.incidents.length)\n\n clear() {\n this.events = []\n this.incidents = []\n this.retention = emptyRetention()\n removeBrowserValue(this.storage, storageKey)\n this.revision++\n this.notify()\n }\n\n subscribe = (listener: () => void) => {\n this.listeners.add(listener)\n return () => {\n this.listeners.delete(listener)\n }\n }\n\n export = () => {\n return {\n schemaVersion: diagnosticsSchemaVersion,\n exportedAt: this.now().toISOString(),\n client: {\n version: this.env.clientVersion,\n assetPath: this.env.assetPath,\n board: this.env.board,\n sessionId: this.sessionId,\n },\n events: this.events,\n githubConsistencyIncidents: this.incidents,\n summary: this.summary(),\n }\n }\n\n private read(): DiagnosticEvent[] {\n const parsed = readBrowserJson<Partial<StoredDiagnostics>>(this.storage, storageKey)\n if (\n !parsed ||\n parsed.schemaVersion !== diagnosticsSchemaVersion ||\n !Array.isArray(parsed.events)\n ) {\n removeBrowserValue(this.storage, storageKey)\n return []\n }\n if (!parsed.events.every(isDiagnosticEvent)) {\n removeBrowserValue(this.storage, storageKey)\n return []\n }\n // v1 retained events predate per-event versions. Their containing store was already v1, so\n // retain them and normalize on the next write rather than discarding viewer evidence.\n const pruned = prune(\n parsed.events.map(\n (event) => ({ ...event, schemaVersion: diagnosticsSchemaVersion }) as DiagnosticEvent,\n ),\n this.now(),\n validRetention(parsed.retention),\n )\n this.retention = pruned.retention\n this.incidents = validIncidents(parsed.githubConsistencyIncidents)\n return pruned.events\n }\n\n private persist() {\n writeBrowserJson(this.storage, storageKey, {\n schemaVersion: diagnosticsSchemaVersion,\n events: this.events,\n retention: this.retention,\n githubConsistencyIncidents: this.incidents,\n })\n }\n\n private notify() {\n for (const listener of this.listeners) listener()\n }\n}\n\nfunction validIncidents(value: unknown): GithubConsistencyIncident[] {\n if (!Array.isArray(value)) return []\n return value.filter((incident): incident is GithubConsistencyIncident => {\n if (!incident || typeof incident !== 'object') return false\n const item = incident as Partial<GithubConsistencyIncident>\n return (\n typeof item.at === 'string' &&\n typeof item.board === 'string' &&\n typeof item.panelId === 'string' &&\n typeof item.endpoint === 'string' &&\n !!item.accepted &&\n !!item.regressed &&\n !!item.response\n )\n })\n}\n\nexport function cacheMetadata(headers: Headers): CacheMetadata | undefined {\n const entries = [\n ['cacheControl', 'cache-control'],\n ['etag', 'etag'],\n ['lastModified', 'last-modified'],\n ['date', 'date'],\n ['age', 'age'],\n ] as const\n const metadata = Object.fromEntries(\n entries.flatMap(([key, header]) => {\n const value = headers.get(header)\n return value ? [[key, value]] : []\n }),\n ) as CacheMetadata\n return Object.keys(metadata).length ? metadata : undefined\n}\n\nfunction emptyRetention(): DiagnosticRetention {\n return { eventsPrunedByAge: 0, eventsPrunedByCount: 0 }\n}\n\nfunction validRetention(value: unknown): DiagnosticRetention {\n if (!value || typeof value !== 'object') return emptyRetention()\n const retention = value as Partial<DiagnosticRetention>\n return {\n eventsPrunedByAge:\n typeof retention.eventsPrunedByAge === 'number' && retention.eventsPrunedByAge >= 0\n ? retention.eventsPrunedByAge\n : 0,\n eventsPrunedByCount:\n typeof retention.eventsPrunedByCount === 'number' && retention.eventsPrunedByCount >= 0\n ? retention.eventsPrunedByCount\n : 0,\n }\n}\n\nfunction prune(events: DiagnosticEvent[], now: Date, priorRetention: DiagnosticRetention) {\n const cutoff = now.valueOf() - maximumAgeMillis\n const current = events.filter(\n (event) =>\n Number.isFinite(new Date(event.at).valueOf()) && new Date(event.at).valueOf() >= cutoff,\n )\n const discardedByAge = events.length - current.length\n const discardedByCount = Math.max(0, current.length - maximumEvents)\n return {\n events: current.slice(-maximumEvents),\n retention: {\n eventsPrunedByAge: priorRetention.eventsPrunedByAge + discardedByAge,\n eventsPrunedByCount: priorRetention.eventsPrunedByCount + discardedByCount,\n },\n }\n}\n\nfunction isDiagnosticEvent(value: unknown): value is PersistedDiagnosticEvent {\n if (!value || typeof value !== 'object') return false\n const event = value as Partial<DiagnosticEvent>\n return (\n (event.schemaVersion === undefined || event.schemaVersion === diagnosticsSchemaVersion) &&\n typeof event.at === 'string' &&\n Number.isFinite(new Date(event.at).valueOf()) &&\n typeof event.sessionId === 'string' &&\n typeof event.board === 'string' &&\n diagnosticKinds.includes(event.kind as (typeof diagnosticKinds)[number])\n )\n}\n",".panel {\n grid-column: var(--panel-column, span 6);\n grid-row: var(--panel-row, auto);\n display: flex;\n flex-direction: column;\n justify-content: center;\n gap: 0.15em;\n min-width: 0;\n min-height: 0;\n padding: clamp(0.5rem, 0.8vw, var(--gap));\n border: 1px solid var(--edge);\n border-radius: var(--radius);\n background: var(--surface-raised);\n position: relative;\n isolation: isolate;\n overflow: hidden;\n line-height: 1.2;\n container-name: panel;\n container-type: size;\n}\n.content {\n position: relative;\n z-index: 1;\n display: flex;\n flex: 0 1 auto;\n flex-direction: column;\n justify-content: center;\n gap: 0.1em;\n min-width: 0;\n min-height: 0;\n overflow: hidden;\n}\n.content > *,\n.details > * {\n min-width: 0;\n max-width: 100%;\n}\n.content:has([data-running-progress=\"runway\"]),\n.content:has([data-running-progress=\"signal-field\"]) {\n flex: 1 1 0;\n}\n.error {\n border-color: var(--status-serious);\n}\n.wide {\n grid-column: span 12;\n}\n.density-comfortable {\n padding: 0.65em;\n gap: 0.1em;\n}\n.density-comfortable .content {\n gap: 0.1em;\n}\n.density-compact {\n min-height: 3.5em;\n padding: 0.2em;\n gap: 0;\n line-height: 1.05;\n justify-content: flex-start;\n}\n.density-compact .content {\n gap: 0;\n}\n.label {\n margin: 0;\n overflow-wrap: anywhere;\n font-size: 1em;\n font-weight: 600;\n font-family: ui-monospace, SFMono-Regular, Menlo, monospace;\n color: var(--ink-secondary);\n}\n.density-compact .label {\n font-size: 0.8em;\n}\n.hint {\n margin: 0;\n font-size: 0.75em;\n color: var(--ink-muted);\n overflow-wrap: anywhere;\n}\n.branch {\n font-family: ui-monospace, SFMono-Regular, Menlo, monospace;\n overflow-wrap: anywhere;\n}\n.observed {\n display: flex;\n flex-wrap: wrap;\n gap: 0.35em;\n align-items: center;\n}\n.meta {\n display: var(--panel-meta-display, block);\n}\n.metaValue {\n min-width: 0;\n overflow-wrap: anywhere;\n}\n.stale {\n color: var(--status-warning);\n}\n.status {\n margin: 0;\n font-size: 1.35em;\n font-weight: 650;\n}\n.density-compact .status {\n font-size: 1.1em;\n}\n.passed {\n color: var(--status-good);\n}\n.failed {\n color: var(--status-critical);\n}\n.running {\n color: var(--status-warning);\n}\n.cancelled,\n.unknown {\n color: var(--ink-secondary);\n}\n.sourceAction {\n position: absolute;\n z-index: 2;\n top: 0.35em;\n right: 0.35em;\n display: inline-grid;\n width: 2em;\n height: 2em;\n place-items: center;\n border-radius: 0.3em;\n color: var(--ink-secondary);\n font-size: 0.85em;\n font-weight: 600;\n line-height: 1;\n text-decoration: none;\n}\n.sourceAction:hover {\n color: var(--ink-primary);\n background: color-mix(in srgb, var(--ink-primary) 8%, transparent);\n}\n.sourceAction:focus-visible {\n outline: 2px solid var(--ink-primary);\n outline-offset: 2px;\n}\n\n.density-comfortable :is(.hint, .observed),\n.density-compact :is(.hint, .observed) {\n font-size: 0.65em;\n}\n@container panel (min-width: 48rem) {\n .density-comfortable.shallow,\n .density-auto.shallow {\n padding: 0.45em 0.65em;\n }\n .density-comfortable.shallow .content,\n .density-auto.shallow .content {\n flex-direction: row;\n flex-wrap: wrap;\n align-items: baseline;\n column-gap: 0.7em;\n row-gap: 0.15em;\n }\n .density-comfortable.shallow .status,\n .density-auto.shallow .status {\n flex: 0 0 auto;\n font-size: 1em;\n }\n .density-comfortable.shallow :is(.label, .observed),\n .density-auto.shallow :is(.label, .observed) {\n flex: 0 0 auto;\n }\n}\n@container panel (min-width: 12rem) {\n .density-compact.shallow .content,\n .density-auto.shallow .content {\n flex-direction: row;\n flex-wrap: wrap;\n align-items: baseline;\n column-gap: 0.7em;\n row-gap: 0.15em;\n }\n .density-compact.shallow :is(.label, .observed),\n .density-auto.shallow :is(.label, .observed) {\n flex: 0 0 auto;\n }\n}\n/* Width and height use the same scale steps, so a narrow or tall cell gets the same text budget. */\n@container panel (max-width: 22rem) {\n .content,\n .sourceAction {\n font-size: 0.8em;\n }\n}\n@container panel (max-width: 15rem) {\n .content,\n .sourceAction {\n font-size: 0.9em;\n }\n}\n@container panel (max-height: 10rem) {\n .content,\n .sourceAction {\n font-size: 0.8em;\n }\n}\n@container panel (max-height: 7rem) {\n .content,\n .sourceAction {\n font-size: 0.9em;\n }\n}\n/* Responsive layout may flow authored cells into one column; content never escapes its cell. */\n@media (max-width: 64rem) {\n .panel {\n grid-column: 1 / -1;\n grid-row: auto;\n min-height: 6em;\n }\n .density-comfortable .content,\n .density-compact .content,\n .density-auto .content {\n flex-direction: column;\n align-items: stretch;\n }\n}\n\n@container panel (max-width: 11rem) and (max-height: 9rem) {\n .content {\n --panel-meta-display: flex;\n }\n .label {\n font-size: 0.85em;\n }\n .status {\n font-size: 1.05em;\n }\n}\n@container panel (max-height: 5rem) {\n .content {\n --panel-meta-display: flex;\n }\n .label {\n font-size: 0.85em;\n }\n .status {\n font-size: 1.05em;\n }\n}\n\n@container panel (max-width: 13rem) {\n .density-compact .content {\n --panel-meta-display: flex;\n }\n .density-compact .content > .meta {\n font-size: 0.6em;\n }\n}\n@container panel (max-width: 8rem) {\n /* Text-light is an internal sub-mode: secondary text remains in the accessibility tree. */\n .content {\n --panel-meta-display: flex;\n gap: 0.05em;\n }\n}\n@container panel (min-height: 24rem) and (max-width: 13rem) {\n .content {\n --panel-meta-display: flex;\n gap: 0.05em;\n }\n}\n@container panel (max-height: 4rem) {\n .content {\n --panel-meta-display: flex;\n gap: 0.05em;\n }\n}\n\n@container panel (max-width: 13rem) and (max-height: 10rem) {\n .density-comfortable .content > .meta {\n font-size: 0.68em;\n }\n}\n\n@container panel (max-width: 18rem) and (max-height: 10rem) {\n .density-compact .content > .meta {\n font-size: 0.6em;\n }\n}\n\n.meta {\n align-items: center;\n gap: 0.2em;\n min-width: 0;\n}\n.metaValue {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n","/**\n * A panel-shaped hole, so the grid can be looked at and argued with before any signal exists.\n * Replaced by real panels in Stage 2 — nothing here is meant to survive.\n */\nexport function PanelPlaceholder({\n label,\n hint,\n wide = false,\n}: {\n label: string\n hint: string\n wide?: boolean\n}) {\n return (\n <section\n className={`${styles.panel} ${wide ? styles.wide : ''}`}\n data-panel\n data-panel-id=\"placeholder\"\n >\n <h2 className={styles.label}>{label}</h2>\n <p className={styles.hint}>{hint}</p>\n </section>\n )\n}\n\nimport styles from './PanelFrame.module.css'\n",".fact {\n display: contents;\n}\n@container panel (min-width: 48rem) {\n :global([data-density=\"compact\"][data-shallow=\"true\"]) .fact > *,\n :global([data-density=\"auto\"][data-shallow=\"true\"]) .fact > * {\n margin: 0;\n }\n}\n@container panel (min-width: 12rem) {\n :global([data-density=\"compact\"][data-shallow=\"true\"]) .fact > *,\n :global([data-density=\"auto\"][data-shallow=\"true\"]) .fact > * {\n margin: 0;\n }\n}\n","import type { Panel } from '@ze-great-dashboard/shared'\nimport type { CSSProperties } from 'react'\n\n/** Convert the advisory board position into CSS grid placement. */\nexport function panelLayout(panel: Panel): CSSProperties | undefined {\n const position = panel.position\n if (!position) return undefined\n\n return {\n '--panel-column': `${position.x + 1} / span ${position.w}`,\n '--panel-row': `${position.y + 1} / span ${position.h}`,\n } as CSSProperties\n}\n","import type { Envelope, Panel } from '@ze-great-dashboard/shared'\nimport type { ReactNode } from 'react'\nimport styles from './PanelFrame.module.css'\nimport { panelLayout } from './panel-layout.ts'\n\ntype PanelStatusKind = 'passed' | 'failed' | 'running' | 'cancelled' | 'unknown'\n\nexport function PanelHint({\n children,\n className,\n title,\n}: {\n children: ReactNode\n className?: string\n title?: string\n}) {\n return (\n <p className={`${styles.hint} ${className ?? ''}`} title={title}>\n {children}\n </p>\n )\n}\n\n/** A concise metadata row with one visible glyph and the full value retained in the DOM. */\nexport function PanelMetadata({\n glyph,\n label,\n value,\n title,\n observed = false,\n stale = false,\n className,\n}: {\n glyph: string\n label: string\n value: ReactNode\n title?: string\n observed?: boolean\n stale?: boolean\n className?: string\n}) {\n return (\n <p\n className={`${styles.hint} ${observed ? styles.observed : ''} ${stale ? styles.stale : ''} ${styles.meta} ${className ?? ''}`}\n data-panel-meta\n >\n <span aria-hidden=\"true\">{glyph}</span> <span className=\"screen-reader-only\">{label}: </span>\n <span className={styles.metaValue} title={title}>\n {value}\n </span>\n </p>\n )\n}\n\nexport function PanelStatus({\n children,\n status,\n}: {\n children: ReactNode\n status?: PanelStatusKind\n}) {\n return <p className={`${styles.status} ${status ? styles[status] : ''}`}>{children}</p>\n}\n\nexport function PanelFrame({\n panel,\n envelope,\n error = false,\n field,\n children,\n}: {\n panel: Panel\n envelope?: Envelope\n error?: boolean\n /** Decorative active-run layer. It is intentionally a sibling of readable panel content. */\n field?: ReactNode\n children: ReactNode\n}) {\n const density = panel.density ?? 'auto'\n const position = panel.position\n const shallow = position !== undefined && position.h <= 2\n const short = position !== undefined && position.h <= 3\n return (\n <section\n className={`${styles.panel} ${styles[`density-${density}`]} ${shallow ? styles.shallow : ''} ${short ? styles.short : ''} ${error ? styles.error : ''}`}\n style={panelLayout(panel)}\n aria-busy={envelope ? undefined : true}\n data-panel\n data-panel-id={panel.id}\n data-panel-position={\n position ? `${position.x},${position.y},${position.w},${position.h}` : undefined\n }\n data-density={density}\n data-shallow={shallow}\n data-short={short}\n data-error={error || undefined}\n >\n {field}\n <PanelSourceLink panelId={panel.id} link={envelope?.link} />\n <div className={styles.content} data-panel-content>\n <h2 className={styles.label}>{panel.label ?? panel.id}</h2>\n {children}\n </div>\n </section>\n )\n}\n\nfunction PanelSourceLink({ panelId, link }: { panelId: string; link?: string | null }) {\n if (!link) return null\n\n return (\n <a\n className={styles.sourceAction}\n href={link}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n aria-label={`View source for ${panelId} (opens in a new tab)`}\n title={`View source for ${panelId} (opens in a new tab)`}\n data-panel-action=\"source\"\n data-panel-link\n >\n <span aria-hidden=\"true\">↗</span>\n <span className=\"screen-reader-only\">View source</span>\n </a>\n )\n}\n","import { PanelMetadata } from './PanelFrame.tsx'\n\nexport function CheckedAt({ value }: { value: string }) {\n return <TimeAge value={value} stale label=\"Checked\" variant=\"age\" />\n}\n\nexport function RunAge({ value, running }: { value: string; running: boolean }) {\n return <TimeAge value={value} label={running ? 'Started' : 'Run updated'} variant=\"age\" />\n}\n\nfunction TimeAge({\n value,\n label,\n stale = false,\n variant,\n}: {\n value: string\n label: string\n stale?: boolean\n variant: 'clock' | 'age'\n}) {\n const observed = new Date(value)\n const formatted = observed.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })\n const age = Date.now() - observed.getTime()\n const content =\n variant === 'clock' ? `${label} ${formatted} · ${formatAge(age)}` : `${label} ${formatAge(age)}`\n return (\n <PanelMetadata\n glyph=\"◷\"\n label={label}\n value={content}\n title={`${label} at ${formatted}`}\n observed\n stale={stale}\n />\n )\n}\n\nexport function formatAge(milliseconds: number) {\n if (milliseconds < 60_000) return 'just now'\n const minutes = Math.floor(milliseconds / 60_000)\n if (minutes < 60) return `${minutes}m ago`\n const hours = Math.floor(minutes / 60)\n return `${hours}h ${minutes % 60}m ago`\n}\n","import { httpValueSchema } from '@ze-great-dashboard/shared'\nimport styles from './HttpValuePanel.module.css'\nimport { PanelFrame, PanelHint, PanelStatus } from './PanelFrame.tsx'\nimport type { PanelProps } from './panel-props.ts'\nimport { CheckedAt } from './TimeAge.tsx'\n\nexport function HttpValuePanel({ panel, envelope, checkedAt }: PanelProps) {\n if (!envelope)\n return (\n <PanelFrame panel={panel}>\n <PanelHint>Loading…</PanelHint>\n </PanelFrame>\n )\n if (envelope.state === 'error')\n return (\n <PanelFrame panel={panel} envelope={envelope} error>\n <PanelStatus>⚠ Unable to read</PanelStatus>\n <PanelHint>{envelope.error.message}</PanelHint>\n {checkedAt && <CheckedAt value={checkedAt} />}\n </PanelFrame>\n )\n const signal = httpValueSchema.safeParse(envelope.signal)\n if (!signal.success)\n return (\n <PanelFrame panel={panel} envelope={envelope} error>\n <PanelStatus>⚠ Invalid value</PanelStatus>\n {checkedAt && <CheckedAt value={checkedAt} />}\n </PanelFrame>\n )\n return (\n <PanelFrame panel={panel} envelope={envelope}>\n <div className={styles.fact}>\n <PanelStatus>{String(signal.data.value)}</PanelStatus>\n {checkedAt && <CheckedAt value={checkedAt} />}\n </div>\n </PanelFrame>\n )\n}\n","export type FallingDirection = 'horizontal' | 'vertical'\nexport type FallingCell = { x: number; y: number }\nexport type FallingShape = {\n id: number\n bornAt: number\n cells: FallingCell[]\n x: number\n y: number\n targetX?: number\n targetY?: number\n phase: 'entry' | 'align' | 'travel' | 'settled'\n}\n\nexport const FALLING_TARGET_FILL = 0.85\n\nconst shapes: FallingCell[][] = [\n [\n { x: 0, y: 0 },\n { x: 1, y: 0 },\n ],\n [\n { x: 0, y: 0 },\n { x: 0, y: 1 },\n ],\n [\n { x: 0, y: 0 },\n { x: 1, y: 0 },\n { x: 0, y: 1 },\n ],\n [\n { x: 0, y: 0 },\n { x: 1, y: 0 },\n { x: 2, y: 0 },\n ],\n [\n { x: 0, y: 0 },\n { x: 0, y: 1 },\n { x: 1, y: 1 },\n ],\n]\n\nexport function fallingDirection(width: number, height: number): FallingDirection {\n return width > height ? 'horizontal' : 'vertical'\n}\n\nexport function fallingGrid(\n direction: FallingDirection,\n width = direction === 'horizontal' ? 12 : 3,\n height = direction === 'horizontal' ? 3 : 12,\n): { columns: number; rows: number } {\n const fieldWidth = Math.max(1, width * 0.8)\n const fieldHeight = Math.max(1, height * 0.8)\n const cellSize = Math.max(24, Math.min(42, Math.min(fieldWidth, fieldHeight) / 4))\n const columns = Math.max(3, Math.min(24, Math.round(fieldWidth / cellSize)))\n const rows = Math.max(3, Math.min(16, Math.round(fieldHeight / cellSize)))\n return direction === 'horizontal'\n ? { columns: Math.max(columns, rows), rows }\n : { columns, rows: Math.max(rows, columns) }\n}\n\nexport function fallingSeed(value: string): number {\n return Array.from(value).reduce(\n (hash, character) => (hash * 31 + character.charCodeAt(0)) >>> 0,\n 7,\n )\n}\n\nexport function shapeFits(shape: FallingCell[], columns: number, rows: number): boolean {\n const maxX = Math.max(...shape.map((cell) => cell.x))\n const maxY = Math.max(...shape.map((cell) => cell.y))\n return maxX < columns && maxY < rows\n}\n\nexport function overlaps(left: FallingShape, right: FallingShape): boolean {\n return left.cells.some((leftCell) =>\n right.cells.some(\n (rightCell) =>\n left.x + leftCell.x === right.x + rightCell.x &&\n left.y + leftCell.y === right.y + rightCell.y,\n ),\n )\n}\n\nexport function chooseShape(seed: number, columns: number, rows: number): FallingCell[] {\n const candidates = shapes.filter((shape) => shapeFits(shape, columns, rows))\n return candidates[randomIndex(seed, candidates.length)] ?? [{ x: 0, y: 0 }]\n}\n\nexport function findDestination(\n shape: FallingCell[],\n direction: FallingDirection,\n columns: number,\n rows: number,\n settled: readonly FallingShape[],\n seed = 0,\n requireSupported = false,\n): { x: number; y: number } | undefined {\n const width = Math.max(...shape.map((cell) => cell.x)) + 1\n const height = Math.max(...shape.map((cell) => cell.y)) + 1\n const candidates: Array<{ x: number; y: number; support: number }> = []\n for (let y = 0; y <= rows - height; y++) {\n for (let x = 0; x <= columns - width; x++) {\n const candidate = { id: -1, bornAt: 0, cells: shape, x, y, phase: 'settled' as const }\n if (settled.some((item) => overlaps(candidate, item))) continue\n if (!clearPath(shape, direction, columns, rows, candidate, settled)) continue\n const support =\n direction === 'vertical'\n ? shape.filter(\n (cell) =>\n y + cell.y === rows - 1 ||\n settled.some((item) =>\n item.cells.some(\n (other) =>\n item.x + other.x === x + cell.x && item.y + other.y === y + cell.y + 1,\n ),\n ),\n ).length\n : shape.filter(\n (cell) =>\n x + cell.x === 0 ||\n settled.some((item) =>\n item.cells.some(\n (other) =>\n item.x + other.x === x + cell.x - 1 && item.y + other.y === y + cell.y,\n ),\n ),\n ).length\n if (requireSupported && support < leadingEdgeCount(shape, direction)) continue\n candidates.push({ x, y, support })\n }\n }\n candidates.sort(\n (left, right) =>\n right.support - left.support ||\n (direction === 'vertical'\n ? right.y - left.y || left.x - right.x\n : left.x - right.x || left.y - right.y),\n )\n const bestSupport = candidates[0]?.support\n const best = candidates.filter((candidate) => candidate.support === bestSupport)\n const destination = best[randomIndex(seed, best.length)]\n return destination ? { x: destination.x, y: destination.y } : undefined\n}\n\nexport function findPlacement(\n direction: FallingDirection,\n columns: number,\n rows: number,\n settled: readonly FallingShape[],\n seed: number,\n requireSupported: boolean,\n): { shape: FallingCell[]; destination: { x: number; y: number } } | undefined {\n const candidates = shapes.flatMap((shape, index) => {\n if (!shapeFits(shape, columns, rows)) return []\n const destination = findDestination(\n shape,\n direction,\n columns,\n rows,\n settled,\n seed + index * 31,\n requireSupported,\n )\n return destination ? [{ shape, destination }] : []\n })\n if (candidates.length === 0) return undefined\n return candidates[randomIndex(seed, candidates.length)]\n}\n\nexport function targetCellCount(columns: number, rows: number, progress: number): number {\n return Math.ceil(columns * rows * FALLING_TARGET_FILL * Math.min(1, Math.max(0, progress)))\n}\n\nexport function occupiedCellCount(shapes: readonly FallingShape[]): number {\n return shapes.reduce((count, shape) => count + shape.cells.length, 0)\n}\n\nexport type LineClear = {\n shapes: FallingShape[]\n cleared: FallingCell[]\n complete: boolean\n}\n\n/** Clears only cells in the trailing edge line and slides the surviving field into it. */\nexport function clearTrailingLine(\n direction: FallingDirection,\n columns: number,\n rows: number,\n settled: readonly FallingShape[],\n allowPartial: boolean,\n): LineClear | undefined {\n const edgeLine = direction === 'vertical' ? rows - 1 : 0\n const occupied = new Set(\n settled.flatMap((item) =>\n item.cells\n .filter((cell) =>\n direction === 'vertical' ? item.y + cell.y === edgeLine : item.x + cell.x === edgeLine,\n )\n .map((cell) => (direction === 'vertical' ? item.x + cell.x : item.y + cell.y)),\n ),\n )\n const lineWidth = direction === 'vertical' ? columns : rows\n const complete = occupied.size === lineWidth\n if (!complete && !allowPartial) return undefined\n if (occupied.size === 0) return undefined\n\n const cleared: FallingCell[] = []\n const shapes = settled.flatMap((item) => {\n const remaining = item.cells.filter((cell) => {\n const onLine =\n direction === 'vertical' ? item.y + cell.y === edgeLine : item.x + cell.x === edgeLine\n if (onLine) {\n cleared.push({ x: item.x + cell.x, y: item.y + cell.y })\n }\n return !onLine\n })\n if (remaining.length === 0) return []\n return [\n {\n ...item,\n cells: remaining,\n y: direction === 'vertical' ? item.y + 1 : item.y,\n x: direction === 'horizontal' ? item.x - 1 : item.x,\n },\n ]\n })\n return { shapes, cleared, complete }\n}\n\nexport function buildStaticField(\n direction: FallingDirection,\n columns: number,\n rows: number,\n seed: number,\n count: number,\n): FallingShape[] {\n const settled: FallingShape[] = []\n for (let id = 0; id < count; id += 1) {\n const pieceSeed = seed + id * 17\n const shape = chooseShape(pieceSeed, columns, rows)\n const destination = findDestination(shape, direction, columns, rows, settled, pieceSeed + 1)\n if (!destination) break\n settled.push({\n id,\n bornAt: 0,\n cells: shape,\n x: destination.x,\n y: destination.y,\n phase: 'settled',\n })\n }\n return settled\n}\n\nfunction leadingEdgeCount(shape: FallingCell[], direction: FallingDirection): number {\n if (direction === 'vertical') {\n return new Set(shape.map((cell) => cell.x)).size\n }\n return new Set(shape.map((cell) => cell.y)).size\n}\n\nfunction clearPath(\n shape: FallingCell[],\n direction: FallingDirection,\n columns: number,\n rows: number,\n destination: FallingShape,\n settled: readonly FallingShape[],\n): boolean {\n const width = Math.max(...shape.map((cell) => cell.x)) + 1\n const height = Math.max(...shape.map((cell) => cell.y)) + 1\n if (direction === 'vertical') {\n for (let y = 0; y <= destination.y; y += 1) {\n if (settled.some((item) => overlaps({ ...destination, y }, item))) return false\n }\n return destination.y + height <= rows\n }\n for (let x = columns - width; x >= destination.x; x -= 1) {\n if (settled.some((item) => overlaps({ ...destination, x }, item))) return false\n }\n return destination.x + width <= columns\n}\n\nfunction randomIndex(seed: number, length: number): number {\n if (length <= 1) return 0\n const value = Math.sin(seed * 12.9898 + 78.233) * 43_758.5453\n return Math.floor((value - Math.floor(value)) * length)\n}\n",".variant {\n margin: 0;\n color: var(--ink-muted);\n font-size: 0.72em;\n text-transform: capitalize;\n transition: color 180ms ease;\n}\n@media (prefers-reduced-motion: reduce) {\n .variant {\n transition: none;\n }\n}\n",".field {\n position: absolute;\n z-index: 0;\n inset: 0;\n overflow: hidden;\n pointer-events: none;\n contain: layout paint;\n color: var(--status-warning);\n}\n.grid {\n position: absolute;\n inset: 10%;\n}\n.piece {\n position: absolute;\n left: calc((var(--piece-x) / var(--shape-columns)) * 100%);\n top: calc((var(--piece-y) / var(--shape-rows)) * 100%);\n width: calc((var(--piece-width) / var(--shape-columns)) * 100%);\n height: calc((var(--piece-height) / var(--shape-rows)) * 100%);\n transition:\n left 120ms linear,\n top 120ms linear;\n}\n.field[data-recycling=\"true\"] .piece {\n transition:\n left 500ms cubic-bezier(0.22, 1, 0.36, 1),\n top 500ms cubic-bezier(0.22, 1, 0.36, 1),\n opacity 180ms ease;\n}\n.field[data-overdue=\"true\"] .piece[data-piece-phase=\"settled\"] {\n opacity: 0.72;\n border-color: currentColor;\n}\n.field[data-overdue=\"true\"] .cell {\n background: color-mix(in srgb, currentColor 38%, transparent);\n box-shadow: 0 0 0.6em color-mix(in srgb, currentColor 48%, transparent);\n}\n.field[data-overdue=\"true\"] .clearingCell {\n animation-duration: 900ms;\n}\n/* biome-ignore lint/style/noDescendingSpecificity: base cell rules follow the overdue override intentionally. */\n.cell {\n position: absolute;\n left: calc((var(--cell-x) / var(--piece-width)) * 100% + 0.12em);\n top: calc((var(--cell-y) / var(--piece-height)) * 100% + 0.12em);\n width: calc(100% / var(--piece-width) - 0.24em);\n height: calc(100% / var(--piece-height) - 0.24em);\n border: 1px solid color-mix(in srgb, currentColor 55%, transparent);\n border-radius: 0.12em;\n background: color-mix(in srgb, currentColor 28%, transparent);\n box-shadow: 0 0 0.45em color-mix(in srgb, currentColor 35%, transparent);\n}\n/* biome-ignore lint/style/noDescendingSpecificity: base clearing rules follow the overdue override intentionally. */\n.clearingCell {\n position: absolute;\n left: calc((var(--clear-x) / var(--shape-columns)) * 100% + 0.12em);\n top: calc((var(--clear-y) / var(--shape-rows)) * 100% + 0.12em);\n width: calc(100% / var(--shape-columns) - 0.24em);\n height: calc(100% / var(--shape-rows) - 0.24em);\n border: 1px solid color-mix(in srgb, currentColor 55%, transparent);\n border-radius: 0.12em;\n background: color-mix(in srgb, currentColor 28%, transparent);\n animation: clear-cell 500ms ease-out forwards;\n}\n.piece[data-piece-phase=\"entry\"] {\n opacity: 0.35;\n}\n.piece[data-piece-phase=\"align\"] {\n opacity: 0.65;\n}\n.piece[data-piece-phase=\"travel\"] {\n opacity: 0.9;\n}\n/* biome-ignore lint/style/noDescendingSpecificity: settled phase is the base state for the overdue override. */\n.piece[data-piece-phase=\"settled\"] {\n opacity: 0.5;\n}\n@media (prefers-reduced-motion: reduce) {\n .piece,\n .field[data-recycling=\"true\"] .piece {\n transition: none;\n }\n .field[data-overdue=\"true\"] .clearingCell {\n animation: none;\n opacity: 0;\n }\n /* biome-ignore lint/style/noDescendingSpecificity: reduced-motion base rule follows the overdue override. */\n .clearingCell {\n animation: none;\n opacity: 0;\n }\n}\n\n@keyframes clear-cell {\n to {\n opacity: 0;\n transform: scale(0.35);\n }\n}\n","import type { CSSProperties } from 'react'\nimport { useEffect, useRef, useState } from 'react'\nimport styles from './FallingShapesField.module.css'\nimport {\n buildStaticField,\n clearTrailingLine,\n type FallingDirection,\n type FallingShape,\n fallingDirection,\n fallingGrid,\n findPlacement,\n occupiedCellCount,\n targetCellCount,\n} from './falling-shapes.ts'\n\nconst TICK_MS = 50\nconst PIECE_INTERVAL_MS = 1_250\nconst ENTRY_MS = 250\nconst TRAVEL_MS = 850\nconst RECYCLE_MS = 500\n\nexport function FallingShapesField({\n progress,\n estimatedDurationMs,\n overdue,\n seed = 0,\n}: {\n progress: number\n estimatedDurationMs?: number\n overdue: boolean\n seed?: number\n}) {\n const rootRef = useRef<HTMLDivElement>(null)\n const [geometry, setGeometry] = useState<{\n columns: number\n rows: number\n direction: FallingDirection\n }>({\n ...fallingGrid('vertical'),\n direction: 'vertical' as const,\n })\n const [pieces, setPieces] = useState<FallingShape[]>([])\n const [recycling, setRecycling] = useState(false)\n const [clearingCells, setClearingCells] = useState<{ x: number; y: number }[]>([])\n const [reducedMotion, setReducedMotion] = useState(false)\n const geometryRef = useRef(geometry)\n const previousGeometryRef = useRef(geometry)\n const progressRef = useRef(progress)\n const seedRef = useRef(seed)\n const directionRef = useRef<FallingDirection | undefined>(undefined)\n const piecesRef = useRef<FallingShape[]>([])\n const recyclingRef = useRef(false)\n const simulation = useRef({\n startedAt: Date.now(),\n nextPieceAt: PIECE_INTERVAL_MS,\n recycleUntil: 0,\n id: 0,\n settled: [] as FallingShape[],\n })\n\n useEffect(() => {\n progressRef.current = progress\n }, [progress])\n\n useEffect(() => {\n seedRef.current = seed\n }, [seed])\n\n useEffect(() => {\n const root = rootRef.current\n if (!root) return\n const update = () => {\n const rect = root.getBoundingClientRect()\n if (rect.width === 0 || rect.height === 0) return\n setGeometry((_current) => {\n const direction = directionRef.current ?? fallingDirection(rect.width, rect.height)\n directionRef.current = direction\n const next = { ...fallingGrid(direction, rect.width, rect.height), direction }\n geometryRef.current = next\n return next\n })\n }\n update()\n if (typeof ResizeObserver === 'undefined') return\n const observer = new ResizeObserver(update)\n observer.observe(root)\n return () => observer.disconnect()\n }, [])\n\n useEffect(() => {\n const media = window.matchMedia('(prefers-reduced-motion: reduce)')\n const update = () => setReducedMotion(media.matches)\n update()\n media.addEventListener?.('change', update)\n return () => media.removeEventListener?.('change', update)\n }, [])\n\n useEffect(() => {\n const previous = previousGeometryRef.current\n const changed =\n previous.direction !== geometry.direction ||\n previous.columns !== geometry.columns ||\n previous.rows !== geometry.rows\n previousGeometryRef.current = geometry\n if (!changed || reducedMotion) return\n simulation.current = {\n startedAt: Date.now(),\n nextPieceAt: PIECE_INTERVAL_MS,\n id: 0,\n recycleUntil: 0,\n settled: [],\n }\n piecesRef.current = []\n setPieces([])\n setRecycling(false)\n setClearingCells([])\n recyclingRef.current = false\n }, [geometry, reducedMotion])\n\n useEffect(() => {\n if (!reducedMotion) return\n const staticPieces = buildStaticField(\n geometry.direction,\n geometry.columns,\n geometry.rows,\n seedRef.current,\n Math.max(1, Math.floor(progressRef.current * 6)),\n )\n piecesRef.current = staticPieces\n simulation.current.settled = staticPieces\n setPieces(staticPieces)\n }, [geometry, reducedMotion])\n\n useEffect(() => {\n if (reducedMotion) return\n const timer = window.setInterval(() => {\n const state = simulation.current\n const elapsed = Date.now() - state.startedAt\n const currentGeometry = geometryRef.current\n const currentProgress = progressRef.current\n const target = targetCellCount(currentGeometry.columns, currentGeometry.rows, currentProgress)\n let next = [...state.settled]\n let active = piecesRef.current.filter((piece) => piece.phase !== 'settled')\n if (elapsed < state.recycleUntil) return\n if (recyclingRef.current) {\n recyclingRef.current = false\n setRecycling(false)\n setClearingCells([])\n }\n if (elapsed >= state.nextPieceAt && active.length === 0) {\n if (currentProgress < 1 && occupiedCellCount(next) >= target) {\n return\n }\n const id = state.id\n const pieceSeed = seedRef.current + id * 17\n const placement = findPlacement(\n currentGeometry.direction,\n currentGeometry.columns,\n currentGeometry.rows,\n next,\n pieceSeed + 1,\n !overdue,\n )\n if (!placement && (currentProgress >= 1 || estimatedDurationMs === undefined)) {\n const cleared = clearTrailingLine(\n currentGeometry.direction,\n currentGeometry.columns,\n currentGeometry.rows,\n next,\n true,\n )\n if (cleared) {\n next = cleared.shapes\n state.settled = next\n state.recycleUntil = elapsed + RECYCLE_MS\n state.nextPieceAt = state.recycleUntil\n piecesRef.current = next\n recyclingRef.current = true\n setClearingCells(cleared.cleared)\n setPieces(next)\n setRecycling(true)\n return\n }\n }\n if (placement) {\n state.id += 1\n const { shape, destination } = placement\n const height = Math.max(...shape.map((cell) => cell.y)) + 1\n active = [\n ...active,\n {\n id,\n bornAt: elapsed,\n cells: shape,\n x:\n currentGeometry.direction === 'horizontal'\n ? currentGeometry.columns - Math.max(...shape.map((cell) => cell.x)) - 0.5\n : destination.x,\n y: currentGeometry.direction === 'vertical' ? -height + 0.5 : destination.y,\n targetX: destination.x,\n targetY: destination.y,\n phase: 'entry',\n },\n ]\n }\n state.nextPieceAt += pieceInterval(estimatedDurationMs, currentGeometry)\n }\n active = active.map((piece) => {\n const age = elapsed - piece.bornAt\n const destination =\n piece.targetX === undefined || piece.targetY === undefined\n ? undefined\n : { x: piece.targetX, y: piece.targetY }\n if (!destination) return piece\n const amount = Math.min(1, Math.max(0, (age - ENTRY_MS) / TRAVEL_MS))\n if (amount >= 1) {\n next = [\n ...next,\n { ...piece, x: destination.x, y: destination.y, phase: 'settled' as const },\n ]\n return { ...piece, x: destination.x, y: destination.y, phase: 'settled' as const }\n }\n const startX =\n currentGeometry.direction === 'horizontal'\n ? currentGeometry.columns - Math.max(...piece.cells.map((cell) => cell.x)) - 1\n : destination.x\n const startY = currentGeometry.direction === 'vertical' ? 0 : destination.y\n const lifecycleAmount = Math.min(1, Math.max(0, age / (ENTRY_MS + TRAVEL_MS)))\n return {\n ...piece,\n x:\n currentGeometry.direction === 'horizontal'\n ? startX + (destination.x - startX) * amount\n : startX,\n y:\n currentGeometry.direction === 'vertical'\n ? startY + (destination.y - startY) * amount\n : startY,\n phase: age < ENTRY_MS ? 'entry' : lifecycleAmount < 0.35 ? 'align' : 'travel',\n }\n })\n state.settled = next\n const visible = [...next, ...active.filter((piece) => piece.phase !== 'settled')]\n piecesRef.current = visible\n setPieces(visible)\n }, TICK_MS)\n return () => window.clearInterval(timer)\n }, [estimatedDurationMs, overdue, reducedMotion])\n\n return (\n <div\n ref={rootRef}\n className={styles.field}\n data-running-part=\"falling-shapes-field\"\n data-overdue={overdue || undefined}\n data-direction={geometry.direction}\n data-recycling={recycling || undefined}\n style={\n { '--shape-columns': geometry.columns, '--shape-rows': geometry.rows } as CSSProperties\n }\n >\n <div className={styles.grid}>\n {clearingCells.map((cell) => (\n <span\n key={`${cell.x}-${cell.y}`}\n className={styles.clearingCell}\n style={{ '--clear-x': cell.x, '--clear-y': cell.y } as CSSProperties}\n />\n ))}\n {pieces.map((piece) => (\n <div\n key={piece.id}\n className={styles.piece}\n data-piece={piece.id}\n data-piece-phase={piece.phase}\n style={\n {\n '--piece-x': piece.x,\n '--piece-y': piece.y,\n '--piece-width': Math.max(...piece.cells.map((cell) => cell.x)) + 1,\n '--piece-height': Math.max(...piece.cells.map((cell) => cell.y)) + 1,\n } as CSSProperties\n }\n >\n {piece.cells.map((cell) => (\n <span\n key={`${cell.x}-${cell.y}`}\n className={styles.cell}\n style={{ '--cell-x': cell.x, '--cell-y': cell.y } as CSSProperties}\n />\n ))}\n </div>\n ))}\n </div>\n </div>\n )\n}\n\nfunction pieceInterval(\n estimatedDurationMs: number | undefined,\n geometry: { columns: number; rows: number },\n) {\n const target = Math.ceil(geometry.columns * geometry.rows * 0.85)\n if (estimatedDurationMs === undefined || target <= 0) return PIECE_INTERVAL_MS\n return Math.max(400, estimatedDurationMs / Math.max(1, Math.ceil(target / 3)))\n}\n",".frontier {\n position: absolute;\n inset: 0 auto 0 0;\n width: var(--running-progress);\n background: linear-gradient(\n 90deg,\n color-mix(in srgb, currentColor 16%, transparent),\n transparent\n );\n border-right: 1px solid color-mix(in srgb, currentColor 75%, transparent);\n}\n.now {\n position: absolute;\n top: 10%;\n bottom: 10%;\n left: 70%;\n width: 1px;\n background: color-mix(in srgb, var(--ink-primary) 45%, transparent);\n}\n.routes {\n position: absolute;\n inset: 18% 8%;\n display: grid;\n align-content: space-between;\n}\n.route {\n height: 1px;\n background: linear-gradient(\n 90deg,\n transparent,\n color-mix(in srgb, var(--ink-muted) 45%, transparent),\n transparent\n );\n}\n.route:nth-child(2) {\n transform: translateX(8%);\n}\n.route:nth-child(3) {\n transform: translateX(-6%);\n}\n.trail,\n.packet {\n position: absolute;\n top: 50%;\n left: -10%;\n border-radius: 999px;\n animation: packet 4.8s ease-in-out infinite alternate;\n}\n.trail {\n width: 18%;\n height: 2px;\n background: linear-gradient(90deg, transparent, currentColor);\n opacity: 0.65;\n}\n.packet {\n width: 0.48em;\n height: 0.48em;\n background: currentColor;\n box-shadow: 0 0 0.65em currentColor;\n}\n@container running-field (max-width: 40rem) {\n .routes,\n .trail,\n .packet,\n .now {\n display: none;\n }\n .frontier {\n width: 0.28em;\n border-right: 0;\n background: currentColor;\n }\n}\n[data-overdue=\"true\"] .frontier {\n width: 70%;\n background: linear-gradient(\n 90deg,\n color-mix(in srgb, currentColor 28%, transparent),\n transparent\n );\n}\n[data-overdue=\"true\"] .packet {\n left: 70%;\n animation: packet-stall 1.8s ease-in-out infinite alternate;\n}\n[data-overdue=\"true\"] .trail {\n left: 43%;\n width: 27%;\n animation: trail-backup 1.8s ease-in-out infinite alternate;\n}\n@keyframes packet {\n from {\n transform: translate(-10cqw, -50%);\n }\n to {\n transform: translate(120cqw, -50%);\n }\n}\n@keyframes packet-stall {\n from {\n transform: translate(-50%, -50%) scale(0.82);\n opacity: 0.72;\n }\n to {\n transform: translate(-50%, -50%) scale(1.12);\n opacity: 1;\n }\n}\n@keyframes trail-backup {\n from {\n transform: translate(-8%, -50%);\n opacity: 0.5;\n }\n to {\n transform: translate(8%, -50%);\n opacity: 0.95;\n }\n}\n@media (prefers-reduced-motion: reduce) {\n [data-overdue=\"true\"] .trail,\n [data-overdue=\"true\"] .packet,\n .trail,\n .packet {\n animation: none;\n }\n .frontier {\n transition: none;\n }\n}\n","import styles from './ReleaseTransitField.module.css'\n\nexport function ReleaseTransitField() {\n return (\n <>\n <span className={styles.frontier} data-running-part=\"frontier\" />\n <span className={styles.now} data-running-part=\"transit-now\" />\n <span className={styles.routes} data-running-part=\"transit-routes\">\n {[0, 1, 2].map((route) => (\n <span className={styles.route} key={route} />\n ))}\n </span>\n <span className={styles.trail} data-running-part=\"transit-trail\" />\n <span className={styles.packet} data-running-part=\"transit-packet\" />\n </>\n )\n}\n",".field {\n position: absolute;\n z-index: 0;\n inset: 0;\n overflow: hidden;\n pointer-events: none;\n container-type: size;\n container-name: running-field;\n color: var(--status-warning);\n}\n.overdue {\n color: var(--status-serious);\n}\n.timing {\n width: min(12ch, 100%);\n max-width: 100%;\n min-width: 0;\n flex: 0 1 12ch;\n margin: 0;\n color: var(--ink-secondary);\n font-family: ui-monospace, SFMono-Regular, Menlo, monospace;\n font-size: 0.72em;\n font-variant-numeric: tabular-nums;\n text-align: end;\n white-space: nowrap;\n overflow: hidden;\n}\n.timingOverdue {\n color: var(--status-serious);\n}\n",".haze {\n position: absolute;\n inset: -15%;\n background:\n radial-gradient(\n ellipse at 18% 44%,\n color-mix(in srgb, currentColor 19%, transparent),\n transparent 42%\n ),\n radial-gradient(\n ellipse at 74% 63%,\n color-mix(in srgb, currentColor 12%, transparent),\n transparent 38%\n );\n animation: haze 15s ease-in-out infinite alternate;\n}\n.pressure {\n display: none;\n}\n.band {\n position: absolute;\n right: -15%;\n left: -15%;\n height: 1px;\n background: linear-gradient(\n 90deg,\n transparent,\n color-mix(in srgb, currentColor 32%, transparent),\n transparent\n );\n animation: band 10s ease-in-out infinite alternate;\n}\n.bandOne {\n top: 32%;\n}\n.bandTwo {\n top: 67%;\n animation-delay: -4s;\n}\n.bandThree {\n top: 49%;\n animation-delay: -7s;\n opacity: 0.55;\n}\n.drift {\n position: absolute;\n width: clamp(0.34em, 0.9cqw, 0.7em);\n height: clamp(0.34em, 0.9cqw, 0.7em);\n border: 1px solid color-mix(in srgb, currentColor 78%, transparent);\n border-radius: 50%;\n box-shadow: 0 0 0.55em color-mix(in srgb, currentColor 55%, transparent);\n animation: drift 11s ease-in-out infinite alternate;\n}\n.driftOne {\n top: 25%;\n left: 12%;\n}\n.driftTwo {\n top: 72%;\n left: 58%;\n width: 0.34em;\n height: 0.34em;\n animation-duration: 14s;\n animation-delay: -4s;\n opacity: 0.6;\n}\n.driftThree {\n top: 18%;\n left: 74%;\n width: 0.7em;\n height: 0.7em;\n animation-duration: 17s;\n animation-delay: -9s;\n opacity: 0.55;\n}\n.driftFour {\n top: 58%;\n left: 31%;\n width: 0.42em;\n height: 0.42em;\n animation-duration: 9s;\n animation-delay: -2s;\n opacity: 0.75;\n}\n.driftFive {\n top: 84%;\n left: 83%;\n width: 0.58em;\n height: 0.58em;\n animation-duration: 13s;\n animation-delay: -6s;\n opacity: 0.45;\n}\n@container running-field (max-width: 40rem) or (max-height: 6rem) {\n .drift,\n .band {\n display: none;\n }\n .haze {\n inset: auto 0 0 auto;\n width: 2.5em;\n height: 2.5em;\n opacity: 0.65;\n }\n}\n[data-overdue=\"true\"] .haze {\n inset: -30%;\n background:\n radial-gradient(\n ellipse at 22% 48%,\n color-mix(in srgb, currentColor 34%, transparent),\n transparent 42%\n ),\n radial-gradient(\n ellipse at 78% 58%,\n color-mix(in srgb, currentColor 25%, transparent),\n transparent 36%\n );\n}\n[data-overdue=\"true\"] .pressure {\n display: block;\n position: absolute;\n inset: 20% 0;\n border-top: 1px solid color-mix(in srgb, currentColor 65%, transparent);\n border-bottom: 1px solid color-mix(in srgb, currentColor 65%, transparent);\n background: repeating-linear-gradient(\n 180deg,\n transparent 0 0.55em,\n color-mix(in srgb, currentColor 14%, transparent) 0.55em 0.62em\n );\n opacity: 0.75;\n animation: pressure 3.4s ease-in-out infinite alternate;\n}\n[data-overdue=\"true\"] .band {\n background: linear-gradient(90deg, transparent, currentColor, transparent);\n animation-name: storm-band;\n}\n[data-overdue=\"true\"] .drift {\n transform: translate(12cqw, -2cqh) scale(0.82);\n}\n@keyframes haze {\n to {\n transform: translate(9%, -4%);\n }\n}\n@keyframes band {\n to {\n transform: translateX(8%);\n opacity: 0.45;\n }\n}\n@keyframes drift {\n to {\n transform: translate(10cqw, -2cqh);\n }\n}\n@keyframes pressure {\n from {\n transform: scaleY(0.72);\n opacity: 0.45;\n }\n to {\n transform: scaleY(1.12);\n opacity: 0.9;\n }\n}\n@keyframes storm-band {\n to {\n transform: translateX(-14%);\n opacity: 0.9;\n }\n}\n@media (prefers-reduced-motion: reduce) {\n [data-overdue=\"true\"] .pressure,\n .haze,\n .band,\n .drift {\n animation: none;\n }\n .pressure {\n animation: none;\n }\n}\n","import styles from './StatusWeatherField.module.css'\n\nexport function StatusWeatherField() {\n return (\n <>\n <span className={styles.haze} data-running-part=\"weather-haze\" />\n <span className={styles.pressure} data-running-part=\"weather-pressure\" />\n <span className={`${styles.band} ${styles.bandOne}`} />\n <span className={`${styles.band} ${styles.bandTwo}`} />\n <span className={`${styles.band} ${styles.bandThree}`} />\n <span className={`${styles.drift} ${styles.driftOne}`} />\n <span className={`${styles.drift} ${styles.driftTwo}`} />\n <span className={`${styles.drift} ${styles.driftThree}`} />\n <span className={`${styles.drift} ${styles.driftFour}`} />\n <span className={`${styles.drift} ${styles.driftFive}`} />\n </>\n )\n}\n",".anchor {\n position: absolute;\n top: 50%;\n left: var(--running-progress);\n}\n.body {\n position: absolute;\n inset: 0;\n animation: phased-marker 3.2s ease-in-out infinite alternate;\n animation-delay: var(--phased-marker-delay, 0s);\n will-change: transform;\n}\n@keyframes phased-marker {\n from {\n transform: translate(var(--phased-marker-travel, -10em), -50%);\n }\n to {\n transform: translate(-50%, -50%);\n }\n}\n@media (prefers-reduced-motion: reduce) {\n .body {\n animation: none;\n }\n}\n","import type { CSSProperties } from 'react'\nimport styles from './PhasedProgressMarker.module.css'\n\n/**\n * A progress-anchored decorative marker. The anchor owns live progress geometry; the body owns\n * its independent phase animation, so a timing render cannot replace its transform.\n */\nexport function PhasedProgressMarker({\n anchorClassName,\n bodyClassName,\n delay,\n anchorPart,\n bodyPart,\n}: {\n anchorClassName: string | undefined\n bodyClassName: string | undefined\n delay?: string\n anchorPart?: string\n bodyPart: string\n}) {\n const style = delay ? ({ '--phased-marker-delay': delay } as CSSProperties) : undefined\n return (\n <span className={`${styles.anchor} ${anchorClassName ?? ''}`} data-running-part={anchorPart}>\n <span\n className={`${styles.body} ${bodyClassName ?? ''}`}\n data-running-part={bodyPart}\n style={style}\n />\n </span>\n )\n}\n",".frontier {\n position: absolute;\n inset: 0 auto 0 0;\n width: var(--running-progress);\n background: linear-gradient(\n 90deg,\n color-mix(in srgb, currentColor 16%, transparent),\n transparent\n );\n border-right: 1px solid color-mix(in srgb, currentColor 75%, transparent);\n}\n.flare {\n display: none;\n}\n.lanes {\n position: absolute;\n inset: 13% 7%;\n display: grid;\n align-content: space-between;\n}\n.lane {\n position: relative;\n height: 1px;\n background: linear-gradient(\n 90deg,\n transparent,\n color-mix(in srgb, var(--edge) 90%, transparent),\n transparent\n );\n}\n.markerAnchor {\n width: 0.42em;\n height: 0.25em;\n}\n.markerBody {\n --phased-marker-travel: -10cqw;\n border-radius: 999px;\n background: currentColor;\n box-shadow: 0 0 0.6em currentColor;\n}\n.lane:nth-child(2) .markerBody {\n opacity: 0.7;\n}\n.lane:nth-child(3) .markerBody {\n opacity: 0.5;\n}\n.lane:nth-child(4) .markerBody {\n opacity: 0.8;\n}\n@container running-field (max-width: 40rem) or (max-height: 6rem) {\n .lanes {\n display: none;\n }\n .frontier {\n width: 0.28em;\n border-right: 0;\n background: currentColor;\n }\n}\n[data-overdue=\"true\"] .frontier {\n width: 100%;\n background: linear-gradient(\n 90deg,\n color-mix(in srgb, currentColor 34%, transparent),\n transparent\n );\n border-right-color: currentColor;\n}\n[data-overdue=\"true\"] .flare {\n display: block;\n position: absolute;\n top: 0;\n left: 100%;\n width: 2.4em;\n height: 100%;\n background: radial-gradient(ellipse, currentColor 0, transparent 68%);\n transform: translateX(-50%);\n animation: bloom-flare 1.6s ease-in-out infinite alternate;\n}\n[data-overdue=\"true\"] .markerBody {\n --phased-marker-travel: -22.5cqw;\n animation-duration: 0.72s;\n animation-timing-function: ease-in-out;\n}\n@media (prefers-reduced-motion: reduce) {\n .frontier {\n transition: none;\n }\n [data-overdue=\"true\"] .flare,\n [data-overdue=\"true\"] .markerBody {\n animation: none;\n }\n}\n@keyframes bloom-flare {\n from {\n opacity: 0.42;\n transform: translateX(-50%) scale(0.8);\n }\n to {\n opacity: 0.95;\n transform: translateX(-50%) scale(1.15);\n }\n}\n","import { PhasedProgressMarker } from './PhasedProgressMarker.tsx'\nimport styles from './TelemetryBloomField.module.css'\n\nexport function TelemetryBloomField() {\n return (\n <>\n <span className={styles.frontier} data-running-part=\"frontier\" />\n <span className={styles.flare} data-running-part=\"bloom-flare\" />\n <span className={styles.lanes} data-running-part=\"bloom-lanes\">\n {[0, 1, 2, 3].map((lane) => (\n <span className={styles.lane} key={lane} data-running-part=\"bloom-lane\">\n <PhasedProgressMarker\n anchorClassName={styles.markerAnchor}\n bodyClassName={styles.markerBody}\n delay={[undefined, '-0.8s', '-1.7s', '-2.4s'][lane]}\n anchorPart=\"bloom-marker-anchor\"\n bodyPart=\"bloom-marker\"\n />\n </span>\n ))}\n </span>\n </>\n )\n}\n","import type { RunningAnimation } from '@ze-great-dashboard/shared'\nimport type { CSSProperties } from 'react'\nimport { FallingShapesField } from './FallingShapesField.tsx'\nimport { ReleaseTransitField } from './ReleaseTransitField.tsx'\nimport styles from './RunningField.module.css'\nimport { StatusWeatherField } from './StatusWeatherField.tsx'\nimport { TelemetryBloomField } from './TelemetryBloomField.tsx'\n\nexport type RunningFieldAnimation = Extract<\n RunningAnimation,\n 'telemetry-bloom' | 'release-transit' | 'status-weather' | 'falling-shapes'\n>\n\nexport function isRunningFieldAnimation(\n animation: Exclude<RunningAnimation, 'off'>,\n): animation is RunningFieldAnimation {\n return ['telemetry-bloom', 'release-transit', 'status-weather', 'falling-shapes'].includes(\n animation,\n )\n}\n\nexport function RunningField({\n animation,\n progress,\n estimatedDurationMs,\n overdue,\n indeterminate,\n seed,\n}: {\n animation: RunningFieldAnimation\n progress: number\n estimatedDurationMs?: number\n overdue: boolean\n indeterminate: boolean\n seed?: number\n}) {\n const style = {\n '--running-progress': `${progress * 100}%`,\n } as CSSProperties\n return (\n <div\n className={`${styles.field} ${overdue ? styles.overdue : ''}`}\n data-animation={animation}\n data-running-field\n data-overdue={overdue || undefined}\n data-indeterminate={indeterminate || undefined}\n aria-hidden=\"true\"\n style={style}\n >\n {animation === 'telemetry-bloom' && <TelemetryBloomField />}\n {animation === 'release-transit' && <ReleaseTransitField />}\n {animation === 'status-weather' && <StatusWeatherField />}\n {animation === 'falling-shapes' && (\n <FallingShapesField\n progress={progress}\n estimatedDurationMs={estimatedDurationMs}\n overdue={overdue}\n seed={seed}\n />\n )}\n </div>\n )\n}\n","import { useEffect, useState } from 'react'\n\nconst VISUAL_TICK_MS = 20\n\nexport type RunningTiming = {\n elapsedMs: number | undefined\n estimatedDurationMs: number | undefined\n hasEstimate: boolean\n overdue: boolean\n progress: number\n}\n\nexport function useRunningTiming(\n runStartedAt?: string,\n estimatedDurationMs?: number,\n): RunningTiming {\n const now = useClock(Boolean(runStartedAt))\n const startedAt = runStartedAt ? new Date(runStartedAt).valueOf() : Number.NaN\n const elapsedMs = Number.isFinite(startedAt) ? Math.max(0, now - startedAt) : undefined\n const hasEstimate = elapsedMs !== undefined && estimatedDurationMs !== undefined\n const overdue = hasEstimate && elapsedMs > estimatedDurationMs\n const progress = hasEstimate ? Math.min(elapsedMs / estimatedDurationMs, 1) : 0\n return { elapsedMs, estimatedDurationMs, hasEstimate, overdue, progress }\n}\n\nfunction useClock(enabled: boolean) {\n const [now, setNow] = useState(() => Date.now())\n useEffect(() => {\n if (!enabled) return\n setNow(Date.now())\n // The timing text rounds to seconds, but progress gets display-cadence intermediate positions.\n // This avoids the visible sawtooth created by a coarse timer and CSS transition.\n const interval = window.setInterval(() => setNow(Date.now()), VISUAL_TICK_MS)\n return () => window.clearInterval(interval)\n }, [enabled])\n return now\n}\n\nexport function timingDescription(\n elapsedMs: number | undefined,\n estimatedDurationMs: number | undefined,\n overdue: boolean,\n) {\n const elapsed =\n elapsedMs === undefined ? 'Run in progress' : `Elapsed ${formatDuration(elapsedMs)}`\n const expected =\n estimatedDurationMs === undefined\n ? 'Expected duration unavailable'\n : `Expected ≈ ${formatDuration(estimatedDurationMs)}`\n return `${elapsed} · ${expected}${overdue ? ' · Over estimate' : ''}`\n}\n\nexport function compactTiming(\n elapsedMs: number | undefined,\n estimatedDurationMs: number | undefined,\n overdue: boolean,\n) {\n const elapsed = elapsedMs === undefined ? '—' : formatClockDuration(elapsedMs)\n const expected =\n estimatedDurationMs === undefined ? '?' : `~${formatClockDuration(estimatedDurationMs)}`\n return `${overdue ? '⚠' : '\\u00a0'}${elapsed}/${expected}`\n}\n\nfunction formatDuration(durationMs: number) {\n const totalSeconds = Math.floor(durationMs / 1_000)\n const hours = Math.floor(totalSeconds / 3_600)\n const minutes = Math.floor((totalSeconds % 3_600) / 60)\n const seconds = totalSeconds % 60\n if (hours > 0) return `${hours}h ${minutes}m`\n if (minutes > 0) return `${minutes}m ${seconds}s`\n return `${seconds}s`\n}\n\nfunction formatClockDuration(durationMs: number) {\n const totalSeconds = Math.floor(durationMs / 1_000)\n const hours = Math.floor(totalSeconds / 3_600)\n const minutes = Math.floor((totalSeconds % 3_600) / 60)\n const seconds = totalSeconds % 60\n const clock = `${minutes}:${String(seconds).padStart(2, '0')}`\n return hours > 0 ? `${hours}:${clock.padStart(5, '0')}` : clock\n}\n","import styles from './RunningField.module.css'\nimport { compactTiming, timingDescription } from './running-timing.ts'\n\n/** The sole readable timing projection for panel-scale decorative fields. */\nexport function RunningFieldTiming({\n elapsedMs,\n estimatedDurationMs,\n overdue,\n}: {\n elapsedMs: number | undefined\n estimatedDurationMs: number | undefined\n overdue: boolean\n}) {\n return (\n <p className={`${styles.timing} ${overdue ? styles.timingOverdue : ''}`}>\n <span className=\"screen-reader-only\">\n {timingDescription(elapsedMs, estimatedDurationMs, overdue)}\n </span>\n <span aria-hidden=\"true\">{compactTiming(elapsedMs, estimatedDurationMs, overdue)}</span>\n </p>\n )\n}\n",".progress {\n display: flex;\n align-items: center;\n gap: 0.6em;\n min-width: 0;\n color: var(--status-warning);\n}\n.visual {\n position: relative;\n flex: 0 0 auto;\n}\n.timing {\n margin: 0;\n color: var(--ink-secondary);\n font-size: 0.72em;\n}\n.overdue {\n color: var(--status-serious);\n}\n.overdue .timing {\n color: var(--status-serious);\n}\n.readout {\n width: 12ch;\n flex: 0 0 12ch;\n font-family: ui-monospace, SFMono-Regular, Menlo, monospace;\n font-variant-numeric: tabular-nums;\n text-align: end;\n white-space: nowrap;\n}\n.radial .visual {\n width: 2.35em;\n height: 2.35em;\n border: 0.14em solid var(--edge);\n border-radius: 50%;\n background: conic-gradient(var(--status-warning) var(--running-progress), var(--edge) 0);\n box-shadow:\n inset 0 0 0 0.22em var(--surface-raised),\n 0 0 0.55em color-mix(in srgb, var(--status-warning) 45%, transparent);\n}\n.radial .visual::after {\n content: \"\";\n position: absolute;\n inset: -0.14em;\n border-radius: 50%;\n border-top: 0.14em solid var(--status-warning);\n animation: sweep 1.7s linear infinite;\n}\n.overdue.radial .visual::before {\n content: \"\";\n position: absolute;\n inset: -0.42em;\n border: 0.1em solid var(--status-serious);\n border-radius: 50%;\n box-shadow: 0 0 0.55em color-mix(in srgb, var(--status-serious) 65%, transparent);\n animation: alarm-ring 1.8s ease-in-out infinite;\n}\n.radialCore {\n position: absolute;\n inset: 0.68em;\n border-radius: 50%;\n background: var(--status-warning);\n box-shadow: 0 0 0.45em var(--status-warning);\n}\n.overdue .radialCore {\n background: var(--status-serious);\n box-shadow: 0 0 0.55em var(--status-serious);\n animation: reactor-breathe 1.8s ease-in-out infinite alternate;\n}\n.runway {\n display: grid;\n grid-template-columns: minmax(0, 1fr) auto;\n align-self: stretch;\n container-type: inline-size;\n}\n.runway .visual {\n width: min(12em, 100%);\n max-width: 100%;\n height: 0.8em;\n overflow: hidden;\n border: 1px solid var(--edge);\n border-radius: 999px;\n background: linear-gradient(90deg, var(--status-warning) var(--running-progress), var(--edge) 0);\n}\n.runway .visual::after {\n content: \"\";\n position: absolute;\n top: -0.25em;\n bottom: -0.25em;\n left: calc(var(--running-progress) - 0.06em);\n width: 0.12em;\n background: var(--ink-primary);\n box-shadow: 0 0 0.45em var(--ink-primary);\n}\n.overdue.runway .visual::before {\n content: \"\";\n position: absolute;\n inset: -0.2em 0;\n left: calc(100% - 0.55em);\n width: 0.55em;\n background: repeating-linear-gradient(\n -45deg,\n var(--status-serious) 0 0.12em,\n var(--surface) 0.12em 0.24em\n );\n box-shadow: 0 0 0.5em color-mix(in srgb, var(--status-serious) 70%, transparent);\n animation: barrier-pulse 1.4s ease-in-out infinite alternate;\n}\n.overdue.runway .visual::after {\n background: var(--status-serious);\n box-shadow: 0 0 0.55em var(--status-serious);\n animation: barrier-pulse 1.4s ease-in-out infinite alternate;\n}\n.spark {\n position: absolute;\n top: 50%;\n left: -0.5em;\n width: 0.35em;\n height: 0.35em;\n border-radius: 50%;\n background: var(--ink-primary);\n box-shadow: 0 0 0.4em var(--status-warning);\n animation: spark 1.5s linear infinite;\n}\n.overdue.runway .spark {\n animation-duration: 1s;\n}\n.sparkTwo {\n display: none;\n animation-delay: -0.5s;\n}\n.overdue.runway .sparkTwo {\n display: block;\n}\n.orbit .visual {\n width: 2.4em;\n height: 2.4em;\n border: 1px solid var(--edge);\n border-radius: 50%;\n}\n/* biome-ignore lint/style/noDescendingSpecificity: the radial overdue ring precedes this separate legacy treatment. */\n.orbit .visual::before {\n content: \"\";\n position: absolute;\n inset: 0.18em;\n border: 0.12em solid transparent;\n border-top-color: var(--status-warning);\n border-radius: 50%;\n transform: rotate(var(--running-degrees));\n}\n.orbitCore {\n position: absolute;\n inset: 0.75em;\n border-radius: 50%;\n background: var(--status-warning);\n box-shadow: 0 0 0.45em var(--status-warning);\n}\n.overdue .orbitCore {\n background: var(--status-serious);\n box-shadow: 0 0 0.55em var(--status-serious);\n animation: reactor-breathe 1.15s ease-in-out infinite alternate;\n}\n.particle {\n position: absolute;\n top: 0.25em;\n left: calc(50% - 0.16em);\n width: 0.32em;\n height: 0.32em;\n border-radius: 50%;\n background: var(--ink-primary);\n transform-origin: 0.16em 0.95em;\n animation: orbit 1.8s linear infinite;\n}\n.particleTwo {\n animation-delay: -0.9s;\n background: var(--status-warning);\n}\n.overdue.orbit .visual::after {\n content: \"\";\n position: absolute;\n inset: 0.42em;\n border: 0.08em solid color-mix(in srgb, var(--status-serious) 75%, transparent);\n border-radius: 50%;\n box-shadow: 0 0 0.6em color-mix(in srgb, var(--status-serious) 55%, transparent);\n animation: gravity-well 1.15s ease-in-out infinite alternate;\n}\n.overdue.orbit .particle {\n transform-origin: 0.16em 0.7em;\n animation-duration: 0.95s;\n}\n.indeterminate .visual {\n background-image: repeating-linear-gradient(\n 135deg,\n color-mix(in srgb, var(--status-warning) 70%, transparent) 0 0.25em,\n var(--edge) 0.25em 0.5em\n );\n animation: shift 1s linear infinite;\n}\n.signalField {\n container-type: size;\n display: grid;\n grid-template-columns: minmax(0, 1fr) auto;\n align-self: stretch;\n flex: 1 1 auto;\n min-height: 0;\n max-height: 100%;\n}\n.signalField .visual {\n width: auto;\n height: 1em;\n max-height: 100%;\n overflow: hidden;\n border: 1px solid var(--edge);\n border-radius: 999px;\n background: var(--surface);\n}\n.rail {\n position: absolute;\n inset: 0;\n background: linear-gradient(90deg, var(--status-warning) var(--running-progress), var(--edge) 0);\n opacity: 0.75;\n}\n.lead {\n position: absolute;\n top: -0.2em;\n bottom: -0.2em;\n left: calc(var(--running-progress) - 0.08em);\n width: 0.16em;\n border-radius: 999px;\n background: var(--ink-primary);\n box-shadow: 0 0 0.5em var(--status-warning);\n}\n.pulse {\n position: absolute;\n top: 50%;\n left: -0.5em;\n width: 0.3em;\n height: 0.3em;\n border-radius: 50%;\n background: var(--ink-primary);\n box-shadow: 0 0 0.4em var(--status-warning);\n animation: pulse 2.4s ease-in-out infinite alternate;\n}\n.pulseTwo {\n animation-delay: -1.2s;\n}\n.tracks {\n display: none;\n}\n@container panel (min-width: 26rem) {\n .runway .visual {\n flex: 1 1 auto;\n width: auto;\n height: clamp(1.1em, 7cqw, 2.7em);\n box-shadow: inset 0 0 1em color-mix(in srgb, var(--status-warning) 16%, transparent);\n }\n .runway .visual::after {\n left: calc(var(--running-progress) - 0.08em);\n width: 0.16em;\n }\n .spark {\n animation-name: sparkWide;\n }\n}\n@container panel (max-width: 18rem) {\n .signalField {\n flex: 0 1 auto;\n min-height: 0;\n }\n .signalField .visual {\n width: 2.65em;\n height: 1.15em;\n }\n .signalField .rail {\n background: var(--edge);\n }\n .signalField .lead {\n top: 0.2em;\n bottom: 0.2em;\n width: 0.38em;\n border-radius: 50%;\n }\n .pulse {\n display: none;\n }\n}\n@container panel (max-height: 5rem) {\n .signalField {\n flex: 0 1 auto;\n min-height: 0;\n }\n .signalField .visual {\n width: 2.65em;\n height: 1.15em;\n }\n .signalField .rail {\n background: var(--edge);\n }\n .signalField .lead {\n top: 0.2em;\n bottom: 0.2em;\n width: 0.38em;\n border-radius: 50%;\n }\n .pulse {\n display: none;\n }\n}\n/* A size-contained signal field cannot use its own intrinsic height as a query input: its\n auto-sized content would always satisfy the compact branch. Width is the stable panel-scale\n discriminator; the field's parent already controls its available height. */\n@container panel (min-width: 26rem) {\n .signalField .visual {\n height: 100%;\n min-height: 0;\n border-radius: 0.25em;\n background: linear-gradient(\n 180deg,\n color-mix(in srgb, var(--edge) 60%, transparent),\n transparent\n );\n }\n .signalField .visual::before {\n content: \"\";\n position: absolute;\n inset: 0 auto 0 0;\n width: var(--running-progress);\n background:\n repeating-linear-gradient(\n 0deg,\n transparent 0 0.55em,\n color-mix(in srgb, var(--status-warning) 16%, transparent) 0.55em 0.6em\n ),\n linear-gradient(\n 90deg,\n color-mix(in srgb, var(--status-warning) 19%, transparent),\n color-mix(in srgb, var(--status-warning) 7%, transparent)\n );\n box-shadow: inset -0.8em 0 1em color-mix(in srgb, var(--status-warning) 22%, transparent);\n }\n .signalField .rail {\n top: 50%;\n bottom: auto;\n height: 1px;\n }\n .signalField .lead {\n top: calc(50% - 0.45em);\n bottom: auto;\n height: 0.9em;\n }\n .pulse {\n display: none;\n }\n .tracks {\n position: absolute;\n inset: 0.8em 0;\n display: flex;\n flex-direction: column;\n justify-content: space-between;\n }\n .track {\n position: relative;\n height: 1px;\n background: linear-gradient(\n 90deg,\n transparent,\n color-mix(in srgb, var(--edge) 85%, transparent),\n transparent\n );\n }\n .markerAnchor {\n width: 0.38em;\n height: 0.22em;\n }\n .markerBody {\n border-radius: 0.06em;\n background: var(--status-warning);\n box-shadow: 0 0 0.4em var(--status-warning);\n }\n .track:nth-child(2) .markerBody {\n animation-delay: -0.8s;\n opacity: 0.7;\n }\n .track:nth-child(3) .markerBody {\n animation-delay: -1.7s;\n opacity: 0.45;\n }\n .track:nth-child(4) .markerBody {\n animation-delay: -2.4s;\n opacity: 0.7;\n }\n .track:nth-child(5) .markerBody {\n animation-delay: -0.35s;\n opacity: 0.55;\n }\n}\n.overdue.signalField .rail {\n background: linear-gradient(90deg, var(--status-serious) 0 100%);\n opacity: 0.42;\n}\n.overdue.signalField .lead {\n background: var(--status-serious);\n box-shadow: 0 0 0.7em var(--status-serious);\n animation: endpoint-pulse 1.2s ease-in-out infinite alternate;\n}\n.overdue.signalField .markerBody {\n --phased-marker-travel: -10em;\n background: var(--status-serious);\n box-shadow: 0 0 0.55em var(--status-serious);\n animation-duration: 0.68s;\n animation-timing-function: ease-in-out;\n}\n.short .signalField .visual {\n height: 1em;\n}\n@keyframes sweep {\n to {\n transform: rotate(360deg);\n }\n}\n@keyframes alarm-ring {\n from {\n transform: scale(0.92);\n opacity: 0.45;\n }\n to {\n transform: scale(1.08);\n opacity: 1;\n }\n}\n@keyframes reactor-breathe {\n from {\n transform: scale(0.84);\n opacity: 0.7;\n }\n to {\n transform: scale(1.12);\n opacity: 1;\n }\n}\n@keyframes barrier-pulse {\n from {\n opacity: 0.55;\n }\n to {\n opacity: 1;\n }\n}\n@keyframes gravity-well {\n from {\n transform: scale(0.82);\n opacity: 0.45;\n }\n to {\n transform: scale(1.08);\n opacity: 0.95;\n }\n}\n@keyframes endpoint-pulse {\n from {\n transform: scaleY(0.75);\n opacity: 0.65;\n }\n to {\n transform: scaleY(1.15);\n opacity: 1;\n }\n}\n@keyframes spark {\n to {\n transform: translateX(13em);\n }\n}\n@keyframes sparkWide {\n to {\n transform: translateX(100cqw);\n }\n}\n@keyframes orbit {\n to {\n transform: rotate(360deg);\n }\n}\n@keyframes shift {\n to {\n background-position: 1em 0;\n }\n}\n@keyframes pulse {\n from {\n transform: translate(-0.5em, -50%);\n }\n to {\n transform: translate(calc(var(--running-progress) + 0.5em), -50%);\n }\n}\n@media (prefers-reduced-motion: reduce) {\n .radial .visual::after,\n .overdue.radial .visual::before,\n .overdue .radialCore,\n .spark,\n .runway .visual::after,\n .overdue.runway .visual::before,\n .overdue.runway .visual::after,\n .particle,\n .overdue.orbit .visual::after,\n .pulse,\n .lead,\n .overdue.signalField .lead,\n .overdue.signalField .markerBody,\n /* biome-ignore lint/style/noDescendingSpecificity: the shared reduced-motion list intentionally follows themed overrides. */\n .signalField .visual::before,\n .indeterminate .visual {\n animation: none;\n }\n}\n","import type { RunningAnimation } from '@ze-great-dashboard/shared'\nimport type { CSSProperties } from 'react'\nimport { PhasedProgressMarker } from './PhasedProgressMarker.tsx'\nimport styles from './RunningProgress.module.css'\nimport { compactTiming, type RunningTiming, timingDescription } from './running-timing.ts'\n\nexport function RunningProgress({\n animation,\n timing,\n}: {\n animation: LegacyRunningAnimation\n timing: RunningTiming\n}) {\n const { elapsedMs, estimatedDurationMs, hasEstimate, overdue, progress } = timing\n const usesReadout = animation === 'runway' || animation === 'signal-field'\n const timingText = timingDescription(elapsedMs, estimatedDurationMs, overdue)\n const style = {\n '--running-progress': `${progress * 100}%`,\n '--running-degrees': `${progress * 360}deg`,\n } as CSSProperties\n const animationStyle = animation === 'signal-field' ? styles.signalField : styles[animation]\n\n return (\n <div\n className={`${styles.progress} ${animationStyle} ${overdue ? styles.overdue : ''} ${hasEstimate ? '' : styles.indeterminate}`}\n style={style}\n data-running-progress={animation}\n data-overdue={overdue || undefined}\n data-indeterminate={!hasEstimate || undefined}\n >\n <div className={styles.visual} aria-hidden=\"true\" data-running-visual>\n {animation === 'radial' && <span className={styles.radialCore} />}\n {animation === 'runway' && (\n <>\n <span className={styles.spark} data-running-part=\"runway-spark\" />\n <span\n className={`${styles.spark} ${styles.sparkTwo}`}\n data-running-part=\"runway-spark-two\"\n />\n </>\n )}\n {animation === 'orbit' && (\n <>\n <span className={styles.orbitCore} />\n <span className={styles.particle} />\n <span className={`${styles.particle} ${styles.particleTwo}`} />\n </>\n )}\n {animation === 'signal-field' && (\n <>\n <span className={styles.rail} />\n <span className={styles.lead} />\n <span className={styles.pulse} />\n <span className={`${styles.pulse} ${styles.pulseTwo}`} />\n <span className={styles.tracks} data-running-part=\"signal-tracks\">\n {[0, 1, 2, 3, 4].map((track) => (\n <span className={styles.track} key={track} data-running-part=\"signal-track\">\n <PhasedProgressMarker\n anchorClassName={styles.markerAnchor}\n bodyClassName={styles.markerBody}\n delay={[undefined, '-0.8s', '-1.7s', '-2.4s', '-0.35s'][track]}\n anchorPart=\"signal-marker-anchor\"\n bodyPart=\"signal-marker\"\n />\n </span>\n ))}\n </span>\n </>\n )}\n </div>\n <p className={`${styles.timing} ${usesReadout ? styles.readout : ''}`}>\n {usesReadout ? (\n <>\n <span className=\"screen-reader-only\">{timingText}</span>\n <span aria-hidden=\"true\">{compactTiming(elapsedMs, estimatedDurationMs, overdue)}</span>\n </>\n ) : (\n timingText\n )}\n </p>\n </div>\n )\n}\n\n/** The compact, inline treatments retained for existing boards. */\nexport type LegacyRunningAnimation = Extract<\n RunningAnimation,\n 'radial' | 'runway' | 'orbit' | 'signal-field'\n>\n\nexport function isLegacyRunningAnimation(\n animation: RunningAnimation,\n): animation is LegacyRunningAnimation {\n return ['radial', 'runway', 'orbit', 'signal-field'].includes(animation)\n}\n","import { type Panel, parseDuration } from '@ze-great-dashboard/shared'\nimport { useEffect, useState } from 'react'\nimport { fallingSeed } from './falling-shapes.ts'\nimport { PanelFrame, PanelStatus } from './PanelFrame.tsx'\nimport styles from './PipelineAnimationDemoPanel.module.css'\nimport { isRunningFieldAnimation, RunningField } from './RunningField.tsx'\nimport { RunningFieldTiming } from './RunningFieldTiming.tsx'\nimport { RunningProgress } from './RunningProgress.tsx'\nimport { useRunningTiming } from './running-timing.ts'\n\nconst DEFAULT_RUN_DURATION_MS = 20_000\nconst ESTIMATED_DURATION_MS = 15_000\nconst DEFAULT_REVIEW_DURATION_MS = 300_000\nconst REVIEW_CYCLE_MULTIPLIER = 1.25\nconst variants = [\n 'radial',\n 'runway',\n 'orbit',\n 'signal-field',\n 'telemetry-bloom',\n 'release-transit',\n 'status-weather',\n 'falling-shapes',\n] as const\n\n/**\n * A local comparison aid for the active-run treatments. It deliberately creates no signal or\n * diagnostic evidence: its state is derived only from the wall clock and repeats forever.\n */\nexport function PipelineAnimationDemoPanel({ panel }: { panel: Panel }) {\n const now = useClock()\n // A configured visible treatment turns the local comparison aid into a stable review panel.\n // `off` retains the rotating default: the demo exists to render a treatment.\n const fixedAnimation =\n panel.running_animation === undefined || panel.running_animation === 'off'\n ? undefined\n : panel.running_animation\n const runDurationMs = durationMillis(panel.demo_run_duration, DEFAULT_RUN_DURATION_MS)\n const reviewDurationMs = durationMillis(panel.demo_review_duration, DEFAULT_REVIEW_DURATION_MS)\n const durationMs = fixedAnimation\n ? Math.ceil(reviewDurationMs * REVIEW_CYCLE_MULTIPLIER)\n : runDurationMs\n const runNumber = Math.floor(now / durationMs)\n const animation = fixedAnimation ?? variants[runNumber % variants.length] ?? 'radial'\n const runStartedAt = runNumber * durationMs\n\n return (\n <DemoRun\n panel={panel}\n animation={animation}\n runStartedAt={runStartedAt}\n estimatedDurationMs={fixedAnimation ? reviewDurationMs : ESTIMATED_DURATION_MS}\n />\n )\n}\n\nfunction durationMillis(value: Panel['demo_run_duration'], fallback: number): number {\n if (!value) return fallback\n return parseDuration(value) ?? fallback\n}\n\nfunction DemoRun({\n panel,\n animation,\n runStartedAt,\n estimatedDurationMs,\n}: {\n panel: Panel\n animation: (typeof variants)[number]\n runStartedAt: number\n estimatedDurationMs: number\n}) {\n const startedAt = new Date(runStartedAt).toISOString()\n const timing = useRunningTiming(startedAt, estimatedDurationMs)\n const usesField = isRunningFieldAnimation(animation)\n return (\n <PanelFrame\n panel={panel}\n field={\n usesField ? (\n <RunningField\n key={`${animation}-${runStartedAt}`}\n animation={animation}\n progress={timing.progress}\n estimatedDurationMs={timing.estimatedDurationMs}\n overdue={timing.overdue}\n indeterminate={!timing.hasEstimate}\n seed={fallingSeed(panel.id)}\n />\n ) : undefined\n }\n >\n <PanelStatus status=\"running\">↻ Running</PanelStatus>\n <p className={styles.variant}>Demo treatment · {animation}</p>\n {usesField ? (\n <RunningFieldTiming\n elapsedMs={timing.elapsedMs}\n estimatedDurationMs={estimatedDurationMs}\n overdue={timing.overdue}\n />\n ) : (\n <RunningProgress animation={animation} timing={timing} />\n )}\n </PanelFrame>\n )\n}\n\nfunction useClock() {\n const [now, setNow] = useState(() => Date.now())\n useEffect(() => {\n const interval = window.setInterval(() => setNow(Date.now()), 1_000)\n return () => window.clearInterval(interval)\n }, [])\n return now\n}\n",".details {\n display: contents;\n}\n.details > :global(.hint) {\n line-height: 1.1;\n}\n.activity,\n.duration {\n overflow-wrap: anywhere;\n}\n@container panel (min-width: 48rem) {\n :global([data-density=\"comfortable\"][data-shallow=\"true\"]) .details > *,\n :global([data-density=\"auto\"][data-shallow=\"true\"]) .details > * {\n margin: 0;\n }\n}\n","import type { PipelineStatus } from '@ze-great-dashboard/shared'\n\nexport type PanelStatusKind = PipelineStatus['status']\n\nexport function statusPresentation(status: PanelStatusKind, passedLabel = 'Passed') {\n switch (status) {\n case 'passed':\n return { glyph: '✓', label: passedLabel }\n case 'failed':\n return { glyph: '✕', label: 'Failed' }\n case 'running':\n return { glyph: '↻', label: 'Running' }\n case 'cancelled':\n return { glyph: '⊘', label: 'Cancelled' }\n case 'unknown':\n return { glyph: '?', label: 'Unknown' }\n }\n}\n","import type { PipelineActivity } from '@ze-great-dashboard/shared'\n\nexport function formatPipelineActivity(activity: PipelineActivity | undefined) {\n if (!activity) return 'Activity unavailable'\n return activity.parent ? `${activity.parent} › ${activity.name}` : activity.name\n}\n","import {\n type Envelope,\n type Panel,\n type PipelineStatus,\n pipelineStatusSchema,\n type RunningAnimation,\n visibleRunningAnimations,\n} from '@ze-great-dashboard/shared'\nimport { useRef, useState } from 'react'\nimport { fallingSeed } from './falling-shapes.ts'\nimport { PanelFrame, PanelHint, PanelMetadata, PanelStatus } from './PanelFrame.tsx'\nimport styles from './PipelinePanel.module.css'\nimport type { PanelProps } from './panel-props.ts'\nimport { statusPresentation } from './panel-status.ts'\nimport { formatPipelineActivity } from './pipeline-activity.ts'\nimport { isRunningFieldAnimation, RunningField } from './RunningField.tsx'\nimport { RunningFieldTiming } from './RunningFieldTiming.tsx'\nimport { isLegacyRunningAnimation, RunningProgress } from './RunningProgress.tsx'\nimport { useRunningTiming } from './running-timing.ts'\nimport { CheckedAt, RunAge } from './TimeAge.tsx'\n\nexport function PipelinePanel({ panel, envelope, checkedAt }: PanelProps) {\n if (!envelope)\n return (\n <PanelFrame panel={panel}>\n <PanelHint>Loading…</PanelHint>\n </PanelFrame>\n )\n if (envelope.state === 'error') {\n return (\n <PanelFrame panel={panel} envelope={envelope} error>\n <PanelStatus>\n ⚠ {envelope.error.kind === 'no-runs' ? 'No workflow runs' : 'Unable to read'}\n </PanelStatus>\n <PanelHint>{envelope.error.message}</PanelHint>\n {checkedAt && <CheckedAt value={checkedAt} />}\n </PanelFrame>\n )\n }\n\n const signal = pipelineStatusSchema.safeParse(envelope.signal)\n if (!signal.success)\n return (\n <PanelFrame panel={panel} envelope={envelope} error>\n <PanelStatus>⚠ Invalid signal</PanelStatus>\n {checkedAt && <CheckedAt value={checkedAt} />}\n </PanelFrame>\n )\n return (\n <PipelineSignalPanel\n panel={panel}\n envelope={envelope}\n signal={signal.data}\n checkedAt={checkedAt}\n />\n )\n}\n\nfunction PipelineSignalPanel({\n panel,\n envelope,\n signal,\n checkedAt,\n}: {\n panel: Panel\n envelope: Envelope\n signal: PipelineStatus\n checkedAt?: string\n}) {\n const presentation = statusPresentation(signal.status)\n const [defaultAnimation, setDefaultAnimation] = useState<RunningAnimation | undefined>(() =>\n signal.status === 'running' ? selectDefaultRunningAnimation() : undefined,\n )\n const previousStatusRef = useRef(signal.status)\n if (signal.status !== previousStatusRef.current) {\n const wasRunning = previousStatusRef.current === 'running'\n previousStatusRef.current = signal.status\n if (panel.running_animation === undefined && !wasRunning && signal.status === 'running') {\n setDefaultAnimation((previousAnimation) => selectDefaultRunningAnimation(previousAnimation))\n }\n }\n const animation = panel.running_animation ?? defaultAnimation ?? 'off'\n const activeRun = signal.status === 'running' && animation !== 'off'\n const timing = useRunningTiming(signal.runStartedAt, signal.estimatedDurationMs)\n const usesField = activeRun && isRunningFieldAnimation(animation)\n const usesLegacyProgress = activeRun && isLegacyRunningAnimation(animation)\n return (\n <PanelFrame\n panel={panel}\n envelope={envelope}\n field={\n usesField ? (\n <RunningField\n animation={animation}\n progress={timing.progress}\n estimatedDurationMs={timing.estimatedDurationMs}\n overdue={timing.overdue}\n indeterminate={!timing.hasEstimate}\n seed={fallingSeed(panel.id)}\n />\n ) : undefined\n }\n >\n <div className={styles.details}>\n <PanelStatus status={signal.status}>\n {presentation.glyph} {presentation.label}\n </PanelStatus>\n {signal.status === 'running' && (\n <PanelMetadata\n glyph=\"⚙\"\n label=\"Activity\"\n value={formatPipelineActivity(signal.activity)}\n title={`Activity: ${formatPipelineActivity(signal.activity)}`}\n className={styles.activity}\n />\n )}\n {signal.branch && (\n <PanelMetadata\n glyph=\"⎇\"\n label=\"Branch\"\n value={<span className={styles.branch}>{signal.branch}</span>}\n title={`Branch: ${signal.branch}`}\n />\n )}\n {usesField && (\n <RunningFieldTiming\n elapsedMs={timing.elapsedMs}\n estimatedDurationMs={signal.estimatedDurationMs}\n overdue={timing.overdue}\n />\n )}\n {usesLegacyProgress && <RunningProgress animation={animation} timing={timing} />}\n {signal.status !== 'running' && signal.durationMs !== undefined && (\n <PanelMetadata\n glyph=\"◷\"\n label=\"Duration\"\n value={`Took ${formatDuration(signal.durationMs)}`}\n title={`Duration: Took ${formatDuration(signal.durationMs)}`}\n className={styles.duration}\n />\n )}\n {((signal.status === 'running' && signal.runStartedAt) || signal.sourceUpdatedAt) && (\n <RunAge\n value={\n signal.status === 'running' && signal.runStartedAt\n ? signal.runStartedAt\n : (signal.sourceUpdatedAt ?? envelope.observedAt)\n }\n running={signal.status === 'running'}\n />\n )}\n {checkedAt && <CheckedAt value={checkedAt} />}\n </div>\n </PanelFrame>\n )\n}\n\nfunction selectDefaultRunningAnimation(previousAnimation?: RunningAnimation) {\n const candidates = visibleRunningAnimations.filter((animation) => animation !== previousAnimation)\n return candidates[Math.floor(Math.random() * candidates.length)] ?? 'telemetry-bloom'\n}\n\nfunction formatDuration(durationMs: number) {\n const totalSeconds = Math.floor(durationMs / 1_000)\n const hours = Math.floor(totalSeconds / 3_600)\n const minutes = Math.floor((totalSeconds % 3_600) / 60)\n const seconds = totalSeconds % 60\n\n if (hours > 0) return `${hours}h ${minutes}m`\n if (minutes > 0) return `${minutes}m ${seconds}s`\n return `${seconds}s`\n}\n",".compactFacts {\n display: none;\n min-width: 0;\n flex-direction: column;\n gap: 0.1em;\n overflow: hidden;\n}\n\n.compactFact {\n min-width: 0;\n margin: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.compactPrimary {\n color: var(--ink-primary);\n font-size: 0.85em;\n font-weight: 600;\n}\n\n.compactSecondary {\n color: var(--ink-muted);\n font-size: 0.7em;\n}\n\n@container panel (max-width: 13rem) {\n :global([data-density=\"compact\"]) .compactFacts {\n display: flex;\n }\n\n :global([data-density=\"compact\"]) .fullSummary {\n position: absolute;\n width: 1px;\n height: 1px;\n padding: 0;\n margin: -1px;\n overflow: hidden;\n clip: rect(0, 0, 0, 0);\n white-space: nowrap;\n border: 0;\n }\n}\n\n@container panel (max-width: 13rem) and (max-height: 10rem) {\n :global([data-density=\"compact\"]) .compactFacts ~ :global([data-panel-meta]) {\n display: none;\n }\n}\n","export function formatCount(count: number, singular: string, plural = `${singular}s`) {\n return `${count} ${count === 1 ? singular : plural}`\n}\n","import type { PullRequestHealth } from '@ze-great-dashboard/shared'\nimport { formatCount } from './panel-formatting.ts'\n\nexport type PullRequestHealthCompactFacts = {\n primary: string\n secondary: string\n primaryDetail?: string\n title: string\n}\n\n/**\n * Keep the wall-facing version of this aggregate signal short without making the\n * server's prose summary part of the client contract.\n */\nexport function compactPullRequestHealthFacts(\n signal: PullRequestHealth,\n): PullRequestHealthCompactFacts {\n const failedItem = [...signal.workflows, ...signal.pullRequests].find(\n (item) => item.status === 'failed',\n )\n\n if (failedItem) {\n return {\n primary: `${failedItem.label} failed`,\n secondary: `${formatCount(signal.workflows.length, 'workflow')} · ${formatCount(signal.pullRequests.length, 'open PR')}`,\n primaryDetail: failedItem.detail,\n title: `${signal.summary} — ${failedItem.label}: ${failedItem.detail}`,\n }\n }\n\n return {\n primary: formatCount(signal.workflows.length, 'workflow'),\n secondary: formatCount(signal.pullRequests.length, 'open PR'),\n title: signal.summary,\n }\n}\n","import { pullRequestHealthSchema } from '@ze-great-dashboard/shared'\nimport { PanelFrame, PanelHint, PanelStatus } from './PanelFrame.tsx'\nimport styles from './PullRequestHealthPanel.module.css'\nimport type { PanelProps } from './panel-props.ts'\nimport { statusPresentation } from './panel-status.ts'\nimport { compactPullRequestHealthFacts } from './pull-request-health.ts'\nimport { CheckedAt } from './TimeAge.tsx'\n\nexport function PullRequestHealthPanel({ panel, envelope, checkedAt }: PanelProps) {\n if (!envelope)\n return (\n <PanelFrame panel={panel}>\n <PanelHint>Loading…</PanelHint>\n </PanelFrame>\n )\n if (envelope.state === 'error')\n return (\n <PanelFrame panel={panel} envelope={envelope} error>\n <PanelStatus>⚠ Unable to read</PanelStatus>\n <PanelHint>{envelope.error.message}</PanelHint>\n {checkedAt && <CheckedAt value={checkedAt} />}\n </PanelFrame>\n )\n const signal = pullRequestHealthSchema.safeParse(envelope.signal)\n if (!signal.success)\n return (\n <PanelFrame panel={panel} envelope={envelope} error>\n <PanelStatus>⚠ Invalid signal</PanelStatus>\n </PanelFrame>\n )\n const presentation = statusPresentation(signal.data.status, 'Healthy')\n const compactFacts = compactPullRequestHealthFacts(signal.data)\n return (\n <PanelFrame panel={panel} envelope={envelope}>\n <PanelStatus status={signal.data.status}>\n {presentation.glyph} {presentation.label}\n </PanelStatus>\n <PanelHint className={styles.fullSummary} title={signal.data.summary}>\n {signal.data.summary}\n </PanelHint>\n <div className={styles.compactFacts} title={compactFacts.title} data-compact-facts>\n <p\n className={`${styles.compactFact} ${styles.compactPrimary}`}\n title={compactFacts.primaryDetail}\n >\n {compactFacts.primary}\n </p>\n <p className={`${styles.compactFact} ${styles.compactSecondary}`}>\n {compactFacts.secondary}\n </p>\n </div>\n {checkedAt && <CheckedAt value={checkedAt} />}\n </PanelFrame>\n )\n}\n","import type { ComponentType } from 'react'\nimport { HttpValuePanel } from './HttpValuePanel.tsx'\nimport { PanelPlaceholder } from './PanelPlaceholder.tsx'\nimport { PipelineAnimationDemoPanel } from './PipelineAnimationDemoPanel.tsx'\nimport { PipelinePanel } from './PipelinePanel.tsx'\nimport { PullRequestHealthPanel } from './PullRequestHealthPanel.tsx'\nimport type { PanelProps } from './panel-props.ts'\n\ntype PanelRendererProps = PanelProps\n\n/** The one client-side dispatch point for panel types. */\nexport const panelRenderers: Record<string, ComponentType<PanelRendererProps>> = {\n 'pipeline-status': PipelinePanel,\n 'pull-request-health': PullRequestHealthPanel,\n 'http-value': HttpValuePanel,\n 'pipeline-animation-demo': PipelineAnimationDemoPanel,\n}\n\nexport function PanelRenderer({ panel, envelope, checkedAt }: PanelRendererProps) {\n const Renderer = panelRenderers[panel.type]\n return Renderer ? (\n <Renderer panel={panel} envelope={envelope} checkedAt={checkedAt} />\n ) : (\n <PanelPlaceholder label={panel.type} hint=\"Not wired yet\" wide />\n )\n}\n","import { type ClientEnv, clientIdentitySchema } from '@ze-great-dashboard/shared'\nimport { useEffect } from 'react'\nimport type { DiagnosticSink } from './diagnostics.ts'\n\nconst clientUpdateIntervalMillis = 60_000\nconst clientUpdateTimeoutMillis = 10_000\nconst defaultReload = () => globalThis.window.location.reload()\n\nexport function useClientUpdate({\n env,\n diagnostics,\n fetcher,\n reload = defaultReload,\n}: {\n env: ClientEnv\n diagnostics: DiagnosticSink\n fetcher?: typeof fetch\n reload?: () => void\n}) {\n useEffect(() => {\n let cancelled = false\n let inFlight = false\n let activeController: AbortController | undefined\n const path = `${env.proxyPath}/client`\n\n const check = async () => {\n if (cancelled || inFlight) return\n inFlight = true\n const controller = new AbortController()\n activeController = controller\n const timeout = globalThis.setTimeout(() => controller.abort(), clientUpdateTimeoutMillis)\n diagnostics.record({ kind: 'client-update-check', path })\n try {\n const response = await (fetcher ?? globalThis.fetch)(path, {\n cache: 'no-store',\n signal: controller.signal,\n })\n if (!response.ok) throw new Error(`Client identity returned ${response.status}`)\n const parsed = clientIdentitySchema.safeParse(await response.json())\n if (!parsed.success) throw new Error('Client identity response was invalid')\n if (cancelled) return\n // assetPath is the server's immutable deployment selector. clientVersion is a label and\n // can change independently without changing the code the browser should load.\n if (parsed.data.assetPath !== env.assetPath) {\n diagnostics.record({\n kind: 'client-update-detected',\n path,\n current: { assetPath: env.assetPath, clientVersion: env.clientVersion },\n next: parsed.data,\n })\n reload()\n }\n } catch (error) {\n if (!cancelled && !(error instanceof DOMException && error.name === 'AbortError')) {\n diagnostics.record({\n kind: 'client-update-failure',\n path,\n message: error instanceof Error ? error.message : String(error),\n })\n }\n } finally {\n globalThis.clearTimeout(timeout)\n inFlight = false\n if (activeController === controller) activeController = undefined\n if (!cancelled) globalThis.setTimeout(() => void check(), clientUpdateIntervalMillis)\n }\n }\n\n void check()\n return () => {\n cancelled = true\n activeController?.abort()\n }\n }, [diagnostics, env.assetPath, env.clientVersion, env.proxyPath, fetcher, reload])\n}\n","import {\n type Envelope,\n type Panel,\n pipelineStatusSchema,\n pullRequestHealthSchema,\n} from '@ze-great-dashboard/shared'\nimport type { RenderedPanelDiagnostic } from './diagnostics.ts'\n\n/**\n * The compact public fact a viewer saw. Keep new panel projections here beside their\n * presentation boundary; this is intentionally not a source or server event contract.\n */\nexport function projectPanelDiagnostic(panel: Panel, envelope: Envelope): RenderedPanelDiagnostic {\n if (envelope.state === 'error') return { state: envelope.state, link: envelope.link }\n\n if (panel.type === 'pipeline-status') {\n const signal = pipelineStatusSchema.safeParse(envelope.signal)\n return {\n state: envelope.state,\n status: signal.success ? signal.data.status : undefined,\n link: envelope.link,\n }\n }\n\n if (panel.type === 'pull-request-health') {\n const signal = pullRequestHealthSchema.safeParse(envelope.signal)\n return {\n state: envelope.state,\n status: signal.success ? signal.data.status : undefined,\n link: envelope.link,\n }\n }\n\n return { state: envelope.state, link: envelope.link }\n}\n\nexport function panelDiagnosticChanged(\n previous: Envelope | undefined,\n panel: Panel,\n next: Envelope,\n) {\n if (!previous) return true\n const before = projectPanelDiagnostic(panel, previous)\n const after = projectPanelDiagnostic(panel, next)\n return (\n before.state !== after.state || before.status !== after.status || before.link !== after.link\n )\n}\n","import type { Panel, PipelineStatus } from '@ze-great-dashboard/shared'\nimport { browserLocalStorage, readBrowserJson, writeBrowserJson } from './browser-storage.ts'\n\nconst storageKey = 'ze-great-dashboard.panel-memory.v1'\nconst schemaVersion = 1\nconst historyWindowMillis = 14 * 24 * 60 * 60 * 1_000\n\nexport type PanelMemoryIdentity = {\n board: string\n panelId: string\n source: string\n workflow: string\n branch: string\n}\n\nexport type AcceptedPipeline = {\n sourceUpdatedAt: string\n status: PipelineStatus['status']\n link: string | null\n}\n\nexport type DurationSample = {\n link: string | null\n sourceRunId?: string\n durationMs: number\n sourceUpdatedAt: string\n}\ntype History = {\n latest?: AcceptedPipeline\n durations: Record<string, DurationSample>\n latestCompleted?: DurationSample\n}\ntype StoredMemory = { schemaVersion: number; histories: Record<string, History> }\ntype StorageLike = Pick<Storage, 'getItem' | 'setItem'>\n\nexport class BrowserPanelMemory {\n private histories: Record<string, History>\n private readonly storage: StorageLike | undefined\n\n constructor(\n storage: StorageLike | undefined = browserLocalStorage(),\n private readonly now: () => Date = () => new Date(),\n ) {\n this.storage = storage\n this.histories = this.read()\n this.pruneAll()\n }\n\n latest(identity: PanelMemoryIdentity): AcceptedPipeline | undefined {\n return this.history(identity).latest\n }\n\n rememberLatest(identity: PanelMemoryIdentity, latest: AcceptedPipeline) {\n this.history(identity).latest = latest\n this.persist()\n }\n\n recordRun(identity: PanelMemoryIdentity, sample: DurationSample, successful = false) {\n const history = this.history(identity)\n if (successful) history.durations[sampleKey(sample)] = sample\n const previous = history.latestCompleted\n if (!previous || isAtLeastAsRecent(sample.sourceUpdatedAt, previous.sourceUpdatedAt)) {\n history.latestCompleted = sample\n }\n this.pruneHistory(history)\n this.persist()\n }\n\n recordSuccessfulRun(identity: PanelMemoryIdentity, sample: DurationSample) {\n this.recordRun(identity, sample, true)\n }\n\n recordCompletedRun(identity: PanelMemoryIdentity, sample: DurationSample) {\n this.recordRun(identity, sample)\n }\n\n medianDuration(identity: PanelMemoryIdentity): number | undefined {\n const history = this.history(identity)\n this.pruneHistory(history)\n const durations = Object.values(history.durations)\n .map(({ durationMs }) => durationMs)\n .sort((left, right) => left - right)\n if (durations.length === 0) return undefined\n const middle = Math.floor(durations.length / 2)\n if (durations.length % 2 === 1) return durations[middle]\n const lower = durations[middle - 1]\n const upper = durations[middle]\n return lower === undefined || upper === undefined ? undefined : Math.floor((lower + upper) / 2)\n }\n\n resolveEstimatedDuration(identity: PanelMemoryIdentity): number | undefined {\n const successful = this.medianDuration(identity)\n if (successful !== undefined) return successful\n\n const history = this.history(identity)\n this.pruneHistory(history)\n return history.latestCompleted?.durationMs\n }\n\n private history(identity: PanelMemoryIdentity) {\n const key = identityKey(identity)\n const existing = this.histories[key]\n if (existing) return existing\n const created: History = { durations: {} }\n this.histories[key] = created\n return created\n }\n\n private pruneAll() {\n for (const history of Object.values(this.histories)) this.pruneHistory(history)\n this.persist()\n }\n\n private pruneHistory(history: History) {\n const cutoff = this.now().valueOf() - historyWindowMillis\n for (const [link, sample] of Object.entries(history.durations)) {\n const at = sourceTimestamp(sample.sourceUpdatedAt)\n if (at === undefined || at < cutoff) delete history.durations[link]\n }\n const latestCompletedAt = history.latestCompleted\n ? sourceTimestamp(history.latestCompleted.sourceUpdatedAt)\n : undefined\n if (\n history.latestCompleted &&\n (latestCompletedAt === undefined || latestCompletedAt < cutoff)\n ) {\n delete history.latestCompleted\n }\n }\n\n private read(): Record<string, History> {\n const parsed = readBrowserJson<Partial<StoredMemory>>(this.storage, storageKey)\n if (parsed?.schemaVersion !== schemaVersion || !parsed.histories) return {}\n return isHistories(parsed.histories) ? parsed.histories : {}\n }\n\n private persist() {\n writeBrowserJson(this.storage, storageKey, { schemaVersion, histories: this.histories })\n }\n}\n\nfunction sampleKey(sample: DurationSample) {\n return sample.sourceRunId ?? sample.link ?? sample.sourceUpdatedAt\n}\n\nfunction isAtLeastAsRecent(left: string, right: string) {\n const leftAt = sourceTimestamp(left)\n const rightAt = sourceTimestamp(right)\n return leftAt !== undefined && (rightAt === undefined || leftAt >= rightAt)\n}\n\nfunction sourceTimestamp(value: string) {\n const timestamp = Date.parse(value)\n return Number.isFinite(timestamp) ? timestamp : undefined\n}\n\nexport function resolvePanelMemoryIdentity(board: string, panel: Panel): PanelMemoryIdentity {\n return {\n board,\n panelId: panel.id,\n source: panel.source ?? '',\n workflow:\n typeof panel.pipeline === 'string' || typeof panel.pipeline === 'number'\n ? String(panel.pipeline)\n : '',\n branch: panel.branch ?? '',\n }\n}\n\nfunction identityKey(identity: PanelMemoryIdentity) {\n return JSON.stringify([\n identity.board,\n identity.panelId,\n identity.source,\n identity.workflow,\n identity.branch,\n ])\n}\n\nfunction isHistories(value: unknown): value is Record<string, History> {\n if (!isRecord(value)) return false\n return Object.values(value).every(isHistory)\n}\n\nfunction isHistory(value: unknown): value is History {\n if (!isRecord(value) || !isRecord(value.durations)) return false\n if (!Object.values(value.durations).every(isDurationSample)) return false\n return value.latestCompleted === undefined || isDurationSample(value.latestCompleted)\n}\n\nfunction isDurationSample(value: unknown): value is DurationSample {\n if (!isRecord(value)) return false\n return (\n (typeof value.link === 'string' || value.link === null) &&\n (value.sourceRunId === undefined || typeof value.sourceRunId === 'string') &&\n typeof value.durationMs === 'number' &&\n Number.isInteger(value.durationMs) &&\n value.durationMs >= 0 &&\n typeof value.sourceUpdatedAt === 'string' &&\n sourceTimestamp(value.sourceUpdatedAt) !== undefined\n )\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return !!value && typeof value === 'object' && !Array.isArray(value)\n}\n","import type { Envelope, PipelineStatus } from '@ze-great-dashboard/shared'\nimport { pipelineStatusSchema } from '@ze-great-dashboard/shared'\nimport type { AcceptedPipeline } from './panel-memory.ts'\n\nexport type PipelineDurationSample = {\n link: string | null\n sourceRunId?: string\n durationMs: number\n sourceUpdatedAt: string\n}\n\nexport type PipelineReconciliation =\n | { kind: 'not-pipeline'; envelope: Envelope }\n | {\n kind: 'rejected'\n envelope: Extract<Envelope, { state: 'ok' }>\n signal: PipelineStatus & { sourceUpdatedAt: string }\n }\n | {\n kind: 'accepted'\n envelope: Envelope\n signal: PipelineStatus\n accepted?: AcceptedPipeline\n durationSample?: PipelineDurationSample\n }\n\nexport function reconcilePipelineResponse(args: {\n envelope: Envelope\n accepted?: AcceptedPipeline\n estimatedDurationMs?: number\n}): PipelineReconciliation {\n const signal = pipelineStatus(args.envelope)\n if (!signal) return { kind: 'not-pipeline', envelope: args.envelope }\n if (\n args.accepted &&\n signal.sourceUpdatedAt &&\n Date.parse(signal.sourceUpdatedAt) < Date.parse(args.accepted.sourceUpdatedAt)\n ) {\n if (args.envelope.state !== 'ok' || !signal.sourceUpdatedAt)\n return { kind: 'not-pipeline', envelope: args.envelope }\n return {\n kind: 'rejected',\n envelope: args.envelope,\n signal: { ...signal, sourceUpdatedAt: signal.sourceUpdatedAt },\n }\n }\n\n const accepted = signal.sourceUpdatedAt\n ? { sourceUpdatedAt: signal.sourceUpdatedAt, status: signal.status, link: args.envelope.link }\n : undefined\n const durationSample =\n signal.status !== 'running' &&\n signal.durationMs !== undefined &&\n signal.sourceUpdatedAt &&\n Number.isFinite(Date.parse(signal.sourceUpdatedAt))\n ? {\n link: args.envelope.link,\n ...(signal.sourceRunId ? { sourceRunId: signal.sourceRunId } : {}),\n durationMs: signal.durationMs,\n sourceUpdatedAt: signal.sourceUpdatedAt,\n }\n : undefined\n const envelope =\n signal.status === 'running' &&\n args.estimatedDurationMs !== undefined &&\n args.envelope.state === 'ok'\n ? { ...args.envelope, signal: { ...signal, estimatedDurationMs: args.estimatedDurationMs } }\n : args.envelope\n return { kind: 'accepted', envelope, signal, accepted, durationSample }\n}\n\nexport function pipelineStatus(envelope: Envelope): PipelineStatus | undefined {\n if (envelope.state !== 'ok') return undefined\n const result = pipelineStatusSchema.safeParse(envelope.signal)\n return result.success ? result.data : undefined\n}\n","import {\n type Envelope,\n type PipelineStatus,\n type PollingSettings,\n pipelineStatusSchema,\n} from '@ze-great-dashboard/shared'\n\n/** Return the next delay for a panel, keeping active runs responsive without polling forever at burst speed. */\nexport function nextPollDelayMillis(\n envelope: Envelope | undefined,\n nowMillis: number,\n settings: PollingSettings,\n): number {\n const pipeline = runningPipeline(envelope)\n if (!pipeline) return settings.refreshMillis\n\n const completionAt = estimatedCompletionAt(pipeline)\n if (completionAt === undefined) return settings.runningRefreshMillis\n\n if (nowMillis < completionAt) {\n return Math.min(settings.runningRefreshMillis, completionAt - nowMillis)\n }\n if (nowMillis < completionAt + settings.runningCompletionWindowMillis) {\n return settings.runningCompletionRefreshMillis\n }\n return settings.runningRefreshMillis\n}\n\nfunction runningPipeline(envelope: Envelope | undefined): PipelineStatus | undefined {\n if (envelope?.state !== 'ok') return undefined\n const result = pipelineStatusSchema.safeParse(envelope.signal)\n return result.success && result.data.status === 'running' ? result.data : undefined\n}\n\nfunction estimatedCompletionAt(signal: PipelineStatus): number | undefined {\n if (!signal.runStartedAt || signal.estimatedDurationMs === undefined) return undefined\n const startedAt = Date.parse(signal.runStartedAt)\n return Number.isFinite(startedAt) ? startedAt + signal.estimatedDurationMs : undefined\n}\n","import {\n type Board,\n type ClientEnv,\n type Envelope,\n envelopeSchema,\n isZeroPosition,\n resolvePollingSettings,\n} from '@ze-great-dashboard/shared'\nimport { useEffect, useRef, useState } from 'react'\nimport { cacheMetadata, type DiagnosticSink } from './diagnostics.ts'\nimport { panelDiagnosticChanged, projectPanelDiagnostic } from './panel-diagnostics.ts'\nimport { BrowserPanelMemory, resolvePanelMemoryIdentity } from './panel-memory.ts'\nimport { reconcilePipelineResponse } from './pipeline-reconciliation.ts'\nimport { nextPollDelayMillis } from './polling-schedule.ts'\n\nexport function usePanelSignals({\n board,\n env,\n diagnostics,\n memory,\n}: {\n board: Board | undefined\n env: ClientEnv\n diagnostics: DiagnosticSink\n memory?: BrowserPanelMemory\n}) {\n const [signals, setSignals] = useState<Record<string, Envelope | undefined>>({})\n const [checkedAt, setCheckedAt] = useState<Record<string, string | undefined>>({})\n const signalsRef = useRef<Record<string, Envelope | undefined>>({})\n const memoryRef = useRef<BrowserPanelMemory | null>(null)\n if (!memoryRef.current) memoryRef.current = memory ?? new BrowserPanelMemory()\n\n useEffect(() => {\n signalsRef.current = {}\n setSignals({})\n setCheckedAt({})\n if (!board) return\n\n let cancelled = false\n const timers = new Set<number>()\n for (const panel of board.panels) {\n if (isZeroPosition(panel.position)) continue\n if (\n panel.type !== 'pipeline-status' &&\n panel.type !== 'pull-request-health' &&\n panel.type !== 'http-value'\n )\n continue\n let inFlight = false\n const memory = memoryRef.current\n if (!memory) return\n const settings = resolvePollingSettings(board, panel)\n const path = `${env.proxyPath}/panel/${encodeURIComponent(env.board)}/${encodeURIComponent(panel.id)}`\n let lastEnvelope: Envelope | undefined\n const refresh = () => {\n if (cancelled || inFlight) return\n inFlight = true\n diagnostics.record({ kind: 'panel-fetch-start', panelId: panel.id, path })\n fetch(path)\n .then(async (response) => {\n if (!cancelled) {\n setCheckedAt((current) => ({\n ...current,\n [panel.id]: new Date().toISOString(),\n }))\n }\n const transport = {\n kind: 'panel-fetch-response' as const,\n panelId: panel.id,\n path,\n status: response.status,\n cache: cacheMetadata(response.headers),\n }\n if (response.status === 304) {\n diagnostics.record(transport)\n return undefined\n }\n try {\n const value: unknown = await response.json()\n const envelope = parseEnvelope(value)\n if (!envelope) {\n diagnostics.record(transport)\n diagnostics.record({\n kind: 'panel-fetch-parse-failure',\n panelId: panel.id,\n path,\n message: 'Response was not a valid signal envelope.',\n })\n return undefined\n }\n diagnostics.record({ ...transport, envelope })\n return { envelope, cache: transport.cache, status: response.status }\n } catch (error) {\n diagnostics.record(transport)\n diagnostics.record({\n kind: 'panel-fetch-parse-failure',\n panelId: panel.id,\n path,\n message: errorMessage(error),\n })\n throw new DiagnosticParseFailure(error)\n }\n })\n .then((result) => {\n if (!result) return\n let envelope = result.envelope\n if (panel.type === 'pipeline-status') {\n const identity = resolvePanelMemoryIdentity(env.board, panel)\n const accepted = memory.latest(identity)\n const reconciliation = reconcilePipelineResponse({\n envelope,\n accepted,\n estimatedDurationMs: memory.resolveEstimatedDuration(identity),\n })\n if (reconciliation.kind === 'rejected' && accepted) {\n const signal = reconciliation.signal\n diagnostics.recordGithubConsistencyIncident({\n panelId: panel.id,\n endpoint: path,\n identity: {\n source: identity.source,\n workflow: identity.workflow,\n branch: identity.branch,\n },\n accepted,\n regressed: {\n sourceUpdatedAt: signal.sourceUpdatedAt,\n status: signal.status,\n link: envelope.link,\n },\n response: {\n httpStatus: result.status,\n date: result.cache?.date,\n etag: result.cache?.etag,\n cacheControl: result.cache?.cacheControl,\n },\n })\n return\n }\n if (reconciliation.kind === 'accepted') {\n envelope = reconciliation.envelope\n if (reconciliation.accepted)\n memory.rememberLatest(identity, reconciliation.accepted)\n if (reconciliation.durationSample) {\n const sample = {\n link: reconciliation.durationSample.link,\n ...(reconciliation.durationSample.sourceRunId\n ? { sourceRunId: reconciliation.durationSample.sourceRunId }\n : {}),\n durationMs: reconciliation.durationSample.durationMs,\n sourceUpdatedAt: reconciliation.durationSample.sourceUpdatedAt,\n }\n memory.recordRun(identity, sample, reconciliation.signal.status === 'passed')\n }\n }\n }\n lastEnvelope = envelope\n if (!cancelled) {\n const previous = signalsRef.current[panel.id]\n if (panelDiagnosticChanged(previous, panel, envelope)) {\n diagnostics.record({\n kind: 'panel-rendered',\n panelId: panel.id,\n path,\n rendered: projectPanelDiagnostic(panel, envelope),\n })\n }\n signalsRef.current = { ...signalsRef.current, [panel.id]: envelope }\n setSignals(signalsRef.current)\n }\n })\n .catch((error) => {\n if (!(error instanceof DiagnosticParseFailure)) {\n diagnostics.record({\n kind: 'panel-fetch-failure',\n panelId: panel.id,\n path,\n message: errorMessage(error),\n })\n }\n })\n .finally(() => {\n inFlight = false\n if (!cancelled) {\n const nextTimer = window.setTimeout(\n () => {\n timers.delete(nextTimer)\n refresh()\n },\n nextPollDelayMillis(lastEnvelope, Date.now(), settings),\n )\n timers.add(nextTimer)\n }\n })\n }\n refresh()\n }\n return () => {\n cancelled = true\n for (const timer of timers) window.clearTimeout(timer)\n }\n }, [board, diagnostics, env.board, env.proxyPath])\n\n return { signals, checkedAt }\n}\n\nfunction errorMessage(error: unknown) {\n return error instanceof Error ? error.message : String(error)\n}\n\nclass DiagnosticParseFailure extends Error {\n constructor(error: unknown) {\n super(errorMessage(error))\n }\n}\n\nfunction parseEnvelope(value: unknown): Envelope | undefined {\n const result = envelopeSchema.safeParse(value)\n return result.success ? result.data : undefined\n}\n","import {\n analyzeBoardLayout,\n type Board,\n type ClientEnv,\n isZeroPosition,\n} from '@ze-great-dashboard/shared'\nimport { useEffect, useMemo, useRef, useState } from 'react'\nimport styles from './App.module.css'\nimport { Diagnostics } from './Diagnostics.tsx'\nimport { BrowserDiagnosticStore, cacheMetadata } from './diagnostics.ts'\nimport { PanelPlaceholder } from './PanelPlaceholder.tsx'\nimport { PanelRenderer } from './panel-registry.tsx'\nimport { useClientUpdate } from './useClientUpdate.ts'\nimport { usePanelSignals } from './usePanelSignals.ts'\n\n/**\n * The board shell.\n *\n * Stage 1 has no data: there is no proxy endpoint to poll yet. What this proves is the plumbing —\n * that the client was handed its configuration by the server and knows which version of itself it\n * is. The version readout is what makes two published versions visibly different, which is the\n * whole point of the Stage 1 exit criterion.\n */\nexport function App({ env }: { env: ClientEnv }) {\n const [board, setBoard] = useState<Board>()\n const [loadedBoardName, setLoadedBoardName] = useState<string>()\n const diagnosticsRef = useRef<BrowserDiagnosticStore | null>(null)\n if (!diagnosticsRef.current) diagnosticsRef.current = new BrowserDiagnosticStore(env)\n const diagnostics = diagnosticsRef.current\n useClientUpdate({ env, diagnostics })\n const { signals, checkedAt } = usePanelSignals({\n board: loadedBoardName === env.board ? board : undefined,\n env,\n diagnostics,\n })\n const layout = useMemo(() => (board ? analyzeBoardLayout(board.panels) : undefined), [board])\n\n useEffect(() => {\n if (!layout || layout.issues.length === 0) return\n diagnostics.record({\n kind: 'layout-analyzed',\n issueCount: layout.issues.length,\n affectedPanelIds: layout.issues.map((issue) => issue.panelId),\n })\n }, [diagnostics, layout])\n\n useEffect(() => {\n let cancelled = false\n setBoard(undefined)\n setLoadedBoardName(undefined)\n const path = `${env.proxyPath}/boards/${encodeURIComponent(env.board)}`\n diagnostics.record({ kind: 'board-fetch-start', path })\n fetch(path)\n .then(async (response) => {\n diagnostics.record({\n kind: 'board-fetch-response',\n path,\n status: response.status,\n cache: cacheMetadata(response.headers),\n })\n if (!response.ok) throw new Error(`Board configuration returned ${response.status}`)\n try {\n return await response.json()\n } catch (error) {\n diagnostics.record({\n kind: 'board-fetch-parse-failure',\n path,\n message: errorMessage(error),\n })\n throw new DiagnosticParseFailure(error)\n }\n })\n .then((value: unknown) => {\n if (!cancelled) {\n setBoard(value as Board)\n setLoadedBoardName(env.board)\n const panels = Array.isArray((value as { panels?: unknown }).panels)\n ? (value as { panels: Array<{ id?: unknown }> }).panels\n : []\n diagnostics.record({\n kind: 'board-fetch-response',\n path,\n boardSummary: {\n panelCount: panels.length,\n panelIds: panels.flatMap((panel) => (typeof panel.id === 'string' ? [panel.id] : [])),\n },\n })\n }\n })\n .catch((error) => {\n if (!(error instanceof DiagnosticParseFailure)) {\n diagnostics.record({ kind: 'board-fetch-failure', path, message: errorMessage(error) })\n }\n if (!cancelled) {\n setBoard({ panels: [] })\n setLoadedBoardName(env.board)\n }\n })\n return () => {\n cancelled = true\n }\n }, [diagnostics, env.board, env.proxyPath])\n\n return (\n <div className={styles.board}>\n <header className={styles.header}>\n <h1 className={styles.title}>{env.board}</h1>\n </header>\n <main className={styles.grid}>\n {!board && <PanelPlaceholder label=\"board\" hint=\"Loading configuration…\" wide />}\n {board?.panels\n .filter((panel) => !isZeroPosition(panel.position))\n .map((panel) => (\n <PanelRenderer\n key={panel.id}\n panel={panel}\n envelope={signals[panel.id]}\n checkedAt={checkedAt[panel.id]}\n />\n ))}\n </main>\n\n <footer className={styles.footer} data-board-footer>\n <span>Signals are read live from their configured authorities.</span>\n <div className={styles.footerTools}>\n {layout && layout.issues.length > 0 && (\n <LayoutWarning board={env.board} layout={layout} proxyPath={env.proxyPath} />\n )}\n <Diagnostics log={diagnostics} />\n </div>\n </footer>\n </div>\n )\n}\n\nfunction LayoutWarning({\n board,\n layout,\n proxyPath,\n}: {\n board: string\n layout: ReturnType<typeof analyzeBoardLayout>\n proxyPath: string\n}) {\n const [open, setOpen] = useState(false)\n const dialogId = `layout-warning-${board}`\n\n useEffect(() => {\n if (!open) return\n const closeOnEscape = (event: KeyboardEvent) => {\n if (event.key === 'Escape') setOpen(false)\n }\n window.addEventListener('keydown', closeOnEscape)\n return () => window.removeEventListener('keydown', closeOnEscape)\n }, [open])\n\n const boardPath = `${proxyPath}/boards/${encodeURIComponent(board)}`\n return (\n <div className={styles.layoutWarning} data-layout-warning>\n <button\n className={styles.layoutWarningButton}\n type=\"button\"\n aria-label={`Layout warnings (${layout.issues.length})`}\n aria-expanded={open}\n aria-controls={dialogId}\n onClick={() => setOpen(!open)}\n >\n <span aria-hidden=\"true\">⚠</span>\n <span>{layout.issues.length}</span>\n </button>\n {open && (\n <aside\n className={styles.layoutWarningDialog}\n id={dialogId}\n role=\"dialog\"\n aria-labelledby={`${dialogId}-title`}\n aria-modal=\"false\"\n >\n <div className={styles.layoutWarningHeading}>\n <strong id={`${dialogId}-title`}>Layout warnings</strong>\n <button\n className={styles.layoutWarningClose}\n type=\"button\"\n aria-label=\"Close layout warnings\"\n onClick={() => setOpen(false)}\n >\n ×\n </button>\n </div>\n <p>\n {layout.issues.length} layout issue{layout.issues.length === 1 ? '' : 's'} detected\n against the intended 12×12 space. The live board is unchanged: explicit overlaps remain\n overlapped and overflow continues in implicit rows.\n </p>\n <ul>\n {layout.issues.map((issue) => (\n <li key={`${issue.panelId}-${issue.kind}`}>\n <strong>{issue.panelId}</strong>: {issue.kind} at ({issue.position.x},{' '}\n {issue.position.y}), {issue.position.w}×{issue.position.h}\n {issue.conflictsWith.length ? `; overlaps ${issue.conflictsWith.join(', ')}` : ''}\n </li>\n ))}\n </ul>\n <div className={styles.layoutWarningDownloads}>\n <a href={`${boardPath}/rendered`} download={`${board}-layout-rendered.yaml`}>\n Download legal rendered layout\n </a>\n <a href={`${boardPath}/authored`} download={`${board}-layout-authored.yaml`}>\n Download authored layout\n </a>\n </div>\n <p className={styles.layoutWarningNote}>\n The legal rendered layout normalizes the currently visible explicit area into 12×12 and\n makes the smallest deterministic adjustments needed to avoid collisions. The authored\n layout preserves the original coordinates exactly.\n </p>\n </aside>\n )}\n </div>\n )\n}\n\nfunction errorMessage(error: unknown) {\n return error instanceof Error ? error.message : String(error)\n}\n\nclass DiagnosticParseFailure extends Error {\n constructor(error: unknown) {\n super(errorMessage(error))\n }\n}\n",".error {\n margin: 0 auto;\n max-width: 60ch;\n padding: 2rem;\n color: var(--ink-primary);\n}\n.error pre {\n padding: 1rem;\n border-radius: var(--radius);\n border: 1px solid var(--status-critical);\n background: var(--surface-raised);\n color: var(--ink-secondary);\n font-size: 0.75em;\n white-space: pre-wrap;\n overflow-wrap: anywhere;\n}\n","import styles from './ConfigError.module.css'\n\nexport function ConfigError({ message }: { message: string }) {\n return (\n <div className={styles.error} role=\"alert\">\n <h1>⚠️ Dashboard misconfigured</h1>\n <p>The page loaded, but the server did not hand it usable configuration.</p>\n <pre>{message}</pre>\n </div>\n )\n}\n","import { readClientEnv } from '@ze-great-dashboard/shared'\nimport { StrictMode } from 'react'\nimport { createRoot } from 'react-dom/client'\nimport { App } from './App.tsx'\nimport { ConfigError } from './ConfigError.tsx'\nimport './styles.css'\n\nconst container = document.getElementById('root')\nif (!container) {\n throw new Error('No #root element in the document — the template is not the one we expect.')\n}\n\nconst root = createRoot(container)\n\ntry {\n root.render(\n <StrictMode>\n <App env={readClientEnv()} />\n </StrictMode>,\n )\n} catch (error) {\n // A radiator that fails silently is worse than one that says what's wrong. If configuration\n // never arrived, say so on screen rather than rendering an empty board.\n root.render(<ConfigError message={error instanceof Error ? error.message : String(error)} />)\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index-CJ25jkMk.js","names":[],"sources":["../../../shared/dist/index.js","../../src/App.module.css","../../src/Diagnostics.module.css","../../src/Diagnostics.tsx","../../src/browser-storage.ts","../../src/diagnostics-summary.ts","../../src/diagnostics.ts","../../src/PanelFrame.module.css","../../src/PanelPlaceholder.tsx","../../src/HttpValuePanel.module.css","../../src/panel-layout.ts","../../src/PanelFrame.tsx","../../src/TimeAge.tsx","../../src/HttpValuePanel.tsx","../../src/falling-shapes.ts","../../src/PipelineAnimationDemoPanel.module.css","../../src/FallingShapesField.module.css","../../src/FallingShapesField.tsx","../../src/ReleaseTransitField.module.css","../../src/ReleaseTransitField.tsx","../../src/RunningField.module.css","../../src/StatusWeatherField.module.css","../../src/StatusWeatherField.tsx","../../src/PhasedProgressMarker.module.css","../../src/PhasedProgressMarker.tsx","../../src/TelemetryBloomField.module.css","../../src/TelemetryBloomField.tsx","../../src/RunningField.tsx","../../src/running-timing.ts","../../src/RunningFieldTiming.tsx","../../src/RunningProgress.module.css","../../src/RunningProgress.tsx","../../src/PipelineAnimationDemoPanel.tsx","../../src/PipelinePanel.module.css","../../src/panel-status.ts","../../src/pipeline-activity.ts","../../src/PipelinePanel.tsx","../../src/PullRequestHealthPanel.module.css","../../src/panel-formatting.ts","../../src/pull-request-health.ts","../../src/PullRequestHealthPanel.tsx","../../src/panel-registry.tsx","../../src/useClientUpdate.ts","../../src/panel-diagnostics.ts","../../src/panel-memory.ts","../../src/pipeline-reconciliation.ts","../../src/polling-schedule.ts","../../src/usePanelSignals.ts","../../src/App.tsx","../../src/ConfigError.module.css","../../src/ConfigError.tsx","../../src/main.tsx"],"sourcesContent":["// packages/shared/src/board-config.ts\nimport { z as z2 } from \"zod\";\n\n// packages/shared/src/duration.ts\nimport { z } from \"zod\";\nvar DURATION_PATTERN = /^(\\d+)(ms|s|m|h)$/;\nvar UNIT_MILLIS = {\n ms: 1,\n s: 1e3,\n m: 6e4,\n h: 36e5\n};\nfunction parseDuration(value) {\n const match = DURATION_PATTERN.exec(value);\n if (!match) return null;\n const [, rawAmount, rawUnit] = match;\n if (rawAmount === void 0 || rawUnit === void 0) return null;\n const amount = Number(rawAmount);\n if (amount <= 0) return null;\n return amount * UNIT_MILLIS[rawUnit];\n}\nvar durationSchema = z.string().refine((value) => parseDuration(value) !== null, {\n message: 'must be a positive duration like \"30s\", \"5m\", or \"1h\"'\n}).brand();\n\n// packages/shared/src/board-config.ts\nvar positionSchema = z2.union([\n z2.object({\n x: z2.number().int().min(0),\n y: z2.number().int().min(0),\n w: z2.number().int().min(1).max(12),\n h: z2.number().int().min(1)\n }),\n z2.object({ x: z2.literal(0), y: z2.literal(0), w: z2.literal(0), h: z2.literal(0) })\n]);\nvar panelDensities = [\"auto\", \"comfortable\", \"compact\"];\nvar panelDensitySchema = z2.enum(panelDensities);\nvar visibleRunningAnimations = [\n \"radial\",\n \"runway\",\n \"orbit\",\n \"signal-field\",\n \"telemetry-bloom\",\n \"release-transit\",\n \"status-weather\",\n \"falling-shapes\"\n];\nvar runningAnimationSchema = z2.enum([...visibleRunningAnimations, \"off\"]);\nvar panelSchema = z2.looseObject({\n /** Presentation-only wall label. `id` remains the stable proxy and allowlist address. */\n label: z2.string().min(1).optional(),\n id: z2.string().min(1),\n type: z2.string().min(1),\n source: z2.string().min(1).optional(),\n pipeline: z2.union([z2.string(), z2.number()]).optional(),\n /** Resolved public source branch, supplied by the board endpoint for client memory scoping. */\n branch: z2.string().min(1).optional(),\n /** Content-density bias; position still controls the panel's explicit grid placement. */\n density: panelDensitySchema.optional(),\n /** Advisory in v1 — a panel without a position renders in config order rather than not at all. */\n position: positionSchema.optional(),\n refresh: durationSchema.optional(),\n /** Active pipeline runs are checked more often than normal panels. */\n running_refresh: durationSchema.optional(),\n /** Polling cadence around the estimated completion boundary. */\n running_completion_refresh: durationSchema.optional(),\n /** Maximum length of the tighter completion polling burst. */\n running_completion_window: durationSchema.optional(),\n /** Optional active-run treatment. Omitted selects a visible treatment at random. */\n running_animation: runningAnimationSchema.optional(),\n /** Local animation-demo cycle duration; ignored by other panel types. */\n demo_run_duration: durationSchema.optional(),\n /** Local animation-demo focused-review duration; ignored by other panel types. */\n demo_review_duration: durationSchema.optional(),\n /** A deliberate override only. Adapters derive links; hand-written ones drift. */\n link: z2.url().optional(),\n /** Source-agnostic endpoint used by the http-value signal. */\n url: z2.url().optional(),\n /** Small, deliberate JSON path subset: $.version, $.deployment.version, or $.response.docs[0].latestVersion. */\n json_path: z2.string().regex(/^\\$(?:\\.[A-Za-z_][A-Za-z0-9_]*|\\[\\d+\\])*$/, \"must be a simple JSON path\").optional()\n}).superRefine((panel, ctx) => {\n if (\"display\" in panel) {\n ctx.addIssue({\n code: \"custom\",\n path: [\"display\"],\n message: \"display was removed; use density\"\n });\n }\n});\nvar githubAppSchema = z2.object({\n app_id_env: z2.string().min(1),\n private_key_env: z2.string().min(1),\n installation_id_env: z2.string().min(1)\n});\nvar sourceAuthenticationSchema = {\n /** Credentials are never in the config — only the name of the env var holding one. */\n token_env: z2.string().min(1).optional(),\n github_app: githubAppSchema.optional()\n};\nfunction exactlyOneGithubAuthenticationMode(source, ctx) {\n if (source.token_env && source.github_app)\n ctx.addIssue({ code: \"custom\", message: \"configure token_env or github_app, not both\" });\n}\nvar githubActionsSourceSchema = z2.looseObject({\n type: z2.literal(\"github-actions\"),\n repo: z2.string().regex(/^[^/\\s]+\\/[^/\\s]+$/, \"must be an owner/repository pair\"),\n /** The branch whose workflow health the dashboard represents. */\n branch: z2.string().min(1).optional(),\n ...sourceAuthenticationSchema\n}).superRefine(exactlyOneGithubAuthenticationMode);\nvar sourceSchema = z2.looseObject({ type: z2.string().min(1), ...sourceAuthenticationSchema }).superRefine(exactlyOneGithubAuthenticationMode);\nfunction credentialEnvironmentNames(source) {\n return [\n ...source.token_env ? [source.token_env] : [],\n ...source.github_app ? [\n source.github_app.app_id_env,\n source.github_app.private_key_env,\n source.github_app.installation_id_env\n ] : []\n ];\n}\nvar boardSchema = z2.object({\n refresh: durationSchema.optional(),\n running_refresh: durationSchema.optional(),\n running_completion_refresh: durationSchema.optional(),\n running_completion_window: durationSchema.optional(),\n panels: z2.array(panelSchema).min(1).superRefine((panels, ctx) => {\n const seen = /* @__PURE__ */ new Map();\n panels.forEach((panel, index) => {\n const firstIndex = seen.get(panel.id);\n if (firstIndex === void 0) {\n seen.set(panel.id, index);\n return;\n }\n ctx.addIssue({\n code: \"custom\",\n path: [index, \"id\"],\n message: `duplicate panel id \"${panel.id}\" (already used by panel at index ${firstIndex})`\n });\n });\n })\n});\nvar authSchema = z2.object({\n issuer: z2.url(),\n /** Absent in gateway mode — the gateway does the flow, the proxy still validates. */\n client_id: z2.string().min(1).optional(),\n allow: z2.object({\n groups: z2.array(z2.string().min(1)).optional(),\n subjects: z2.array(z2.string().min(1)).optional()\n }).optional()\n});\nvar boardConfigSchema = z2.object({\n sources: z2.record(z2.string().min(1), sourceSchema).default({}),\n boards: z2.record(z2.string().min(1), boardSchema),\n auth: authSchema.optional()\n});\nfunction resolveRefreshMillis(args) {\n const requested = args.panelOverrideMillis ?? args.boardDefaultMillis;\n return Math.max(requested, args.adapterFloorMillis);\n}\n\n// packages/shared/src/board-config-modeline.ts\nvar MODEL_LINE = /^# yaml-language-server:\\s*\\$schema=(\\S+)\\s*$/;\nvar SCHEMA_FILE = \"board-config.schema.json\";\nfunction schemaUrlForAssetPath(assetPath) {\n return `${assetPath.replace(/\\/+$/, \"\")}/${SCHEMA_FILE}`;\n}\nfunction readBoardSchemaModeline(source, expectedSchemaUrl) {\n const line = source.split(/\\r?\\n/)[0];\n if (!line?.includes(\"yaml-language-server\"))\n throw new Error(\n `Board configuration must include a ${SCHEMA_FILE} modeline. Add this as the first line:\n# yaml-language-server: $schema=${expectedSchemaUrl ?? `https://<asset-host>/dashboard/<release-version>/${SCHEMA_FILE}`}`\n );\n const match = MODEL_LINE.exec(line);\n if (!match?.[1]) {\n throw new Error(\n `Malformed board schema modeline; expected \"# yaml-language-server: $schema=<URL>/${SCHEMA_FILE}\"`\n );\n }\n let url;\n try {\n url = new URL(match[1]);\n } catch {\n throw new Error(`Malformed board schema modeline; schema URL is not a valid URL: ${match[1]}`);\n }\n if (![\"http:\", \"https:\"].includes(url.protocol) || !url.pathname.endsWith(`/${SCHEMA_FILE}`)) {\n throw new Error(`Malformed board schema modeline; URL must end in /${SCHEMA_FILE}: ${match[1]}`);\n }\n return match[1];\n}\nfunction boardSchemaModeline(url) {\n return `# yaml-language-server: $schema=${url}`;\n}\nvar boardSchemaFileName = SCHEMA_FILE;\n\n// packages/shared/src/client-env.ts\nimport { z as z3 } from \"zod\";\nvar clientEnvSchema = z3.object({\n /** Where the immutable client assets live. The one variable that repoints the whole client. */\n assetPath: z3.string().min(1),\n /** Same-origin path the proxy is mounted at, so there is no CORS and no cookie problem. */\n proxyPath: z3.string().min(1),\n /** Which board this is, resolved server-side so the client parses no URLs. */\n board: z3.string().min(1),\n /** The client version being served, so two published versions are visibly distinguishable. */\n clientVersion: z3.string().min(1),\n /** Omitted entirely when unauthenticated — presence is what turns auth on. */\n auth: z3.object({\n issuer: z3.string().min(1),\n clientId: z3.string().min(1).optional()\n }).optional()\n});\nvar clientIdentitySchema = clientEnvSchema.pick({ assetPath: true, clientVersion: true });\nfunction readClientEnv(source = globalThis.window?.env) {\n const result = clientEnvSchema.safeParse(source);\n if (!result.success) {\n throw new Error(\n `window.env is missing or invalid \\u2014 the server did not inject usable configuration.\n${z3.prettifyError(result.error)}`\n );\n }\n return result.data;\n}\n\n// packages/shared/src/envelope.ts\nimport { z as z4 } from \"zod\";\nvar errorKindSchema = z4.enum([\n \"unreachable\",\n \"unauthorized\",\n \"not-found\",\n \"no-runs\",\n \"upstream-error\"\n]);\nvar envelopeErrorSchema = z4.object({\n kind: errorKindSchema,\n message: z4.string()\n});\nvar envelopeSchema = z4.discriminatedUnion(\"state\", [\n z4.object({\n panelId: z4.string().min(1),\n state: z4.literal(\"ok\"),\n /** From the upstream response `Date`. A cached value must never be shown without its age. */\n observedAt: z4.iso.datetime(),\n /** Adapter-derived. The authority for this panel; the dashboard itself asserts nothing. */\n link: z4.url().nullable(),\n signal: z4.unknown()\n }),\n z4.object({\n panelId: z4.string().min(1),\n state: z4.literal(\"error\"),\n /**\n * Populated even on error: knowing *when* a failure was observed is the difference between\n * \"broken just now\" and \"broken all morning\", and a panel that can't reach its source is\n * exactly when a viewer most wants to click through.\n */\n observedAt: z4.iso.datetime(),\n link: z4.url().nullable(),\n error: envelopeErrorSchema\n })\n]);\nvar pipelineActivitySchema = z4.object({\n kind: z4.enum([\"job\", \"stage\", \"step\"]),\n name: z4.string().min(1),\n parent: z4.string().min(1).optional()\n});\nvar pipelineStatusSchema = z4.object({\n type: z4.literal(\"pipeline-status\"),\n status: z4.enum([\"passed\", \"failed\", \"running\", \"cancelled\", \"unknown\"]),\n /** The source's unmodified status/result vocabulary, for an honest display. */\n rawStatus: z4.string(),\n name: z4.string().min(1),\n /** The branch represented by this status, when the upstream supplies or filters by one. */\n branch: z4.string().min(1).optional(),\n /** Elapsed execution time, supplied only after the upstream run has completed. */\n durationMs: z4.number().int().nonnegative().optional(),\n /** When an active run began, so the client can advance its elapsed display between polls. */\n runStartedAt: z4.iso.datetime().optional(),\n /** Stable source-run identity, when the adapter provides one. */\n sourceRunId: z4.string().min(1).optional(),\n /** Best-effort live work detail; adapters may describe a job, stage, or step. */\n activity: pipelineActivitySchema.optional(),\n /** Advisory duration from recent completed runs remembered by this browser. */\n estimatedDurationMs: z4.number().int().positive().optional(),\n /** When this workflow run was last updated by its source, distinct from our observation time. */\n sourceUpdatedAt: z4.iso.datetime().optional()\n});\nvar pullRequestHealthItemSchema = z4.object({\n label: z4.string().min(1),\n status: pipelineStatusSchema.shape.status,\n detail: z4.string().min(1),\n link: z4.url().nullable()\n});\nvar pullRequestHealthSchema = z4.object({\n type: z4.literal(\"pull-request-health\"),\n status: pipelineStatusSchema.shape.status,\n summary: z4.string().min(1),\n workflows: z4.array(pullRequestHealthItemSchema),\n pullRequests: z4.array(pullRequestHealthItemSchema)\n});\nvar httpValueSchema = z4.object({\n type: z4.literal(\"http-value\"),\n value: z4.union([z4.string(), z4.number(), z4.boolean()])\n});\n\n// packages/shared/src/layout.ts\nvar columnCount = 12;\nvar rowCount = 12;\nfunction analyzeBoardLayout(panels) {\n const issues = panels.flatMap((panel) => {\n if (!panel.position || isZeroPosition(panel.position) || isPositionInCanvas(panel.position))\n return [];\n return [\n {\n panelId: panel.id,\n kind: \"out-of-bounds\",\n position: panel.position,\n conflictsWith: []\n }\n ];\n });\n const overlapIssues = /* @__PURE__ */ new Map();\n for (let leftIndex = 0; leftIndex < panels.length; leftIndex++) {\n const left = panels[leftIndex];\n if (!left?.position || isZeroPosition(left.position)) continue;\n for (let rightIndex = leftIndex + 1; rightIndex < panels.length; rightIndex++) {\n const right = panels[rightIndex];\n if (!right?.position || isZeroPosition(right.position)) continue;\n if (!overlaps(left.position, right.position)) continue;\n const key = `${right.id}\\0overlap`;\n const issue = overlapIssues.get(key);\n if (issue) issue.conflictsWith.push(left.id);\n else {\n const nextIssue = {\n panelId: right.id,\n kind: \"overlap\",\n position: right.position,\n conflictsWith: [left.id]\n };\n overlapIssues.set(key, nextIssue);\n issues.push(nextIssue);\n }\n }\n }\n return { issues };\n}\nfunction normalizeBoardLayout(panels) {\n const positioned = panels.flatMap((panel) => {\n if (!panel.position || isZeroPosition(panel.position)) return [];\n return [{ ...panel.position, panelId: panel.id }];\n });\n if (positioned.length === 0) return panels.map((panel) => ({ ...panel }));\n const minX = Math.min(...positioned.map((rectangle) => rectangle.x));\n const minY = Math.min(...positioned.map((rectangle) => rectangle.y));\n const maxX = Math.max(...positioned.map((rectangle) => rectangle.x + rectangle.w));\n const maxY = Math.max(...positioned.map((rectangle) => rectangle.y + rectangle.h));\n const scaleX = maxX - minX > columnCount ? columnCount / (maxX - minX) : 1;\n const scaleY = maxY - minY > rowCount ? rowCount / (maxY - minY) : 1;\n const accepted = [];\n return panels.map((panel) => {\n const position = panel.position;\n if (!position || isZeroPosition(position)) return { ...panel };\n const desired = scaleRectangle(position, minX, minY, scaleX, scaleY);\n const legal = nearestLegalRectangle(desired, accepted);\n if (!legal) return { ...panel, position: zeroPosition };\n accepted.push({ ...legal, panelId: panel.id });\n return { ...panel, position: legal };\n });\n}\nfunction isZeroPosition(position) {\n return position?.x === 0 && position.y === 0 && position.w === 0 && position.h === 0;\n}\nvar zeroPosition = { x: 0, y: 0, w: 0, h: 0 };\nfunction isPositionInCanvas(position) {\n return !isZeroPosition(position) && position.x + position.w <= columnCount && position.y + position.h <= rowCount;\n}\nfunction overlaps(left, right) {\n return left.x < right.x + right.w && left.x + left.w > right.x && left.y < right.y + right.h && left.y + left.h > right.y;\n}\nfunction scaleRectangle(position, minX, minY, scaleX, scaleY) {\n const x = scaleCoordinate(position.x, minX, scaleX);\n const y = scaleCoordinate(position.y, minY, scaleY);\n const right = scaleCoordinate(position.x + position.w, minX, scaleX);\n const bottom = scaleCoordinate(position.y + position.h, minY, scaleY);\n return {\n x,\n y,\n w: Math.max(1, right - x),\n h: Math.max(1, bottom - y)\n };\n}\nfunction scaleCoordinate(value, origin, scale) {\n return Math.round((value - origin) * scale);\n}\nfunction nearestLegalRectangle(desired, accepted) {\n const candidates = [];\n for (let width = desired.w; width >= 1; width--) {\n for (let height = desired.h; height >= 1; height--) {\n const shrink = desired.w - width + (desired.h - height);\n for (let y = 0; y <= rowCount - height; y++) {\n for (let x = 0; x <= columnCount - width; x++) {\n const candidate2 = { x, y, w: width, h: height };\n if (accepted.some((rectangle) => overlaps(candidate2, rectangle))) continue;\n candidates.push({\n ...candidate2,\n shrink,\n distance: Math.abs(x - desired.x) + Math.abs(y - desired.y)\n });\n }\n }\n }\n }\n candidates.sort(\n (left, right) => left.shrink - right.shrink || left.distance - right.distance || left.y - right.y || left.x - right.x\n );\n const [candidate] = candidates;\n if (!candidate) return void 0;\n return { x: candidate.x, y: candidate.y, w: candidate.w, h: candidate.h };\n}\n\n// packages/shared/src/polling-policy.ts\nvar pollingDefaults = {\n refreshMillis: 6e4,\n runningRefreshMillis: 15e3,\n runningCompletionRefreshMillis: 5e3,\n runningCompletionWindowMillis: 12e4\n};\nfunction resolvePollingSettings(board, panel) {\n const duration = (value, fallback) => parseDuration(value ?? \"\") ?? fallback;\n const panelValue = (key, boardValue, fallback) => duration(panel[key], duration(board[boardValue], fallback));\n return {\n refreshMillis: panelValue(\"refresh\", \"refresh\", pollingDefaults.refreshMillis),\n runningRefreshMillis: panelValue(\n \"running_refresh\",\n \"running_refresh\",\n pollingDefaults.runningRefreshMillis\n ),\n runningCompletionRefreshMillis: panelValue(\n \"running_completion_refresh\",\n \"running_completion_refresh\",\n pollingDefaults.runningCompletionRefreshMillis\n ),\n runningCompletionWindowMillis: panelValue(\n \"running_completion_window\",\n \"running_completion_window\",\n pollingDefaults.runningCompletionWindowMillis\n )\n };\n}\nexport {\n analyzeBoardLayout,\n authSchema,\n boardConfigSchema,\n boardSchema,\n boardSchemaFileName,\n boardSchemaModeline,\n clientEnvSchema,\n clientIdentitySchema,\n credentialEnvironmentNames,\n durationSchema,\n envelopeSchema,\n errorKindSchema,\n githubActionsSourceSchema,\n githubAppSchema,\n httpValueSchema,\n isZeroPosition,\n normalizeBoardLayout,\n panelDensities,\n panelDensitySchema,\n panelSchema,\n parseDuration,\n pipelineActivitySchema,\n pipelineStatusSchema,\n pollingDefaults,\n positionSchema,\n pullRequestHealthSchema,\n readBoardSchemaModeline,\n readClientEnv,\n resolvePollingSettings,\n resolveRefreshMillis,\n runningAnimationSchema,\n schemaUrlForAssetPath,\n sourceSchema,\n visibleRunningAnimations\n};\n",".board {\n display: flex;\n flex-direction: column;\n gap: var(--gap);\n height: 100dvh;\n min-height: 0;\n padding: var(--gap);\n overflow-x: hidden;\n overflow-y: auto;\n}\n.header {\n display: flex;\n align-items: baseline;\n border-bottom: 1px solid var(--edge);\n padding-bottom: var(--gap);\n flex: 0 0 auto;\n}\n.title {\n margin: 0;\n font-size: 1.75em;\n font-weight: 650;\n letter-spacing: -0.01em;\n}\n.grid {\n display: grid;\n grid-template-columns: repeat(12, minmax(0, 1fr));\n grid-template-rows: repeat(12, minmax(0, 1fr));\n grid-auto-rows: minmax(0, 1fr);\n gap: var(--gap);\n flex: 1;\n min-height: 0;\n align-content: stretch;\n}\n.footerTools {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n}\n.layoutWarning {\n position: relative;\n}\n.layoutWarningButton {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: 0.2em;\n min-width: 2em;\n min-height: 2em;\n border: 1px solid var(--status-warning);\n border-radius: 50%;\n color: var(--status-warning);\n background: var(--surface-raised);\n font: inherit;\n cursor: pointer;\n}\n.layoutWarningButton:hover,\n.layoutWarningButton:focus-visible {\n background: var(--surface);\n}\n.layoutWarningDialog {\n position: absolute;\n z-index: 10;\n right: 0;\n bottom: calc(100% + 0.75rem);\n width: min(32rem, calc(100vw - 2 * var(--gap)));\n padding: 0.8rem;\n border: 1px solid var(--status-warning);\n border-radius: var(--radius);\n color: var(--ink-secondary);\n background: var(--surface-raised);\n box-shadow: 0 0.5rem 1.5rem rgb(0 0 0 / 35%);\n}\n.layoutWarningHeading {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 1rem;\n}\n.layoutWarningHeading strong {\n color: var(--status-warning);\n}\n.layoutWarningDialog p {\n margin: 0.6rem 0;\n}\n.layoutWarningDialog ul {\n margin: 0.35rem 0 0.75rem;\n padding-left: 1.25rem;\n font-family: ui-monospace, SFMono-Regular, Menlo, monospace;\n font-size: 0.85em;\n}\n.layoutWarningClose {\n border: 0;\n color: var(--ink-muted);\n background: transparent;\n font-size: 1.25em;\n line-height: 1;\n cursor: pointer;\n}\n.layoutWarningDownloads {\n display: grid;\n gap: 0.35rem;\n}\n.layoutWarningDownloads a {\n border: 1px solid var(--edge);\n border-radius: 0.25rem;\n background: var(--surface-raised);\n color: var(--ink-secondary);\n font: inherit;\n padding: 0.3em 0.55em;\n text-align: center;\n text-decoration: none;\n}\n.layoutWarningDownloads a:hover,\n.layoutWarningDownloads a:focus-visible {\n border-color: var(--ink-secondary);\n color: var(--ink-primary);\n}\n.layoutWarningNote {\n color: var(--ink-muted);\n font-size: 0.85em;\n}\n.footer {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n justify-content: space-between;\n gap: 0.5rem;\n color: var(--ink-muted);\n font-size: 0.75em;\n flex: 0 0 auto;\n}\n@media (max-width: 64rem) {\n .board {\n height: auto;\n min-height: 100dvh;\n overflow: visible;\n }\n .grid {\n grid-template-columns: 1fr;\n grid-auto-rows: auto;\n flex: 0 0 auto;\n min-height: auto;\n }\n .layoutWarningDialog {\n position: fixed;\n right: var(--gap);\n bottom: calc(var(--gap) + 3rem);\n }\n}\n",".diagnostics {\n position: relative;\n}\n\n.button {\n border: 1px solid var(--edge);\n border-radius: 0.25rem;\n background: var(--surface-raised);\n color: var(--ink-secondary);\n font: inherit;\n padding: 0.3em 0.55em;\n}\n\n.area {\n position: absolute;\n z-index: 1;\n right: 0;\n bottom: calc(100% + 0.5rem);\n width: min(24rem, 90vw);\n padding: 0.75rem;\n border: 1px solid var(--edge);\n border-radius: var(--radius);\n background: var(--surface-raised);\n box-shadow: 0 0.5rem 1.5rem #0008;\n}\n\n.area p {\n margin: 0 0 0.5rem;\n}\n\n.warning {\n color: var(--status-warning);\n}\n\n.panels {\n max-height: 12rem;\n overflow-y: auto;\n border-top: 1px solid var(--edge);\n margin: 0.5rem 0;\n padding-top: 0.5rem;\n}\n\n.actions {\n display: flex;\n gap: 0.5rem;\n}\n","import { useState, useSyncExternalStore } from 'react'\nimport styles from './Diagnostics.module.css'\nimport type { BrowserDiagnosticStore } from './diagnostics.ts'\n\nexport function Diagnostics({ log }: { log: BrowserDiagnosticStore }) {\n const [open, setOpen] = useState(false)\n useSyncExternalStore(log.subscribe, log.snapshot, log.snapshot)\n const count = log.count()\n const githubConsistencyIncidents = log.githubConsistencyIncidentCount()\n const summary = log.summary()\n const download = () => {\n const blob = new Blob([JSON.stringify(log.export(), null, 2)], { type: 'application/json' })\n const url = URL.createObjectURL(blob)\n const link = document.createElement('a')\n link.href = url\n link.download = `dashboard-diagnostics-${new Date().toISOString().replaceAll(':', '-')}.json`\n link.click()\n URL.revokeObjectURL(url)\n }\n const clear = () => {\n if (!window.confirm('Clear this browser’s retained dashboard diagnostics?')) return\n log.clear()\n }\n\n return (\n <section className={styles.diagnostics}>\n <button\n className={styles.button}\n type=\"button\"\n aria-expanded={open}\n onClick={() => setOpen(!open)}\n >\n Diagnostics ({count})\n {githubConsistencyIncidents > 0 && ` · GitHub consistency ${githubConsistencyIncidents}`}\n </button>\n {open && (\n <div className={styles.area}>\n <p>\n Client {log.clientVersion()} · assets {log.assetPath()}\n </p>\n <p>\n {summary.retained.eventCount} retained browser-local events across{' '}\n {summary.retained.sessionCount} session{summary.retained.sessionCount === 1 ? '' : 's'}\n {summary.retained.firstEventAt && summary.retained.lastEventAt\n ? ` (${formatWindow(summary.retained.firstEventAt, summary.retained.lastEventAt)})`\n : ''}\n . They are never uploaded.\n </p>\n {summary.retained.evidenceMayBeIncomplete && (\n <p className={styles.warning} role=\"alert\">\n Earlier evidence was pruned: {summary.retained.retention.eventsPrunedByCount} at the\n 2,000-event cap and {summary.retained.retention.eventsPrunedByAge} by the 7-day age\n limit. “No failures” applies only to the retained window.\n </p>\n )}\n <p>\n Update failures: {summary.failures.clientUpdate}; board fetch failures:{' '}\n {summary.failures.boardFetch}.\n </p>\n {log.githubConsistencyIncidentCount() > 0 && (\n <p className={styles.warning} role=\"alert\">\n GitHub API consistency incidents: {log.githubConsistencyIncidentCount()}. A response\n older than the last accepted run was rejected; download diagnostics to report it.\n </p>\n )}\n {summary.panels.length > 0 && (\n <div className={styles.panels}>\n {summary.panels.map((panel) => (\n <p key={panel.panelId}>\n <strong>{panel.panelId}</strong> — {panel.requests} requests\n {Object.keys(panel.httpStatuses).length\n ? `; HTTP ${Object.entries(panel.httpStatuses)\n .map(([status, count]) => `${status}×${count}`)\n .join(', ')}`\n : ''}\n ; parse/network failures {panel.parseFailures}/{panel.networkFailures}; visible\n changes {panel.visibleStateChanges}; latest{' '}\n {panel.latestRendered\n ? `${panel.latestRendered.state}${panel.latestRendered.status ? `/${panel.latestRendered.status}` : ''}`\n : 'not rendered'}\n .\n </p>\n ))}\n </div>\n )}\n <div className={styles.actions}>\n <button className={styles.button} type=\"button\" onClick={download}>\n Download\n </button>\n <button className={styles.button} type=\"button\" onClick={clear}>\n Clear\n </button>\n </div>\n </div>\n )}\n </section>\n )\n}\n\nfunction formatWindow(first: string, last: string) {\n return first === last ? first : `${first} to ${last}`\n}\n","export type BrowserStorageLike = Pick<Storage, 'getItem' | 'setItem'>\n\nexport function browserLocalStorage(): BrowserStorageLike | undefined {\n try {\n return window.localStorage\n } catch {\n return undefined\n }\n}\n\nexport function readBrowserJson<T>(\n storage: BrowserStorageLike | undefined,\n key: string,\n): T | undefined {\n try {\n const raw = storage?.getItem(key)\n return raw ? (JSON.parse(raw) as T) : undefined\n } catch {\n return undefined\n }\n}\n\nexport function writeBrowserJson(\n storage: BrowserStorageLike | undefined,\n key: string,\n value: unknown,\n) {\n try {\n storage?.setItem(key, JSON.stringify(value))\n } catch {\n // Browser storage is an optimization; callers retain their in-memory state.\n }\n}\n\nexport function removeBrowserValue(storage: Pick<Storage, 'removeItem'> | undefined, key: string) {\n try {\n storage?.removeItem(key)\n } catch {\n // Storage can be unavailable in private browsing or restricted frames.\n }\n}\n","import type {\n DiagnosticEvent,\n DiagnosticRetention,\n RenderedPanelDiagnostic,\n} from './diagnostics.ts'\n\nexport type PanelDiagnosticsSummary = {\n panelId: string\n requests: number\n httpStatuses: Record<string, number>\n parseFailures: number\n networkFailures: number\n visibleStateChanges: number\n latestRendered?: RenderedPanelDiagnostic\n}\n\nexport type DiagnosticsSummary = {\n githubConsistencyIncidents: number\n retained: {\n eventCount: number\n firstEventAt?: string\n lastEventAt?: string\n sessionCount: number\n retention: DiagnosticRetention\n evidenceMayBeIncomplete: boolean\n }\n failures: {\n clientUpdate: number\n boardFetch: number\n }\n panels: PanelDiagnosticsSummary[]\n}\n\n/** Summarizes retained browser evidence only; omitted history is disclosed through retention. */\nexport function summarizeDiagnostics(\n events: readonly DiagnosticEvent[],\n retention: DiagnosticRetention,\n githubConsistencyIncidents = 0,\n): DiagnosticsSummary {\n const panels = new Map<string, PanelDiagnosticsSummary>()\n const sessions = new Set<string>()\n let clientUpdate = 0\n let boardFetch = 0\n\n for (const event of events) {\n sessions.add(event.sessionId)\n if (event.kind === 'client-update-failure') clientUpdate++\n if (event.kind === 'board-fetch-failure' || event.kind === 'board-fetch-parse-failure')\n boardFetch++\n if (!('panelId' in event)) continue\n\n const panel = panels.get(event.panelId) ?? {\n panelId: event.panelId,\n requests: 0,\n httpStatuses: {},\n parseFailures: 0,\n networkFailures: 0,\n visibleStateChanges: 0,\n }\n if (event.kind === 'panel-fetch-start') panel.requests++\n if (event.kind === 'panel-fetch-response') {\n if (event.status !== undefined) {\n const status = String(event.status)\n panel.httpStatuses[status] = (panel.httpStatuses[status] ?? 0) + 1\n }\n }\n if (event.kind === 'panel-fetch-parse-failure') panel.parseFailures++\n if (event.kind === 'panel-fetch-failure') panel.networkFailures++\n if (event.kind === 'panel-rendered') {\n panel.visibleStateChanges++\n panel.latestRendered = event.rendered\n }\n panels.set(event.panelId, panel)\n }\n\n const timestamps = events.map((event) => event.at).sort()\n const discarded = retention.eventsPrunedByAge + retention.eventsPrunedByCount\n return {\n githubConsistencyIncidents,\n retained: {\n eventCount: events.length,\n firstEventAt: timestamps[0],\n lastEventAt: timestamps.at(-1),\n sessionCount: sessions.size,\n retention,\n evidenceMayBeIncomplete: discarded > 0,\n },\n failures: { clientUpdate, boardFetch },\n panels: [...panels.values()].sort((left, right) => left.panelId.localeCompare(right.panelId)),\n }\n}\n","import type { ClientEnv, Envelope } from '@ze-great-dashboard/shared'\nimport {\n type BrowserStorageLike,\n browserLocalStorage,\n readBrowserJson,\n removeBrowserValue,\n writeBrowserJson,\n} from './browser-storage.ts'\nimport { type DiagnosticsSummary, summarizeDiagnostics } from './diagnostics-summary.ts'\n\nconst storageKey = 'ze-great-dashboard.diagnostics.v1'\nexport const diagnosticsSchemaVersion = 1\nconst maximumEvents = 2_000\nconst maximumAgeMillis = 7 * 24 * 60 * 60 * 1_000\nconst diagnosticKinds = [\n 'session-start',\n 'client-update-check',\n 'client-update-failure',\n 'client-update-detected',\n 'board-fetch-start',\n 'board-fetch-response',\n 'board-fetch-parse-failure',\n 'board-fetch-failure',\n 'layout-analyzed',\n 'panel-fetch-start',\n 'panel-fetch-response',\n 'panel-fetch-parse-failure',\n 'panel-fetch-failure',\n 'panel-rendered',\n] as const\n\nexport type CacheMetadata = Partial<\n Record<'cacheControl' | 'etag' | 'lastModified' | 'date' | 'age', string>\n>\n\nexport type GithubConsistencyIncident = {\n at: string\n board: string\n panelId: string\n endpoint: string\n identity: { source: string; workflow: string; branch: string }\n accepted: { sourceUpdatedAt: string; status: string; link: string | null }\n regressed: { sourceUpdatedAt: string; status: string; link: string | null }\n response: { httpStatus?: number; date?: string; etag?: string; cacheControl?: string }\n}\n\ntype EventMetadata = {\n schemaVersion: typeof diagnosticsSchemaVersion\n at: string\n sessionId: string\n board: string\n}\n\nexport type RenderedPanelDiagnostic = {\n state: Envelope['state']\n status?: string\n link: string | null\n}\n\nexport type DiagnosticEventInput =\n | { kind: 'session-start' }\n | { kind: 'client-update-check'; path: string }\n | { kind: 'client-update-failure'; path: string; message: string }\n | {\n kind: 'client-update-detected'\n path: string\n current: { assetPath: string; clientVersion: string }\n next: { assetPath: string; clientVersion: string }\n }\n | { kind: 'board-fetch-start'; path: string }\n | {\n kind: 'board-fetch-response'\n path: string\n status?: number\n cache?: CacheMetadata\n boardSummary?: { panelCount: number; panelIds: string[] }\n }\n | { kind: 'board-fetch-parse-failure'; path: string; message: string }\n | { kind: 'board-fetch-failure'; path: string; message: string }\n | { kind: 'layout-analyzed'; issueCount: number; affectedPanelIds: string[] }\n | { kind: 'panel-fetch-start'; panelId: string; path: string }\n | {\n kind: 'panel-fetch-response'\n panelId: string\n path: string\n status?: number\n cache?: CacheMetadata\n envelope?: Envelope\n }\n | { kind: 'panel-fetch-parse-failure'; panelId: string; path: string; message: string }\n | { kind: 'panel-fetch-failure'; panelId: string; path: string; message: string }\n | {\n kind: 'panel-rendered'\n panelId: string\n path: string\n rendered: RenderedPanelDiagnostic\n }\n\nexport type DiagnosticEvent = DiagnosticEventInput extends infer Event\n ? Event extends DiagnosticEventInput\n ? Event & EventMetadata\n : never\n : never\n\n/** The only interface client features need in order to emit browser diagnostics. */\nexport interface DiagnosticSink {\n record(event: DiagnosticEventInput): void\n recordGithubConsistencyIncident(incident: Omit<GithubConsistencyIncident, 'at' | 'board'>): void\n}\n\ntype PersistedDiagnosticEvent = Omit<DiagnosticEvent, 'schemaVersion'> & { schemaVersion?: number }\nexport type DiagnosticRetention = {\n eventsPrunedByAge: number\n eventsPrunedByCount: number\n}\n\ntype StoredDiagnostics = {\n schemaVersion: number\n events: PersistedDiagnosticEvent[]\n retention?: Partial<DiagnosticRetention>\n githubConsistencyIncidents?: GithubConsistencyIncident[]\n}\n\ntype StorageLike = BrowserStorageLike & Pick<Storage, 'removeItem'>\n\n/** Browser-local diagnostic evidence. It deliberately has no server or shared-contract counterpart. */\nexport class BrowserDiagnosticStore implements DiagnosticSink {\n private events: DiagnosticEvent[] = []\n private retention: DiagnosticRetention = emptyRetention()\n private revision = 0\n private incidents: GithubConsistencyIncident[] = []\n private readonly listeners = new Set<() => void>()\n private readonly sessionId = crypto.randomUUID?.() ?? `${Date.now()}-${Math.random()}`\n\n constructor(\n private readonly env: ClientEnv,\n private readonly storage: StorageLike | undefined = browserLocalStorage() as\n | StorageLike\n | undefined,\n private readonly now: () => Date = () => new Date(),\n ) {\n this.events = this.read()\n this.record({ kind: 'session-start' })\n }\n\n recordGithubConsistencyIncident(incident: Omit<GithubConsistencyIncident, 'at' | 'board'>) {\n this.incidents.push({ ...incident, at: this.now().toISOString(), board: this.env.board })\n this.persist()\n this.revision++\n this.notify()\n }\n\n githubConsistencyIncidentCount = () => this.incidents.length\n\n record(event: DiagnosticEventInput) {\n const pruned = prune(\n [\n ...this.events,\n {\n ...event,\n schemaVersion: diagnosticsSchemaVersion,\n at: this.now().toISOString(),\n sessionId: this.sessionId,\n board: this.env.board,\n },\n ],\n this.now(),\n this.retention,\n )\n this.events = pruned.events\n this.retention = pruned.retention\n this.persist()\n this.revision++\n this.notify()\n }\n\n count = () => {\n return this.events.length\n }\n\n clientVersion = () => this.env.clientVersion\n\n assetPath = () => this.env.assetPath\n\n snapshot = () => this.revision\n\n summary = (): DiagnosticsSummary =>\n summarizeDiagnostics(this.events, this.retention, this.incidents.length)\n\n clear() {\n this.events = []\n this.incidents = []\n this.retention = emptyRetention()\n removeBrowserValue(this.storage, storageKey)\n this.revision++\n this.notify()\n }\n\n subscribe = (listener: () => void) => {\n this.listeners.add(listener)\n return () => {\n this.listeners.delete(listener)\n }\n }\n\n export = () => {\n return {\n schemaVersion: diagnosticsSchemaVersion,\n exportedAt: this.now().toISOString(),\n client: {\n version: this.env.clientVersion,\n assetPath: this.env.assetPath,\n board: this.env.board,\n sessionId: this.sessionId,\n },\n events: this.events,\n githubConsistencyIncidents: this.incidents,\n summary: this.summary(),\n }\n }\n\n private read(): DiagnosticEvent[] {\n const parsed = readBrowserJson<Partial<StoredDiagnostics>>(this.storage, storageKey)\n if (\n !parsed ||\n parsed.schemaVersion !== diagnosticsSchemaVersion ||\n !Array.isArray(parsed.events)\n ) {\n removeBrowserValue(this.storage, storageKey)\n return []\n }\n if (!parsed.events.every(isDiagnosticEvent)) {\n removeBrowserValue(this.storage, storageKey)\n return []\n }\n // v1 retained events predate per-event versions. Their containing store was already v1, so\n // retain them and normalize on the next write rather than discarding viewer evidence.\n const pruned = prune(\n parsed.events.map(\n (event) => ({ ...event, schemaVersion: diagnosticsSchemaVersion }) as DiagnosticEvent,\n ),\n this.now(),\n validRetention(parsed.retention),\n )\n this.retention = pruned.retention\n this.incidents = validIncidents(parsed.githubConsistencyIncidents)\n return pruned.events\n }\n\n private persist() {\n writeBrowserJson(this.storage, storageKey, {\n schemaVersion: diagnosticsSchemaVersion,\n events: this.events,\n retention: this.retention,\n githubConsistencyIncidents: this.incidents,\n })\n }\n\n private notify() {\n for (const listener of this.listeners) listener()\n }\n}\n\nfunction validIncidents(value: unknown): GithubConsistencyIncident[] {\n if (!Array.isArray(value)) return []\n return value.filter((incident): incident is GithubConsistencyIncident => {\n if (!incident || typeof incident !== 'object') return false\n const item = incident as Partial<GithubConsistencyIncident>\n return (\n typeof item.at === 'string' &&\n typeof item.board === 'string' &&\n typeof item.panelId === 'string' &&\n typeof item.endpoint === 'string' &&\n !!item.accepted &&\n !!item.regressed &&\n !!item.response\n )\n })\n}\n\nexport function cacheMetadata(headers: Headers): CacheMetadata | undefined {\n const entries = [\n ['cacheControl', 'cache-control'],\n ['etag', 'etag'],\n ['lastModified', 'last-modified'],\n ['date', 'date'],\n ['age', 'age'],\n ] as const\n const metadata = Object.fromEntries(\n entries.flatMap(([key, header]) => {\n const value = headers.get(header)\n return value ? [[key, value]] : []\n }),\n ) as CacheMetadata\n return Object.keys(metadata).length ? metadata : undefined\n}\n\nfunction emptyRetention(): DiagnosticRetention {\n return { eventsPrunedByAge: 0, eventsPrunedByCount: 0 }\n}\n\nfunction validRetention(value: unknown): DiagnosticRetention {\n if (!value || typeof value !== 'object') return emptyRetention()\n const retention = value as Partial<DiagnosticRetention>\n return {\n eventsPrunedByAge:\n typeof retention.eventsPrunedByAge === 'number' && retention.eventsPrunedByAge >= 0\n ? retention.eventsPrunedByAge\n : 0,\n eventsPrunedByCount:\n typeof retention.eventsPrunedByCount === 'number' && retention.eventsPrunedByCount >= 0\n ? retention.eventsPrunedByCount\n : 0,\n }\n}\n\nfunction prune(events: DiagnosticEvent[], now: Date, priorRetention: DiagnosticRetention) {\n const cutoff = now.valueOf() - maximumAgeMillis\n const current = events.filter(\n (event) =>\n Number.isFinite(new Date(event.at).valueOf()) && new Date(event.at).valueOf() >= cutoff,\n )\n const discardedByAge = events.length - current.length\n const discardedByCount = Math.max(0, current.length - maximumEvents)\n return {\n events: current.slice(-maximumEvents),\n retention: {\n eventsPrunedByAge: priorRetention.eventsPrunedByAge + discardedByAge,\n eventsPrunedByCount: priorRetention.eventsPrunedByCount + discardedByCount,\n },\n }\n}\n\nfunction isDiagnosticEvent(value: unknown): value is PersistedDiagnosticEvent {\n if (!value || typeof value !== 'object') return false\n const event = value as Partial<DiagnosticEvent>\n return (\n (event.schemaVersion === undefined || event.schemaVersion === diagnosticsSchemaVersion) &&\n typeof event.at === 'string' &&\n Number.isFinite(new Date(event.at).valueOf()) &&\n typeof event.sessionId === 'string' &&\n typeof event.board === 'string' &&\n diagnosticKinds.includes(event.kind as (typeof diagnosticKinds)[number])\n )\n}\n",".panel {\n grid-column: var(--panel-column, span 6);\n grid-row: var(--panel-row, auto);\n display: flex;\n flex-direction: column;\n justify-content: center;\n gap: 0.15em;\n min-width: 0;\n min-height: 0;\n padding: clamp(0.5rem, 0.8vw, var(--gap));\n border: 1px solid var(--edge);\n border-radius: var(--radius);\n background: var(--surface-raised);\n position: relative;\n isolation: isolate;\n overflow: hidden;\n line-height: 1.2;\n container-name: panel;\n container-type: size;\n}\n.content {\n position: relative;\n z-index: 1;\n display: flex;\n flex: 0 1 auto;\n flex-direction: column;\n justify-content: center;\n gap: 0.1em;\n min-width: 0;\n min-height: 0;\n overflow: hidden;\n}\n.content > *,\n.details > * {\n min-width: 0;\n max-width: 100%;\n}\n.content:has([data-running-progress=\"runway\"]),\n.content:has([data-running-progress=\"signal-field\"]) {\n flex: 1 1 0;\n}\n.error {\n border-color: var(--status-serious);\n}\n.wide {\n grid-column: span 12;\n}\n.density-comfortable {\n padding: 0.65em;\n gap: 0.1em;\n}\n.density-comfortable .content {\n gap: 0.1em;\n}\n.density-compact {\n min-height: 3.5em;\n padding: 0.2em;\n gap: 0;\n line-height: 1.05;\n justify-content: flex-start;\n}\n.density-compact .content {\n gap: 0;\n}\n.label {\n margin: 0;\n overflow-wrap: anywhere;\n font-size: 1em;\n font-weight: 600;\n font-family: ui-monospace, SFMono-Regular, Menlo, monospace;\n color: var(--ink-secondary);\n}\n.density-compact .label {\n font-size: 0.8em;\n}\n.hint {\n margin: 0;\n font-size: 0.75em;\n color: var(--ink-muted);\n overflow-wrap: anywhere;\n}\n.branch {\n font-family: ui-monospace, SFMono-Regular, Menlo, monospace;\n overflow-wrap: anywhere;\n}\n.observed {\n display: flex;\n flex-wrap: wrap;\n gap: 0.35em;\n align-items: center;\n}\n.meta {\n display: var(--panel-meta-display, block);\n}\n.metaValue {\n min-width: 0;\n overflow-wrap: anywhere;\n}\n.stale {\n color: var(--status-warning);\n}\n.status {\n margin: 0;\n font-size: 1.35em;\n font-weight: 650;\n}\n.density-compact .status {\n font-size: 1.1em;\n}\n.passed {\n color: var(--status-good);\n}\n.failed {\n color: var(--status-critical);\n}\n.running {\n color: var(--status-warning);\n}\n.cancelled,\n.unknown {\n color: var(--ink-secondary);\n}\n.sourceAction {\n position: absolute;\n z-index: 2;\n top: 0.35em;\n right: 0.35em;\n display: inline-grid;\n width: 2em;\n height: 2em;\n place-items: center;\n border-radius: 0.3em;\n color: var(--ink-secondary);\n font-size: 0.85em;\n font-weight: 600;\n line-height: 1;\n text-decoration: none;\n}\n.sourceAction:hover {\n color: var(--ink-primary);\n background: color-mix(in srgb, var(--ink-primary) 8%, transparent);\n}\n.sourceAction:focus-visible {\n outline: 2px solid var(--ink-primary);\n outline-offset: 2px;\n}\n\n.density-comfortable :is(.hint, .observed),\n.density-compact :is(.hint, .observed) {\n font-size: 0.65em;\n}\n@container panel (min-width: 48rem) {\n .density-comfortable.shallow,\n .density-auto.shallow {\n padding: 0.45em 0.65em;\n }\n .density-comfortable.shallow .content,\n .density-auto.shallow .content {\n flex-direction: row;\n flex-wrap: wrap;\n align-items: baseline;\n column-gap: 0.7em;\n row-gap: 0.15em;\n }\n .density-comfortable.shallow .status,\n .density-auto.shallow .status {\n flex: 0 0 auto;\n font-size: 1em;\n }\n .density-comfortable.shallow :is(.label, .observed),\n .density-auto.shallow :is(.label, .observed) {\n flex: 0 0 auto;\n }\n}\n@container panel (min-width: 12rem) {\n .density-compact.shallow .content,\n .density-auto.shallow .content {\n flex-direction: row;\n flex-wrap: wrap;\n align-items: baseline;\n column-gap: 0.7em;\n row-gap: 0.15em;\n }\n .density-compact.shallow :is(.label, .observed),\n .density-auto.shallow :is(.label, .observed) {\n flex: 0 0 auto;\n }\n}\n/* Width and height use the same scale steps, so a narrow or tall cell gets the same text budget. */\n@container panel (max-width: 22rem) {\n .content,\n .sourceAction {\n font-size: 0.8em;\n }\n}\n@container panel (max-width: 15rem) {\n .content,\n .sourceAction {\n font-size: 0.9em;\n }\n}\n@container panel (max-height: 10rem) {\n .content,\n .sourceAction {\n font-size: 0.8em;\n }\n}\n@container panel (max-height: 7rem) {\n .content,\n .sourceAction {\n font-size: 0.9em;\n }\n}\n/* Responsive layout may flow authored cells into one column; content never escapes its cell. */\n@media (max-width: 64rem) {\n .panel {\n grid-column: 1 / -1;\n grid-row: auto;\n min-height: 6em;\n }\n .density-comfortable .content,\n .density-compact .content,\n .density-auto .content {\n flex-direction: column;\n align-items: stretch;\n }\n}\n\n@container panel (max-width: 11rem) and (max-height: 9rem) {\n .content {\n --panel-meta-display: flex;\n }\n .label {\n font-size: 0.85em;\n }\n .status {\n font-size: 1.05em;\n }\n}\n@container panel (max-height: 5rem) {\n .content {\n --panel-meta-display: flex;\n }\n .label {\n font-size: 0.85em;\n }\n .status {\n font-size: 1.05em;\n }\n}\n\n@container panel (max-width: 13rem) {\n .density-compact .content {\n --panel-meta-display: flex;\n }\n .density-compact .content > .meta {\n font-size: 0.6em;\n }\n}\n@container panel (max-width: 8rem) {\n /* Text-light is an internal sub-mode: secondary text remains in the accessibility tree. */\n .content {\n --panel-meta-display: flex;\n gap: 0.05em;\n }\n}\n@container panel (min-height: 24rem) and (max-width: 13rem) {\n .content {\n --panel-meta-display: flex;\n gap: 0.05em;\n }\n}\n@container panel (max-height: 4rem) {\n .content {\n --panel-meta-display: flex;\n gap: 0.05em;\n }\n}\n\n@container panel (max-width: 13rem) and (max-height: 10rem) {\n .density-comfortable .content > .meta {\n font-size: 0.68em;\n }\n}\n\n@container panel (max-width: 18rem) and (max-height: 10rem) {\n .density-compact .content > .meta {\n font-size: 0.6em;\n }\n}\n\n.meta {\n align-items: center;\n gap: 0.2em;\n min-width: 0;\n}\n.metaValue {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n","/**\n * A panel-shaped hole, so the grid can be looked at and argued with before any signal exists.\n * Replaced by real panels in Stage 2 — nothing here is meant to survive.\n */\nexport function PanelPlaceholder({\n label,\n hint,\n wide = false,\n}: {\n label: string\n hint: string\n wide?: boolean\n}) {\n return (\n <section\n className={`${styles.panel} ${wide ? styles.wide : ''}`}\n data-panel\n data-panel-id=\"placeholder\"\n >\n <h2 className={styles.label}>{label}</h2>\n <p className={styles.hint}>{hint}</p>\n </section>\n )\n}\n\nimport styles from './PanelFrame.module.css'\n",".fact {\n display: contents;\n}\n@container panel (min-width: 48rem) {\n :global([data-density=\"compact\"][data-shallow=\"true\"]) .fact > *,\n :global([data-density=\"auto\"][data-shallow=\"true\"]) .fact > * {\n margin: 0;\n }\n}\n@container panel (min-width: 12rem) {\n :global([data-density=\"compact\"][data-shallow=\"true\"]) .fact > *,\n :global([data-density=\"auto\"][data-shallow=\"true\"]) .fact > * {\n margin: 0;\n }\n}\n","import type { Panel } from '@ze-great-dashboard/shared'\nimport type { CSSProperties } from 'react'\n\n/** Convert the advisory board position into CSS grid placement. */\nexport function panelLayout(panel: Panel): CSSProperties | undefined {\n const position = panel.position\n if (!position) return undefined\n\n return {\n '--panel-column': `${position.x + 1} / span ${position.w}`,\n '--panel-row': `${position.y + 1} / span ${position.h}`,\n } as CSSProperties\n}\n","import type { Envelope, Panel } from '@ze-great-dashboard/shared'\nimport type { ReactNode } from 'react'\nimport styles from './PanelFrame.module.css'\nimport { panelLayout } from './panel-layout.ts'\n\ntype PanelStatusKind = 'passed' | 'failed' | 'running' | 'cancelled' | 'unknown'\n\nexport function PanelHint({\n children,\n className,\n title,\n}: {\n children: ReactNode\n className?: string\n title?: string\n}) {\n return (\n <p className={`${styles.hint} ${className ?? ''}`} title={title}>\n {children}\n </p>\n )\n}\n\n/** A concise metadata row with one visible glyph and the full value retained in the DOM. */\nexport function PanelMetadata({\n glyph,\n label,\n value,\n title,\n observed = false,\n stale = false,\n className,\n}: {\n glyph: string\n label: string\n value: ReactNode\n title?: string\n observed?: boolean\n stale?: boolean\n className?: string\n}) {\n return (\n <p\n className={`${styles.hint} ${observed ? styles.observed : ''} ${stale ? styles.stale : ''} ${styles.meta} ${className ?? ''}`}\n data-panel-meta\n >\n <span aria-hidden=\"true\">{glyph}</span> <span className=\"screen-reader-only\">{label}: </span>\n <span className={styles.metaValue} title={title}>\n {value}\n </span>\n </p>\n )\n}\n\nexport function PanelStatus({\n children,\n status,\n}: {\n children: ReactNode\n status?: PanelStatusKind\n}) {\n return <p className={`${styles.status} ${status ? styles[status] : ''}`}>{children}</p>\n}\n\nexport function PanelFrame({\n panel,\n envelope,\n error = false,\n field,\n children,\n}: {\n panel: Panel\n envelope?: Envelope\n error?: boolean\n /** Decorative active-run layer. It is intentionally a sibling of readable panel content. */\n field?: ReactNode\n children: ReactNode\n}) {\n const density = panel.density ?? 'auto'\n const position = panel.position\n const shallow = position !== undefined && position.h <= 2\n const short = position !== undefined && position.h <= 3\n return (\n <section\n className={`${styles.panel} ${styles[`density-${density}`]} ${shallow ? styles.shallow : ''} ${short ? styles.short : ''} ${error ? styles.error : ''}`}\n style={panelLayout(panel)}\n aria-busy={envelope ? undefined : true}\n data-panel\n data-panel-id={panel.id}\n data-panel-position={\n position ? `${position.x},${position.y},${position.w},${position.h}` : undefined\n }\n data-density={density}\n data-shallow={shallow}\n data-short={short}\n data-error={error || undefined}\n >\n {field}\n <PanelSourceLink panelId={panel.id} link={envelope?.link} />\n <div className={styles.content} data-panel-content>\n <h2 className={styles.label}>{panel.label ?? panel.id}</h2>\n {children}\n </div>\n </section>\n )\n}\n\nfunction PanelSourceLink({ panelId, link }: { panelId: string; link?: string | null }) {\n if (!link) return null\n\n return (\n <a\n className={styles.sourceAction}\n href={link}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n aria-label={`View source for ${panelId} (opens in a new tab)`}\n title={`View source for ${panelId} (opens in a new tab)`}\n data-panel-action=\"source\"\n data-panel-link\n >\n <span aria-hidden=\"true\">↗</span>\n <span className=\"screen-reader-only\">View source</span>\n </a>\n )\n}\n","import { PanelMetadata } from './PanelFrame.tsx'\n\nexport function CheckedAt({ value }: { value: string }) {\n return <TimeAge value={value} stale label=\"Checked\" variant=\"age\" />\n}\n\nexport function RunAge({ value, running }: { value: string; running: boolean }) {\n return <TimeAge value={value} label={running ? 'Started' : 'Run updated'} variant=\"age\" />\n}\n\nfunction TimeAge({\n value,\n label,\n stale = false,\n variant,\n}: {\n value: string\n label: string\n stale?: boolean\n variant: 'clock' | 'age'\n}) {\n const observed = new Date(value)\n const formatted = observed.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })\n const age = Date.now() - observed.getTime()\n const content =\n variant === 'clock' ? `${label} ${formatted} · ${formatAge(age)}` : `${label} ${formatAge(age)}`\n return (\n <PanelMetadata\n glyph=\"◷\"\n label={label}\n value={content}\n title={`${label} at ${formatted}`}\n observed\n stale={stale}\n />\n )\n}\n\nexport function formatAge(milliseconds: number) {\n if (milliseconds < 60_000) return 'just now'\n const minutes = Math.floor(milliseconds / 60_000)\n if (minutes < 60) return `${minutes}m ago`\n const hours = Math.floor(minutes / 60)\n return `${hours}h ${minutes % 60}m ago`\n}\n","import { httpValueSchema } from '@ze-great-dashboard/shared'\nimport styles from './HttpValuePanel.module.css'\nimport { PanelFrame, PanelHint, PanelStatus } from './PanelFrame.tsx'\nimport type { PanelProps } from './panel-props.ts'\nimport { CheckedAt } from './TimeAge.tsx'\n\nexport function HttpValuePanel({ panel, envelope, checkedAt }: PanelProps) {\n if (!envelope)\n return (\n <PanelFrame panel={panel}>\n <PanelHint>Loading…</PanelHint>\n </PanelFrame>\n )\n if (envelope.state === 'error')\n return (\n <PanelFrame panel={panel} envelope={envelope} error>\n <PanelStatus>⚠ Unable to read</PanelStatus>\n <PanelHint>{envelope.error.message}</PanelHint>\n {checkedAt && <CheckedAt value={checkedAt} />}\n </PanelFrame>\n )\n const signal = httpValueSchema.safeParse(envelope.signal)\n if (!signal.success)\n return (\n <PanelFrame panel={panel} envelope={envelope} error>\n <PanelStatus>⚠ Invalid value</PanelStatus>\n {checkedAt && <CheckedAt value={checkedAt} />}\n </PanelFrame>\n )\n return (\n <PanelFrame panel={panel} envelope={envelope}>\n <div className={styles.fact}>\n <PanelStatus>{String(signal.data.value)}</PanelStatus>\n {checkedAt && <CheckedAt value={checkedAt} />}\n </div>\n </PanelFrame>\n )\n}\n","export type FallingDirection = 'horizontal' | 'vertical'\nexport type FallingCell = { x: number; y: number }\nexport type FallingShape = {\n id: number\n bornAt: number\n cells: FallingCell[]\n x: number\n y: number\n targetX?: number\n targetY?: number\n phase: 'entry' | 'align' | 'travel' | 'settled'\n}\n\nexport const FALLING_TARGET_FILL = 0.85\n\nconst shapes: FallingCell[][] = [\n [\n { x: 0, y: 0 },\n { x: 1, y: 0 },\n ],\n [\n { x: 0, y: 0 },\n { x: 0, y: 1 },\n ],\n [\n { x: 0, y: 0 },\n { x: 1, y: 0 },\n { x: 0, y: 1 },\n ],\n [\n { x: 0, y: 0 },\n { x: 1, y: 0 },\n { x: 2, y: 0 },\n ],\n [\n { x: 0, y: 0 },\n { x: 0, y: 1 },\n { x: 1, y: 1 },\n ],\n]\n\nexport function fallingDirection(width: number, height: number): FallingDirection {\n return width > height ? 'horizontal' : 'vertical'\n}\n\nexport function fallingGrid(\n direction: FallingDirection,\n width = direction === 'horizontal' ? 12 : 3,\n height = direction === 'horizontal' ? 3 : 12,\n): { columns: number; rows: number } {\n const fieldWidth = Math.max(1, width * 0.8)\n const fieldHeight = Math.max(1, height * 0.8)\n const cellSize = Math.max(24, Math.min(42, Math.min(fieldWidth, fieldHeight) / 4))\n const columns = Math.max(3, Math.min(24, Math.round(fieldWidth / cellSize)))\n const rows = Math.max(3, Math.min(16, Math.round(fieldHeight / cellSize)))\n return direction === 'horizontal'\n ? { columns: Math.max(columns, rows), rows }\n : { columns, rows: Math.max(rows, columns) }\n}\n\nexport function fallingSeed(value: string): number {\n return Array.from(value).reduce(\n (hash, character) => (hash * 31 + character.charCodeAt(0)) >>> 0,\n 7,\n )\n}\n\nexport function shapeFits(shape: FallingCell[], columns: number, rows: number): boolean {\n const maxX = Math.max(...shape.map((cell) => cell.x))\n const maxY = Math.max(...shape.map((cell) => cell.y))\n return maxX < columns && maxY < rows\n}\n\nexport function overlaps(left: FallingShape, right: FallingShape): boolean {\n return left.cells.some((leftCell) =>\n right.cells.some(\n (rightCell) =>\n left.x + leftCell.x === right.x + rightCell.x &&\n left.y + leftCell.y === right.y + rightCell.y,\n ),\n )\n}\n\nexport function chooseShape(seed: number, columns: number, rows: number): FallingCell[] {\n const candidates = shapes.filter((shape) => shapeFits(shape, columns, rows))\n return candidates[randomIndex(seed, candidates.length)] ?? [{ x: 0, y: 0 }]\n}\n\nexport function findDestination(\n shape: FallingCell[],\n direction: FallingDirection,\n columns: number,\n rows: number,\n settled: readonly FallingShape[],\n seed = 0,\n requireSupported = false,\n): { x: number; y: number } | undefined {\n const width = Math.max(...shape.map((cell) => cell.x)) + 1\n const height = Math.max(...shape.map((cell) => cell.y)) + 1\n const candidates: Array<{ x: number; y: number; support: number }> = []\n for (let y = 0; y <= rows - height; y++) {\n for (let x = 0; x <= columns - width; x++) {\n const candidate = { id: -1, bornAt: 0, cells: shape, x, y, phase: 'settled' as const }\n if (settled.some((item) => overlaps(candidate, item))) continue\n if (!clearPath(shape, direction, columns, rows, candidate, settled)) continue\n const support =\n direction === 'vertical'\n ? shape.filter(\n (cell) =>\n y + cell.y === rows - 1 ||\n settled.some((item) =>\n item.cells.some(\n (other) =>\n item.x + other.x === x + cell.x && item.y + other.y === y + cell.y + 1,\n ),\n ),\n ).length\n : shape.filter(\n (cell) =>\n x + cell.x === 0 ||\n settled.some((item) =>\n item.cells.some(\n (other) =>\n item.x + other.x === x + cell.x - 1 && item.y + other.y === y + cell.y,\n ),\n ),\n ).length\n if (requireSupported && support < leadingEdgeCount(shape, direction)) continue\n candidates.push({ x, y, support })\n }\n }\n candidates.sort(\n (left, right) =>\n right.support - left.support ||\n (direction === 'vertical'\n ? right.y - left.y || left.x - right.x\n : left.x - right.x || left.y - right.y),\n )\n const bestSupport = candidates[0]?.support\n const best = candidates.filter((candidate) => candidate.support === bestSupport)\n const destination = best[randomIndex(seed, best.length)]\n return destination ? { x: destination.x, y: destination.y } : undefined\n}\n\nexport function findPlacement(\n direction: FallingDirection,\n columns: number,\n rows: number,\n settled: readonly FallingShape[],\n seed: number,\n requireSupported: boolean,\n): { shape: FallingCell[]; destination: { x: number; y: number } } | undefined {\n const candidates = shapes.flatMap((shape, index) => {\n if (!shapeFits(shape, columns, rows)) return []\n const destination = findDestination(\n shape,\n direction,\n columns,\n rows,\n settled,\n seed + index * 31,\n requireSupported,\n )\n return destination ? [{ shape, destination }] : []\n })\n if (candidates.length === 0) return undefined\n return candidates[randomIndex(seed, candidates.length)]\n}\n\nexport function targetCellCount(columns: number, rows: number, progress: number): number {\n return Math.ceil(columns * rows * FALLING_TARGET_FILL * Math.min(1, Math.max(0, progress)))\n}\n\nexport function occupiedCellCount(shapes: readonly FallingShape[]): number {\n return shapes.reduce((count, shape) => count + shape.cells.length, 0)\n}\n\nexport type LineClear = {\n shapes: FallingShape[]\n cleared: FallingCell[]\n complete: boolean\n}\n\n/** Clears only cells in the trailing edge line and slides the surviving field into it. */\nexport function clearTrailingLine(\n direction: FallingDirection,\n columns: number,\n rows: number,\n settled: readonly FallingShape[],\n allowPartial: boolean,\n): LineClear | undefined {\n const edgeLine = direction === 'vertical' ? rows - 1 : 0\n const occupied = new Set(\n settled.flatMap((item) =>\n item.cells\n .filter((cell) =>\n direction === 'vertical' ? item.y + cell.y === edgeLine : item.x + cell.x === edgeLine,\n )\n .map((cell) => (direction === 'vertical' ? item.x + cell.x : item.y + cell.y)),\n ),\n )\n const lineWidth = direction === 'vertical' ? columns : rows\n const complete = occupied.size === lineWidth\n if (!complete && !allowPartial) return undefined\n if (occupied.size === 0) return undefined\n\n const cleared: FallingCell[] = []\n const shapes = settled.flatMap((item) => {\n const remaining = item.cells.filter((cell) => {\n const onLine =\n direction === 'vertical' ? item.y + cell.y === edgeLine : item.x + cell.x === edgeLine\n if (onLine) {\n cleared.push({ x: item.x + cell.x, y: item.y + cell.y })\n }\n return !onLine\n })\n if (remaining.length === 0) return []\n return [\n {\n ...item,\n cells: remaining,\n y: direction === 'vertical' ? item.y + 1 : item.y,\n x: direction === 'horizontal' ? item.x - 1 : item.x,\n },\n ]\n })\n return { shapes, cleared, complete }\n}\n\nexport function buildStaticField(\n direction: FallingDirection,\n columns: number,\n rows: number,\n seed: number,\n count: number,\n): FallingShape[] {\n const settled: FallingShape[] = []\n for (let id = 0; id < count; id += 1) {\n const pieceSeed = seed + id * 17\n const shape = chooseShape(pieceSeed, columns, rows)\n const destination = findDestination(shape, direction, columns, rows, settled, pieceSeed + 1)\n if (!destination) break\n settled.push({\n id,\n bornAt: 0,\n cells: shape,\n x: destination.x,\n y: destination.y,\n phase: 'settled',\n })\n }\n return settled\n}\n\nfunction leadingEdgeCount(shape: FallingCell[], direction: FallingDirection): number {\n if (direction === 'vertical') {\n return new Set(shape.map((cell) => cell.x)).size\n }\n return new Set(shape.map((cell) => cell.y)).size\n}\n\nfunction clearPath(\n shape: FallingCell[],\n direction: FallingDirection,\n columns: number,\n rows: number,\n destination: FallingShape,\n settled: readonly FallingShape[],\n): boolean {\n const width = Math.max(...shape.map((cell) => cell.x)) + 1\n const height = Math.max(...shape.map((cell) => cell.y)) + 1\n if (direction === 'vertical') {\n for (let y = 0; y <= destination.y; y += 1) {\n if (settled.some((item) => overlaps({ ...destination, y }, item))) return false\n }\n return destination.y + height <= rows\n }\n for (let x = columns - width; x >= destination.x; x -= 1) {\n if (settled.some((item) => overlaps({ ...destination, x }, item))) return false\n }\n return destination.x + width <= columns\n}\n\nfunction randomIndex(seed: number, length: number): number {\n if (length <= 1) return 0\n const value = Math.sin(seed * 12.9898 + 78.233) * 43_758.5453\n return Math.floor((value - Math.floor(value)) * length)\n}\n",".variant {\n margin: 0;\n color: var(--ink-muted);\n font-size: 0.72em;\n text-transform: capitalize;\n transition: color 180ms ease;\n}\n@media (prefers-reduced-motion: reduce) {\n .variant {\n transition: none;\n }\n}\n",".field {\n position: absolute;\n z-index: 0;\n inset: 0;\n overflow: hidden;\n pointer-events: none;\n contain: layout paint;\n color: var(--status-warning);\n}\n.grid {\n position: absolute;\n inset: 10%;\n}\n.piece {\n position: absolute;\n left: calc((var(--piece-x) / var(--shape-columns)) * 100%);\n top: calc((var(--piece-y) / var(--shape-rows)) * 100%);\n width: calc((var(--piece-width) / var(--shape-columns)) * 100%);\n height: calc((var(--piece-height) / var(--shape-rows)) * 100%);\n transition:\n left 120ms linear,\n top 120ms linear;\n}\n.field[data-recycling=\"true\"] .piece {\n transition:\n left 500ms cubic-bezier(0.22, 1, 0.36, 1),\n top 500ms cubic-bezier(0.22, 1, 0.36, 1),\n opacity 180ms ease;\n}\n.field[data-overdue=\"true\"] .piece[data-piece-phase=\"settled\"] {\n opacity: 0.72;\n border-color: currentColor;\n}\n.field[data-overdue=\"true\"] .cell {\n background: color-mix(in srgb, currentColor 38%, transparent);\n box-shadow: 0 0 0.6em color-mix(in srgb, currentColor 48%, transparent);\n}\n.field[data-overdue=\"true\"] .clearingCell {\n animation-duration: 900ms;\n}\n/* biome-ignore lint/style/noDescendingSpecificity: base cell rules follow the overdue override intentionally. */\n.cell {\n position: absolute;\n left: calc((var(--cell-x) / var(--piece-width)) * 100% + 0.12em);\n top: calc((var(--cell-y) / var(--piece-height)) * 100% + 0.12em);\n width: calc(100% / var(--piece-width) - 0.24em);\n height: calc(100% / var(--piece-height) - 0.24em);\n border: 1px solid color-mix(in srgb, currentColor 55%, transparent);\n border-radius: 0.12em;\n background: color-mix(in srgb, currentColor 28%, transparent);\n box-shadow: 0 0 0.45em color-mix(in srgb, currentColor 35%, transparent);\n}\n/* biome-ignore lint/style/noDescendingSpecificity: base clearing rules follow the overdue override intentionally. */\n.clearingCell {\n position: absolute;\n left: calc((var(--clear-x) / var(--shape-columns)) * 100% + 0.12em);\n top: calc((var(--clear-y) / var(--shape-rows)) * 100% + 0.12em);\n width: calc(100% / var(--shape-columns) - 0.24em);\n height: calc(100% / var(--shape-rows) - 0.24em);\n border: 1px solid color-mix(in srgb, currentColor 55%, transparent);\n border-radius: 0.12em;\n background: color-mix(in srgb, currentColor 28%, transparent);\n animation: clear-cell 500ms ease-out forwards;\n}\n.piece[data-piece-phase=\"entry\"] {\n opacity: 0.35;\n}\n.piece[data-piece-phase=\"align\"] {\n opacity: 0.65;\n}\n.piece[data-piece-phase=\"travel\"] {\n opacity: 0.9;\n}\n/* biome-ignore lint/style/noDescendingSpecificity: settled phase is the base state for the overdue override. */\n.piece[data-piece-phase=\"settled\"] {\n opacity: 0.5;\n}\n@media (prefers-reduced-motion: reduce) {\n .piece,\n .field[data-recycling=\"true\"] .piece {\n transition: none;\n }\n .field[data-overdue=\"true\"] .clearingCell {\n animation: none;\n opacity: 0;\n }\n /* biome-ignore lint/style/noDescendingSpecificity: reduced-motion base rule follows the overdue override. */\n .clearingCell {\n animation: none;\n opacity: 0;\n }\n}\n\n@keyframes clear-cell {\n to {\n opacity: 0;\n transform: scale(0.35);\n }\n}\n","import type { CSSProperties } from 'react'\nimport { useEffect, useRef, useState } from 'react'\nimport styles from './FallingShapesField.module.css'\nimport {\n buildStaticField,\n clearTrailingLine,\n type FallingDirection,\n type FallingShape,\n fallingDirection,\n fallingGrid,\n findPlacement,\n occupiedCellCount,\n targetCellCount,\n} from './falling-shapes.ts'\n\nconst TICK_MS = 50\nconst PIECE_INTERVAL_MS = 1_250\nconst ENTRY_MS = 250\nconst TRAVEL_MS = 850\nconst RECYCLE_MS = 500\n\nexport function FallingShapesField({\n progress,\n estimatedDurationMs,\n overdue,\n seed = 0,\n}: {\n progress: number\n estimatedDurationMs?: number\n overdue: boolean\n seed?: number\n}) {\n const rootRef = useRef<HTMLDivElement>(null)\n const [geometry, setGeometry] = useState<{\n columns: number\n rows: number\n direction: FallingDirection\n }>({\n ...fallingGrid('vertical'),\n direction: 'vertical' as const,\n })\n const [pieces, setPieces] = useState<FallingShape[]>([])\n const [recycling, setRecycling] = useState(false)\n const [clearingCells, setClearingCells] = useState<{ x: number; y: number }[]>([])\n const [reducedMotion, setReducedMotion] = useState(false)\n const geometryRef = useRef(geometry)\n const previousGeometryRef = useRef(geometry)\n const progressRef = useRef(progress)\n const seedRef = useRef(seed)\n const directionRef = useRef<FallingDirection | undefined>(undefined)\n const piecesRef = useRef<FallingShape[]>([])\n const recyclingRef = useRef(false)\n const simulation = useRef({\n startedAt: Date.now(),\n nextPieceAt: PIECE_INTERVAL_MS,\n recycleUntil: 0,\n id: 0,\n settled: [] as FallingShape[],\n })\n\n useEffect(() => {\n progressRef.current = progress\n }, [progress])\n\n useEffect(() => {\n seedRef.current = seed\n }, [seed])\n\n useEffect(() => {\n const root = rootRef.current\n if (!root) return\n const update = () => {\n const rect = root.getBoundingClientRect()\n if (rect.width === 0 || rect.height === 0) return\n setGeometry((_current) => {\n const direction = directionRef.current ?? fallingDirection(rect.width, rect.height)\n directionRef.current = direction\n const next = { ...fallingGrid(direction, rect.width, rect.height), direction }\n geometryRef.current = next\n return next\n })\n }\n update()\n if (typeof ResizeObserver === 'undefined') return\n const observer = new ResizeObserver(update)\n observer.observe(root)\n return () => observer.disconnect()\n }, [])\n\n useEffect(() => {\n const media = window.matchMedia('(prefers-reduced-motion: reduce)')\n const update = () => setReducedMotion(media.matches)\n update()\n media.addEventListener?.('change', update)\n return () => media.removeEventListener?.('change', update)\n }, [])\n\n useEffect(() => {\n const previous = previousGeometryRef.current\n const changed =\n previous.direction !== geometry.direction ||\n previous.columns !== geometry.columns ||\n previous.rows !== geometry.rows\n previousGeometryRef.current = geometry\n if (!changed || reducedMotion) return\n simulation.current = {\n startedAt: Date.now(),\n nextPieceAt: PIECE_INTERVAL_MS,\n id: 0,\n recycleUntil: 0,\n settled: [],\n }\n piecesRef.current = []\n setPieces([])\n setRecycling(false)\n setClearingCells([])\n recyclingRef.current = false\n }, [geometry, reducedMotion])\n\n useEffect(() => {\n if (!reducedMotion) return\n const staticPieces = buildStaticField(\n geometry.direction,\n geometry.columns,\n geometry.rows,\n seedRef.current,\n Math.max(1, Math.floor(progressRef.current * 6)),\n )\n piecesRef.current = staticPieces\n simulation.current.settled = staticPieces\n setPieces(staticPieces)\n }, [geometry, reducedMotion])\n\n useEffect(() => {\n if (reducedMotion) return\n const timer = window.setInterval(() => {\n const state = simulation.current\n const elapsed = Date.now() - state.startedAt\n const currentGeometry = geometryRef.current\n const currentProgress = progressRef.current\n const target = targetCellCount(currentGeometry.columns, currentGeometry.rows, currentProgress)\n let next = [...state.settled]\n let active = piecesRef.current.filter((piece) => piece.phase !== 'settled')\n if (elapsed < state.recycleUntil) return\n if (recyclingRef.current) {\n recyclingRef.current = false\n setRecycling(false)\n setClearingCells([])\n }\n if (elapsed >= state.nextPieceAt && active.length === 0) {\n if (currentProgress < 1 && occupiedCellCount(next) >= target) {\n return\n }\n const id = state.id\n const pieceSeed = seedRef.current + id * 17\n const placement = findPlacement(\n currentGeometry.direction,\n currentGeometry.columns,\n currentGeometry.rows,\n next,\n pieceSeed + 1,\n !overdue,\n )\n if (!placement && (currentProgress >= 1 || estimatedDurationMs === undefined)) {\n const cleared = clearTrailingLine(\n currentGeometry.direction,\n currentGeometry.columns,\n currentGeometry.rows,\n next,\n true,\n )\n if (cleared) {\n next = cleared.shapes\n state.settled = next\n state.recycleUntil = elapsed + RECYCLE_MS\n state.nextPieceAt = state.recycleUntil\n piecesRef.current = next\n recyclingRef.current = true\n setClearingCells(cleared.cleared)\n setPieces(next)\n setRecycling(true)\n return\n }\n }\n if (placement) {\n state.id += 1\n const { shape, destination } = placement\n const height = Math.max(...shape.map((cell) => cell.y)) + 1\n active = [\n ...active,\n {\n id,\n bornAt: elapsed,\n cells: shape,\n x:\n currentGeometry.direction === 'horizontal'\n ? currentGeometry.columns - Math.max(...shape.map((cell) => cell.x)) - 0.5\n : destination.x,\n y: currentGeometry.direction === 'vertical' ? -height + 0.5 : destination.y,\n targetX: destination.x,\n targetY: destination.y,\n phase: 'entry',\n },\n ]\n }\n state.nextPieceAt += pieceInterval(estimatedDurationMs, currentGeometry)\n }\n active = active.map((piece) => {\n const age = elapsed - piece.bornAt\n const destination =\n piece.targetX === undefined || piece.targetY === undefined\n ? undefined\n : { x: piece.targetX, y: piece.targetY }\n if (!destination) return piece\n const amount = Math.min(1, Math.max(0, (age - ENTRY_MS) / TRAVEL_MS))\n if (amount >= 1) {\n next = [\n ...next,\n { ...piece, x: destination.x, y: destination.y, phase: 'settled' as const },\n ]\n return { ...piece, x: destination.x, y: destination.y, phase: 'settled' as const }\n }\n const startX =\n currentGeometry.direction === 'horizontal'\n ? currentGeometry.columns - Math.max(...piece.cells.map((cell) => cell.x)) - 1\n : destination.x\n const startY = currentGeometry.direction === 'vertical' ? 0 : destination.y\n const lifecycleAmount = Math.min(1, Math.max(0, age / (ENTRY_MS + TRAVEL_MS)))\n return {\n ...piece,\n x:\n currentGeometry.direction === 'horizontal'\n ? startX + (destination.x - startX) * amount\n : startX,\n y:\n currentGeometry.direction === 'vertical'\n ? startY + (destination.y - startY) * amount\n : startY,\n phase: age < ENTRY_MS ? 'entry' : lifecycleAmount < 0.35 ? 'align' : 'travel',\n }\n })\n state.settled = next\n const visible = [...next, ...active.filter((piece) => piece.phase !== 'settled')]\n piecesRef.current = visible\n setPieces(visible)\n }, TICK_MS)\n return () => window.clearInterval(timer)\n }, [estimatedDurationMs, overdue, reducedMotion])\n\n return (\n <div\n ref={rootRef}\n className={styles.field}\n data-running-part=\"falling-shapes-field\"\n data-overdue={overdue || undefined}\n data-direction={geometry.direction}\n data-recycling={recycling || undefined}\n style={\n { '--shape-columns': geometry.columns, '--shape-rows': geometry.rows } as CSSProperties\n }\n >\n <div className={styles.grid}>\n {clearingCells.map((cell) => (\n <span\n key={`${cell.x}-${cell.y}`}\n className={styles.clearingCell}\n style={{ '--clear-x': cell.x, '--clear-y': cell.y } as CSSProperties}\n />\n ))}\n {pieces.map((piece) => (\n <div\n key={piece.id}\n className={styles.piece}\n data-piece={piece.id}\n data-piece-phase={piece.phase}\n style={\n {\n '--piece-x': piece.x,\n '--piece-y': piece.y,\n '--piece-width': Math.max(...piece.cells.map((cell) => cell.x)) + 1,\n '--piece-height': Math.max(...piece.cells.map((cell) => cell.y)) + 1,\n } as CSSProperties\n }\n >\n {piece.cells.map((cell) => (\n <span\n key={`${cell.x}-${cell.y}`}\n className={styles.cell}\n style={{ '--cell-x': cell.x, '--cell-y': cell.y } as CSSProperties}\n />\n ))}\n </div>\n ))}\n </div>\n </div>\n )\n}\n\nfunction pieceInterval(\n estimatedDurationMs: number | undefined,\n geometry: { columns: number; rows: number },\n) {\n const target = Math.ceil(geometry.columns * geometry.rows * 0.85)\n if (estimatedDurationMs === undefined || target <= 0) return PIECE_INTERVAL_MS\n return Math.max(400, estimatedDurationMs / Math.max(1, Math.ceil(target / 3)))\n}\n",".frontier {\n position: absolute;\n inset: 0 auto 0 0;\n width: var(--running-progress);\n background: linear-gradient(\n 90deg,\n color-mix(in srgb, currentColor 16%, transparent),\n transparent\n );\n border-right: 1px solid color-mix(in srgb, currentColor 75%, transparent);\n}\n.now {\n position: absolute;\n top: 10%;\n bottom: 10%;\n left: 70%;\n width: 1px;\n background: color-mix(in srgb, var(--ink-primary) 45%, transparent);\n}\n.routes {\n position: absolute;\n inset: 18% 8%;\n display: grid;\n align-content: space-between;\n}\n.route {\n height: 1px;\n background: linear-gradient(\n 90deg,\n transparent,\n color-mix(in srgb, var(--ink-muted) 45%, transparent),\n transparent\n );\n}\n.route:nth-child(2) {\n transform: translateX(8%);\n}\n.route:nth-child(3) {\n transform: translateX(-6%);\n}\n.trail,\n.packet {\n position: absolute;\n top: 50%;\n left: -10%;\n border-radius: 999px;\n animation: packet 4.8s ease-in-out infinite alternate;\n}\n.trail {\n width: 18%;\n height: 2px;\n background: linear-gradient(90deg, transparent, currentColor);\n opacity: 0.65;\n}\n.packet {\n width: 0.48em;\n height: 0.48em;\n background: currentColor;\n box-shadow: 0 0 0.65em currentColor;\n}\n@container running-field (max-width: 40rem) {\n .routes,\n .trail,\n .packet,\n .now {\n display: none;\n }\n .frontier {\n width: 0.28em;\n border-right: 0;\n background: currentColor;\n }\n}\n[data-overdue=\"true\"] .frontier {\n width: 70%;\n background: linear-gradient(\n 90deg,\n color-mix(in srgb, currentColor 28%, transparent),\n transparent\n );\n}\n[data-overdue=\"true\"] .packet {\n left: 70%;\n animation: packet-stall 1.8s ease-in-out infinite alternate;\n}\n[data-overdue=\"true\"] .trail {\n left: 43%;\n width: 27%;\n animation: trail-backup 1.8s ease-in-out infinite alternate;\n}\n@keyframes packet {\n from {\n transform: translate(-10cqw, -50%);\n }\n to {\n transform: translate(120cqw, -50%);\n }\n}\n@keyframes packet-stall {\n from {\n transform: translate(-50%, -50%) scale(0.82);\n opacity: 0.72;\n }\n to {\n transform: translate(-50%, -50%) scale(1.12);\n opacity: 1;\n }\n}\n@keyframes trail-backup {\n from {\n transform: translate(-8%, -50%);\n opacity: 0.5;\n }\n to {\n transform: translate(8%, -50%);\n opacity: 0.95;\n }\n}\n@media (prefers-reduced-motion: reduce) {\n [data-overdue=\"true\"] .trail,\n [data-overdue=\"true\"] .packet,\n .trail,\n .packet {\n animation: none;\n }\n .frontier {\n transition: none;\n }\n}\n","import styles from './ReleaseTransitField.module.css'\n\nexport function ReleaseTransitField() {\n return (\n <>\n <span className={styles.frontier} data-running-part=\"frontier\" />\n <span className={styles.now} data-running-part=\"transit-now\" />\n <span className={styles.routes} data-running-part=\"transit-routes\">\n {[0, 1, 2].map((route) => (\n <span className={styles.route} key={route} />\n ))}\n </span>\n <span className={styles.trail} data-running-part=\"transit-trail\" />\n <span className={styles.packet} data-running-part=\"transit-packet\" />\n </>\n )\n}\n",".field {\n position: absolute;\n z-index: 0;\n inset: 0;\n overflow: hidden;\n pointer-events: none;\n container-type: size;\n container-name: running-field;\n color: var(--status-warning);\n}\n.overdue {\n color: var(--status-serious);\n}\n.timing {\n width: min(12ch, 100%);\n max-width: 100%;\n min-width: 0;\n flex: 0 1 12ch;\n margin: 0;\n color: var(--ink-secondary);\n font-family: ui-monospace, SFMono-Regular, Menlo, monospace;\n font-size: 0.72em;\n font-variant-numeric: tabular-nums;\n text-align: end;\n white-space: nowrap;\n overflow: hidden;\n}\n.timingOverdue {\n color: var(--status-serious);\n}\n",".haze {\n position: absolute;\n inset: -15%;\n background:\n radial-gradient(\n ellipse at 18% 44%,\n color-mix(in srgb, currentColor 19%, transparent),\n transparent 42%\n ),\n radial-gradient(\n ellipse at 74% 63%,\n color-mix(in srgb, currentColor 12%, transparent),\n transparent 38%\n );\n animation: haze 15s ease-in-out infinite alternate;\n}\n.pressure {\n display: none;\n}\n.band {\n position: absolute;\n right: -15%;\n left: -15%;\n height: 1px;\n background: linear-gradient(\n 90deg,\n transparent,\n color-mix(in srgb, currentColor 32%, transparent),\n transparent\n );\n animation: band 10s ease-in-out infinite alternate;\n}\n.bandOne {\n top: 32%;\n}\n.bandTwo {\n top: 67%;\n animation-delay: -4s;\n}\n.bandThree {\n top: 49%;\n animation-delay: -7s;\n opacity: 0.55;\n}\n.drift {\n position: absolute;\n width: clamp(0.34em, 0.9cqw, 0.7em);\n height: clamp(0.34em, 0.9cqw, 0.7em);\n border: 1px solid color-mix(in srgb, currentColor 78%, transparent);\n border-radius: 50%;\n box-shadow: 0 0 0.55em color-mix(in srgb, currentColor 55%, transparent);\n animation: drift 11s ease-in-out infinite alternate;\n}\n.driftOne {\n top: 25%;\n left: 12%;\n}\n.driftTwo {\n top: 72%;\n left: 58%;\n width: 0.34em;\n height: 0.34em;\n animation-duration: 14s;\n animation-delay: -4s;\n opacity: 0.6;\n}\n.driftThree {\n top: 18%;\n left: 74%;\n width: 0.7em;\n height: 0.7em;\n animation-duration: 17s;\n animation-delay: -9s;\n opacity: 0.55;\n}\n.driftFour {\n top: 58%;\n left: 31%;\n width: 0.42em;\n height: 0.42em;\n animation-duration: 9s;\n animation-delay: -2s;\n opacity: 0.75;\n}\n.driftFive {\n top: 84%;\n left: 83%;\n width: 0.58em;\n height: 0.58em;\n animation-duration: 13s;\n animation-delay: -6s;\n opacity: 0.45;\n}\n@container running-field (max-width: 40rem) or (max-height: 6rem) {\n .drift,\n .band {\n display: none;\n }\n .haze {\n inset: auto 0 0 auto;\n width: 2.5em;\n height: 2.5em;\n opacity: 0.65;\n }\n}\n[data-overdue=\"true\"] .haze {\n inset: -30%;\n background:\n radial-gradient(\n ellipse at 22% 48%,\n color-mix(in srgb, currentColor 34%, transparent),\n transparent 42%\n ),\n radial-gradient(\n ellipse at 78% 58%,\n color-mix(in srgb, currentColor 25%, transparent),\n transparent 36%\n );\n}\n[data-overdue=\"true\"] .pressure {\n display: block;\n position: absolute;\n inset: 20% 0;\n border-top: 1px solid color-mix(in srgb, currentColor 65%, transparent);\n border-bottom: 1px solid color-mix(in srgb, currentColor 65%, transparent);\n background: repeating-linear-gradient(\n 180deg,\n transparent 0 0.55em,\n color-mix(in srgb, currentColor 14%, transparent) 0.55em 0.62em\n );\n opacity: 0.75;\n animation: pressure 3.4s ease-in-out infinite alternate;\n}\n[data-overdue=\"true\"] .band {\n background: linear-gradient(90deg, transparent, currentColor, transparent);\n animation-name: storm-band;\n}\n[data-overdue=\"true\"] .drift {\n transform: translate(12cqw, -2cqh) scale(0.82);\n}\n@keyframes haze {\n to {\n transform: translate(9%, -4%);\n }\n}\n@keyframes band {\n to {\n transform: translateX(8%);\n opacity: 0.45;\n }\n}\n@keyframes drift {\n to {\n transform: translate(10cqw, -2cqh);\n }\n}\n@keyframes pressure {\n from {\n transform: scaleY(0.72);\n opacity: 0.45;\n }\n to {\n transform: scaleY(1.12);\n opacity: 0.9;\n }\n}\n@keyframes storm-band {\n to {\n transform: translateX(-14%);\n opacity: 0.9;\n }\n}\n@media (prefers-reduced-motion: reduce) {\n [data-overdue=\"true\"] .pressure,\n .haze,\n .band,\n .drift {\n animation: none;\n }\n .pressure {\n animation: none;\n }\n}\n","import styles from './StatusWeatherField.module.css'\n\nexport function StatusWeatherField() {\n return (\n <>\n <span className={styles.haze} data-running-part=\"weather-haze\" />\n <span className={styles.pressure} data-running-part=\"weather-pressure\" />\n <span className={`${styles.band} ${styles.bandOne}`} />\n <span className={`${styles.band} ${styles.bandTwo}`} />\n <span className={`${styles.band} ${styles.bandThree}`} />\n <span className={`${styles.drift} ${styles.driftOne}`} />\n <span className={`${styles.drift} ${styles.driftTwo}`} />\n <span className={`${styles.drift} ${styles.driftThree}`} />\n <span className={`${styles.drift} ${styles.driftFour}`} />\n <span className={`${styles.drift} ${styles.driftFive}`} />\n </>\n )\n}\n",".anchor {\n position: absolute;\n top: 50%;\n left: var(--running-progress);\n}\n.body {\n position: absolute;\n inset: 0;\n animation: phased-marker 3.2s ease-in-out infinite alternate;\n animation-delay: var(--phased-marker-delay, 0s);\n will-change: transform;\n}\n@keyframes phased-marker {\n from {\n transform: translate(var(--phased-marker-travel, -10em), -50%);\n }\n to {\n transform: translate(-50%, -50%);\n }\n}\n@media (prefers-reduced-motion: reduce) {\n .body {\n animation: none;\n }\n}\n","import type { CSSProperties } from 'react'\nimport styles from './PhasedProgressMarker.module.css'\n\n/**\n * A progress-anchored decorative marker. The anchor owns live progress geometry; the body owns\n * its independent phase animation, so a timing render cannot replace its transform.\n */\nexport function PhasedProgressMarker({\n anchorClassName,\n bodyClassName,\n delay,\n anchorPart,\n bodyPart,\n}: {\n anchorClassName: string | undefined\n bodyClassName: string | undefined\n delay?: string\n anchorPart?: string\n bodyPart: string\n}) {\n const style = delay ? ({ '--phased-marker-delay': delay } as CSSProperties) : undefined\n return (\n <span className={`${styles.anchor} ${anchorClassName ?? ''}`} data-running-part={anchorPart}>\n <span\n className={`${styles.body} ${bodyClassName ?? ''}`}\n data-running-part={bodyPart}\n style={style}\n />\n </span>\n )\n}\n",".frontier {\n position: absolute;\n inset: 0 auto 0 0;\n width: var(--running-progress);\n background: linear-gradient(\n 90deg,\n color-mix(in srgb, currentColor 16%, transparent),\n transparent\n );\n border-right: 1px solid color-mix(in srgb, currentColor 75%, transparent);\n}\n.flare {\n display: none;\n}\n.lanes {\n position: absolute;\n inset: 13% 7%;\n display: grid;\n align-content: space-between;\n}\n.lane {\n position: relative;\n height: 1px;\n background: linear-gradient(\n 90deg,\n transparent,\n color-mix(in srgb, var(--edge) 90%, transparent),\n transparent\n );\n}\n.markerAnchor {\n width: 0.42em;\n height: 0.25em;\n}\n.markerBody {\n --phased-marker-travel: -10cqw;\n border-radius: 999px;\n background: currentColor;\n box-shadow: 0 0 0.6em currentColor;\n}\n.lane:nth-child(2) .markerBody {\n opacity: 0.7;\n}\n.lane:nth-child(3) .markerBody {\n opacity: 0.5;\n}\n.lane:nth-child(4) .markerBody {\n opacity: 0.8;\n}\n@container running-field (max-width: 40rem) or (max-height: 6rem) {\n .lanes {\n display: none;\n }\n .frontier {\n width: 0.28em;\n border-right: 0;\n background: currentColor;\n }\n}\n[data-overdue=\"true\"] .frontier {\n width: 100%;\n background: linear-gradient(\n 90deg,\n color-mix(in srgb, currentColor 34%, transparent),\n transparent\n );\n border-right-color: currentColor;\n}\n[data-overdue=\"true\"] .flare {\n display: block;\n position: absolute;\n top: 0;\n left: 100%;\n width: 2.4em;\n height: 100%;\n background: radial-gradient(ellipse, currentColor 0, transparent 68%);\n transform: translateX(-50%);\n animation: bloom-flare 1.6s ease-in-out infinite alternate;\n}\n[data-overdue=\"true\"] .markerBody {\n --phased-marker-travel: -22.5cqw;\n animation-duration: 0.72s;\n animation-timing-function: ease-in-out;\n}\n@media (prefers-reduced-motion: reduce) {\n .frontier {\n transition: none;\n }\n [data-overdue=\"true\"] .flare,\n [data-overdue=\"true\"] .markerBody {\n animation: none;\n }\n}\n@keyframes bloom-flare {\n from {\n opacity: 0.42;\n transform: translateX(-50%) scale(0.8);\n }\n to {\n opacity: 0.95;\n transform: translateX(-50%) scale(1.15);\n }\n}\n","import { PhasedProgressMarker } from './PhasedProgressMarker.tsx'\nimport styles from './TelemetryBloomField.module.css'\n\nexport function TelemetryBloomField() {\n return (\n <>\n <span className={styles.frontier} data-running-part=\"frontier\" />\n <span className={styles.flare} data-running-part=\"bloom-flare\" />\n <span className={styles.lanes} data-running-part=\"bloom-lanes\">\n {[0, 1, 2, 3].map((lane) => (\n <span className={styles.lane} key={lane} data-running-part=\"bloom-lane\">\n <PhasedProgressMarker\n anchorClassName={styles.markerAnchor}\n bodyClassName={styles.markerBody}\n delay={[undefined, '-0.8s', '-1.7s', '-2.4s'][lane]}\n anchorPart=\"bloom-marker-anchor\"\n bodyPart=\"bloom-marker\"\n />\n </span>\n ))}\n </span>\n </>\n )\n}\n","import type { RunningAnimation } from '@ze-great-dashboard/shared'\nimport type { CSSProperties } from 'react'\nimport { FallingShapesField } from './FallingShapesField.tsx'\nimport { ReleaseTransitField } from './ReleaseTransitField.tsx'\nimport styles from './RunningField.module.css'\nimport { StatusWeatherField } from './StatusWeatherField.tsx'\nimport { TelemetryBloomField } from './TelemetryBloomField.tsx'\n\nexport type RunningFieldAnimation = Extract<\n RunningAnimation,\n 'telemetry-bloom' | 'release-transit' | 'status-weather' | 'falling-shapes'\n>\n\nexport function isRunningFieldAnimation(\n animation: Exclude<RunningAnimation, 'off'>,\n): animation is RunningFieldAnimation {\n return ['telemetry-bloom', 'release-transit', 'status-weather', 'falling-shapes'].includes(\n animation,\n )\n}\n\nexport function RunningField({\n animation,\n progress,\n estimatedDurationMs,\n overdue,\n indeterminate,\n seed,\n}: {\n animation: RunningFieldAnimation\n progress: number\n estimatedDurationMs?: number\n overdue: boolean\n indeterminate: boolean\n seed?: number\n}) {\n const style = {\n '--running-progress': `${progress * 100}%`,\n } as CSSProperties\n return (\n <div\n className={`${styles.field} ${overdue ? styles.overdue : ''}`}\n data-animation={animation}\n data-running-field\n data-overdue={overdue || undefined}\n data-indeterminate={indeterminate || undefined}\n aria-hidden=\"true\"\n style={style}\n >\n {animation === 'telemetry-bloom' && <TelemetryBloomField />}\n {animation === 'release-transit' && <ReleaseTransitField />}\n {animation === 'status-weather' && <StatusWeatherField />}\n {animation === 'falling-shapes' && (\n <FallingShapesField\n progress={progress}\n estimatedDurationMs={estimatedDurationMs}\n overdue={overdue}\n seed={seed}\n />\n )}\n </div>\n )\n}\n","import { useEffect, useState } from 'react'\n\nconst VISUAL_TICK_MS = 20\n\nexport type RunningTiming = {\n elapsedMs: number | undefined\n estimatedDurationMs: number | undefined\n hasEstimate: boolean\n overdue: boolean\n progress: number\n}\n\nexport function useRunningTiming(\n runStartedAt?: string,\n estimatedDurationMs?: number,\n): RunningTiming {\n const now = useClock(Boolean(runStartedAt))\n const startedAt = runStartedAt ? new Date(runStartedAt).valueOf() : Number.NaN\n const elapsedMs = Number.isFinite(startedAt) ? Math.max(0, now - startedAt) : undefined\n const hasEstimate = elapsedMs !== undefined && estimatedDurationMs !== undefined\n const overdue = hasEstimate && elapsedMs > estimatedDurationMs\n const progress = hasEstimate ? Math.min(elapsedMs / estimatedDurationMs, 1) : 0\n return { elapsedMs, estimatedDurationMs, hasEstimate, overdue, progress }\n}\n\nfunction useClock(enabled: boolean) {\n const [now, setNow] = useState(() => Date.now())\n useEffect(() => {\n if (!enabled) return\n setNow(Date.now())\n // The timing text rounds to seconds, but progress gets display-cadence intermediate positions.\n // This avoids the visible sawtooth created by a coarse timer and CSS transition.\n const interval = window.setInterval(() => setNow(Date.now()), VISUAL_TICK_MS)\n return () => window.clearInterval(interval)\n }, [enabled])\n return now\n}\n\nexport function timingDescription(\n elapsedMs: number | undefined,\n estimatedDurationMs: number | undefined,\n overdue: boolean,\n) {\n const elapsed =\n elapsedMs === undefined ? 'Run in progress' : `Elapsed ${formatDuration(elapsedMs)}`\n const expected =\n estimatedDurationMs === undefined\n ? 'Expected duration unavailable'\n : `Expected ≈ ${formatDuration(estimatedDurationMs)}`\n return `${elapsed} · ${expected}${overdue ? ' · Over estimate' : ''}`\n}\n\nexport function compactTiming(\n elapsedMs: number | undefined,\n estimatedDurationMs: number | undefined,\n overdue: boolean,\n) {\n const elapsed = elapsedMs === undefined ? '—' : formatClockDuration(elapsedMs)\n const expected =\n estimatedDurationMs === undefined ? '?' : `~${formatClockDuration(estimatedDurationMs)}`\n return `${overdue ? '⚠' : '\\u00a0'}${elapsed}/${expected}`\n}\n\nfunction formatDuration(durationMs: number) {\n const totalSeconds = Math.floor(durationMs / 1_000)\n const hours = Math.floor(totalSeconds / 3_600)\n const minutes = Math.floor((totalSeconds % 3_600) / 60)\n const seconds = totalSeconds % 60\n if (hours > 0) return `${hours}h ${minutes}m`\n if (minutes > 0) return `${minutes}m ${seconds}s`\n return `${seconds}s`\n}\n\nfunction formatClockDuration(durationMs: number) {\n const totalSeconds = Math.floor(durationMs / 1_000)\n const hours = Math.floor(totalSeconds / 3_600)\n const minutes = Math.floor((totalSeconds % 3_600) / 60)\n const seconds = totalSeconds % 60\n const clock = `${minutes}:${String(seconds).padStart(2, '0')}`\n return hours > 0 ? `${hours}:${clock.padStart(5, '0')}` : clock\n}\n","import styles from './RunningField.module.css'\nimport { compactTiming, timingDescription } from './running-timing.ts'\n\n/** The sole readable timing projection for panel-scale decorative fields. */\nexport function RunningFieldTiming({\n elapsedMs,\n estimatedDurationMs,\n overdue,\n}: {\n elapsedMs: number | undefined\n estimatedDurationMs: number | undefined\n overdue: boolean\n}) {\n return (\n <p className={`${styles.timing} ${overdue ? styles.timingOverdue : ''}`}>\n <span className=\"screen-reader-only\">\n {timingDescription(elapsedMs, estimatedDurationMs, overdue)}\n </span>\n <span aria-hidden=\"true\">{compactTiming(elapsedMs, estimatedDurationMs, overdue)}</span>\n </p>\n )\n}\n",".progress {\n display: flex;\n align-items: center;\n gap: 0.6em;\n min-width: 0;\n color: var(--status-warning);\n}\n.visual {\n position: relative;\n flex: 0 0 auto;\n}\n.timing {\n margin: 0;\n color: var(--ink-secondary);\n font-size: 0.72em;\n}\n.overdue {\n color: var(--status-serious);\n}\n.overdue .timing {\n color: var(--status-serious);\n}\n.readout {\n width: 12ch;\n flex: 0 0 12ch;\n font-family: ui-monospace, SFMono-Regular, Menlo, monospace;\n font-variant-numeric: tabular-nums;\n text-align: end;\n white-space: nowrap;\n}\n.radial .visual {\n width: 2.35em;\n height: 2.35em;\n border: 0.14em solid var(--edge);\n border-radius: 50%;\n background: conic-gradient(var(--status-warning) var(--running-progress), var(--edge) 0);\n box-shadow:\n inset 0 0 0 0.22em var(--surface-raised),\n 0 0 0.55em color-mix(in srgb, var(--status-warning) 45%, transparent);\n}\n.radial .visual::after {\n content: \"\";\n position: absolute;\n inset: -0.14em;\n border-radius: 50%;\n border-top: 0.14em solid var(--status-warning);\n animation: sweep 1.7s linear infinite;\n}\n.overdue.radial .visual::before {\n content: \"\";\n position: absolute;\n inset: -0.42em;\n border: 0.1em solid var(--status-serious);\n border-radius: 50%;\n box-shadow: 0 0 0.55em color-mix(in srgb, var(--status-serious) 65%, transparent);\n animation: alarm-ring 1.8s ease-in-out infinite;\n}\n.radialCore {\n position: absolute;\n inset: 0.68em;\n border-radius: 50%;\n background: var(--status-warning);\n box-shadow: 0 0 0.45em var(--status-warning);\n}\n.overdue .radialCore {\n background: var(--status-serious);\n box-shadow: 0 0 0.55em var(--status-serious);\n animation: reactor-breathe 1.8s ease-in-out infinite alternate;\n}\n.runway {\n display: grid;\n grid-template-columns: minmax(0, 1fr) auto;\n align-self: stretch;\n container-type: inline-size;\n}\n.runway .visual {\n width: min(12em, 100%);\n max-width: 100%;\n height: 0.8em;\n overflow: hidden;\n border: 1px solid var(--edge);\n border-radius: 999px;\n background: linear-gradient(90deg, var(--status-warning) var(--running-progress), var(--edge) 0);\n}\n.runway .visual::after {\n content: \"\";\n position: absolute;\n top: -0.25em;\n bottom: -0.25em;\n left: calc(var(--running-progress) - 0.06em);\n width: 0.12em;\n background: var(--ink-primary);\n box-shadow: 0 0 0.45em var(--ink-primary);\n}\n.overdue.runway .visual::before {\n content: \"\";\n position: absolute;\n inset: -0.2em 0;\n left: calc(100% - 0.55em);\n width: 0.55em;\n background: repeating-linear-gradient(\n -45deg,\n var(--status-serious) 0 0.12em,\n var(--surface) 0.12em 0.24em\n );\n box-shadow: 0 0 0.5em color-mix(in srgb, var(--status-serious) 70%, transparent);\n animation: barrier-pulse 1.4s ease-in-out infinite alternate;\n}\n.overdue.runway .visual::after {\n background: var(--status-serious);\n box-shadow: 0 0 0.55em var(--status-serious);\n animation: barrier-pulse 1.4s ease-in-out infinite alternate;\n}\n.spark {\n position: absolute;\n top: 50%;\n left: -0.5em;\n width: 0.35em;\n height: 0.35em;\n border-radius: 50%;\n background: var(--ink-primary);\n box-shadow: 0 0 0.4em var(--status-warning);\n animation: spark 1.5s linear infinite;\n}\n.overdue.runway .spark {\n animation-duration: 1s;\n}\n.sparkTwo {\n display: none;\n animation-delay: -0.5s;\n}\n.overdue.runway .sparkTwo {\n display: block;\n}\n.orbit .visual {\n width: 2.4em;\n height: 2.4em;\n border: 1px solid var(--edge);\n border-radius: 50%;\n}\n/* biome-ignore lint/style/noDescendingSpecificity: the radial overdue ring precedes this separate legacy treatment. */\n.orbit .visual::before {\n content: \"\";\n position: absolute;\n inset: 0.18em;\n border: 0.12em solid transparent;\n border-top-color: var(--status-warning);\n border-radius: 50%;\n transform: rotate(var(--running-degrees));\n}\n.orbitCore {\n position: absolute;\n inset: 0.75em;\n border-radius: 50%;\n background: var(--status-warning);\n box-shadow: 0 0 0.45em var(--status-warning);\n}\n.overdue .orbitCore {\n background: var(--status-serious);\n box-shadow: 0 0 0.55em var(--status-serious);\n animation: reactor-breathe 1.15s ease-in-out infinite alternate;\n}\n.particle {\n position: absolute;\n top: 0.25em;\n left: calc(50% - 0.16em);\n width: 0.32em;\n height: 0.32em;\n border-radius: 50%;\n background: var(--ink-primary);\n transform-origin: 0.16em 0.95em;\n animation: orbit 1.8s linear infinite;\n}\n.particleTwo {\n animation-delay: -0.9s;\n background: var(--status-warning);\n}\n.overdue.orbit .visual::after {\n content: \"\";\n position: absolute;\n inset: 0.42em;\n border: 0.08em solid color-mix(in srgb, var(--status-serious) 75%, transparent);\n border-radius: 50%;\n box-shadow: 0 0 0.6em color-mix(in srgb, var(--status-serious) 55%, transparent);\n animation: gravity-well 1.15s ease-in-out infinite alternate;\n}\n.overdue.orbit .particle {\n transform-origin: 0.16em 0.7em;\n animation-duration: 0.95s;\n}\n.indeterminate .visual {\n background-image: repeating-linear-gradient(\n 135deg,\n color-mix(in srgb, var(--status-warning) 70%, transparent) 0 0.25em,\n var(--edge) 0.25em 0.5em\n );\n animation: shift 1s linear infinite;\n}\n.signalField {\n container-type: size;\n display: grid;\n grid-template-columns: minmax(0, 1fr) auto;\n align-self: stretch;\n flex: 1 1 auto;\n min-height: 0;\n max-height: 100%;\n}\n.signalField .visual {\n width: auto;\n height: 1em;\n max-height: 100%;\n overflow: hidden;\n border: 1px solid var(--edge);\n border-radius: 999px;\n background: var(--surface);\n}\n.rail {\n position: absolute;\n inset: 0;\n background: linear-gradient(90deg, var(--status-warning) var(--running-progress), var(--edge) 0);\n opacity: 0.75;\n}\n.lead {\n position: absolute;\n top: -0.2em;\n bottom: -0.2em;\n left: calc(var(--running-progress) - 0.08em);\n width: 0.16em;\n border-radius: 999px;\n background: var(--ink-primary);\n box-shadow: 0 0 0.5em var(--status-warning);\n}\n.pulse {\n position: absolute;\n top: 50%;\n left: -0.5em;\n width: 0.3em;\n height: 0.3em;\n border-radius: 50%;\n background: var(--ink-primary);\n box-shadow: 0 0 0.4em var(--status-warning);\n animation: pulse 2.4s ease-in-out infinite alternate;\n}\n.pulseTwo {\n animation-delay: -1.2s;\n}\n.tracks {\n display: none;\n}\n@container panel (min-width: 26rem) {\n .runway .visual {\n flex: 1 1 auto;\n width: auto;\n height: clamp(1.1em, 7cqw, 2.7em);\n box-shadow: inset 0 0 1em color-mix(in srgb, var(--status-warning) 16%, transparent);\n }\n .runway .visual::after {\n left: calc(var(--running-progress) - 0.08em);\n width: 0.16em;\n }\n .spark {\n animation-name: sparkWide;\n }\n}\n@container panel (max-width: 18rem) {\n .signalField {\n flex: 0 1 auto;\n min-height: 0;\n }\n .signalField .visual {\n width: 2.65em;\n height: 1.15em;\n }\n .signalField .rail {\n background: var(--edge);\n }\n .signalField .lead {\n top: 0.2em;\n bottom: 0.2em;\n width: 0.38em;\n border-radius: 50%;\n }\n .pulse {\n display: none;\n }\n}\n@container panel (max-height: 5rem) {\n .signalField {\n flex: 0 1 auto;\n min-height: 0;\n }\n .signalField .visual {\n width: 2.65em;\n height: 1.15em;\n }\n .signalField .rail {\n background: var(--edge);\n }\n .signalField .lead {\n top: 0.2em;\n bottom: 0.2em;\n width: 0.38em;\n border-radius: 50%;\n }\n .pulse {\n display: none;\n }\n}\n/* A size-contained signal field cannot use its own intrinsic height as a query input: its\n auto-sized content would always satisfy the compact branch. Width is the stable panel-scale\n discriminator; the field's parent already controls its available height. */\n@container panel (min-width: 26rem) {\n .signalField .visual {\n height: 100%;\n min-height: 0;\n border-radius: 0.25em;\n background: linear-gradient(\n 180deg,\n color-mix(in srgb, var(--edge) 60%, transparent),\n transparent\n );\n }\n .signalField .visual::before {\n content: \"\";\n position: absolute;\n inset: 0 auto 0 0;\n width: var(--running-progress);\n background:\n repeating-linear-gradient(\n 0deg,\n transparent 0 0.55em,\n color-mix(in srgb, var(--status-warning) 16%, transparent) 0.55em 0.6em\n ),\n linear-gradient(\n 90deg,\n color-mix(in srgb, var(--status-warning) 19%, transparent),\n color-mix(in srgb, var(--status-warning) 7%, transparent)\n );\n box-shadow: inset -0.8em 0 1em color-mix(in srgb, var(--status-warning) 22%, transparent);\n }\n .signalField .rail {\n top: 50%;\n bottom: auto;\n height: 1px;\n }\n .signalField .lead {\n top: calc(50% - 0.45em);\n bottom: auto;\n height: 0.9em;\n }\n .pulse {\n display: none;\n }\n .tracks {\n position: absolute;\n inset: 0.8em 0;\n display: flex;\n flex-direction: column;\n justify-content: space-between;\n }\n .track {\n position: relative;\n height: 1px;\n background: linear-gradient(\n 90deg,\n transparent,\n color-mix(in srgb, var(--edge) 85%, transparent),\n transparent\n );\n }\n .markerAnchor {\n width: 0.38em;\n height: 0.22em;\n }\n .markerBody {\n border-radius: 0.06em;\n background: var(--status-warning);\n box-shadow: 0 0 0.4em var(--status-warning);\n }\n .track:nth-child(2) .markerBody {\n animation-delay: -0.8s;\n opacity: 0.7;\n }\n .track:nth-child(3) .markerBody {\n animation-delay: -1.7s;\n opacity: 0.45;\n }\n .track:nth-child(4) .markerBody {\n animation-delay: -2.4s;\n opacity: 0.7;\n }\n .track:nth-child(5) .markerBody {\n animation-delay: -0.35s;\n opacity: 0.55;\n }\n}\n.overdue.signalField .rail {\n background: linear-gradient(90deg, var(--status-serious) 0 100%);\n opacity: 0.42;\n}\n.overdue.signalField .lead {\n background: var(--status-serious);\n box-shadow: 0 0 0.7em var(--status-serious);\n animation: endpoint-pulse 1.2s ease-in-out infinite alternate;\n}\n.overdue.signalField .markerBody {\n --phased-marker-travel: -10em;\n background: var(--status-serious);\n box-shadow: 0 0 0.55em var(--status-serious);\n animation-duration: 0.68s;\n animation-timing-function: ease-in-out;\n}\n.short .signalField .visual {\n height: 1em;\n}\n@keyframes sweep {\n to {\n transform: rotate(360deg);\n }\n}\n@keyframes alarm-ring {\n from {\n transform: scale(0.92);\n opacity: 0.45;\n }\n to {\n transform: scale(1.08);\n opacity: 1;\n }\n}\n@keyframes reactor-breathe {\n from {\n transform: scale(0.84);\n opacity: 0.7;\n }\n to {\n transform: scale(1.12);\n opacity: 1;\n }\n}\n@keyframes barrier-pulse {\n from {\n opacity: 0.55;\n }\n to {\n opacity: 1;\n }\n}\n@keyframes gravity-well {\n from {\n transform: scale(0.82);\n opacity: 0.45;\n }\n to {\n transform: scale(1.08);\n opacity: 0.95;\n }\n}\n@keyframes endpoint-pulse {\n from {\n transform: scaleY(0.75);\n opacity: 0.65;\n }\n to {\n transform: scaleY(1.15);\n opacity: 1;\n }\n}\n@keyframes spark {\n to {\n transform: translateX(13em);\n }\n}\n@keyframes sparkWide {\n to {\n transform: translateX(100cqw);\n }\n}\n@keyframes orbit {\n to {\n transform: rotate(360deg);\n }\n}\n@keyframes shift {\n to {\n background-position: 1em 0;\n }\n}\n@keyframes pulse {\n from {\n transform: translate(-0.5em, -50%);\n }\n to {\n transform: translate(calc(var(--running-progress) + 0.5em), -50%);\n }\n}\n@media (prefers-reduced-motion: reduce) {\n .radial .visual::after,\n .overdue.radial .visual::before,\n .overdue .radialCore,\n .spark,\n .runway .visual::after,\n .overdue.runway .visual::before,\n .overdue.runway .visual::after,\n .particle,\n .overdue.orbit .visual::after,\n .pulse,\n .lead,\n .overdue.signalField .lead,\n .overdue.signalField .markerBody,\n /* biome-ignore lint/style/noDescendingSpecificity: the shared reduced-motion list intentionally follows themed overrides. */\n .signalField .visual::before,\n .indeterminate .visual {\n animation: none;\n }\n}\n","import type { RunningAnimation } from '@ze-great-dashboard/shared'\nimport type { CSSProperties } from 'react'\nimport { PhasedProgressMarker } from './PhasedProgressMarker.tsx'\nimport styles from './RunningProgress.module.css'\nimport { compactTiming, type RunningTiming, timingDescription } from './running-timing.ts'\n\nexport function RunningProgress({\n animation,\n timing,\n}: {\n animation: LegacyRunningAnimation\n timing: RunningTiming\n}) {\n const { elapsedMs, estimatedDurationMs, hasEstimate, overdue, progress } = timing\n const usesReadout = animation === 'runway' || animation === 'signal-field'\n const timingText = timingDescription(elapsedMs, estimatedDurationMs, overdue)\n const style = {\n '--running-progress': `${progress * 100}%`,\n '--running-degrees': `${progress * 360}deg`,\n } as CSSProperties\n const animationStyle = animation === 'signal-field' ? styles.signalField : styles[animation]\n\n return (\n <div\n className={`${styles.progress} ${animationStyle} ${overdue ? styles.overdue : ''} ${hasEstimate ? '' : styles.indeterminate}`}\n style={style}\n data-running-progress={animation}\n data-overdue={overdue || undefined}\n data-indeterminate={!hasEstimate || undefined}\n >\n <div className={styles.visual} aria-hidden=\"true\" data-running-visual>\n {animation === 'radial' && <span className={styles.radialCore} />}\n {animation === 'runway' && (\n <>\n <span className={styles.spark} data-running-part=\"runway-spark\" />\n <span\n className={`${styles.spark} ${styles.sparkTwo}`}\n data-running-part=\"runway-spark-two\"\n />\n </>\n )}\n {animation === 'orbit' && (\n <>\n <span className={styles.orbitCore} />\n <span className={styles.particle} />\n <span className={`${styles.particle} ${styles.particleTwo}`} />\n </>\n )}\n {animation === 'signal-field' && (\n <>\n <span className={styles.rail} />\n <span className={styles.lead} />\n <span className={styles.pulse} />\n <span className={`${styles.pulse} ${styles.pulseTwo}`} />\n <span className={styles.tracks} data-running-part=\"signal-tracks\">\n {[0, 1, 2, 3, 4].map((track) => (\n <span className={styles.track} key={track} data-running-part=\"signal-track\">\n <PhasedProgressMarker\n anchorClassName={styles.markerAnchor}\n bodyClassName={styles.markerBody}\n delay={[undefined, '-0.8s', '-1.7s', '-2.4s', '-0.35s'][track]}\n anchorPart=\"signal-marker-anchor\"\n bodyPart=\"signal-marker\"\n />\n </span>\n ))}\n </span>\n </>\n )}\n </div>\n <p className={`${styles.timing} ${usesReadout ? styles.readout : ''}`}>\n {usesReadout ? (\n <>\n <span className=\"screen-reader-only\">{timingText}</span>\n <span aria-hidden=\"true\">{compactTiming(elapsedMs, estimatedDurationMs, overdue)}</span>\n </>\n ) : (\n timingText\n )}\n </p>\n </div>\n )\n}\n\n/** The compact, inline treatments retained for existing boards. */\nexport type LegacyRunningAnimation = Extract<\n RunningAnimation,\n 'radial' | 'runway' | 'orbit' | 'signal-field'\n>\n\nexport function isLegacyRunningAnimation(\n animation: RunningAnimation,\n): animation is LegacyRunningAnimation {\n return ['radial', 'runway', 'orbit', 'signal-field'].includes(animation)\n}\n","import { type Panel, parseDuration } from '@ze-great-dashboard/shared'\nimport { useEffect, useState } from 'react'\nimport { fallingSeed } from './falling-shapes.ts'\nimport { PanelFrame, PanelStatus } from './PanelFrame.tsx'\nimport styles from './PipelineAnimationDemoPanel.module.css'\nimport { isRunningFieldAnimation, RunningField } from './RunningField.tsx'\nimport { RunningFieldTiming } from './RunningFieldTiming.tsx'\nimport { RunningProgress } from './RunningProgress.tsx'\nimport { useRunningTiming } from './running-timing.ts'\n\nconst DEFAULT_RUN_DURATION_MS = 20_000\nconst ESTIMATED_DURATION_MS = 15_000\nconst DEFAULT_REVIEW_DURATION_MS = 300_000\nconst REVIEW_CYCLE_MULTIPLIER = 1.25\nconst variants = [\n 'radial',\n 'runway',\n 'orbit',\n 'signal-field',\n 'telemetry-bloom',\n 'release-transit',\n 'status-weather',\n 'falling-shapes',\n] as const\n\n/**\n * A local comparison aid for the active-run treatments. It deliberately creates no signal or\n * diagnostic evidence: its state is derived only from the wall clock and repeats forever.\n */\nexport function PipelineAnimationDemoPanel({ panel }: { panel: Panel }) {\n const now = useClock()\n // A configured visible treatment turns the local comparison aid into a stable review panel.\n // `off` retains the rotating default: the demo exists to render a treatment.\n const fixedAnimation =\n panel.running_animation === undefined || panel.running_animation === 'off'\n ? undefined\n : panel.running_animation\n const runDurationMs = durationMillis(panel.demo_run_duration, DEFAULT_RUN_DURATION_MS)\n const reviewDurationMs = durationMillis(panel.demo_review_duration, DEFAULT_REVIEW_DURATION_MS)\n const durationMs = fixedAnimation\n ? Math.ceil(reviewDurationMs * REVIEW_CYCLE_MULTIPLIER)\n : runDurationMs\n const runNumber = Math.floor(now / durationMs)\n const animation = fixedAnimation ?? variants[runNumber % variants.length] ?? 'radial'\n const runStartedAt = runNumber * durationMs\n\n return (\n <DemoRun\n panel={panel}\n animation={animation}\n runStartedAt={runStartedAt}\n estimatedDurationMs={fixedAnimation ? reviewDurationMs : ESTIMATED_DURATION_MS}\n />\n )\n}\n\nfunction durationMillis(value: Panel['demo_run_duration'], fallback: number): number {\n if (!value) return fallback\n return parseDuration(value) ?? fallback\n}\n\nfunction DemoRun({\n panel,\n animation,\n runStartedAt,\n estimatedDurationMs,\n}: {\n panel: Panel\n animation: (typeof variants)[number]\n runStartedAt: number\n estimatedDurationMs: number\n}) {\n const startedAt = new Date(runStartedAt).toISOString()\n const timing = useRunningTiming(startedAt, estimatedDurationMs)\n const usesField = isRunningFieldAnimation(animation)\n return (\n <PanelFrame\n panel={panel}\n field={\n usesField ? (\n <RunningField\n key={`${animation}-${runStartedAt}`}\n animation={animation}\n progress={timing.progress}\n estimatedDurationMs={timing.estimatedDurationMs}\n overdue={timing.overdue}\n indeterminate={!timing.hasEstimate}\n seed={fallingSeed(panel.id)}\n />\n ) : undefined\n }\n >\n <PanelStatus status=\"running\">↻ Running</PanelStatus>\n <p className={styles.variant}>Demo treatment · {animation}</p>\n {usesField ? (\n <RunningFieldTiming\n elapsedMs={timing.elapsedMs}\n estimatedDurationMs={estimatedDurationMs}\n overdue={timing.overdue}\n />\n ) : (\n <RunningProgress animation={animation} timing={timing} />\n )}\n </PanelFrame>\n )\n}\n\nfunction useClock() {\n const [now, setNow] = useState(() => Date.now())\n useEffect(() => {\n const interval = window.setInterval(() => setNow(Date.now()), 1_000)\n return () => window.clearInterval(interval)\n }, [])\n return now\n}\n",".details {\n display: contents;\n}\n.details > :global(.hint) {\n line-height: 1.1;\n}\n.activity,\n.duration {\n overflow-wrap: anywhere;\n}\n@container panel (min-width: 48rem) {\n :global([data-density=\"comfortable\"][data-shallow=\"true\"]) .details > *,\n :global([data-density=\"auto\"][data-shallow=\"true\"]) .details > * {\n margin: 0;\n }\n}\n","import type { PipelineStatus } from '@ze-great-dashboard/shared'\n\nexport type PanelStatusKind = PipelineStatus['status']\n\nexport function statusPresentation(status: PanelStatusKind, passedLabel = 'Passed') {\n switch (status) {\n case 'passed':\n return { glyph: '✓', label: passedLabel }\n case 'failed':\n return { glyph: '✕', label: 'Failed' }\n case 'running':\n return { glyph: '↻', label: 'Running' }\n case 'cancelled':\n return { glyph: '⊘', label: 'Cancelled' }\n case 'unknown':\n return { glyph: '?', label: 'Unknown' }\n }\n}\n","import type { PipelineActivity } from '@ze-great-dashboard/shared'\n\nexport function formatPipelineActivity(activity: PipelineActivity | undefined) {\n if (!activity) return 'Activity unavailable'\n return activity.parent ? `${activity.parent} › ${activity.name}` : activity.name\n}\n","import {\n type Envelope,\n type Panel,\n type PipelineStatus,\n pipelineStatusSchema,\n type RunningAnimation,\n visibleRunningAnimations,\n} from '@ze-great-dashboard/shared'\nimport { useRef, useState } from 'react'\nimport { fallingSeed } from './falling-shapes.ts'\nimport { PanelFrame, PanelHint, PanelMetadata, PanelStatus } from './PanelFrame.tsx'\nimport styles from './PipelinePanel.module.css'\nimport type { PanelProps } from './panel-props.ts'\nimport { statusPresentation } from './panel-status.ts'\nimport { formatPipelineActivity } from './pipeline-activity.ts'\nimport { isRunningFieldAnimation, RunningField } from './RunningField.tsx'\nimport { RunningFieldTiming } from './RunningFieldTiming.tsx'\nimport { isLegacyRunningAnimation, RunningProgress } from './RunningProgress.tsx'\nimport { useRunningTiming } from './running-timing.ts'\nimport { CheckedAt, RunAge } from './TimeAge.tsx'\n\nexport function PipelinePanel({ panel, envelope, checkedAt }: PanelProps) {\n if (!envelope)\n return (\n <PanelFrame panel={panel}>\n <PanelHint>Loading…</PanelHint>\n </PanelFrame>\n )\n if (envelope.state === 'error') {\n return (\n <PanelFrame panel={panel} envelope={envelope} error>\n <PanelStatus>\n ⚠ {envelope.error.kind === 'no-runs' ? 'No workflow runs' : 'Unable to read'}\n </PanelStatus>\n <PanelHint>{envelope.error.message}</PanelHint>\n {checkedAt && <CheckedAt value={checkedAt} />}\n </PanelFrame>\n )\n }\n\n const signal = pipelineStatusSchema.safeParse(envelope.signal)\n if (!signal.success)\n return (\n <PanelFrame panel={panel} envelope={envelope} error>\n <PanelStatus>⚠ Invalid signal</PanelStatus>\n {checkedAt && <CheckedAt value={checkedAt} />}\n </PanelFrame>\n )\n return (\n <PipelineSignalPanel\n panel={panel}\n envelope={envelope}\n signal={signal.data}\n checkedAt={checkedAt}\n />\n )\n}\n\nfunction PipelineSignalPanel({\n panel,\n envelope,\n signal,\n checkedAt,\n}: {\n panel: Panel\n envelope: Envelope\n signal: PipelineStatus\n checkedAt?: string\n}) {\n const presentation = statusPresentation(signal.status)\n const [defaultAnimation, setDefaultAnimation] = useState<RunningAnimation | undefined>(() =>\n signal.status === 'running' ? selectDefaultRunningAnimation() : undefined,\n )\n const previousStatusRef = useRef(signal.status)\n if (signal.status !== previousStatusRef.current) {\n const wasRunning = previousStatusRef.current === 'running'\n previousStatusRef.current = signal.status\n if (panel.running_animation === undefined && !wasRunning && signal.status === 'running') {\n setDefaultAnimation((previousAnimation) => selectDefaultRunningAnimation(previousAnimation))\n }\n }\n const animation = panel.running_animation ?? defaultAnimation ?? 'off'\n const activeRun = signal.status === 'running' && animation !== 'off'\n const timing = useRunningTiming(signal.runStartedAt, signal.estimatedDurationMs)\n const usesField = activeRun && isRunningFieldAnimation(animation)\n const usesLegacyProgress = activeRun && isLegacyRunningAnimation(animation)\n return (\n <PanelFrame\n panel={panel}\n envelope={envelope}\n field={\n usesField ? (\n <RunningField\n animation={animation}\n progress={timing.progress}\n estimatedDurationMs={timing.estimatedDurationMs}\n overdue={timing.overdue}\n indeterminate={!timing.hasEstimate}\n seed={fallingSeed(panel.id)}\n />\n ) : undefined\n }\n >\n <div className={styles.details}>\n <PanelStatus status={signal.status}>\n {presentation.glyph} {presentation.label}\n </PanelStatus>\n {signal.status === 'running' && (\n <PanelMetadata\n glyph=\"⚙\"\n label=\"Activity\"\n value={formatPipelineActivity(signal.activity)}\n title={`Activity: ${formatPipelineActivity(signal.activity)}`}\n className={styles.activity}\n />\n )}\n {signal.branch && (\n <PanelMetadata\n glyph=\"⎇\"\n label=\"Branch\"\n value={<span className={styles.branch}>{signal.branch}</span>}\n title={`Branch: ${signal.branch}`}\n />\n )}\n {usesField && (\n <RunningFieldTiming\n elapsedMs={timing.elapsedMs}\n estimatedDurationMs={signal.estimatedDurationMs}\n overdue={timing.overdue}\n />\n )}\n {usesLegacyProgress && <RunningProgress animation={animation} timing={timing} />}\n {signal.status !== 'running' && signal.durationMs !== undefined && (\n <PanelMetadata\n glyph=\"◷\"\n label=\"Duration\"\n value={`Took ${formatDuration(signal.durationMs)}`}\n title={`Duration: Took ${formatDuration(signal.durationMs)}`}\n className={styles.duration}\n />\n )}\n {((signal.status === 'running' && signal.runStartedAt) || signal.sourceUpdatedAt) && (\n <RunAge\n value={\n signal.status === 'running' && signal.runStartedAt\n ? signal.runStartedAt\n : (signal.sourceUpdatedAt ?? envelope.observedAt)\n }\n running={signal.status === 'running'}\n />\n )}\n {checkedAt && <CheckedAt value={checkedAt} />}\n </div>\n </PanelFrame>\n )\n}\n\nfunction selectDefaultRunningAnimation(previousAnimation?: RunningAnimation) {\n const candidates = visibleRunningAnimations.filter((animation) => animation !== previousAnimation)\n return candidates[Math.floor(Math.random() * candidates.length)] ?? 'telemetry-bloom'\n}\n\nfunction formatDuration(durationMs: number) {\n const totalSeconds = Math.floor(durationMs / 1_000)\n const hours = Math.floor(totalSeconds / 3_600)\n const minutes = Math.floor((totalSeconds % 3_600) / 60)\n const seconds = totalSeconds % 60\n\n if (hours > 0) return `${hours}h ${minutes}m`\n if (minutes > 0) return `${minutes}m ${seconds}s`\n return `${seconds}s`\n}\n",".compactFacts {\n display: none;\n min-width: 0;\n flex-direction: column;\n gap: 0.1em;\n overflow: hidden;\n}\n\n.compactFact {\n min-width: 0;\n margin: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.compactPrimary {\n color: var(--ink-primary);\n font-size: 0.85em;\n font-weight: 600;\n}\n\n.compactSecondary {\n color: var(--ink-muted);\n font-size: 0.7em;\n}\n\n@container panel (max-width: 13rem) {\n :global([data-density=\"compact\"]) .compactFacts {\n display: flex;\n }\n\n :global([data-density=\"compact\"]) .fullSummary {\n position: absolute;\n width: 1px;\n height: 1px;\n padding: 0;\n margin: -1px;\n overflow: hidden;\n clip: rect(0, 0, 0, 0);\n white-space: nowrap;\n border: 0;\n }\n}\n\n@container panel (max-width: 13rem) and (max-height: 10rem) {\n :global([data-density=\"compact\"]) .compactFacts ~ :global([data-panel-meta]) {\n display: none;\n }\n}\n","export function formatCount(count: number, singular: string, plural = `${singular}s`) {\n return `${count} ${count === 1 ? singular : plural}`\n}\n","import type { PullRequestHealth } from '@ze-great-dashboard/shared'\nimport { formatCount } from './panel-formatting.ts'\n\nexport type PullRequestHealthCompactFacts = {\n primary: string\n secondary: string\n primaryDetail?: string\n title: string\n}\n\n/**\n * Keep the wall-facing version of this aggregate signal short without making the\n * server's prose summary part of the client contract.\n */\nexport function compactPullRequestHealthFacts(\n signal: PullRequestHealth,\n): PullRequestHealthCompactFacts {\n const failedItem = [...signal.workflows, ...signal.pullRequests].find(\n (item) => item.status === 'failed',\n )\n\n if (failedItem) {\n return {\n primary: `${failedItem.label} failed`,\n secondary: `${formatCount(signal.workflows.length, 'workflow')} · ${formatCount(signal.pullRequests.length, 'open PR')}`,\n primaryDetail: failedItem.detail,\n title: `${signal.summary} — ${failedItem.label}: ${failedItem.detail}`,\n }\n }\n\n return {\n primary: formatCount(signal.workflows.length, 'workflow'),\n secondary: formatCount(signal.pullRequests.length, 'open PR'),\n title: signal.summary,\n }\n}\n","import { pullRequestHealthSchema } from '@ze-great-dashboard/shared'\nimport { PanelFrame, PanelHint, PanelStatus } from './PanelFrame.tsx'\nimport styles from './PullRequestHealthPanel.module.css'\nimport type { PanelProps } from './panel-props.ts'\nimport { statusPresentation } from './panel-status.ts'\nimport { compactPullRequestHealthFacts } from './pull-request-health.ts'\nimport { CheckedAt } from './TimeAge.tsx'\n\nexport function PullRequestHealthPanel({ panel, envelope, checkedAt }: PanelProps) {\n if (!envelope)\n return (\n <PanelFrame panel={panel}>\n <PanelHint>Loading…</PanelHint>\n </PanelFrame>\n )\n if (envelope.state === 'error')\n return (\n <PanelFrame panel={panel} envelope={envelope} error>\n <PanelStatus>⚠ Unable to read</PanelStatus>\n <PanelHint>{envelope.error.message}</PanelHint>\n {checkedAt && <CheckedAt value={checkedAt} />}\n </PanelFrame>\n )\n const signal = pullRequestHealthSchema.safeParse(envelope.signal)\n if (!signal.success)\n return (\n <PanelFrame panel={panel} envelope={envelope} error>\n <PanelStatus>⚠ Invalid signal</PanelStatus>\n </PanelFrame>\n )\n const presentation = statusPresentation(signal.data.status, 'Healthy')\n const compactFacts = compactPullRequestHealthFacts(signal.data)\n return (\n <PanelFrame panel={panel} envelope={envelope}>\n <PanelStatus status={signal.data.status}>\n {presentation.glyph} {presentation.label}\n </PanelStatus>\n <PanelHint className={styles.fullSummary} title={signal.data.summary}>\n {signal.data.summary}\n </PanelHint>\n <div className={styles.compactFacts} title={compactFacts.title} data-compact-facts>\n <p\n className={`${styles.compactFact} ${styles.compactPrimary}`}\n title={compactFacts.primaryDetail}\n >\n {compactFacts.primary}\n </p>\n <p className={`${styles.compactFact} ${styles.compactSecondary}`}>\n {compactFacts.secondary}\n </p>\n </div>\n {checkedAt && <CheckedAt value={checkedAt} />}\n </PanelFrame>\n )\n}\n","import type { ComponentType } from 'react'\nimport { HttpValuePanel } from './HttpValuePanel.tsx'\nimport { PanelPlaceholder } from './PanelPlaceholder.tsx'\nimport { PipelineAnimationDemoPanel } from './PipelineAnimationDemoPanel.tsx'\nimport { PipelinePanel } from './PipelinePanel.tsx'\nimport { PullRequestHealthPanel } from './PullRequestHealthPanel.tsx'\nimport type { PanelProps } from './panel-props.ts'\n\ntype PanelRendererProps = PanelProps\n\n/** The one client-side dispatch point for panel types. */\nexport const panelRenderers: Record<string, ComponentType<PanelRendererProps>> = {\n 'pipeline-status': PipelinePanel,\n 'pull-request-health': PullRequestHealthPanel,\n 'http-value': HttpValuePanel,\n 'pipeline-animation-demo': PipelineAnimationDemoPanel,\n}\n\nexport function PanelRenderer({ panel, envelope, checkedAt }: PanelRendererProps) {\n const Renderer = panelRenderers[panel.type]\n return Renderer ? (\n <Renderer panel={panel} envelope={envelope} checkedAt={checkedAt} />\n ) : (\n <PanelPlaceholder label={panel.type} hint=\"Not wired yet\" wide />\n )\n}\n","import { type ClientEnv, clientIdentitySchema } from '@ze-great-dashboard/shared'\nimport { useEffect } from 'react'\nimport type { DiagnosticSink } from './diagnostics.ts'\n\nconst clientUpdateIntervalMillis = 60_000\nconst clientUpdateTimeoutMillis = 10_000\nconst defaultReload = () => globalThis.window.location.reload()\n\nexport function useClientUpdate({\n env,\n diagnostics,\n fetcher,\n reload = defaultReload,\n}: {\n env: ClientEnv\n diagnostics: DiagnosticSink\n fetcher?: typeof fetch\n reload?: () => void\n}) {\n useEffect(() => {\n let cancelled = false\n let inFlight = false\n let activeController: AbortController | undefined\n const path = `${env.proxyPath}/client`\n\n const check = async () => {\n if (cancelled || inFlight) return\n inFlight = true\n const controller = new AbortController()\n activeController = controller\n const timeout = globalThis.setTimeout(() => controller.abort(), clientUpdateTimeoutMillis)\n diagnostics.record({ kind: 'client-update-check', path })\n try {\n const response = await (fetcher ?? globalThis.fetch)(path, {\n cache: 'no-store',\n signal: controller.signal,\n })\n if (!response.ok) throw new Error(`Client identity returned ${response.status}`)\n const parsed = clientIdentitySchema.safeParse(await response.json())\n if (!parsed.success) throw new Error('Client identity response was invalid')\n if (cancelled) return\n // assetPath is the server's immutable deployment selector. clientVersion is a label and\n // can change independently without changing the code the browser should load.\n if (parsed.data.assetPath !== env.assetPath) {\n diagnostics.record({\n kind: 'client-update-detected',\n path,\n current: { assetPath: env.assetPath, clientVersion: env.clientVersion },\n next: parsed.data,\n })\n reload()\n }\n } catch (error) {\n if (!cancelled && !(error instanceof DOMException && error.name === 'AbortError')) {\n diagnostics.record({\n kind: 'client-update-failure',\n path,\n message: error instanceof Error ? error.message : String(error),\n })\n }\n } finally {\n globalThis.clearTimeout(timeout)\n inFlight = false\n if (activeController === controller) activeController = undefined\n if (!cancelled) globalThis.setTimeout(() => void check(), clientUpdateIntervalMillis)\n }\n }\n\n void check()\n return () => {\n cancelled = true\n activeController?.abort()\n }\n }, [diagnostics, env.assetPath, env.clientVersion, env.proxyPath, fetcher, reload])\n}\n","import {\n type Envelope,\n type Panel,\n pipelineStatusSchema,\n pullRequestHealthSchema,\n} from '@ze-great-dashboard/shared'\nimport type { RenderedPanelDiagnostic } from './diagnostics.ts'\n\n/**\n * The compact public fact a viewer saw. Keep new panel projections here beside their\n * presentation boundary; this is intentionally not a source or server event contract.\n */\nexport function projectPanelDiagnostic(panel: Panel, envelope: Envelope): RenderedPanelDiagnostic {\n if (envelope.state === 'error') return { state: envelope.state, link: envelope.link }\n\n if (panel.type === 'pipeline-status') {\n const signal = pipelineStatusSchema.safeParse(envelope.signal)\n return {\n state: envelope.state,\n status: signal.success ? signal.data.status : undefined,\n link: envelope.link,\n }\n }\n\n if (panel.type === 'pull-request-health') {\n const signal = pullRequestHealthSchema.safeParse(envelope.signal)\n return {\n state: envelope.state,\n status: signal.success ? signal.data.status : undefined,\n link: envelope.link,\n }\n }\n\n return { state: envelope.state, link: envelope.link }\n}\n\nexport function panelDiagnosticChanged(\n previous: Envelope | undefined,\n panel: Panel,\n next: Envelope,\n) {\n if (!previous) return true\n const before = projectPanelDiagnostic(panel, previous)\n const after = projectPanelDiagnostic(panel, next)\n return (\n before.state !== after.state || before.status !== after.status || before.link !== after.link\n )\n}\n","import type { Panel, PipelineStatus } from '@ze-great-dashboard/shared'\nimport { browserLocalStorage, readBrowserJson, writeBrowserJson } from './browser-storage.ts'\n\nconst storageKey = 'ze-great-dashboard.panel-memory.v1'\nconst schemaVersion = 1\nconst historyWindowMillis = 14 * 24 * 60 * 60 * 1_000\n\nexport type PanelMemoryIdentity = {\n board: string\n panelId: string\n source: string\n workflow: string\n branch: string\n}\n\nexport type AcceptedPipeline = {\n sourceUpdatedAt: string\n status: PipelineStatus['status']\n link: string | null\n}\n\nexport type DurationSample = {\n link: string | null\n sourceRunId?: string\n durationMs: number\n sourceUpdatedAt: string\n}\ntype History = {\n latest?: AcceptedPipeline\n durations: Record<string, DurationSample>\n latestCompleted?: DurationSample\n}\ntype StoredMemory = { schemaVersion: number; histories: Record<string, History> }\ntype StorageLike = Pick<Storage, 'getItem' | 'setItem'>\n\nexport class BrowserPanelMemory {\n private histories: Record<string, History>\n private readonly storage: StorageLike | undefined\n\n constructor(\n storage: StorageLike | undefined = browserLocalStorage(),\n private readonly now: () => Date = () => new Date(),\n ) {\n this.storage = storage\n this.histories = this.read()\n this.pruneAll()\n }\n\n latest(identity: PanelMemoryIdentity): AcceptedPipeline | undefined {\n return this.history(identity).latest\n }\n\n rememberLatest(identity: PanelMemoryIdentity, latest: AcceptedPipeline) {\n this.history(identity).latest = latest\n this.persist()\n }\n\n recordRun(identity: PanelMemoryIdentity, sample: DurationSample, successful = false) {\n const history = this.history(identity)\n if (successful) history.durations[sampleKey(sample)] = sample\n const previous = history.latestCompleted\n if (!previous || isAtLeastAsRecent(sample.sourceUpdatedAt, previous.sourceUpdatedAt)) {\n history.latestCompleted = sample\n }\n this.pruneHistory(history)\n this.persist()\n }\n\n recordSuccessfulRun(identity: PanelMemoryIdentity, sample: DurationSample) {\n this.recordRun(identity, sample, true)\n }\n\n recordCompletedRun(identity: PanelMemoryIdentity, sample: DurationSample) {\n this.recordRun(identity, sample)\n }\n\n medianDuration(identity: PanelMemoryIdentity): number | undefined {\n const history = this.history(identity)\n this.pruneHistory(history)\n const durations = Object.values(history.durations)\n .map(({ durationMs }) => durationMs)\n .sort((left, right) => left - right)\n if (durations.length === 0) return undefined\n const middle = Math.floor(durations.length / 2)\n if (durations.length % 2 === 1) return durations[middle]\n const lower = durations[middle - 1]\n const upper = durations[middle]\n return lower === undefined || upper === undefined ? undefined : Math.floor((lower + upper) / 2)\n }\n\n resolveEstimatedDuration(identity: PanelMemoryIdentity): number | undefined {\n const successful = this.medianDuration(identity)\n if (successful !== undefined) return successful\n\n const history = this.history(identity)\n this.pruneHistory(history)\n return history.latestCompleted?.durationMs\n }\n\n private history(identity: PanelMemoryIdentity) {\n const key = identityKey(identity)\n const existing = this.histories[key]\n if (existing) return existing\n const created: History = { durations: {} }\n this.histories[key] = created\n return created\n }\n\n private pruneAll() {\n for (const history of Object.values(this.histories)) this.pruneHistory(history)\n this.persist()\n }\n\n private pruneHistory(history: History) {\n const cutoff = this.now().valueOf() - historyWindowMillis\n for (const [link, sample] of Object.entries(history.durations)) {\n const at = sourceTimestamp(sample.sourceUpdatedAt)\n if (at === undefined || at < cutoff) delete history.durations[link]\n }\n const latestCompletedAt = history.latestCompleted\n ? sourceTimestamp(history.latestCompleted.sourceUpdatedAt)\n : undefined\n if (\n history.latestCompleted &&\n (latestCompletedAt === undefined || latestCompletedAt < cutoff)\n ) {\n delete history.latestCompleted\n }\n }\n\n private read(): Record<string, History> {\n const parsed = readBrowserJson<Partial<StoredMemory>>(this.storage, storageKey)\n if (parsed?.schemaVersion !== schemaVersion || !parsed.histories) return {}\n return isHistories(parsed.histories) ? parsed.histories : {}\n }\n\n private persist() {\n writeBrowserJson(this.storage, storageKey, { schemaVersion, histories: this.histories })\n }\n}\n\nfunction sampleKey(sample: DurationSample) {\n return sample.sourceRunId ?? sample.link ?? sample.sourceUpdatedAt\n}\n\nfunction isAtLeastAsRecent(left: string, right: string) {\n const leftAt = sourceTimestamp(left)\n const rightAt = sourceTimestamp(right)\n return leftAt !== undefined && (rightAt === undefined || leftAt >= rightAt)\n}\n\nfunction sourceTimestamp(value: string) {\n const timestamp = Date.parse(value)\n return Number.isFinite(timestamp) ? timestamp : undefined\n}\n\nexport function resolvePanelMemoryIdentity(board: string, panel: Panel): PanelMemoryIdentity {\n return {\n board,\n panelId: panel.id,\n source: panel.source ?? '',\n workflow:\n typeof panel.pipeline === 'string' || typeof panel.pipeline === 'number'\n ? String(panel.pipeline)\n : '',\n branch: panel.branch ?? '',\n }\n}\n\nfunction identityKey(identity: PanelMemoryIdentity) {\n return JSON.stringify([\n identity.board,\n identity.panelId,\n identity.source,\n identity.workflow,\n identity.branch,\n ])\n}\n\nfunction isHistories(value: unknown): value is Record<string, History> {\n if (!isRecord(value)) return false\n return Object.values(value).every(isHistory)\n}\n\nfunction isHistory(value: unknown): value is History {\n if (!isRecord(value) || !isRecord(value.durations)) return false\n if (!Object.values(value.durations).every(isDurationSample)) return false\n return value.latestCompleted === undefined || isDurationSample(value.latestCompleted)\n}\n\nfunction isDurationSample(value: unknown): value is DurationSample {\n if (!isRecord(value)) return false\n return (\n (typeof value.link === 'string' || value.link === null) &&\n (value.sourceRunId === undefined || typeof value.sourceRunId === 'string') &&\n typeof value.durationMs === 'number' &&\n Number.isInteger(value.durationMs) &&\n value.durationMs >= 0 &&\n typeof value.sourceUpdatedAt === 'string' &&\n sourceTimestamp(value.sourceUpdatedAt) !== undefined\n )\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return !!value && typeof value === 'object' && !Array.isArray(value)\n}\n","import type { Envelope, PipelineStatus } from '@ze-great-dashboard/shared'\nimport { pipelineStatusSchema } from '@ze-great-dashboard/shared'\nimport type { AcceptedPipeline } from './panel-memory.ts'\n\nexport type PipelineDurationSample = {\n link: string | null\n sourceRunId?: string\n durationMs: number\n sourceUpdatedAt: string\n}\n\nexport type PipelineReconciliation =\n | { kind: 'not-pipeline'; envelope: Envelope }\n | {\n kind: 'rejected'\n envelope: Extract<Envelope, { state: 'ok' }>\n signal: PipelineStatus & { sourceUpdatedAt: string }\n }\n | {\n kind: 'accepted'\n envelope: Envelope\n signal: PipelineStatus\n accepted?: AcceptedPipeline\n durationSample?: PipelineDurationSample\n }\n\nexport function reconcilePipelineResponse(args: {\n envelope: Envelope\n accepted?: AcceptedPipeline\n estimatedDurationMs?: number\n}): PipelineReconciliation {\n const signal = pipelineStatus(args.envelope)\n if (!signal) return { kind: 'not-pipeline', envelope: args.envelope }\n if (\n args.accepted &&\n signal.sourceUpdatedAt &&\n Date.parse(signal.sourceUpdatedAt) < Date.parse(args.accepted.sourceUpdatedAt)\n ) {\n if (args.envelope.state !== 'ok' || !signal.sourceUpdatedAt)\n return { kind: 'not-pipeline', envelope: args.envelope }\n return {\n kind: 'rejected',\n envelope: args.envelope,\n signal: { ...signal, sourceUpdatedAt: signal.sourceUpdatedAt },\n }\n }\n\n const accepted = signal.sourceUpdatedAt\n ? { sourceUpdatedAt: signal.sourceUpdatedAt, status: signal.status, link: args.envelope.link }\n : undefined\n const durationSample =\n signal.status !== 'running' &&\n signal.durationMs !== undefined &&\n signal.sourceUpdatedAt &&\n Number.isFinite(Date.parse(signal.sourceUpdatedAt))\n ? {\n link: args.envelope.link,\n ...(signal.sourceRunId ? { sourceRunId: signal.sourceRunId } : {}),\n durationMs: signal.durationMs,\n sourceUpdatedAt: signal.sourceUpdatedAt,\n }\n : undefined\n const envelope =\n signal.status === 'running' &&\n args.estimatedDurationMs !== undefined &&\n args.envelope.state === 'ok'\n ? { ...args.envelope, signal: { ...signal, estimatedDurationMs: args.estimatedDurationMs } }\n : args.envelope\n return { kind: 'accepted', envelope, signal, accepted, durationSample }\n}\n\nexport function pipelineStatus(envelope: Envelope): PipelineStatus | undefined {\n if (envelope.state !== 'ok') return undefined\n const result = pipelineStatusSchema.safeParse(envelope.signal)\n return result.success ? result.data : undefined\n}\n","import {\n type Envelope,\n type PipelineStatus,\n type PollingSettings,\n pipelineStatusSchema,\n} from '@ze-great-dashboard/shared'\n\n/** Return the next delay for a panel, keeping active runs responsive without polling forever at burst speed. */\nexport function nextPollDelayMillis(\n envelope: Envelope | undefined,\n nowMillis: number,\n settings: PollingSettings,\n): number {\n const pipeline = runningPipeline(envelope)\n if (!pipeline) return settings.refreshMillis\n\n const completionAt = estimatedCompletionAt(pipeline)\n if (completionAt === undefined) return settings.runningRefreshMillis\n\n if (nowMillis < completionAt) {\n return Math.min(settings.runningRefreshMillis, completionAt - nowMillis)\n }\n if (nowMillis < completionAt + settings.runningCompletionWindowMillis) {\n return settings.runningCompletionRefreshMillis\n }\n return settings.runningRefreshMillis\n}\n\nfunction runningPipeline(envelope: Envelope | undefined): PipelineStatus | undefined {\n if (envelope?.state !== 'ok') return undefined\n const result = pipelineStatusSchema.safeParse(envelope.signal)\n return result.success && result.data.status === 'running' ? result.data : undefined\n}\n\nfunction estimatedCompletionAt(signal: PipelineStatus): number | undefined {\n if (!signal.runStartedAt || signal.estimatedDurationMs === undefined) return undefined\n const startedAt = Date.parse(signal.runStartedAt)\n return Number.isFinite(startedAt) ? startedAt + signal.estimatedDurationMs : undefined\n}\n","import {\n type Board,\n type ClientEnv,\n type Envelope,\n envelopeSchema,\n isZeroPosition,\n resolvePollingSettings,\n} from '@ze-great-dashboard/shared'\nimport { useEffect, useRef, useState } from 'react'\nimport { cacheMetadata, type DiagnosticSink } from './diagnostics.ts'\nimport { panelDiagnosticChanged, projectPanelDiagnostic } from './panel-diagnostics.ts'\nimport { BrowserPanelMemory, resolvePanelMemoryIdentity } from './panel-memory.ts'\nimport { reconcilePipelineResponse } from './pipeline-reconciliation.ts'\nimport { nextPollDelayMillis } from './polling-schedule.ts'\n\nexport function usePanelSignals({\n board,\n env,\n diagnostics,\n memory,\n}: {\n board: Board | undefined\n env: ClientEnv\n diagnostics: DiagnosticSink\n memory?: BrowserPanelMemory\n}) {\n const [signals, setSignals] = useState<Record<string, Envelope | undefined>>({})\n const [checkedAt, setCheckedAt] = useState<Record<string, string | undefined>>({})\n const signalsRef = useRef<Record<string, Envelope | undefined>>({})\n const memoryRef = useRef<BrowserPanelMemory | null>(null)\n if (!memoryRef.current) memoryRef.current = memory ?? new BrowserPanelMemory()\n\n useEffect(() => {\n signalsRef.current = {}\n setSignals({})\n setCheckedAt({})\n if (!board) return\n\n let cancelled = false\n const timers = new Set<number>()\n for (const panel of board.panels) {\n if (isZeroPosition(panel.position)) continue\n if (\n panel.type !== 'pipeline-status' &&\n panel.type !== 'pull-request-health' &&\n panel.type !== 'http-value'\n )\n continue\n let inFlight = false\n const memory = memoryRef.current\n if (!memory) return\n const settings = resolvePollingSettings(board, panel)\n const path = `${env.proxyPath}/panel/${encodeURIComponent(env.board)}/${encodeURIComponent(panel.id)}`\n let lastEnvelope: Envelope | undefined\n const refresh = () => {\n if (cancelled || inFlight) return\n inFlight = true\n diagnostics.record({ kind: 'panel-fetch-start', panelId: panel.id, path })\n fetch(path)\n .then(async (response) => {\n if (!cancelled) {\n setCheckedAt((current) => ({\n ...current,\n [panel.id]: new Date().toISOString(),\n }))\n }\n const transport = {\n kind: 'panel-fetch-response' as const,\n panelId: panel.id,\n path,\n status: response.status,\n cache: cacheMetadata(response.headers),\n }\n if (response.status === 304) {\n diagnostics.record(transport)\n return undefined\n }\n try {\n const value: unknown = await response.json()\n const envelope = parseEnvelope(value)\n if (!envelope) {\n diagnostics.record(transport)\n diagnostics.record({\n kind: 'panel-fetch-parse-failure',\n panelId: panel.id,\n path,\n message: 'Response was not a valid signal envelope.',\n })\n return undefined\n }\n diagnostics.record({ ...transport, envelope })\n return { envelope, cache: transport.cache, status: response.status }\n } catch (error) {\n diagnostics.record(transport)\n diagnostics.record({\n kind: 'panel-fetch-parse-failure',\n panelId: panel.id,\n path,\n message: errorMessage(error),\n })\n throw new DiagnosticParseFailure(error)\n }\n })\n .then((result) => {\n if (!result) return\n let envelope = result.envelope\n if (panel.type === 'pipeline-status') {\n const identity = resolvePanelMemoryIdentity(env.board, panel)\n const accepted = memory.latest(identity)\n const reconciliation = reconcilePipelineResponse({\n envelope,\n accepted,\n estimatedDurationMs: memory.resolveEstimatedDuration(identity),\n })\n if (reconciliation.kind === 'rejected' && accepted) {\n const signal = reconciliation.signal\n diagnostics.recordGithubConsistencyIncident({\n panelId: panel.id,\n endpoint: path,\n identity: {\n source: identity.source,\n workflow: identity.workflow,\n branch: identity.branch,\n },\n accepted,\n regressed: {\n sourceUpdatedAt: signal.sourceUpdatedAt,\n status: signal.status,\n link: envelope.link,\n },\n response: {\n httpStatus: result.status,\n date: result.cache?.date,\n etag: result.cache?.etag,\n cacheControl: result.cache?.cacheControl,\n },\n })\n return\n }\n if (reconciliation.kind === 'accepted') {\n envelope = reconciliation.envelope\n if (reconciliation.accepted)\n memory.rememberLatest(identity, reconciliation.accepted)\n if (reconciliation.durationSample) {\n const sample = {\n link: reconciliation.durationSample.link,\n ...(reconciliation.durationSample.sourceRunId\n ? { sourceRunId: reconciliation.durationSample.sourceRunId }\n : {}),\n durationMs: reconciliation.durationSample.durationMs,\n sourceUpdatedAt: reconciliation.durationSample.sourceUpdatedAt,\n }\n memory.recordRun(identity, sample, reconciliation.signal.status === 'passed')\n }\n }\n }\n lastEnvelope = envelope\n if (!cancelled) {\n const previous = signalsRef.current[panel.id]\n if (panelDiagnosticChanged(previous, panel, envelope)) {\n diagnostics.record({\n kind: 'panel-rendered',\n panelId: panel.id,\n path,\n rendered: projectPanelDiagnostic(panel, envelope),\n })\n }\n signalsRef.current = { ...signalsRef.current, [panel.id]: envelope }\n setSignals(signalsRef.current)\n }\n })\n .catch((error) => {\n if (!(error instanceof DiagnosticParseFailure)) {\n diagnostics.record({\n kind: 'panel-fetch-failure',\n panelId: panel.id,\n path,\n message: errorMessage(error),\n })\n }\n })\n .finally(() => {\n inFlight = false\n if (!cancelled) {\n const nextTimer = window.setTimeout(\n () => {\n timers.delete(nextTimer)\n refresh()\n },\n nextPollDelayMillis(lastEnvelope, Date.now(), settings),\n )\n timers.add(nextTimer)\n }\n })\n }\n refresh()\n }\n return () => {\n cancelled = true\n for (const timer of timers) window.clearTimeout(timer)\n }\n }, [board, diagnostics, env.board, env.proxyPath])\n\n return { signals, checkedAt }\n}\n\nfunction errorMessage(error: unknown) {\n return error instanceof Error ? error.message : String(error)\n}\n\nclass DiagnosticParseFailure extends Error {\n constructor(error: unknown) {\n super(errorMessage(error))\n }\n}\n\nfunction parseEnvelope(value: unknown): Envelope | undefined {\n const result = envelopeSchema.safeParse(value)\n return result.success ? result.data : undefined\n}\n","import {\n analyzeBoardLayout,\n type Board,\n type ClientEnv,\n isZeroPosition,\n} from '@ze-great-dashboard/shared'\nimport { useEffect, useMemo, useRef, useState } from 'react'\nimport styles from './App.module.css'\nimport { Diagnostics } from './Diagnostics.tsx'\nimport { BrowserDiagnosticStore, cacheMetadata } from './diagnostics.ts'\nimport { PanelPlaceholder } from './PanelPlaceholder.tsx'\nimport { PanelRenderer } from './panel-registry.tsx'\nimport { useClientUpdate } from './useClientUpdate.ts'\nimport { usePanelSignals } from './usePanelSignals.ts'\n\n/**\n * The board shell.\n *\n * Stage 1 has no data: there is no proxy endpoint to poll yet. What this proves is the plumbing —\n * that the client was handed its configuration by the server and knows which version of itself it\n * is. The version readout is what makes two published versions visibly different, which is the\n * whole point of the Stage 1 exit criterion.\n */\nexport function App({ env }: { env: ClientEnv }) {\n const [board, setBoard] = useState<Board>()\n const [loadedBoardName, setLoadedBoardName] = useState<string>()\n const diagnosticsRef = useRef<BrowserDiagnosticStore | null>(null)\n if (!diagnosticsRef.current) diagnosticsRef.current = new BrowserDiagnosticStore(env)\n const diagnostics = diagnosticsRef.current\n useClientUpdate({ env, diagnostics })\n const { signals, checkedAt } = usePanelSignals({\n board: loadedBoardName === env.board ? board : undefined,\n env,\n diagnostics,\n })\n const layout = useMemo(() => (board ? analyzeBoardLayout(board.panels) : undefined), [board])\n\n useEffect(() => {\n if (!layout || layout.issues.length === 0) return\n diagnostics.record({\n kind: 'layout-analyzed',\n issueCount: layout.issues.length,\n affectedPanelIds: layout.issues.map((issue) => issue.panelId),\n })\n }, [diagnostics, layout])\n\n useEffect(() => {\n let cancelled = false\n setBoard(undefined)\n setLoadedBoardName(undefined)\n const path = `${env.proxyPath}/boards/${encodeURIComponent(env.board)}`\n diagnostics.record({ kind: 'board-fetch-start', path })\n fetch(path)\n .then(async (response) => {\n diagnostics.record({\n kind: 'board-fetch-response',\n path,\n status: response.status,\n cache: cacheMetadata(response.headers),\n })\n if (!response.ok) throw new Error(`Board configuration returned ${response.status}`)\n try {\n return await response.json()\n } catch (error) {\n diagnostics.record({\n kind: 'board-fetch-parse-failure',\n path,\n message: errorMessage(error),\n })\n throw new DiagnosticParseFailure(error)\n }\n })\n .then((value: unknown) => {\n if (!cancelled) {\n setBoard(value as Board)\n setLoadedBoardName(env.board)\n const panels = Array.isArray((value as { panels?: unknown }).panels)\n ? (value as { panels: Array<{ id?: unknown }> }).panels\n : []\n diagnostics.record({\n kind: 'board-fetch-response',\n path,\n boardSummary: {\n panelCount: panels.length,\n panelIds: panels.flatMap((panel) => (typeof panel.id === 'string' ? [panel.id] : [])),\n },\n })\n }\n })\n .catch((error) => {\n if (!(error instanceof DiagnosticParseFailure)) {\n diagnostics.record({ kind: 'board-fetch-failure', path, message: errorMessage(error) })\n }\n if (!cancelled) {\n setBoard({ panels: [] })\n setLoadedBoardName(env.board)\n }\n })\n return () => {\n cancelled = true\n }\n }, [diagnostics, env.board, env.proxyPath])\n\n return (\n <div className={styles.board}>\n <header className={styles.header}>\n <h1 className={styles.title}>{env.board}</h1>\n </header>\n <main className={styles.grid}>\n {!board && <PanelPlaceholder label=\"board\" hint=\"Loading configuration…\" wide />}\n {board?.panels\n .filter((panel) => !isZeroPosition(panel.position))\n .map((panel) => (\n <PanelRenderer\n key={panel.id}\n panel={panel}\n envelope={signals[panel.id]}\n checkedAt={checkedAt[panel.id]}\n />\n ))}\n </main>\n\n <footer className={styles.footer} data-board-footer>\n <span>Signals are read live from their configured authorities.</span>\n <div className={styles.footerTools}>\n {layout && layout.issues.length > 0 && (\n <LayoutWarning board={env.board} layout={layout} proxyPath={env.proxyPath} />\n )}\n <Diagnostics log={diagnostics} />\n </div>\n </footer>\n </div>\n )\n}\n\nfunction LayoutWarning({\n board,\n layout,\n proxyPath,\n}: {\n board: string\n layout: ReturnType<typeof analyzeBoardLayout>\n proxyPath: string\n}) {\n const [open, setOpen] = useState(false)\n const dialogId = `layout-warning-${board}`\n\n useEffect(() => {\n if (!open) return\n const closeOnEscape = (event: KeyboardEvent) => {\n if (event.key === 'Escape') setOpen(false)\n }\n window.addEventListener('keydown', closeOnEscape)\n return () => window.removeEventListener('keydown', closeOnEscape)\n }, [open])\n\n const boardPath = `${proxyPath}/boards/${encodeURIComponent(board)}`\n return (\n <div className={styles.layoutWarning} data-layout-warning>\n <button\n className={styles.layoutWarningButton}\n type=\"button\"\n aria-label={`Layout warnings (${layout.issues.length})`}\n aria-expanded={open}\n aria-controls={dialogId}\n onClick={() => setOpen(!open)}\n >\n <span aria-hidden=\"true\">⚠</span>\n <span>{layout.issues.length}</span>\n </button>\n {open && (\n <aside\n className={styles.layoutWarningDialog}\n id={dialogId}\n role=\"dialog\"\n aria-labelledby={`${dialogId}-title`}\n aria-modal=\"false\"\n >\n <div className={styles.layoutWarningHeading}>\n <strong id={`${dialogId}-title`}>Layout warnings</strong>\n <button\n className={styles.layoutWarningClose}\n type=\"button\"\n aria-label=\"Close layout warnings\"\n onClick={() => setOpen(false)}\n >\n ×\n </button>\n </div>\n <p>\n {layout.issues.length} layout issue{layout.issues.length === 1 ? '' : 's'} detected\n against the intended 12×12 space. The live board is unchanged: explicit overlaps remain\n overlapped and overflow continues in implicit rows.\n </p>\n <ul>\n {layout.issues.map((issue) => (\n <li key={`${issue.panelId}-${issue.kind}`}>\n <strong>{issue.panelId}</strong>: {issue.kind} at ({issue.position.x},{' '}\n {issue.position.y}), {issue.position.w}×{issue.position.h}\n {issue.conflictsWith.length ? `; overlaps ${issue.conflictsWith.join(', ')}` : ''}\n </li>\n ))}\n </ul>\n <div className={styles.layoutWarningDownloads}>\n <a href={`${boardPath}/rendered`} download={`${board}-layout-rendered.yaml`}>\n Download legal rendered layout\n </a>\n <a href={`${boardPath}/authored`} download={`${board}-layout-authored.yaml`}>\n Download authored layout\n </a>\n </div>\n <p className={styles.layoutWarningNote}>\n The legal rendered layout normalizes the currently visible explicit area into 12×12 and\n makes the smallest deterministic adjustments needed to avoid collisions. The authored\n layout preserves the original coordinates exactly.\n </p>\n </aside>\n )}\n </div>\n )\n}\n\nfunction errorMessage(error: unknown) {\n return error instanceof Error ? error.message : String(error)\n}\n\nclass DiagnosticParseFailure extends Error {\n constructor(error: unknown) {\n super(errorMessage(error))\n }\n}\n",".error {\n margin: 0 auto;\n max-width: 60ch;\n padding: 2rem;\n color: var(--ink-primary);\n}\n.error pre {\n padding: 1rem;\n border-radius: var(--radius);\n border: 1px solid var(--status-critical);\n background: var(--surface-raised);\n color: var(--ink-secondary);\n font-size: 0.75em;\n white-space: pre-wrap;\n overflow-wrap: anywhere;\n}\n","import styles from './ConfigError.module.css'\n\nexport function ConfigError({ message }: { message: string }) {\n return (\n <div className={styles.error} role=\"alert\">\n <h1>⚠️ Dashboard misconfigured</h1>\n <p>The page loaded, but the server did not hand it usable configuration.</p>\n <pre>{message}</pre>\n </div>\n )\n}\n","import { readClientEnv } from '@ze-great-dashboard/shared'\nimport { StrictMode } from 'react'\nimport { createRoot } from 'react-dom/client'\nimport { App } from './App.tsx'\nimport { ConfigError } from './ConfigError.tsx'\nimport './styles.css'\n\nconst container = document.getElementById('root')\nif (!container) {\n throw new Error('No #root element in the document — the template is not the one we expect.')\n}\n\nconst root = createRoot(container)\n\ntry {\n root.render(\n <StrictMode>\n <App env={readClientEnv()} />\n </StrictMode>,\n )\n} catch (error) {\n // A radiator that fails silently is worse than one that says what's wrong. If configuration\n // never arrived, say so on screen rather than rendering an empty board.\n root.render(<ConfigError message={error instanceof Error ? error.message : String(error)} />)\n}\n"],"mappings":"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"}
|
package/dist/cli.js
CHANGED
|
@@ -197,9 +197,13 @@ var boardConfigSchema = z2.object({
|
|
|
197
197
|
// packages/shared/src/board-config-modeline.ts
|
|
198
198
|
var MODEL_LINE = /^# yaml-language-server:\s*\$schema=(\S+)\s*$/;
|
|
199
199
|
var SCHEMA_FILE = "board-config.schema.json";
|
|
200
|
-
function readBoardSchemaModeline(source) {
|
|
201
|
-
const line = source.split(/\r?\n/)
|
|
202
|
-
if (!line
|
|
200
|
+
function readBoardSchemaModeline(source, expectedSchemaUrl) {
|
|
201
|
+
const line = source.split(/\r?\n/)[0];
|
|
202
|
+
if (!line?.includes("yaml-language-server"))
|
|
203
|
+
throw new Error(
|
|
204
|
+
`Board configuration must include a ${SCHEMA_FILE} modeline. Add this as the first line:
|
|
205
|
+
# yaml-language-server: $schema=${expectedSchemaUrl ?? `https://<asset-host>/dashboard/<release-version>/${SCHEMA_FILE}`}`
|
|
206
|
+
);
|
|
203
207
|
const match = MODEL_LINE.exec(line);
|
|
204
208
|
if (!match?.[1]) {
|
|
205
209
|
throw new Error(
|
|
@@ -419,7 +423,7 @@ function clientAssetUrl(version, domain = CANONICAL_ASSET_DOMAIN) {
|
|
|
419
423
|
}
|
|
420
424
|
async function validateBoardConfig(path, expectedSchemaUrl) {
|
|
421
425
|
const source = await readFile(resolve(path), "utf8");
|
|
422
|
-
const authoredSchemaUrl = readBoardSchemaModeline(source);
|
|
426
|
+
const authoredSchemaUrl = readBoardSchemaModeline(source, expectedSchemaUrl);
|
|
423
427
|
const result = boardConfigSchema2.safeParse(parse(source));
|
|
424
428
|
if (!result.success) {
|
|
425
429
|
const stale = authoredSchemaUrl !== expectedSchemaUrl ? `
|
package/dist/index.js
CHANGED
|
@@ -879,9 +879,13 @@ var boardConfigSchema = z2.object({
|
|
|
879
879
|
// packages/shared/src/board-config-modeline.ts
|
|
880
880
|
var MODEL_LINE = /^# yaml-language-server:\s*\$schema=(\S+)\s*$/;
|
|
881
881
|
var SCHEMA_FILE = "board-config.schema.json";
|
|
882
|
-
function readBoardSchemaModeline(source) {
|
|
883
|
-
const line = source.split(/\r?\n/)
|
|
884
|
-
if (!line
|
|
882
|
+
function readBoardSchemaModeline(source, expectedSchemaUrl) {
|
|
883
|
+
const line = source.split(/\r?\n/)[0];
|
|
884
|
+
if (!line?.includes("yaml-language-server"))
|
|
885
|
+
throw new Error(
|
|
886
|
+
`Board configuration must include a ${SCHEMA_FILE} modeline. Add this as the first line:
|
|
887
|
+
# yaml-language-server: $schema=${expectedSchemaUrl ?? `https://<asset-host>/dashboard/<release-version>/${SCHEMA_FILE}`}`
|
|
888
|
+
);
|
|
885
889
|
const match = MODEL_LINE.exec(line);
|
|
886
890
|
if (!match?.[1]) {
|
|
887
891
|
throw new Error(
|
|
@@ -1101,7 +1105,7 @@ function clientAssetUrl(version, domain = CANONICAL_ASSET_DOMAIN) {
|
|
|
1101
1105
|
}
|
|
1102
1106
|
async function validateBoardConfig(path, expectedSchemaUrl) {
|
|
1103
1107
|
const source = await readFile(resolve(path), "utf8");
|
|
1104
|
-
const authoredSchemaUrl = readBoardSchemaModeline(source);
|
|
1108
|
+
const authoredSchemaUrl = readBoardSchemaModeline(source, expectedSchemaUrl);
|
|
1105
1109
|
const result = boardConfigSchema2.safeParse(parse(source));
|
|
1106
1110
|
if (!result.success) {
|
|
1107
1111
|
const stale = authoredSchemaUrl !== expectedSchemaUrl ? `
|
package/dist/lambda.mjs
CHANGED
|
@@ -64093,9 +64093,13 @@ var SCHEMA_FILE = "board-config.schema.json";
|
|
|
64093
64093
|
function schemaUrlForAssetPath(assetPath) {
|
|
64094
64094
|
return `${assetPath.replace(/\/+$/, "")}/${SCHEMA_FILE}`;
|
|
64095
64095
|
}
|
|
64096
|
-
function readBoardSchemaModeline(source) {
|
|
64097
|
-
const line = source.split(/\r?\n/)
|
|
64098
|
-
if (!line
|
|
64096
|
+
function readBoardSchemaModeline(source, expectedSchemaUrl) {
|
|
64097
|
+
const line = source.split(/\r?\n/)[0];
|
|
64098
|
+
if (!line?.includes("yaml-language-server"))
|
|
64099
|
+
throw new Error(
|
|
64100
|
+
`Board configuration must include a ${SCHEMA_FILE} modeline. Add this as the first line:
|
|
64101
|
+
# yaml-language-server: $schema=${expectedSchemaUrl ?? `https://<asset-host>/dashboard/<release-version>/${SCHEMA_FILE}`}`
|
|
64102
|
+
);
|
|
64099
64103
|
const match2 = MODEL_LINE.exec(line);
|
|
64100
64104
|
if (!match2?.[1]) {
|
|
64101
64105
|
throw new Error(
|
|
@@ -67306,7 +67310,7 @@ import { readFile as readFile3 } from "node:fs/promises";
|
|
|
67306
67310
|
var import_yaml2 = __toESM(require_dist(), 1);
|
|
67307
67311
|
async function loadBoardConfig(location, fetcher = globalThis.fetch, expectedSchemaUrl) {
|
|
67308
67312
|
const text = isUrl(location) ? await fetchBoardConfig(location, fetcher) : await readFile3(location, "utf-8");
|
|
67309
|
-
const authoredSchemaUrl = readBoardSchemaModeline(text);
|
|
67313
|
+
const authoredSchemaUrl = readBoardSchemaModeline(text, expectedSchemaUrl);
|
|
67310
67314
|
const result = boardConfigSchema.safeParse((0, import_yaml2.parse)(text));
|
|
67311
67315
|
if (!result.success) {
|
|
67312
67316
|
const stale = expectedSchemaUrl && authoredSchemaUrl !== expectedSchemaUrl ? `
|