@devicechain/widgets 0.21.1 → 0.22.0
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/README.md +28 -7
- package/dist/aggregate-feed.d.ts +14 -0
- package/dist/aggregate-fold.d.ts +11 -0
- package/dist/aggregate-reading.d.ts +19 -0
- package/dist/aggregate-strings.d.ts +16 -0
- package/dist/binding-policy.d.ts +3 -1
- package/dist/builtin-descriptors.d.ts +1210 -8
- package/dist/builtin-registry.d.ts +1197 -8
- package/dist/category-geometry.d.ts +19 -0
- package/dist/category-items.d.ts +10 -0
- package/dist/chunks/aggregate-feed-6ZYKOQOB.js +130 -0
- package/dist/chunks/aggregate-feed-6ZYKOQOB.js.map +7 -0
- package/dist/chunks/aggregate-widgets-WVXAW3UL.js +895 -0
- package/dist/chunks/aggregate-widgets-WVXAW3UL.js.map +7 -0
- package/dist/chunks/chunk-2D7JNKFE.js +65 -0
- package/dist/chunks/chunk-2D7JNKFE.js.map +7 -0
- package/dist/chunks/chunk-S2OMBJLI.js +200 -0
- package/dist/chunks/chunk-S2OMBJLI.js.map +7 -0
- package/dist/chunks/chunk-XQQQNTBX.js +76 -0
- package/dist/chunks/chunk-XQQQNTBX.js.map +7 -0
- package/dist/chunks/chunk-YPFB6DAL.js +157 -0
- package/dist/chunks/chunk-YPFB6DAL.js.map +7 -0
- package/dist/chunks/chunk-ZR74ORIT.js +35 -0
- package/dist/chunks/chunk-ZR74ORIT.js.map +7 -0
- package/dist/chunks/control-widgets-UDS4ET3T.js +775 -0
- package/dist/chunks/control-widgets-UDS4ET3T.js.map +7 -0
- package/dist/chunks/fleet-feed-FK4ZMKIK.js +252 -0
- package/dist/chunks/fleet-feed-FK4ZMKIK.js.map +7 -0
- package/dist/chunks/level-widgets-MJB7TOLU.js +833 -0
- package/dist/chunks/level-widgets-MJB7TOLU.js.map +7 -0
- package/dist/command-control-core.d.ts +68 -0
- package/dist/command-control-strings.d.ts +32 -0
- package/dist/command-control.d.ts +31 -0
- package/dist/dashboard-renderer.d.ts +15 -4
- package/dist/fleet-feed.d.ts +21 -0
- package/dist/fleet-model.d.ts +43 -0
- package/dist/fleet-seed.d.ts +7 -0
- package/dist/fleet-strings.d.ts +25 -0
- package/dist/heading.d.ts +3 -0
- package/dist/index.d.ts +3 -2
- package/dist/index.js +1774 -676
- package/dist/index.js.map +4 -4
- package/dist/level-reading.d.ts +29 -0
- package/dist/level-readout.d.ts +25 -0
- package/dist/level-strings.d.ts +13 -0
- package/dist/options.d.ts +1 -1
- package/dist/time-range-bar.d.ts +28 -0
- package/dist/use-held.d.ts +1 -0
- package/dist/value-scale.d.ts +30 -0
- package/dist/widgets/aggregate-lazy.d.ts +305 -0
- package/dist/widgets/aggregate-widgets.d.ts +4 -0
- package/dist/widgets/alarm-count.d.ts +1 -0
- package/dist/widgets/alarm-table.d.ts +4 -1
- package/dist/widgets/bar-chart.d.ts +5 -0
- package/dist/widgets/battery.d.ts +7 -0
- package/dist/widgets/command-slider.d.ts +2 -0
- package/dist/widgets/command-toggle.d.ts +4 -0
- package/dist/widgets/compass.d.ts +2 -0
- package/dist/widgets/control-lazy.d.ts +92 -0
- package/dist/widgets/control-widgets.d.ts +2 -0
- package/dist/widgets/fleet-table.d.ts +13 -0
- package/dist/widgets/gauge.d.ts +52 -0
- package/dist/widgets/label.d.ts +1 -1
- package/dist/widgets/latest-card.d.ts +44 -1
- package/dist/widgets/lazy-chunk.d.ts +8 -0
- package/dist/widgets/level-gauge.d.ts +2 -0
- package/dist/widgets/level-lazy.d.ts +647 -0
- package/dist/widgets/level-widgets.d.ts +7 -0
- package/dist/widgets/linear-gauge.d.ts +2 -0
- package/dist/widgets/pie-chart.d.ts +2 -0
- package/dist/widgets/progress-ring.d.ts +3 -0
- package/dist/widgets/severity.d.ts +2 -1
- package/dist/widgets/signal-bars.d.ts +3 -0
- package/dist/widgets/stat-card.d.ts +3 -0
- package/dist/widgets/status-light.d.ts +7 -0
- package/dist/widgets/table.d.ts +9 -1
- package/dist/widgets/time-series-chart.d.ts +62 -4
- package/package.json +8 -8
package/dist/index.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
|
-
"sources": ["../src/dashboard-renderer.tsx", "../src/connected-widget.tsx", "../src/
|
|
4
|
-
"sourcesContent": ["// Copyright The DeviceChain Authors\n// SPDX-License-Identifier: Apache-2.0\n\n// DashboardRenderer maps a parsed DashboardDefinition onto a real CSS Grid (ADR-039\n// amendment 2026-07-08): the canvas is `display:grid` with `repeat(columns, 1fr)`, so\n// the board FILLS whatever width its container gives it; each widget is placed by span\n// (`grid-column`/`grid-row`), layered by `z`, and nudged by an optional signed-pixel\n// `offset`. Container sizing (fill / fixed-width / fixed-height) is a mount knob the\n// host may override via the `sizing` prop. It is view-only \u2014 the canvas editor lives in\n// the console. This is the shared viewer the console and the reference /dash app mount.\n\nimport {\n activeBreakpoint,\n defaultHistoryWindow,\n fetchWidgetHistory,\n resolveWidgetBox,\n resolveWidgetDatasource,\n UNKNOWN_WIDGET_TYPE,\n type Breakpoints,\n type CanvasBackground,\n type CanvasSizing,\n type DashboardDefinition,\n type WidgetActions,\n type WidgetBox,\n type WidgetDataSource,\n type MeasurementSample,\n type SlotBinding,\n type WidgetInstance,\n} from '@devicechain/dashboards';\nimport type { WidgetRegistry } from '@devicechain/widget-sdk';\nimport { useEffect, useMemo, useRef, useState, type CSSProperties } from 'react';\n\nimport { ConnectedWidget } from './connected-widget';\nimport {\n type WidgetCandidates,\n WidgetCandidatesProvider,\n type WidgetSelect,\n WidgetSelectProvider,\n WidgetSubjectProvider,\n WidgetThemeRootProvider,\n WidgetTimeZoneProvider,\n} from '@devicechain/widget-sdk';\nimport { defaultWidgetRegistry } from './default-registry';\n\nexport interface DashboardRendererProps {\n definition: DashboardDefinition;\n hub: WidgetDataSource;\n // The widget registry that resolves every widget's component, channel, binding policy and\n // history eligibility. Omitted = the built-ins. A host with extension packages passes the\n // SAME registry it parsed `definition` with (parseDashboardDefinition(raw, { catalog:\n // registry.catalog })), so an extension widget is recognized and rendered consistently.\n registry?: WidgetRegistry;\n // The action seam (writes) for acting widgets (alarm ack/clear, command send). Omit\n // for a strictly read-only mount; the same instance as `hub` when the runtime provides\n // both (DashboardHub / SyntheticDataSource implement WidgetActions).\n actions?: WidgetActions;\n // Whether to backfill each widget from bucketedMeasurements (a real backend call).\n // Default true; set false for offline preview, where the data source (e.g.\n // SyntheticDataSource) supplies its own history and the backend must not be hit.\n seedHistory?: boolean;\n // The settled slot manifest (useResolvedBindings). Every widget's `slot` selector is\n // resolved through it HERE, before the widget subscribes, to the bound device or anchor\n // \u2014 or to an explicit `unbound` selector when the slot has no binding. The hub holds no\n // bindings, so a host keeps ONE hub (useDashboardHub) and a change to this map\n // re-subscribes only the widgets whose slot moved. Omitted = no slot is bound.\n bindings?: Record<string, SlotBinding>;\n // Host override for the definition's container sizing (the embed knob \u2014 a host can\n // force a dashboard authored `fill` into a fixed-px box, or vice versa). Omitted \u2192\n // the definition's own `canvas.sizing`.\n sizing?: CanvasSizing;\n // The selection callback (ADR-039 selection amendment): a widget (e.g. an alarm-table\n // originator drill) calls it to re-point a slot; the host accumulates it into the\n // selection overlay that produces `bindings`. Omit for a static dashboard \u2014 widgets\n // then render no drill affordance.\n select?: WidgetSelect;\n // The candidate provider (useSlotCandidates) an entity-selector widget reads to offer a\n // target slot's options. Omit alongside `select` for a static/edit/preview mount \u2014 the\n // selector then renders inert.\n candidates?: WidgetCandidates;\n // The IANA zone widgets print instants in. Omit for the viewer's own zone (every live\n // host); a host replaying a recording pins one so the board agrees with the recording.\n timeZone?: string;\n // The element chart colors are read from, when the host scopes its design tokens to a\n // container rather than the document root. Omit for the document root (every other host).\n themeRoot?: Element;\n}\n\nexport function DashboardRenderer({\n definition,\n hub,\n registry: registryProp,\n actions,\n seedHistory = true,\n bindings,\n sizing,\n select,\n candidates,\n timeZone,\n themeRoot,\n}: DashboardRendererProps) {\n const breakpoint = useActiveBreakpoint(definition.canvas.breakpoints);\n // Each widget with its slot resolved to a concrete selector. Recomputed per render;\n // that is cheap, and every channel keys its subscription on the selector's VALUE, so a\n // widget whose concrete selector did not change keeps its subscription.\n const widgets = useMemo(() => resolveWidgets(definition.widgets, bindings), [definition.widgets, bindings]);\n const registry = registryProp ?? defaultWidgetRegistry();\n const histories = useWidgetHistories(widgets, seedHistory, registry);\n\n const { grid, background: bg } = definition.canvas;\n const rowGap = typeof grid.gap === 'number' ? grid.gap : grid.gap.row;\n const colGap = typeof grid.gap === 'number' ? grid.gap : grid.gap.col;\n const effectiveSizing = sizing ?? definition.canvas.sizing;\n\n return (\n <div style={sizingStyle(effectiveSizing, bg)}>\n <WidgetThemeRootProvider root={themeRoot}>\n <WidgetTimeZoneProvider timeZone={timeZone}>\n <WidgetSelectProvider select={select}>\n <WidgetCandidatesProvider candidates={candidates}>\n <div\n style={{\n display: 'grid',\n gridTemplateColumns: `repeat(${grid.columns}, minmax(0, 1fr))`,\n gridAutoRows: `${grid.rowHeight}px`,\n columnGap: colGap,\n rowGap,\n width: '100%',\n }}\n >\n {widgets.map((widget) => {\n const box = resolveWidgetBox(widget.layout, breakpoint);\n return (\n <div key={widget.id} style={gridItemStyle(box, grid.columns)}>\n <WidgetSubjectProvider label={widgetSubjectLabel(widget)}>\n <ConnectedWidget\n widget={widget}\n hub={hub}\n registry={registry}\n actions={actions}\n initialSamples={histories[widget.id]}\n />\n </WidgetSubjectProvider>\n </div>\n );\n })}\n </div>\n </WidgetCandidatesProvider>\n </WidgetSelectProvider>\n </WidgetTimeZoneProvider>\n </WidgetThemeRootProvider>\n </div>\n );\n}\n\n// gridItemStyle maps a span box to a grid-item style. col/row are 0-based lines \u2192\n// CSS's 1-based `col+1 / span colSpan`. It CLAMPS the placement into the grid's\n// column count: a box whose `col`/`colSpan` overruns `columns` (a shrunk grid, a\n// hand-authored/overflowing stored box, a boundary-drag rounding edge) would\n// otherwise land in implicit `auto` tracks CSS appends past the `1fr` columns \u2014\n// unequal widths + horizontal overflow instead of a clamped placement. Rows are\n// unbounded (implicit rows are the intended vertical growth), so only columns clamp.\nexport function gridItemStyle(box: WidgetBox, columns: number): CSSProperties {\n const col = Math.min(Math.max(0, box.col), columns - 1);\n const colSpan = Math.min(Math.max(1, box.colSpan), columns - col);\n return {\n gridColumn: `${col + 1} / span ${colSpan}`,\n gridRow: `${box.row + 1} / span ${box.rowSpan}`,\n zIndex: box.z,\n transform: box.offset ? `translate(${box.offset.x}px, ${box.offset.y}px)` : undefined,\n // Let a grid item shrink below its content's intrinsic size so a wide chart/table\n // fits its track instead of overflowing it.\n minWidth: 0,\n minHeight: 0,\n };\n}\n\n// sizingStyle turns the container-sizing knob into the outer wrapper's box. `fill`\n// takes the mount container's full width+height (the grid fills it); `{width}` caps\n// the width (the fluid grid adjusts within it); `{height}` pins the height (rows\n// scroll). All scroll internally so the board owns its single scroll region. The\n// background (color AND image) paints on this wrapper so it covers the whole container\n// even when the grid's rows are shorter than the sizing box.\nexport function sizingStyle(sizing: CanvasSizing, bg: CanvasBackground | undefined): CSSProperties {\n const base: CSSProperties = {\n overflow: 'auto',\n backgroundColor: bg?.color ?? undefined,\n backgroundImage: bg?.imageUrl ? `url(${bg.imageUrl})` : undefined,\n backgroundSize: 'cover',\n };\n if (sizing === 'fill') return { ...base, width: '100%', height: '100%' };\n if ('width' in sizing) return { ...base, width: sizing.width, maxWidth: '100%', height: '100%' };\n return { ...base, width: '100%', height: sizing.height };\n}\n\n// resolveWidgets maps each widget's datasource through the settled bindings\n// (resolveWidgetDatasource): a slot becomes the device or anchor it is bound to, or an\n// explicit `unbound` selector. A widget with no datasource keeps none \u2014 that is a\n// different fact (tenant-wide on the alarm channel) and must not be manufactured here.\nexport function resolveWidgets(\n widgets: WidgetInstance[],\n bindings: Record<string, SlotBinding> | undefined,\n): WidgetInstance[] {\n return widgets.map((widget) => {\n if (widget.type === UNKNOWN_WIDGET_TYPE || widget.datasource?.kind !== 'slot') return widget;\n return { ...widget, datasource: resolveWidgetDatasource(widget.datasource, bindings) };\n });\n}\n\n// widgetSubjectLabel names the entity a widget shows \u2014 its CONCRETE datasource's device\n// or anchor \u2014 for the frame subtitle. Pass the widget as the renderer resolved it\n// (resolveWidgets), so the subtitle is read from the same selector the widget subscribes\n// with and can never name an entity other than the one being shown. Returns undefined for\n// a datasource-free widget (label/image, a tenant-wide alarm tile), an unbound slot, an\n// unresolved slot, or a reserved selector kind \u2014 the frame then shows no subtitle.\nexport function widgetSubjectLabel(widget: WidgetInstance): string | undefined {\n const ds = widget.datasource;\n if (!ds) return undefined;\n if (ds.kind === 'device') return ds.deviceToken || undefined;\n if (ds.kind === 'anchor') return ds.anchor.targetToken;\n return undefined;\n}\n\n// useActiveBreakpoint tracks the viewport width and returns the active breakpoint\n// name, recomputing on resize.\nfunction useActiveBreakpoint(breakpoints: Breakpoints): string {\n const [width, setWidth] = useState(() =>\n typeof window === 'undefined' ? 0 : window.innerWidth,\n );\n useEffect(() => {\n const onResize = () => setWidth(window.innerWidth);\n window.addEventListener('resize', onResize);\n return () => window.removeEventListener('resize', onResize);\n }, []);\n return activeBreakpoint(breakpoints, width);\n}\n\n// A widget's seed, tagged with the concrete selector it was fetched for.\ninterface Seed {\n key: string;\n samples: MeasurementSample[];\n}\n\n// seedKey is the identity of what a measurement widget's history is OF: its concrete\n// selector, by value. Undefined for a widget that takes no seed.\nfunction seedKey(widget: WidgetInstance, registry: WidgetRegistry): string | undefined {\n // Eligibility is registry metadata: only a registered measurement-channel widget takes a\n // seed. A placeholder, an unregistered id and every other channel take none.\n if (widget.type === UNKNOWN_WIDGET_TYPE || registry.descriptor(widget.type)?.channel !== 'measurement') {\n return undefined;\n }\n return JSON.stringify(widget.datasource ?? null);\n}\n\n// useWidgetHistories backfills each measurement widget from bucketedMeasurements and\n// returns an id\u2192samples map. Each seed is keyed by the widget's OWN concrete selector,\n// not by the board's bindings as a whole, so:\n//\n// - a selection that re-points one slot re-fetches only the widgets bound to it;\n// - a seed fetched for a selector the widget no longer has is DROPPED at render,\n// synchronously, so a widget never shows the previous device's history under the new\n// device while the new fetch is pending;\n// - a slow answer for a superseded selector is discarded when it lands.\n//\n// A widget's samples array is the one stored for its seed, so an unchanged seed keeps\n// its identity across renders and does not churn the stream's merge.\nfunction useWidgetHistories(\n widgets: WidgetInstance[],\n enabled: boolean,\n registry: WidgetRegistry,\n): Record<string, MeasurementSample[] | undefined> {\n const [seeds, setSeeds] = useState<Record<string, Seed>>({});\n // widget id \u2192 the selector key most recently REQUESTED for it. A fetch whose key is no\n // longer the requested one is stale when it lands.\n const requested = useRef<Record<string, string>>({});\n const mounted = useRef(true);\n useEffect(() => {\n mounted.current = true;\n return () => {\n mounted.current = false;\n };\n }, []);\n\n // The (id, key) pairs that want a seed; value-compared so an equal render is a no-op.\n const wanted = widgets.flatMap((w) => {\n const key = seedKey(w, registry);\n return key === undefined ? [] : [[w.id, key] as const];\n });\n const wantedKey = JSON.stringify(wanted);\n\n useEffect(() => {\n // Preview (enabled=false) must not touch the backend; clear any prior seed so a\n // toggle from live\u2192preview doesn't leave stale real history under synthetic data.\n if (!enabled) {\n requested.current = {};\n setSeeds({});\n return;\n }\n const historyWindow = defaultHistoryWindow();\n const byId = new Map(widgets.map((w) => [w.id, w]));\n const next: Record<string, string> = {};\n for (const [id, key] of wanted) {\n next[id] = key;\n if (requested.current[id] === key) continue; // already fetched (or in flight) for this selector\n const widget = byId.get(id);\n if (!widget) continue;\n void fetchWidgetHistory(widget, historyWindow).then((samples) => {\n if (!mounted.current || requested.current[id] !== key) return; // superseded or unmounted\n setSeeds((prev) => ({ ...prev, [id]: { key, samples } }));\n });\n }\n requested.current = next;\n // `widgets`/`wanted` are read via wantedKey (value identity), not reference.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [wantedKey, enabled]);\n\n // Hand each widget its seed ONLY if it was fetched for the selector the widget has now.\n return useMemo(() => {\n const out: Record<string, MeasurementSample[] | undefined> = {};\n if (!enabled) return out;\n for (const w of widgets) {\n const seed = seeds[w.id];\n out[w.id] = seed && seed.key === seedKey(w, registry) ? seed.samples : undefined;\n }\n return out;\n }, [widgets, seeds, enabled, registry]);\n}\n", "// Copyright The DeviceChain Authors\n// SPDX-License-Identifier: Apache-2.0\n\n// ConnectedWidget is the one place the imperative DashboardHub meets the pure widget\n// contract. It looks the widget up in the host's REGISTRY and dispatches on the registered\n// descriptor's data CHANNEL: a measurement widget subscribes its datasource (windowed per its\n// binding policy); an alarm widget subscribes its scope+filters through the hub's alarm\n// channel; and so on. Either way it resolves the data and renders the registered component\n// with { widget, data }. A dashboard renderer maps over its widgets rendering one\n// ConnectedWidget each.\n//\n// Each widget renders inside its own containment (widget-containment.tsx): a throw shows a\n// local diagnostic with a reset control and the siblings keep rendering. A widget the\n// registry cannot resolve (an unknown or unavailable package, a version it cannot read) is a\n// placeholder with a specific reason: it reads nothing \u2014 no channel, no availability query \u2014\n// and is handed no actions.\n\nimport {\n UNKNOWN_WIDGET_TYPE,\n type MeasurementSample,\n type UnresolvedWidgetReason,\n type WidgetActions,\n type WidgetDataSource,\n type WidgetDescriptor,\n type WidgetInstance,\n} from '@devicechain/dashboards';\nimport { WidgetCandidatesProvider, WidgetSelectProvider, type WidgetRegistry } from '@devicechain/widget-sdk';\nimport { useMemo, type ComponentType, type ReactNode } from 'react';\n\nimport { alarmSubscription, commandSubscription, measurementWindow } from './binding-policy';\nimport { defaultWidgetRegistry } from './default-registry';\nimport {\n optString,\n useAlarmStream,\n useCommandStream,\n useDatasourceAvailability,\n useLocationStream,\n useMeasurementStream,\n useWidgetCandidates,\n useWidgetSelect,\n WidgetFrame,\n} from '@devicechain/widget-sdk';\nimport { WidgetContainment, useReportRejection } from './widget-containment';\nimport { narrowActions, narrowCandidates, narrowSelect } from './widget-host';\n\nexport interface ConnectedWidgetProps {\n widget: WidgetInstance;\n hub: WidgetDataSource;\n // The registry that resolves the widget's component, channel and binding policy. Omitted =\n // the built-in registry. A host composing extension packages passes the SAME registry it\n // parsed the definition with.\n registry?: WidgetRegistry;\n // The action seam (writes). Narrowed per widget to the interactions its descriptor\n // declares; undefined = read-only.\n actions?: WidgetActions;\n // Optional history backfill for this widget (from bucketedMeasurements), seeded\n // under the live tail so a chart isn't blank until the first live sample. Ignored by\n // every channel but measurement (the others reconcile from a query, not a history seed).\n initialSamples?: MeasurementSample[];\n}\n\nexport function ConnectedWidget(props: ConnectedWidgetProps) {\n const { widget } = props;\n const registry = props.registry ?? defaultWidgetRegistry();\n // A change to what the widget is configured with retries a widget that threw on the old one.\n const resetKey = JSON.stringify([widget.type, widget.options ?? null, widget.datasource ?? null]);\n return (\n <WidgetContainment title={optString(widget.options, 'title')} resetKey={resetKey}>\n <ConnectedWidgetBody {...props} registry={registry} />\n </WidgetContainment>\n );\n}\n\ntype BodyProps = ConnectedWidgetProps & { registry: WidgetRegistry };\n\n// The component a registration renders. Its props are erased in the registry (one registry\n// holds components of every channel); the channel adapters below supply the matching data.\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype AnyWidgetComponent = ComponentType<any>;\n\nfunction ConnectedWidgetBody({ widget, hub, registry, actions, initialSamples }: BodyProps) {\n const unresolved = widget.type === UNKNOWN_WIDGET_TYPE;\n const descriptor = unresolved ? undefined : registry.descriptor(widget.type);\n const implementation = unresolved ? undefined : registry.implementation(widget.type);\n\n // A widget bound to a since-deleted device (its stable token no longer resolves)\n // shows an \"unavailable\" pane rather than a blank one \u2014 checked optimistically, so a\n // valid widget renders from its stream without waiting on this. An unresolved widget asks\n // nothing: it is never given a datasource to check. Nor does a widget whose descriptor\n // binds none (label, image, the selector): a datasource left on its stored JSON is one it\n // never reads, so it must not turn the widget into an \"unavailable\" pane.\n const readsDatasource = descriptor !== undefined && descriptor.datasource.mode !== 'none';\n const availability = useDatasourceAvailability(hub, readsDatasource ? widget.datasource : undefined);\n if (availability === 'unavailable') {\n return <WidgetUnavailableFrame widget={widget} />;\n }\n\n if (widget.type === UNKNOWN_WIDGET_TYPE) {\n return <UnresolvedWidgetFrame storedType={widget.raw.type} reason={widget.reason} />;\n }\n if (!descriptor || !implementation) {\n // Parsed against a catalog this registry does not hold: say so rather than render nothing.\n return (\n <UnresolvedWidgetFrame\n storedType={widget.type}\n reason={{ code: 'unregistered', message: `\"${widget.type}\" is not registered in this host's widget registry` }}\n />\n );\n }\n\n return (\n <HostScope descriptor={descriptor} actions={actions}>\n {(hostActions) => (\n <ChannelBody\n widget={widget}\n hub={hub}\n descriptor={descriptor}\n Component={implementation.component}\n actions={hostActions}\n initialSamples={initialSamples}\n />\n )}\n </HostScope>\n );\n}\n\n// HostScope hands ONE widget only the interactions it declared: a narrowed action seam, and\n// the ambient selection / candidate providers re-provided so an undeclared capability\n// reads as \"not wired\" to a widget that asks.\nfunction HostScope({\n descriptor,\n actions,\n children,\n}: {\n descriptor: WidgetDescriptor;\n actions: WidgetActions | undefined;\n children: (actions: WidgetActions | undefined) => ReactNode;\n}) {\n const report = useReportRejection();\n const select = useWidgetSelect();\n const candidates = useWidgetCandidates();\n const narrowed = useMemo(() => narrowActions(actions, descriptor, report), [actions, descriptor, report]);\n const narrowedSelect = useMemo(() => narrowSelect(select, descriptor), [select, descriptor]);\n const narrowedCandidates = useMemo(\n () => narrowCandidates(candidates, descriptor, report),\n [candidates, descriptor, report],\n );\n return (\n <WidgetSelectProvider select={narrowedSelect}>\n <WidgetCandidatesProvider candidates={narrowedCandidates}>{children(narrowed)}</WidgetCandidatesProvider>\n </WidgetSelectProvider>\n );\n}\n\ninterface ChannelProps {\n widget: WidgetInstance;\n hub: WidgetDataSource;\n descriptor: WidgetDescriptor;\n Component: AnyWidgetComponent;\n actions: WidgetActions | undefined;\n initialSamples?: MeasurementSample[];\n}\n\n// The channel is the only thing the runtime branches on \u2014 never the widget id.\nfunction ChannelBody(props: ChannelProps) {\n switch (props.descriptor.channel) {\n case 'alarm':\n return <AlarmConnectedWidget {...props} />;\n case 'control':\n return <ControlConnectedWidget {...props} />;\n case 'location':\n return <LocationConnectedWidget {...props} />;\n case 'selection':\n case 'none':\n return <StaticConnectedWidget {...props} />;\n case 'measurement':\n return <MeasurementConnectedWidget {...props} />;\n }\n}\n\n// A selection widget (entity-selector) consumes no hub data \u2014 it reads the ambient candidate\n// provider + selection callback; a `none` widget is static. Neither subscribes anything.\nfunction StaticConnectedWidget({ widget, Component, actions }: ChannelProps) {\n return <Component widget={widget} data={null} actions={actions} />;\n}\n\nfunction MeasurementConnectedWidget({ widget, hub, descriptor, Component, actions, initialSamples }: ChannelProps) {\n const data = useMeasurementStream(hub, widget.datasource, {\n window: measurementWindow(descriptor, widget),\n initialSamples,\n });\n\n if (data.error) return <WidgetErrorFrame widget={widget} error={data.error} />;\n return <Component widget={widget} data={data} actions={actions} />;\n}\n\nfunction AlarmConnectedWidget({ widget, hub, descriptor, Component, actions }: ChannelProps) {\n const data = useAlarmStream(hub, alarmSubscription(descriptor, widget));\n\n // Show the error pane ONLY when there's nothing to display (the initial load failed).\n // Once a snapshot has loaded, a later transient poll/query error keeps the last-good\n // rows on screen \u2014 the channel re-queries every 30s and self-heals, so blanking a\n // populated table on one blip is the exact blink the console page avoids.\n if (data.error && data.alarms.length === 0 && data.total === 0) {\n return <WidgetErrorFrame widget={widget} error={data.error} />;\n }\n return <Component widget={widget} data={data} actions={actions} />;\n}\n\nfunction ControlConnectedWidget({ widget, hub, descriptor, Component, actions }: ChannelProps) {\n const data = useCommandStream(hub, commandSubscription(descriptor, widget));\n\n // Unlike the read-only widgets, a command widget is NEVER replaced by the error pane:\n // its primary control is the send form (a separate authority from reading history), so\n // a history poll error must not tear the form down. The widget surfaces the error\n // inline instead.\n return <Component widget={widget} data={data} actions={actions} />;\n}\n\nfunction LocationConnectedWidget({ widget, hub, Component, actions }: ChannelProps) {\n // The tile source lives in the widget's options, not here \u2014 it is a rendering choice, not\n // part of what the widget asks the platform for.\n const data = useLocationStream(hub, { datasource: widget.datasource });\n\n // Same rule as the alarm channel: show the error pane ONLY when there is nothing to\n // display. Once a snapshot has loaded, a later transient poll error keeps the last\n // known positions on screen \u2014 the channel re-polls and self-heals, and blanking a\n // populated map on one blip is worse than a marker being a few seconds stale.\n //\n // \uD83D\uDD34 A REFUSAL IS NOT AN ERROR AND MUST NOT REACH THIS BRANCH. The hub delivers it as\n // a snapshot state with `error` null, so the widget renders its own permission copy \u2014\n // if it were surfaced as an error, every ordinary member would see \"Data unavailable\"\n // where the platform is working exactly as designed.\n if (data.error && data.locations.length === 0) {\n return <WidgetErrorFrame widget={widget} error={data.error} />;\n }\n return <Component widget={widget} data={data} actions={actions} />;\n}\n\n// The placeholder for a widget this build cannot resolve. It names the stored type and says\n// WHY (not installed, no version metadata, a settings or SDK generation it cannot read); the\n// stored object is otherwise untouched (the serializer writes it back verbatim).\nfunction UnresolvedWidgetFrame({\n storedType: stored,\n reason,\n}: {\n storedType: unknown;\n reason: UnresolvedWidgetReason | undefined;\n}): ReactNode {\n const storedType = typeof stored === 'string' ? stored : '';\n const heading =\n (reason?.code ?? 'unregistered') === 'unregistered'\n ? 'This widget needs a newer viewer'\n : 'This widget cannot be shown here';\n return (\n <WidgetFrame>\n <div\n style={{\n display: 'flex',\n flexDirection: 'column',\n alignItems: 'center',\n justifyContent: 'center',\n gap: 4,\n width: '100%',\n height: '100%',\n padding: 12,\n boxSizing: 'border-box',\n textAlign: 'center',\n color: 'hsl(var(--muted-foreground))',\n }}\n >\n <div style={{ fontSize: 13, fontWeight: 600 }}>{heading}</div>\n {storedType && !reason?.message.includes(storedType) && (\n <div style={{ fontSize: 11, opacity: 0.8 }}>Widget type: {storedType}</div>\n )}\n {reason && <div style={{ fontSize: 11, opacity: 0.8, wordBreak: 'break-word' }}>{reason.message}</div>}\n </div>\n </WidgetFrame>\n );\n}\n\n// WidgetUnavailableFrame is shown when a widget's bound device no longer exists (a\n// deleted device's stable token). Distinct from the error frame: not a transient\n// failure to retry, but a settled \"this entity is gone\" \u2014 so it reads as a state, not\n// an error.\nfunction WidgetUnavailableFrame({ widget }: { widget: WidgetInstance }): ReactNode {\n return (\n <WidgetFrame title={optString(widget.options, 'title')}>\n <div\n style={{\n display: 'flex',\n flexDirection: 'column',\n alignItems: 'center',\n justifyContent: 'center',\n gap: 4,\n width: '100%',\n height: '100%',\n padding: 12,\n boxSizing: 'border-box',\n textAlign: 'center',\n color: 'hsl(var(--muted-foreground))',\n }}\n >\n <div style={{ fontSize: 20, lineHeight: 1 }} aria-hidden=\"true\">\u2298</div>\n <div style={{ fontSize: 13, fontWeight: 600 }}>Device unavailable</div>\n <div style={{ fontSize: 11, opacity: 0.8 }}>The bound device no longer exists.</div>\n </div>\n </WidgetFrame>\n );\n}\n\n// A resolution/socket error surfaces as a muted error state rather than a blank pane.\n// Shared by both the measurement and alarm channels.\nfunction WidgetErrorFrame({ widget, error }: { widget: WidgetInstance; error: unknown }): ReactNode {\n return (\n <WidgetFrame title={optString(widget.options, 'title')}>\n <div\n style={{\n display: 'flex',\n flexDirection: 'column',\n alignItems: 'center',\n justifyContent: 'center',\n gap: 4,\n width: '100%',\n height: '100%',\n padding: 12,\n boxSizing: 'border-box',\n textAlign: 'center',\n color: 'hsl(var(--muted-foreground))',\n }}\n >\n <div style={{ fontSize: 20, lineHeight: 1 }}>\u26A0</div>\n <div style={{ fontSize: 13, fontWeight: 600 }}>Data unavailable</div>\n <div style={{ fontSize: 11, opacity: 0.8, wordBreak: 'break-word' }}>{String(error)}</div>\n </div>\n </WidgetFrame>\n );\n}\n", "// Copyright The DeviceChain Authors\n// SPDX-License-Identifier: Apache-2.0\n\n// The channel adapters' half of a widget's declarative binding policy: turn the descriptor's\n// `binding` (typed constants and references to declared option keys) plus the widget's stored\n// options into the subscription arguments a hub channel takes. This is the ONLY place that\n// reads a policy-referenced option, so it reads them by the NAME the descriptor declares \u2014\n// no widget id is consulted, and an extension that declares `{ option: 'rows' }` is honored\n// exactly as a built-in declaring `{ option: 'maxRows' }` is.\n\nimport type {\n AlarmSubscription,\n CommandSubscription,\n WidgetDescriptor,\n WidgetInstance,\n} from '@devicechain/dashboards';\n\nimport { optNumber, optString } from '@devicechain/widget-sdk';\n\n// The shapes a policy value takes at runtime (the descriptor is validated at registration,\n// so a ref names a declared option of a compatible kind; the value stored in a widget may\n// still be absent or the wrong type, in which case the ref's default applies).\ninterface NumberBinding {\n const?: number;\n option?: string;\n default?: number;\n min?: number;\n}\ninterface StringBinding {\n option?: string;\n default?: string;\n}\n\nfunction numberValue(binding: NumberBinding | undefined, options: WidgetInstance['options']): number | undefined {\n if (!binding) return undefined;\n let value: number | undefined;\n if (typeof binding.const === 'number') value = binding.const;\n else if (binding.option !== undefined) value = optNumber(options, binding.option) ?? binding.default;\n if (value === undefined) return undefined;\n return binding.min !== undefined ? Math.max(binding.min, value) : value;\n}\n\nfunction stringValue(binding: StringBinding | undefined, options: WidgetInstance['options']): string | undefined {\n if (!binding || binding.option === undefined) return undefined;\n return optString(options, binding.option) ?? binding.default;\n}\n\nfunction policy(descriptor: WidgetDescriptor): Record<string, unknown> {\n return descriptor.binding as Record<string, unknown>;\n}\n\n// The rolling-window size a measurement widget asked for, or undefined for the hook default.\nexport function measurementWindow(descriptor: WidgetDescriptor, widget: WidgetInstance): number | undefined {\n return numberValue(policy(descriptor).window as NumberBinding | undefined, widget.options);\n}\n\n// The acknowledged filter is stored as 'true' / 'false' (or absent = any).\nfunction parseAcknowledged(value: string | undefined): boolean | undefined {\n if (value === 'true') return true;\n if (value === 'false') return false;\n return undefined;\n}\n\n// An alarm widget's scope + filters. The datasource (undefined = tenant-wide) is the\n// renderer's; the page size and filters come from the policy.\nexport function alarmSubscription(descriptor: WidgetDescriptor, widget: WidgetInstance): AlarmSubscription {\n const p = policy(descriptor);\n return {\n datasource: widget.datasource,\n state: stringValue(p.state as StringBinding | undefined, widget.options),\n severity: stringValue(p.severity as StringBinding | undefined, widget.options),\n acknowledged: parseAcknowledged(stringValue(p.acknowledged as StringBinding | undefined, widget.options)),\n pageSize: numberValue(p.pageSize as NumberBinding | undefined, widget.options) ?? 1,\n };\n}\n\n// A command widget's target scope and how many recent commands its history shows.\nexport function commandSubscription(descriptor: WidgetDescriptor, widget: WidgetInstance): CommandSubscription {\n return {\n datasource: widget.datasource,\n pageSize: numberValue(policy(descriptor).pageSize as NumberBinding | undefined, widget.options) ?? 1,\n };\n}\n", "// Copyright The DeviceChain Authors\n// SPDX-License-Identifier: Apache-2.0\n\n// The built-in widgets as registrations. Each widget module declares its own registration\n// (descriptor + component) through the SAME public `defineWidget` a third-party package uses\n// -- there is no privileged internal path and no id-keyed component table; this module only\n// lists them, in the catalog's order.\n\nimport { createWidgetRegistry, type WidgetRegistry } from '@devicechain/widget-sdk';\n\nimport { alarmCountWidget } from './widgets/alarm-count';\nimport { alarmTableWidget } from './widgets/alarm-table';\nimport { commandButtonWidget } from './widgets/command-button';\nimport { entitySelectorWidget } from './widgets/entity-selector';\nimport { gaugeWidget } from './widgets/gauge';\nimport { imageWidget } from './widgets/image';\nimport { labelWidget } from './widgets/label';\nimport { latestCardWidget } from './widgets/latest-card';\nimport { mapWidget } from './widgets/map';\nimport { tableWidget } from './widgets/table';\nimport { timeSeriesChartWidget } from './widgets/time-series-chart';\n\nexport const builtinWidgetDefinitions = [\n timeSeriesChartWidget,\n latestCardWidget,\n gaugeWidget,\n tableWidget,\n labelWidget,\n imageWidget,\n alarmTableWidget,\n alarmCountWidget,\n commandButtonWidget,\n entitySelectorWidget,\n mapWidget,\n] as const;\n\n// A fresh, sealed registry holding exactly the built-ins. Every call returns an independent\n// instance; a host composing extensions passes `[...builtinWidgetDefinitions, theirs]` to\n// createWidgetRegistry from @devicechain/widget-sdk instead.\nexport function createBuiltinWidgetRegistry(): WidgetRegistry {\n return createWidgetRegistry(builtinWidgetDefinitions);\n}\n", "// Copyright The DeviceChain Authors\n// SPDX-License-Identifier: Apache-2.0\n\n// alarm-count \u2014 a KPI card of how many alarms match the widget's scope+filter\n// (ADR-041). The number is the server total (past the loaded page); its color is the\n// most severe among the CURRENTLY-LOADED alarms (the newest page), and the worst\n// severity is also spelled out as text/aria so the signal never reads on hue alone (a\n// color-blind or screen-reader viewer still gets it). At zero it stays muted.\n\nimport {\n type AlarmStreamState,\n css,\n defineWidget,\n optString,\n useElementSize,\n WidgetFrame,\n type WidgetProps,\n} from '@devicechain/widget-sdk';\n\nimport { builtinWidgetDescriptors } from '../builtin-descriptors';\nimport { highestSeverity, severityColor, severityLabel } from './severity';\n\nconst clamp = (v: number, lo: number, hi: number): number => Math.max(lo, Math.min(hi, v));\n\nexport function AlarmCount({ widget, data }: WidgetProps<AlarmStreamState>) {\n const [sizeRef, size] = useElementSize<HTMLDivElement>();\n const { total, alarms, loading } = data;\n\n const worst = highestSeverity(alarms.map((a) => a.severity));\n // At zero (or before any alarm is loaded) stay neutral; otherwise take the worst\n // loaded severity's color as the alert accent.\n const alerting = total > 0 && worst != null;\n const color = alerting ? severityColor(worst) : css('muted-foreground');\n\n const valueFont = size.height > 0 ? clamp(Math.round(size.height / 2.8), 20, 56) : 40;\n const display = loading && total === 0 ? '\u2014' : String(total);\n const unit = total === 1 ? 'alarm' : 'alarms';\n const ariaLabel = alerting ? `${total} ${unit}, worst severity ${severityLabel(worst)}` : `${total} ${unit}`;\n\n return (\n <WidgetFrame title={optString(widget.options, 'title')}>\n <div\n ref={sizeRef}\n style={{\n display: 'flex',\n flexDirection: 'column',\n justifyContent: 'center',\n alignItems: 'center',\n height: '100%',\n padding: '12px 16px',\n textAlign: 'center',\n }}\n >\n <div aria-label={ariaLabel} style={{ fontSize: valueFont, fontWeight: 700, lineHeight: 1, color }}>\n {display}\n </div>\n <div\n style={{\n fontSize: 11,\n color: css('muted-foreground'),\n marginTop: 6,\n textTransform: 'uppercase',\n letterSpacing: '0.05em',\n }}\n >\n <span>{unit}</span>\n {alerting ? <span>{` \u00B7 worst ${severityLabel(worst)}`}</span> : null}\n </div>\n </div>\n </WidgetFrame>\n );\n}\n\n// The registration: this widget's portable descriptor paired with its component, declared\n// through the same public `defineWidget` a third-party package uses.\nexport const alarmCountWidget = defineWidget({\n descriptor: builtinWidgetDescriptors['alarm-count'],\n implementation: { kind: 'trusted-react', component: AlarmCount },\n});\n", "// Copyright The DeviceChain Authors\n// SPDX-License-Identifier: Apache-2.0\n\n// The portable descriptor of every built-in widget \u2014 pure data, React-free, importing no\n// component. The headless validators read the catalog built from these without ever\n// loading a widget; builtin-registry.ts pairs each descriptor with its component.\n//\n// \uD83D\uDD11 THE SOURCE OF TRUTH. A built-in's channel, option schema, defaults and binding policy are\n// declared here, once, as data. Nothing else in this package keeps an id-keyed table of them:\n// the by-id views the console still reads (WIDGET_CHANNEL, WIDGET_OPTIONS, ...) are derived,\n// read-only projections of these descriptors (registry.ts, options.ts).\n//\n// Every built-in carries version 1.0.0: a per-widget release number, NOT the platform\n// version. It is bumped only on a rendering change worth surfacing to an author, so a\n// platform release does not make every board look \"authored with an older widget\".\n\nimport {\n createWidgetCatalog,\n defineWidgetDescriptor,\n type BuiltinWidgetId,\n type OptionSpec,\n type WidgetDescriptor,\n} from '@devicechain/dashboards';\n\n// ---- Shared option specs ----------------------------------------------------\n// Declared once and referenced by each widget that reads them, so the same key always\n// carries the same type and bounds. They are still listed PER WIDGET below rather than\n// merged in from a base: which widget reads which option is the fact this table exists\n// to record, and a base object would hide it.\n\nconst TITLE = {\n kind: 'string',\n labelId: 'widgetLabelTitle',\n doc: 'Heading shown in the widget frame. Blank hides the frame heading.',\n} as const satisfies OptionSpec;\n\n// gauge and latest-card fall back to the displayed measurement's name when no title is set.\nconst TITLE_OR_MEASUREMENT = {\n kind: 'string',\n labelId: 'widgetLabelTitle',\n doc: 'Heading shown in the widget frame. Defaults to the displayed measurement name.',\n} as const satisfies OptionSpec;\n\n// toFixed()'s domain is 0..100 \u2014 outside it throws a RangeError, which would take the\n// whole widget subtree down rather than degrading.\nconst PRECISION = {\n kind: 'number',\n integer: true,\n min: 0,\n max: 100,\n labelId: 'widgetLabelPrecision',\n helpId: 'widgetHintPrecision',\n doc: 'Decimal places to round displayed values to. Unset shows the raw value.',\n} as const satisfies OptionSpec;\n\nconst FLASH_ON_CHANGE = {\n kind: 'boolean',\n labelId: 'widgetFlashOnChange',\n helpId: 'widgetFlashOnChangeHint',\n doc: 'Briefly tint a value green on a rise and red on a fall when it changes.',\n} as const satisfies OptionSpec;\n\n// Read by MeasurementConnectedWidget for every measurement-channel widget, and declared on\n// each one that binds a datasource. It is NOT declared on label/image, which carry no\n// datasource at all, so there is no stream for it to size.\n//\n// It bounds the RETAINED buffer, not what is drawn: useMeasurementStream keeps `latest`\n// per measurement unconditionally and trims only `samples`. Only the chart draws\n// `samples`, so on a card, gauge or table this is a memory bound with no visible effect \u2014\n// declared because the renderer honors it, documented so nobody expects it to show.\n//\n// The trim is GLOBAL across the widget's measurements, not per measurement: `samples` is\n// one interleaved list, so a chart drawing N series retains roughly window/N of each. An\n// earlier version of this doc said \"per measurement\", and a caller sized a window off it\n// and got half the history it intended.\nconst WINDOW = {\n kind: 'number',\n integer: true,\n min: 1,\n labelId: 'widgetLabelWindow',\n helpId: 'widgetHintWindow',\n doc: 'Samples retained across ALL of the widget\\'s measurements before the oldest are dropped. Bounds memory; only the chart draws them. Default 300.',\n} as const satisfies OptionSpec;\n\nconst UNIT = {\n kind: 'string',\n labelId: 'widgetLabelUnit',\n doc: 'Unit suffix shown beside the value.',\n} as const satisfies OptionSpec;\n\nconst ALARM_STATE = {\n kind: 'enum',\n values: ['ACTIVE', 'CLEARED'],\n labelId: 'widgetLabelState',\n helpId: 'widgetStateHint',\n valueLabelIds: { ACTIVE: 'widgetAlarmStateActive', CLEARED: 'widgetAlarmStateCleared' },\n placeholderId: 'widgetPlaceholderAny',\n doc: 'Show only alarms in this state. Unset shows every state.',\n} as const satisfies OptionSpec;\n\nconst ALARM_SEVERITY = {\n kind: 'enum',\n values: ['CRITICAL', 'MAJOR', 'MINOR', 'WARNING', 'INDETERMINATE'],\n labelId: 'widgetLabelSeverity',\n helpId: 'widgetSeverityHint',\n valueLabelIds: { CRITICAL: 'widgetAlarmSeverityCritical', MAJOR: 'widgetAlarmSeverityMajor', MINOR: 'widgetAlarmSeverityMinor', WARNING: 'widgetAlarmSeverityWarning', INDETERMINATE: 'widgetAlarmSeverityIndeterminate' },\n placeholderId: 'widgetPlaceholderAny',\n doc: 'Show only alarms at this severity. Unset shows every severity.',\n} as const satisfies OptionSpec;\n\n// Stored as the STRING 'true'/'false', not a boolean \u2014 alarmSubscription() reads it with\n// optString and maps it through parseAcknowledged, so a real boolean here is read as\n// undefined and the filter silently disappears. Typed as an enum of those two strings so\n// that mistake is an error rather than a no-op.\nconst ALARM_ACKNOWLEDGED = {\n kind: 'enum',\n values: ['true', 'false'],\n labelId: 'widgetLabelAcknowledged',\n helpId: 'widgetAcknowledgedHint',\n valueLabelIds: { true: 'widgetAlarmAckAcknowledged', false: 'widgetAlarmAckUnacknowledged' },\n placeholderId: 'widgetPlaceholderAny',\n doc: \"Show only acknowledged ('true') or unacknowledged ('false') alarms. Unset shows both.\",\n} as const satisfies OptionSpec;\n\nconst SELECTION_TARGET = {\n kind: 'string',\n labelId: 'widgetLabelTargetSlot',\n helpId: 'widgetTargetSlotHint',\n control: 'slot-target',\n doc: 'Name of the slot this widget re-points when the viewer picks an entity.',\n} as const satisfies OptionSpec;\n\n\nconst VERSION = '1.0.0';\nconst ALL_SELECTORS = ['device', 'anchor', 'slot'] as const;\nconst NO_DATASOURCE = { mode: 'none' } as const;\n\n// The alarm filters are read by both alarm widgets from the same option keys.\nconst ALARM_FILTERS = {\n state: { option: 'state' },\n severity: { option: 'severity' },\n acknowledged: { option: 'acknowledged' },\n} as const;\n\nexport const builtinWidgetDescriptors = {\n 'timeseries-chart': defineWidgetDescriptor({\n id: 'timeseries-chart',\n version: VERSION,\n sdkApiVersion: 1,\n optionsVersion: 1,\n display: { title: 'Timeseries chart', category: 'Telemetry', titleId: 'widgetTypeTimeseriesChart', categoryId: 'widgetCategoryTelemetry' },\n channel: 'measurement',\n datasource: { mode: 'required', selectors: ALL_SELECTORS },\n binding: { window: { option: 'window', min: 1 } },\n options: {\n title: TITLE,\n window: WINDOW,\n },\n defaults: { title: 'Timeseries chart' },\n interactions: {},\n }),\n\n 'latest-card': defineWidgetDescriptor({\n id: 'latest-card',\n version: VERSION,\n sdkApiVersion: 1,\n optionsVersion: 1,\n display: { title: 'Latest card', category: 'Telemetry', titleId: 'widgetTypeLatestCard', categoryId: 'widgetCategoryTelemetry' },\n channel: 'measurement',\n datasource: { mode: 'required', selectors: ALL_SELECTORS },\n binding: { window: { option: 'window', min: 1 } },\n options: {\n title: TITLE_OR_MEASUREMENT,\n measurement: {\n kind: 'string',\n labelId: 'widgetLabelMeasurement',\n helpId: 'widgetHintMeasurement',\n doc: 'Which measurement to display. Defaults to the first the datasource selects.',\n },\n unit: UNIT,\n precision: PRECISION,\n flashOnChange: FLASH_ON_CHANGE,\n window: WINDOW,\n },\n defaults: { title: 'Latest card' },\n interactions: {},\n }),\n\n gauge: defineWidgetDescriptor({\n id: 'gauge',\n version: VERSION,\n sdkApiVersion: 1,\n optionsVersion: 1,\n display: { title: 'Gauge', category: 'Telemetry', titleId: 'widgetTypeGauge', categoryId: 'widgetCategoryTelemetry' },\n channel: 'measurement',\n datasource: { mode: 'required', selectors: ALL_SELECTORS },\n binding: { window: { option: 'window', min: 1 } },\n options: {\n title: TITLE_OR_MEASUREMENT,\n measurement: {\n kind: 'string',\n labelId: 'widgetLabelMeasurement',\n helpId: 'widgetHintMeasurement',\n doc: 'Which measurement to display. Defaults to the first the datasource selects.',\n },\n min: {\n kind: 'number',\n labelId: 'widgetLabelMin',\n doc: 'Low end of the gauge scale. Default 0.',\n },\n max: {\n kind: 'number',\n labelId: 'widgetLabelMax',\n doc: 'High end of the gauge scale. Default 100.',\n },\n unit: UNIT,\n flashOnChange: FLASH_ON_CHANGE,\n window: WINDOW,\n },\n constraints: [{ kind: 'greater-than', key: 'max', than: 'min' }],\n defaults: { title: 'Gauge' },\n interactions: {},\n }),\n\n table: defineWidgetDescriptor({\n id: 'table',\n version: VERSION,\n sdkApiVersion: 1,\n optionsVersion: 1,\n display: { title: 'Table', category: 'Telemetry', titleId: 'widgetTypeTable', categoryId: 'widgetCategoryTelemetry' },\n channel: 'measurement',\n datasource: { mode: 'required', selectors: ALL_SELECTORS },\n binding: { window: { option: 'window', min: 1 } },\n options: {\n title: TITLE,\n precision: PRECISION,\n flashOnChange: FLASH_ON_CHANGE,\n window: WINDOW,\n },\n defaults: { title: 'Table' },\n interactions: {},\n }),\n\n // label and image are static: the `none` channel, no datasource, no subscription and no\n // history seed.\n label: defineWidgetDescriptor({\n id: 'label',\n version: VERSION,\n sdkApiVersion: 1,\n optionsVersion: 1,\n display: { title: 'Label', category: 'Static', titleId: 'widgetTypeLabel', categoryId: 'widgetCategoryStatic' },\n channel: 'none',\n datasource: NO_DATASOURCE,\n binding: {},\n options: {\n title: TITLE,\n text: {\n kind: 'string',\n required: true,\n labelId: 'widgetLabelText',\n doc: 'The text to show. Rendered as plain text \u2014 markup is never interpreted.',\n },\n align: {\n kind: 'enum',\n values: ['left', 'center', 'right'],\n labelId: 'widgetLabelAlign',\n valueLabelIds: { left: 'widgetAlignLeft', center: 'widgetAlignCenter', right: 'widgetAlignRight' },\n placeholderId: 'widgetPlaceholderDefault',\n doc: 'Horizontal alignment of the text. Default center.',\n },\n fontSize: {\n kind: 'number',\n min: 1,\n labelId: 'widgetLabelFontSize',\n helpId: 'widgetHintFontSize',\n doc: 'Text size in pixels. Default 16.',\n },\n },\n defaults: { text: 'New label' },\n interactions: {},\n }),\n\n image: defineWidgetDescriptor({\n id: 'image',\n version: VERSION,\n sdkApiVersion: 1,\n optionsVersion: 1,\n display: { title: 'Image', category: 'Static', titleId: 'widgetTypeImage', categoryId: 'widgetCategoryStatic' },\n channel: 'none',\n datasource: NO_DATASOURCE,\n binding: {},\n options: {\n title: TITLE,\n url: {\n kind: 'string',\n required: true,\n labelId: 'widgetLabelImageUrl',\n doc: 'Source URL of the image.',\n },\n alt: {\n kind: 'string',\n labelId: 'widgetLabelAltText',\n doc: 'Alternative text describing the image for assistive technology.',\n },\n fit: {\n kind: 'enum',\n values: ['contain', 'cover', 'fill'],\n labelId: 'widgetLabelFit',\n valueLabelIds: { contain: 'widgetFitContain', cover: 'widgetFitCover', fill: 'widgetFitFill' },\n placeholderId: 'widgetPlaceholderDefault',\n doc: 'How the image fills its box. Default contain.',\n },\n },\n defaults: { title: 'Image' },\n interactions: {},\n }),\n\n 'alarm-table': defineWidgetDescriptor({\n id: 'alarm-table',\n version: VERSION,\n sdkApiVersion: 1,\n optionsVersion: 1,\n display: { title: 'Alarm table', category: 'Alarms', titleId: 'widgetTypeAlarmTable', categoryId: 'widgetCategoryAlarms' },\n channel: 'alarm',\n datasource: { mode: 'optional', selectors: ALL_SELECTORS },\n binding: { pageSize: { option: 'maxRows', default: 50, min: 1 }, ...ALARM_FILTERS },\n options: {\n title: TITLE,\n state: ALARM_STATE,\n severity: ALARM_SEVERITY,\n acknowledged: ALARM_ACKNOWLEDGED,\n maxRows: {\n kind: 'number',\n integer: true,\n min: 1,\n labelId: 'widgetLabelMaxRows',\n helpId: 'widgetMaxRowsAlarmHint',\n doc: 'Alarms loaded into the table. Default 50.',\n },\n precision: PRECISION,\n flashOnChange: FLASH_ON_CHANGE,\n selectionTarget: SELECTION_TARGET,\n },\n defaults: { title: 'Alarm table', state: 'ACTIVE' },\n interactions: { alarmActions: true, selection: true },\n }),\n\n // The count shows the SERVER total and reads a page only to sample the worst loaded\n // severity, so its page size is a constant rather than an authorable option.\n 'alarm-count': defineWidgetDescriptor({\n id: 'alarm-count',\n version: VERSION,\n sdkApiVersion: 1,\n optionsVersion: 1,\n display: { title: 'Alarm count', category: 'Alarms', titleId: 'widgetTypeAlarmCount', categoryId: 'widgetCategoryAlarms' },\n channel: 'alarm',\n datasource: { mode: 'optional', selectors: ALL_SELECTORS },\n binding: { pageSize: { const: 50 }, ...ALARM_FILTERS },\n // No maxRows: alarmSubscription() forces the default page size for a count, because the\n // number it shows is the SERVER total and the page is read only to sample the worst\n // loaded severity. An authored maxRows here would be read by nothing.\n options: {\n title: TITLE,\n state: ALARM_STATE,\n severity: ALARM_SEVERITY,\n acknowledged: ALARM_ACKNOWLEDGED,\n },\n defaults: { title: 'Alarm count', state: 'ACTIVE' },\n interactions: {},\n }),\n\n 'command-button': defineWidgetDescriptor({\n id: 'command-button',\n version: VERSION,\n sdkApiVersion: 1,\n optionsVersion: 1,\n display: { title: 'Command button', category: 'Control', titleId: 'widgetTypeCommandButton', categoryId: 'widgetCategoryControl' },\n channel: 'control',\n datasource: { mode: 'required', selectors: ['device', 'slot'] },\n binding: { pageSize: { option: 'maxRows', default: 20, min: 1 } },\n options: {\n title: TITLE,\n commandName: {\n kind: 'string',\n required: true,\n labelId: 'widgetCommandHeading',\n helpId: 'widgetCommandFieldHint',\n control: 'command-vocabulary',\n doc: 'Command key issued to the target device. Without it the widget cannot send.',\n },\n commandLabel: {\n kind: 'string',\n labelId: 'widgetCommandHeading',\n helpId: 'widgetCommandFieldHint',\n control: 'command-vocabulary',\n doc: 'Text on the send button. Defaults to the command key.',\n },\n parameterSchema: {\n kind: 'string',\n format: 'json',\n labelId: 'widgetCommandHeading',\n helpId: 'widgetCommandFieldHint',\n control: 'command-vocabulary',\n doc: \"The command's parameter descriptors, baked in as JSON at author time. Drives the typed form.\",\n },\n maxRows: {\n kind: 'number',\n integer: true,\n min: 1,\n labelId: 'widgetLabelMaxRows',\n helpId: 'widgetMaxRowsCommandHint',\n doc: 'Recent commands shown in the history. Default 20.',\n },\n },\n defaults: { title: 'Command button' },\n interactions: { commandSend: true },\n }),\n\n 'entity-selector': defineWidgetDescriptor({\n id: 'entity-selector',\n version: VERSION,\n sdkApiVersion: 1,\n optionsVersion: 1,\n display: { title: 'Entity selector', category: 'Navigation', titleId: 'widgetTypeEntitySelector', categoryId: 'widgetCategoryNavigation' },\n channel: 'selection',\n datasource: NO_DATASOURCE,\n binding: {},\n options: {\n title: TITLE,\n selectionTarget: { ...SELECTION_TARGET, required: true },\n },\n defaults: { title: 'Entity selector' },\n interactions: { selection: true, candidates: true },\n }),\n\n map: defineWidgetDescriptor({\n id: 'map',\n version: VERSION,\n sdkApiVersion: 1,\n optionsVersion: 1,\n display: { title: 'Map', category: 'Location', titleId: 'widgetTypeMap', categoryId: 'widgetCategoryLocation' },\n channel: 'location',\n datasource: { mode: 'required', selectors: ALL_SELECTORS },\n binding: {},\n // \uD83D\uDD34 tileUrl is NOT `required`, and that is the decision rather than an oversight.\n // `required` means \"absent leaves the widget with nothing to show\", and a map without\n // a basemap still shows every position it was asked to \u2014 on a plain panel, saying why\n // there is no map behind them. Marking it required would report a correctly-rendering\n // widget as broken on every board that names no provider of its own \u2014 which is most\n // of them, because the usual and recommended answer is to inherit the tenant's\n // basemap rather than to configure tiles per board.\n options: {\n title: TITLE,\n tileUrl: {\n kind: 'string',\n labelId: 'widgetLabelTileUrl',\n helpId: 'widgetTileUrlHint',\n control: 'basemap',\n doc: \"Raster tile URL template, e.g. https://tiles.example.com/{z}/{x}/{y}.png. Leave empty to inherit the tenant's basemap; setting one overrides it for this board only.\",\n },\n attribution: {\n kind: 'string',\n labelId: 'widgetLabelAttribution',\n helpId: 'widgetAttributionHint',\n control: 'basemap',\n doc: 'Credit line the tile source requires, shown on the map. Set whatever the provider you chose asks for.',\n },\n },\n defaults: { title: 'Map' },\n interactions: {},\n }),\n} as const satisfies Record<BuiltinWidgetId, WidgetDescriptor>;\n\n// The catalog the headless validators read. Constructed at module load, so a built-in that\n// fails its own validation fails every consumer of this package on import \u2014 loudly, and not\n// only in a test.\nexport const builtinWidgetCatalog = createWidgetCatalog(Object.values(builtinWidgetDescriptors));\n", "// Copyright The DeviceChain Authors\n// SPDX-License-Identifier: Apache-2.0\n\n// Alarm-severity presentation shared by the alarm widgets (ADR-041 vocabulary:\n// CRITICAL | MAJOR | MINOR | WARNING | INDETERMINATE). Severity is SEMANTIC color \u2014\n// deliberately fixed, not derived from the dashboard accent \u2014 so a critical alarm\n// reads the same red on every tenant's theme. The warm-to-cool ramp mirrors the\n// console's alarm badges (red \u2192 orange \u2192 amber \u2192 sky \u2192 slate) so an operator reads the\n// same hue for the same severity on both surfaces; shades are tuned to hold contrast as\n// a foreground color on both light and dark widget backgrounds.\n\nconst SEVERITY_COLORS: Record<string, string> = {\n CRITICAL: '#dc2626', // red-600\n MAJOR: '#f97316', // orange-500\n MINOR: '#d97706', // amber-600 (readable as foreground; console uses amber-400 as a fill)\n WARNING: '#0ea5e9', // sky-500 \u2014 cool end of the ramp, matching the console\n INDETERMINATE: '#64748b', // slate-500\n};\n\nconst SEVERITY_ORDER: Record<string, number> = {\n CRITICAL: 0,\n MAJOR: 1,\n MINOR: 2,\n WARNING: 3,\n INDETERMINATE: 4,\n};\n\nconst UNKNOWN_COLOR = '#64748b';\n\n// severityColor maps a severity to its badge/stripe color, falling back to a muted\n// slate for an unrecognized value (a hand-edited or future severity).\nexport function severityColor(severity: string): string {\n return SEVERITY_COLORS[severity] ?? UNKNOWN_COLOR;\n}\n\n// severityRank orders severities most-severe-first; unknown severities sort last.\nexport function severityRank(severity: string): number {\n return SEVERITY_ORDER[severity] ?? 99;\n}\n\n// severityLabel renders a severity in Title Case ('CRITICAL' \u2192 'Critical').\nexport function severityLabel(severity: string): string {\n if (!severity) return '';\n return severity.charAt(0).toUpperCase() + severity.slice(1).toLowerCase();\n}\n\n// highestSeverity returns the most severe severity present in a list, or undefined for\n// an empty list \u2014 the accent an alarm-count uses to signal \"how bad is the worst one\".\nexport function highestSeverity(severities: string[]): string | undefined {\n let best: string | undefined;\n for (const s of severities) {\n if (best === undefined || severityRank(s) < severityRank(best)) best = s;\n }\n return best;\n}\n", "// Copyright The DeviceChain Authors\n// SPDX-License-Identifier: Apache-2.0\n\n// alarm-table \u2014 the raised alarms in the widget's scope (ADR-041), newest first, with\n// a severity stripe per row. When the runtime supplies an action seam AND the viewer\n// holds alarm:write, each active row gets Acknowledge / Clear controls; otherwise the\n// table is read-only. Bound through the hub's alarm channel, so it renders identically\n// from live data or the synthetic preview source.\n\nimport type { AlarmRow, WidgetActions } from '@devicechain/dashboards';\nimport { useState, type CSSProperties } from 'react';\n\nimport {\n type AlarmStreamState,\n css,\n defineWidget,\n FlashValue,\n formatDateTime,\n optBoolean,\n optNumber,\n optString,\n useWidgetSelect,\n useWidgetTimeZone,\n WidgetFrame,\n type WidgetProps,\n type WidgetSelect,\n} from '@devicechain/widget-sdk';\n\nimport { builtinWidgetDescriptors } from '../builtin-descriptors';\nimport { severityColor, severityLabel } from './severity';\n\nconst cell: CSSProperties = { padding: '6px 10px', textAlign: 'left', whiteSpace: 'nowrap' };\nconst headCell: CSSProperties = {\n ...cell,\n position: 'sticky',\n top: 0,\n background: css('card'),\n fontSize: 11,\n fontWeight: 600,\n textTransform: 'uppercase',\n letterSpacing: '0.04em',\n color: css('muted-foreground'),\n borderBottom: `1px solid ${css('border')}`,\n};\n\n// statusLabel collapses the 4-state model (state \u00D7 acknowledged) into the one signal an\n// operator reads, matching the console's alarm badges: cleared wins regardless of the\n// acknowledged flag; an active alarm is \"Acknowledged\" once owned, else \"Active\".\nfunction statusLabel(alarm: AlarmRow): string {\n if (alarm.state === 'CLEARED') return 'Cleared';\n return alarm.acknowledged ? 'Acknowledged' : 'Active';\n}\n\nexport function AlarmTable({ widget, data, actions }: WidgetProps<AlarmStreamState>) {\n const { alarms, total, loading } = data;\n // Actions render only when the runtime supplies a seam AND the viewer may write.\n const canAct = actions?.can('alarm:write') ?? false;\n const columns = canAct ? 8 : 7;\n // Round the triggering value to a fixed precision when configured; unset keeps the raw\n // value (formatValue's default), matching the table widget. An alarm's raw lastValue is\n // otherwise a full-width float (e.g. 31.19073834583732).\n const precision = optNumber(widget.options, 'precision');\n // Opt-in directional flash on the triggering value, per row (keyed by alarm token).\n const flash = optBoolean(widget.options, 'flashOnChange');\n // Drill: when a `selectionTarget` slot is configured AND the renderer wired a selection\n // callback (view mode, a host that supports it), a device originator becomes a link that\n // re-points that slot \u2014 driving the per-device widgets to the clicked thermostat\n // (ADR-039 selection amendment). Absent either, the originator is plain text.\n const select = useWidgetSelect();\n const timeZone = useWidgetTimeZone();\n const selectionTarget = optString(widget.options, 'selectionTarget');\n const drillTo = select && selectionTarget ? { select, slot: selectionTarget } : undefined;\n\n return (\n <WidgetFrame title={optString(widget.options, 'title')}>\n <div style={{ display: 'flex', flexDirection: 'column', height: '100%' }}>\n <div style={{ flex: 1, minHeight: 0, overflow: 'auto' }}>\n <table\n style={{\n width: '100%',\n borderCollapse: 'collapse',\n fontSize: 13,\n color: css('foreground'),\n fontVariantNumeric: 'tabular-nums',\n }}\n >\n <thead>\n <tr>\n <th style={{ ...headCell, width: 4, padding: 0 }} aria-hidden=\"true\" />\n <th scope=\"col\" style={headCell}>\n Severity\n </th>\n <th scope=\"col\" style={headCell}>\n Status\n </th>\n <th scope=\"col\" style={headCell}>\n Originator\n </th>\n <th scope=\"col\" style={headCell}>\n Alarm\n </th>\n <th scope=\"col\" style={{ ...headCell, textAlign: 'right' }}>\n Value\n </th>\n <th scope=\"col\" style={headCell}>\n Raised\n </th>\n {canAct ? (\n <th scope=\"col\" style={{ ...headCell, textAlign: 'right' }}>\n Actions\n </th>\n ) : null}\n </tr>\n </thead>\n <tbody>\n {alarms.length === 0 ? (\n <tr>\n <td colSpan={columns} style={{ ...cell, textAlign: 'center', color: css('muted-foreground') }}>\n {loading ? 'Loading\u2026' : 'No alarms'}\n </td>\n </tr>\n ) : (\n alarms.map((alarm) => {\n const color = severityColor(alarm.severity);\n return (\n <tr key={alarm.token} style={{ borderBottom: `1px solid ${css('border')}` }}>\n <td aria-hidden=\"true\" style={{ padding: 0, width: 4, background: color }} />\n <td style={cell}>\n <span style={{ display: 'inline-flex', alignItems: 'center', gap: 6 }}>\n <span\n aria-hidden=\"true\"\n style={{ width: 8, height: 8, borderRadius: '50%', background: color, flexShrink: 0 }}\n />\n {severityLabel(alarm.severity)}\n </span>\n </td>\n <td style={{ ...cell, color: css('muted-foreground') }}>{statusLabel(alarm)}</td>\n <td style={cell}>\n <OriginatorCell alarm={alarm} drillTo={drillTo} />\n </td>\n <td style={cell}>\n {alarm.alarmKey}\n </td>\n <td style={{ ...cell, textAlign: 'right' }}>\n <FlashValue\n value={alarm.lastValue}\n precision={precision}\n enabled={flash}\n identity={alarm.token}\n />\n </td>\n <td style={{ ...cell, color: css('muted-foreground') }}>\n {formatDateTime(alarm.raisedTime, timeZone)}\n </td>\n {canAct ? (\n <td style={{ ...cell, textAlign: 'right' }}>\n {/* actions is defined whenever canAct is true. */}\n <AlarmRowActions alarm={alarm} actions={actions as WidgetActions} />\n </td>\n ) : null}\n </tr>\n );\n })\n )}\n </tbody>\n </table>\n </div>\n {total > alarms.length ? (\n <div\n style={{\n padding: '4px 10px',\n fontSize: 11,\n color: css('muted-foreground'),\n borderTop: `1px solid ${css('border')}`,\n }}\n >\n Showing {alarms.length} of {total}\n </div>\n ) : null}\n </div>\n </WidgetFrame>\n );\n}\n\n// OriginatorCell renders the alarm's originator. When drill is wired AND the originator\n// is a device (it carries a token), it is a link that re-points the target slot to that\n// device; otherwise it is plain text (the token, or the originator type when tokenless).\n// The drill target is a device binding \u2014 a building-scoped alarm table's originators are\n// already members of the context, so the drill stays in-context.\nfunction OriginatorCell({\n alarm,\n drillTo,\n}: {\n alarm: AlarmRow;\n drillTo: { select: WidgetSelect; slot: string } | undefined;\n}) {\n if (drillTo && alarm.originatorType === 'device' && alarm.originatorToken) {\n const token = alarm.originatorToken;\n return (\n <button\n type=\"button\"\n onClick={() => drillTo.select({ slot: drillTo.slot, binding: { kind: 'device', deviceToken: token } })}\n title={`Show ${token} in the linked widgets`}\n style={{\n padding: 0,\n border: 'none',\n background: 'none',\n font: 'inherit',\n color: css('primary'),\n cursor: 'pointer',\n textDecoration: 'underline',\n textUnderlineOffset: 2,\n }}\n >\n {token}\n </button>\n );\n }\n return <>{alarm.originatorToken ?? alarm.originatorType}</>;\n}\n\nconst actionButton: CSSProperties = {\n padding: '2px 8px',\n fontSize: 12,\n lineHeight: 1.4,\n borderRadius: 4,\n border: `1px solid ${css('border')}`,\n background: css('card'),\n color: css('foreground'),\n cursor: 'pointer',\n};\n\n// AlarmRowActions owns the pending/error state for one row's Acknowledge / Clear. Only\n// an ACTIVE alarm is actionable (a cleared \u2014 or any future non-active \u2014 state shows\n// \"\u2014\"); an acknowledged one still shows Clear. After a successful mutation the hub\n// reconciles the table, so the row updates itself.\nfunction AlarmRowActions({ alarm, actions }: { alarm: AlarmRow; actions: WidgetActions }) {\n const [pending, setPending] = useState<'ack' | 'clear' | null>(null);\n const [failed, setFailed] = useState(false);\n\n if (alarm.state !== 'ACTIVE') {\n return <span style={{ color: css('muted-foreground') }}>\u2014</span>;\n }\n\n const run = (kind: 'ack' | 'clear', op: () => Promise<void>) => {\n setPending(kind);\n setFailed(false);\n // Call op() synchronously (so an immediate dispatch is observable) but guard a\n // synchronous throw too, so a misbehaving seam can't leave the row stuck-disabled.\n let promise: Promise<void>;\n try {\n promise = op();\n } catch {\n setFailed(true);\n setPending(null);\n return;\n }\n promise.catch(() => setFailed(true)).finally(() => setPending(null));\n };\n\n return (\n <span style={{ display: 'inline-flex', gap: 6, justifyContent: 'flex-end', alignItems: 'center' }}>\n {failed ? (\n <span\n role=\"img\"\n aria-label=\"Action failed \u2014 retry\"\n title=\"Action failed \u2014 retry\"\n style={{ color: severityColor('CRITICAL'), fontSize: 12 }}\n >\n \u26A0\n </span>\n ) : null}\n {!alarm.acknowledged ? (\n <button\n type=\"button\"\n style={{ ...actionButton, opacity: pending ? 0.6 : 1 }}\n disabled={pending !== null}\n aria-busy={pending === 'ack'}\n aria-label={`Acknowledge alarm ${alarm.alarmKey}`}\n onClick={() => run('ack', () => actions.acknowledgeAlarm(alarm.token))}\n >\n {pending === 'ack' ? '\u2026' : 'Ack'}\n </button>\n ) : null}\n <button\n type=\"button\"\n style={{ ...actionButton, opacity: pending ? 0.6 : 1 }}\n disabled={pending !== null}\n aria-busy={pending === 'clear'}\n aria-label={`Clear alarm ${alarm.alarmKey}`}\n onClick={() => run('clear', () => actions.clearAlarm(alarm.token))}\n >\n {pending === 'clear' ? '\u2026' : 'Clear'}\n </button>\n </span>\n );\n}\n\n// The registration: this widget's portable descriptor paired with its component, declared\n// through the same public `defineWidget` a third-party package uses.\nexport const alarmTableWidget = defineWidget({\n descriptor: builtinWidgetDescriptors['alarm-table'],\n implementation: { kind: 'trusted-react', component: AlarmTable },\n});\n", "// Copyright The DeviceChain Authors\n// SPDX-License-Identifier: Apache-2.0\n\n// command-button \u2014 issue a device command from the dashboard and watch its delivery\n// lifecycle (command-delivery). The console bakes a command definition into the widget's\n// options at author time (its name + parameterSchema); this renders a typed form from\n// that schema, issues via the action seam (gated on command:write), and shows the recent\n// commands for the target device with live status (QUEUED \u2192 SENT \u2192\n// SUCCESSFUL / FAILED \u2026), so an operator can see whether a command was acted on rather\n// than only that it was sent. Bound through the hub's control channel, so it renders identically from live\n// data or the synthetic preview source.\n//\n// The baked schema is a SNAPSHOT taken when the author picked the command: a later edit\n// to the profile's command definition (a changed schema, or a deleted command) leaves\n// this widget's form stale until the author re-picks it. That's acceptable \u2014 dashboards\n// are opaque snapshots \u2014 and a since-removed command fails visibly at the delivery\n// boundary (the server validates device existence and JSON); it isn't silently wrong.\n\nimport type { CommandDispatch, CommandParameter } from '@devicechain/dashboards';\nimport { useEffect, useMemo, useRef, useState, type CSSProperties } from 'react';\n\nimport {\n type CommandStreamState,\n css,\n defineWidget,\n formatDateTime,\n optString,\n useWidgetTimeZone,\n WidgetFrame,\n type WidgetProps,\n} from '@devicechain/widget-sdk';\n\nimport { builtinWidgetDescriptors } from '../builtin-descriptors';\nimport { commandStatusColor, commandStatusLabel } from './command-status';\nimport {\n buildPayload,\n defaultValues,\n isScalar,\n parseBool,\n parseParameterSchema,\n validateParams,\n} from './command-params';\n\nexport function CommandButton({ widget, data, actions }: WidgetProps<CommandStreamState>) {\n const commandName = optString(widget.options, 'commandName');\n const commandLabel = optString(widget.options, 'commandLabel') ?? commandName;\n const parameterSchema = optString(widget.options, 'parameterSchema') ?? null;\n\n const params = useMemo(() => parseParameterSchema(parameterSchema), [parameterSchema]);\n // A stable key over the configured command: reset the form when the author repoints\n // the widget at a different command (or edits its schema).\n const schemaKey = `${commandName ?? ''}::${parameterSchema ?? ''}`;\n\n const [values, setValues] = useState<Record<string, string>>(() => defaultValues(params));\n const [errors, setErrors] = useState<Record<string, string>>({});\n const [pending, setPending] = useState(false);\n const [sendError, setSendError] = useState<string | null>(null);\n const [sentToken, setSentToken] = useState<string | null>(null);\n // Bumped whenever the configured command changes; an in-flight send captures the\n // current value and drops its result if it settles after a repoint (so command A's\n // dispatch token/error can't land under a freshly-configured command B).\n const sendGen = useRef(0);\n\n // Reset the form to the schema's defaults whenever the configured command changes.\n useEffect(() => {\n sendGen.current += 1;\n setValues(defaultValues(params));\n setErrors({});\n setSendError(null);\n setSentToken(null);\n // params is derived from schemaKey; keying on schemaKey avoids re-running on an\n // equal-but-new params array reference.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [schemaKey]);\n\n const canWrite = actions?.can('command:write') ?? false;\n const hasSeam = typeof actions?.sendCommand === 'function';\n const deviceToken = data.deviceToken;\n // The form is operable only when the viewer may write AND the runtime supplies the send\n // seam; a read-only mount shows the form disabled. Sending additionally needs a bound\n // target device and a configured command.\n const formDisabled = !canWrite || !hasSeam || pending;\n const canSend = !formDisabled && !!deviceToken && !!commandName;\n\n const setField = (name: string, value: string) => {\n setValues((prev) => ({ ...prev, [name]: value }));\n // Clear a field's error as the operator edits it.\n setErrors((prev) => (prev[name] ? { ...prev, [name]: '' } : prev));\n setSendError(null);\n };\n\n const send = () => {\n if (!deviceToken || !commandName || !actions?.sendCommand) return;\n const found = validateParams(params, values);\n const active = Object.fromEntries(Object.entries(found).filter(([, v]) => v));\n if (Object.keys(active).length > 0) {\n setErrors(active);\n return;\n }\n const payload = buildPayload(params, values);\n const gen = sendGen.current; // capture: drop the result if the command is repointed mid-flight\n setPending(true);\n setSendError(null);\n // Call synchronously so a dispatch is observable, but guard a synchronous throw so a\n // misbehaving seam can't leave the button stuck-disabled.\n let promise: Promise<CommandDispatch>;\n try {\n promise = actions.sendCommand(deviceToken, commandName, payload);\n } catch {\n setSendError(SEND_FAILED);\n setPending(false);\n return;\n }\n promise\n .then((dispatch) => {\n if (gen !== sendGen.current) return;\n // \uD83D\uDD34 A REFUSAL IS SHOWN, A FAILURE IS NOT. The server decided this command was\n // wrong and said why in client-safe terms (an unknown command for this device, a\n // parameter that violates the schema, the tenant's held-command ceiling) \u2014 that\n // reason is the whole point of the answer, and an operator can act on it. A\n // thrown error, below, is an availability failure: it says nothing about the\n // command, and its text is internal, so it gets one fixed message instead.\n if (dispatch.status === 'rejected') {\n setSendError(dispatch.reason);\n return;\n }\n setSentToken(dispatch.token);\n })\n .catch(() => {\n if (gen === sendGen.current) setSendError(SEND_FAILED);\n })\n .finally(() => {\n if (gen === sendGen.current) setPending(false);\n });\n };\n\n return (\n <WidgetFrame title={optString(widget.options, 'title')}>\n <div style={{ display: 'flex', flexDirection: 'column', height: '100%', gap: 10 }}>\n {!commandName ? (\n <div style={{ ...hint, margin: 'auto' }}>No command configured.</div>\n ) : (\n <>\n {/* Typed parameter form. */}\n <div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>\n {params.map((param) =>\n isScalar(param) ? (\n <ParamField\n key={param.name}\n widgetId={widget.id}\n param={param}\n value={values[param.name] ?? ''}\n error={errors[param.name]}\n disabled={formDisabled}\n onChange={(v) => setField(param.name, v)}\n />\n ) : (\n // A structured (OBJECT) parameter isn't form-editable. A REQUIRED one\n // blocks sending (validateParams flags it); flag that in the note.\n <div key={param.name} style={{ ...hint, color: param.required ? commandStatusColor('FAILED') : css('muted-foreground') }}>\n {param.name}: {param.required ? 'required ' : ''}structured parameter \u2014 not supported here.\n </div>\n ),\n )}\n\n <button\n type=\"button\"\n style={{ ...sendButton, opacity: canSend ? 1 : 0.55, cursor: canSend ? 'pointer' : 'not-allowed' }}\n disabled={!canSend}\n aria-busy={pending}\n onClick={send}\n >\n {pending ? 'Sending\u2026' : `Send ${commandLabel}`}\n </button>\n\n {!canWrite ? (\n <div style={hint}>You don\u2019t have permission to issue commands.</div>\n ) : !hasSeam ? (\n <div style={hint}>Commands aren\u2019t available in this view.</div>\n ) : !deviceToken ? (\n <div style={hint}>No device is selected for this command.</div>\n ) : null}\n {sendError ? (\n <div role=\"alert\" style={{ ...hint, color: commandStatusColor('FAILED') }}>\n {sendError}\n </div>\n ) : null}\n </div>\n\n {/* Recent-command history with live delivery status. */}\n <CommandHistory commands={data.commands} sentToken={sentToken} loading={data.loading} error={data.error} />\n </>\n )}\n </div>\n </WidgetFrame>\n );\n}\n\n// \u2500\u2500 Parameter field \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nfunction ParamField({\n widgetId,\n param,\n value,\n error,\n disabled,\n onChange,\n}: {\n widgetId: string;\n param: CommandParameter;\n value: string;\n error?: string;\n disabled: boolean;\n onChange: (value: string) => void;\n}) {\n // Scope the input id to the widget so two command-buttons sharing a parameter name\n // don't produce duplicate DOM ids (which would misdirect a label click to the first).\n const labelId = `cmd-${widgetId}-${param.name}`;\n const unit = param.unit ? ` (${param.unit})` : '';\n return (\n <label htmlFor={labelId} style={{ display: 'flex', flexDirection: 'column', gap: 3 }}>\n <span style={{ fontSize: 12, color: css('muted-foreground') }}>\n {param.name}\n {unit}\n {param.required ? <span style={{ color: commandStatusColor('FAILED') }}> *</span> : null}\n </span>\n <ParamInput id={labelId} param={param} value={value} disabled={disabled} onChange={onChange} />\n {error ? (\n <span style={{ fontSize: 11, color: commandStatusColor('FAILED') }}>{error}</span>\n ) : null}\n </label>\n );\n}\n\nfunction ParamInput({\n id,\n param,\n value,\n disabled,\n onChange,\n}: {\n id: string;\n param: CommandParameter;\n value: string;\n disabled: boolean;\n onChange: (value: string) => void;\n}) {\n // An enum (of any data type) \u2192 a select; a boolean \u2192 a checkbox; a number \u2192 a numeric\n // input with the declared bounds; everything else \u2192 text.\n if (param.enum && param.enum.length > 0) {\n return (\n <select id={id} style={inputStyle} value={value} disabled={disabled} onChange={(e) => onChange(e.target.value)}>\n {!param.required ? <option value=\"\">\u2014</option> : null}\n {param.enum.map((opt) => (\n <option key={opt} value={opt}>\n {opt}\n </option>\n ))}\n </select>\n );\n }\n if (param.dataType === 'BOOLEAN') {\n return (\n <input\n id={id}\n type=\"checkbox\"\n style={{ width: 16, height: 16 }}\n checked={parseBool(value)}\n disabled={disabled}\n onChange={(e) => onChange(e.target.checked ? 'true' : 'false')}\n />\n );\n }\n const numeric = param.dataType === 'INT' || param.dataType === 'DOUBLE';\n return (\n <input\n id={id}\n type={numeric ? 'number' : 'text'}\n style={inputStyle}\n value={value}\n disabled={disabled}\n min={param.minValue ?? undefined}\n max={param.maxValue ?? undefined}\n step={param.dataType === 'INT' ? 1 : 'any'}\n placeholder={param.default ?? undefined}\n onChange={(e) => onChange(e.target.value)}\n />\n );\n}\n\n// \u2500\u2500 History \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nfunction CommandHistory({\n commands,\n sentToken,\n loading,\n error,\n}: {\n commands: CommandStreamState['commands'];\n sentToken: string | null;\n loading: boolean;\n error: unknown;\n}) {\n // An error is shown inline here (not by replacing the whole widget) so a transient poll\n // blip never tears down the still-usable send form. Last-good rows stay on screen when\n // present; only an empty-and-errored history shows the notice.\n const empty = commands.length === 0;\n const timeZone = useWidgetTimeZone();\n return (\n <div\n style={{\n flex: 1,\n minHeight: 0,\n overflow: 'auto',\n borderTop: `1px solid ${css('border')}`,\n paddingTop: 6,\n }}\n >\n {empty ? (\n <div style={{ ...hint, textAlign: 'center', color: error ? commandStatusColor('FAILED') : css('muted-foreground') }}>\n {error ? 'Couldn\u2019t load command history.' : loading ? 'Loading\u2026' : 'No commands issued yet.'}\n </div>\n ) : (\n <ul style={{ listStyle: 'none', margin: 0, padding: 0, display: 'flex', flexDirection: 'column', gap: 4 }}>\n {commands.map((command) => (\n <li\n key={command.token}\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: 8,\n fontSize: 12,\n // Highlight the command just issued from this widget.\n fontWeight: command.token === sentToken ? 600 : 400,\n }}\n >\n <StatusBadge status={command.status} />\n <span style={{ color: css('foreground'), whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>\n {command.name}\n </span>\n <span style={{ marginLeft: 'auto', color: css('muted-foreground'), whiteSpace: 'nowrap' }}>\n {formatDateTime(command.queuedTime, timeZone)}\n </span>\n </li>\n ))}\n </ul>\n )}\n </div>\n );\n}\n\nfunction StatusBadge({ status }: { status: string }) {\n const color = commandStatusColor(status);\n return (\n <span\n style={{\n display: 'inline-flex',\n alignItems: 'center',\n gap: 4,\n flexShrink: 0,\n fontSize: 11,\n fontWeight: 600,\n color,\n }}\n >\n <span aria-hidden=\"true\" style={{ width: 7, height: 7, borderRadius: '50%', background: color }} />\n {commandStatusLabel(status)}\n </span>\n );\n}\n\n// \u2500\u2500 styles / helpers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nconst hint: CSSProperties = { fontSize: 11, color: css('muted-foreground') };\n\n// What a viewer is told when the platform could not decide the enqueue. It is fixed\n// prose on purpose: the thrown error's text describes in-cluster machinery, and a\n// dashboard is the surface most likely to be embedded outside the tenant's own console.\nconst SEND_FAILED = 'Couldn\u2019t issue the command. Try again.';\n\nconst inputStyle: CSSProperties = {\n width: '100%',\n boxSizing: 'border-box',\n padding: '4px 8px',\n fontSize: 13,\n borderRadius: 4,\n border: `1px solid ${css('border')}`,\n background: css('background'),\n color: css('foreground'),\n};\n\nconst sendButton: CSSProperties = {\n padding: '6px 12px',\n fontSize: 13,\n fontWeight: 600,\n borderRadius: 4,\n border: 'none',\n background: css('primary'),\n color: css('background'),\n marginTop: 2,\n};\n\n// The registration: this widget's portable descriptor paired with its component, declared\n// through the same public `defineWidget` a third-party package uses.\nexport const commandButtonWidget = defineWidget({\n descriptor: builtinWidgetDescriptors['command-button'],\n implementation: { kind: 'trusted-react', component: CommandButton },\n});\n", "// Copyright The DeviceChain Authors\n// SPDX-License-Identifier: Apache-2.0\n\n// Command delivery-status presentation for the command-button widget (command-delivery\n// lifecycle: QUEUED \u2192 SENT \u2192 SUCCESSFUL | FAILED, with HELD for a dispatch withheld from\n// a known-absent device, PARKED for one published to a device that turned out to be\n// unreachable, and TIMEOUT / EXPIRED / CANCELLED as the other terminals).\n// Status color is SEMANTIC (good/working/waiting/bad), deliberately fixed rather than\n// derived from the dashboard accent, so the same status reads the same on every theme \u2014\n// and it mirrors the console's DeviceCommandsPanel status variants (success /\n// destructive / outline / in-flight) so an operator reads the same signal on both\n// surfaces.\n\nimport { isTerminalCommandStatus } from '@devicechain/dashboards';\n\n// \uD83D\uDD34 EVERY STATUS NEEDS AN ENTRY, INCLUDING THE ONES THAT LOOK NEUTRAL. UNKNOWN_COLOR\n// below is the same slate as EXPIRED, so a status with no entry does not merely fall\n// back \u2014 it becomes INDISTINGUISHABLE from \"lapsed before it was sent\". HELD and PARKED\n// (the command is still coming) rendered in EXPIRED's slate tell an operator the opposite\n// of the truth, which is why they, and CANCELLED, are spelled out rather than left to the\n// fallback.\n//\n// The scheme is by MEANING, not by lifecycle position: sky = moving under its own steam,\n// amber = waiting on a device that isn't there. HELD and PARKED share the amber family\n// because they are the same answer to \"why hasn't it arrived?\" \u2014 the device is away \u2014 and\n// take different shades because they are different answers to \"what did the platform\n// already try?\": HELD never left the platform, PARKED was published and found nobody home.\nconst STATUS_COLORS: Record<string, string> = {\n SUCCESSFUL: '#16a34a', // green-600 \u2014 acknowledged by the device\n FAILED: '#dc2626', // red-600\n TIMEOUT: '#dc2626', // red-600 \u2014 never acknowledged in time\n EXPIRED: '#64748b', // slate-500 \u2014 lapsed before it was ever sent\n CANCELLED: '#7c3aed', // violet-600 \u2014 deliberately called off; a decision, not a failure\n QUEUED: '#0284c7', // sky-600 \u2014 in flight\n SENT: '#0284c7',\n HELD: '#d97706', // amber-600 \u2014 withheld: the device is absent, the command still stands\n PARKED: '#f59e0b', // amber-500 \u2014 published, nobody home; held for the device's return\n};\n\nconst UNKNOWN_COLOR = '#64748b';\n\n// commandStatusColor maps a status to its badge color, falling back to muted slate for\n// an unrecognized value (a future/hand-edited status).\nexport function commandStatusColor(status: string): string {\n return STATUS_COLORS[status] ?? UNKNOWN_COLOR;\n}\n\n// isTerminalStatus reports whether a command has reached a state it can't leave \u2014 the\n// widget stops treating it as in-flight.\n//\n// It is NOT the question \"can this still be cancelled?\": SENT is non-terminal and is not\n// cancellable, so a host gating a cancel control must ask @devicechain/dashboards'\n// isCancellableCommandStatus instead of negating this.\n//\n// It is an alias, not a second definition: the terminal set lives in @devicechain/dashboards\n// so the console, this package and the preview cannot disagree about it. The name is kept\n// because it is part of this package's published surface.\nexport function isTerminalStatus(status: string): boolean {\n return isTerminalCommandStatus(status);\n}\n\n// commandStatusLabel renders a status in Title Case ('SUCCESSFUL' \u2192 'Successful').\nexport function commandStatusLabel(status: string): string {\n if (!status) return '';\n return status.charAt(0).toUpperCase() + status.slice(1).toLowerCase();\n}\n", "// Copyright The DeviceChain Authors\n// SPDX-License-Identifier: Apache-2.0\n\n// Pure form logic for the command-button widget's typed parameter form (ADR-043). The\n// console bakes a command definition's `parameterSchema` (a JSON string) into the\n// widget's options; these helpers parse it, seed defaults, validate operator input, and\n// serialize the typed values back to the JSON payload command-delivery sends the device.\n// Kept separate from the widget so the coercion/validation is unit-tested in isolation.\n//\n// SCOPE: the form types top-level SCALAR parameters (DOUBLE / INT / BOOLEAN / STRING,\n// with enum / bounds / required / default). OBJECT (nested) parameters are not\n// form-editable \u2014 the form blocks sending when one is REQUIRED (it can't be satisfied\n// here) and otherwise omits it. The payload is a flat JSON object keyed by parameter name.\n\nimport type { CommandParameter } from '@devicechain/dashboards';\n\nconst DATA_TYPES = new Set(['DOUBLE', 'INT', 'BOOLEAN', 'STRING']);\n\n// parseParameterSchema turns the baked JSON string into descriptors, defensively:\n// a null/empty/malformed schema (or a non-array root) yields an empty list so a command\n// with no arguments (or a hand-broken schema) renders as a bare Send button, never throws.\n// Each descriptor is NORMALIZED (enum\u2192string[], default\u2192string, bounds\u2192finite number,\n// kind/dataType\u2192known value) so a hand-edited dashboard definition with wrong-typed fields\n// (e.g. `enum: \"on\"` or `default: 5`) can't crash the form at render/send time.\nexport function parseParameterSchema(schema: string | null | undefined): CommandParameter[] {\n if (!schema) return [];\n let parsed: unknown;\n try {\n parsed = JSON.parse(schema);\n } catch {\n return [];\n }\n if (!Array.isArray(parsed)) return [];\n const out: CommandParameter[] = [];\n for (const raw of parsed) {\n const norm = normalizeParam(raw);\n if (norm) out.push(norm);\n }\n return out;\n}\n\n// normalizeParam validates one descriptor and coerces every field to its expected type,\n// dropping the descriptor entirely if it has no string `name`. Unknown/wrong-typed fields\n// are discarded rather than trusted, so downstream code never sees a non-array enum or a\n// numeric default.\nfunction normalizeParam(raw: unknown): CommandParameter | null {\n if (typeof raw !== 'object' || raw === null) return null;\n const r = raw as Record<string, unknown>;\n if (typeof r.name !== 'string') return null;\n\n const param: CommandParameter = { name: r.name };\n if (typeof r.description === 'string') param.description = r.description;\n if (r.kind === 'OBJECT') param.kind = 'OBJECT';\n else if (r.kind === 'SCALAR') param.kind = 'SCALAR';\n if (typeof r.dataType === 'string' && DATA_TYPES.has(r.dataType)) {\n param.dataType = r.dataType as CommandParameter['dataType'];\n }\n if (typeof r.unit === 'string') param.unit = r.unit;\n if (r.required === true) param.required = true;\n if (typeof r.default === 'string') param.default = r.default;\n if (typeof r.minValue === 'number' && Number.isFinite(r.minValue)) param.minValue = r.minValue;\n if (typeof r.maxValue === 'number' && Number.isFinite(r.maxValue)) param.maxValue = r.maxValue;\n if (Array.isArray(r.enum)) {\n const values = r.enum.filter((v): v is string => typeof v === 'string');\n if (values.length > 0) param.enum = values;\n }\n return param;\n}\n\n// isScalar reports whether a parameter is a typed single value the form renders an input\n// for. Kind absent means SCALAR (the Go default); only an explicit OBJECT is nested.\nexport function isScalar(param: CommandParameter): boolean {\n return param.kind !== 'OBJECT';\n}\n\n// parseBool interprets a schema/string boolean the way the server's strconv.ParseBool\n// does (accepting '1'/'t'/'true'/'yes'/'on', case-insensitively) so a definition default\n// of \"True\" doesn't silently render \u2014 and send \u2014 as false.\nexport function parseBool(raw: string): boolean {\n const s = raw.trim().toLowerCase();\n return s === 'true' || s === '1' || s === 't' || s === 'yes' || s === 'on';\n}\n\n// defaultValues seeds the form's value map from each scalar parameter. A BOOLEAN always\n// gets a concrete 'true'/'false' (default false) \u2014 a checkbox is never \"empty\", so the\n// value must reflect the box's state exactly. Other scalars seed from their declared\n// default (as a string \u2014 inputs are string-backed), else start empty.\nexport function defaultValues(params: CommandParameter[]): Record<string, string> {\n const values: Record<string, string> = {};\n for (const p of params) {\n if (!isScalar(p)) continue;\n if (p.dataType === 'BOOLEAN') values[p.name] = parseBool(p.default ?? '') ? 'true' : 'false';\n else if (p.default != null) values[p.name] = p.default;\n }\n return values;\n}\n\n// validateParams returns a per-parameter error map (empty = valid). It enforces required\n// (a missing value on a required scalar; a BOOLEAN always has a value so is never\n// \"required-missing\"), numeric validity/bounds for INT/DOUBLE, and blocks a REQUIRED\n// OBJECT parameter (it can't be supplied through the typed form).\nexport function validateParams(\n params: CommandParameter[],\n values: Record<string, string>,\n): Record<string, string> {\n const errors: Record<string, string> = {};\n for (const p of params) {\n if (!isScalar(p)) {\n // A required structured parameter can't be satisfied here \u2014 refuse to send an\n // incomplete command rather than silently omitting it.\n if (p.required) errors[p.name] = 'Structured parameter \u2014 not supported here';\n continue;\n }\n if (p.dataType === 'BOOLEAN') continue; // a checkbox always carries a valid value\n const raw = (values[p.name] ?? '').trim();\n if (raw === '') {\n if (p.required) errors[p.name] = 'Required';\n continue; // an empty optional value is fine \u2014 it's just omitted from the payload\n }\n if (p.dataType === 'INT' || p.dataType === 'DOUBLE') {\n const n = Number(raw);\n if (!Number.isFinite(n)) {\n errors[p.name] = 'Must be a number';\n } else if (p.dataType === 'INT' && !Number.isInteger(n)) {\n errors[p.name] = 'Must be a whole number';\n } else if (p.minValue != null && n < p.minValue) {\n errors[p.name] = `Must be \u2265 ${p.minValue}`;\n } else if (p.maxValue != null && n > p.maxValue) {\n errors[p.name] = `Must be \u2264 ${p.maxValue}`;\n }\n }\n }\n return errors;\n}\n\n// buildPayload serializes the typed values to the JSON payload string command-delivery\n// sends the device \u2014 coercing each scalar to its declared type (INT/DOUBLE \u2192 number,\n// BOOLEAN \u2192 boolean, STRING \u2192 string). A BOOLEAN is always included (its checkbox state\n// is meaningful); other empty optional values are omitted. OBJECT parameters are omitted\n// (validateParams blocks a required one first). Returns undefined when no parameter\n// contributes a value (a parameterless command sends no payload).\nexport function buildPayload(\n params: CommandParameter[],\n values: Record<string, string>,\n): string | undefined {\n const payload: Record<string, unknown> = {};\n for (const p of params) {\n if (!isScalar(p)) continue;\n const raw = (values[p.name] ?? '').trim();\n if (p.dataType === 'BOOLEAN') {\n payload[p.name] = parseBool(raw);\n continue;\n }\n if (raw === '') continue;\n payload[p.name] = coerce(p, raw);\n }\n return Object.keys(payload).length === 0 ? undefined : JSON.stringify(payload);\n}\n\nfunction coerce(param: CommandParameter, raw: string): unknown {\n switch (param.dataType) {\n case 'INT':\n case 'DOUBLE': {\n const n = Number(raw);\n return Number.isFinite(n) ? n : raw; // validation gates this; fall back to raw defensively\n }\n case 'BOOLEAN':\n return parseBool(raw);\n default:\n return raw; // STRING (and untyped)\n }\n}\n", "// Copyright The DeviceChain Authors\n// SPDX-License-Identifier: Apache-2.0\n\n// entity-selector \u2014 a flat picker that re-points a target slot's binding (ADR-039 selection\n// amendment). It is the authored companion to the alarm-originator drill: the viewer chooses\n// WHICH entity a slot binds to, and every widget bound to that slot (and its scoped children,\n// via the cascade) follows. Two shapes, both from `options.selectionTarget`:\n// \u2022 target is a SCOPED child slot \u2192 a member picker (which thermostat within the building).\n// \u2022 target is a ROOT slot \u2192 a context picker (which building the dashboard shows).\n// The candidate set comes from the ambient provider (useCandidates), which the host computes\n// from the target slot's scope; the pick fires the ambient select() callback. Inert (a muted\n// hint) wherever selection isn't wired \u2014 edit mode, preview, a read-only embedder.\n\nimport type { SlotBinding } from '@devicechain/dashboards';\nimport { useEffect, useState, type ChangeEvent, type CSSProperties } from 'react';\n\nimport {\n css,\n defineWidget,\n optString,\n useCandidates,\n useWidgetSelect,\n WidgetFrame,\n type WidgetProps,\n} from '@devicechain/widget-sdk';\n\nimport { builtinWidgetDescriptors } from '../builtin-descriptors';\n\n// A binding's stable option value \u2014 the device token or the anchor's target token. Used as\n// the <option> value (not the array index) so the control's value survives a re-fetch that\n// reorders/replaces candidates.\nfunction tokenOf(b: SlotBinding): string {\n return b.kind === 'device' ? b.deviceToken : b.anchor.targetToken;\n}\n\nconst control: CSSProperties = {\n width: '100%',\n fontSize: 14,\n padding: '8px 10px',\n borderRadius: 6,\n border: `1px solid ${css('border')}`,\n background: css('background'),\n color: css('foreground'),\n};\n\nconst hint: CSSProperties = {\n fontSize: 12,\n color: css('muted-foreground'),\n};\n\nexport function EntitySelector({ widget }: WidgetProps<null>) {\n const select = useWidgetSelect();\n const target = optString(widget.options, 'selectionTarget');\n const { candidates, loading, error, wired } = useCandidates(target);\n const title = optString(widget.options, 'title');\n\n // Optimistic pick: hold the just-chosen token so the control reflects the choice\n // immediately \u2014 through the (on a scoped dashboard, two-hop) async re-resolve \u2014 rather\n // than snapping back to the prior selection until the refetch settles. Cleared once the\n // fetched candidates reflect it, or it is no longer offered (the pick was dropped).\n const [pending, setPending] = useState<string | null>(null);\n const selected = candidates.find((c) => c.selected);\n const selectedToken = selected ? tokenOf(selected.binding) : '';\n useEffect(() => {\n if (pending !== null && (selectedToken === pending || !candidates.some((c) => tokenOf(c.binding) === pending))) {\n setPending(null);\n }\n }, [candidates, selectedToken, pending]);\n\n // Inert wherever selection isn't wired (no select callback OR no candidate provider) or no\n // target slot is authored \u2014 the picker would drive nothing, so show a muted explanation.\n const inert = !select || !target || !wired;\n const value = pending ?? selectedToken;\n\n const onChange = (e: ChangeEvent<HTMLSelectElement>) => {\n const token = e.target.value;\n if (!token) return; // the disabled placeholder ('') \u2014 nothing to select\n const candidate = candidates.find((c) => tokenOf(c.binding) === token);\n if (select && target && candidate) {\n setPending(token);\n select({ slot: target, binding: candidate.binding });\n }\n };\n\n return (\n <WidgetFrame title={title}>\n <div style={{ display: 'flex', flexDirection: 'column', gap: 8, padding: '12px 16px', height: '100%' }}>\n {inert ? (\n <span style={hint}>\n {select && target ? 'Selection isn\u2019t available here.' : select ? 'No target slot configured.' : 'Selection is available on the live dashboard.'}\n </span>\n ) : (\n <>\n <select\n style={{ ...control, opacity: loading ? 0.6 : 1 }}\n value={value}\n disabled={candidates.length === 0}\n onChange={onChange}\n aria-label={title || `Select ${target}`}\n >\n {/* A blank option so an unbound slot (no member picked yet, or the prior pick\n is out of the new context) shows a prompt rather than defaulting to a row. */}\n <option value=\"\" disabled>\n {loading ? 'Loading\u2026' : candidates.length === 0 ? 'No options' : 'Select\u2026'}\n </option>\n {candidates.map((c) => (\n <option key={tokenOf(c.binding)} value={tokenOf(c.binding)}>\n {c.label}\n </option>\n ))}\n </select>\n {error ? <span style={hint}>Couldn\u2019t load options.</span> : null}\n </>\n )}\n </div>\n </WidgetFrame>\n );\n}\n\n// The registration: this widget's portable descriptor paired with its component, declared\n// through the same public `defineWidget` a third-party package uses.\nexport const entitySelectorWidget = defineWidget({\n descriptor: builtinWidgetDescriptors['entity-selector'],\n implementation: { kind: 'trusted-react', component: EntitySelector },\n});\n", "// Copyright The DeviceChain Authors\n// SPDX-License-Identifier: Apache-2.0\n\n// gauge \u2014 the current value of one measurement on an ECharts radial gauge.\n\nimport { useMemo } from 'react';\n\nimport {\n defineWidget,\n flashBackgroundStyle,\n optBoolean,\n optNumber,\n optString,\n pickSample,\n primaryMeasurementName,\n useElementSize,\n useFlashOnChange,\n WidgetFrame,\n type WidgetProps,\n} from '@devicechain/widget-sdk';\nimport { buildGaugeOption, EChart, useChartTheme } from '@devicechain/widget-sdk/echarts';\n\nimport { builtinWidgetDescriptors } from '../builtin-descriptors';\n\nexport function Gauge({ widget, data }: WidgetProps) {\n const theme = useChartTheme();\n const [sizeRef, size] = useElementSize<HTMLDivElement>();\n const name = primaryMeasurementName(widget);\n const sample = pickSample(data.latest, name);\n\n const min = optNumber(widget.options, 'min');\n const max = optNumber(widget.options, 'max');\n const unit = optString(widget.options, 'unit');\n\n const option = useMemo(\n () => buildGaugeOption(sample?.value ?? null, theme, { min, max, unit }, size),\n [sample?.value, theme, min, max, unit, size.width, size.height],\n );\n\n // Opt-in directional flash. The value lives on an opaque canvas, so the cue is a\n // translucent tint on the container behind it rather than a recolored number. The identity\n // (device + measurement) suppresses a false flash on an anchor's cross-device interleave.\n const flashDirection = useFlashOnChange(\n sample?.value,\n optBoolean(widget.options, 'flashOnChange'),\n sample && `${sample.deviceToken}:${sample.name}`,\n );\n\n return (\n <WidgetFrame title={optString(widget.options, 'title') ?? name}>\n <div ref={sizeRef} style={{ width: '100%', height: '100%', ...flashBackgroundStyle(flashDirection) }}>\n <EChart option={option} />\n </div>\n </WidgetFrame>\n );\n}\n\n// The registration: this widget's portable descriptor paired with its component, declared\n// through the same public `defineWidget` a third-party package uses.\nexport const gaugeWidget = defineWidget({\n descriptor: builtinWidgetDescriptors['gauge'],\n implementation: { kind: 'trusted-react', component: Gauge },\n});\n", "// Copyright The DeviceChain Authors\n// SPDX-License-Identifier: Apache-2.0\n\n// image \u2014 a static image on the canvas (floor plans, logos, SCADA backdrops). No\n// datasource; the Phase-4 SCADA symbol family will layer live SVG on top of this.\n\nimport type { CSSProperties } from 'react';\n\nimport {\n css,\n defineWidget,\n optString,\n WidgetFrame,\n type WidgetProps,\n} from '@devicechain/widget-sdk';\n\nimport { builtinWidgetDescriptors } from '../builtin-descriptors';\n\nconst FITS = new Set(['contain', 'cover', 'fill']);\n\nexport function Image({ widget }: WidgetProps<null>) {\n const url = optString(widget.options, 'url');\n const alt = optString(widget.options, 'alt') ?? '';\n const fitOption = optString(widget.options, 'fit');\n const objectFit = (fitOption && FITS.has(fitOption) ? fitOption : 'contain') as CSSProperties['objectFit'];\n\n return (\n <WidgetFrame title={optString(widget.options, 'title')}>\n {url ? (\n <img src={url} alt={alt} style={{ width: '100%', height: '100%', objectFit, display: 'block' }} />\n ) : (\n <div\n style={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n height: '100%',\n color: css('muted-foreground'),\n fontSize: 13,\n }}\n >\n No image URL\n </div>\n )}\n </WidgetFrame>\n );\n}\n\n// The registration: this widget's portable descriptor paired with its component, declared\n// through the same public `defineWidget` a third-party package uses.\nexport const imageWidget = defineWidget({\n descriptor: builtinWidgetDescriptors['image'],\n implementation: { kind: 'trusted-react', component: Image },\n});\n", "// Copyright The DeviceChain Authors\n// SPDX-License-Identifier: Apache-2.0\n\n// label \u2014 static text on the canvas (headings, captions, annotations). No\n// datasource. Renders plain text only (no raw HTML) so a tenant-authored\n// definition can't inject markup.\n\nimport type { CSSProperties } from 'react';\n\nimport {\n css,\n defineWidget,\n optNumber,\n optString,\n WidgetFrame,\n type WidgetProps,\n} from '@devicechain/widget-sdk';\n\nimport { builtinWidgetDescriptors } from '../builtin-descriptors';\n\nconst justify: Record<string, CSSProperties['justifyContent']> = {\n left: 'flex-start',\n center: 'center',\n right: 'flex-end',\n};\n\nexport function Label({ widget }: WidgetProps<null>) {\n const text = optString(widget.options, 'text') ?? '';\n const align = optString(widget.options, 'align') ?? 'center';\n const fontSize = optNumber(widget.options, 'fontSize') ?? 16;\n\n return (\n <WidgetFrame title={optString(widget.options, 'title')}>\n <div\n style={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: justify[align] ?? 'center',\n height: '100%',\n padding: 12,\n }}\n >\n <span\n style={{\n fontSize,\n color: css('foreground'),\n textAlign: align as CSSProperties['textAlign'],\n whiteSpace: 'pre-wrap',\n }}\n >\n {text}\n </span>\n </div>\n </WidgetFrame>\n );\n}\n\n// The registration: this widget's portable descriptor paired with its component, declared\n// through the same public `defineWidget` a third-party package uses.\nexport const labelWidget = defineWidget({\n descriptor: builtinWidgetDescriptors['label'],\n implementation: { kind: 'trusted-react', component: Label },\n});\n", "// Copyright The DeviceChain Authors\n// SPDX-License-Identifier: Apache-2.0\n\n// latest-card \u2014 the current value of one measurement, big and legible.\n\nimport {\n css,\n defineWidget,\n flashTextStyle,\n formatTimestamp,\n formatValue,\n optBoolean,\n optNumber,\n optString,\n pickSample,\n primaryMeasurementName,\n useElementSize,\n useFlashOnChange,\n useWidgetTimeZone,\n WidgetFrame,\n type WidgetProps,\n} from '@devicechain/widget-sdk';\n\nimport { builtinWidgetDescriptors } from '../builtin-descriptors';\n\nconst clamp = (v: number, lo: number, hi: number): number => Math.max(lo, Math.min(hi, v));\n\nexport function LatestCard({ widget, data }: WidgetProps) {\n const [sizeRef, size] = useElementSize<HTMLDivElement>();\n const timeZone = useWidgetTimeZone();\n const name = primaryMeasurementName(widget);\n const sample = pickSample(data.latest, name);\n\n const title = optString(widget.options, 'title') ?? name;\n const unit = optString(widget.options, 'unit');\n const precision = optNumber(widget.options, 'precision');\n const display = formatValue(sample?.value, precision);\n\n // Opt-in directional flash: tint the number green/red on a rise/fall, then fade back. The\n // identity (device + measurement) suppresses a false flash when an anchor's single slot\n // interleaves values across member devices, or the shown measurement switches.\n const flashDirection = useFlashOnChange(\n sample?.value,\n optBoolean(widget.options, 'flashOnChange'),\n sample && `${sample.deviceToken}:${sample.name}`,\n );\n\n // Scale the value to the card so it doesn't overflow a small slot (falls back to\n // a comfortable size before first measure / in a non-DOM test).\n const valueFont = size.height > 0 ? clamp(Math.round(size.height / 3.5), 16, 44) : 32;\n\n return (\n <WidgetFrame title={title}>\n <div\n ref={sizeRef}\n style={{\n display: 'flex',\n flexDirection: 'column',\n justifyContent: 'center',\n height: '100%',\n padding: '12px 16px',\n }}\n >\n <div\n style={{\n fontSize: valueFont,\n fontWeight: 600,\n lineHeight: 1.1,\n color: css('foreground'),\n ...flashTextStyle(flashDirection),\n }}\n >\n {display}\n {sample?.value != null && unit ? (\n <span style={{ fontSize: Math.round(valueFont / 2), color: css('muted-foreground'), marginLeft: 6 }}>\n {unit}\n </span>\n ) : null}\n </div>\n {sample?.occurredTime ? (\n <div style={{ fontSize: 11, color: css('muted-foreground'), marginTop: 4 }}>\n {formatTimestamp(sample.occurredTime, timeZone)}\n </div>\n ) : null}\n </div>\n </WidgetFrame>\n );\n}\n\n// The registration: this widget's portable descriptor paired with its component, declared\n// through the same public `defineWidget` a third-party package uses.\nexport const latestCardWidget = defineWidget({\n descriptor: builtinWidgetDescriptors['latest-card'],\n implementation: { kind: 'trusted-react', component: LatestCard },\n});\n", "// Copyright The DeviceChain Authors\n// SPDX-License-Identifier: Apache-2.0\n\n// map \u2014 the bound devices' last-known positions, on the location channel.\n//\n// Three rules shape everything here, and each of them is a state some other design\n// would have collapsed into \"the map is empty\":\n//\n// \uD83D\uDD34 REFUSED IS NOT EMPTY. Position is gated on its own `location:read` authority,\n// deliberately absent from the read-only viewer baseline, so an ordinary member with\n// full telemetry access is routinely refused. \"No devices to show\" and \"you are not\n// allowed to see this\" are opposite facts and only one of them is actionable, so the\n// refusal gets its own copy and its own look \u2014 never a blank map.\n//\n// \uD83D\uDD34 NO TILE SOURCE IS NOT A BROKEN MAP. This package hardcodes no tile URL (see\n// rasterStyleFor) and inherits one from the tenant (ADR-079), whose instance-wide\n// default now ships a real provider \u2014 so in practice this branch is rare. It is not\n// dead, though: an operator can empty that default, an air-gapped install can have no\n// route to any provider at all, and a viewer can be looking at a board on either.\n//\n// That case renders a REAL MapLibre map against the BUNDLED public-domain world\n// (loadLandStyle) \u2014 continents and country outlines, compiled into this package.\n//\n// \uD83D\uDD34 Be precise about what survives of the old promise, because an earlier version of\n// this comment was not. It said the widget \"issues no request to any host\" and backed\n// that with \"loads no map library\", and the second half is now FALSE: this path loads\n// the renderer and the geometry, two chunks, from the app's OWN origin. What is still\n// true \u2014 and is the part that ever mattered \u2014 is that it contacts no THIRD-PARTY host,\n// because it has been given none it would be entitled to ask. What it no longer does\n// is show a void that reads as breakage.\n//\n// \uD83D\uDD34 ABSENT IS NOT ZERO. A marker describes only what its device reported; an\n// unreported heading is not due north. See describePosition.\n\nimport { useEffect, useRef, useState, type CSSProperties } from 'react';\nimport { renderableBasemap, resolveBasemap } from '@devicechain/client';\n\nimport { useTenantBasemap } from '../basemap-context';\nimport { useMapRuntime, type MapRuntime } from '../map-runtime-context';\nimport {\n css,\n defineWidget,\n type LocationStreamState,\n optString,\n WidgetFrame,\n type WidgetProps,\n} from '@devicechain/widget-sdk';\n\nimport { builtinWidgetDescriptors } from '../builtin-descriptors';\nimport {\n describePosition,\n loadLandStyle,\n placeable,\n projectToPanel,\n rasterStyleFor,\n type PlaceableLocation,\n} from './map-geometry';\n\n// The MapLibre pieces this widget drives. A TYPE-only import is erased at build time,\n// so naming them here creates no static dependency on the library \u2014 the value only ever\n// arrives through the dynamic import below.\nimport type { Map as MapLibreMap, Marker as MapLibreMarker } from 'maplibre-gl';\n\n// \uD83D\uDD34 THE LIBRARY IS LOADED LAZILY, BY CONSTRUCTION. MapLibre is ~200 KB gzipped, and\n// only a dashboard that actually contains a map widget may pay for it \u2014 a console user\n// who never opens a board with a map must not download a map renderer. The dynamic\n// import is what puts it in its own chunk; a top-level `import 'maplibre-gl'` anywhere\n// in this package would fold it into the main bundle for every viewer, and nothing\n// about the widget's behaviour would change to reveal it.\n//\n// MapLibre's STYLESHEET is no longer imported here at all \u2014 it is the host's, along with\n// the worker URL, for the reason set out below and in map-runtime-context. A host may hand\n// back a loader for it (`MapRuntime.loadStyles`) to keep it on this same lazy chunk, or\n// import it eagerly and pay 83 KB (10.7 KB gzipped) in its main stylesheet. That is the\n// host's call, and both are reasonable; what a LIBRARY cannot do is decide it for them in\n// one bundler's dialect.\n//\n// Loaded once and memoized: several map widgets on one board share the fetch.\nlet mapLibrePromise: Promise<typeof import('maplibre-gl')> | undefined;\n\n// \uD83D\uDD34 THE WORKER HAS TO BE ASKED FOR BY NAME, and getting this wrong produces a map\n// that builds, type-checks, passes every test and then renders nothing. MapLibre\n// otherwise derives the worker's URL at runtime from its own module URL, which is a\n// string no bundler can follow \u2014 nothing emits the file, the browser 404s it, and\n// `new Worker()` does not throw on a 404: the failure arrives later as an async error\n// event, so the map simply sits there having loaded no tiles.\n//\n// \uD83D\uDD34 THE URL COMES FROM THE HOST, and this package no longer computes it. Emitting a\n// worker entry is a bundler-specific act \u2014 Vite spells it `?worker&url`, webpack and\n// Rollup spell it differently \u2014 so a library that writes one dialect works under that\n// bundler and silently renders a blank map under every other. See map-runtime-context\n// for the full argument; the short version is that the specifier is externalized, so\n// no build anywhere reports the breakage.\n//\n// Memoized for the whole module, and FIRST CALLER WINS: several map widgets on one\n// board share the fetch, and `setWorkerUrl` is global state in MapLibre, so a second\n// caller with a different URL could not be honoured even if we tried. In practice\n// there is one provider at the top of the tree and therefore one URL.\nfunction loadMapLibre(runtime: MapRuntime): Promise<typeof import('maplibre-gl')> {\n if (!mapLibrePromise) {\n // The stylesheet rides the SAME dynamic boundary as the renderer, which is why a host\n // may pass a loader rather than importing it at module scope: it is 83 KB raw, 10.7 KB\n // gzipped (maplibre-gl 6.6.0), and a viewer who opens no map should download none of\n // it. Optional \u2014 a host that imports the stylesheet itself is doing the ordinary thing.\n //\n // \uD83D\uDD34 `Promise.resolve().then(...)` IS NOT CEREMONY. `loadStyles()` is host code, and a\n // host CAN throw synchronously \u2014 `loadStyles: () => require('\u2026css')` on a bundler with\n // no CSS loader is the realistic form. Called while building the argument array, that\n // throw escapes loadMapLibre entirely, propagates through the caller's own\n // `Promise.all` argument evaluation, and lands in React's commit phase where the\n // effect's `.catch` cannot see it: React 19 unmounts the tree, so one misconfigured\n // host loader takes down the whole dashboard instead of degrading to the plain panel.\n // Deferring the call puts it inside the promise chain, where the existing catch works.\n mapLibrePromise = Promise.all([\n import('maplibre-gl'),\n Promise.resolve().then(() => runtime.loadStyles?.()),\n ]).then(([mod]) => {\n mod.setWorkerUrl(runtime.workerUrl);\n return mod;\n });\n }\n return mapLibrePromise;\n}\n\n// The zoom a single-device map opens at \u2014 close enough to read a site, wide enough that\n// a lone marker is not floating in featureless tiles. A multi-device map ignores it and\n// fits the fleet's bounds instead.\nconst SINGLE_DEVICE_ZOOM = 14;\n\nexport function MapWidget({ widget, data }: WidgetProps<LocationStreamState>) {\n const title = optString(widget.options, 'title');\n const positions = placeable(data.locations);\n\n // The host's bundler-produced MapLibre runtime. Read unconditionally, with the other\n // hooks, because a hook cannot live behind one of the early returns below.\n const runtime = useMapRuntime();\n\n // Precedence is per-widget override \u2192 tenant \u2192 no basemap (ADR-079 \u00A79). The\n // per-widget options are kept, not replaced: they are how someone tries a provider\n // on one board before committing it tenant-wide.\n //\n // \uD83D\uDD34 resolveBasemap is NOT `override ?? tenant` per field. A widget that names its\n // own tile URL does not inherit the tenant's credit line, because that would credit\n // the tenant's provider for tiles it did not serve. The SDK owns that rule so the\n // fence editor and the /dash app cannot disagree with this widget about it.\n const basemap = renderableBasemap(\n resolveBasemap(\n {\n tileUrl: optString(widget.options, 'tileUrl'),\n attribution: optString(widget.options, 'attribution'),\n },\n useTenantBasemap(),\n ),\n );\n\n // The refusal is checked FIRST and unconditionally: it is a fact about the caller, so\n // it outranks anything about the data, and it must not be reachable only through some\n // \"no positions\" branch that a later edit could reorder past.\n if (data.forbidden) {\n return (\n <WidgetFrame title={title}>\n <MapNotice\n glyph=\"\uD83D\uDD12\"\n heading=\"Location not permitted\"\n detail=\"You do not have permission to view device locations.\"\n />\n </WidgetFrame>\n );\n }\n\n // \uD83D\uDD34 AND THE HOST'S OWN WIRING IS CHECKED SECOND, for the same reason the refusal is\n // checked first: it is a fact about the environment rather than about the data, so it\n // outranks every \"nothing to show\" branch below. Checking it later would hide it behind\n // \"No devices selected\" on exactly the board a developer is using to find it.\n //\n // There is no fallback to take. The only alternative to a host-supplied worker URL is\n // MapLibre's runtime derivation, which is the silent blank map this seam exists to\n // prevent \u2014 so an unwired host is told, in the widget, what it has to install.\n if (!runtime) {\n return (\n <WidgetFrame title={title}>\n <MapNotice\n glyph=\"\uD83E\uDDE9\"\n heading=\"Map runtime not configured\"\n detail=\"This host must install MapRuntimeProvider with its bundler's MapLibre worker URL.\"\n />\n </WidgetFrame>\n );\n }\n\n if (data.loading && positions.length === 0) {\n return (\n <WidgetFrame title={title}>\n <MapNotice heading=\"Loading\u2026\" />\n </WidgetFrame>\n );\n }\n\n if (positions.length === 0) {\n // Two different empty states, because they call for two different actions: bind the\n // widget, or wait for a device to report.\n return (\n <WidgetFrame title={title}>\n <MapNotice\n heading={data.deviceTokens.length === 0 ? 'No devices selected' : 'No positions reported'}\n detail={\n data.deviceTokens.length === 0\n ? 'Bind this widget to a device or anchor and select its location series.'\n : 'None of the selected devices has reported a position yet.'\n }\n />\n </WidgetFrame>\n );\n }\n\n return (\n <WidgetFrame title={title} bodyStyle={{ padding: 0 }}>\n <LiveMap basemap={basemap} positions={positions} runtime={runtime} />\n </WidgetFrame>\n );\n}\n\n// ---- The tile-less panel ----------------------------------------------------\n\n// PlainPanel draws the positions on a themed background with no basemap at all.\n//\n// \uD83D\uDD34 IT HAS EXACTLY ONE JOB LEFT, AND IT IS NOT THE UNCONFIGURED CASE. Since the\n// bundled world basemap landed, an unconfigured widget renders a REAL MapLibre map\n// against public-domain geometry \u2014 so this panel is reached only when the map could\n// not be BUILT at all. Three ways in, not one: the MapLibre chunk fails to load, the\n// bundled-geometry chunk fails to load, or the Map constructor throws (a browser or a\n// context with no usable WebGL). They share a catch because they share an answer.\n//\n// It survives because on that path it is strictly better than an error box. The\n// question a map widget answers is \"where is my fleet, relative to each other\",\n// and this still answers it when the renderer cannot load. That is also why\n// projectToPanel exists at all, and why deleting either would look like tidying up\n// dead code right until someone's dashboard went blank behind a proxy.\nfunction PlainPanel({ positions, note }: { positions: PlaceableLocation[]; note: string }) {\n const points = projectToPanel(positions);\n return (\n <div\n data-testid=\"map-plain-panel\"\n style={{\n position: 'relative',\n width: '100%',\n height: '100%',\n overflow: 'hidden',\n background: css('muted'),\n }}\n >\n {positions.map((position, i) => (\n <Marker\n key={position.deviceToken}\n position={position}\n style={{\n position: 'absolute',\n left: `${points[i].x * 100}%`,\n top: `${points[i].y * 100}%`,\n transform: 'translate(-50%, -50%)',\n }}\n />\n ))}\n <div\n data-testid=\"map-no-tiles-note\"\n style={{\n position: 'absolute',\n left: 0,\n right: 0,\n bottom: 0,\n padding: '4px 8px',\n fontSize: 10,\n lineHeight: 1.3,\n textAlign: 'center',\n color: css('muted-foreground'),\n background: css('card'),\n opacity: 0.9,\n }}\n >\n {note}\n </div>\n </div>\n );\n}\n\n// ---- The map ----------------------------------------------------------------\n\ntype MapStatus = 'loading' | 'ready' | 'unavailable';\n\n// LiveMap renders MapLibre for BOTH basemap states.\n//\n// The branch is over the STYLE, not over whether there is a map: a configured tile\n// source gets a raster style, and no tile source gets the bundled public-domain\n// world. Everything downstream of that \u2014 the projection, the markers, the fit, the\n// teardown \u2014 is the same code on both paths, which is the point. When the two were\n// different components, \"unconfigured\" was a second rendering path that could drift\n// away from the real one without any test noticing.\n// `runtime` is a required prop rather than a context read, so that LiveMap cannot be\n// constructed without one. The null case is handled once, in MapWidget, and this\n// component never has to reason about it.\nfunction LiveMap({\n basemap,\n positions,\n runtime,\n}: {\n basemap: { tileUrl: string; attribution: string | null } | null;\n positions: PlaceableLocation[];\n runtime: MapRuntime;\n}) {\n const containerRef = useRef<HTMLDivElement>(null);\n const mapRef = useRef<MapLibreMap | null>(null);\n const markersRef = useRef<MapLibreMarker[]>([]);\n const [status, setStatus] = useState<MapStatus>('loading');\n\n const tileUrl = basemap?.tileUrl ?? null;\n const attribution = basemap?.attribution ?? null;\n\n // Init + teardown for this basemap. Re-runs when the source changes, which is the\n // only thing that invalidates the style.\n useEffect(() => {\n let cancelled = false;\n setStatus('loading');\n\n // \uD83D\uDD34 The bundled style is FETCHED, not built inline: its geometry sits behind a\n // dynamic import so a configured viewer never downloads a world map they will\n // not look at. Resolved alongside the renderer so the Map is still constructed\n // once, with its final style \u2014 nothing re-styles after mount.\n Promise.all([\n loadMapLibre(runtime),\n tileUrl ? rasterStyleFor(tileUrl, attribution ?? undefined) : loadLandStyle(),\n ])\n .then(([maplibre, style]) => {\n const el = containerRef.current;\n if (cancelled || !el) return;\n const map = new maplibre.Map({\n container: el,\n style: style as never,\n center: [0, 0],\n zoom: 1,\n });\n mapRef.current = map;\n setStatus('ready');\n })\n .catch(() => {\n // The renderer or the bundled geometry could not be fetched (offline viewer,\n // a CSP that blocks the chunk). Fall back to the plain panel rather than to\n // nothing: the positions are what the operator came for, and the basemap is\n // the part that failed.\n if (!cancelled) setStatus('unavailable');\n });\n\n return () => {\n cancelled = true;\n for (const marker of markersRef.current) marker.remove();\n markersRef.current = [];\n mapRef.current?.remove();\n mapRef.current = null;\n };\n // \uD83D\uDD34 Keyed on runtime.workerUrl, NOT on `runtime`. A host that builds the runtime\n // inline in JSX hands a new object every render; depending on the object would tear the\n // map down and rebuild it each time, which looks like flicker and loses view state. The\n // URL is the only part of it this effect's outcome depends on.\n //\n // `runtime.loadStyles` is used inside and is deliberately not a dependency: loadMapLibre\n // memoizes at module scope, first caller wins, so only the first runtime's loader is\n // ever invoked and a later one could not take effect however this array were written.\n // That is the documented contract, not an oversight \u2014 and no eslint config in this repo\n // lints packages/*, so a disable comment here would suppress nothing and merely look\n // like the question had been settled by a linter.\n }, [tileUrl, attribution, runtime.workerUrl]);\n\n // Sync the markers to the current positions. Rebuilt wholesale rather than diffed:\n // a poll delivers a whole snapshot, the marker count is a dashboard's worth of\n // devices, and a diff here would be state to get wrong for no measurable saving.\n useEffect(() => {\n const map = mapRef.current;\n if (status !== 'ready' || !map) return;\n\n let live = true;\n loadMapLibre(runtime).then((maplibre) => {\n if (!live || mapRef.current !== map) return;\n for (const marker of markersRef.current) marker.remove();\n markersRef.current = positions.map((position) => {\n const el = document.createElement('div');\n el.setAttribute('data-testid', 'map-marker');\n el.setAttribute('data-device', position.deviceToken);\n el.setAttribute('title', describePosition(position));\n el.setAttribute('aria-label', describePosition(position));\n Object.assign(el.style, MARKER_DOT_STYLE);\n // \uD83D\uDD34 setLngLat takes [LONGITUDE, LATITUDE] \u2014 x before y, the opposite order\n // from how a coordinate is spoken and written everywhere else on the platform.\n // Swapping them puts a device reporting Atlanta into the Indian Ocean, which\n // renders perfectly.\n return new maplibre.Marker({ element: el })\n .setLngLat([position.longitude, position.latitude])\n .addTo(map);\n });\n\n if (positions.length === 1) {\n map.jumpTo({ center: [positions[0].longitude, positions[0].latitude], zoom: SINGLE_DEVICE_ZOOM });\n } else if (positions.length > 1) {\n const bounds = new maplibre.LngLatBounds();\n for (const p of positions) bounds.extend([p.longitude, p.latitude]);\n map.fitBounds(bounds, { padding: 40, animate: false });\n }\n });\n\n return () => {\n live = false;\n };\n // Positions are compared by VALUE: a poll hands back a fresh array every tick, and\n // rebuilding every marker 4 times a minute for an unchanged fleet would make the\n // markers flicker.\n }, [status, positionsKey(positions)]);\n\n if (status === 'unavailable') {\n return (\n <PlainPanel\n positions={positions}\n note=\"Map renderer unavailable \u2014 positions are shown without a basemap.\"\n />\n );\n }\n\n return <div ref={containerRef} data-testid=\"map-canvas\" style={{ width: '100%', height: '100%' }} />;\n}\n\n// positionsKey is the value identity of a marker set: what is drawn, not which array\n// object carries it.\nfunction positionsKey(positions: PlaceableLocation[]): string {\n return positions.map((p) => `${p.deviceToken}:${p.latitude}:${p.longitude}:${p.heading ?? ''}`).join('|');\n}\n\n// ---- Shared bits ------------------------------------------------------------\n\nconst MARKER_DOT_STYLE = {\n width: '12px',\n height: '12px',\n borderRadius: '50%',\n background: css('primary'),\n border: `2px solid ${css('card')}`,\n boxShadow: '0 0 0 1px rgba(0,0,0,0.25)',\n cursor: 'default',\n} as const;\n\n// Marker is the tile-less panel's dot. The tiled map builds an equivalent element\n// imperatively (MapLibre owns the DOM its markers live in), which is why the styling is\n// shared as an object rather than as a component.\nfunction Marker({\n position,\n style,\n}: {\n position: PlaceableLocation;\n style: CSSProperties;\n}) {\n const label = describePosition(position);\n return (\n <div\n data-testid=\"map-marker\"\n data-device={position.deviceToken}\n title={label}\n aria-label={label}\n style={{ ...MARKER_DOT_STYLE, ...style }}\n />\n );\n}\n\n// MapNotice is the widget's non-map state: permission, loading, empty. One component so\n// the three read as siblings \u2014 a viewer should be able to tell them apart by their words,\n// not by their layout.\nfunction MapNotice({ glyph, heading, detail }: { glyph?: string; heading: string; detail?: string }) {\n return (\n <div\n style={{\n display: 'flex',\n flexDirection: 'column',\n alignItems: 'center',\n justifyContent: 'center',\n gap: 4,\n width: '100%',\n height: '100%',\n padding: 12,\n boxSizing: 'border-box',\n textAlign: 'center',\n color: css('muted-foreground'),\n }}\n >\n {glyph ? (\n <div style={{ fontSize: 20, lineHeight: 1 }} aria-hidden=\"true\">\n {glyph}\n </div>\n ) : null}\n <div style={{ fontSize: 13, fontWeight: 600 }}>{heading}</div>\n {detail ? <div style={{ fontSize: 11, opacity: 0.8 }}>{detail}</div> : null}\n </div>\n );\n}\n\n// The registration: this widget's portable descriptor paired with its component, declared\n// through the same public `defineWidget` a third-party package uses.\nexport const mapWidget = defineWidget({\n descriptor: builtinWidgetDescriptors['map'],\n implementation: { kind: 'trusted-react', component: MapWidget },\n});\n", "// Copyright The DeviceChain Authors\n// SPDX-License-Identifier: Apache-2.0\n\n// The tenant basemap, threaded to map widgets as ambient environment (ADR-079).\n//\n// \uD83D\uDD34 Why context rather than a new field on WidgetProps. A widget is contractually a\n// pure function of (widget, data): the props carry what the widget SHOWS. A tenant's\n// tile source is not data \u2014 it is environment, like the theme \u2014 and putting it in the\n// props would change the contract for all fifteen widgets to serve one of them.\n//\n// The default is null, deliberately. A host that installs no provider (widgetlab, the\n// synthetic preview, every existing test) behaves exactly as before: the map falls\n// back to its per-widget options, and to a plain panel when it has none. Adding the\n// provider is what turns a tenant's configured basemap on; nothing breaks without it.\n\nimport { createContext, useContext, type ReactNode } from 'react';\nimport type { Basemap } from '@devicechain/client';\n\nconst TenantBasemapContext = createContext<Basemap | null>(null);\n\n/**\n * Supplies the tenant's effective basemap to every map widget beneath it.\n *\n * Both hosts install this ONCE, high in the tree, rather than at each place they\n * render a widget: the console from its TenantProvider, the /dash viewer app from the\n * one place it mounts a DashboardRenderer.\n *\n * \uD83D\uDD34 That placement is the whole safety argument, because a host that forgets this\n * does NOT fail loudly \u2014 its maps simply render as they did before the tenant setting\n * existed, on that surface only. Wrapping individual render sites is the version that\n * silently half-works; there is no render site to forget from the top of the tree.\n */\nexport function TenantBasemapProvider({\n basemap,\n children,\n}: {\n basemap: Basemap | null;\n children: ReactNode;\n}) {\n return <TenantBasemapContext.Provider value={basemap}>{children}</TenantBasemapContext.Provider>;\n}\n\n/**\n * The tenant's effective basemap, or null when no host supplied one.\n *\n * Null means \"no tenant basemap in force\" \u2014 either the host installs no provider, or\n * neither the tenant nor the operator has configured one. Both cases resolve the same\n * way downstream (fall back to the per-widget override, then to a plain panel), so\n * callers do not need to distinguish them.\n */\nexport function useTenantBasemap(): Basemap | null {\n return useContext(TenantBasemapContext);\n}\n", "// Copyright The DeviceChain Authors\n// SPDX-License-Identifier: Apache-2.0\n\n// The map runtime: the pieces of MapLibre that only the HOST'S BUNDLER can produce.\n//\n// \uD83D\uDD34 WHY THIS EXISTS AT ALL. MapLibre parses tiles and geometry off the main thread, and\n// left to itself it derives the worker's URL at runtime from its own module URL \u2014\n// `new URL('./maplibre-gl-worker.mjs', import.meta.url)`. That is a string no bundler can\n// follow, so nothing emits the file, the browser resolves it to a 404, and `new Worker()`\n// does not throw on one: the failure arrives later as an async error event. The map builds,\n// type-checks, passes every test, and renders nothing.\n//\n// The only thing that can emit that file is the application's own bundler, using its own\n// dialect \u2014 Vite spells it `?worker&url`, webpack and Rollup each spell it differently.\n// So the URL is something a HOST computes and a LIBRARY cannot.\n//\n// \uD83D\uDD34 THIS PACKAGE USED TO WRITE VITE'S DIALECT ITSELF, and that is the defect this seam\n// removes. A published library containing `import('\u2026?worker&url')` works under a consumer's\n// Vite and silently renders a blank map under anything else \u2014 and because the specifier is\n// externalized, no bundler ever tries to resolve it, so NOTHING IN ANY BUILD REPORTS IT.\n// A green pipeline over a broken artifact is strictly worse than a red one.\n//\n// \u26A0\uFE0F HOW THIS DIFFERS FROM TenantBasemapProvider, which sits beside it and looks alike.\n// The basemap provider is OPTIONAL BY DESIGN: a host that installs none behaves exactly as\n// it did before the tenant setting existed, and that is a coherent state. This one is\n// REQUIRED, and a host that omits it gets a loud notice rather than a map. The asymmetry is\n// deliberate and is the whole point: a missing basemap is a configuration a viewer can read\n// off the screen, while a missing worker URL is invisible \u2014 it is the blank map above.\n// Copying the basemap's optional-by-default shape here would relocate that defect into\n// every unwired host instead of removing it.\n\nimport { createContext, useContext, type ReactNode } from 'react';\n\n/**\n * The bundler-produced runtime a map widget needs from its host.\n *\n * `workerUrl` is the emitted, host-resolvable URL of MapLibre's worker entry\n * (`maplibre-gl/dist/maplibre-gl-worker.mjs`). It is handed to MapLibre's `setWorkerUrl`\n * before the first `Map` is constructed.\n *\n * `loadStyles` is OPTIONAL, and imports MapLibre's stylesheet\n * (`maplibre-gl/dist/maplibre-gl.css`). Omit it and import the stylesheet yourself, the way\n * every map library asks you to \u2014 that is the ordinary path and nothing here second-guesses\n * it. Supplying it buys one thing: the CSS rides the renderer's lazy chunk instead of your\n * main stylesheet, which is worth **83 KB raw / 10.7 KB gzipped** to a viewer who never\n * opens a board with a map on it.\n *\n * \uD83D\uDD34 The size is measured against maplibre-gl 6.6.0, the version this package peers on. An\n * earlier draft said 70 KB \"measured, not estimated\" \u2014 measured, but against a stale\n * `node_modules` carrying 6.2.0. Measuring the right thing in the wrong tree reads exactly\n * like measuring, which is why the version is named here.\n *\n * \uD83D\uDD34 It is a FUNCTION rather than a boolean or a URL because the host's bundler owns its\n * CSS pipeline: only the host can say \"load this, lazily, your way\".\n */\nexport type MapRuntime = {\n workerUrl: string;\n loadStyles?: () => Promise<unknown>;\n};\n\nconst MapRuntimeContext = createContext<MapRuntime | null>(null);\n\n/**\n * Supplies the host's MapLibre runtime to every map widget beneath it.\n *\n * Install it ONCE, high in the tree, next to TenantBasemapProvider \u2014 the console from its\n * TenantProvider, the /dash viewer from the one place it mounts a DashboardRenderer.\n *\n * \uD83D\uDD11 ON VITE, DO NOT WRITE ANY OF THIS \u2014 import the ready-made runtime:\n *\n * ```tsx\n * import { viteMapRuntime } from '@devicechain/widgets/vite';\n *\n * <MapRuntimeProvider runtime={viteMapRuntime}>{children}</MapRuntimeProvider>\n * ```\n *\n * On any other bundler you supply the URL yourself, and there is ONE REQUIREMENT that\n * decides whether it works: MapLibre loads the URL as a MODULE worker, so whatever it\n * serves must be a module with no unresolved imports left in it.\n * `maplibre-gl/dist/maplibre-gl-worker.mjs` does not satisfy that on its own \u2014 its first\n * line is `import \u2026 from './maplibre-gl-shared.mjs'`.\n *\n * \uD83D\uDD34 SO DO NOT POINT AT A VERBATIM COPY OF THE WORKER FILE, and in particular do not\n * reach for `new URL('maplibre-gl/dist/maplibre-gl-worker.mjs', import.meta.url)`. That\n * looks exactly right and is wrong: webpack treats the target as an ASSET and copies it,\n * the sibling is never emitted, and the worker dies on its own first line. Measured\n * against webpack 5, from a packed tarball: the worker URL answered 200, both maps drew\n * canvases, all markers appeared, tiles loaded, THE BUILD EXITED 0 AND THE CONSOLE WAS\n * EMPTY \u2014 and the bundled basemap rendered ocean with no land on it.\n *\n * Two recipes that were measured working, in `hack/consumer-proof`:\n *\n * ```js\n * // webpack \u2014 make the worker a second ENTRY, so its imports are bundled into it.\n * entry: { main: './src/index.tsx', 'maplibre-worker': 'maplibre-gl/dist/maplibre-gl-worker.mjs' }\n * // \u2026then: <MapRuntimeProvider runtime={{ workerUrl: '/maplibre-worker.js' }}>\n * ```\n *\n * ```js\n * // any bundler, or none \u2014 copy the worker AND ITS SIBLING, under their own names,\n * // into one served directory: maplibre-gl-worker.mjs + maplibre-gl-shared.mjs\n * // \u2026then: <MapRuntimeProvider runtime={{ workerUrl: '/vendor/maplibre-gl-worker.mjs' }}>\n * ```\n *\n * \uD83D\uDD34 Hold the runtime in a MODULE CONSTANT, as above, rather than building it inline in\n * JSX. An object literal in the element is a new identity on every render, and while the\n * widget deliberately keys its effects on `workerUrl` rather than on the object to survive\n * that, a host that also passes it anywhere keyed on identity would tear down and rebuild\n * the map on every parent render. There is nothing per-render in it to justify the risk.\n *\n * \uD83D\uDD34 `maplibre-gl` is a PEER dependency of this package precisely so that the copy the host\n * takes the worker from is the same copy this package renders with. A worker built from one\n * version driving a main thread from another is the blank map again, by a different route.\n */\nexport function MapRuntimeProvider({\n runtime,\n children,\n}: {\n runtime: MapRuntime;\n children: ReactNode;\n}) {\n return <MapRuntimeContext.Provider value={runtime}>{children}</MapRuntimeContext.Provider>;\n}\n\n/**\n * The host's map runtime, or null when no host supplied one.\n *\n * \uD83D\uDD34 Callers MUST treat null as a refusal to render a map, not as a default to paper over.\n * There is no sensible fallback: the only alternative to a host-supplied URL is MapLibre's\n * own runtime derivation, which is the broken behaviour this seam exists to prevent.\n */\nexport function useMapRuntime(): MapRuntime | null {\n return useContext(MapRuntimeContext);\n}\n", "// Copyright The DeviceChain Authors\n// SPDX-License-Identifier: Apache-2.0\n\n// The map widget's pure parts: which samples are placeable, where they land on a\n// tile-less panel, and how a fix is described in words.\n//\n// Split out from the component for the usual reason the chart-option builders are \u2014\n// this is the arithmetic that decides whether a marker is in the right place, and it is\n// worth an awful lot more when it can be asserted directly than when it can only be\n// inferred from a rendered `style` string.\n\nimport type { LocationSample } from '@devicechain/dashboards';\n\n// A sample that actually has coordinates. A LocationSample's latitude/longitude are\n// nullable (the projection's columns are), and a sample missing either is not a\n// position \u2014 placing it would put a marker at (0, 0) in the Gulf of Guinea and label it\n// with a real device's name.\nexport interface PlaceableLocation extends LocationSample {\n latitude: number;\n longitude: number;\n}\n\n// placeable keeps the samples that can be drawn.\n//\n// `!= null`, NOT truthiness: latitude 0 is the equator and longitude 0 is Greenwich,\n// and both are real reported positions. A truthy filter would silently drop a device\n// sitting on either line.\nexport function placeable(samples: readonly LocationSample[]): PlaceableLocation[] {\n return samples.filter(\n (s): s is PlaceableLocation => s.latitude != null && s.longitude != null,\n );\n}\n\n// A point on the tile-less panel, as a FRACTION of its width/height, so the component\n// can express it as a percentage and stay resolution-independent.\nexport interface PanelPoint {\n x: number;\n y: number;\n}\n\n// Fraction of the panel kept clear at each edge, so a marker at the extreme of the\n// bounding box sits inside the panel rather than half-clipped by it.\nconst PANEL_PADDING = 0.1;\n\n// projectToPanel lays a set of positions out on a plain (tile-less) panel.\n//\n// An equirectangular fit of the positions' own bounding box: longitude \u2192 x, latitude \u2192\n// y, each stretched across the padded panel. Deliberately NOT a web-mercator\n// projection \u2014 without a basemap there is nothing to align to, so the only job is to\n// show the relative arrangement of a fleet truthfully, and at the extent of a site or a\n// city the difference between the two is invisible. (With a tile source the widget uses\n// MapLibre's real projection instead; this function is never asked to agree with one.)\n//\n// \uD83D\uDD34 THE AXES ARE NOT INTERCHANGEABLE, AND THE Y AXIS IS INVERTED. Longitude is\n// east-west (x); latitude is north-south (y); and screen y grows DOWNWARD while\n// latitude grows northward, so the maximum latitude maps to y = 0. Swap the two and\n// every marker still lands inside the panel, in a plausible-looking scatter \u2014 the\n// output stays well-formed, which is exactly why this is asserted directly rather than\n// eyeballed.\n//\n// A degenerate axis (one device, or several at the same latitude) has no span to\n// stretch across, so it centres on that axis rather than dividing by zero.\nexport function projectToPanel(positions: readonly PlaceableLocation[]): PanelPoint[] {\n if (positions.length === 0) return [];\n\n let minLat = Infinity;\n let maxLat = -Infinity;\n let minLon = Infinity;\n let maxLon = -Infinity;\n for (const p of positions) {\n if (p.latitude < minLat) minLat = p.latitude;\n if (p.latitude > maxLat) maxLat = p.latitude;\n if (p.longitude < minLon) minLon = p.longitude;\n if (p.longitude > maxLon) maxLon = p.longitude;\n }\n\n const lonSpan = maxLon - minLon;\n const latSpan = maxLat - minLat;\n const scale = 1 - 2 * PANEL_PADDING;\n\n return positions.map((p) => ({\n x: PANEL_PADDING + scale * (lonSpan === 0 ? 0.5 : (p.longitude - minLon) / lonSpan),\n // maxLat at the TOP: screen y grows downward, latitude grows northward.\n y: PANEL_PADDING + scale * (latSpan === 0 ? 0.5 : (maxLat - p.latitude) / latSpan),\n }));\n}\n\n// Coordinates are WGS84 decimal degrees platform-wide. Six decimal places is ~0.1 m at\n// the equator \u2014 finer than any consumer receiver \u2014 and fixed notation stops a small\n// value rendering in exponential form. Matches the device-detail position panel, so the\n// same fix reads identically in both places.\nexport function formatDegrees(value: number): string {\n return value.toFixed(6);\n}\n\n// describePosition renders one fix as a marker's hover/screen-reader text.\n//\n// \uD83D\uDD34 IT REPORTS ONLY WHAT THE DEVICE REPORTED. Elevation, accuracy, speed and heading\n// are each optional, and an absent one contributes NO SEGMENT at all \u2014 it is never\n// filled in with a zero. A marker reading \"0\u00B0\" claims the device reported due north; a\n// marker with no heading segment claims nothing, which is the truth. Every test is\n// `!= null`, so a genuine 0 (parked, sea level, due north) is still shown.\n//\n// Units are fixed platform-wide: metres, metres per second, degrees clockwise from true\n// north.\nexport function describePosition(sample: PlaceableLocation): string {\n const parts: string[] = [\n sample.deviceToken,\n `${formatDegrees(sample.latitude)}, ${formatDegrees(sample.longitude)}`,\n ];\n if (sample.elevation != null) parts.push(`${sample.elevation} m`);\n if (sample.accuracy != null) parts.push(`\u00B1${sample.accuracy} m`);\n if (sample.speed != null) parts.push(`${sample.speed} m/s`);\n if (sample.heading != null) parts.push(`${sample.heading}\u00B0`);\n return parts.join(' \u00B7 ');\n}\n\n// rasterStyleFor builds the MapLibre style document for a user-supplied raster tile\n// source.\n//\n// \uD83D\uDD34 THIS PACKAGE HARDCODES NO TILE SOURCE, AND THAT IS A DECISION RATHER THAN AN\n// OMISSION. The library is not the map \u2014 the TILES are, and they carry their own terms,\n// so a widget library is the wrong place to choose a provider on an operator's behalf.\n// The URL arrives as config, and with none set the widget falls back to the BUNDLED\n// world basemap below \u2014 public-domain geometry compiled into this package, which asks\n// no host for anything and so adopts nobody's terms. That is the distinction the rule\n// is actually about: not \"ship no map\", but \"make no request on an operator's behalf\n// to a host they never chose\".\n//\n// The PLATFORM does ship a default (ADR-079): an instance-wide setting a tenant can\n// override, which a board then inherits when its own options name nothing. That is a\n// named, visible, replaceable choice made once by an operator \u2014 a different thing from\n// this module quietly baking a host into every build of the library.\n//\n// `attribution` is passed to the source rather than hidden: a tile source's licence\n// commonly REQUIRES visible credit, so it is a property of the data, not decoration a\n// host may strip.\nexport function rasterStyleFor(tileUrl: string, attribution: string | undefined): unknown {\n return {\n version: 8,\n projection: PROJECTION,\n sources: {\n basemap: {\n type: 'raster',\n tiles: [tileUrl],\n tileSize: 256,\n ...(attribution ? { attribution } : {}),\n },\n },\n layers: [{ id: 'basemap', type: 'raster', source: 'basemap' }],\n };\n}\n\n// ---- The bundled world basemap ----------------------------------------------\n\n// \uD83D\uDD34 THE PROJECTION IS THE CORRECTNESS PROPERTY OF THIS WHOLE FILE, and it is\n// declared explicitly \u2014 on BOTH styles \u2014 rather than left to the default.\n//\n// The fence editor stores the coordinates a click produces, so what a style\n// changes must be what is DRAWN and never where a click LANDS. Mercator is\n// MapLibre's default, so writing it out changes no behaviour today. What it buys\n// is that the two styles now state the same thing in the same words, and a test\n// can compare them: an invariant nobody wrote down is an invariant a later edit\n// breaks without anything going red.\n//\n// This is not hypothetical in MapLibre 6. `projection` is a root style key whose\n// `type` is a ZOOM-INTERPOLATABLE expression, so a style is entitled to hand back\n// a globe past some zoom. A globe re-projects the pointer; every ring an author\n// then drew would be saved somewhere they never pointed at, on a map that looked\n// beautiful throughout.\nconst PROJECTION = { type: 'mercator' } as const;\n\n// The bundled basemap's credit line. Natural Earth requires NO attribution \u2014 its\n// licence says in as many words that crediting the authors is unnecessary \u2014 so\n// this is their own suggested short citation, shown for a reason of ours: a\n// viewer has to be able to tell a schematic bundled world apart from a configured\n// provider, or \"no tiles\" reads as \"broken\" all over again.\nexport const BUNDLED_BASEMAP_ATTRIBUTION = 'Made with Natural Earth';\n\n// The bundled style's palette. Literal colours, not theme tokens: a MapLibre style\n// document is JSON handed to a WebGL renderer, and it does not resolve the CSS\n// custom properties the rest of this package themes with. These sit close to the\n// dark surface the fence editor already drew, so the change reads as \"the void\n// grew continents\" rather than as a new skin.\nconst OCEAN = '#0b1220';\nconst LAND = '#1e293b';\nconst BOUNDARY = '#475569';\n\n// landStyleFrom builds the bundled world style from Natural Earth geometry.\n//\n// Kept separate from the loader, and pure, so the style document can be asserted\n// without pulling 150 KiB of coordinates into a test \u2014 and so the one thing worth\n// asserting about it (that it projects exactly as the tiled style does) is\n// checkable in isolation.\nexport function landStyleFrom(land: unknown, boundaries: unknown): unknown {\n return {\n version: 8,\n projection: PROJECTION,\n sources: {\n land: { type: 'geojson', data: land, attribution: BUNDLED_BASEMAP_ATTRIBUTION },\n boundaries: { type: 'geojson', data: boundaries },\n },\n layers: [\n { id: 'ocean', type: 'background', paint: { 'background-color': OCEAN } },\n { id: 'land', type: 'fill', source: 'land', paint: { 'fill-color': LAND } },\n {\n id: 'boundaries',\n type: 'line',\n source: 'boundaries',\n paint: { 'line-color': BOUNDARY, 'line-width': 0.5 },\n },\n ],\n };\n}\n\n// loadLandStyle fetches the bundled geometry and builds its style.\n//\n// \uD83D\uDD34 THE DYNAMIC IMPORT IS THE WHOLE POINT. natural-earth-data is ~150 KiB (~44\n// KiB over the wire) and it must never enter this package's entry chunk: with a\n// tile source configured \u2014 which, since the platform ships a default provider, is\n// the ordinary case \u2014 nobody should download a world map they will not see. A\n// static `import { NATURAL_EARTH }` at the top of this file would give every\n// viewer the payload and change nothing observable, which is how it would survive\n// review.\n//\n// Memoized on the promise, so several map widgets on one board parse it once.\n//\n// \uD83D\uDD34 That memoizes a REJECTION too: one transient chunk failure leaves every\n// unconfigured map on the page falling back until a reload. Deliberate, and the same\n// bargain loadMapLibre has always made \u2014 a retry-on-failure cache would let N widgets\n// re-request a chunk that is failing for a reason retrying will not fix. Worth knowing\n// that the blast radius grew when this became the DEFAULT unconfigured path rather\n// than a rarity.\nlet landStylePromise: Promise<unknown> | undefined;\n\nexport function loadLandStyle(): Promise<unknown> {\n if (!landStylePromise) {\n landStylePromise = import('./natural-earth-data').then((mod) =>\n landStyleFrom(mod.NATURAL_EARTH.land, mod.NATURAL_EARTH.boundaries),\n );\n }\n return landStylePromise;\n}\n", "// Copyright The DeviceChain Authors\n// SPDX-License-Identifier: Apache-2.0\n\n// table \u2014 the latest value of every measurement the datasource carries, one row\n// per measurement name.\n\nimport type { CSSProperties } from 'react';\n\nimport {\n css,\n defineWidget,\n FlashValue,\n formatTimestamp,\n optBoolean,\n optNumber,\n optString,\n useWidgetTimeZone,\n WidgetFrame,\n type WidgetProps,\n} from '@devicechain/widget-sdk';\n\nimport { builtinWidgetDescriptors } from '../builtin-descriptors';\n\nconst cell: CSSProperties = { padding: '6px 12px', textAlign: 'left' };\nconst headCell: CSSProperties = {\n ...cell,\n fontSize: 11,\n fontWeight: 600,\n textTransform: 'uppercase',\n letterSpacing: '0.04em',\n color: css('muted-foreground'),\n borderBottom: `1px solid ${css('border')}`,\n};\n\nexport function Table({ widget, data }: WidgetProps) {\n const timeZone = useWidgetTimeZone();\n const rows = Object.values(data.latest).sort((a, b) => a.name.localeCompare(b.name));\n // Round to a fixed number of decimals when configured; unset keeps the raw value\n // (formatValue's default). A live sensor value is otherwise a wall of digits.\n const precision = optNumber(widget.options, 'precision');\n // Opt-in directional flash per row (keyed by measurement name, so each value's cue is\n // independent \u2014 see FlashValue).\n const flash = optBoolean(widget.options, 'flashOnChange');\n\n return (\n <WidgetFrame title={optString(widget.options, 'title')}>\n <div style={{ height: '100%', overflow: 'auto' }}>\n <table style={{ width: '100%', borderCollapse: 'collapse', fontSize: 13, color: css('foreground') }}>\n <thead>\n <tr>\n <th style={headCell}>Measurement</th>\n <th style={headCell}>Value</th>\n <th style={headCell}>Time</th>\n </tr>\n </thead>\n <tbody>\n {rows.length === 0 ? (\n <tr>\n <td colSpan={3} style={{ ...cell, textAlign: 'center', color: css('muted-foreground') }}>\n No data yet\n </td>\n </tr>\n ) : (\n rows.map((row) => (\n <tr key={row.name}>\n <td style={cell}>{row.name}</td>\n <td style={{ ...cell, fontVariantNumeric: 'tabular-nums' }}>\n <FlashValue\n value={row.value}\n precision={precision}\n enabled={flash}\n identity={`${row.deviceToken}:${row.name}`}\n />\n {/* classifier is deliberately NOT shown: it is the bound metric\n definition's internal id (ADR-016), not a user-facing label \u2014\n appending it rendered as spurious digits after the value. */}\n </td>\n <td style={{ ...cell, color: css('muted-foreground') }}>{formatTimestamp(row.occurredTime, timeZone)}</td>\n </tr>\n ))\n )}\n </tbody>\n </table>\n </div>\n </WidgetFrame>\n );\n}\n\n// The registration: this widget's portable descriptor paired with its component, declared\n// through the same public `defineWidget` a third-party package uses.\nexport const tableWidget = defineWidget({\n descriptor: builtinWidgetDescriptors['table'],\n implementation: { kind: 'trusted-react', component: Table },\n});\n", "// Copyright The DeviceChain Authors\n// SPDX-License-Identifier: Apache-2.0\n\n// timeseries-chart \u2014 a live line chart of the rolling measurement window, one\n// series per measurement name. The window is seeded from bucketedMeasurements\n// history (via useMeasurementStream's initialSamples) and extended by the live tail.\n\nimport { useMemo } from 'react';\n\nimport {\n defineWidget,\n optString,\n useElementSize,\n WidgetFrame,\n type WidgetProps,\n} from '@devicechain/widget-sdk';\nimport { buildLineOption, EChart, useChartTheme } from '@devicechain/widget-sdk/echarts';\n\nimport { builtinWidgetDescriptors } from '../builtin-descriptors';\n\nexport function TimeSeriesChart({ widget, data }: WidgetProps) {\n const theme = useChartTheme();\n const [sizeRef, size] = useElementSize<HTMLDivElement>();\n\n const measurements = widget.datasource?.measurements;\n const option = useMemo(\n () => buildLineOption(data.samples, theme, { measurements }, size),\n [data.samples, theme, measurements, size.width, size.height],\n );\n\n return (\n <WidgetFrame title={optString(widget.options, 'title')}>\n <div ref={sizeRef} style={{ width: '100%', height: '100%' }}>\n <EChart option={option} />\n </div>\n </WidgetFrame>\n );\n}\n\n// The registration: this widget's portable descriptor paired with its component, declared\n// through the same public `defineWidget` a third-party package uses.\nexport const timeSeriesChartWidget = defineWidget({\n descriptor: builtinWidgetDescriptors['timeseries-chart'],\n implementation: { kind: 'trusted-react', component: TimeSeriesChart },\n});\n", "// Copyright The DeviceChain Authors\n// SPDX-License-Identifier: Apache-2.0\n\nimport type { WidgetRegistry } from '@devicechain/widget-sdk';\n\nimport { createBuiltinWidgetRegistry } from './builtin-registry';\n\n// The registry a renderer uses when its host passes none: the built-ins, built once per\n// module instance. A registry is sealed and immutable, so sharing this one default between\n// hosts carries no state \u2014 a host with extension packages passes its own.\nlet builtin: WidgetRegistry | undefined;\n\nexport function defaultWidgetRegistry(): WidgetRegistry {\n builtin ??= createBuiltinWidgetRegistry();\n return builtin;\n}\n", "// Copyright The DeviceChain Authors\n// SPDX-License-Identifier: Apache-2.0\n\n// Per-widget failure containment. Every widget implementation renders inside its own error\n// boundary: a component that throws shows a local diagnostic with a reset control while its\n// siblings keep rendering, and a host callback that rejects (an action, a candidate lookup)\n// is surfaced on the widget that made the call instead of vanishing into an unhandled\n// rejection. An error boundary cannot contain an infinite loop or hostile same-page code;\n// trusted package installation remains the operator's responsibility.\n\nimport { Component, createContext, useCallback, useContext, useState, type ReactNode } from 'react';\n\nimport { WidgetFrame } from '@devicechain/widget-sdk';\nimport { describeError, type ReportRejection } from './widget-host';\n\nconst MESSAGE_STYLE = {\n display: 'flex',\n flexDirection: 'column',\n alignItems: 'center',\n justifyContent: 'center',\n gap: 4,\n width: '100%',\n height: '100%',\n padding: 12,\n boxSizing: 'border-box',\n textAlign: 'center',\n color: 'hsl(var(--muted-foreground))',\n} as const;\n\nconst BUTTON_STYLE = {\n marginTop: 4,\n fontSize: 11,\n padding: '2px 8px',\n cursor: 'pointer',\n} as const;\n\n// The reporter a body uses for async host callbacks. A no-op outside a containment, so a\n// component rendered on its own never needs one.\nconst ReportContext = createContext<ReportRejection>(() => {});\n\nexport function useReportRejection(): ReportRejection {\n return useContext(ReportContext);\n}\n\ninterface BoundaryProps {\n title?: string;\n // Changes when the widget's stored configuration changes, so an edit retries a widget\n // that threw on the old one.\n resetKey: string;\n onReset: () => void;\n children: ReactNode;\n}\n\ninterface BoundaryState {\n error: { message: string } | null;\n resetKey: string;\n}\n\nclass WidgetErrorBoundary extends Component<BoundaryProps, BoundaryState> {\n state: BoundaryState = { error: null, resetKey: this.props.resetKey };\n\n static getDerivedStateFromError(error: unknown): Partial<BoundaryState> {\n return { error: { message: describeError(error) } };\n }\n\n static getDerivedStateFromProps(props: BoundaryProps, state: BoundaryState): Partial<BoundaryState> | null {\n if (props.resetKey === state.resetKey) return null;\n return { error: null, resetKey: props.resetKey };\n }\n\n private reset = (): void => {\n this.props.onReset();\n this.setState({ error: null });\n };\n\n render(): ReactNode {\n const { error } = this.state;\n if (!error) return this.props.children;\n return (\n <WidgetFrame title={this.props.title}>\n <div style={MESSAGE_STYLE} role=\"alert\">\n <div style={{ fontSize: 20, lineHeight: 1 }} aria-hidden=\"true\">\n \u26A0\n </div>\n <div style={{ fontSize: 13, fontWeight: 600 }}>This widget failed to render</div>\n <div style={{ fontSize: 11, opacity: 0.8, wordBreak: 'break-word' }}>{error.message}</div>\n <button type=\"button\" style={BUTTON_STYLE} onClick={this.reset}>\n Reset widget\n </button>\n </div>\n </WidgetFrame>\n );\n }\n}\n\nexport interface WidgetContainmentProps {\n title?: string;\n resetKey: string;\n children: ReactNode;\n}\n\n// WidgetContainment wraps ONE widget. Rejections reported by the host callbacks it hands\n// down appear in a dismissible strip over the widget's bottom edge.\nexport function WidgetContainment({ title, resetKey, children }: WidgetContainmentProps) {\n const [messages, setMessages] = useState<string[]>([]);\n const report = useCallback<ReportRejection>((message) => {\n setMessages((prev) => (prev.includes(message) ? prev : [...prev, message].slice(-3)));\n }, []);\n const clear = useCallback(() => setMessages([]), []);\n return (\n <div style={{ position: 'relative', width: '100%', height: '100%' }}>\n <ReportContext.Provider value={report}>\n <WidgetErrorBoundary title={title} resetKey={resetKey} onReset={clear}>\n {children}\n </WidgetErrorBoundary>\n </ReportContext.Provider>\n {messages.length > 0 && (\n <div\n role=\"status\"\n style={{\n position: 'absolute',\n left: 4,\n right: 4,\n bottom: 4,\n fontSize: 11,\n padding: '2px 6px',\n borderRadius: 4,\n background: 'hsl(var(--destructive, 0 70% 45%))',\n color: 'hsl(var(--destructive-foreground, 0 0% 100%))',\n display: 'flex',\n gap: 6,\n alignItems: 'center',\n }}\n >\n <span style={{ flex: 1, wordBreak: 'break-word' }}>{messages.join(' \u00B7 ')}</span>\n <button type=\"button\" aria-label=\"Dismiss\" onClick={clear} style={{ cursor: 'pointer' }}>\n \u00D7\n </button>\n </div>\n )}\n </div>\n );\n}\n", "// Copyright The DeviceChain Authors\n// SPDX-License-Identifier: Apache-2.0\n\n// What the host hands one widget: ONLY the interactions its descriptor declares,\n// intersected with what the host supports. Declaring an interaction is a request, and this\n// narrowing is API hygiene, not a security boundary (trusted React runs with the page's\n// privileges); the server stays the authority on every write.\n\nimport type { WidgetActions, WidgetDescriptor } from '@devicechain/dashboards';\n\nimport { type WidgetCandidates, type WidgetSelect } from '@devicechain/widget-sdk';\n\n// Receives the message of an async host callback that rejected, so it can be shown on the\n// widget that made the call.\nexport type ReportRejection = (message: string) => void;\n\nexport function describeError(error: unknown): string {\n if (error instanceof Error) return error.message || error.name;\n return String(error);\n}\n\n// guardAsync reports a rejection to the widget's local diagnostics and rethrows it, so a\n// widget that handles the failure itself (a refusal it shows inline) still sees it.\nfunction guardAsync<A extends unknown[], R>(\n fn: (...args: A) => Promise<R>,\n report: ReportRejection,\n): (...args: A) => Promise<R> {\n return (...args: A) => {\n let pending: Promise<R>;\n try {\n pending = Promise.resolve(fn(...args));\n } catch (e) {\n report(describeError(e));\n return Promise.reject(e);\n }\n return pending.catch((e: unknown) => {\n report(describeError(e));\n throw e;\n });\n };\n}\n\nconst ALARM_AUTHORITY = 'alarm:write';\nconst COMMAND_AUTHORITY = 'command:write';\n\n// A call to an interaction the widget did not declare rejects, and the rejection is reported\n// on the widget like any other failed host callback: a widget that fires and forgets\n// (`void actions.acknowledgeAlarm(t)`) must still SHOW the refusal, not swallow it.\nfunction undeclared(capability: string, report: ReportRejection): () => Promise<never> {\n return guardAsync(\n () => Promise.reject(new Error(`this widget did not declare the ${capability} interaction`)),\n report,\n );\n}\n\n// narrowActions returns the action seam a widget may use. A widget that declares neither\n// alarm actions nor command send gets none; one that declares a subset gets the declared\n// methods working and the rest refusing loudly (never a silent no-op), and `can` denies the\n// write authorities of capabilities it did not declare.\nexport function narrowActions(\n actions: WidgetActions | undefined,\n descriptor: WidgetDescriptor,\n report: ReportRejection,\n): WidgetActions | undefined {\n if (!actions) return undefined;\n const alarm = descriptor.interactions.alarmActions === true;\n const command = descriptor.interactions.commandSend === true;\n if (!alarm && !command) return undefined;\n const narrowed: WidgetActions = {\n acknowledgeAlarm: alarm\n ? guardAsync((t) => actions.acknowledgeAlarm(t), report)\n : undeclared('alarmActions', report),\n clearAlarm: alarm ? guardAsync((t) => actions.clearAlarm(t), report) : undeclared('alarmActions', report),\n can: (authority) => {\n if (authority === ALARM_AUTHORITY && !alarm) return false;\n if (authority === COMMAND_AUTHORITY && !command) return false;\n return actions.can(authority);\n },\n };\n // Left absent when undeclared or unsupported: a command widget feature-detects it and\n // renders its Send control disabled.\n if (command && typeof actions.sendCommand === 'function') {\n narrowed.sendCommand = guardAsync((d, n, p) => actions.sendCommand!(d, n, p), report);\n }\n return narrowed;\n}\n\n// narrowSelect: the view-selection callback, only for a widget that declared `selection`.\nexport function narrowSelect(select: WidgetSelect | undefined, descriptor: WidgetDescriptor): WidgetSelect | undefined {\n return descriptor.interactions.selection === true ? select : undefined;\n}\n\n// narrowCandidates: the candidate lookup, only for a widget that declared `candidates`; its\n// rejections are reported locally and rethrown.\nexport function narrowCandidates(\n candidates: WidgetCandidates | undefined,\n descriptor: WidgetDescriptor,\n report: ReportRejection,\n): WidgetCandidates | undefined {\n if (!candidates || descriptor.interactions.candidates !== true) return undefined;\n return guardAsync((slot) => candidates(slot), report);\n}\n", "// Copyright The DeviceChain Authors\n// SPDX-License-Identifier: Apache-2.0\n\n// The by-id views of the built-in registrations that older consumers still import.\n//\n// \uD83D\uDD34 READ-ONLY PROJECTIONS, NOT A REGISTRY. A widget's channel and whether it binds a\n// datasource are declared once, on its descriptor (builtin-descriptors.ts), and the\n// renderer resolves everything through a registry instance (createWidgetRegistry) -- never\n// through these. They exist so code that wants to ask \"which channel is this built-in on?\"\n// without building a registry (the console's config panel, fixtures) keeps working. They are\n// frozen, computed from the descriptors at module load, and there is no way to add an\n// entry: an extension widget registers through createWidgetRegistry, not here.\n\nimport type { BuiltinWidgetId, WidgetChannel } from '@devicechain/dashboards';\n\nimport { builtinWidgetDescriptors } from './builtin-descriptors';\n\n// WidgetChannel itself is declared once, in @devicechain/dashboards; re-exported so this\n// module's importers are unchanged.\nexport type { WidgetChannel };\n\ntype Descriptors = typeof builtinWidgetDescriptors;\n\nconst entries = Object.entries(builtinWidgetDescriptors) as Array<[BuiltinWidgetId, Descriptors[BuiltinWidgetId]]>;\n\n// A built-in's data channel, as its descriptor declares it.\nexport const WIDGET_CHANNEL: { readonly [K in BuiltinWidgetId]: Descriptors[K]['channel'] } = Object.freeze(\n Object.fromEntries(entries.map(([id, d]) => [id, d.channel])),\n) as { readonly [K in BuiltinWidgetId]: Descriptors[K]['channel'] };\n\n// Whether a built-in binds a DATASOURCE -- the entity whose data it reads. Derived from the\n// descriptor's datasource mode: `none` binds nothing (label, image, the entity selector).\nexport const WIDGET_BINDS_DATASOURCE: { readonly [K in BuiltinWidgetId]: boolean } = Object.freeze(\n Object.fromEntries(entries.map(([id, d]) => [id, d.datasource.mode !== 'none'])),\n) as { readonly [K in BuiltinWidgetId]: boolean };\n", "// Copyright The DeviceChain Authors\n// SPDX-License-Identifier: Apache-2.0\n\n// @devicechain/widgets \u2014 presentational dashboard widgets (ADR-039).\n//\n// Eleven built-ins over the DashboardHub's live data, themed via CSS custom\n// properties (no Tailwind leakage \u2014 embeddable in any React host). Each is a\n// registration declared with the public `defineWidget` from @devicechain/widget-sdk;\n// a renderer resolves a widget through a registry instance.\n\n// The view-only dashboard renderer: lays a parsed definition's widgets on the\n// canvas and binds each to the hub. The shared viewer for the console + external apps.\nexport { DashboardRenderer, resolveWidgets, widgetSubjectLabel, type DashboardRendererProps } from './dashboard-renderer';\n\n// Renderer entry point: binds the hub to a widget by type.\nexport { ConnectedWidget, type ConnectedWidgetProps } from './connected-widget';\n\n// The built-ins as registrations (the same descriptor + component pairing a third-party\n// package supplies), and the factory for a sealed registry holding exactly them.\nexport { builtinWidgetCatalog, builtinWidgetDescriptors } from './builtin-descriptors';\nexport { builtinWidgetDefinitions, createBuiltinWidgetRegistry } from './builtin-registry';\n\n// Read-only by-id views of the built-in descriptors (channel, datasource binding), and the\n// widget contract. The registrations above are the source of truth; these are derived.\nexport { WIDGET_CHANNEL, WIDGET_BINDS_DATASOURCE, type WidgetChannel } from './registry';\nexport { pickSample, optBoolean, type WidgetProps, type WidgetComponent } from '@devicechain/widget-sdk';\n\n// The tenant basemap seam. A host installs the provider; map widgets read it.\nexport { TenantBasemapProvider, useTenantBasemap } from './basemap-context';\n\n// The map RUNTIME seam \u2014 the MapLibre pieces only the host's bundler can emit.\n//\n// \uD83D\uDD34 Unlike the basemap provider above, this one is REQUIRED by any host that renders a\n// map widget: without it the widget shows a notice instead of a map. That is deliberate.\n// The alternative to a host-supplied worker URL is MapLibre's own runtime derivation,\n// which no bundler can follow, and which fails as a map that renders nothing at all.\nexport { MapRuntimeProvider, useMapRuntime, type MapRuntime } from './map-runtime-context';\n\n// The typed schema for each widget's options bag: what the renderer reads, at what type,\n// with what legal values. WidgetOptions<T> types code that BUILDS options;\n// validateWidgetOptions reports where a stored bag disagrees with the renderer.\nexport {\n WIDGET_OPTIONS,\n validateWidgetOptions,\n numberOptionSpec,\n clampNumberOption,\n enumOptionValues,\n type WidgetOptions,\n type WidgetOptionSpecs,\n type OptionSpec,\n type StringOptionSpec,\n type NumberOptionSpec,\n type BooleanOptionSpec,\n type EnumOptionSpec,\n type OptionIssue,\n type OptionIssueCode,\n} from './options';\n\n// The same schemas applied to a whole board: what a producer of definitions asks\n// before it publishes one, plus the repair for the one issue an author cannot fix in\n// a config panel.\nexport {\n validateDefinitionOptions,\n stripUnknownOptions,\n type DefinitionOptionIssue,\n type DefinitionValidationOptions,\n} from './definition-options';\n\n// Individual widgets (for direct/custom use).\nexport { LatestCard } from './widgets/latest-card';\nexport { Gauge } from './widgets/gauge';\nexport { TimeSeriesChart } from './widgets/time-series-chart';\nexport { Table } from './widgets/table';\nexport { Label } from './widgets/label';\nexport { Image } from './widgets/image';\nexport { AlarmTable } from './widgets/alarm-table';\nexport { AlarmCount } from './widgets/alarm-count';\nexport { CommandButton } from './widgets/command-button';\nexport { EntitySelector } from './widgets/entity-selector';\nexport { MapWidget } from './widgets/map';\n// The map's pure parts: which samples can be placed, where they land on a tile-less\n// panel, and how a fix is described without inventing the fields it does not carry.\n//\n// loadLandStyle is the bundled world basemap \u2014 the style used when no tile source\n// is configured. Exported so the console's fence editor and this package's map\n// widget cannot end up drawing two different worlds; the geometry itself stays\n// behind a dynamic import inside that module, so naming it here costs nothing.\nexport {\n placeable,\n projectToPanel,\n describePosition,\n formatDegrees,\n rasterStyleFor,\n landStyleFrom,\n loadLandStyle,\n BUNDLED_BASEMAP_ATTRIBUTION,\n type PlaceableLocation,\n type PanelPoint,\n} from './widgets/map-geometry';\nexport {\n severityColor,\n severityLabel,\n severityRank,\n highestSeverity,\n} from './widgets/severity';\nexport { commandStatusColor, commandStatusLabel, isTerminalStatus } from './widgets/command-status';\nexport {\n parseParameterSchema,\n defaultValues,\n validateParams,\n buildPayload,\n isScalar,\n} from './widgets/command-params';\n\n// Building blocks for custom widgets. They live in @devicechain/widget-sdk (the one place the\n// ambient host contexts may be defined) and are re-exported so existing imports keep resolving;\n// the chart helpers come from its `/echarts` subpath.\nexport {\n WidgetFrame,\n WidgetSubjectProvider,\n WidgetSelectProvider,\n useWidgetSelect,\n WidgetTimeZoneProvider,\n useWidgetTimeZone,\n WidgetThemeRootProvider,\n useWidgetThemeRoot,\n WidgetCandidatesProvider,\n useWidgetCandidates,\n useFlashOnChange,\n flashTextStyle,\n flashBackgroundStyle,\n FlashValue,\n useMeasurementStream,\n useAlarmStream,\n useCommandStream,\n useLocationStream,\n useDatasourceAvailability,\n useDashboardHub,\n useResolvedBindings,\n useSlotCandidates,\n useCandidates,\n css,\n type FlashDirection,\n type WidgetFrameProps,\n type WidgetSelect,\n type WidgetCandidates,\n type MeasurementStreamState,\n type AlarmStreamState,\n type CommandStreamState,\n type LocationStreamState,\n type CandidatesState,\n type DatasourceAvailability,\n type ThemeVar,\n} from '@devicechain/widget-sdk';\nexport {\n EChart,\n buildLineOption,\n buildGaugeOption,\n resolveChartTheme,\n useChartTheme,\n type EChartOption,\n type LineChartOptions,\n type GaugeChartOptions,\n type ChartTheme,\n} from '@devicechain/widget-sdk/echarts';\n", "// Copyright The DeviceChain Authors\n// SPDX-License-Identifier: Apache-2.0\n\n// WIDGET_OPTIONS \u2014 the typed schema for each widget type's `options` bag, as a by-id view.\n//\n// A WidgetInstance's `options` is `Record<string, unknown>` in the stored definition:\n// dashboard-management keeps a definition as opaque JSON, and the definition parser does\n// not look inside `options` at all. Each built-in's descriptor (builtin-descriptors.ts)\n// declares every option the RENDERER actually reads, with its type and legal values; this\n// module projects those schemas by id and wraps the shared engine under the by-type names\n// the console and fixtures use:\n// \u2022 validateWidgetOptions() \u2014 the runtime check, for anything that PRODUCES a definition\n// (a generated dashboard must not ship an options blob the renderer ignores).\n// \u2022 WidgetOptions<T> \u2014 the compile-time shape, for code that builds options.\n//\n// The schema describes the RENDERER, because that is the contract deciding what a viewer\n// actually sees. Where the console's authoring UI offers fewer keys than this \u2014 it does:\n// `align`, `fontSize`, `fit`, `window` and `measurement` are all honored by the renderer\n// and not authorable in the config panel \u2014 the gap is in the panel, not here.\n//\n// The spec VOCABULARY and the engine that checks a bag against a schema live in\n// @devicechain/dashboards (option-schema.ts) \u2014 they know no widget type, so the SDK's\n// registry validates an extension's schema with the very code that validates this one.\n\nimport {\n clampNumberOption,\n enumValues,\n numberSpec,\n validateOptions,\n type NumberOptionSpec,\n type OptionConstraint,\n type OptionIssueCode,\n type BuiltinWidgetId,\n type OptionsOf,\n type WidgetOptionSpecs,\n type WidgetType,\n} from '@devicechain/dashboards';\n\nimport { builtinWidgetCatalog, builtinWidgetDescriptors } from './builtin-descriptors';\n\nexport type {\n BooleanOptionSpec,\n EnumOptionSpec,\n NumberOptionSpec,\n OptionIssueCode,\n OptionSpec,\n StringOptionSpec,\n WidgetOptionSpecs,\n} from '@devicechain/dashboards';\nexport { clampNumberOption };\n\n// ---- The derived by-id view -------------------------------------------------\n\n// Every built-in's option schema, keyed by id. A frozen PROJECTION of the descriptors in\n// builtin-descriptors.ts (each schema is declared there, once, beside the widget's channel and\n// binding policy); it holds no schema of its own, so it cannot drift from what the registry\n// validates. The cross-field rules (gauge's max > min) travel on the descriptor as data.\ntype OptionsById = { readonly [K in BuiltinWidgetId]: (typeof builtinWidgetDescriptors)[K]['options'] };\n\nexport const WIDGET_OPTIONS: OptionsById = Object.freeze(\n Object.fromEntries(Object.entries(builtinWidgetDescriptors).map(([id, d]) => [id, d.options])),\n) as OptionsById;\n\nfunction constraintsFor(widgetType: WidgetType): readonly OptionConstraint[] {\n return builtinWidgetCatalog.get(widgetType)?.constraints ?? [];\n}\n\n// ---- Derived compile-time types ---------------------------------------------\n\n// WidgetOptions<'gauge'> is the typed options bag for a gauge: every declared key at its\n// declared type, required ones mandatory. Code that BUILDS a definition should type its\n// options with this \u2014 a typo is then a compile error rather than a key nothing reads.\n//\n// DISTRIBUTIVE over T, which is the whole reason it is written as a conditional. `keyof` a\n// union of the built-in tables is their INTERSECTION \u2014 only `title` \u2014 and the required-keys\n// computation over that union collapses to never, so the undistributed form silently\n// degenerates for any generic T: it would reject `{ text: 'body' }` as an excess property\n// while accepting `{}` for a widget that requires an option. That is exactly the position a\n// generator writing one widget of each type sits in. Distributing makes\n// WidgetOptions<WidgetType> the union of the per-type bags instead.\nexport type WidgetOptions<T extends WidgetType> = T extends WidgetType ? OptionsOf<(typeof WIDGET_OPTIONS)[T]> : never;\n\n// ---- Runtime validation -----------------------------------------------------\n\n// The by-type issue shape the console reads. `widgetType` keeps its name so existing\n// consumers compile unchanged; the engine's own issue calls the same value `widgetId`.\nexport interface OptionIssue {\n widgetType: WidgetType;\n // The offending option key. For a cross-field rule, the key the fix belongs on.\n key: string;\n code: OptionIssueCode;\n message: string;\n}\n\n// validateWidgetOptions reports every way a widget's stored options bag disagrees with\n// what the renderer reads. An empty result means every key present is one the renderer\n// honors, at a value it accepts, and no required option is missing.\n//\n// It is deliberately a REPORT rather than a throw: the renderer is tolerant by design and\n// must stay that way for a hand-edited definition, so the strictness belongs to whoever\n// produces definitions (fixtures, generators, the config panel) and to the tests that\n// gate them. Callers decide which codes are fatal \u2014 a stored dashboard carrying an\n// 'unknown' leftover is untidy; a generated one carrying 'missing' is broken.\nexport function validateWidgetOptions(\n widgetType: WidgetType,\n options: Record<string, unknown> | undefined,\n): OptionIssue[] {\n const specs: WidgetOptionSpecs = WIDGET_OPTIONS[widgetType];\n return validateOptions(specs, options, { constraints: constraintsFor(widgetType), label: widgetType }).map(\n ({ key, code, message }) => ({ widgetType, key, code, message }),\n );\n}\n\n// numberOptionSpec returns the declared bounds for a numeric option, so an authoring\n// UI can constrain its input from the schema rather than from a second, hand-written\n// copy of the same numbers. See numberSpec for why it exists.\nexport function numberOptionSpec(type: WidgetType, key: string): NumberOptionSpec | undefined {\n return numberSpec(WIDGET_OPTIONS[type], key);\n}\n\n// enumOptionValues returns the legal values of an enum option, so an authoring UI can\n// build its dropdown from the schema instead of a private copy of the same list.\nexport function enumOptionValues(type: WidgetType, key: string): readonly string[] | undefined {\n return enumValues(WIDGET_OPTIONS[type], key);\n}\n", "// Copyright The DeviceChain Authors\n// SPDX-License-Identifier: Apache-2.0\n\n// The definition-level layer over validateWidgetOptions: \"is every widget on this\n// board configured with options the renderer actually reads?\"\n//\n// WHY IT IS A SEPARATE FUNCTION RATHER THAN A LOOP AT EACH CALL SITE. Every consumer\n// wants the same three things \u2014 walk the widgets, keep the issues, and know WHICH\n// widget each belongs to \u2014 and the third is the one a hand-rolled loop forgets. An\n// issue reported without its widget id tells an author that `commandName` is missing\n// on a board with three command buttons, which is a report they cannot act on.\n//\n// \uD83D\uDD11 THE OPTION SCHEMAS ARE TYPESCRIPT, AND THAT DECIDES WHERE THE GATE CAN LIVE.\n// dashboard-management stores a definition as opaque JSON and checks only that it is\n// a JSON object; it is Go, so it cannot run these schemas, and a Go copy of them\n// would be a THIRD representation of the same table (the reason ADR-076 declined a\n// cross-language widget manifest). So the strictness belongs to whoever PRODUCES a\n// definition, and \uD83D\uDD34 EACH PRODUCER HAS TO WIRE IT FOR ITSELF \u2014 there is no chokepoint\n// downstream that would catch a producer nobody thought about:\n//\n// \u2022 the console, by its publish action (apps/console/src/lib/api/dashboards.ts);\n// \u2022 the sim, by the golden-fixture gate over frontend/testdata/sim-dashboards, which\n// covers every dashboard of every REGISTERED scenario. It was widgetlab-only when\n// this function was written, and the sentence here claimed otherwise \u2014 buildingpulse,\n// the demo board, was gated by nothing. Two reviewers found the same overclaim\n// independently. The gate walks sim.Registry now, so the claim is true by\n// construction rather than by a list someone has to remember to extend.\n//\n// Anything ELSE writing a definition \u2014 raw GraphQL, a future importer \u2014 is unchecked,\n// because dashboard-management deliberately validates nothing. This is not the\n// server-side, ADR-044-style publish gate it superficially resembles, and calling it one\n// would misdescribe exactly which documents are protected.\n\nimport {\n UNKNOWN_WIDGET_TYPE,\n validateOptions,\n type DashboardDefinition,\n type WidgetCatalog,\n type WidgetDescriptor,\n type WidgetInstance,\n} from '@devicechain/dashboards';\n\nimport { builtinWidgetCatalog } from './builtin-descriptors';\nimport type { OptionIssue } from './options';\n\n// A DefinitionOptionIssue is an OptionIssue plus the widget that carries it.\n//\n// It deliberately carries the ID and nothing friendlier. An earlier version also read\n// `options.title` so a consumer could label the issue \u2014 and that one read, purely for\n// presentation, put this file into the option-read scan in options.test.ts, where every\n// other entry is evidence that a RENDERER reads a key. It needed a paragraph explaining\n// why it did not mean what its neighbours meant. A consumer that wants a title already\n// holds the definition and can join on the id; the scan goes back to meaning one thing.\nexport interface DefinitionOptionIssue extends Omit<OptionIssue, 'widgetType'> {\n // The stored widget id: a built-in type, or an extension's namespaced id.\n widgetType: string;\n widgetId: string;\n}\n\n// A definition as this module reads it: only the widget list matters, so the fixture\n// tests and the console's in-flight editor state both satisfy it without either having\n// to be a fully parsed DashboardDefinition.\ntype WidgetCarrier = Pick<DashboardDefinition, 'widgets'>;\n\n// validateDefinitionOptions reports every option issue on the board, in widget order.\n// An empty result means every widget's bag is one the renderer honors in full.\n//\n// A placeholder for a widget type this build does not know reports nothing: it carries\n// no options of its own (its stored object is kept verbatim, options and all), and this\n// build has no schema to judge a newer widget's options against.\n//\n// `options.catalog` is the host's widget catalog (registry.catalog): an extension widget is\n// judged against ITS registered schema. Omitted = the built-ins only, so a board carrying an\n// extension widget must be validated with the catalog it was parsed with.\nexport interface DefinitionValidationOptions {\n catalog?: WidgetCatalog;\n}\n\nexport function validateDefinitionOptions(\n definition: WidgetCarrier,\n options: DefinitionValidationOptions = {},\n): DefinitionOptionIssue[] {\n return definition.widgets.flatMap((widget) => {\n if (widget.type === UNKNOWN_WIDGET_TYPE) return [];\n const type = widget.type;\n const descriptor = descriptorFor(type, options.catalog);\n return validateOptions(descriptor.options, widget.options, {\n constraints: descriptor.constraints,\n label: type,\n }).map(({ key, code, message }) => ({ widgetType: type, key, code, message, widgetId: widget.id }));\n });\n}\n\n// The schema a recognized widget is judged against comes from the built-in CATALOG \u2014 the\n// same descriptors a registry holds \u2014 rather than from a by-type table, so this gate is the\n// live consumer of the registry's data. Every built-in type is in the catalog by\n// construction (builtin-registry.test.ts), so a miss is a defect to surface, not a widget\n// to skip.\n//\n// A catalog the host supplies is consulted first (an extension lives only there); a built-in\n// the supplied catalog omits falls back to the built-in descriptor, since its schema is the\n// same everywhere. An id neither holds is a defect \u2014 the board was parsed against a catalog\n// other than the one it is validated with \u2014 so it throws rather than skipping the widget.\nfunction descriptorFor(type: string, catalog: WidgetCatalog | undefined): WidgetDescriptor {\n const descriptor = catalog?.get(type) ?? builtinWidgetCatalog.get(type);\n if (!descriptor) {\n throw new Error(`no widget descriptor for \"${type}\"; validate with the catalog the definition was parsed with`);\n }\n return descriptor;\n}\n\n// stripUnknownOptions removes every option key no widget of that type reads, leaving\n// everything else untouched.\n//\n// \uD83D\uDD34 IT EXISTS BECAUSE 'unknown' IS THE ONE ISSUE CODE AN AUTHOR CANNOT FIX IN THE UI.\n// This is the canonical statement of that reasoning; the call sites point here.\n// Every other code sits on a DECLARED key, so the config panel renders a control for it\n// and the author edits or clears it. An unknown key is by definition one the panel has\n// no control for \u2014 and the panel preserves the bag it did not write (it spreads\n// `widget.options` on every edit), so the key survives every subsequent change. Without\n// this, a publish gate that treats 'unknown' as fatal is a dead end: a dashboard that\n// acquired a leftover key \u2014 from a version predating an option rename, or from a\n// producer other than the console \u2014 could never be published again through the UI.\n//\n// Returns the SAME object when there is nothing to strip, so a caller can detect a\n// no-op with `next === before`.\n//\n// \uD83D\uDD34 THE OBVIOUS REASON TO WANT THIS IS NOT THE REAL ONE, and the first version of this\n// comment gave the wrong one: it claimed a fresh-but-equal object would read as an\n// unsaved edit. It would not \u2014 the console's isDirty compares SERIALIZATIONS\n// (dashboards/src/definition.ts), so an equal-but-new object is not dirty. What the\n// identity actually buys is smaller and still worth having: the caller can tell \"there\n// was nothing to remove\" from \"I removed something\" without diffing, and it avoids a\n// state write that would re-render the editor for no change.\nexport function stripUnknownOptions<T extends WidgetCarrier>(definition: T, options: DefinitionValidationOptions = {}): T {\n let changed = false;\n const widgets = definition.widgets.map((widget) => {\n const stripped = stripUnknownWidgetOptions(widget, options.catalog);\n if (stripped !== widget) changed = true;\n return stripped;\n });\n return changed ? { ...definition, widgets } : definition;\n}\n\nfunction stripUnknownWidgetOptions(widget: WidgetInstance, catalog: WidgetCatalog | undefined): WidgetInstance {\n // A placeholder for an unknown widget type carries no options (they stay in its raw\n // object, which is never rewritten), so it returns here unchanged.\n const bag = widget.options;\n if (!bag) return widget;\n const specs = descriptorFor(widget.type, catalog).options;\n // hasOwnProperty.call, not `in` \u2014 see validateWidgetOptions: every specs table\n // inherits Object.prototype, so `in` would report '__proto__' and 'constructor' as\n // declared and leave exactly the keys a JSON.parse'd definition can smuggle in.\n const keys = Object.keys(bag);\n const kept = keys.filter((key) => Object.prototype.hasOwnProperty.call(specs, key));\n if (kept.length === keys.length) return widget;\n const options: Record<string, unknown> = {};\n for (const key of kept) options[key] = bag[key];\n return { ...widget, options };\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
6
|
-
"names": ["UNKNOWN_WIDGET_TYPE", "useEffect", "useMemo", "useRef", "useState", "useMemo", "
|
|
3
|
+
"sources": ["../src/dashboard-renderer.tsx", "../src/connected-widget.tsx", "../src/use-held.ts", "../src/builtin-registry.ts", "../src/widgets/aggregate-lazy.tsx", "../src/builtin-descriptors.ts", "../src/widgets/lazy-chunk.tsx", "../src/widgets/alarm-count.tsx", "../src/widgets/severity.ts", "../src/widgets/alarm-table.tsx", "../src/widgets/command-button.tsx", "../src/widgets/control-lazy.tsx", "../src/widgets/entity-selector.tsx", "../src/widgets/gauge.tsx", "../src/widgets/image.tsx", "../src/widgets/label.tsx", "../src/widgets/latest-card.tsx", "../src/widgets/level-lazy.tsx", "../src/widgets/map.tsx", "../src/basemap-context.tsx", "../src/map-runtime-context.tsx", "../src/widgets/map-geometry.ts", "../src/widgets/table.tsx", "../src/widgets/time-series-chart.tsx", "../src/default-registry.ts", "../src/widget-containment.tsx", "../src/widget-host.ts", "../src/time-range-bar.tsx", "../src/registry.ts", "../src/index.ts", "../src/options.ts", "../src/definition-options.ts"],
|
|
4
|
+
"sourcesContent": ["// Copyright The DeviceChain Authors\n// SPDX-License-Identifier: Apache-2.0\n\n// DashboardRenderer maps a parsed DashboardDefinition onto a real CSS Grid of SQUARE cells: the\n// canvas is `display:grid` with `repeat(columns, 1fr)`, so the board FILLS whatever width its\n// container gives it, and every row is as tall as a column is wide (the cell size is computed in\n// CSS from the grid's own width, `100cqw`, so it needs no measurement and has no first-frame\n// flash). A `grid` widget occupies its footprint (`grid-column`/`grid-row`); a `relative` widget\n// is drawn over its host's area at the host's anchor point, offset in cell pitches, and above\n// every grid widget. Gutters and padding are lengths or spacing tokens scaled by the density;\n// each widget's frame is the canvas default merged with its own (resolveFrame).\n//\n// Adaptive columns and reflow: the board measures its CONTAINER (not the window), and while a\n// cell at the authored column count is at least `minCellSize` it renders as authored and the\n// cells stretch. Narrower than that the column count drops to what fits and the base layout is\n// poured into it in reading order (effectiveLayout), each widget clamped into the span limits\n// its descriptor declares; below STACK_BELOW_WIDTH (a phone) that is a single column. A breakpoint the author defined for the width wins over the automatic\n// reflow. Until the container has a measured width the authored layout is drawn. Container sizing\n// (fill / fixed-width / fixed-height) is a mount knob the host may override via the `sizing`\n// prop. It is view-only; the canvas editor lives in the console. This is the shared viewer the\n// console and the reference /dash app mount.\n\nimport {\n anchorFraction,\n DEFAULT_CANVAS_DENSITY,\n defaultHistoryWindow,\n effectiveLayout,\n historyWindowFor,\n initialTimeRange,\n fetchWidgetHistory,\n layoutShape,\n resolveFrame,\n resolvePlacement,\n resolveWidgetDatasource,\n spanLimitsOfLayout,\n UNKNOWN_WIDGET_TYPE,\n type CanvasBackground,\n type CanvasDensity,\n type CanvasGrid,\n type CanvasSizing,\n type DashboardDefinition,\n type GridLength,\n type GridPlacement,\n type RelativePlacement,\n type WidgetActions,\n type WidgetDataSource,\n type MeasurementSample,\n type SlotBinding,\n type TimeRangeState,\n type WidgetFrameSpec,\n type WidgetInstance,\n} from '@devicechain/dashboards';\nimport {\n densityScale,\n tokenStyle,\n WidgetDensityProvider,\n WidgetFrameStyleProvider,\n WidgetTimeRangeProvider,\n WidgetTokenStyles,\n type WidgetRegistry,\n} from '@devicechain/widget-sdk';\nimport { Fragment, useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState, type CSSProperties, type ReactNode, type RefObject } from 'react';\n\nimport { measurementSpan } from './binding-policy';\nimport { ConnectedWidget } from './connected-widget';\nimport {\n type WidgetCandidates,\n WidgetCandidatesProvider,\n type WidgetSelect,\n WidgetSelectProvider,\n WidgetSubjectProvider,\n WidgetThemeRootProvider,\n WidgetTimeZoneProvider,\n} from '@devicechain/widget-sdk';\nimport { defaultWidgetRegistry } from './default-registry';\n\nexport interface DashboardRendererProps {\n definition: DashboardDefinition;\n hub: WidgetDataSource;\n // The widget registry that resolves every widget's component, channel, binding policy and\n // history eligibility. Omitted = the built-ins. A host with extension packages passes the\n // SAME registry it parsed `definition` with (parseDashboardDefinition(raw, { catalog:\n // registry.catalog })), so an extension widget is recognized and rendered consistently.\n registry?: WidgetRegistry;\n // The action seam (writes) for acting widgets (alarm ack/clear, command send). Omit\n // for a strictly read-only mount; the same instance as `hub` when the runtime provides\n // both (DashboardHub / SyntheticDataSource implement WidgetActions).\n actions?: WidgetActions;\n // Whether to backfill each widget from bucketedMeasurements (a real backend call).\n // Default true; set false for offline preview, where the data source (e.g.\n // SyntheticDataSource) supplies its own history and the backend must not be hit.\n seedHistory?: boolean;\n // The settled slot manifest (useResolvedBindings). Every widget's `slot` selector is\n // resolved through it HERE, before the widget subscribes, to the bound device or anchor\n // \u2014 or to an explicit `unbound` selector when the slot has no binding. The hub holds no\n // bindings, so a host keeps ONE hub (useDashboardHub) and a change to this map\n // re-subscribes only the widgets whose slot moved. Omitted = no slot is bound.\n bindings?: Record<string, SlotBinding>;\n // Host override for the definition's container sizing (the embed knob \u2014 a host can\n // force a dashboard authored `fill` into a fixed-px box, or vice versa). Omitted \u2192\n // the definition's own `canvas.sizing`.\n sizing?: CanvasSizing;\n // The selection callback (ADR-039 selection amendment): a widget (e.g. an alarm-table\n // originator drill) calls it to re-point a slot; the host accumulates it into the\n // selection overlay that produces `bindings`. Omit for a static dashboard \u2014 widgets\n // then render no drill affordance.\n select?: WidgetSelect;\n // The candidate provider (useSlotCandidates) an entity-selector widget reads to offer a\n // target slot's options. Omit alongside `select` for a static/edit/preview mount \u2014 the\n // selector then renders inert.\n candidates?: WidgetCandidates;\n // The IANA zone widgets print instants in. Omit for the viewer's own zone (every live\n // host); a host replaying a recording pins one so the board agrees with the recording.\n timeZone?: string;\n // The element chart colors are read from, when the host scopes its design tokens to a\n // container rather than the document root. Omit for the document root (every other host).\n themeRoot?: Element;\n // A viewer's density override (the /dash app's `?density=`). Wins over the definition's\n // authored `canvas.density`, which wins over `comfortable`. Density scales every size token\n // (font, spacing) and the floor of the value-font curve, never the curve itself.\n density?: CanvasDensity;\n // The board's time range: the span its time-series widgets draw, and whether the viewer has\n // frozen it. Owned by the host (useBoardTimeRange + TimeRangeBar) so the control can live in the\n // host's own header. Omitted = live over the definition's default span (or one hour), with no\n // control -- a static embed, the replay page, an edit preview.\n timeRange?: TimeRangeState;\n}\n\nexport function DashboardRenderer({\n definition,\n hub,\n registry: registryProp,\n actions,\n seedHistory = true,\n bindings,\n sizing,\n select,\n candidates,\n timeZone,\n themeRoot,\n density,\n timeRange,\n}: DashboardRendererProps) {\n // Each widget with its slot resolved to a concrete selector. Recomputed per render;\n // that is cheap, and every channel keys its subscription on the selector's VALUE, so a\n // widget whose concrete selector did not change keeps its subscription.\n const widgets = useMemo(() => resolveWidgets(definition.widgets, bindings), [definition.widgets, bindings]);\n const registry = registryProp ?? defaultWidgetRegistry();\n // The default is derived, not stored: a host with no control still gets the board's own span.\n const defaultSeconds = definition.timeRange?.defaultSeconds;\n const range = useMemo(\n () => timeRange ?? initialTimeRange(defaultSeconds),\n [timeRange, defaultSeconds],\n );\n const histories = useWidgetHistories(widgets, seedHistory, registry, range);\n\n const { grid, background: bg, frame: canvasFrame } = definition.canvas;\n const effectiveSizing = sizing ?? definition.canvas.sizing;\n const effectiveDensity = density ?? definition.canvas.density ?? DEFAULT_CANVAS_DENSITY;\n const scale = densityScale(effectiveDensity);\n // The width is kept only when it changes the layout's shape (breakpoint, columns, single\n // column): within one shape the cells stretch through CSS, so a resize redraws nothing until\n // a column comes or goes.\n const { canvas } = definition;\n const shapeKey = useCallback((width: number) => JSON.stringify(layoutShape(canvas, width, scale)), [canvas, scale]);\n const [boardRef, containerWidth] = useContainerWidth<HTMLDivElement>(shapeKey);\n const layout = useMemo(\n () =>\n effectiveLayout(definition, containerWidth, {\n scale,\n limitsOf: (w) => (w.type === UNKNOWN_WIDGET_TYPE ? undefined : spanLimitsOfLayout(registry.descriptor(w.type)?.layout)),\n }),\n [definition, containerWidth, scale, registry],\n );\n const { breakpoint, columns } = layout;\n const lengths = gridCss(grid, columns);\n\n return (\n <div\n ref={boardRef}\n data-density={effectiveDensity}\n data-columns={columns}\n data-time-paused={range.paused ? '' : undefined}\n style={{ ...sizingStyle(effectiveSizing, bg), ...tokenStyle(scale) }}\n >\n <WidgetTokenStyles />\n <WidgetDensityProvider scale={scale}>\n <WidgetThemeRootProvider root={themeRoot}>\n <WidgetTimeZoneProvider timeZone={timeZone}>\n <WidgetTimeRangeProvider range={range}>\n <WidgetSelectProvider select={select}>\n <WidgetCandidatesProvider candidates={candidates}>\n <div style={{ padding: lengths.padding }}>\n {/* The query container: its width is the grid's, so 100cqw below is the grid width. */}\n <div style={{ containerType: 'inline-size' }}>\n <div\n data-grid=\"\"\n style={{\n display: 'grid',\n gridTemplateColumns: `repeat(${columns}, minmax(0, 1fr))`,\n gridAutoRows: CELL,\n columnGap: lengths.gutterX,\n rowGap: lengths.gutterY,\n width: '100%',\n ...({ '--dc-cell': lengths.cell } as CSSProperties),\n }}\n >\n <PlacedWidgets\n widgets={widgets}\n breakpoint={breakpoint}\n columns={columns}\n grid={layout.grid}\n lengths={lengths}\n render={(widget) => (\n <WidgetFrameStyleProvider frame={resolveFrame(canvasFrame, widgetFrame(widget))}>\n <WidgetSubjectProvider label={widgetSubjectLabel(widget)}>\n <ConnectedWidget\n widget={widget}\n hub={hub}\n registry={registry}\n actions={actions}\n initialSamples={histories[widget.id]}\n />\n </WidgetSubjectProvider>\n </WidgetFrameStyleProvider>\n )}\n />\n </div>\n </div>\n </div>\n </WidgetCandidatesProvider>\n </WidgetSelectProvider>\n </WidgetTimeRangeProvider>\n </WidgetTimeZoneProvider>\n </WidgetThemeRootProvider>\n </WidgetDensityProvider>\n </div>\n );\n}\n\n// The live cell size, as the grid element defines it.\nconst CELL = 'var(--dc-cell)';\n\n// The grid's lengths as CSS: px multiply by the density scale like every size token, and a\n// spacing token reads the board's own variable.\nexport interface GridCss {\n gutterX: string;\n gutterY: string;\n padding: string;\n // The live cell size: the grid's width less its gutters, shared by the columns. Read inside\n // the query container, so `100cqw` is the grid's width.\n cell: string;\n}\n\nexport function gridLengthCss(len: GridLength): string {\n if (typeof len === 'number') return `calc(${len}px * var(--dc-scale, 1))`;\n return len === 'space-0' ? '0px' : `var(--dc-${len})`;\n}\n\nexport function gridCss(grid: CanvasGrid, columns: number): GridCss {\n const g = grid.gutter;\n const gutterX = gridLengthCss(typeof g === 'object' ? g.x : g);\n const gutterY = gridLengthCss(typeof g === 'object' ? g.y : g);\n const p = grid.padding;\n const padding =\n typeof p === 'object'\n ? [p.top, p.right, p.bottom, p.left].map(gridLengthCss).join(' ')\n : gridLengthCss(p);\n return { gutterX, gutterY, padding, cell: `calc((100cqw - ${columns - 1} * ${gutterX}) / ${columns})` };\n}\n\n// The frame override a widget carries (a placeholder carries none: its stored frame is the\n// newer release's to read).\nfunction widgetFrame(widget: WidgetInstance): WidgetFrameSpec | undefined {\n return widget.type === UNKNOWN_WIDGET_TYPE ? undefined : widget.frame;\n}\n\n// gridItemStyle maps a grid placement to a grid-item style. col/row are 0-based cells \u2192\n// CSS's 1-based `col+1 / span cols`. It CLAMPS the placement into the grid's column count: a\n// footprint whose `col`/`cols` overruns `columns` (a hand-authored or imported one; the lint\n// reports it) would otherwise land in implicit `auto` tracks CSS appends past the `1fr`\n// columns \u2014 unequal widths + horizontal overflow instead of a clamped placement. Rows are\n// unbounded (implicit rows are the intended vertical growth), so only columns clamp.\nexport function gridItemStyle(p: GridPlacement, columns: number): CSSProperties {\n const col = Math.min(Math.max(0, p.col), columns - 1);\n const cols = Math.min(Math.max(1, p.cols), columns - col);\n return {\n gridColumn: `${col + 1} / span ${cols}`,\n gridRow: `${p.row + 1} / span ${p.rows}`,\n // Let a grid item shrink below its content's intrinsic size so a wide chart/table\n // fits its track instead of overflowing it.\n minWidth: 0,\n minHeight: 0,\n };\n}\n\n// Relative widgets paint above every grid widget, in `layer` order among themselves.\nconst RELATIVE_Z = 100;\n\n// relativeBoxStyle positions a relative widget inside its host's box (the containing block): the\n// host's anchor point (a percentage of the host), minus this widget's own `self` point (a\n// percentage of itself, via translate), plus the offset in cell pitches.\nexport function relativeBoxStyle(p: RelativePlacement, lengths: Pick<GridCss, 'gutterX' | 'gutterY'>): CSSProperties {\n const a = anchorFraction(p.anchor);\n const s = anchorFraction(p.self ?? p.anchor);\n const span = (n: number, gutter: string) => `calc(${n} * ${CELL} + ${n - 1} * ${gutter})`;\n const pitches = (n: number, gutter: string) => `${n} * (${CELL} + ${gutter})`;\n const fill = 'fill' in p.size;\n return {\n position: 'absolute',\n left: `calc(${a.fx * 100}% + ${pitches(p.offset?.x ?? 0, lengths.gutterX)})`,\n top: `calc(${a.fy * 100}% + ${pitches(p.offset?.y ?? 0, lengths.gutterY)})`,\n width: fill ? '100%' : span((p.size as { cols: number }).cols, lengths.gutterX),\n height: fill ? '100%' : span((p.size as { rows: number }).rows, lengths.gutterY),\n transform: `translate(${-s.fx * 100}%, ${-s.fy * 100}%)`,\n zIndex: RELATIVE_Z + (p.layer ?? 0),\n pointerEvents: 'auto',\n };\n}\n\n// PlacedWidgets draws every widget at a breakpoint: each grid widget as a grid item, and each\n// relative widget inside a layer over its host's grid area (a relative widget hosted on another\n// relative widget is drawn inside that one's box, one level deep, as the parser allows).\nfunction PlacedWidgets({\n widgets,\n breakpoint,\n columns,\n grid,\n lengths,\n render,\n}: {\n widgets: WidgetInstance[];\n breakpoint: string;\n columns: number;\n // Where each grid widget is DRAWN: its authored footprint, or the reflowed one.\n grid: ReadonlyMap<string, GridPlacement>;\n lengths: GridCss;\n render: (widget: WidgetInstance) => ReactNode;\n}) {\n const placed = widgets.map((w) => ({ widget: w, placement: resolvePlacement(w.layout, breakpoint) }));\n const dependents = new Map<string, { widget: WidgetInstance; placement: RelativePlacement }[]>();\n for (const { widget, placement } of placed) {\n if (placement.mode !== 'relative') continue;\n dependents.set(placement.host, [...(dependents.get(placement.host) ?? []), { widget, placement }]);\n }\n const relative = (host: string): ReactNode =>\n (dependents.get(host) ?? []).map(({ widget, placement }) => (\n // data-widget names the box a widget occupies, so a check over the rendered board (the\n // readability gate in apps/board-replay) can find it.\n <div key={widget.id} data-widget={widget.id} data-host={host} style={relativeBoxStyle(placement, lengths)}>\n {render(widget)}\n {relative(widget.id)}\n </div>\n ));\n return (\n <>\n {placed.map(({ widget, placement }) => {\n if (placement.mode !== 'grid') return null;\n const style = gridItemStyle(grid.get(widget.id) ?? placement, columns);\n // Keyed by the widget, so removing or reordering widgets never remounts (and so never\n // re-subscribes) the ones that stay.\n return (\n <Fragment key={widget.id}>\n <div data-widget={widget.id} style={style}>\n {render(widget)}\n </div>\n {dependents.has(widget.id) ? (\n // The host's area again, as a layer for its relative widgets to be positioned in.\n // It takes no pointer events itself, so the host underneath stays usable.\n <div style={{ ...style, position: 'relative', pointerEvents: 'none', zIndex: RELATIVE_Z }}>\n {relative(widget.id)}\n </div>\n ) : null}\n </Fragment>\n );\n })}\n </>\n );\n}\n\n// sizingStyle turns the container-sizing knob into the outer wrapper's box. `fill`\n// takes the mount container's full width+height (the grid fills it); `{width}` caps\n// the width (the fluid grid adjusts within it); `{height}` pins the height (rows\n// scroll). All scroll internally so the board owns its single scroll region. The\n// background (color AND image) paints on this wrapper so it covers the whole container\n// even when the grid's rows are shorter than the sizing box.\nexport function sizingStyle(sizing: CanvasSizing, bg: CanvasBackground | undefined): CSSProperties {\n const base: CSSProperties = {\n overflow: 'auto',\n backgroundColor: bg?.color ?? undefined,\n backgroundImage: bg?.imageUrl ? `url(${bg.imageUrl})` : undefined,\n backgroundSize: 'cover',\n };\n if (sizing === 'fill') return { ...base, width: '100%', height: '100%' };\n if ('width' in sizing) return { ...base, width: sizing.width, maxWidth: '100%', height: '100%' };\n return { ...base, width: '100%', height: sizing.height };\n}\n\n// resolveWidgets maps each widget's datasource through the settled bindings\n// (resolveWidgetDatasource): a slot becomes the device or anchor it is bound to, or an\n// explicit `unbound` selector. A widget with no datasource keeps none \u2014 that is a\n// different fact (tenant-wide on the alarm channel) and must not be manufactured here.\nexport function resolveWidgets(\n widgets: WidgetInstance[],\n bindings: Record<string, SlotBinding> | undefined,\n): WidgetInstance[] {\n return widgets.map((widget) => {\n if (widget.type === UNKNOWN_WIDGET_TYPE || widget.datasource?.kind !== 'slot') return widget;\n return { ...widget, datasource: resolveWidgetDatasource(widget.datasource, bindings) };\n });\n}\n\n// widgetSubjectLabel names the entity a widget shows \u2014 its CONCRETE datasource's device\n// or anchor \u2014 for the frame subtitle. Pass the widget as the renderer resolved it\n// (resolveWidgets), so the subtitle is read from the same selector the widget subscribes\n// with and can never name an entity other than the one being shown. Returns undefined for\n// a datasource-free widget (label/image, a tenant-wide alarm tile), an unbound slot, an\n// unresolved slot, or a reserved selector kind \u2014 the frame then shows no subtitle.\nexport function widgetSubjectLabel(widget: WidgetInstance): string | undefined {\n const ds = widget.datasource;\n if (!ds) return undefined;\n if (ds.kind === 'device') return ds.deviceToken || undefined;\n if (ds.kind === 'anchor') return ds.anchor.targetToken;\n return undefined;\n}\n\n// useContainerWidth tracks an element's content width with a ResizeObserver, measured\n// synchronously before first paint so a narrow container never flashes the authored layout. 0\n// means \"not measured\" (no layout engine, or not yet laid out) and draws the authored layout.\n// A new width is taken only when `keyOf` tells it apart from the one held, so a resize that\n// does not change what is drawn does not re-render; a new `keyOf` re-measures under its rule.\nfunction useContainerWidth<T extends HTMLElement>(keyOf: (width: number) => string): [RefObject<T | null>, number] {\n const ref = useRef<T>(null);\n const [width, setWidth] = useState(0);\n const keyOfRef = useRef(keyOf);\n const measure = useCallback(() => {\n const el = ref.current;\n if (!el) return;\n const next = el.clientWidth;\n setWidth((prev) => (keyOfRef.current(prev) === keyOfRef.current(next) ? prev : next));\n }, []);\n useLayoutEffect(() => {\n keyOfRef.current = keyOf;\n measure();\n }, [keyOf, measure]);\n useLayoutEffect(() => {\n const el = ref.current;\n if (!el || typeof ResizeObserver === 'undefined') return;\n const ro = new ResizeObserver(measure);\n ro.observe(el);\n return () => ro.disconnect();\n }, [measure]);\n return [ref, width];\n}\n\n// A widget's seed, tagged with the concrete selector it was fetched for.\ninterface Seed {\n key: string;\n samples: MeasurementSample[];\n}\n\n// seedKey is the identity of what a measurement widget's history is OF: its concrete\n// selector, by value. Undefined for a widget that takes no seed.\nfunction seedKey(widget: WidgetInstance, registry: WidgetRegistry): string | undefined {\n // Eligibility is registry metadata: only a registered measurement-channel widget takes a\n // seed. A placeholder, an unregistered id and every other channel take none.\n if (widget.type === UNKNOWN_WIDGET_TYPE || registry.descriptor(widget.type)?.channel !== 'measurement') {\n return undefined;\n }\n return JSON.stringify(widget.datasource ?? null);\n}\n\n// useWidgetHistories backfills each measurement widget from bucketedMeasurements and\n// returns an id\u2192samples map. Each seed is keyed by the widget's OWN concrete selector,\n// not by the board's bindings as a whole, so:\n//\n// - a selection that re-points one slot re-fetches only the widgets bound to it;\n// - a seed fetched for a selector the widget no longer has is DROPPED at render,\n// synchronously, so a widget never shows the previous device's history under the new\n// device while the new fetch is pending;\n// - a slow answer for a superseded selector is discarded when it lands.\n//\n// A widget's samples array is the one stored for its seed, so an unchanged seed keeps\n// its identity across renders and does not churn the stream's merge.\nfunction useWidgetHistories(\n widgets: WidgetInstance[],\n enabled: boolean,\n registry: WidgetRegistry,\n range: TimeRangeState,\n): Record<string, MeasurementSample[] | undefined> {\n const [seeds, setSeeds] = useState<Record<string, Seed>>({});\n // widget id \u2192 the selector key most recently REQUESTED for it. A fetch whose key is no\n // longer the requested one is stale when it lands.\n const requested = useRef<Record<string, string>>({});\n const mounted = useRef(true);\n useEffect(() => {\n mounted.current = true;\n return () => {\n mounted.current = false;\n };\n }, []);\n\n // The (id, key, span) triples that want a seed; value-compared so an equal render is a no-op.\n // `span` is the seconds a TIME-RANGED widget draws (null for one that is not, which keeps the\n // fixed default seed): a new span re-fetches, but the seed on screen stays until the new one lands,\n // because it is the same device's history and the stream prunes it to the span anyway.\n const wanted = widgets.flatMap((w) => {\n const key = seedKey(w, registry);\n if (key === undefined) return [];\n const descriptor = w.type === UNKNOWN_WIDGET_TYPE ? undefined : registry.descriptor(w.type);\n const span = descriptor ? (measurementSpan(descriptor, w, range.spanSeconds) ?? null) : null;\n return [[w.id, key, span] as const];\n });\n const wantedKey = JSON.stringify(wanted);\n\n useEffect(() => {\n // Preview (enabled=false) must not touch the backend; clear any prior seed so a\n // toggle from live\u2192preview doesn't leave stale real history under synthetic data.\n if (!enabled) {\n requested.current = {};\n setSeeds({});\n return;\n }\n const now = Date.now();\n const byId = new Map(widgets.map((w) => [w.id, w]));\n const next: Record<string, string> = {};\n for (const [id, key, span] of wanted) {\n // What was asked for: the selector AND the span. Equal = fetched, or in flight.\n const asked = `${key}|${span ?? ''}`;\n next[id] = asked;\n if (requested.current[id] === asked) continue;\n const widget = byId.get(id);\n if (!widget) continue;\n // A frozen board reads up to the freeze instant, so a range change while paused re-fetches\n // the same moment at the new span instead of sliding forward.\n const historyWindow =\n span === null\n ? defaultHistoryWindow()\n : historyWindowFor(span, range.paused && range.pausedAt !== undefined ? range.pausedAt : now);\n void fetchWidgetHistory(widget, historyWindow).then((samples) => {\n if (!mounted.current || requested.current[id] !== asked) return; // superseded or unmounted\n setSeeds((prev) => ({ ...prev, [id]: { key, samples } }));\n });\n }\n requested.current = next;\n // `widgets`/`wanted` are read via wantedKey (value identity), not reference.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [wantedKey, enabled]);\n\n // Hand each widget its seed ONLY if it was fetched for the selector the widget has now.\n return useMemo(() => {\n const out: Record<string, MeasurementSample[] | undefined> = {};\n if (!enabled) return out;\n for (const w of widgets) {\n const seed = seeds[w.id];\n out[w.id] = seed && seed.key === seedKey(w, registry) ? seed.samples : undefined;\n }\n return out;\n }, [widgets, seeds, enabled, registry]);\n}\n", "// Copyright The DeviceChain Authors\n// SPDX-License-Identifier: Apache-2.0\n\n// ConnectedWidget is the one place the imperative DashboardHub meets the pure widget\n// contract. It looks the widget up in the host's REGISTRY and dispatches on the registered\n// descriptor's data CHANNEL: a measurement widget subscribes its datasource (windowed per its\n// binding policy); an alarm widget subscribes its scope+filters through the hub's alarm\n// channel; and so on. Either way it resolves the data and renders the registered component\n// with { widget, data }. A dashboard renderer maps over its widgets rendering one\n// ConnectedWidget each.\n//\n// Each widget renders inside its own containment (widget-containment.tsx): a throw shows a\n// local diagnostic with a reset control and the siblings keep rendering. A widget the\n// registry cannot resolve (an unknown or unavailable package, a version it cannot read) is a\n// placeholder with a specific reason: it reads nothing \u2014 no channel, no availability query \u2014\n// and is handed no actions.\n\nimport {\n UNKNOWN_WIDGET_TYPE,\n type MeasurementSample,\n type UnresolvedWidgetReason,\n type WidgetActions,\n type WidgetDataSource,\n type WidgetDescriptor,\n type WidgetInstance,\n} from '@devicechain/dashboards';\nimport {\n newestSampleTime,\n resolveStaleAfterSeconds,\n WidgetCandidatesProvider,\n WidgetFreshnessProvider,\n WidgetSelectProvider,\n useWidgetTimeRange,\n type WidgetFreshness,\n type WidgetRegistry,\n} from '@devicechain/widget-sdk';\nimport { useMemo, type ComponentType, type ReactNode } from 'react';\n\nimport { alarmSubscription, commandSubscription, measurementSpan, measurementWindow, membersMode } from './binding-policy';\nimport { useHeld } from './use-held';\nimport { defaultWidgetRegistry } from './default-registry';\nimport {\n optString,\n useAlarmStream,\n useCommandStream,\n useDatasourceAvailability,\n useLocationStream,\n useMeasurementStream,\n useWidgetCandidates,\n useWidgetSelect,\n WidgetFrame,\n} from '@devicechain/widget-sdk';\nimport { WidgetContainment, useReportRejection } from './widget-containment';\nimport { lazyChunk } from './widgets/lazy-chunk';\nimport type { AggregateFeedProps } from './aggregate-feed';\nimport type { FleetFeedProps } from './fleet-feed';\nimport { narrowActions, narrowCandidates, narrowSelect } from './widget-host';\n\nexport interface ConnectedWidgetProps {\n widget: WidgetInstance;\n hub: WidgetDataSource;\n // The registry that resolves the widget's component, channel and binding policy. Omitted =\n // the built-in registry. A host composing extension packages passes the SAME registry it\n // parsed the definition with.\n registry?: WidgetRegistry;\n // The action seam (writes). Narrowed per widget to the interactions its descriptor\n // declares; undefined = read-only.\n actions?: WidgetActions;\n // Optional history backfill for this widget (from bucketedMeasurements), seeded\n // under the live tail so a chart isn't blank until the first live sample. Ignored by\n // every channel but measurement (the others reconcile from a query, not a history seed).\n initialSamples?: MeasurementSample[];\n}\n\nexport function ConnectedWidget(props: ConnectedWidgetProps) {\n const { widget } = props;\n const registry = props.registry ?? defaultWidgetRegistry();\n // A change to what the widget is configured with retries a widget that threw on the old one.\n const resetKey = JSON.stringify([widget.type, widget.options ?? null, widget.datasource ?? null]);\n return (\n <WidgetContainment title={optString(widget.options, 'title')} resetKey={resetKey}>\n <ConnectedWidgetBody {...props} registry={registry} />\n </WidgetContainment>\n );\n}\n\ntype BodyProps = ConnectedWidgetProps & { registry: WidgetRegistry };\n\n// The component a registration renders. Its props are erased in the registry (one registry\n// holds components of every channel); the channel adapters below supply the matching data.\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype AnyWidgetComponent = ComponentType<any>;\n\nfunction ConnectedWidgetBody({ widget, hub, registry, actions, initialSamples }: BodyProps) {\n const unresolved = widget.type === UNKNOWN_WIDGET_TYPE;\n const descriptor = unresolved ? undefined : registry.descriptor(widget.type);\n const implementation = unresolved ? undefined : registry.implementation(widget.type);\n\n // A widget bound to a since-deleted device (its stable token no longer resolves)\n // shows an \"unavailable\" pane rather than a blank one \u2014 checked optimistically, so a\n // valid widget renders from its stream without waiting on this. An unresolved widget asks\n // nothing: it is never given a datasource to check. Nor does a widget whose descriptor\n // binds none (label, image, the selector): a datasource left on its stored JSON is one it\n // never reads, so it must not turn the widget into an \"unavailable\" pane.\n const readsDatasource = descriptor !== undefined && descriptor.datasource.mode !== 'none';\n const availability = useDatasourceAvailability(hub, readsDatasource ? widget.datasource : undefined);\n if (availability === 'unavailable') {\n return <WidgetUnavailableFrame widget={widget} />;\n }\n\n if (widget.type === UNKNOWN_WIDGET_TYPE) {\n return <UnresolvedWidgetFrame storedType={widget.raw.type} reason={widget.reason} />;\n }\n if (!descriptor || !implementation) {\n // Parsed against a catalog this registry does not hold: say so rather than render nothing.\n return (\n <UnresolvedWidgetFrame\n storedType={widget.type}\n reason={{ code: 'unregistered', message: `\"${widget.type}\" is not registered in this host's widget registry` }}\n />\n );\n }\n\n return (\n <HostScope descriptor={descriptor} actions={actions}>\n {(hostActions) => (\n <ChannelBody\n widget={widget}\n hub={hub}\n descriptor={descriptor}\n Component={implementation.component}\n actions={hostActions}\n initialSamples={initialSamples}\n />\n )}\n </HostScope>\n );\n}\n\n// HostScope hands ONE widget only the interactions it declared: a narrowed action seam, and\n// the ambient selection / candidate providers re-provided so an undeclared capability\n// reads as \"not wired\" to a widget that asks.\nfunction HostScope({\n descriptor,\n actions,\n children,\n}: {\n descriptor: WidgetDescriptor;\n actions: WidgetActions | undefined;\n children: (actions: WidgetActions | undefined) => ReactNode;\n}) {\n const report = useReportRejection();\n const select = useWidgetSelect();\n const candidates = useWidgetCandidates();\n const narrowed = useMemo(() => narrowActions(actions, descriptor, report), [actions, descriptor, report]);\n const narrowedSelect = useMemo(() => narrowSelect(select, descriptor), [select, descriptor]);\n const narrowedCandidates = useMemo(\n () => narrowCandidates(candidates, descriptor, report),\n [candidates, descriptor, report],\n );\n return (\n <WidgetSelectProvider select={narrowedSelect}>\n <WidgetCandidatesProvider candidates={narrowedCandidates}>{children(narrowed)}</WidgetCandidatesProvider>\n </WidgetSelectProvider>\n );\n}\n\ninterface ChannelProps {\n widget: WidgetInstance;\n hub: WidgetDataSource;\n descriptor: WidgetDescriptor;\n Component: AnyWidgetComponent;\n actions: WidgetActions | undefined;\n initialSamples?: MeasurementSample[];\n}\n\n// The channel is the only thing the runtime branches on \u2014 never the widget id.\nfunction ChannelBody(props: ChannelProps) {\n switch (props.descriptor.channel) {\n case 'alarm':\n return <AlarmConnectedWidget {...props} />;\n case 'control':\n return <ControlConnectedWidget {...props} />;\n case 'location':\n return <LocationConnectedWidget {...props} />;\n case 'aggregate':\n return <AggregateConnectedWidget {...props} />;\n case 'selection':\n case 'none':\n return <StaticConnectedWidget {...props} />;\n case 'measurement':\n return <MeasurementConnectedWidget {...props} />;\n }\n}\n\n// A selection widget (entity-selector) consumes no hub data \u2014 it reads the ambient candidate\n// provider + selection callback; a `none` widget is static. Neither subscribes anything.\nfunction StaticConnectedWidget({ widget, Component, actions }: ChannelProps) {\n return <Component widget={widget} data={null} actions={actions} />;\n}\n\n// The fleet feed is its own chunk (fleet-feed.tsx), like the aggregate feed: a board without a fleet\n// table or a per-device bar chart never downloads it. A chunk that fails to load is thrown to the\n// widget's containment, which shows the failure, and its Reset fetches it again (lazyChunk).\nconst FleetFeed = lazyChunk<typeof import('./fleet-feed')>(() => import('./fleet-feed')).component<never, FleetFeedProps>('default');\n\nfunction MeasurementConnectedWidget(props: ChannelProps) {\n // Read member by member, or as one stream keyed by measurement name: decided by the descriptor\n // and the widget's options, never by the widget id.\n //\n // Keyed by measurement name, a group's devices would overwrite one another and the widget would\n // show whichever spoke last as if it were the answer. So a group reaching a widget that is not\n // reading member by member is refused in words (the fleet chunk says so), whatever brought it\n // here: a host binding, an older definition. The editor offers a group only to the fleet widgets.\n const { widget, hub, descriptor, Component, actions } = props;\n const members = membersMode(descriptor, widget);\n if (members || widget.datasource?.kind === 'anchor') {\n return (\n <FleetFeed hub={hub} widget={widget} descriptor={descriptor} Component={Component} actions={actions} ErrorFrame={WidgetErrorFrame} refuse={!members} />\n );\n }\n return <StreamConnectedWidget {...props} />;\n}\n\nfunction StreamConnectedWidget({ widget, hub, descriptor, Component, actions, initialSamples }: ChannelProps) {\n // The board's time range (D-1). A widget that declares `binding.windowSeconds` draws a SPAN: its\n // own pinned one, else the board's. Every measurement widget honors the pause, because a frozen\n // board must freeze its cards and gauges too -- a number that kept moving under a \"Paused\"\n // badge would be the worst possible answer.\n const range = useWidgetTimeRange();\n // The source's own clock (a recorded run is dated by the run), else the wall clock.\n const now = useMemo(() => (hub.now ? () => hub.now!() : Date.now), [hub]);\n const data = useMeasurementStream(hub, widget.datasource, {\n window: measurementWindow(descriptor, widget),\n windowSeconds: measurementSpan(descriptor, widget, range?.spanSeconds),\n pausedAt: range?.paused ? range.pausedAt : undefined,\n now,\n initialSamples,\n });\n\n // Opt-in through the descriptor. The age is of the newest sample among the measurements this\n // widget shows (its pinned one, else its datasource's, else whatever has arrived) -- right for\n // a chart or a table, which time every point or row. A single-value widget narrows it to the\n // sample it actually shows by passing that sample's time to its WidgetFrame (`sampleTime`).\n // The threshold is the widget's own option, and absent means age only.\n const freshness = useMemo<WidgetFreshness | undefined>(() => {\n if (descriptor.freshness !== true) return undefined;\n const pinned = optString(widget.options, 'measurement');\n const names = pinned ? [pinned] : widget.datasource?.measurements;\n return {\n at: newestSampleTime(data.latest, names),\n staleAfterSeconds: resolveStaleAfterSeconds(widget.options),\n };\n }, [descriptor, widget.options, widget.datasource, data.latest]);\n\n if (data.error) return <WidgetErrorFrame widget={widget} error={data.error} />;\n return (\n <WidgetFreshnessProvider freshness={freshness}>\n <Component widget={widget} data={data} actions={actions} />\n </WidgetFreshnessProvider>\n );\n}\n\n// The aggregate feed is its own chunk (aggregate-feed.tsx): a board without an aggregate widget\n// never downloads it. Nothing renders until it arrives, and a chunk that fails to load is thrown to\n// the widget's containment, which shows the failure, and its Reset fetches it again.\nconst AggregateFeed = lazyChunk<typeof import('./aggregate-feed')>(() => import('./aggregate-feed')).component<never, AggregateFeedProps>('default');\n\nfunction AggregateConnectedWidget({ widget, hub, descriptor, Component, actions }: ChannelProps) {\n // An aggregate names one device's measurements, so a group is refused as above.\n const props = { hub, widget, descriptor, Component, actions, ErrorFrame: WidgetErrorFrame };\n return widget.datasource?.kind === 'anchor' ? <FleetFeed {...props} refuse /> : <AggregateFeed {...props} />;\n}\n\nfunction AlarmConnectedWidget({ widget, hub, descriptor, Component, actions }: ChannelProps) {\n // Frozen while the board is paused: the snapshot on screen at the pause (or the first one to land,\n // when the board opened paused) stays, and the live one is shown again on resume.\n const range = useWidgetTimeRange();\n const live = useAlarmStream(hub, alarmSubscription(descriptor, widget));\n const data = useHeld(live, range?.paused === true, (s) => !s.loading);\n\n // Show the error pane ONLY when there's nothing to display (the initial load failed).\n // Once a snapshot has loaded, a later transient poll/query error keeps the last-good\n // rows on screen \u2014 the channel re-queries every 30s and self-heals, so blanking a\n // populated table on one blip is the exact blink the console page avoids.\n if (data.error && data.alarms.length === 0 && data.total === 0) {\n return <WidgetErrorFrame widget={widget} error={data.error} />;\n }\n return <Component widget={widget} data={data} actions={actions} />;\n}\n\nfunction ControlConnectedWidget({ widget, hub, descriptor, Component, actions }: ChannelProps) {\n const data = useCommandStream(hub, commandSubscription(descriptor, widget));\n\n // Unlike the read-only widgets, a command widget is NEVER replaced by the error pane:\n // its primary control is the send form (a separate authority from reading history), so\n // a history poll error must not tear the form down. The widget surfaces the error\n // inline instead.\n return <Component widget={widget} data={data} actions={actions} />;\n}\n\nfunction LocationConnectedWidget({ widget, hub, Component, actions }: ChannelProps) {\n // The tile source lives in the widget's options, not here \u2014 it is a rendering choice, not\n // part of what the widget asks the platform for.\n const range = useWidgetTimeRange();\n const live = useLocationStream(hub, { datasource: widget.datasource });\n const data = useHeld(live, range?.paused === true, (s) => !s.loading);\n\n // Same rule as the alarm channel: show the error pane ONLY when there is nothing to\n // display. Once a snapshot has loaded, a later transient poll error keeps the last\n // known positions on screen \u2014 the channel re-polls and self-heals, and blanking a\n // populated map on one blip is worse than a marker being a few seconds stale.\n //\n // \uD83D\uDD34 A REFUSAL IS NOT AN ERROR AND MUST NOT REACH THIS BRANCH. The hub delivers it as\n // a snapshot state with `error` null, so the widget renders its own permission copy \u2014\n // if it were surfaced as an error, every ordinary member would see \"Data unavailable\"\n // where the platform is working exactly as designed.\n if (data.error && data.locations.length === 0) {\n return <WidgetErrorFrame widget={widget} error={data.error} />;\n }\n return <Component widget={widget} data={data} actions={actions} />;\n}\n\n// The placeholder for a widget this build cannot resolve. It names the stored type and says\n// WHY (not installed, no version metadata, a settings or SDK generation it cannot read); the\n// stored object is otherwise untouched (the serializer writes it back verbatim).\nfunction UnresolvedWidgetFrame({\n storedType: stored,\n reason,\n}: {\n storedType: unknown;\n reason: UnresolvedWidgetReason | undefined;\n}): ReactNode {\n const storedType = typeof stored === 'string' ? stored : '';\n const heading =\n (reason?.code ?? 'unregistered') === 'unregistered'\n ? 'This widget needs a newer viewer'\n : 'This widget cannot be shown here';\n return (\n <WidgetFrame>\n <div\n style={{\n display: 'flex',\n flexDirection: 'column',\n alignItems: 'center',\n justifyContent: 'center',\n gap: 4,\n width: '100%',\n height: '100%',\n padding: 12,\n boxSizing: 'border-box',\n textAlign: 'center',\n color: 'hsl(var(--muted-foreground))',\n }}\n >\n <div style={{ fontSize: 13, fontWeight: 600 }}>{heading}</div>\n {storedType && !reason?.message.includes(storedType) && (\n <div style={{ fontSize: 11, opacity: 0.8 }}>Widget type: {storedType}</div>\n )}\n {reason && <div style={{ fontSize: 11, opacity: 0.8, wordBreak: 'break-word' }}>{reason.message}</div>}\n </div>\n </WidgetFrame>\n );\n}\n\n// WidgetUnavailableFrame is shown when a widget's bound device no longer exists (a\n// deleted device's stable token). Distinct from the error frame: not a transient\n// failure to retry, but a settled \"this entity is gone\" \u2014 so it reads as a state, not\n// an error.\nfunction WidgetUnavailableFrame({ widget }: { widget: WidgetInstance }): ReactNode {\n return (\n <WidgetFrame title={optString(widget.options, 'title')}>\n <div\n style={{\n display: 'flex',\n flexDirection: 'column',\n alignItems: 'center',\n justifyContent: 'center',\n gap: 4,\n width: '100%',\n height: '100%',\n padding: 12,\n boxSizing: 'border-box',\n textAlign: 'center',\n color: 'hsl(var(--muted-foreground))',\n }}\n >\n <div style={{ fontSize: 20, lineHeight: 1 }} aria-hidden=\"true\">\u2298</div>\n <div style={{ fontSize: 13, fontWeight: 600 }}>Device unavailable</div>\n <div style={{ fontSize: 11, opacity: 0.8 }}>The bound device no longer exists.</div>\n </div>\n </WidgetFrame>\n );\n}\n\n// A resolution/socket error surfaces as a muted error state rather than a blank pane.\n// Shared by both the measurement and alarm channels.\nfunction WidgetErrorFrame({ widget, error }: { widget: WidgetInstance; error: unknown }): ReactNode {\n return (\n <WidgetFrame title={optString(widget.options, 'title')}>\n <div\n style={{\n display: 'flex',\n flexDirection: 'column',\n alignItems: 'center',\n justifyContent: 'center',\n gap: 4,\n width: '100%',\n height: '100%',\n padding: 12,\n boxSizing: 'border-box',\n textAlign: 'center',\n color: 'hsl(var(--muted-foreground))',\n }}\n >\n <div style={{ fontSize: 20, lineHeight: 1 }}>\u26A0</div>\n <div style={{ fontSize: 13, fontWeight: 600 }}>Data unavailable</div>\n <div style={{ fontSize: 11, opacity: 0.8, wordBreak: 'break-word' }}>{String(error)}</div>\n </div>\n </WidgetFrame>\n );\n}\n", "// Copyright The DeviceChain Authors\n// SPDX-License-Identifier: Apache-2.0\n\nimport { useState } from 'react';\n\n// useHeld returns `value` live, and while `hold` is true the value it had when the hold began:\n// the whole-snapshot channels (alarms, locations) deliver a complete state each time, so freezing\n// one is just not looking at the newer ones. Nothing is lost -- the source keeps updating, and\n// releasing the hold shows its current state at once.\n//\n// `ready` says whether a value is worth freezing on. A board that OPENS paused (a deep link) holds\n// its first value, which is the \"loading\" one; freezing on that would leave the widget loading for\n// as long as the pause lasts. So the hold takes the first value that is ready, and keeps it.\n//\n// A held snapshot that is ready while the live one is loading again means the stream was re-pointed:\n// the alarm and location streams read as loading in the very render that carries a new subscription\n// (their snapshots are tagged with it, so this holds even for a source that answers inside\n// subscribe), or when the host replaces the hub itself (new authorities), which re-subscribes the same\n// way -- and at no other time: a dropped socket, a failed query and the reconnect's re-query all\n// answer the SAME subscription, ready, and leave the hold alone. Selection stays live while a board\n// is paused. That hold belongs to the previous entity, so it is dropped and the new entity's first\n// ready snapshot is held instead. Kept, the alarm rows and map markers of the device the board was\n// paused on would stay under the new device's name. So the hold follows the live value whenever the\n// two disagree on being ready.\nexport function useHeld<T>(value: T, hold: boolean, ready: (v: T) => boolean): T {\n const [held, setHeld] = useState<{ value: T } | undefined>(undefined);\n if (!hold) {\n if (held !== undefined) setHeld(undefined);\n return value;\n }\n if (held === undefined || ready(held.value) !== ready(value)) {\n setHeld({ value });\n return value;\n }\n return held.value;\n}\n", "// Copyright The DeviceChain Authors\n// SPDX-License-Identifier: Apache-2.0\n\n// The built-in widgets as registrations. Each widget module declares its own registration\n// (descriptor + component) through the SAME public `defineWidget` a third-party package uses\n// -- there is no privileged internal path and no id-keyed component table; this module only\n// lists them, in the catalog's order.\n\nimport { createWidgetRegistry, type WidgetRegistry } from '@devicechain/widget-sdk';\n\nimport { barChartWidget, fleetTableWidget, pieChartWidget, statCardWidget } from './widgets/aggregate-lazy';\nimport { alarmCountWidget } from './widgets/alarm-count';\nimport { alarmTableWidget } from './widgets/alarm-table';\nimport { commandButtonWidget } from './widgets/command-button';\nimport { commandSliderWidget, commandToggleWidget } from './widgets/control-lazy';\nimport { entitySelectorWidget } from './widgets/entity-selector';\nimport { gaugeWidget } from './widgets/gauge';\nimport { imageWidget } from './widgets/image';\nimport { labelWidget } from './widgets/label';\nimport { latestCardWidget } from './widgets/latest-card';\nimport {\n batteryWidget,\n compassWidget,\n levelGaugeWidget,\n linearGaugeWidget,\n progressRingWidget,\n signalBarsWidget,\n statusLightWidget,\n} from './widgets/level-lazy';\nimport { mapWidget } from './widgets/map';\nimport { tableWidget } from './widgets/table';\nimport { timeSeriesChartWidget } from './widgets/time-series-chart';\n\nexport const builtinWidgetDefinitions = [\n timeSeriesChartWidget,\n latestCardWidget,\n gaugeWidget,\n tableWidget,\n labelWidget,\n imageWidget,\n alarmTableWidget,\n alarmCountWidget,\n commandButtonWidget,\n entitySelectorWidget,\n mapWidget,\n linearGaugeWidget,\n levelGaugeWidget,\n batteryWidget,\n statusLightWidget,\n signalBarsWidget,\n compassWidget,\n progressRingWidget,\n commandSliderWidget,\n commandToggleWidget,\n statCardWidget,\n barChartWidget,\n pieChartWidget,\n fleetTableWidget,\n] as const;\n\n// A fresh, sealed registry holding exactly the built-ins. Every call returns an independent\n// instance; a host composing extensions passes `[...builtinWidgetDefinitions, theirs]` to\n// createWidgetRegistry from @devicechain/widget-sdk instead.\nexport function createBuiltinWidgetRegistry(): WidgetRegistry {\n return createWidgetRegistry(builtinWidgetDefinitions);\n}\n", "// Copyright The DeviceChain Authors\n// SPDX-License-Identifier: Apache-2.0\n\n// The aggregate and categorical registrations: descriptor eager, component lazy, from a chunk of\n// their own (aggregate-widgets.ts), so a board without a stat card, bar chart or pie chart never\n// downloads them. The bar and pie charts are SVG, so no chart engine type is loaded for them.\n\nimport { defineWidget, type AggregateStreamState } from '@devicechain/widget-sdk';\n\nimport { builtinWidgetDescriptors } from '../builtin-descriptors';\nimport { lazyChunk } from './lazy-chunk';\n\nconst chunk = lazyChunk<typeof import('./aggregate-widgets')>(() => import('./aggregate-widgets'));\n\nexport const loadAggregateWidgets = chunk.load;\n\nexport const statCardWidget = defineWidget({\n descriptor: builtinWidgetDescriptors['stat-card'],\n implementation: { kind: 'trusted-react', component: chunk.component<AggregateStreamState>('StatCard') },\n});\n\nexport const barChartWidget = defineWidget({\n descriptor: builtinWidgetDescriptors['bar-chart'],\n implementation: { kind: 'trusted-react', component: chunk.component('BarChart') },\n});\n\nexport const pieChartWidget = defineWidget({\n descriptor: builtinWidgetDescriptors['pie-chart'],\n implementation: { kind: 'trusted-react', component: chunk.component('PieChart') },\n});\n\nexport const fleetTableWidget = defineWidget({\n descriptor: builtinWidgetDescriptors['fleet-table'],\n implementation: { kind: 'trusted-react', component: chunk.component('FleetTable') },\n});\n", "// Copyright The DeviceChain Authors\n// SPDX-License-Identifier: Apache-2.0\n\n// The portable descriptor of every built-in widget \u2014 pure data, React-free, importing no\n// component. The headless validators read the catalog built from these without ever\n// loading a widget; builtin-registry.ts pairs each descriptor with its component.\n//\n// \uD83D\uDD11 THE SOURCE OF TRUTH. A built-in's channel, option schema, defaults and binding policy are\n// declared here, once, as data. Nothing else in this package keeps an id-keyed table of them:\n// the by-id views the console still reads (WIDGET_CHANNEL, WIDGET_OPTIONS, ...) are derived,\n// read-only projections of these descriptors (registry.ts, options.ts).\n//\n// Every built-in carries version 1.0.0: a per-widget release number, NOT the platform\n// version. It is bumped only on a rendering change worth surfacing to an author, so a\n// platform release does not make every board look \"authored with an older widget\".\n\nimport { SEVERITY_LEVELS } from '@devicechain/widget-sdk';\nimport {\n createWidgetCatalog,\n defineWidgetDescriptor,\n type BuiltinWidgetId,\n type OptionSpec,\n type WidgetDescriptor,\n} from '@devicechain/dashboards';\n\n// ---- Shared option specs ----------------------------------------------------\n// Declared once and referenced by each widget that reads them, so the same key always\n// carries the same type and bounds. They are still listed PER WIDGET below rather than\n// merged in from a base: which widget reads which option is the fact this table exists\n// to record, and a base object would hide it.\n\nconst TITLE = {\n kind: 'string',\n labelId: 'widgetLabelTitle',\n doc: 'Heading shown in the widget frame. Blank hides the frame heading.',\n} as const satisfies OptionSpec;\n\n// gauge and latest-card fall back to the displayed measurement's name when no title is set.\nconst TITLE_OR_MEASUREMENT = {\n kind: 'string',\n labelId: 'widgetLabelTitle',\n doc: 'Heading shown in the widget frame. Defaults to the displayed measurement name.',\n} as const satisfies OptionSpec;\n\n// toFixed()'s domain is 0..100 \u2014 outside it throws a RangeError, which would take the\n// whole widget subtree down rather than degrading.\nconst PRECISION = {\n kind: 'number',\n integer: true,\n min: 0,\n max: 100,\n labelId: 'widgetLabelPrecision',\n helpId: 'widgetHintPrecision',\n doc: 'Decimal places to round displayed values to. Unset rounds to at most 3 decimals (4 significant digits under 1).',\n} as const satisfies OptionSpec;\n\n// Where a measurement crosses from one severity to the next. A threshold STARTS a band that\n// runs to the next threshold's value, so \"overheat above 105\" is one entry and \"low fuel below\n// 15\" is two (critical from 0, normal from 15). `level` is a severity NAME that the theme turns\n// into a colour; there is deliberately no colour field, so a board cannot carry a hex value\n// that ignores dark mode or the host's theme. Optional with no default: absent means no bands,\n// exactly as before the option existed, so it needs no optionsVersion bump.\nconst THRESHOLDS = {\n kind: 'list',\n maxItems: 12,\n labelId: 'widgetLabelThresholds',\n helpId: 'widgetHintThresholds',\n doc: 'Severity bands over the value. Each entry starts a band at its value that runs to the next entry; below the first, and in a normal band, the widget keeps its own colour.',\n item: {\n value: {\n kind: 'number',\n required: true,\n labelId: 'widgetLabelThresholdValue',\n doc: 'The value at which this band starts.',\n },\n level: {\n kind: 'enum',\n required: true,\n values: SEVERITY_LEVELS,\n labelId: 'widgetLabelThresholdLevel',\n valueLabelIds: {\n normal: 'widgetSeverityNormal',\n warning: 'widgetSeverityWarning',\n minor: 'widgetSeverityMinor',\n major: 'widgetSeverityMajor',\n critical: 'widgetSeverityCritical',\n },\n placeholderId: 'widgetPlaceholderThresholdLevel',\n doc: 'The severity of this band. The theme decides the colour; normal has none.',\n },\n label: {\n kind: 'string',\n labelId: 'widgetLabelThresholdLabel',\n doc: 'Text shown on the chart line for this threshold. Defaults to its value.',\n },\n },\n} as const satisfies OptionSpec;\n\nconst FLASH_ON_CHANGE = {\n kind: 'boolean',\n labelId: 'widgetFlashOnChange',\n helpId: 'widgetFlashOnChangeHint',\n doc: 'Briefly tint a value green on a rise and red on a fall when it changes.',\n} as const satisfies OptionSpec;\n\n// Read by MeasurementConnectedWidget for every measurement-channel widget, and declared on\n// each one that binds a datasource. It is NOT declared on label/image, which carry no\n// datasource at all, so there is no stream for it to size.\n//\n// It bounds the RETAINED buffer, not what is drawn: useMeasurementStream keeps `latest`\n// per measurement unconditionally and trims only `samples`. Only the chart draws\n// `samples`, so on a card, gauge or table this is a memory bound with no visible effect \u2014\n// declared because the renderer honors it, documented so nobody expects it to show.\n//\n// The trim is GLOBAL across the widget's measurements, not per measurement: `samples` is\n// one interleaved list, so a chart drawing N series retains roughly window/N of each. An\n// earlier version of this doc said \"per measurement\", and a caller sized a window off it\n// and got half the history it intended.\nconst WINDOW = {\n kind: 'number',\n integer: true,\n min: 1,\n labelId: 'widgetLabelWindow',\n helpId: 'widgetHintWindow',\n doc: 'Samples retained across ALL of the widget\\'s measurements before the oldest are dropped. Bounds memory; only the chart draws them. Default 300.',\n} as const satisfies OptionSpec;\n\n// Read by the frame, not by the widget: with it set, a widget whose newest sample is older than\n// this many seconds is greyed out under a \"stale\" badge. Unset is the DEFAULT and means age\n// only -- there is no built-in threshold, because any number would paint a sparse fleet stale.\nconst STALE_AFTER_SECONDS = {\n kind: 'number',\n integer: true,\n min: 1,\n labelId: 'widgetLabelStaleAfter',\n helpId: 'widgetHintStaleAfter',\n doc: 'Seconds after which the newest sample is called stale: the value is greyed out and badged. Unset shows the sample age only and never marks the widget stale.',\n} as const satisfies OptionSpec;\n\nconst UNIT = {\n kind: 'string',\n labelId: 'widgetLabelUnit',\n doc: 'Unit suffix shown beside the value.',\n} as const satisfies OptionSpec;\n\n// The two ends of a level widget's scale. REQUIRED, with no default on the descriptor: a tank\n// or a thermometer drawn against a range nobody chose reads a wrong value as a plausible one,\n// so a widget without both ends says so instead of drawing (see level-reading.ts). The\n// greater-than constraint on each descriptor keeps the pair ordered.\nconst SCALE_MIN = {\n kind: 'number',\n required: true,\n labelId: 'widgetLabelMin',\n helpId: 'widgetHintScaleMin',\n doc: 'Value at the empty end of the scale. Required: the widget does not guess a range.',\n} as const satisfies OptionSpec;\n\nconst SCALE_MAX = {\n kind: 'number',\n required: true,\n labelId: 'widgetLabelMax',\n helpId: 'widgetHintScaleMax',\n doc: 'Value at the full end of the scale. Required, and above min.',\n} as const satisfies OptionSpec;\n\n// The command a control sends. The three keys are the command-vocabulary triple the console's\n// command picker writes at once (the command button declares the same three), so picking a\n// command in the editor bakes its key, label and parameter schema here too.\nconst CONTROL_COMMAND_NAME = {\n kind: 'string',\n required: true,\n labelId: 'widgetCommandHeading',\n helpId: 'widgetCommandFieldHint',\n control: 'command-vocabulary',\n doc: 'Command key issued to the target device. Without it the control cannot send.',\n} as const satisfies OptionSpec;\n\nconst CONTROL_COMMAND_LABEL = {\n kind: 'string',\n labelId: 'widgetCommandHeading',\n helpId: 'widgetCommandFieldHint',\n control: 'command-vocabulary',\n doc: 'Name of the control for assistive technology. Defaults to the command key.',\n} as const satisfies OptionSpec;\n\nconst CONTROL_PARAMETER_SCHEMA = {\n kind: 'string',\n format: 'json',\n labelId: 'widgetCommandHeading',\n helpId: 'widgetCommandFieldHint',\n control: 'command-vocabulary',\n doc: \"The command's parameter descriptors, baked in as JSON at author time. Gives the control its range and its refusals.\",\n} as const satisfies OptionSpec;\n\nconst CONTROL_PARAMETER = {\n kind: 'string',\n labelId: 'widgetLabelParameter',\n helpId: 'widgetHintControlParameter',\n doc: 'Which parameter of the command this control sets. May be left blank when the command has exactly one parameter of the right type.',\n} as const satisfies OptionSpec;\n\nconst MEASUREMENT = {\n kind: 'string',\n labelId: 'widgetLabelMeasurement',\n helpId: 'widgetHintMeasurement',\n doc: 'Which measurement to display. Defaults to the first the datasource selects.',\n} as const satisfies OptionSpec;\n\nconst ALARM_STATE = {\n kind: 'enum',\n values: ['ACTIVE', 'CLEARED'],\n labelId: 'widgetLabelState',\n helpId: 'widgetStateHint',\n valueLabelIds: { ACTIVE: 'widgetAlarmStateActive', CLEARED: 'widgetAlarmStateCleared' },\n placeholderId: 'widgetPlaceholderAny',\n doc: 'Show only alarms in this state. Unset shows every state.',\n} as const satisfies OptionSpec;\n\nconst ALARM_SEVERITY = {\n kind: 'enum',\n values: ['CRITICAL', 'MAJOR', 'MINOR', 'WARNING', 'INDETERMINATE'],\n labelId: 'widgetLabelSeverity',\n helpId: 'widgetSeverityHint',\n valueLabelIds: { CRITICAL: 'widgetAlarmSeverityCritical', MAJOR: 'widgetAlarmSeverityMajor', MINOR: 'widgetAlarmSeverityMinor', WARNING: 'widgetAlarmSeverityWarning', INDETERMINATE: 'widgetAlarmSeverityIndeterminate' },\n placeholderId: 'widgetPlaceholderAny',\n doc: 'Show only alarms at this severity. Unset shows every severity.',\n} as const satisfies OptionSpec;\n\n// Stored as the STRING 'true'/'false', not a boolean \u2014 alarmSubscription() reads it with\n// optString and maps it through parseAcknowledged, so a real boolean here is read as\n// undefined and the filter silently disappears. Typed as an enum of those two strings so\n// that mistake is an error rather than a no-op.\nconst ALARM_ACKNOWLEDGED = {\n kind: 'enum',\n values: ['true', 'false'],\n labelId: 'widgetLabelAcknowledged',\n helpId: 'widgetAcknowledgedHint',\n valueLabelIds: { true: 'widgetAlarmAckAcknowledged', false: 'widgetAlarmAckUnacknowledged' },\n placeholderId: 'widgetPlaceholderAny',\n doc: \"Show only acknowledged ('true') or unacknowledged ('false') alarms. Unset shows both.\",\n} as const satisfies OptionSpec;\n\nconst SELECTION_TARGET = {\n kind: 'string',\n labelId: 'widgetLabelTargetSlot',\n helpId: 'widgetTargetSlotHint',\n control: 'slot-target',\n doc: 'Name of the slot this widget re-points when the viewer picks an entity.',\n} as const satisfies OptionSpec;\n\n\n// Each widget's `layout` is its size contract, in SQUARE cells. A cell is never smaller than the\n// grid's minCellSize (56 px by default; a narrower board reflows instead), so a span is a\n// readable size by construction, and the minimums below are sized at that smallest cell, with\n// 8 px gutters: n cells cover 64n - 8 px, so 2 is 120 px, 3 is 184 px and 4 is 248 px. On a wider\n// screen the cells stretch and every widget only grows.\n//\n// The minimums are the smallest box in which the widget's parts all fit with room to spare:\n// height is usually the binding constraint, since the frame header costs ~34-50 px before the\n// widget's own content. The defaults are what a freshly added widget takes. A maximum is\n// declared only where the content stops filling the box (a single value, a dial, a button, a\n// one-line selector); a chart, table, map or image fills a whole wall, so it has none, and a\n// label's column limit is set past any authored column count.\n\nconst VERSION = '1.0.0';\nconst ALL_SELECTORS = ['device', 'anchor', 'slot'] as const;\n// A telemetry widget that shows readings keyed by measurement name shows ONE device: bound to a group,\n// two devices reporting the same name would overwrite each other in it. Only the fleet widgets (the\n// fleet table, a bar chart with one bar per device) take a group, and the runtime refuses a group\n// that reaches any other one some other way (a host binding, a hand-edited definition).\nconst ONE_DEVICE = ['device', 'slot'] as const;\nconst NO_DATASOURCE = { mode: 'none' } as const;\n\n// The alarm filters are read by both alarm widgets from the same option keys.\nconst ALARM_FILTERS = {\n state: { option: 'state' },\n severity: { option: 'severity' },\n acknowledged: { option: 'acknowledged' },\n} as const;\n\n// The timeseries chart's window, as a SPAN. Unset, the chart follows the board's time range (which\n// a viewer can change from the header); set, it is PINNED to this span whatever the viewer picks,\n// which is what a \"last 5 minutes\" strip on a wall board wants. The bounds are the board range's:\n// a minute to a week.\nconst WINDOW_SECONDS = {\n kind: 'number',\n integer: true,\n min: 60,\n max: 604800,\n labelId: 'widgetLabelWindowSeconds',\n helpId: 'widgetHintWindowSeconds',\n doc: 'Seconds of history the widget covers, back from now. Leave unset to follow the board\u2019s time range; set it to pin this widget to a fixed span that the viewer\u2019s range picker does not change. 60 to 604800.',\n} as const satisfies OptionSpec;\n\n// The categorical charts' shared options. Both draw the latest reading of each measurement the\n// datasource names: the order is the datasource's own unless a sort is set.\nconst CATEGORY_SORT = {\n kind: 'enum',\n values: ['none', 'ascending', 'descending'],\n labelId: 'widgetLabelSort',\n valueLabelIds: { none: 'widgetSortNone', ascending: 'widgetSortAscending', descending: 'widgetSortDescending' },\n placeholderId: 'widgetPlaceholderDefault',\n doc: 'Order of the categories. Default: as the data source lists them.',\n} as const satisfies OptionSpec;\n\n// A fleet table's per-column and per-column-threshold entries NAME their measurement, because a list\n// item holds scalars only: one flat list per concern keeps each editable as a row, and a column\n// without an entry keeps the datasource's name, the board's formatting and no bands.\n// The measurement column a fleet table's list entry (a format, a band) applies to.\nconst FLEET_MEASUREMENT = {\n kind: 'string',\n required: true,\n labelId: 'widgetLabelMeasurement',\n doc: 'The measurement column this entry applies to.',\n} as const satisfies OptionSpec;\n\nconst FLEET_COLUMNS = {\n kind: 'list',\n maxItems: 24,\n labelId: 'widgetLabelColumns',\n helpId: 'widgetHintColumns',\n doc: 'Heading, unit and precision per measurement column; a column with none shows its name.',\n item: {\n measurement: FLEET_MEASUREMENT,\n label: { kind: 'string', labelId: 'widgetLabelColumnHeading', doc: 'Column heading. Defaults to the measurement name.' },\n unit: { ...UNIT },\n precision: { ...PRECISION },\n },\n} as const satisfies OptionSpec;\n\nconst FLEET_THRESHOLDS = {\n ...THRESHOLDS,\n item: {\n measurement: FLEET_MEASUREMENT,\n ...THRESHOLDS.item,\n },\n} as const satisfies OptionSpec;\n\nexport const builtinWidgetDescriptors = {\n 'timeseries-chart': defineWidgetDescriptor({\n id: 'timeseries-chart',\n version: VERSION,\n sdkApiVersion: 1,\n optionsVersion: 2,\n display: { title: 'Timeseries chart', category: 'Telemetry', titleId: 'widgetTypeTimeseriesChart', categoryId: 'widgetCategoryTelemetry' },\n channel: 'measurement',\n datasource: { mode: 'required', selectors: ONE_DEVICE },\n binding: { windowSeconds: { option: 'windowSeconds' } },\n options: {\n title: TITLE,\n unit: UNIT,\n precision: PRECISION,\n thresholds: THRESHOLDS,\n staleAfterSeconds: STALE_AFTER_SECONDS,\n windowSeconds: WINDOW_SECONDS,\n },\n defaults: { title: 'Timeseries chart' },\n interactions: {},\n freshness: true,\n layout: { defaultSpan: { cols: 6, rows: 4 }, minSpan: { cols: 4, rows: 3 } },\n }),\n\n 'latest-card': defineWidgetDescriptor({\n id: 'latest-card',\n version: VERSION,\n sdkApiVersion: 1,\n optionsVersion: 1,\n display: { title: 'Latest card', category: 'Telemetry', titleId: 'widgetTypeLatestCard', categoryId: 'widgetCategoryTelemetry' },\n channel: 'measurement',\n datasource: { mode: 'required', selectors: ONE_DEVICE },\n binding: { window: { option: 'window', min: 1 } },\n options: {\n title: TITLE_OR_MEASUREMENT,\n measurement: {\n kind: 'string',\n labelId: 'widgetLabelMeasurement',\n helpId: 'widgetHintMeasurement',\n doc: 'Which measurement to display. Defaults to the first the datasource selects.',\n },\n unit: UNIT,\n precision: PRECISION,\n thresholds: THRESHOLDS,\n flashOnChange: FLASH_ON_CHANGE,\n staleAfterSeconds: STALE_AFTER_SECONDS,\n window: WINDOW,\n },\n defaults: { title: 'Latest card' },\n interactions: {},\n freshness: true,\n layout: { defaultSpan: { cols: 3, rows: 2 }, minSpan: { cols: 3, rows: 2 }, maxSpan: { cols: 6, rows: 4 } },\n }),\n\n gauge: defineWidgetDescriptor({\n id: 'gauge',\n version: VERSION,\n sdkApiVersion: 1,\n optionsVersion: 1,\n display: { title: 'Gauge', category: 'Telemetry', titleId: 'widgetTypeGauge', categoryId: 'widgetCategoryTelemetry' },\n channel: 'measurement',\n datasource: { mode: 'required', selectors: ONE_DEVICE },\n binding: { window: { option: 'window', min: 1 } },\n options: {\n title: TITLE_OR_MEASUREMENT,\n measurement: {\n kind: 'string',\n labelId: 'widgetLabelMeasurement',\n helpId: 'widgetHintMeasurement',\n doc: 'Which measurement to display. Defaults to the first the datasource selects.',\n },\n min: {\n kind: 'number',\n labelId: 'widgetLabelMin',\n doc: 'Low end of the gauge scale. Default 0.',\n },\n max: {\n kind: 'number',\n labelId: 'widgetLabelMax',\n doc: 'High end of the gauge scale. Default 100.',\n },\n unit: UNIT,\n precision: PRECISION,\n thresholds: THRESHOLDS,\n flashOnChange: FLASH_ON_CHANGE,\n staleAfterSeconds: STALE_AFTER_SECONDS,\n window: WINDOW,\n },\n constraints: [{ kind: 'greater-than', key: 'max', than: 'min' }],\n defaults: { title: 'Gauge' },\n interactions: {},\n freshness: true,\n layout: { defaultSpan: { cols: 3, rows: 3 }, minSpan: { cols: 3, rows: 3 }, maxSpan: { cols: 6, rows: 6 } },\n }),\n\n table: defineWidgetDescriptor({\n id: 'table',\n version: VERSION,\n sdkApiVersion: 1,\n optionsVersion: 1,\n display: { title: 'Table', category: 'Telemetry', titleId: 'widgetTypeTable', categoryId: 'widgetCategoryTelemetry' },\n channel: 'measurement',\n datasource: { mode: 'required', selectors: ONE_DEVICE },\n binding: { window: { option: 'window', min: 1 } },\n options: {\n title: TITLE,\n precision: PRECISION,\n flashOnChange: FLASH_ON_CHANGE,\n staleAfterSeconds: STALE_AFTER_SECONDS,\n window: WINDOW,\n },\n defaults: { title: 'Table' },\n interactions: {},\n freshness: true,\n layout: { defaultSpan: { cols: 6, rows: 3 }, minSpan: { cols: 4, rows: 2 } },\n }),\n\n // label and image are static: the `none` channel, no datasource, no subscription and no\n // history seed.\n label: defineWidgetDescriptor({\n id: 'label',\n version: VERSION,\n sdkApiVersion: 1,\n optionsVersion: 1,\n display: { title: 'Label', category: 'Static', titleId: 'widgetTypeLabel', categoryId: 'widgetCategoryStatic' },\n channel: 'none',\n datasource: NO_DATASOURCE,\n binding: {},\n options: {\n title: TITLE,\n text: {\n kind: 'string',\n required: true,\n labelId: 'widgetLabelText',\n doc: 'The text to show. Rendered as plain text \u2014 markup is never interpreted.',\n },\n align: {\n kind: 'enum',\n values: ['left', 'center', 'right'],\n labelId: 'widgetLabelAlign',\n valueLabelIds: { left: 'widgetAlignLeft', center: 'widgetAlignCenter', right: 'widgetAlignRight' },\n placeholderId: 'widgetPlaceholderDefault',\n doc: 'Horizontal alignment of the text. Default center.',\n },\n fontSize: {\n kind: 'number',\n min: 1,\n labelId: 'widgetLabelFontSize',\n helpId: 'widgetHintFontSize',\n doc: 'Text size in pixels at the comfortable density; it scales with the board density. Default 16.',\n },\n },\n defaults: { text: 'New label' },\n interactions: {},\n layout: { defaultSpan: { cols: 3, rows: 1 }, minSpan: { cols: 1, rows: 1 }, maxSpan: { cols: 24, rows: 3 } },\n }),\n\n image: defineWidgetDescriptor({\n id: 'image',\n version: VERSION,\n sdkApiVersion: 1,\n optionsVersion: 1,\n display: { title: 'Image', category: 'Static', titleId: 'widgetTypeImage', categoryId: 'widgetCategoryStatic' },\n channel: 'none',\n datasource: NO_DATASOURCE,\n binding: {},\n options: {\n title: TITLE,\n url: {\n kind: 'string',\n required: true,\n labelId: 'widgetLabelImageUrl',\n doc: 'Source URL of the image.',\n },\n alt: {\n kind: 'string',\n labelId: 'widgetLabelAltText',\n doc: 'Alternative text describing the image for assistive technology.',\n },\n fit: {\n kind: 'enum',\n values: ['contain', 'cover', 'fill'],\n labelId: 'widgetLabelFit',\n valueLabelIds: { contain: 'widgetFitContain', cover: 'widgetFitCover', fill: 'widgetFitFill' },\n placeholderId: 'widgetPlaceholderDefault',\n doc: 'How the image fills its box. Default contain.',\n },\n },\n defaults: { title: 'Image' },\n interactions: {},\n layout: { defaultSpan: { cols: 3, rows: 2 }, minSpan: { cols: 1, rows: 1 } },\n }),\n\n 'alarm-table': defineWidgetDescriptor({\n id: 'alarm-table',\n version: VERSION,\n sdkApiVersion: 1,\n optionsVersion: 1,\n display: { title: 'Alarm table', category: 'Alarms', titleId: 'widgetTypeAlarmTable', categoryId: 'widgetCategoryAlarms' },\n channel: 'alarm',\n datasource: { mode: 'optional', selectors: ALL_SELECTORS },\n binding: { pageSize: { option: 'maxRows', default: 50, min: 1 }, ...ALARM_FILTERS },\n options: {\n title: TITLE,\n state: ALARM_STATE,\n severity: ALARM_SEVERITY,\n acknowledged: ALARM_ACKNOWLEDGED,\n maxRows: {\n kind: 'number',\n integer: true,\n min: 1,\n labelId: 'widgetLabelMaxRows',\n helpId: 'widgetMaxRowsAlarmHint',\n doc: 'Alarms loaded into the table. Default 50.',\n },\n precision: PRECISION,\n flashOnChange: FLASH_ON_CHANGE,\n selectionTarget: SELECTION_TARGET,\n },\n defaults: { title: 'Alarm table', state: 'ACTIVE' },\n interactions: { alarmActions: true, selection: true },\n layout: { defaultSpan: { cols: 6, rows: 4 }, minSpan: { cols: 4, rows: 2 } },\n }),\n\n // The count shows the SERVER total and reads a page only to sample the worst loaded\n // severity, so its page size is a constant rather than an authorable option.\n 'alarm-count': defineWidgetDescriptor({\n id: 'alarm-count',\n version: VERSION,\n sdkApiVersion: 1,\n optionsVersion: 1,\n display: { title: 'Alarm count', category: 'Alarms', titleId: 'widgetTypeAlarmCount', categoryId: 'widgetCategoryAlarms' },\n channel: 'alarm',\n datasource: { mode: 'optional', selectors: ALL_SELECTORS },\n binding: { pageSize: { const: 50 }, ...ALARM_FILTERS },\n // No maxRows: alarmSubscription() forces the default page size for a count, because the\n // number it shows is the SERVER total and the page is read only to sample the worst\n // loaded severity. An authored maxRows here would be read by nothing.\n options: {\n title: TITLE,\n state: ALARM_STATE,\n severity: ALARM_SEVERITY,\n acknowledged: ALARM_ACKNOWLEDGED,\n },\n defaults: { title: 'Alarm count', state: 'ACTIVE' },\n interactions: {},\n layout: { defaultSpan: { cols: 3, rows: 2 }, minSpan: { cols: 2, rows: 2 }, maxSpan: { cols: 6, rows: 4 } },\n }),\n\n 'command-button': defineWidgetDescriptor({\n id: 'command-button',\n version: VERSION,\n sdkApiVersion: 1,\n optionsVersion: 1,\n display: { title: 'Command button', category: 'Control', titleId: 'widgetTypeCommandButton', categoryId: 'widgetCategoryControl' },\n channel: 'control',\n datasource: { mode: 'required', selectors: ONE_DEVICE },\n binding: { pageSize: { option: 'maxRows', default: 20, min: 1 } },\n options: {\n title: TITLE,\n commandName: {\n kind: 'string',\n required: true,\n labelId: 'widgetCommandHeading',\n helpId: 'widgetCommandFieldHint',\n control: 'command-vocabulary',\n doc: 'Command key issued to the target device. Without it the widget cannot send.',\n },\n commandLabel: {\n kind: 'string',\n labelId: 'widgetCommandHeading',\n helpId: 'widgetCommandFieldHint',\n control: 'command-vocabulary',\n doc: 'Text on the send button. Defaults to the command key.',\n },\n parameterSchema: {\n kind: 'string',\n format: 'json',\n labelId: 'widgetCommandHeading',\n helpId: 'widgetCommandFieldHint',\n control: 'command-vocabulary',\n doc: \"The command's parameter descriptors, baked in as JSON at author time. Drives the typed form.\",\n },\n maxRows: {\n kind: 'number',\n integer: true,\n min: 1,\n labelId: 'widgetLabelMaxRows',\n helpId: 'widgetMaxRowsCommandHint',\n doc: 'Recent commands shown in the history. Default 20.',\n },\n },\n defaults: { title: 'Command button' },\n interactions: { commandSend: true },\n layout: { defaultSpan: { cols: 3, rows: 3 }, minSpan: { cols: 3, rows: 2 }, maxSpan: { cols: 6, rows: 6 } },\n }),\n\n 'entity-selector': defineWidgetDescriptor({\n id: 'entity-selector',\n version: VERSION,\n sdkApiVersion: 1,\n optionsVersion: 1,\n display: { title: 'Entity selector', category: 'Navigation', titleId: 'widgetTypeEntitySelector', categoryId: 'widgetCategoryNavigation' },\n channel: 'selection',\n datasource: NO_DATASOURCE,\n binding: {},\n options: {\n title: TITLE,\n selectionTarget: { ...SELECTION_TARGET, required: true },\n },\n defaults: { title: 'Entity selector' },\n interactions: { selection: true, candidates: true },\n // A select control is one line high, so its rows are pinned; it widens to fit long names.\n layout: { defaultSpan: { cols: 3, rows: 1 }, minSpan: { cols: 3, rows: 1 }, maxSpan: { cols: 12, rows: 1 }, resize: 'horizontal' },\n }),\n\n map: defineWidgetDescriptor({\n id: 'map',\n version: VERSION,\n sdkApiVersion: 1,\n optionsVersion: 1,\n display: { title: 'Map', category: 'Location', titleId: 'widgetTypeMap', categoryId: 'widgetCategoryLocation' },\n channel: 'location',\n datasource: { mode: 'required', selectors: ALL_SELECTORS },\n binding: {},\n // \uD83D\uDD34 tileUrl is NOT `required`, and that is the decision rather than an oversight.\n // `required` means \"absent leaves the widget with nothing to show\", and a map without\n // a basemap still shows every position it was asked to \u2014 on a plain panel, saying why\n // there is no map behind them. Marking it required would report a correctly-rendering\n // widget as broken on every board that names no provider of its own \u2014 which is most\n // of them, because the usual and recommended answer is to inherit the tenant's\n // basemap rather than to configure tiles per board.\n options: {\n title: TITLE,\n tileUrl: {\n kind: 'string',\n labelId: 'widgetLabelTileUrl',\n helpId: 'widgetTileUrlHint',\n control: 'basemap',\n doc: \"Raster tile URL template, e.g. https://tiles.example.com/{z}/{x}/{y}.png. Leave empty to inherit the tenant's basemap; setting one overrides it for this board only.\",\n },\n attribution: {\n kind: 'string',\n labelId: 'widgetLabelAttribution',\n helpId: 'widgetAttributionHint',\n control: 'basemap',\n doc: 'Credit line the tile source requires, shown on the map. Set whatever the provider you chose asks for.',\n },\n },\n defaults: { title: 'Map' },\n interactions: {},\n layout: { defaultSpan: { cols: 6, rows: 4 }, minSpan: { cols: 4, rows: 3 } },\n }),\n\n // ---- Levels and indicators ------------------------------------------------\n // DOM/SVG single-value widgets on the measurement channel. A threshold band colours the fill\n // or lamp; `normal` keeps the widget's neutral accent.\n\n 'linear-gauge': defineWidgetDescriptor({\n id: 'linear-gauge',\n version: VERSION,\n sdkApiVersion: 1,\n optionsVersion: 1,\n display: { title: 'Linear gauge', category: 'Telemetry', titleId: 'widgetTypeLinearGauge', categoryId: 'widgetCategoryTelemetry' },\n channel: 'measurement',\n datasource: { mode: 'required', selectors: ONE_DEVICE },\n binding: { window: { option: 'window', min: 1 } },\n options: {\n title: TITLE_OR_MEASUREMENT,\n measurement: MEASUREMENT,\n min: SCALE_MIN,\n max: SCALE_MAX,\n style: {\n kind: 'enum',\n values: ['bar', 'thermometer'],\n labelId: 'widgetLabelLinearStyle',\n valueLabelIds: { bar: 'widgetLinearStyleBar', thermometer: 'widgetLinearStyleThermometer' },\n placeholderId: 'widgetPlaceholderDefault',\n doc: 'A plain bar (default) or a thermometer: a vertical tube with a bulb. A thermometer is always vertical.',\n },\n orientation: {\n kind: 'enum',\n values: ['horizontal', 'vertical'],\n labelId: 'widgetLabelOrientation',\n valueLabelIds: { horizontal: 'widgetOrientationHorizontal', vertical: 'widgetOrientationVertical' },\n placeholderId: 'widgetPlaceholderDefault',\n doc: 'Direction of a bar: horizontal (default) or vertical. Ignored by a thermometer.',\n },\n unit: UNIT,\n precision: PRECISION,\n thresholds: THRESHOLDS,\n staleAfterSeconds: STALE_AFTER_SECONDS,\n window: WINDOW,\n },\n constraints: [{ kind: 'greater-than', key: 'max', than: 'min' }],\n defaults: { title: 'Linear gauge' },\n interactions: {},\n freshness: true,\n layout: { defaultSpan: { cols: 4, rows: 3 }, minSpan: { cols: 3, rows: 3 }, maxSpan: { cols: 8, rows: 8 } },\n }),\n\n 'level-gauge': defineWidgetDescriptor({\n id: 'level-gauge',\n version: VERSION,\n sdkApiVersion: 1,\n optionsVersion: 1,\n display: { title: 'Level gauge', category: 'Telemetry', titleId: 'widgetTypeLevelGauge', categoryId: 'widgetCategoryTelemetry' },\n channel: 'measurement',\n datasource: { mode: 'required', selectors: ONE_DEVICE },\n binding: { window: { option: 'window', min: 1 } },\n options: {\n title: TITLE_OR_MEASUREMENT,\n measurement: MEASUREMENT,\n min: SCALE_MIN,\n max: SCALE_MAX,\n readout: {\n kind: 'enum',\n values: ['value', 'percent'],\n labelId: 'widgetLabelReadout',\n valueLabelIds: { value: 'widgetReadoutValue', percent: 'widgetReadoutPercent' },\n placeholderId: 'widgetPlaceholderDefault',\n doc: 'What the readout shows: the value with its unit (default) or the percent of the scale.',\n },\n unit: UNIT,\n precision: PRECISION,\n thresholds: THRESHOLDS,\n staleAfterSeconds: STALE_AFTER_SECONDS,\n window: WINDOW,\n },\n constraints: [{ kind: 'greater-than', key: 'max', than: 'min' }],\n defaults: { title: 'Level gauge' },\n interactions: {},\n freshness: true,\n layout: { defaultSpan: { cols: 3, rows: 4 }, minSpan: { cols: 2, rows: 3 }, maxSpan: { cols: 6, rows: 8 } },\n }),\n\n battery: defineWidgetDescriptor({\n id: 'battery',\n version: VERSION,\n sdkApiVersion: 1,\n optionsVersion: 1,\n display: { title: 'Battery', category: 'Telemetry', titleId: 'widgetTypeBattery', categoryId: 'widgetCategoryTelemetry' },\n channel: 'measurement',\n datasource: { mode: 'required', selectors: ONE_DEVICE },\n binding: { window: { option: 'window', min: 1 } },\n options: {\n title: TITLE_OR_MEASUREMENT,\n measurement: MEASUREMENT,\n min: {\n kind: 'number',\n labelId: 'widgetLabelMin',\n helpId: 'widgetHintBatteryRange',\n doc: 'Value of an empty battery. Default 0 (the scale is percent unless you set min and max).',\n },\n max: {\n kind: 'number',\n labelId: 'widgetLabelMax',\n helpId: 'widgetHintBatteryRange',\n doc: 'Value of a full battery. Default 100 (the scale is percent unless you set min and max).',\n },\n unit: UNIT,\n precision: PRECISION,\n thresholds: THRESHOLDS,\n staleAfterSeconds: STALE_AFTER_SECONDS,\n window: WINDOW,\n },\n constraints: [{ kind: 'greater-than', key: 'max', than: 'min' }],\n defaults: { title: 'Battery' },\n interactions: {},\n freshness: true,\n layout: { defaultSpan: { cols: 3, rows: 2 }, minSpan: { cols: 2, rows: 2 }, maxSpan: { cols: 6, rows: 4 } },\n }),\n\n 'status-light': defineWidgetDescriptor({\n id: 'status-light',\n version: VERSION,\n sdkApiVersion: 1,\n optionsVersion: 1,\n display: { title: 'Status light', category: 'Telemetry', titleId: 'widgetTypeStatusLight', categoryId: 'widgetCategoryTelemetry' },\n channel: 'measurement',\n datasource: { mode: 'required', selectors: ONE_DEVICE },\n binding: { window: { option: 'window', min: 1 } },\n options: {\n title: TITLE_OR_MEASUREMENT,\n measurement: MEASUREMENT,\n onAt: {\n kind: 'number',\n labelId: 'widgetLabelOnAt',\n helpId: 'widgetHintOnAt',\n doc: 'For an on/off signal: the lamp is lit at or above this value and dark below it. Unset keeps the lamp lit while a value is present, coloured by its threshold band.',\n },\n unit: UNIT,\n precision: PRECISION,\n thresholds: THRESHOLDS,\n staleAfterSeconds: STALE_AFTER_SECONDS,\n window: WINDOW,\n },\n defaults: { title: 'Status light' },\n interactions: {},\n freshness: true,\n layout: { defaultSpan: { cols: 2, rows: 2 }, minSpan: { cols: 2, rows: 2 }, maxSpan: { cols: 4, rows: 4 } },\n }),\n\n 'signal-bars': defineWidgetDescriptor({\n id: 'signal-bars',\n version: VERSION,\n sdkApiVersion: 1,\n optionsVersion: 1,\n display: { title: 'Signal bars', category: 'Telemetry', titleId: 'widgetTypeSignalBars', categoryId: 'widgetCategoryTelemetry' },\n channel: 'measurement',\n datasource: { mode: 'required', selectors: ONE_DEVICE },\n binding: { window: { option: 'window', min: 1 } },\n options: {\n title: TITLE_OR_MEASUREMENT,\n measurement: MEASUREMENT,\n unit: UNIT,\n precision: PRECISION,\n // One bar per threshold: the entries ARE the steps, so they are required.\n thresholds: {\n ...THRESHOLDS,\n maxItems: 8,\n required: true,\n helpId: 'widgetHintSignalThresholds',\n doc: 'The steps of the signal, lowest first: one bar per entry, lit once the value reaches it and coloured by its level. At least two, at most eight.',\n },\n staleAfterSeconds: STALE_AFTER_SECONDS,\n window: WINDOW,\n },\n defaults: { title: 'Signal bars' },\n interactions: {},\n freshness: true,\n layout: { defaultSpan: { cols: 2, rows: 2 }, minSpan: { cols: 2, rows: 2 }, maxSpan: { cols: 4, rows: 4 } },\n }),\n\n // ---- Radial family ----------------------------------------------------------\n // A heading on a full turn, and a ring filled between a configured min and max. The compass\n // draws on the registered gauge series; the ring is SVG. Both put their number in DOM text.\n\n compass: defineWidgetDescriptor({\n id: 'compass',\n version: VERSION,\n sdkApiVersion: 1,\n optionsVersion: 1,\n display: { title: 'Compass', category: 'Telemetry', titleId: 'widgetTypeCompass', categoryId: 'widgetCategoryTelemetry' },\n channel: 'measurement',\n datasource: { mode: 'required', selectors: ONE_DEVICE },\n binding: { window: { option: 'window', min: 1 } },\n options: {\n title: TITLE_OR_MEASUREMENT,\n measurement: MEASUREMENT,\n precision: {\n ...PRECISION,\n doc: 'Decimal places of the heading. Default 0 (whole degrees). The heading is rounded first, then folded onto 0 to 360, so it never reads 360.',\n },\n thresholds: {\n ...THRESHOLDS,\n doc: 'Severity bands over the heading in degrees (0 to 360, after folding). Each entry starts a band at its value that runs to the next entry; below the first, and in a normal band, the needle keeps its own colour.',\n },\n staleAfterSeconds: STALE_AFTER_SECONDS,\n window: WINDOW,\n },\n defaults: { title: 'Compass' },\n interactions: {},\n freshness: true,\n layout: { defaultSpan: { cols: 4, rows: 4 }, minSpan: { cols: 3, rows: 3 }, maxSpan: { cols: 8, rows: 8 } },\n }),\n\n 'progress-ring': defineWidgetDescriptor({\n id: 'progress-ring',\n version: VERSION,\n sdkApiVersion: 1,\n optionsVersion: 1,\n display: { title: 'Progress ring', category: 'Telemetry', titleId: 'widgetTypeProgressRing', categoryId: 'widgetCategoryTelemetry' },\n channel: 'measurement',\n datasource: { mode: 'required', selectors: ONE_DEVICE },\n binding: { window: { option: 'window', min: 1 } },\n options: {\n title: TITLE_OR_MEASUREMENT,\n measurement: MEASUREMENT,\n min: SCALE_MIN,\n max: SCALE_MAX,\n readout: {\n kind: 'enum',\n values: ['percent', 'value'],\n labelId: 'widgetLabelReadout',\n valueLabelIds: { percent: 'widgetReadoutPercent', value: 'widgetReadoutValue' },\n placeholderId: 'widgetPlaceholderDefault',\n doc: 'What the middle of the ring shows: the percent of the scale (default) or the value with its unit.',\n },\n unit: UNIT,\n precision: PRECISION,\n thresholds: THRESHOLDS,\n staleAfterSeconds: STALE_AFTER_SECONDS,\n window: WINDOW,\n },\n constraints: [{ kind: 'greater-than', key: 'max', than: 'min' }],\n defaults: { title: 'Progress ring' },\n interactions: {},\n freshness: true,\n layout: { defaultSpan: { cols: 3, rows: 3 }, minSpan: { cols: 2, rows: 2 }, maxSpan: { cols: 6, rows: 6 } },\n }),\n\n 'command-slider': defineWidgetDescriptor({\n id: 'command-slider',\n version: VERSION,\n sdkApiVersion: 1,\n optionsVersion: 1,\n display: { title: 'Command slider', category: 'Control', titleId: 'widgetTypeCommandSlider', categoryId: 'widgetCategoryControl' },\n channel: 'control',\n datasource: { mode: 'required', selectors: ONE_DEVICE },\n // The control reads its last-sent value off this history, so it asks for a long one.\n binding: { pageSize: { const: 50 } },\n options: {\n title: TITLE,\n commandName: CONTROL_COMMAND_NAME,\n commandLabel: CONTROL_COMMAND_LABEL,\n parameterSchema: CONTROL_PARAMETER_SCHEMA,\n parameter: CONTROL_PARAMETER,\n min: {\n kind: 'number',\n labelId: 'widgetLabelMin',\n helpId: 'widgetHintSliderRange',\n doc: \"Lowest value, used only when the command's parameter declares no minimum.\",\n },\n max: {\n kind: 'number',\n labelId: 'widgetLabelMax',\n helpId: 'widgetHintSliderRange',\n doc: \"Highest value, used only when the command's parameter declares no maximum.\",\n },\n step: {\n kind: 'number',\n min: 0,\n labelId: 'widgetLabelStep',\n helpId: 'widgetHintSliderStep',\n doc: 'Distance between values. Defaults to 1 for a whole-number parameter, else a hundredth of the range.',\n },\n },\n constraints: [{ kind: 'greater-than', key: 'max', than: 'min' }],\n defaults: { title: 'Command slider' },\n interactions: { commandSend: true },\n layout: { defaultSpan: { cols: 4, rows: 2 }, minSpan: { cols: 3, rows: 2 }, maxSpan: { cols: 8, rows: 3 } },\n }),\n\n 'command-toggle': defineWidgetDescriptor({\n id: 'command-toggle',\n version: VERSION,\n sdkApiVersion: 1,\n optionsVersion: 1,\n display: { title: 'Command toggle', category: 'Control', titleId: 'widgetTypeCommandToggle', categoryId: 'widgetCategoryControl' },\n channel: 'control',\n datasource: { mode: 'required', selectors: ONE_DEVICE },\n binding: { pageSize: { const: 50 } },\n options: {\n title: TITLE,\n commandName: CONTROL_COMMAND_NAME,\n commandLabel: CONTROL_COMMAND_LABEL,\n parameterSchema: CONTROL_PARAMETER_SCHEMA,\n parameter: CONTROL_PARAMETER,\n },\n defaults: { title: 'Command toggle' },\n interactions: { commandSend: true },\n layout: { defaultSpan: { cols: 3, rows: 2 }, minSpan: { cols: 2, rows: 2 }, maxSpan: { cols: 6, rows: 3 } },\n }),\n 'stat-card': defineWidgetDescriptor({\n id: 'stat-card',\n version: VERSION,\n sdkApiVersion: 1,\n optionsVersion: 1,\n display: { title: 'Stat card', category: 'Telemetry', titleId: 'widgetTypeStatCard', categoryId: 'widgetCategoryTelemetry' },\n channel: 'aggregate',\n datasource: { mode: 'required', selectors: ONE_DEVICE },\n binding: { windowSeconds: { option: 'windowSeconds' } },\n options: {\n title: TITLE_OR_MEASUREMENT,\n measurement: MEASUREMENT,\n stat: {\n kind: 'enum',\n values: ['avg', 'min', 'max', 'sum', 'count', 'last'],\n labelId: 'widgetLabelStat',\n helpId: 'widgetHintStat',\n valueLabelIds: {\n avg: 'widgetStatAvg',\n min: 'widgetStatMin',\n max: 'widgetStatMax',\n sum: 'widgetStatSum',\n count: 'widgetStatCount',\n last: 'widgetStatLast',\n },\n placeholderId: 'widgetPlaceholderDefault',\n doc: 'Which figure to show. Default average.',\n },\n unit: UNIT,\n precision: PRECISION,\n thresholds: THRESHOLDS,\n windowSeconds: WINDOW_SECONDS,\n },\n defaults: { title: 'Stat card' },\n interactions: {},\n layout: { defaultSpan: { cols: 3, rows: 3 }, minSpan: { cols: 3, rows: 2 }, maxSpan: { cols: 6, rows: 4 } },\n }),\n\n 'bar-chart': defineWidgetDescriptor({\n id: 'bar-chart',\n version: VERSION,\n sdkApiVersion: 1,\n optionsVersion: 1,\n display: { title: 'Bar chart', category: 'Telemetry', titleId: 'widgetTypeBarChart', categoryId: 'widgetCategoryTelemetry' },\n channel: 'measurement',\n datasource: { mode: 'required', selectors: ALL_SELECTORS },\n // One bar per measurement of a device, or (groupBy device) one bar per member of an anchor.\n binding: { members: { option: 'groupBy', equals: 'device' } },\n options: {\n title: TITLE,\n groupBy: {\n kind: 'enum',\n values: ['measurement', 'device'],\n labelId: 'widgetLabelGroupBy',\n helpId: 'widgetHintGroupBy',\n valueLabelIds: { measurement: 'widgetGroupByMeasurement', device: 'widgetGroupByDevice' },\n placeholderId: 'widgetPlaceholderDefault',\n doc: 'One bar per measurement (the default), or per device of the group for the measurement set below.',\n },\n measurement: MEASUREMENT,\n unit: UNIT,\n precision: PRECISION,\n sort: CATEGORY_SORT,\n },\n defaults: { title: 'Bar chart' },\n interactions: {},\n layout: { defaultSpan: { cols: 6, rows: 4 }, minSpan: { cols: 4, rows: 3 } },\n }),\n\n 'pie-chart': defineWidgetDescriptor({\n id: 'pie-chart',\n version: VERSION,\n sdkApiVersion: 1,\n optionsVersion: 1,\n display: { title: 'Pie chart', category: 'Telemetry', titleId: 'widgetTypePieChart', categoryId: 'widgetCategoryTelemetry' },\n channel: 'measurement',\n datasource: { mode: 'required', selectors: ONE_DEVICE },\n binding: {},\n options: { title: TITLE, unit: UNIT, precision: PRECISION, sort: CATEGORY_SORT },\n defaults: { title: 'Pie chart' },\n interactions: {},\n layout: { defaultSpan: { cols: 4, rows: 4 }, minSpan: { cols: 3, rows: 3 }, maxSpan: { cols: 8, rows: 8 } },\n }),\n\n // A new widget rather than a mode of `table`: that one is one device's measurements as rows, on a\n // channel that keys its values by name; this one is a fleet, a row per member and a column per\n // measurement, and reads its data by device.\n 'fleet-table': defineWidgetDescriptor({\n id: 'fleet-table',\n version: VERSION,\n sdkApiVersion: 1,\n optionsVersion: 1,\n display: { title: 'Fleet table', category: 'Telemetry', titleId: 'widgetTypeFleetTable', categoryId: 'widgetCategoryTelemetry' },\n channel: 'measurement',\n datasource: { mode: 'required', selectors: ALL_SELECTORS },\n binding: { windowSeconds: { option: 'windowSeconds' }, members: { const: true } },\n options: {\n title: TITLE,\n columns: FLEET_COLUMNS,\n thresholds: FLEET_THRESHOLDS,\n staleAfterSeconds: STALE_AFTER_SECONDS,\n ageLagSeconds: {\n kind: 'number',\n integer: true,\n min: 1,\n labelId: 'widgetLabelAgeLag',\n helpId: 'widgetHintAgeLag',\n doc: \"Show a reading's age under it only when the reading is at least this many seconds older than the newest reading in the table (or stale). Unset shows every reading's age.\",\n },\n sortBy: {\n kind: 'string',\n labelId: 'widgetLabelSortBy',\n helpId: 'widgetHintSortBy',\n doc: 'The measurement the table is ordered by. Blank orders by device name.',\n },\n sortDescending: { kind: 'boolean', labelId: 'widgetLabelSortDescending', doc: 'Largest first.' },\n pageSize: {\n kind: 'number',\n integer: true,\n min: 5,\n max: 100,\n labelId: 'widgetLabelPageSize',\n doc: 'Devices per page. Default 20.',\n },\n selectionTarget: SELECTION_TARGET,\n windowSeconds: WINDOW_SECONDS,\n },\n defaults: { title: 'Fleet table' },\n // The frame shows the age of the newest reading in the fleet; each cell shows its own.\n freshness: true,\n interactions: { selection: true },\n layout: { defaultSpan: { cols: 12, rows: 6 }, minSpan: { cols: 6, rows: 3 } },\n }),\n} as const satisfies Record<BuiltinWidgetId, WidgetDescriptor>;\n\n// The catalog the headless validators read. Constructed at module load, so a built-in that\n// fails its own validation fails every consumer of this package on import \u2014 loudly, and not\n// only in a test.\nexport const builtinWidgetCatalog = createWidgetCatalog(Object.values(builtinWidgetDescriptors));\n", "// Copyright The DeviceChain Authors\n// SPDX-License-Identifier: Apache-2.0\n\n// The lazy registration shared by the widget families that ship as their own chunk. A family's\n// descriptors stay eager (the catalog, the editor and the validators read them), and each\n// registration's component loads the family's chunk on first mount, together, from one fetch.\n//\n// Until the chunk arrives the widget renders nothing inside its box. A chunk that fails to load is\n// THROWN, so the widget's error boundary shows the failure: an empty box that looks like a widget\n// with nothing to say is the outcome this must never produce. The failure is NOT remembered: the\n// next mount (the boundary's \"Reset widget\") fetches the chunk again, so a blip on a wall display's\n// network is not a widget that stays broken until the page is reloaded. React.lazy remembers it,\n// which is why the feeds load through here too.\n//\n// The `import()` itself stays in each family's own module, as a literal: that is what makes the\n// bundler split the chunk, and it is what the dist-shape guard looks for.\n\nimport { useEffect, useState, type ComponentType } from 'react';\nimport type { MeasurementStreamState, WidgetProps } from '@devicechain/widget-sdk';\n\nexport function lazyChunk<M extends Record<string, unknown>, D = MeasurementStreamState>(importer: () => Promise<M>) {\n let loaded: M | undefined;\n let loading: Promise<M> | undefined;\n\n // Memoized: every widget of the family on a board shares one fetch. Once it has resolved,\n // `loaded` lets a later mount render synchronously, with no empty first frame. A rejection is\n // forgotten, so the next load fetches again; only a mount asks, so a chunk that keeps failing\n // is never retried in a loop.\n const load = (): Promise<M> =>\n (loading ??= importer().then(\n (m) => (loaded = m),\n (err: unknown) => {\n loading = undefined;\n throw err;\n },\n ));\n\n // `P` is the data a given component takes when it differs from the family's default `D` (a chunk\n // that holds widgets of two channels). `Props` is for a component that is not a widget at all.\n function component<P = D, Props extends object = WidgetProps<P>>(name: keyof M & string) {\n function LazyChunkWidget(props: Props) {\n const [mod, setMod] = useState(loaded);\n const [error, setError] = useState<unknown>();\n useEffect(() => {\n if (!mod) load().then(setMod, setError);\n }, [mod]);\n if (error !== undefined) throw error;\n if (!mod) return null;\n const Component = mod[name] as ComponentType<Props>;\n return <Component {...props} />;\n }\n LazyChunkWidget.displayName = `Lazy(${name})`;\n return LazyChunkWidget;\n }\n\n return { load, component };\n}\n", "// Copyright The DeviceChain Authors\n// SPDX-License-Identifier: Apache-2.0\n\n// alarm-count \u2014 a KPI card of how many alarms match the widget's scope+filter\n// (ADR-041). The number is the server total (past the loaded page); its color is the\n// most severe among the CURRENTLY-LOADED alarms (the newest page), and the worst\n// severity is also spelled out as text/aria so the signal never reads on hue alone (a\n// color-blind or screen-reader viewer still gets it). At zero it stays muted.\n\nimport {\n type AlarmStreamState,\n css,\n defineWidget,\n fitValueFont,\n fitValueFontCss,\n FIT_MIN_FONT_PX,\n fontVar,\n optString,\n spaceVar,\n useSeverityColors,\n useStickyChars,\n useWidgetScale,\n WidgetFrame,\n type WidgetProps,\n} from '@devicechain/widget-sdk';\n\nimport { builtinWidgetDescriptors } from '../builtin-descriptors';\nimport { highestSeverity, severityColor, severityLabel } from './severity';\n\n// The caption under the count (11 px text plus its 6 px margin). It always shows -- it names\n// the worst severity -- so the count is fitted to what is left rather than pushing it out.\nexport const ALARM_COUNT_CAPTION_ROOM_PX = 20;\n\n// Rendered INSIDE the frame: the widget scale is the frame's content column, which is only in\n// context below the frame.\nfunction AlarmCountBody({ data }: { data: AlarmStreamState }) {\n const { size, scale } = useWidgetScale();\n const severity = useSeverityColors();\n const { total, alarms, loading } = data;\n\n const worst = highestSeverity(alarms.map((a) => a.severity));\n // At zero (or before any alarm is loaded) stay neutral; otherwise take the worst\n // loaded severity's color as the alert accent.\n const alerting = total > 0 && worst != null;\n const color = alerting ? severityColor(severity, worst) : css('muted-foreground');\n\n const display = loading && total === 0 ? '\u2014' : String(total);\n const chars = useStickyChars(display.length);\n const floor = Math.round(FIT_MIN_FONT_PX * scale);\n const measured = size.width > 0 && size.height > 0;\n const valueFont = measured\n ? fitValueFont(\n { width: size.width, height: Math.max(1, size.height - ALARM_COUNT_CAPTION_ROOM_PX * scale) },\n chars,\n { floor },\n )\n : // First frame: the same curve in cq units, resolved by the browser against the frame's\n // column (it does not take the caption's room off; the first measure does).\n fitValueFontCss(chars, { floor });\n const unit = total === 1 ? 'alarm' : 'alarms';\n const ariaLabel = alerting ? `${total} ${unit}, worst severity ${severityLabel(worst)}` : `${total} ${unit}`;\n\n return (\n <div\n style={{\n display: 'flex',\n flexDirection: 'column',\n justifyContent: 'safe center',\n alignItems: 'center',\n height: '100%',\n boxSizing: 'border-box',\n overflow: 'hidden',\n textAlign: 'center',\n }}\n >\n <div\n aria-label={ariaLabel}\n style={{\n fontSize: valueFont,\n fontWeight: 700,\n lineHeight: 1,\n whiteSpace: 'nowrap',\n fontVariantNumeric: 'tabular-nums',\n color,\n }}\n >\n {display}\n </div>\n <div\n style={{\n fontSize: fontVar('xs'),\n color: css('muted-foreground'),\n marginTop: spaceVar(1),\n textTransform: 'uppercase',\n letterSpacing: '0.05em',\n }}\n >\n <span>{unit}</span>\n {alerting ? <span>{` \u00B7 worst ${severityLabel(worst)}`}</span> : null}\n </div>\n </div>\n );\n}\n\nexport function AlarmCount({ widget, data }: WidgetProps<AlarmStreamState>) {\n return (\n <WidgetFrame title={optString(widget.options, 'title')}>\n <AlarmCountBody data={data} />\n </WidgetFrame>\n );\n}\n\n// The registration: this widget's portable descriptor paired with its component, declared\n// through the same public `defineWidget` a third-party package uses.\nexport const alarmCountWidget = defineWidget({\n descriptor: builtinWidgetDescriptors['alarm-count'],\n implementation: { kind: 'trusted-react', component: AlarmCount },\n});\n", "// Copyright The DeviceChain Authors\n// SPDX-License-Identifier: Apache-2.0\n\n// Alarm-severity presentation shared by the alarm widgets (ADR-041 vocabulary:\n// CRITICAL | MAJOR | MINOR | WARNING | INDETERMINATE). Severity is SEMANTIC color --\n// deliberately fixed, not derived from the dashboard accent -- so a critical alarm reads the\n// same red on every tenant's theme.\n//\n// \uD83D\uDD11 ONE PALETTE. The hues are the SDK's severity tokens (`--sev-*`, widget-sdk/severity.ts):\n// the same colour a threshold band uses is the colour an alarm row uses, in light and dark, and\n// a host that re-themes a token re-themes both. This file keeps only the VOCABULARY mapping\n// (the backend's UPPER_CASE severities onto the token levels). INDETERMINATE -- and anything\n// unrecognized -- has no alarm hue: it renders in the muted foreground, the same neutral an\n// absent alarm gets.\n\nimport { css, type AlarmLevel } from '@devicechain/widget-sdk';\n\nconst LEVEL_OF: Record<string, AlarmLevel> = {\n CRITICAL: 'critical',\n MAJOR: 'major',\n MINOR: 'minor',\n WARNING: 'warning',\n};\n\nconst SEVERITY_ORDER: Record<string, number> = {\n CRITICAL: 0,\n MAJOR: 1,\n MINOR: 2,\n WARNING: 3,\n INDETERMINATE: 4,\n};\n\n// severityColor maps a severity to its badge/stripe color. `colors` is useSeverityColors() --\n// the concrete token colours in scope -- so the result follows the host's theme and dark mode.\n// An INDETERMINATE or unrecognized severity (a hand-edited or future one) takes the muted\n// foreground rather than a hue it has not earned.\nexport function severityColor(colors: Readonly<Record<AlarmLevel, string>>, severity: string): string {\n const level = LEVEL_OF[severity];\n return level ? colors[level] : css('muted-foreground');\n}\n\n// severityRank orders severities most-severe-first; unknown severities sort last.\nexport function severityRank(severity: string): number {\n return SEVERITY_ORDER[severity] ?? 99;\n}\n\n// severityLabel renders a severity in Title Case ('CRITICAL' \u2192 'Critical').\nexport function severityLabel(severity: string): string {\n if (!severity) return '';\n return severity.charAt(0).toUpperCase() + severity.slice(1).toLowerCase();\n}\n\n// highestSeverity returns the most severe severity present in a list, or undefined for\n// an empty list \u2014 the accent an alarm-count uses to signal \"how bad is the worst one\".\nexport function highestSeverity(severities: string[]): string | undefined {\n let best: string | undefined;\n for (const s of severities) {\n if (best === undefined || severityRank(s) < severityRank(best)) best = s;\n }\n return best;\n}\n", "// Copyright The DeviceChain Authors\n// SPDX-License-Identifier: Apache-2.0\n\n// alarm-table \u2014 the raised alarms in the widget's scope (ADR-041), newest first, with\n// a severity stripe per row. When the runtime supplies an action seam AND the viewer\n// holds alarm:write, each active row gets Acknowledge / Clear controls; otherwise the\n// table is read-only. Bound through the hub's alarm channel, so it renders identically\n// from live data or the synthetic preview source.\n\nimport type { AlarmRow, WidgetActions } from '@devicechain/dashboards';\nimport { Fragment, useState, type CSSProperties, type ReactNode } from 'react';\n\nimport {\n type AlarmStreamState,\n css,\n fontVar,\n defineWidget,\n FlashValue,\n formatDateTime,\n optBoolean,\n optNumber,\n optString,\n useElementSize,\n useSeverityColors,\n useWidgetSelect,\n useWidgetTimeZone,\n WidgetFrame,\n type WidgetProps,\n type WidgetSelect,\n} from '@devicechain/widget-sdk';\n\nimport { builtinWidgetDescriptors } from '../builtin-descriptors';\nimport { severityColor, severityLabel } from './severity';\n\nconst cell: CSSProperties = { padding: '6px 10px', textAlign: 'left', whiteSpace: 'nowrap' };\nconst headCell: CSSProperties = {\n ...cell,\n position: 'sticky',\n top: 0,\n background: css('card'),\n fontSize: fontVar('xs'),\n fontWeight: 600,\n textTransform: 'uppercase',\n letterSpacing: '0.04em',\n color: css('muted-foreground'),\n borderBottom: `1px solid ${css('border')}`,\n};\n\n// statusLabel collapses the 4-state model (state \u00D7 acknowledged) into the one signal an\n// operator reads, matching the console's alarm badges: cleared wins regardless of the\n// acknowledged flag; an active alarm is \"Acknowledged\" once owned, else \"Active\".\n// Below this measured width the table drops its lowest-value columns (Status, Raised) rather\n// than clipping or scrolling sideways: severity, originator, alarm and value are what an\n// operator reads at a glance, and the text columns wrap instead of pushing the value off the\n// right edge (a phone's single column is ~390 px). Unmeasured (first frame, jsdom) keeps every\n// column on one line.\nexport const ALARM_TABLE_NARROW_PX = 480;\n\n// A narrow table's text cells: tighter padding, and a long originator or alarm key wraps\n// across lines rather than widening the table past its box. Identifiers break at their\n// hyphens first (see hyphenBreaks); `break-word` splits inside a word only when a single\n// segment is wider than the cell. `anywhere` is deliberately NOT used: it also lowers the\n// column's min-content width, so a squeezed column was split mid-word (\"engine-overhea|t\")\n// instead of at a hyphen.\nconst narrowCell: CSSProperties = {\n ...cell,\n padding: '6px 6px',\n whiteSpace: 'normal',\n overflowWrap: 'break-word',\n wordBreak: 'normal',\n};\n\n// hyphenBreaks renders an identifier with a break opportunity after each hyphen, so a\n// hyphenated key (\"tyre-pressure-low\") wraps as \"tyre-/pressure-/low\". The <wbr> also keeps\n// the column's min-content width at the longest segment, which is what lets the table\n// shrink at 390 px without pushing the Value column off the edge.\nexport function hyphenBreaks(text: string): ReactNode {\n // Split after each hyphen, keeping it on the left part. Not a lookbehind regex: this is a\n // published package, and a lookbehind literal is a parse error in older WebKit.\n const parts = text.split('-').map((p, i, all) => (i < all.length - 1 ? `${p}-` : p));\n return parts.map((part, i) => (\n <Fragment key={i}>\n {i > 0 ? <wbr /> : null}\n {part}\n </Fragment>\n ));\n}\n\nfunction statusLabel(alarm: AlarmRow): string {\n if (alarm.state === 'CLEARED') return 'Cleared';\n return alarm.acknowledged ? 'Acknowledged' : 'Active';\n}\n\nexport function AlarmTable({ widget, data, actions }: WidgetProps<AlarmStreamState>) {\n const { alarms, total, loading } = data;\n // Actions render only when the runtime supplies a seam AND the viewer may write.\n const canAct = actions?.can('alarm:write') ?? false;\n const [sizeRef, size] = useElementSize<HTMLDivElement>();\n const severity = useSeverityColors();\n const narrow = size.width > 0 && size.width < ALARM_TABLE_NARROW_PX;\n const columns = 5 + (narrow ? 0 : 2) + (canAct ? 1 : 0);\n const text = narrow ? narrowCell : cell;\n // Round the triggering value to a fixed precision when configured; unset keeps the raw\n // value (formatValue's default), matching the table widget. An alarm's raw lastValue is\n // otherwise a full-width float (e.g. 31.19073834583732).\n const precision = optNumber(widget.options, 'precision');\n // Opt-in directional flash on the triggering value, per row (keyed by alarm token).\n const flash = optBoolean(widget.options, 'flashOnChange');\n // Drill: when a `selectionTarget` slot is configured AND the renderer wired a selection\n // callback (view mode, a host that supports it), a device originator becomes a link that\n // re-points that slot \u2014 driving the per-device widgets to the clicked thermostat\n // (ADR-039 selection amendment). Absent either, the originator is plain text.\n const select = useWidgetSelect();\n const timeZone = useWidgetTimeZone();\n const selectionTarget = optString(widget.options, 'selectionTarget');\n const drillTo = select && selectionTarget ? { select, slot: selectionTarget } : undefined;\n\n return (\n <WidgetFrame title={optString(widget.options, 'title')} flush>\n <div style={{ display: 'flex', flexDirection: 'column', height: '100%' }}>\n <div ref={sizeRef} style={{ flex: 1, minHeight: 0, overflow: 'auto' }}>\n <table\n style={{\n width: '100%',\n borderCollapse: 'collapse',\n fontSize: fontVar('md'),\n color: css('foreground'),\n fontVariantNumeric: 'tabular-nums',\n }}\n >\n <thead>\n <tr>\n <th style={{ ...headCell, width: 4, padding: 0 }} aria-hidden=\"true\" />\n <th scope=\"col\" style={headCell}>\n Severity\n </th>\n {narrow ? null : (\n <th scope=\"col\" style={headCell}>\n Status\n </th>\n )}\n <th scope=\"col\" style={headCell}>\n Originator\n </th>\n <th scope=\"col\" style={headCell}>\n Alarm\n </th>\n <th scope=\"col\" style={{ ...headCell, textAlign: 'right' }}>\n Value\n </th>\n {narrow ? null : (\n <th scope=\"col\" style={headCell}>\n Raised\n </th>\n )}\n {canAct ? (\n <th scope=\"col\" style={{ ...headCell, textAlign: 'right' }}>\n Actions\n </th>\n ) : null}\n </tr>\n </thead>\n <tbody>\n {alarms.length === 0 ? (\n <tr>\n <td colSpan={columns} style={{ ...cell, textAlign: 'center', color: css('muted-foreground') }}>\n {loading ? 'Loading\u2026' : 'No alarms'}\n </td>\n </tr>\n ) : (\n alarms.map((alarm) => {\n const color = severityColor(severity, alarm.severity);\n return (\n <tr key={alarm.token} style={{ borderBottom: `1px solid ${css('border')}` }}>\n <td aria-hidden=\"true\" style={{ padding: 0, width: 4, background: color }} />\n <td style={cell}>\n <span style={{ display: 'inline-flex', alignItems: 'center', gap: 6 }}>\n <span\n aria-hidden=\"true\"\n style={{ width: 8, height: 8, borderRadius: '50%', background: color, flexShrink: 0 }}\n />\n {severityLabel(alarm.severity)}\n </span>\n </td>\n {narrow ? null : <td style={{ ...cell, color: css('muted-foreground') }}>{statusLabel(alarm)}</td>}\n <td style={text}>\n <OriginatorCell alarm={alarm} drillTo={drillTo} />\n </td>\n <td style={text}>\n {hyphenBreaks(alarm.alarmKey)}\n </td>\n <td style={{ ...cell, textAlign: 'right' }}>\n <FlashValue\n value={alarm.lastValue}\n precision={precision}\n enabled={flash}\n identity={alarm.token}\n />\n </td>\n {narrow ? null : (\n <td style={{ ...cell, color: css('muted-foreground') }}>\n {formatDateTime(alarm.raisedTime, timeZone)}\n </td>\n )}\n {canAct ? (\n <td style={{ ...cell, textAlign: 'right' }}>\n {/* actions is defined whenever canAct is true. */}\n <AlarmRowActions alarm={alarm} actions={actions as WidgetActions} />\n </td>\n ) : null}\n </tr>\n );\n })\n )}\n </tbody>\n </table>\n </div>\n {total > alarms.length ? (\n <div\n style={{\n padding: '4px 10px',\n fontSize: fontVar('xs'),\n color: css('muted-foreground'),\n borderTop: `1px solid ${css('border')}`,\n }}\n >\n Showing {alarms.length} of {total}\n </div>\n ) : null}\n </div>\n </WidgetFrame>\n );\n}\n\n// OriginatorCell renders the alarm's originator. When drill is wired AND the originator\n// is a device (it carries a token), it is a link that re-points the target slot to that\n// device; otherwise it is plain text (the token, or the originator type when tokenless).\n// The drill target is a device binding \u2014 a building-scoped alarm table's originators are\n// already members of the context, so the drill stays in-context.\nfunction OriginatorCell({\n alarm,\n drillTo,\n}: {\n alarm: AlarmRow;\n drillTo: { select: WidgetSelect; slot: string } | undefined;\n}) {\n if (drillTo && alarm.originatorType === 'device' && alarm.originatorToken) {\n const token = alarm.originatorToken;\n return (\n <button\n type=\"button\"\n onClick={() => drillTo.select({ slot: drillTo.slot, binding: { kind: 'device', deviceToken: token } })}\n title={`Show ${token} in the linked widgets`}\n style={{\n padding: 0,\n border: 'none',\n background: 'none',\n font: 'inherit',\n color: css('primary'),\n cursor: 'pointer',\n textDecoration: 'underline',\n textUnderlineOffset: 2,\n }}\n >\n {hyphenBreaks(token)}\n </button>\n );\n }\n return <>{hyphenBreaks(alarm.originatorToken ?? alarm.originatorType)}</>;\n}\n\nconst actionButton: CSSProperties = {\n padding: '2px 8px',\n fontSize: fontVar('sm'),\n lineHeight: 1.4,\n borderRadius: 4,\n border: `1px solid ${css('border')}`,\n background: css('card'),\n color: css('foreground'),\n cursor: 'pointer',\n};\n\n// AlarmRowActions owns the pending/error state for one row's Acknowledge / Clear. Only\n// an ACTIVE alarm is actionable (a cleared \u2014 or any future non-active \u2014 state shows\n// \"\u2014\"); an acknowledged one still shows Clear. After a successful mutation the hub\n// reconciles the table, so the row updates itself.\nfunction AlarmRowActions({ alarm, actions }: { alarm: AlarmRow; actions: WidgetActions }) {\n const severity = useSeverityColors();\n const [pending, setPending] = useState<'ack' | 'clear' | null>(null);\n const [failed, setFailed] = useState(false);\n\n if (alarm.state !== 'ACTIVE') {\n return <span style={{ color: css('muted-foreground') }}>\u2014</span>;\n }\n\n const run = (kind: 'ack' | 'clear', op: () => Promise<void>) => {\n setPending(kind);\n setFailed(false);\n // Call op() synchronously (so an immediate dispatch is observable) but guard a\n // synchronous throw too, so a misbehaving seam can't leave the row stuck-disabled.\n let promise: Promise<void>;\n try {\n promise = op();\n } catch {\n setFailed(true);\n setPending(null);\n return;\n }\n promise.catch(() => setFailed(true)).finally(() => setPending(null));\n };\n\n return (\n <span style={{ display: 'inline-flex', gap: 6, justifyContent: 'flex-end', alignItems: 'center' }}>\n {failed ? (\n <span\n role=\"img\"\n aria-label=\"Action failed \u2014 retry\"\n title=\"Action failed \u2014 retry\"\n style={{ color: severityColor(severity, 'CRITICAL'), fontSize: fontVar('sm') }}\n >\n \u26A0\n </span>\n ) : null}\n {!alarm.acknowledged ? (\n <button\n type=\"button\"\n style={{ ...actionButton, opacity: pending ? 0.6 : 1 }}\n disabled={pending !== null}\n aria-busy={pending === 'ack'}\n aria-label={`Acknowledge alarm ${alarm.alarmKey}`}\n onClick={() => run('ack', () => actions.acknowledgeAlarm(alarm.token))}\n >\n {pending === 'ack' ? '\u2026' : 'Ack'}\n </button>\n ) : null}\n <button\n type=\"button\"\n style={{ ...actionButton, opacity: pending ? 0.6 : 1 }}\n disabled={pending !== null}\n aria-busy={pending === 'clear'}\n aria-label={`Clear alarm ${alarm.alarmKey}`}\n onClick={() => run('clear', () => actions.clearAlarm(alarm.token))}\n >\n {pending === 'clear' ? '\u2026' : 'Clear'}\n </button>\n </span>\n );\n}\n\n// The registration: this widget's portable descriptor paired with its component, declared\n// through the same public `defineWidget` a third-party package uses.\nexport const alarmTableWidget = defineWidget({\n descriptor: builtinWidgetDescriptors['alarm-table'],\n implementation: { kind: 'trusted-react', component: AlarmTable },\n});\n", "// Copyright The DeviceChain Authors\n// SPDX-License-Identifier: Apache-2.0\n\n// command-button \u2014 issue a device command from the dashboard and watch its delivery\n// lifecycle (command-delivery). The console bakes a command definition into the widget's\n// options at author time (its name + parameterSchema); this renders a typed form from\n// that schema, issues via the action seam (gated on command:write), and shows the recent\n// commands for the target device with live status (QUEUED \u2192 SENT \u2192\n// SUCCESSFUL / FAILED \u2026), so an operator can see whether a command was acted on rather\n// than only that it was sent. Bound through the hub's control channel, so it renders identically from live\n// data or the synthetic preview source.\n//\n// The baked schema is a SNAPSHOT taken when the author picked the command: a later edit\n// to the profile's command definition (a changed schema, or a deleted command) leaves\n// this widget's form stale until the author re-picks it. That's acceptable \u2014 dashboards\n// are opaque snapshots \u2014 and a since-removed command fails visibly at the delivery\n// boundary (the server validates device existence and JSON); it isn't silently wrong.\n\nimport type { CommandDispatch, CommandParameter } from '@devicechain/dashboards';\nimport { useEffect, useMemo, useRef, useState, type CSSProperties } from 'react';\n\nimport {\n type CommandStreamState,\n css,\n fontVar,\n defineWidget,\n formatDateTime,\n optString,\n useWidgetTimeZone,\n WidgetFrame,\n type WidgetProps,\n} from '@devicechain/widget-sdk';\n\nimport { builtinWidgetDescriptors } from '../builtin-descriptors';\nimport { commandStatusColor, commandStatusLabel } from './command-status';\nimport {\n buildPayload,\n defaultValues,\n isScalar,\n parseBool,\n parseParameterSchema,\n validateParams,\n} from './command-params';\n\nexport function CommandButton({ widget, data, actions }: WidgetProps<CommandStreamState>) {\n const commandName = optString(widget.options, 'commandName');\n const commandLabel = optString(widget.options, 'commandLabel') ?? commandName;\n const parameterSchema = optString(widget.options, 'parameterSchema') ?? null;\n\n const params = useMemo(() => parseParameterSchema(parameterSchema), [parameterSchema]);\n // A stable key over the configured command: reset the form when the author repoints\n // the widget at a different command (or edits its schema).\n const schemaKey = `${commandName ?? ''}::${parameterSchema ?? ''}`;\n\n const [values, setValues] = useState<Record<string, string>>(() => defaultValues(params));\n const [errors, setErrors] = useState<Record<string, string>>({});\n const [pending, setPending] = useState(false);\n const [sendError, setSendError] = useState<string | null>(null);\n const [sentToken, setSentToken] = useState<string | null>(null);\n // Bumped whenever the configured command changes; an in-flight send captures the\n // current value and drops its result if it settles after a repoint (so command A's\n // dispatch token/error can't land under a freshly-configured command B).\n const sendGen = useRef(0);\n\n // Reset the form to the schema's defaults whenever the configured command changes.\n useEffect(() => {\n sendGen.current += 1;\n setValues(defaultValues(params));\n setErrors({});\n setSendError(null);\n setSentToken(null);\n // params is derived from schemaKey; keying on schemaKey avoids re-running on an\n // equal-but-new params array reference.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [schemaKey]);\n\n const canWrite = actions?.can('command:write') ?? false;\n const hasSeam = typeof actions?.sendCommand === 'function';\n const deviceToken = data.deviceToken;\n // The form is operable only when the viewer may write AND the runtime supplies the send\n // seam; a read-only mount shows the form disabled. Sending additionally needs a bound\n // target device and a configured command.\n const formDisabled = !canWrite || !hasSeam || pending;\n const canSend = !formDisabled && !!deviceToken && !!commandName;\n\n const setField = (name: string, value: string) => {\n setValues((prev) => ({ ...prev, [name]: value }));\n // Clear a field's error as the operator edits it.\n setErrors((prev) => (prev[name] ? { ...prev, [name]: '' } : prev));\n setSendError(null);\n };\n\n const send = () => {\n if (!deviceToken || !commandName || !actions?.sendCommand) return;\n const found = validateParams(params, values);\n const active = Object.fromEntries(Object.entries(found).filter(([, v]) => v));\n if (Object.keys(active).length > 0) {\n setErrors(active);\n return;\n }\n const payload = buildPayload(params, values);\n const gen = sendGen.current; // capture: drop the result if the command is repointed mid-flight\n setPending(true);\n setSendError(null);\n // Call synchronously so a dispatch is observable, but guard a synchronous throw so a\n // misbehaving seam can't leave the button stuck-disabled.\n let promise: Promise<CommandDispatch>;\n try {\n promise = actions.sendCommand(deviceToken, commandName, payload);\n } catch {\n setSendError(SEND_FAILED);\n setPending(false);\n return;\n }\n promise\n .then((dispatch) => {\n if (gen !== sendGen.current) return;\n // \uD83D\uDD34 A REFUSAL IS SHOWN, A FAILURE IS NOT. The server decided this command was\n // wrong and said why in client-safe terms (an unknown command for this device, a\n // parameter that violates the schema, the tenant's held-command ceiling) \u2014 that\n // reason is the whole point of the answer, and an operator can act on it. A\n // thrown error, below, is an availability failure: it says nothing about the\n // command, and its text is internal, so it gets one fixed message instead.\n if (dispatch.status === 'rejected') {\n setSendError(dispatch.reason);\n return;\n }\n setSentToken(dispatch.token);\n })\n .catch(() => {\n if (gen === sendGen.current) setSendError(SEND_FAILED);\n })\n .finally(() => {\n if (gen === sendGen.current) setPending(false);\n });\n };\n\n return (\n <WidgetFrame title={optString(widget.options, 'title')}>\n {/* A short widget (its minimum is two rows, and a cell on a phone is ~56 px) scrolls the\n form down rather than cutting off the send button or the line explaining why it is off. */}\n <div style={{ display: 'flex', flexDirection: 'column', height: '100%', gap: 10, overflowY: 'auto' }}>\n {!commandName ? (\n <div style={{ ...hint, margin: 'auto' }}>No command configured.</div>\n ) : (\n <>\n {/* Typed parameter form. */}\n <div style={{ display: 'flex', flexDirection: 'column', gap: 8, flexShrink: 0 }}>\n {params.map((param) =>\n isScalar(param) ? (\n <ParamField\n key={param.name}\n widgetId={widget.id}\n param={param}\n value={values[param.name] ?? ''}\n error={errors[param.name]}\n disabled={formDisabled}\n onChange={(v) => setField(param.name, v)}\n />\n ) : (\n // A structured (OBJECT) parameter isn't form-editable. A REQUIRED one\n // blocks sending (validateParams flags it); flag that in the note.\n <div key={param.name} style={{ ...hint, color: param.required ? commandStatusColor('FAILED') : css('muted-foreground') }}>\n {param.name}: {param.required ? 'required ' : ''}structured parameter \u2014 not supported here.\n </div>\n ),\n )}\n\n <button\n type=\"button\"\n style={{ ...sendButton, opacity: canSend ? 1 : 0.55, cursor: canSend ? 'pointer' : 'not-allowed' }}\n disabled={!canSend}\n aria-busy={pending}\n onClick={send}\n >\n {pending ? 'Sending\u2026' : `Send ${commandLabel}`}\n </button>\n\n {!canWrite ? (\n <div style={hint}>You don\u2019t have permission to issue commands.</div>\n ) : !hasSeam ? (\n <div style={hint}>Commands aren\u2019t available in this view.</div>\n ) : !deviceToken ? (\n <div style={hint}>No device is selected for this command.</div>\n ) : null}\n {sendError ? (\n <div role=\"alert\" style={{ ...hint, color: commandStatusColor('FAILED') }}>\n {sendError}\n </div>\n ) : null}\n </div>\n\n {/* Recent-command history with live delivery status. */}\n <CommandHistory commands={data.commands} sentToken={sentToken} loading={data.loading} error={data.error} />\n </>\n )}\n </div>\n </WidgetFrame>\n );\n}\n\n// \u2500\u2500 Parameter field \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nfunction ParamField({\n widgetId,\n param,\n value,\n error,\n disabled,\n onChange,\n}: {\n widgetId: string;\n param: CommandParameter;\n value: string;\n error?: string;\n disabled: boolean;\n onChange: (value: string) => void;\n}) {\n // Scope the input id to the widget so two command-buttons sharing a parameter name\n // don't produce duplicate DOM ids (which would misdirect a label click to the first).\n const labelId = `cmd-${widgetId}-${param.name}`;\n const unit = param.unit ? ` (${param.unit})` : '';\n return (\n <label htmlFor={labelId} style={{ display: 'flex', flexDirection: 'column', gap: 3 }}>\n <span style={{ fontSize: fontVar('sm'), color: css('muted-foreground') }}>\n {param.name}\n {unit}\n {param.required ? <span style={{ color: commandStatusColor('FAILED') }}> *</span> : null}\n </span>\n <ParamInput id={labelId} param={param} value={value} disabled={disabled} onChange={onChange} />\n {error ? (\n <span style={{ fontSize: fontVar('xs'), color: commandStatusColor('FAILED') }}>{error}</span>\n ) : null}\n </label>\n );\n}\n\nfunction ParamInput({\n id,\n param,\n value,\n disabled,\n onChange,\n}: {\n id: string;\n param: CommandParameter;\n value: string;\n disabled: boolean;\n onChange: (value: string) => void;\n}) {\n // An enum (of any data type) \u2192 a select; a boolean \u2192 a checkbox; a number \u2192 a numeric\n // input with the declared bounds; everything else \u2192 text.\n if (param.enum && param.enum.length > 0) {\n return (\n <select id={id} style={inputStyle} value={value} disabled={disabled} onChange={(e) => onChange(e.target.value)}>\n {!param.required ? <option value=\"\">\u2014</option> : null}\n {param.enum.map((opt) => (\n <option key={opt} value={opt}>\n {opt}\n </option>\n ))}\n </select>\n );\n }\n if (param.dataType === 'BOOLEAN') {\n return (\n <input\n id={id}\n type=\"checkbox\"\n style={{ width: 16, height: 16 }}\n checked={parseBool(value)}\n disabled={disabled}\n onChange={(e) => onChange(e.target.checked ? 'true' : 'false')}\n />\n );\n }\n const numeric = param.dataType === 'INT' || param.dataType === 'DOUBLE';\n return (\n <input\n id={id}\n type={numeric ? 'number' : 'text'}\n style={inputStyle}\n value={value}\n disabled={disabled}\n min={param.minValue ?? undefined}\n max={param.maxValue ?? undefined}\n step={param.dataType === 'INT' ? 1 : 'any'}\n placeholder={param.default ?? undefined}\n onChange={(e) => onChange(e.target.value)}\n />\n );\n}\n\n// \u2500\u2500 History \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nfunction CommandHistory({\n commands,\n sentToken,\n loading,\n error,\n}: {\n commands: CommandStreamState['commands'];\n sentToken: string | null;\n loading: boolean;\n error: unknown;\n}) {\n // An error is shown inline here (not by replacing the whole widget) so a transient poll\n // blip never tears down the still-usable send form. Last-good rows stay on screen when\n // present; only an empty-and-errored history shows the notice.\n const empty = commands.length === 0;\n const timeZone = useWidgetTimeZone();\n return (\n <div\n style={{\n flex: 1,\n minHeight: 0,\n overflow: 'auto',\n borderTop: `1px solid ${css('border')}`,\n paddingTop: 6,\n }}\n >\n {empty ? (\n <div style={{ ...hint, textAlign: 'center', color: error ? commandStatusColor('FAILED') : css('muted-foreground') }}>\n {error ? 'Couldn\u2019t load command history.' : loading ? 'Loading\u2026' : 'No commands issued yet.'}\n </div>\n ) : (\n <ul style={{ listStyle: 'none', margin: 0, padding: 0, display: 'flex', flexDirection: 'column', gap: 4 }}>\n {commands.map((command) => (\n <li\n key={command.token}\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: 8,\n fontSize: fontVar('sm'),\n // Highlight the command just issued from this widget.\n fontWeight: command.token === sentToken ? 600 : 400,\n }}\n >\n <StatusBadge status={command.status} />\n <span style={{ color: css('foreground'), whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>\n {command.name}\n </span>\n <span style={{ marginLeft: 'auto', color: css('muted-foreground'), whiteSpace: 'nowrap' }}>\n {formatDateTime(command.queuedTime, timeZone)}\n </span>\n </li>\n ))}\n </ul>\n )}\n </div>\n );\n}\n\nfunction StatusBadge({ status }: { status: string }) {\n const color = commandStatusColor(status);\n return (\n <span\n style={{\n display: 'inline-flex',\n alignItems: 'center',\n gap: 4,\n flexShrink: 0,\n fontSize: fontVar('xs'),\n fontWeight: 600,\n color,\n }}\n >\n <span aria-hidden=\"true\" style={{ width: 7, height: 7, borderRadius: '50%', background: color }} />\n {commandStatusLabel(status)}\n </span>\n );\n}\n\n// \u2500\u2500 styles / helpers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nconst hint: CSSProperties = { fontSize: fontVar('xs'), color: css('muted-foreground') };\n\n// What a viewer is told when the platform could not decide the enqueue. It is fixed\n// prose on purpose: the thrown error's text describes in-cluster machinery, and a\n// dashboard is the surface most likely to be embedded outside the tenant's own console.\nconst SEND_FAILED = 'Couldn\u2019t issue the command. Try again.';\n\nconst inputStyle: CSSProperties = {\n width: '100%',\n boxSizing: 'border-box',\n padding: '4px 8px',\n fontSize: fontVar('md'),\n borderRadius: 4,\n border: `1px solid ${css('border')}`,\n background: css('background'),\n color: css('foreground'),\n};\n\nconst sendButton: CSSProperties = {\n padding: '6px 12px',\n fontSize: fontVar('md'),\n fontWeight: 600,\n borderRadius: 4,\n border: 'none',\n background: css('primary'),\n color: css('background'),\n marginTop: 2,\n};\n\n// The registration: this widget's portable descriptor paired with its component, declared\n// through the same public `defineWidget` a third-party package uses.\nexport const commandButtonWidget = defineWidget({\n descriptor: builtinWidgetDescriptors['command-button'],\n implementation: { kind: 'trusted-react', component: CommandButton },\n});\n", "// Copyright The DeviceChain Authors\n// SPDX-License-Identifier: Apache-2.0\n\n// The command-control registrations: descriptor eager, component lazy, from a chunk of their own\n// (control-widgets.ts) so a board without a slider or toggle never downloads the sending code.\n\nimport { defineWidget, type CommandStreamState } from '@devicechain/widget-sdk';\n\nimport { builtinWidgetDescriptors } from '../builtin-descriptors';\nimport { lazyChunk } from './lazy-chunk';\n\nconst chunk = lazyChunk<typeof import('./control-widgets'), CommandStreamState>(() => import('./control-widgets'));\n\nexport const loadControlWidgets = chunk.load;\n\nexport const commandSliderWidget = defineWidget({\n descriptor: builtinWidgetDescriptors['command-slider'],\n implementation: { kind: 'trusted-react', component: chunk.component('CommandSlider') },\n});\n\nexport const commandToggleWidget = defineWidget({\n descriptor: builtinWidgetDescriptors['command-toggle'],\n implementation: { kind: 'trusted-react', component: chunk.component('CommandToggle') },\n});\n", "// Copyright The DeviceChain Authors\n// SPDX-License-Identifier: Apache-2.0\n\n// entity-selector \u2014 a flat picker that re-points a target slot's binding (ADR-039 selection\n// amendment). It is the authored companion to the alarm-originator drill: the viewer chooses\n// WHICH entity a slot binds to, and every widget bound to that slot (and its scoped children,\n// via the cascade) follows. Two shapes, both from `options.selectionTarget`:\n// \u2022 target is a SCOPED child slot \u2192 a member picker (which thermostat within the building).\n// \u2022 target is a ROOT slot \u2192 a context picker (which building the dashboard shows).\n// The candidate set comes from the ambient provider (useCandidates), which the host computes\n// from the target slot's scope; the pick fires the ambient select() callback. Inert (a muted\n// hint) wherever selection isn't wired \u2014 edit mode, preview, a read-only embedder.\n\nimport type { SlotBinding } from '@devicechain/dashboards';\nimport { useEffect, useState, type ChangeEvent, type CSSProperties } from 'react';\n\nimport {\n css,\n fontVar,\n defineWidget,\n optString,\n useCandidates,\n useWidgetSelect,\n WidgetFrame,\n type WidgetProps,\n} from '@devicechain/widget-sdk';\n\nimport { builtinWidgetDescriptors } from '../builtin-descriptors';\n\n// A binding's stable option value \u2014 the device token or the anchor's target token. Used as\n// the <option> value (not the array index) so the control's value survives a re-fetch that\n// reorders/replaces candidates.\nfunction tokenOf(b: SlotBinding): string {\n return b.kind === 'device' ? b.deviceToken : b.anchor.targetToken;\n}\n\nconst control: CSSProperties = {\n width: '100%',\n fontSize: fontVar('md'),\n padding: '8px 10px',\n borderRadius: 6,\n border: `1px solid ${css('border')}`,\n background: css('background'),\n color: css('foreground'),\n};\n\nconst hint: CSSProperties = {\n fontSize: fontVar('sm'),\n color: css('muted-foreground'),\n};\n\nexport function EntitySelector({ widget }: WidgetProps<null>) {\n const select = useWidgetSelect();\n const target = optString(widget.options, 'selectionTarget');\n const { candidates, loading, error, wired } = useCandidates(target);\n const title = optString(widget.options, 'title');\n\n // Optimistic pick: hold the just-chosen token so the control reflects the choice\n // immediately \u2014 through the (on a scoped dashboard, two-hop) async re-resolve \u2014 rather\n // than snapping back to the prior selection until the refetch settles. Cleared once the\n // fetched candidates reflect it, or it is no longer offered (the pick was dropped).\n const [pending, setPending] = useState<string | null>(null);\n const selected = candidates.find((c) => c.selected);\n const selectedToken = selected ? tokenOf(selected.binding) : '';\n useEffect(() => {\n if (pending !== null && (selectedToken === pending || !candidates.some((c) => tokenOf(c.binding) === pending))) {\n setPending(null);\n }\n }, [candidates, selectedToken, pending]);\n\n // Inert wherever selection isn't wired (no select callback OR no candidate provider) or no\n // target slot is authored \u2014 the picker would drive nothing, so show a muted explanation.\n const inert = !select || !target || !wired;\n const value = pending ?? selectedToken;\n\n const onChange = (e: ChangeEvent<HTMLSelectElement>) => {\n const token = e.target.value;\n if (!token) return; // the disabled placeholder ('') \u2014 nothing to select\n const candidate = candidates.find((c) => tokenOf(c.binding) === token);\n if (select && target && candidate) {\n setPending(token);\n select({ slot: target, binding: candidate.binding });\n }\n };\n\n return (\n <WidgetFrame title={title}>\n <div\n style={{\n display: 'flex',\n flexDirection: 'column',\n gap: 8,\n height: '100%',\n boxSizing: 'border-box',\n overflow: 'auto',\n }}\n >\n {inert ? (\n <span style={hint}>\n {select && target ? 'Selection isn\u2019t available here.' : select ? 'No target slot configured.' : 'Selection is available on the live dashboard.'}\n </span>\n ) : (\n <>\n <select\n style={{ ...control, opacity: loading ? 0.6 : 1 }}\n value={value}\n disabled={candidates.length === 0}\n onChange={onChange}\n aria-label={title || `Select ${target}`}\n >\n {/* A blank option so an unbound slot (no member picked yet, or the prior pick\n is out of the new context) shows a prompt rather than defaulting to a row. */}\n <option value=\"\" disabled>\n {loading ? 'Loading\u2026' : candidates.length === 0 ? 'No options' : 'Select\u2026'}\n </option>\n {candidates.map((c) => (\n <option key={tokenOf(c.binding)} value={tokenOf(c.binding)}>\n {c.label}\n </option>\n ))}\n </select>\n {error ? <span style={hint}>Couldn\u2019t load options.</span> : null}\n </>\n )}\n </div>\n </WidgetFrame>\n );\n}\n\n// The registration: this widget's portable descriptor paired with its component, declared\n// through the same public `defineWidget` a third-party package uses.\nexport const entitySelectorWidget = defineWidget({\n descriptor: builtinWidgetDescriptors['entity-selector'],\n implementation: { kind: 'trusted-react', component: EntitySelector },\n});\n", "// Copyright The DeviceChain Authors\n// SPDX-License-Identifier: Apache-2.0\n\n// gauge \u2014 the current value of one measurement on an ECharts radial gauge.\n\nimport { useMemo } from 'react';\n\nimport {\n defineWidget,\n flashBackgroundStyle,\n formatValue,\n optBoolean,\n optNumber,\n optString,\n optThresholds,\n pickSample,\n primaryMeasurementName,\n useFlashOnChange,\n useWidgetScale,\n WidgetFrame,\n type WidgetProps,\n} from '@devicechain/widget-sdk';\nimport { buildGaugeOption, EChart, gaugeReadoutBox, useChartTheme } from '@devicechain/widget-sdk/echarts';\n\nimport { builtinWidgetDescriptors } from '../builtin-descriptors';\nimport { LevelReadout } from '../level-readout';\nimport { readRange } from '../value-scale';\n\nexport function Gauge({ widget, data }: WidgetProps) {\n const name = primaryMeasurementName(widget);\n const sample = pickSample(data.latest, name);\n return (\n <WidgetFrame title={optString(widget.options, 'title') ?? name} sampleTime={sample?.occurredTime ?? null} flush>\n <GaugeBody widget={widget} data={data} />\n </WidgetFrame>\n );\n}\n\n// Rendered INSIDE the frame: the widget scale is the frame's content column, which is only in\n// context below the frame.\nfunction GaugeBody({ widget, data }: WidgetProps) {\n const theme = useChartTheme();\n const { size, scale } = useWidgetScale();\n const name = primaryMeasurementName(widget);\n const sample = pickSample(data.latest, name);\n\n const min = optNumber(widget.options, 'min');\n const max = optNumber(widget.options, 'max');\n const unit = optString(widget.options, 'unit');\n const precision = optNumber(widget.options, 'precision');\n // The stored list is re-parsed only when the options bag changes, so the memo below keys on\n // a stable array rather than a fresh one per render.\n const thresholds = useMemo(() => optThresholds(widget.options, 'thresholds'), [widget.options]);\n\n const option = useMemo(\n () => buildGaugeOption(sample?.value ?? null, theme, { min, max, thresholds, scale, readout: 'none', emptyNeedle: 'none' }, size),\n [sample?.value, theme, min, max, thresholds, scale, size],\n );\n\n // Opt-in directional flash. The value lives on an opaque canvas, so the cue is a\n // translucent tint on the container behind it rather than a recolored number. The identity\n // (device + measurement) suppresses a false flash on an anchor's cross-device interleave.\n const flashDirection = useFlashOnChange(\n sample?.value,\n optBoolean(widget.options, 'flashOnChange'),\n sample && `${sample.deviceToken}:${sample.name}`,\n );\n\n // The number is DOM text laid over the dial where the canvas used to print it, so the\n // readability gate can measure it (it cannot see canvas text). The meter role carries the\n // reading to assistive tech, which the canvas never did.\n const box = gaugeReadoutBox(size);\n const range = readRange(min, max, { min: 0, max: 100 });\n const value = sample?.value ?? undefined;\n const meter =\n range.ok && value !== undefined && Number.isFinite(value)\n ? {\n role: 'meter' as const,\n 'aria-valuemin': range.range.min,\n 'aria-valuemax': range.range.max,\n 'aria-valuenow': Math.min(range.range.max, Math.max(range.range.min, value)),\n 'aria-valuetext': `${formatValue(value, precision)}${unit ? ` ${unit}` : ''}`,\n }\n : {};\n\n return (\n <div style={{ position: 'relative', width: '100%', height: '100%', ...flashBackgroundStyle(flashDirection) }} {...meter}>\n <EChart option={option} />\n <div\n style={{\n position: 'absolute',\n left: box.centerX - box.width / 2,\n top: box.centerY - box.height / 2,\n width: box.width,\n height: box.height,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n pointerEvents: 'none',\n }}\n >\n <LevelReadout\n text={formatValue(value, precision)}\n unit={value === undefined ? undefined : unit}\n size={{ width: box.width, height: box.height }}\n scale={scale}\n />\n </div>\n </div>\n );\n}\n\n// The registration: this widget's portable descriptor paired with its component, declared\n// through the same public `defineWidget` a third-party package uses.\nexport const gaugeWidget = defineWidget({\n descriptor: builtinWidgetDescriptors['gauge'],\n implementation: { kind: 'trusted-react', component: Gauge },\n});\n", "// Copyright The DeviceChain Authors\n// SPDX-License-Identifier: Apache-2.0\n\n// image \u2014 a static image on the canvas (floor plans, logos, SCADA backdrops). No\n// datasource; the Phase-4 SCADA symbol family will layer live SVG on top of this.\n\nimport type { CSSProperties } from 'react';\n\nimport {\n css,\n defineWidget,\n fontVar,\n optString,\n WidgetFrame,\n type WidgetProps,\n} from '@devicechain/widget-sdk';\n\nimport { builtinWidgetDescriptors } from '../builtin-descriptors';\n\nconst FITS = new Set(['contain', 'cover', 'fill']);\n\nexport function Image({ widget }: WidgetProps<null>) {\n const url = optString(widget.options, 'url');\n const alt = optString(widget.options, 'alt') ?? '';\n const fitOption = optString(widget.options, 'fit');\n const objectFit = (fitOption && FITS.has(fitOption) ? fitOption : 'contain') as CSSProperties['objectFit'];\n\n return (\n <WidgetFrame title={optString(widget.options, 'title')} flush>\n {url ? (\n <img src={url} alt={alt} style={{ width: '100%', height: '100%', objectFit, display: 'block' }} />\n ) : (\n <div\n style={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n height: '100%',\n color: css('muted-foreground'),\n fontSize: fontVar('md'),\n }}\n >\n No image URL\n </div>\n )}\n </WidgetFrame>\n );\n}\n\n// The registration: this widget's portable descriptor paired with its component, declared\n// through the same public `defineWidget` a third-party package uses.\nexport const imageWidget = defineWidget({\n descriptor: builtinWidgetDescriptors['image'],\n implementation: { kind: 'trusted-react', component: Image },\n});\n", "// Copyright The DeviceChain Authors\n// SPDX-License-Identifier: Apache-2.0\n\n// label \u2014 static text on the canvas (headings, captions, annotations). No\n// datasource. Renders plain text only (no raw HTML) so a tenant-authored\n// definition can't inject markup.\n\nimport type { CSSProperties } from 'react';\n\nimport {\n css,\n defineWidget,\n fontVar,\n spaceVar,\n optNumber,\n optString,\n WidgetFrame,\n type WidgetProps,\n} from '@devicechain/widget-sdk';\n\nimport { builtinWidgetDescriptors } from '../builtin-descriptors';\n\nconst justify: Record<string, CSSProperties['justifyContent']> = {\n left: 'flex-start',\n center: 'center',\n right: 'flex-end',\n};\n\nexport function Label({ widget }: WidgetProps<null>) {\n const text = optString(widget.options, 'text') ?? '';\n const align = optString(widget.options, 'align') ?? 'center';\n // An authored size is a design size in px at the board's normal density: it scales with it,\n // so a wall board's label grows with the rest. Unset takes the large step of the type ramp.\n const authored = optNumber(widget.options, 'fontSize');\n const fontSize = authored !== undefined ? `calc(${authored}px * var(--dc-scale, 1))` : fontVar('lg');\n\n return (\n <WidgetFrame title={optString(widget.options, 'title')} flush>\n <div\n style={{\n display: 'flex',\n alignItems: 'safe center',\n justifyContent: justify[align] ?? 'center',\n height: '100%',\n boxSizing: 'border-box',\n overflow: 'hidden',\n // A label is often one row tall: the frame's uniform inset would leave it a line's\n // height or less, so it keeps a slim vertical inset and the usual side inset.\n padding: `${spaceVar(1)} ${spaceVar(3)}`,\n }}\n >\n <span\n style={{\n fontSize,\n color: css('foreground'),\n textAlign: align as CSSProperties['textAlign'],\n whiteSpace: 'pre-wrap',\n }}\n >\n {text}\n </span>\n </div>\n </WidgetFrame>\n );\n}\n\n// The registration: this widget's portable descriptor paired with its component, declared\n// through the same public `defineWidget` a third-party package uses.\nexport const labelWidget = defineWidget({\n descriptor: builtinWidgetDescriptors['label'],\n implementation: { kind: 'trusted-react', component: Label },\n});\n", "// Copyright The DeviceChain Authors\n// SPDX-License-Identifier: Apache-2.0\n\n// latest-card \u2014 the current value of one measurement, big and legible.\n\nimport { useMemo } from 'react';\n\nimport {\n bandAt,\n css,\n defineWidget,\n fitValueFont,\n fitValueFontCss,\n FIT_MIN_FONT_PX,\n flashTextStyle,\n fontVar,\n formatTimestamp,\n formatValue,\n levelColor,\n optBoolean,\n optNumber,\n optString,\n optThresholds,\n pickSample,\n primaryMeasurementName,\n spaceVar,\n useSeverityColors,\n useStickyChars,\n useFlashOnChange,\n useWidgetTimeZone,\n WidgetFrame,\n type WidgetProps,\n} from '@devicechain/widget-sdk';\n\nimport { builtinWidgetDescriptors } from '../builtin-descriptors';\n\n// The room a timestamp line needs under the value. The frame's content column (what the\n// widget scale reports) is already net of the frame's padding.\nconst TIMESTAMP_ROOM_PX = 18;\n\nexport function LatestCard({ widget, data }: WidgetProps) {\n const severity = useSeverityColors();\n const timeZone = useWidgetTimeZone();\n const name = primaryMeasurementName(widget);\n const sample = pickSample(data.latest, name);\n\n const title = optString(widget.options, 'title') ?? name;\n const unit = optString(widget.options, 'unit');\n const precision = optNumber(widget.options, 'precision');\n const display = formatValue(sample?.value, precision);\n // The value reads in the colour of the band it falls in; below the lowest threshold (or with\n // none, or in a `normal` band) it keeps the foreground: colour only for the abnormal.\n const thresholds = useMemo(() => optThresholds(widget.options, 'thresholds'), [widget.options]);\n const band = bandAt(thresholds, sample?.value);\n const valueColor = levelColor(severity, band?.level) ?? css('foreground');\n\n // Opt-in directional flash: tint the number green/red on a rise/fall, then fade back. The\n // identity (device + measurement) suppresses a false flash when an anchor's single slot\n // interleaves values across member devices, or the shown measurement switches.\n const flashDirection = useFlashOnChange(\n sample?.value,\n optBoolean(widget.options, 'flashOnChange'),\n sample && `${sample.deviceToken}:${sample.name}`,\n );\n\n // Fit the value to the card from both dimensions and the string length (the unit renders at\n // half size, so it counts for half its characters).\n // Sticky: the longest length seen lately, so a value crossing 9.99 -> 10.01 holds its size.\n const chars = useStickyChars(display.length + (sample?.value != null && unit ? Math.ceil(unit.length / 2) + 1 : 0));\n return (\n <WidgetFrame title={title} sampleTime={sample?.occurredTime ?? null}>\n {({ size, scale }) => {\n // Measured: the JS curve. Unmeasured (first frame): the SAME curve in cq units, resolved\n // by the browser against the frame's content column, so there is no fallback-size flash.\n const floor = Math.round(FIT_MIN_FONT_PX * scale);\n const measured = size.width > 0 && size.height > 0;\n const valuePx = measured ? fitValueFont(size, chars, { floor }) : undefined;\n const valueFont = valuePx ?? fitValueFontCss(chars, { floor });\n // The timestamp is the first thing to give: it shows only when the measured box has room\n // for it under the value (unmeasured -- first frame, jsdom -- it shows).\n const showTimestamp =\n valuePx === undefined || size.height - Math.ceil(valuePx * 1.1) >= TIMESTAMP_ROOM_PX * scale;\n return (\n <div\n style={{\n display: 'flex',\n flexDirection: 'column',\n justifyContent: 'safe center',\n height: '100%',\n boxSizing: 'border-box',\n overflow: 'hidden',\n }}\n >\n <div\n data-threshold-level={band?.level}\n title={band?.label}\n style={{\n fontSize: valueFont,\n fontWeight: 600,\n lineHeight: 1.1,\n // One line, and digits of one width: the fit counts characters, so a live value\n // must not wrap or shift sideways as its digits change.\n whiteSpace: 'nowrap',\n fontVariantNumeric: 'tabular-nums',\n color: valueColor,\n ...flashTextStyle(flashDirection),\n }}\n >\n {display}\n {sample?.value != null && unit ? (\n <span\n style={{\n fontSize: valuePx !== undefined ? Math.round(valuePx / 2) : `calc(${valueFont} / 2)`,\n color: css('muted-foreground'),\n marginLeft: spaceVar(1),\n }}\n >\n {unit}\n </span>\n ) : null}\n </div>\n {sample?.occurredTime && showTimestamp ? (\n <div style={{ fontSize: fontVar('xs'), color: css('muted-foreground'), marginTop: spaceVar(1) }}>\n {formatTimestamp(sample.occurredTime, timeZone)}\n </div>\n ) : null}\n </div>\n );\n }}\n </WidgetFrame>\n );\n}\n\n// The registration: this widget's portable descriptor paired with its component, declared\n// through the same public `defineWidget` a third-party package uses.\nexport const latestCardWidget = defineWidget({\n descriptor: builtinWidgetDescriptors['latest-card'],\n implementation: { kind: 'trusted-react', component: LatestCard },\n});\n", "// Copyright The DeviceChain Authors\n// SPDX-License-Identifier: Apache-2.0\n\n// The level, indicator and radial registrations: descriptor eager, component lazy. The descriptors\n// are the catalog (the editor, the validators and WIDGET_TYPES read them without rendering\n// anything), so they stay in the entry; the seven components load on first mount, together,\n// from one chunk (level-widgets.ts), so a board without one of them never downloads it.\n//\n// Until the chunk arrives the widget renders nothing inside its box. A chunk that fails to\n// load is THROWN, so the widget's error boundary shows the failure: an empty tank that looks\n// like a reading is the outcome this must never produce.\n\nimport { defineWidget } from '@devicechain/widget-sdk';\n\nimport { builtinWidgetDescriptors } from '../builtin-descriptors';\nimport { lazyChunk } from './lazy-chunk';\n\nconst chunk = lazyChunk(() => import('./level-widgets'));\n\nexport const loadLevelWidgets = chunk.load;\n\nconst lazyComponent = chunk.component;\n\nexport const linearGaugeWidget = defineWidget({\n descriptor: builtinWidgetDescriptors['linear-gauge'],\n implementation: { kind: 'trusted-react', component: lazyComponent('LinearGauge') },\n});\n\nexport const levelGaugeWidget = defineWidget({\n descriptor: builtinWidgetDescriptors['level-gauge'],\n implementation: { kind: 'trusted-react', component: lazyComponent('LevelGauge') },\n});\n\nexport const batteryWidget = defineWidget({\n descriptor: builtinWidgetDescriptors['battery'],\n implementation: { kind: 'trusted-react', component: lazyComponent('Battery') },\n});\n\nexport const statusLightWidget = defineWidget({\n descriptor: builtinWidgetDescriptors['status-light'],\n implementation: { kind: 'trusted-react', component: lazyComponent('StatusLight') },\n});\n\nexport const signalBarsWidget = defineWidget({\n descriptor: builtinWidgetDescriptors['signal-bars'],\n implementation: { kind: 'trusted-react', component: lazyComponent('SignalBars') },\n});\n\nexport const compassWidget = defineWidget({\n descriptor: builtinWidgetDescriptors['compass'],\n implementation: { kind: 'trusted-react', component: lazyComponent('Compass') },\n});\n\nexport const progressRingWidget = defineWidget({\n descriptor: builtinWidgetDescriptors['progress-ring'],\n implementation: { kind: 'trusted-react', component: lazyComponent('ProgressRing') },\n});\n", "// Copyright The DeviceChain Authors\n// SPDX-License-Identifier: Apache-2.0\n\n// map \u2014 the bound devices' last-known positions, on the location channel.\n//\n// Three rules shape everything here, and each of them is a state some other design\n// would have collapsed into \"the map is empty\":\n//\n// \uD83D\uDD34 REFUSED IS NOT EMPTY. Position is gated on its own `location:read` authority,\n// deliberately absent from the read-only viewer baseline, so an ordinary member with\n// full telemetry access is routinely refused. \"No devices to show\" and \"you are not\n// allowed to see this\" are opposite facts and only one of them is actionable, so the\n// refusal gets its own copy and its own look \u2014 never a blank map.\n//\n// \uD83D\uDD34 NO TILE SOURCE IS NOT A BROKEN MAP. This package hardcodes no tile URL (see\n// rasterStyleFor) and inherits one from the tenant (ADR-079), whose instance-wide\n// default now ships a real provider \u2014 so in practice this branch is rare. It is not\n// dead, though: an operator can empty that default, an air-gapped install can have no\n// route to any provider at all, and a viewer can be looking at a board on either.\n//\n// That case renders a REAL MapLibre map against the BUNDLED public-domain world\n// (loadLandStyle) \u2014 continents and country outlines, compiled into this package.\n//\n// \uD83D\uDD34 Be precise about what survives of the old promise, because an earlier version of\n// this comment was not. It said the widget \"issues no request to any host\" and backed\n// that with \"loads no map library\", and the second half is now FALSE: this path loads\n// the renderer and the geometry, two chunks, from the app's OWN origin. What is still\n// true \u2014 and is the part that ever mattered \u2014 is that it contacts no THIRD-PARTY host,\n// because it has been given none it would be entitled to ask. What it no longer does\n// is show a void that reads as breakage.\n//\n// \uD83D\uDD34 ABSENT IS NOT ZERO. A marker describes only what its device reported; an\n// unreported heading is not due north. See describePosition.\n\nimport { useEffect, useRef, useState, type CSSProperties } from 'react';\nimport { renderableBasemap, resolveBasemap } from '@devicechain/client';\n\nimport { useTenantBasemap } from '../basemap-context';\nimport { useMapRuntime, type MapRuntime } from '../map-runtime-context';\nimport {\n css,\n fontVar,\n defineWidget,\n type LocationStreamState,\n optString,\n WidgetFrame,\n type WidgetProps,\n} from '@devicechain/widget-sdk';\n\nimport { builtinWidgetDescriptors } from '../builtin-descriptors';\nimport {\n describePosition,\n loadLandStyle,\n placeable,\n projectToPanel,\n rasterStyleFor,\n type PlaceableLocation,\n} from './map-geometry';\n\n// The MapLibre pieces this widget drives. A TYPE-only import is erased at build time,\n// so naming them here creates no static dependency on the library \u2014 the value only ever\n// arrives through the dynamic import below.\nimport type { Map as MapLibreMap, Marker as MapLibreMarker } from 'maplibre-gl';\n\n// \uD83D\uDD34 THE LIBRARY IS LOADED LAZILY, BY CONSTRUCTION. MapLibre is ~200 KB gzipped, and\n// only a dashboard that actually contains a map widget may pay for it \u2014 a console user\n// who never opens a board with a map must not download a map renderer. The dynamic\n// import is what puts it in its own chunk; a top-level `import 'maplibre-gl'` anywhere\n// in this package would fold it into the main bundle for every viewer, and nothing\n// about the widget's behaviour would change to reveal it.\n//\n// MapLibre's STYLESHEET is no longer imported here at all \u2014 it is the host's, along with\n// the worker URL, for the reason set out below and in map-runtime-context. A host may hand\n// back a loader for it (`MapRuntime.loadStyles`) to keep it on this same lazy chunk, or\n// import it eagerly and pay 83 KB (10.7 KB gzipped) in its main stylesheet. That is the\n// host's call, and both are reasonable; what a LIBRARY cannot do is decide it for them in\n// one bundler's dialect.\n//\n// Loaded once and memoized: several map widgets on one board share the fetch.\nlet mapLibrePromise: Promise<typeof import('maplibre-gl')> | undefined;\n\n// \uD83D\uDD34 THE WORKER HAS TO BE ASKED FOR BY NAME, and getting this wrong produces a map\n// that builds, type-checks, passes every test and then renders nothing. MapLibre\n// otherwise derives the worker's URL at runtime from its own module URL, which is a\n// string no bundler can follow \u2014 nothing emits the file, the browser 404s it, and\n// `new Worker()` does not throw on a 404: the failure arrives later as an async error\n// event, so the map simply sits there having loaded no tiles.\n//\n// \uD83D\uDD34 THE URL COMES FROM THE HOST, and this package no longer computes it. Emitting a\n// worker entry is a bundler-specific act \u2014 Vite spells it `?worker&url`, webpack and\n// Rollup spell it differently \u2014 so a library that writes one dialect works under that\n// bundler and silently renders a blank map under every other. See map-runtime-context\n// for the full argument; the short version is that the specifier is externalized, so\n// no build anywhere reports the breakage.\n//\n// Memoized for the whole module, and FIRST CALLER WINS: several map widgets on one\n// board share the fetch, and `setWorkerUrl` is global state in MapLibre, so a second\n// caller with a different URL could not be honoured even if we tried. In practice\n// there is one provider at the top of the tree and therefore one URL.\nfunction loadMapLibre(runtime: MapRuntime): Promise<typeof import('maplibre-gl')> {\n if (!mapLibrePromise) {\n // The stylesheet rides the SAME dynamic boundary as the renderer, which is why a host\n // may pass a loader rather than importing it at module scope: it is 83 KB raw, 10.7 KB\n // gzipped (maplibre-gl 6.6.0), and a viewer who opens no map should download none of\n // it. Optional \u2014 a host that imports the stylesheet itself is doing the ordinary thing.\n //\n // \uD83D\uDD34 `Promise.resolve().then(...)` IS NOT CEREMONY. `loadStyles()` is host code, and a\n // host CAN throw synchronously \u2014 `loadStyles: () => require('\u2026css')` on a bundler with\n // no CSS loader is the realistic form. Called while building the argument array, that\n // throw escapes loadMapLibre entirely, propagates through the caller's own\n // `Promise.all` argument evaluation, and lands in React's commit phase where the\n // effect's `.catch` cannot see it: React 19 unmounts the tree, so one misconfigured\n // host loader takes down the whole dashboard instead of degrading to the plain panel.\n // Deferring the call puts it inside the promise chain, where the existing catch works.\n mapLibrePromise = Promise.all([\n import('maplibre-gl'),\n Promise.resolve().then(() => runtime.loadStyles?.()),\n ]).then(([mod]) => {\n mod.setWorkerUrl(runtime.workerUrl);\n return mod;\n });\n }\n return mapLibrePromise;\n}\n\n// The zoom a single-device map opens at \u2014 close enough to read a site, wide enough that\n// a lone marker is not floating in featureless tiles. A multi-device map ignores it and\n// fits the fleet's bounds instead.\nconst SINGLE_DEVICE_ZOOM = 14;\n\nexport function MapWidget({ widget, data }: WidgetProps<LocationStreamState>) {\n const title = optString(widget.options, 'title');\n const positions = placeable(data.locations);\n\n // The host's bundler-produced MapLibre runtime. Read unconditionally, with the other\n // hooks, because a hook cannot live behind one of the early returns below.\n const runtime = useMapRuntime();\n\n // Precedence is per-widget override \u2192 tenant \u2192 no basemap (ADR-079 \u00A79). The\n // per-widget options are kept, not replaced: they are how someone tries a provider\n // on one board before committing it tenant-wide.\n //\n // \uD83D\uDD34 resolveBasemap is NOT `override ?? tenant` per field. A widget that names its\n // own tile URL does not inherit the tenant's credit line, because that would credit\n // the tenant's provider for tiles it did not serve. The SDK owns that rule so the\n // fence editor and the /dash app cannot disagree with this widget about it.\n const basemap = renderableBasemap(\n resolveBasemap(\n {\n tileUrl: optString(widget.options, 'tileUrl'),\n attribution: optString(widget.options, 'attribution'),\n },\n useTenantBasemap(),\n ),\n );\n\n // The refusal is checked FIRST and unconditionally: it is a fact about the caller, so\n // it outranks anything about the data, and it must not be reachable only through some\n // \"no positions\" branch that a later edit could reorder past.\n if (data.forbidden) {\n return (\n <WidgetFrame title={title}>\n <MapNotice\n glyph=\"\uD83D\uDD12\"\n heading=\"Location not permitted\"\n detail=\"You do not have permission to view device locations.\"\n />\n </WidgetFrame>\n );\n }\n\n // \uD83D\uDD34 AND THE HOST'S OWN WIRING IS CHECKED SECOND, for the same reason the refusal is\n // checked first: it is a fact about the environment rather than about the data, so it\n // outranks every \"nothing to show\" branch below. Checking it later would hide it behind\n // \"No devices selected\" on exactly the board a developer is using to find it.\n //\n // There is no fallback to take. The only alternative to a host-supplied worker URL is\n // MapLibre's runtime derivation, which is the silent blank map this seam exists to\n // prevent \u2014 so an unwired host is told, in the widget, what it has to install.\n if (!runtime) {\n return (\n <WidgetFrame title={title}>\n <MapNotice\n glyph=\"\uD83E\uDDE9\"\n heading=\"Map runtime not configured\"\n detail=\"This host must install MapRuntimeProvider with its bundler's MapLibre worker URL.\"\n />\n </WidgetFrame>\n );\n }\n\n if (data.loading && positions.length === 0) {\n return (\n <WidgetFrame title={title}>\n <MapNotice heading=\"Loading\u2026\" />\n </WidgetFrame>\n );\n }\n\n if (positions.length === 0) {\n // Two different empty states, because they call for two different actions: bind the\n // widget, or wait for a device to report.\n return (\n <WidgetFrame title={title}>\n <MapNotice\n heading={data.deviceTokens.length === 0 ? 'No devices selected' : 'No positions reported'}\n detail={\n data.deviceTokens.length === 0\n ? 'Bind this widget to a device or anchor and select its location series.'\n : 'None of the selected devices has reported a position yet.'\n }\n />\n </WidgetFrame>\n );\n }\n\n return (\n <WidgetFrame title={title} flush>\n <LiveMap basemap={basemap} positions={positions} runtime={runtime} />\n </WidgetFrame>\n );\n}\n\n// ---- The tile-less panel ----------------------------------------------------\n\n// PlainPanel draws the positions on a themed background with no basemap at all.\n//\n// \uD83D\uDD34 IT HAS EXACTLY ONE JOB LEFT, AND IT IS NOT THE UNCONFIGURED CASE. Since the\n// bundled world basemap landed, an unconfigured widget renders a REAL MapLibre map\n// against public-domain geometry \u2014 so this panel is reached only when the map could\n// not be BUILT at all. Three ways in, not one: the MapLibre chunk fails to load, the\n// bundled-geometry chunk fails to load, or the Map constructor throws (a browser or a\n// context with no usable WebGL). They share a catch because they share an answer.\n//\n// It survives because on that path it is strictly better than an error box. The\n// question a map widget answers is \"where is my fleet, relative to each other\",\n// and this still answers it when the renderer cannot load. That is also why\n// projectToPanel exists at all, and why deleting either would look like tidying up\n// dead code right until someone's dashboard went blank behind a proxy.\nfunction PlainPanel({ positions, note }: { positions: PlaceableLocation[]; note: string }) {\n const points = projectToPanel(positions);\n return (\n <div\n data-testid=\"map-plain-panel\"\n style={{\n position: 'relative',\n width: '100%',\n height: '100%',\n overflow: 'hidden',\n background: css('muted'),\n }}\n >\n {positions.map((position, i) => (\n <Marker\n key={position.deviceToken}\n position={position}\n style={{\n position: 'absolute',\n left: `${points[i].x * 100}%`,\n top: `${points[i].y * 100}%`,\n transform: 'translate(-50%, -50%)',\n }}\n />\n ))}\n <div\n data-testid=\"map-no-tiles-note\"\n style={{\n position: 'absolute',\n left: 0,\n right: 0,\n bottom: 0,\n padding: '4px 8px',\n fontSize: fontVar('sm'),\n lineHeight: 1.3,\n textAlign: 'center',\n color: css('muted-foreground'),\n background: css('card'),\n opacity: 0.9,\n }}\n >\n {note}\n </div>\n </div>\n );\n}\n\n// ---- The map ----------------------------------------------------------------\n\ntype MapStatus = 'loading' | 'ready' | 'unavailable';\n\n// LiveMap renders MapLibre for BOTH basemap states.\n//\n// The branch is over the STYLE, not over whether there is a map: a configured tile\n// source gets a raster style, and no tile source gets the bundled public-domain\n// world. Everything downstream of that \u2014 the projection, the markers, the fit, the\n// teardown \u2014 is the same code on both paths, which is the point. When the two were\n// different components, \"unconfigured\" was a second rendering path that could drift\n// away from the real one without any test noticing.\n// `runtime` is a required prop rather than a context read, so that LiveMap cannot be\n// constructed without one. The null case is handled once, in MapWidget, and this\n// component never has to reason about it.\nfunction LiveMap({\n basemap,\n positions,\n runtime,\n}: {\n basemap: { tileUrl: string; attribution: string | null } | null;\n positions: PlaceableLocation[];\n runtime: MapRuntime;\n}) {\n const containerRef = useRef<HTMLDivElement>(null);\n const mapRef = useRef<MapLibreMap | null>(null);\n const markersRef = useRef<MapLibreMarker[]>([]);\n const [status, setStatus] = useState<MapStatus>('loading');\n\n const tileUrl = basemap?.tileUrl ?? null;\n const attribution = basemap?.attribution ?? null;\n\n // Init + teardown for this basemap. Re-runs when the source changes, which is the\n // only thing that invalidates the style.\n useEffect(() => {\n let cancelled = false;\n setStatus('loading');\n\n // \uD83D\uDD34 The bundled style is FETCHED, not built inline: its geometry sits behind a\n // dynamic import so a configured viewer never downloads a world map they will\n // not look at. Resolved alongside the renderer so the Map is still constructed\n // once, with its final style \u2014 nothing re-styles after mount.\n Promise.all([\n loadMapLibre(runtime),\n tileUrl ? rasterStyleFor(tileUrl, attribution ?? undefined) : loadLandStyle(),\n ])\n .then(([maplibre, style]) => {\n const el = containerRef.current;\n if (cancelled || !el) return;\n const map = new maplibre.Map({\n container: el,\n style: style as never,\n center: [0, 0],\n zoom: 1,\n });\n mapRef.current = map;\n setStatus('ready');\n })\n .catch(() => {\n // The renderer or the bundled geometry could not be fetched (offline viewer,\n // a CSP that blocks the chunk). Fall back to the plain panel rather than to\n // nothing: the positions are what the operator came for, and the basemap is\n // the part that failed.\n if (!cancelled) setStatus('unavailable');\n });\n\n return () => {\n cancelled = true;\n for (const marker of markersRef.current) marker.remove();\n markersRef.current = [];\n mapRef.current?.remove();\n mapRef.current = null;\n };\n // \uD83D\uDD34 Keyed on runtime.workerUrl, NOT on `runtime`. A host that builds the runtime\n // inline in JSX hands a new object every render; depending on the object would tear the\n // map down and rebuild it each time, which looks like flicker and loses view state. The\n // URL is the only part of it this effect's outcome depends on.\n //\n // `runtime.loadStyles` is used inside and is deliberately not a dependency: loadMapLibre\n // memoizes at module scope, first caller wins, so only the first runtime's loader is\n // ever invoked and a later one could not take effect however this array were written.\n // That is the documented contract, not an oversight \u2014 and no eslint config in this repo\n // lints packages/*, so a disable comment here would suppress nothing and merely look\n // like the question had been settled by a linter.\n }, [tileUrl, attribution, runtime.workerUrl]);\n\n // Sync the markers to the current positions. Rebuilt wholesale rather than diffed:\n // a poll delivers a whole snapshot, the marker count is a dashboard's worth of\n // devices, and a diff here would be state to get wrong for no measurable saving.\n useEffect(() => {\n const map = mapRef.current;\n if (status !== 'ready' || !map) return;\n\n let live = true;\n loadMapLibre(runtime).then((maplibre) => {\n if (!live || mapRef.current !== map) return;\n for (const marker of markersRef.current) marker.remove();\n markersRef.current = positions.map((position) => {\n const el = document.createElement('div');\n el.setAttribute('data-testid', 'map-marker');\n el.setAttribute('data-device', position.deviceToken);\n el.setAttribute('title', describePosition(position));\n el.setAttribute('aria-label', describePosition(position));\n Object.assign(el.style, MARKER_DOT_STYLE);\n // \uD83D\uDD34 setLngLat takes [LONGITUDE, LATITUDE] \u2014 x before y, the opposite order\n // from how a coordinate is spoken and written everywhere else on the platform.\n // Swapping them puts a device reporting Atlanta into the Indian Ocean, which\n // renders perfectly.\n return new maplibre.Marker({ element: el })\n .setLngLat([position.longitude, position.latitude])\n .addTo(map);\n });\n\n if (positions.length === 1) {\n map.jumpTo({ center: [positions[0].longitude, positions[0].latitude], zoom: SINGLE_DEVICE_ZOOM });\n } else if (positions.length > 1) {\n const bounds = new maplibre.LngLatBounds();\n for (const p of positions) bounds.extend([p.longitude, p.latitude]);\n map.fitBounds(bounds, { padding: 40, animate: false });\n }\n });\n\n return () => {\n live = false;\n };\n // Positions are compared by VALUE: a poll hands back a fresh array every tick, and\n // rebuilding every marker 4 times a minute for an unchanged fleet would make the\n // markers flicker.\n }, [status, positionsKey(positions)]);\n\n if (status === 'unavailable') {\n return (\n <PlainPanel\n positions={positions}\n note=\"Map renderer unavailable \u2014 positions are shown without a basemap.\"\n />\n );\n }\n\n return <div ref={containerRef} data-testid=\"map-canvas\" style={{ width: '100%', height: '100%' }} />;\n}\n\n// positionsKey is the value identity of a marker set: what is drawn, not which array\n// object carries it.\nfunction positionsKey(positions: PlaceableLocation[]): string {\n return positions.map((p) => `${p.deviceToken}:${p.latitude}:${p.longitude}:${p.heading ?? ''}`).join('|');\n}\n\n// ---- Shared bits ------------------------------------------------------------\n\nconst MARKER_DOT_STYLE = {\n width: '12px',\n height: '12px',\n borderRadius: '50%',\n background: css('primary'),\n border: `2px solid ${css('card')}`,\n boxShadow: '0 0 0 1px rgba(0,0,0,0.25)',\n cursor: 'default',\n} as const;\n\n// Marker is the tile-less panel's dot. The tiled map builds an equivalent element\n// imperatively (MapLibre owns the DOM its markers live in), which is why the styling is\n// shared as an object rather than as a component.\nfunction Marker({\n position,\n style,\n}: {\n position: PlaceableLocation;\n style: CSSProperties;\n}) {\n const label = describePosition(position);\n return (\n <div\n data-testid=\"map-marker\"\n data-device={position.deviceToken}\n title={label}\n aria-label={label}\n style={{ ...MARKER_DOT_STYLE, ...style }}\n />\n );\n}\n\n// MapNotice is the widget's non-map state: permission, loading, empty. One component so\n// the three read as siblings \u2014 a viewer should be able to tell them apart by their words,\n// not by their layout.\nfunction MapNotice({ glyph, heading, detail }: { glyph?: string; heading: string; detail?: string }) {\n return (\n <div\n style={{\n display: 'flex',\n flexDirection: 'column',\n alignItems: 'center',\n justifyContent: 'safe center',\n overflow: 'hidden',\n gap: 4,\n width: '100%',\n height: '100%',\n boxSizing: 'border-box',\n textAlign: 'center',\n color: css('muted-foreground'),\n }}\n >\n {glyph ? (\n <div style={{ fontSize: fontVar('xl'), lineHeight: 1 }} aria-hidden=\"true\">\n {glyph}\n </div>\n ) : null}\n <div style={{ fontSize: fontVar('md'), fontWeight: 600 }}>{heading}</div>\n {detail ? <div style={{ fontSize: fontVar('sm'), opacity: 0.8 }}>{detail}</div> : null}\n </div>\n );\n}\n\n// The registration: this widget's portable descriptor paired with its component, declared\n// through the same public `defineWidget` a third-party package uses.\nexport const mapWidget = defineWidget({\n descriptor: builtinWidgetDescriptors['map'],\n implementation: { kind: 'trusted-react', component: MapWidget },\n});\n", "// Copyright The DeviceChain Authors\n// SPDX-License-Identifier: Apache-2.0\n\n// The tenant basemap, threaded to map widgets as ambient environment (ADR-079).\n//\n// \uD83D\uDD34 Why context rather than a new field on WidgetProps. A widget is contractually a\n// pure function of (widget, data): the props carry what the widget SHOWS. A tenant's\n// tile source is not data \u2014 it is environment, like the theme \u2014 and putting it in the\n// props would change the contract for all fifteen widgets to serve one of them.\n//\n// The default is null, deliberately. A host that installs no provider (widgetlab, the\n// synthetic preview, every existing test) behaves exactly as before: the map falls\n// back to its per-widget options, and to a plain panel when it has none. Adding the\n// provider is what turns a tenant's configured basemap on; nothing breaks without it.\n\nimport { createContext, useContext, type ReactNode } from 'react';\nimport type { Basemap } from '@devicechain/client';\n\nconst TenantBasemapContext = createContext<Basemap | null>(null);\n\n/**\n * Supplies the tenant's effective basemap to every map widget beneath it.\n *\n * Both hosts install this ONCE, high in the tree, rather than at each place they\n * render a widget: the console from its TenantProvider, the /dash viewer app from the\n * one place it mounts a DashboardRenderer.\n *\n * \uD83D\uDD34 That placement is the whole safety argument, because a host that forgets this\n * does NOT fail loudly \u2014 its maps simply render as they did before the tenant setting\n * existed, on that surface only. Wrapping individual render sites is the version that\n * silently half-works; there is no render site to forget from the top of the tree.\n */\nexport function TenantBasemapProvider({\n basemap,\n children,\n}: {\n basemap: Basemap | null;\n children: ReactNode;\n}) {\n return <TenantBasemapContext.Provider value={basemap}>{children}</TenantBasemapContext.Provider>;\n}\n\n/**\n * The tenant's effective basemap, or null when no host supplied one.\n *\n * Null means \"no tenant basemap in force\" \u2014 either the host installs no provider, or\n * neither the tenant nor the operator has configured one. Both cases resolve the same\n * way downstream (fall back to the per-widget override, then to a plain panel), so\n * callers do not need to distinguish them.\n */\nexport function useTenantBasemap(): Basemap | null {\n return useContext(TenantBasemapContext);\n}\n", "// Copyright The DeviceChain Authors\n// SPDX-License-Identifier: Apache-2.0\n\n// The map runtime: the pieces of MapLibre that only the HOST'S BUNDLER can produce.\n//\n// \uD83D\uDD34 WHY THIS EXISTS AT ALL. MapLibre parses tiles and geometry off the main thread, and\n// left to itself it derives the worker's URL at runtime from its own module URL \u2014\n// `new URL('./maplibre-gl-worker.mjs', import.meta.url)`. That is a string no bundler can\n// follow, so nothing emits the file, the browser resolves it to a 404, and `new Worker()`\n// does not throw on one: the failure arrives later as an async error event. The map builds,\n// type-checks, passes every test, and renders nothing.\n//\n// The only thing that can emit that file is the application's own bundler, using its own\n// dialect \u2014 Vite spells it `?worker&url`, webpack and Rollup each spell it differently.\n// So the URL is something a HOST computes and a LIBRARY cannot.\n//\n// \uD83D\uDD34 THIS PACKAGE USED TO WRITE VITE'S DIALECT ITSELF, and that is the defect this seam\n// removes. A published library containing `import('\u2026?worker&url')` works under a consumer's\n// Vite and silently renders a blank map under anything else \u2014 and because the specifier is\n// externalized, no bundler ever tries to resolve it, so NOTHING IN ANY BUILD REPORTS IT.\n// A green pipeline over a broken artifact is strictly worse than a red one.\n//\n// \u26A0\uFE0F HOW THIS DIFFERS FROM TenantBasemapProvider, which sits beside it and looks alike.\n// The basemap provider is OPTIONAL BY DESIGN: a host that installs none behaves exactly as\n// it did before the tenant setting existed, and that is a coherent state. This one is\n// REQUIRED, and a host that omits it gets a loud notice rather than a map. The asymmetry is\n// deliberate and is the whole point: a missing basemap is a configuration a viewer can read\n// off the screen, while a missing worker URL is invisible \u2014 it is the blank map above.\n// Copying the basemap's optional-by-default shape here would relocate that defect into\n// every unwired host instead of removing it.\n\nimport { createContext, useContext, type ReactNode } from 'react';\n\n/**\n * The bundler-produced runtime a map widget needs from its host.\n *\n * `workerUrl` is the emitted, host-resolvable URL of MapLibre's worker entry\n * (`maplibre-gl/dist/maplibre-gl-worker.mjs`). It is handed to MapLibre's `setWorkerUrl`\n * before the first `Map` is constructed.\n *\n * `loadStyles` is OPTIONAL, and imports MapLibre's stylesheet\n * (`maplibre-gl/dist/maplibre-gl.css`). Omit it and import the stylesheet yourself, the way\n * every map library asks you to \u2014 that is the ordinary path and nothing here second-guesses\n * it. Supplying it buys one thing: the CSS rides the renderer's lazy chunk instead of your\n * main stylesheet, which is worth **83 KB raw / 10.7 KB gzipped** to a viewer who never\n * opens a board with a map on it.\n *\n * \uD83D\uDD34 The size is measured against maplibre-gl 6.6.0, the version this package peers on. An\n * earlier draft said 70 KB \"measured, not estimated\" \u2014 measured, but against a stale\n * `node_modules` carrying 6.2.0. Measuring the right thing in the wrong tree reads exactly\n * like measuring, which is why the version is named here.\n *\n * \uD83D\uDD34 It is a FUNCTION rather than a boolean or a URL because the host's bundler owns its\n * CSS pipeline: only the host can say \"load this, lazily, your way\".\n */\nexport type MapRuntime = {\n workerUrl: string;\n loadStyles?: () => Promise<unknown>;\n};\n\nconst MapRuntimeContext = createContext<MapRuntime | null>(null);\n\n/**\n * Supplies the host's MapLibre runtime to every map widget beneath it.\n *\n * Install it ONCE, high in the tree, next to TenantBasemapProvider \u2014 the console from its\n * TenantProvider, the /dash viewer from the one place it mounts a DashboardRenderer.\n *\n * \uD83D\uDD11 ON VITE, DO NOT WRITE ANY OF THIS \u2014 import the ready-made runtime:\n *\n * ```tsx\n * import { viteMapRuntime } from '@devicechain/widgets/vite';\n *\n * <MapRuntimeProvider runtime={viteMapRuntime}>{children}</MapRuntimeProvider>\n * ```\n *\n * On any other bundler you supply the URL yourself, and there is ONE REQUIREMENT that\n * decides whether it works: MapLibre loads the URL as a MODULE worker, so whatever it\n * serves must be a module with no unresolved imports left in it.\n * `maplibre-gl/dist/maplibre-gl-worker.mjs` does not satisfy that on its own \u2014 its first\n * line is `import \u2026 from './maplibre-gl-shared.mjs'`.\n *\n * \uD83D\uDD34 SO DO NOT POINT AT A VERBATIM COPY OF THE WORKER FILE, and in particular do not\n * reach for `new URL('maplibre-gl/dist/maplibre-gl-worker.mjs', import.meta.url)`. That\n * looks exactly right and is wrong: webpack treats the target as an ASSET and copies it,\n * the sibling is never emitted, and the worker dies on its own first line. Measured\n * against webpack 5, from a packed tarball: the worker URL answered 200, both maps drew\n * canvases, all markers appeared, tiles loaded, THE BUILD EXITED 0 AND THE CONSOLE WAS\n * EMPTY \u2014 and the bundled basemap rendered ocean with no land on it.\n *\n * Two recipes that were measured working, in `hack/consumer-proof`:\n *\n * ```js\n * // webpack \u2014 make the worker a second ENTRY, so its imports are bundled into it.\n * entry: { main: './src/index.tsx', 'maplibre-worker': 'maplibre-gl/dist/maplibre-gl-worker.mjs' }\n * // \u2026then: <MapRuntimeProvider runtime={{ workerUrl: '/maplibre-worker.js' }}>\n * ```\n *\n * ```js\n * // any bundler, or none \u2014 copy the worker AND ITS SIBLING, under their own names,\n * // into one served directory: maplibre-gl-worker.mjs + maplibre-gl-shared.mjs\n * // \u2026then: <MapRuntimeProvider runtime={{ workerUrl: '/vendor/maplibre-gl-worker.mjs' }}>\n * ```\n *\n * \uD83D\uDD34 Hold the runtime in a MODULE CONSTANT, as above, rather than building it inline in\n * JSX. An object literal in the element is a new identity on every render, and while the\n * widget deliberately keys its effects on `workerUrl` rather than on the object to survive\n * that, a host that also passes it anywhere keyed on identity would tear down and rebuild\n * the map on every parent render. There is nothing per-render in it to justify the risk.\n *\n * \uD83D\uDD34 `maplibre-gl` is a PEER dependency of this package precisely so that the copy the host\n * takes the worker from is the same copy this package renders with. A worker built from one\n * version driving a main thread from another is the blank map again, by a different route.\n */\nexport function MapRuntimeProvider({\n runtime,\n children,\n}: {\n runtime: MapRuntime;\n children: ReactNode;\n}) {\n return <MapRuntimeContext.Provider value={runtime}>{children}</MapRuntimeContext.Provider>;\n}\n\n/**\n * The host's map runtime, or null when no host supplied one.\n *\n * \uD83D\uDD34 Callers MUST treat null as a refusal to render a map, not as a default to paper over.\n * There is no sensible fallback: the only alternative to a host-supplied URL is MapLibre's\n * own runtime derivation, which is the broken behaviour this seam exists to prevent.\n */\nexport function useMapRuntime(): MapRuntime | null {\n return useContext(MapRuntimeContext);\n}\n", "// Copyright The DeviceChain Authors\n// SPDX-License-Identifier: Apache-2.0\n\n// The map widget's pure parts: which samples are placeable, where they land on a\n// tile-less panel, and how a fix is described in words.\n//\n// Split out from the component for the usual reason the chart-option builders are \u2014\n// this is the arithmetic that decides whether a marker is in the right place, and it is\n// worth an awful lot more when it can be asserted directly than when it can only be\n// inferred from a rendered `style` string.\n\nimport type { LocationSample } from '@devicechain/dashboards';\n\n// A sample that actually has coordinates. A LocationSample's latitude/longitude are\n// nullable (the projection's columns are), and a sample missing either is not a\n// position \u2014 placing it would put a marker at (0, 0) in the Gulf of Guinea and label it\n// with a real device's name.\nexport interface PlaceableLocation extends LocationSample {\n latitude: number;\n longitude: number;\n}\n\n// placeable keeps the samples that can be drawn.\n//\n// `!= null`, NOT truthiness: latitude 0 is the equator and longitude 0 is Greenwich,\n// and both are real reported positions. A truthy filter would silently drop a device\n// sitting on either line.\nexport function placeable(samples: readonly LocationSample[]): PlaceableLocation[] {\n return samples.filter(\n (s): s is PlaceableLocation => s.latitude != null && s.longitude != null,\n );\n}\n\n// A point on the tile-less panel, as a FRACTION of its width/height, so the component\n// can express it as a percentage and stay resolution-independent.\nexport interface PanelPoint {\n x: number;\n y: number;\n}\n\n// Fraction of the panel kept clear at each edge, so a marker at the extreme of the\n// bounding box sits inside the panel rather than half-clipped by it.\nconst PANEL_PADDING = 0.1;\n\n// projectToPanel lays a set of positions out on a plain (tile-less) panel.\n//\n// An equirectangular fit of the positions' own bounding box: longitude \u2192 x, latitude \u2192\n// y, each stretched across the padded panel. Deliberately NOT a web-mercator\n// projection \u2014 without a basemap there is nothing to align to, so the only job is to\n// show the relative arrangement of a fleet truthfully, and at the extent of a site or a\n// city the difference between the two is invisible. (With a tile source the widget uses\n// MapLibre's real projection instead; this function is never asked to agree with one.)\n//\n// \uD83D\uDD34 THE AXES ARE NOT INTERCHANGEABLE, AND THE Y AXIS IS INVERTED. Longitude is\n// east-west (x); latitude is north-south (y); and screen y grows DOWNWARD while\n// latitude grows northward, so the maximum latitude maps to y = 0. Swap the two and\n// every marker still lands inside the panel, in a plausible-looking scatter \u2014 the\n// output stays well-formed, which is exactly why this is asserted directly rather than\n// eyeballed.\n//\n// A degenerate axis (one device, or several at the same latitude) has no span to\n// stretch across, so it centres on that axis rather than dividing by zero.\nexport function projectToPanel(positions: readonly PlaceableLocation[]): PanelPoint[] {\n if (positions.length === 0) return [];\n\n let minLat = Infinity;\n let maxLat = -Infinity;\n let minLon = Infinity;\n let maxLon = -Infinity;\n for (const p of positions) {\n if (p.latitude < minLat) minLat = p.latitude;\n if (p.latitude > maxLat) maxLat = p.latitude;\n if (p.longitude < minLon) minLon = p.longitude;\n if (p.longitude > maxLon) maxLon = p.longitude;\n }\n\n const lonSpan = maxLon - minLon;\n const latSpan = maxLat - minLat;\n const scale = 1 - 2 * PANEL_PADDING;\n\n return positions.map((p) => ({\n x: PANEL_PADDING + scale * (lonSpan === 0 ? 0.5 : (p.longitude - minLon) / lonSpan),\n // maxLat at the TOP: screen y grows downward, latitude grows northward.\n y: PANEL_PADDING + scale * (latSpan === 0 ? 0.5 : (maxLat - p.latitude) / latSpan),\n }));\n}\n\n// Coordinates are WGS84 decimal degrees platform-wide. Six decimal places is ~0.1 m at\n// the equator \u2014 finer than any consumer receiver \u2014 and fixed notation stops a small\n// value rendering in exponential form. Matches the device-detail position panel, so the\n// same fix reads identically in both places.\nexport function formatDegrees(value: number): string {\n return value.toFixed(6);\n}\n\n// describePosition renders one fix as a marker's hover/screen-reader text.\n//\n// \uD83D\uDD34 IT REPORTS ONLY WHAT THE DEVICE REPORTED. Elevation, accuracy, speed and heading\n// are each optional, and an absent one contributes NO SEGMENT at all \u2014 it is never\n// filled in with a zero. A marker reading \"0\u00B0\" claims the device reported due north; a\n// marker with no heading segment claims nothing, which is the truth. Every test is\n// `!= null`, so a genuine 0 (parked, sea level, due north) is still shown.\n//\n// Units are fixed platform-wide: metres, metres per second, degrees clockwise from true\n// north.\nexport function describePosition(sample: PlaceableLocation): string {\n const parts: string[] = [\n sample.deviceToken,\n `${formatDegrees(sample.latitude)}, ${formatDegrees(sample.longitude)}`,\n ];\n if (sample.elevation != null) parts.push(`${sample.elevation} m`);\n if (sample.accuracy != null) parts.push(`\u00B1${sample.accuracy} m`);\n if (sample.speed != null) parts.push(`${sample.speed} m/s`);\n if (sample.heading != null) parts.push(`${sample.heading}\u00B0`);\n return parts.join(' \u00B7 ');\n}\n\n// rasterStyleFor builds the MapLibre style document for a user-supplied raster tile\n// source.\n//\n// \uD83D\uDD34 THIS PACKAGE HARDCODES NO TILE SOURCE, AND THAT IS A DECISION RATHER THAN AN\n// OMISSION. The library is not the map \u2014 the TILES are, and they carry their own terms,\n// so a widget library is the wrong place to choose a provider on an operator's behalf.\n// The URL arrives as config, and with none set the widget falls back to the BUNDLED\n// world basemap below \u2014 public-domain geometry compiled into this package, which asks\n// no host for anything and so adopts nobody's terms. That is the distinction the rule\n// is actually about: not \"ship no map\", but \"make no request on an operator's behalf\n// to a host they never chose\".\n//\n// The PLATFORM does ship a default (ADR-079): an instance-wide setting a tenant can\n// override, which a board then inherits when its own options name nothing. That is a\n// named, visible, replaceable choice made once by an operator \u2014 a different thing from\n// this module quietly baking a host into every build of the library.\n//\n// `attribution` is passed to the source rather than hidden: a tile source's licence\n// commonly REQUIRES visible credit, so it is a property of the data, not decoration a\n// host may strip.\nexport function rasterStyleFor(tileUrl: string, attribution: string | undefined): unknown {\n return {\n version: 8,\n projection: PROJECTION,\n sources: {\n basemap: {\n type: 'raster',\n tiles: [tileUrl],\n tileSize: 256,\n ...(attribution ? { attribution } : {}),\n },\n },\n layers: [{ id: 'basemap', type: 'raster', source: 'basemap' }],\n };\n}\n\n// ---- The bundled world basemap ----------------------------------------------\n\n// \uD83D\uDD34 THE PROJECTION IS THE CORRECTNESS PROPERTY OF THIS WHOLE FILE, and it is\n// declared explicitly \u2014 on BOTH styles \u2014 rather than left to the default.\n//\n// The fence editor stores the coordinates a click produces, so what a style\n// changes must be what is DRAWN and never where a click LANDS. Mercator is\n// MapLibre's default, so writing it out changes no behaviour today. What it buys\n// is that the two styles now state the same thing in the same words, and a test\n// can compare them: an invariant nobody wrote down is an invariant a later edit\n// breaks without anything going red.\n//\n// This is not hypothetical in MapLibre 6. `projection` is a root style key whose\n// `type` is a ZOOM-INTERPOLATABLE expression, so a style is entitled to hand back\n// a globe past some zoom. A globe re-projects the pointer; every ring an author\n// then drew would be saved somewhere they never pointed at, on a map that looked\n// beautiful throughout.\nconst PROJECTION = { type: 'mercator' } as const;\n\n// The bundled basemap's credit line. Natural Earth requires NO attribution \u2014 its\n// licence says in as many words that crediting the authors is unnecessary \u2014 so\n// this is their own suggested short citation, shown for a reason of ours: a\n// viewer has to be able to tell a schematic bundled world apart from a configured\n// provider, or \"no tiles\" reads as \"broken\" all over again.\nexport const BUNDLED_BASEMAP_ATTRIBUTION = 'Made with Natural Earth';\n\n// The bundled style's palette. Literal colours, not theme tokens: a MapLibre style\n// document is JSON handed to a WebGL renderer, and it does not resolve the CSS\n// custom properties the rest of this package themes with. These sit close to the\n// dark surface the fence editor already drew, so the change reads as \"the void\n// grew continents\" rather than as a new skin.\nconst OCEAN = '#0b1220';\nconst LAND = '#1e293b';\nconst BOUNDARY = '#475569';\n\n// landStyleFrom builds the bundled world style from Natural Earth geometry.\n//\n// Kept separate from the loader, and pure, so the style document can be asserted\n// without pulling 150 KiB of coordinates into a test \u2014 and so the one thing worth\n// asserting about it (that it projects exactly as the tiled style does) is\n// checkable in isolation.\nexport function landStyleFrom(land: unknown, boundaries: unknown): unknown {\n return {\n version: 8,\n projection: PROJECTION,\n sources: {\n land: { type: 'geojson', data: land, attribution: BUNDLED_BASEMAP_ATTRIBUTION },\n boundaries: { type: 'geojson', data: boundaries },\n },\n layers: [\n { id: 'ocean', type: 'background', paint: { 'background-color': OCEAN } },\n { id: 'land', type: 'fill', source: 'land', paint: { 'fill-color': LAND } },\n {\n id: 'boundaries',\n type: 'line',\n source: 'boundaries',\n paint: { 'line-color': BOUNDARY, 'line-width': 0.5 },\n },\n ],\n };\n}\n\n// loadLandStyle fetches the bundled geometry and builds its style.\n//\n// \uD83D\uDD34 THE DYNAMIC IMPORT IS THE WHOLE POINT. natural-earth-data is ~150 KiB (~44\n// KiB over the wire) and it must never enter this package's entry chunk: with a\n// tile source configured \u2014 which, since the platform ships a default provider, is\n// the ordinary case \u2014 nobody should download a world map they will not see. A\n// static `import { NATURAL_EARTH }` at the top of this file would give every\n// viewer the payload and change nothing observable, which is how it would survive\n// review.\n//\n// Memoized on the promise, so several map widgets on one board parse it once.\n//\n// \uD83D\uDD34 That memoizes a REJECTION too: one transient chunk failure leaves every\n// unconfigured map on the page falling back until a reload. Deliberate, and the same\n// bargain loadMapLibre has always made \u2014 a retry-on-failure cache would let N widgets\n// re-request a chunk that is failing for a reason retrying will not fix. Worth knowing\n// that the blast radius grew when this became the DEFAULT unconfigured path rather\n// than a rarity.\nlet landStylePromise: Promise<unknown> | undefined;\n\nexport function loadLandStyle(): Promise<unknown> {\n if (!landStylePromise) {\n landStylePromise = import('./natural-earth-data').then((mod) =>\n landStyleFrom(mod.NATURAL_EARTH.land, mod.NATURAL_EARTH.boundaries),\n );\n }\n return landStylePromise;\n}\n", "// Copyright The DeviceChain Authors\n// SPDX-License-Identifier: Apache-2.0\n\n// table \u2014 the latest value of every measurement the datasource carries, one row\n// per measurement name.\n\nimport type { CSSProperties } from 'react';\n\nimport {\n css,\n defineWidget,\n fontVar,\n spaceVar,\n FlashValue,\n formatTimestamp,\n optBoolean,\n optNumber,\n optString,\n useWidgetTimeZone,\n WidgetFrame,\n type WidgetProps,\n} from '@devicechain/widget-sdk';\n\nimport { builtinWidgetDescriptors } from '../builtin-descriptors';\n\nconst cell: CSSProperties = { padding: `${spaceVar(1)} ${spaceVar(3)}`, textAlign: 'left' };\nconst headCell: CSSProperties = {\n ...cell,\n fontSize: fontVar('xs'),\n fontWeight: 600,\n textTransform: 'uppercase',\n letterSpacing: '0.04em',\n color: css('muted-foreground'),\n borderBottom: `1px solid ${css('border')}`,\n};\n\nexport function Table({ widget, data }: WidgetProps) {\n const timeZone = useWidgetTimeZone();\n const rows = Object.values(data.latest).sort((a, b) => a.name.localeCompare(b.name));\n // Round to a fixed number of decimals when configured; unset keeps the raw value\n // (formatValue's default). A live sensor value is otherwise a wall of digits.\n const precision = optNumber(widget.options, 'precision');\n // Opt-in directional flash per row (keyed by measurement name, so each value's cue is\n // independent \u2014 see FlashValue).\n const flash = optBoolean(widget.options, 'flashOnChange');\n\n return (\n <WidgetFrame title={optString(widget.options, 'title')} flush>\n <div style={{ height: '100%', overflow: 'auto' }}>\n <table style={{ width: '100%', borderCollapse: 'collapse', fontSize: fontVar('md'), color: css('foreground') }}>\n <thead>\n <tr>\n <th style={headCell}>Measurement</th>\n <th style={headCell}>Value</th>\n <th style={headCell}>Time</th>\n </tr>\n </thead>\n <tbody>\n {rows.length === 0 ? (\n <tr>\n <td colSpan={3} style={{ ...cell, textAlign: 'center', color: css('muted-foreground') }}>\n No data yet\n </td>\n </tr>\n ) : (\n rows.map((row) => (\n <tr key={row.name}>\n <td style={cell}>{row.name}</td>\n <td style={{ ...cell, fontVariantNumeric: 'tabular-nums' }}>\n <FlashValue\n value={row.value}\n precision={precision}\n enabled={flash}\n identity={`${row.deviceToken}:${row.name}`}\n />\n {/* classifier is deliberately NOT shown: it is the bound metric\n definition's internal id (ADR-016), not a user-facing label \u2014\n appending it rendered as spurious digits after the value. */}\n </td>\n <td style={{ ...cell, color: css('muted-foreground') }}>{formatTimestamp(row.occurredTime, timeZone)}</td>\n </tr>\n ))\n )}\n </tbody>\n </table>\n </div>\n </WidgetFrame>\n );\n}\n\n// The registration: this widget's portable descriptor paired with its component, declared\n// through the same public `defineWidget` a third-party package uses.\nexport const tableWidget = defineWidget({\n descriptor: builtinWidgetDescriptors['table'],\n implementation: { kind: 'trusted-react', component: Table },\n});\n", "// Copyright The DeviceChain Authors\n// SPDX-License-Identifier: Apache-2.0\n\n// timeseries-chart \u2014 a live line chart of the rolling measurement window, one\n// series per measurement name. The window is seeded from bucketedMeasurements\n// history (via useMeasurementStream's initialSamples) and extended by the live tail.\n\nimport { useMemo } from 'react';\n\nimport { isValidSpanSeconds, spanLabel } from '@devicechain/dashboards';\nimport {\n css,\n defineWidget,\n fontVar,\n formatDateTime,\n formatTimestamp,\n optNumber,\n optString,\n optThresholds,\n spaceVar,\n useWidgetScale,\n useWidgetTimeRange,\n useWidgetTimeZone,\n viewerLocale,\n WidgetFrame,\n type MeasurementStreamState,\n type WidgetProps,\n} from '@devicechain/widget-sdk';\nimport { buildLineOption, EChart, useChartTheme } from '@devicechain/widget-sdk/echarts';\n\nimport { builtinWidgetDescriptors } from '../builtin-descriptors';\n\nexport function TimeSeriesChart({ widget, data }: WidgetProps) {\n return (\n <WidgetFrame title={optString(widget.options, 'title')} flush>\n <TimeSeriesBody widget={widget} data={data} />\n </WidgetFrame>\n );\n}\n\n// Rendered INSIDE the frame: the widget scale is the frame's content column, which is only in\n// context below the frame.\nfunction TimeSeriesBody({ widget, data }: WidgetProps) {\n const theme = useChartTheme();\n const { size, scale } = useWidgetScale();\n\n const measurements = widget.datasource?.measurements;\n const unit = optString(widget.options, 'unit');\n const precision = optNumber(widget.options, 'precision');\n const thresholds = useMemo(() => optThresholds(widget.options, 'thresholds'), [widget.options]);\n const option = useMemo(\n () => buildLineOption(data.samples, theme, { measurements, unit, precision, thresholds, scale }, size),\n [data.samples, theme, measurements, unit, precision, thresholds, scale, size],\n );\n\n return (\n <div style={{ position: 'relative', width: '100%', height: '100%' }}>\n <EChart option={option} />\n <SpanBadge widget={widget} data={data} />\n </div>\n );\n}\n\n// The words the span badge prints. The widget packages carry no i18n runtime (see level-strings).\nconst SPAN_STRINGS = {\n en: {\n from: (time: string) => `from ${time}`,\n pinned: (span: string) => `Pinned to ${span}: the board's time range does not apply to this chart.`,\n cut: (time: string, span: string) =>\n `Showing from ${time}, not the whole ${span}: older samples were dropped to bound memory.`,\n },\n es: {\n from: (time: string) => `desde ${time}`,\n pinned: (span: string) => `Fijado a ${span}: el intervalo de tiempo del panel no se aplica a este gr\u00E1fico.`,\n cut: (time: string, span: string) =>\n `Se muestra desde ${time}, no todo el intervalo de ${span}: se descartaron las muestras m\u00E1s antiguas para acotar la memoria.`,\n },\n};\n\nconst DAY_MS = 86_400_000;\n\n// SpanBadge says what span the chart draws whenever the board's header would say something else:\n// - a chart PINNED to its own span (`windowSeconds`) ignores the viewer's range pick, so under a\n// \"24h\" header a pinned hour would read as a day of data. It prints its own span (\"1h\").\n// - a window the retention ceiling cut (`truncatedBefore`) covers less than its span. It prints\n// where it starts (\"from 14:03\"), so a short window never passes for the whole range.\n// Nothing shows when the chart draws exactly the board's range, or off a board (no header).\nfunction SpanBadge({ widget, data }: { widget: WidgetProps['widget']; data: MeasurementStreamState }) {\n const range = useWidgetTimeRange();\n const timeZone = useWidgetTimeZone();\n const pinned = optNumber(widget.options, 'windowSeconds');\n const span = isValidSpanSeconds(pinned) ? pinned : range?.spanSeconds;\n const showSpan = range !== undefined && span !== range.spanSeconds;\n const cutAt = data.truncatedBefore;\n if (!showSpan && !cutAt) return null;\n\n const words = viewerLocale()?.toLowerCase().startsWith('es') ? SPAN_STRINGS.es : SPAN_STRINGS.en;\n const label = span === undefined ? '' : spanLabel(span);\n // A start more than a day back prints its date, or \"from 09:14\" would name the wrong day.\n const end = range?.paused && range.pausedAt !== undefined ? range.pausedAt : Date.now();\n const time = cutAt\n ? end - Date.parse(cutAt) > DAY_MS\n ? formatDateTime(cutAt, timeZone)\n : formatTimestamp(cutAt, timeZone)\n : '';\n const text = [showSpan ? label : '', cutAt ? words.from(time) : ''].filter(Boolean).join(' \u00B7 ');\n const title = [showSpan ? words.pinned(label) : '', cutAt ? words.cut(time, label) : ''].filter(Boolean).join(' ');\n return (\n <span\n data-chart-span={showSpan ? label : ''}\n data-chart-truncated={cutAt ? '' : undefined}\n title={title}\n style={{\n position: 'absolute',\n top: spaceVar(1),\n right: spaceVar(2),\n padding: `0 ${spaceVar(1)}`,\n fontSize: fontVar('xs'),\n whiteSpace: 'nowrap',\n color: css('muted-foreground'),\n background: css('muted'),\n borderRadius: 4,\n pointerEvents: 'auto',\n }}\n >\n {text}\n </span>\n );\n}\n\n// The registration: this widget's portable descriptor paired with its component, declared\n// through the same public `defineWidget` a third-party package uses.\nexport const timeSeriesChartWidget = defineWidget({\n descriptor: builtinWidgetDescriptors['timeseries-chart'],\n implementation: { kind: 'trusted-react', component: TimeSeriesChart },\n});\n", "// Copyright The DeviceChain Authors\n// SPDX-License-Identifier: Apache-2.0\n\nimport type { WidgetRegistry } from '@devicechain/widget-sdk';\n\nimport { createBuiltinWidgetRegistry } from './builtin-registry';\n\n// The registry a renderer uses when its host passes none: the built-ins, built once per\n// module instance. A registry is sealed and immutable, so sharing this one default between\n// hosts carries no state \u2014 a host with extension packages passes its own.\nlet builtin: WidgetRegistry | undefined;\n\nexport function defaultWidgetRegistry(): WidgetRegistry {\n builtin ??= createBuiltinWidgetRegistry();\n return builtin;\n}\n", "// Copyright The DeviceChain Authors\n// SPDX-License-Identifier: Apache-2.0\n\n// Per-widget failure containment. Every widget implementation renders inside its own error\n// boundary: a component that throws shows a local diagnostic with a reset control while its\n// siblings keep rendering, and a host callback that rejects (an action, a candidate lookup)\n// is surfaced on the widget that made the call instead of vanishing into an unhandled\n// rejection. An error boundary cannot contain an infinite loop or hostile same-page code;\n// trusted package installation remains the operator's responsibility.\n\nimport { Component, createContext, useCallback, useContext, useState, type ReactNode } from 'react';\n\nimport { WidgetFrame } from '@devicechain/widget-sdk';\nimport { describeError, type ReportRejection } from './widget-host';\n\nconst MESSAGE_STYLE = {\n display: 'flex',\n flexDirection: 'column',\n alignItems: 'center',\n justifyContent: 'center',\n gap: 4,\n width: '100%',\n height: '100%',\n padding: 12,\n boxSizing: 'border-box',\n textAlign: 'center',\n color: 'hsl(var(--muted-foreground))',\n} as const;\n\nconst BUTTON_STYLE = {\n marginTop: 4,\n fontSize: 11,\n padding: '2px 8px',\n cursor: 'pointer',\n} as const;\n\n// The reporter a body uses for async host callbacks. A no-op outside a containment, so a\n// component rendered on its own never needs one.\nconst ReportContext = createContext<ReportRejection>(() => {});\n\nexport function useReportRejection(): ReportRejection {\n return useContext(ReportContext);\n}\n\ninterface BoundaryProps {\n title?: string;\n // Changes when the widget's stored configuration changes, so an edit retries a widget\n // that threw on the old one.\n resetKey: string;\n onReset: () => void;\n children: ReactNode;\n}\n\ninterface BoundaryState {\n error: { message: string } | null;\n resetKey: string;\n}\n\nclass WidgetErrorBoundary extends Component<BoundaryProps, BoundaryState> {\n state: BoundaryState = { error: null, resetKey: this.props.resetKey };\n\n static getDerivedStateFromError(error: unknown): Partial<BoundaryState> {\n return { error: { message: describeError(error) } };\n }\n\n static getDerivedStateFromProps(props: BoundaryProps, state: BoundaryState): Partial<BoundaryState> | null {\n if (props.resetKey === state.resetKey) return null;\n return { error: null, resetKey: props.resetKey };\n }\n\n private reset = (): void => {\n this.props.onReset();\n this.setState({ error: null });\n };\n\n render(): ReactNode {\n const { error } = this.state;\n if (!error) return this.props.children;\n return (\n <WidgetFrame title={this.props.title}>\n <div style={MESSAGE_STYLE} role=\"alert\">\n <div style={{ fontSize: 20, lineHeight: 1 }} aria-hidden=\"true\">\n \u26A0\n </div>\n <div style={{ fontSize: 13, fontWeight: 600 }}>This widget failed to render</div>\n <div style={{ fontSize: 11, opacity: 0.8, wordBreak: 'break-word' }}>{error.message}</div>\n <button type=\"button\" style={BUTTON_STYLE} onClick={this.reset}>\n Reset widget\n </button>\n </div>\n </WidgetFrame>\n );\n }\n}\n\nexport interface WidgetContainmentProps {\n title?: string;\n resetKey: string;\n children: ReactNode;\n}\n\n// WidgetContainment wraps ONE widget. Rejections reported by the host callbacks it hands\n// down appear in a dismissible strip over the widget's bottom edge.\nexport function WidgetContainment({ title, resetKey, children }: WidgetContainmentProps) {\n const [messages, setMessages] = useState<string[]>([]);\n const report = useCallback<ReportRejection>((message) => {\n setMessages((prev) => (prev.includes(message) ? prev : [...prev, message].slice(-3)));\n }, []);\n const clear = useCallback(() => setMessages([]), []);\n return (\n <div style={{ position: 'relative', width: '100%', height: '100%' }}>\n <ReportContext.Provider value={report}>\n <WidgetErrorBoundary title={title} resetKey={resetKey} onReset={clear}>\n {children}\n </WidgetErrorBoundary>\n </ReportContext.Provider>\n {messages.length > 0 && (\n <div\n role=\"status\"\n style={{\n position: 'absolute',\n left: 4,\n right: 4,\n bottom: 4,\n fontSize: 11,\n padding: '2px 6px',\n borderRadius: 4,\n background: 'hsl(var(--destructive, 0 70% 45%))',\n color: 'hsl(var(--destructive-foreground, 0 0% 100%))',\n display: 'flex',\n gap: 6,\n alignItems: 'center',\n }}\n >\n <span style={{ flex: 1, wordBreak: 'break-word' }}>{messages.join(' \u00B7 ')}</span>\n <button type=\"button\" aria-label=\"Dismiss\" onClick={clear} style={{ cursor: 'pointer' }}>\n \u00D7\n </button>\n </div>\n )}\n </div>\n );\n}\n", "// Copyright The DeviceChain Authors\n// SPDX-License-Identifier: Apache-2.0\n\n// What the host hands one widget: ONLY the interactions its descriptor declares,\n// intersected with what the host supports. Declaring an interaction is a request, and this\n// narrowing is API hygiene, not a security boundary (trusted React runs with the page's\n// privileges); the server stays the authority on every write.\n\nimport type { WidgetActions, WidgetDescriptor } from '@devicechain/dashboards';\n\nimport { type WidgetCandidates, type WidgetSelect } from '@devicechain/widget-sdk';\n\n// Receives the message of an async host callback that rejected, so it can be shown on the\n// widget that made the call.\nexport type ReportRejection = (message: string) => void;\n\nexport function describeError(error: unknown): string {\n if (error instanceof Error) return error.message || error.name;\n return String(error);\n}\n\n// guardAsync reports a rejection to the widget's local diagnostics and rethrows it, so a\n// widget that handles the failure itself (a refusal it shows inline) still sees it.\nfunction guardAsync<A extends unknown[], R>(\n fn: (...args: A) => Promise<R>,\n report: ReportRejection,\n): (...args: A) => Promise<R> {\n return (...args: A) => {\n let pending: Promise<R>;\n try {\n pending = Promise.resolve(fn(...args));\n } catch (e) {\n report(describeError(e));\n return Promise.reject(e);\n }\n return pending.catch((e: unknown) => {\n report(describeError(e));\n throw e;\n });\n };\n}\n\nconst ALARM_AUTHORITY = 'alarm:write';\nconst COMMAND_AUTHORITY = 'command:write';\n\n// A call to an interaction the widget did not declare rejects, and the rejection is reported\n// on the widget like any other failed host callback: a widget that fires and forgets\n// (`void actions.acknowledgeAlarm(t)`) must still SHOW the refusal, not swallow it.\nfunction undeclared(capability: string, report: ReportRejection): () => Promise<never> {\n return guardAsync(\n () => Promise.reject(new Error(`this widget did not declare the ${capability} interaction`)),\n report,\n );\n}\n\n// narrowActions returns the action seam a widget may use. A widget that declares neither\n// alarm actions nor command send gets none; one that declares a subset gets the declared\n// methods working and the rest refusing loudly (never a silent no-op), and `can` denies the\n// write authorities of capabilities it did not declare.\nexport function narrowActions(\n actions: WidgetActions | undefined,\n descriptor: WidgetDescriptor,\n report: ReportRejection,\n): WidgetActions | undefined {\n if (!actions) return undefined;\n const alarm = descriptor.interactions.alarmActions === true;\n const command = descriptor.interactions.commandSend === true;\n if (!alarm && !command) return undefined;\n const narrowed: WidgetActions = {\n acknowledgeAlarm: alarm\n ? guardAsync((t) => actions.acknowledgeAlarm(t), report)\n : undeclared('alarmActions', report),\n clearAlarm: alarm ? guardAsync((t) => actions.clearAlarm(t), report) : undeclared('alarmActions', report),\n can: (authority) => {\n if (authority === ALARM_AUTHORITY && !alarm) return false;\n if (authority === COMMAND_AUTHORITY && !command) return false;\n return actions.can(authority);\n },\n };\n // Left absent when undeclared or unsupported: a command widget feature-detects it and\n // renders its Send control disabled.\n if (command && typeof actions.sendCommand === 'function') {\n narrowed.sendCommand = guardAsync((d, n, p) => actions.sendCommand!(d, n, p), report);\n }\n return narrowed;\n}\n\n// narrowSelect: the view-selection callback, only for a widget that declared `selection`.\nexport function narrowSelect(select: WidgetSelect | undefined, descriptor: WidgetDescriptor): WidgetSelect | undefined {\n return descriptor.interactions.selection === true ? select : undefined;\n}\n\n// narrowCandidates: the candidate lookup, only for a widget that declared `candidates`; its\n// rejections are reported locally and rethrown.\nexport function narrowCandidates(\n candidates: WidgetCandidates | undefined,\n descriptor: WidgetDescriptor,\n report: ReportRejection,\n): WidgetCandidates | undefined {\n if (!candidates || descriptor.interactions.candidates !== true) return undefined;\n return guardAsync((slot) => candidates(slot), report);\n}\n", "// Copyright The DeviceChain Authors\n// SPDX-License-Identifier: Apache-2.0\n\n// The viewer's time-range control: the presets, a pause, and the \"Paused\" indicator. One component\n// for every host (the console viewer, the /dash app), so the two cannot disagree about what a\n// frozen board looks like. It is a plain controlled bar -- the host owns the state through\n// useBoardTimeRange and feeds it to the renderer as `timeRange` -- and it carries no copy of its\n// own beyond English defaults: a host passes its translations as `labels`.\n\nimport {\n DEFAULT_TIME_RANGE_SECONDS,\n TIME_RANGE_PRESETS,\n initialTimeRange,\n isValidSpanSeconds,\n pauseRange,\n presetIdOf,\n resumeRange,\n spanLabel,\n withSpan,\n type TimeRangeState,\n} from '@devicechain/dashboards';\nimport { useCallback, useEffect, useMemo, useRef, useState, type CSSProperties } from 'react';\n\nexport interface TimeRangeControls {\n setSpan(spanSeconds: number): void;\n pause(): void;\n resume(): void;\n}\n\n// useBoardTimeRange holds the board's range for a host: the definition's default span, or the\n// deep link's, and live unless the link says paused. `defaultSeconds` is read once, at mount; a\n// host that swaps boards remounts (the console and /dash both do), which is when it should reset.\nexport function useBoardTimeRange(\n defaultSeconds: number | undefined,\n link: { spanSeconds?: number; paused?: boolean } = {},\n): [TimeRangeState, TimeRangeControls] {\n const [state, setState] = useState<TimeRangeState>(() => initialTimeRange(defaultSeconds, link));\n // An author who changes the board's default while the viewer is open expects the board to follow;\n // a viewer's own pick is only overridden when the DEFAULT moves, never by re-rendering.\n const lastDefault = useRef(defaultSeconds);\n useEffect(() => {\n if (lastDefault.current === defaultSeconds) return;\n lastDefault.current = defaultSeconds;\n setState((s) => withSpan(s, isValidSpanSeconds(defaultSeconds) ? defaultSeconds : DEFAULT_TIME_RANGE_SECONDS));\n }, [defaultSeconds]);\n const controls = useMemo<TimeRangeControls>(\n () => ({\n setSpan: (spanSeconds) => setState((s) => withSpan(s, spanSeconds)),\n pause: () => setState((s) => pauseRange(s, Date.now())),\n resume: () => setState((s) => resumeRange(s)),\n }),\n [],\n );\n return [state, controls];\n}\n\nexport interface TimeRangeLabels {\n range: string;\n pause: string;\n resume: string;\n paused: string;\n // \"Paused at 14:03:22\".\n pausedAt: (time: string) => string;\n // Printed inside the pill: a pause freezes what the board SHOWS, never what it DOES. Commands\n // (and alarm acknowledge / clear) still go out at once, and their status keeps updating, so an\n // operator who acts on a frozen board is told the action is live.\n actionsLive: string;\n}\n\nexport const DEFAULT_TIME_RANGE_LABELS: TimeRangeLabels = {\n range: 'Time range',\n pause: 'Pause',\n resume: 'Resume',\n paused: 'Paused',\n pausedAt: (time) => `Paused at ${time}`,\n actionsLive: 'commands still send',\n};\n\nconst button = (active: boolean): CSSProperties => ({\n padding: '2px 8px',\n fontSize: 12,\n lineHeight: '18px',\n cursor: 'pointer',\n color: active ? 'hsl(var(--background))' : 'hsl(var(--foreground))',\n background: active ? 'hsl(var(--foreground))' : 'transparent',\n border: '1px solid hsl(var(--border))',\n borderRadius: 4,\n});\n\n// The pill is deliberately loud: filled, bordered and spelled out, because a frozen board that\n// reads as live is the failure this slice exists to prevent. Exported so a kiosk wall (which has\n// no bar) can show it alone.\nexport function PausedIndicator({\n pausedAt,\n labels = DEFAULT_TIME_RANGE_LABELS,\n}: {\n pausedAt: number | undefined;\n labels?: TimeRangeLabels;\n}) {\n const time = pausedAt === undefined ? undefined : new Date(pausedAt).toLocaleTimeString();\n return (\n <span\n role=\"status\"\n data-time-range-paused=\"\"\n title={time ? labels.pausedAt(time) : labels.paused}\n style={{\n display: 'inline-flex',\n alignItems: 'center',\n gap: 4,\n padding: '2px 8px',\n fontSize: 12,\n fontWeight: 700,\n letterSpacing: 0.4,\n textTransform: 'uppercase',\n color: 'hsl(var(--background))',\n background: 'hsl(var(--foreground))',\n border: '2px solid hsl(var(--foreground))',\n borderRadius: 4,\n }}\n >\n <span aria-hidden=\"true\">{'\u23F8'}</span>\n {labels.paused}\n {time ? <span style={{ fontWeight: 400, textTransform: 'none' }}>{` ${time}`}</span> : null}\n <span data-time-range-actions-live=\"\" style={{ fontWeight: 400, textTransform: 'none' }}>\n {`\u00B7 ${labels.actionsLive}`}\n </span>\n </span>\n );\n}\n\nexport function TimeRangeBar({\n state,\n controls,\n labels = DEFAULT_TIME_RANGE_LABELS,\n}: {\n state: TimeRangeState;\n controls: TimeRangeControls;\n labels?: TimeRangeLabels;\n}) {\n const preset = presetIdOf(state.spanSeconds);\n const onPause = useCallback(() => (state.paused ? controls.resume() : controls.pause()), [state.paused, controls]);\n return (\n <div\n data-time-range-bar=\"\"\n role=\"group\"\n aria-label={labels.range}\n style={{ display: 'inline-flex', alignItems: 'center', gap: 6, flexWrap: 'wrap' }}\n >\n {/* A board default that is none of the presets (two hours, say) is still the selected span,\n shown under its own label rather than silently looking like another preset. */}\n {preset === undefined ? (\n <button type=\"button\" aria-pressed=\"true\" data-range={spanLabel(state.spanSeconds)} style={button(true)}>\n {spanLabel(state.spanSeconds)}\n </button>\n ) : null}\n {TIME_RANGE_PRESETS.map((p) => (\n <button\n key={p.id}\n type=\"button\"\n aria-pressed={p.id === preset}\n data-range={p.id}\n onClick={() => controls.setSpan(p.seconds)}\n style={button(p.id === preset)}\n >\n {p.id}\n </button>\n ))}\n <button type=\"button\" aria-pressed={state.paused} data-time-range-pause=\"\" onClick={onPause} style={button(state.paused)}>\n {state.paused ? labels.resume : labels.pause}\n </button>\n {state.paused ? <PausedIndicator pausedAt={state.pausedAt} labels={labels} /> : null}\n </div>\n );\n}\n", "// Copyright The DeviceChain Authors\n// SPDX-License-Identifier: Apache-2.0\n\n// The by-id views of the built-in registrations that older consumers still import.\n//\n// \uD83D\uDD34 READ-ONLY PROJECTIONS, NOT A REGISTRY. A widget's channel and whether it binds a\n// datasource are declared once, on its descriptor (builtin-descriptors.ts), and the\n// renderer resolves everything through a registry instance (createWidgetRegistry) -- never\n// through these. They exist so code that wants to ask \"which channel is this built-in on?\"\n// without building a registry (the console's config panel, fixtures) keeps working. They are\n// frozen, computed from the descriptors at module load, and there is no way to add an\n// entry: an extension widget registers through createWidgetRegistry, not here.\n\nimport type { BuiltinWidgetId, WidgetChannel } from '@devicechain/dashboards';\n\nimport { builtinWidgetDescriptors } from './builtin-descriptors';\n\n// WidgetChannel itself is declared once, in @devicechain/dashboards; re-exported so this\n// module's importers are unchanged.\nexport type { WidgetChannel };\n\ntype Descriptors = typeof builtinWidgetDescriptors;\n\nconst entries = Object.entries(builtinWidgetDescriptors) as Array<[BuiltinWidgetId, Descriptors[BuiltinWidgetId]]>;\n\n// A built-in's data channel, as its descriptor declares it.\nexport const WIDGET_CHANNEL: { readonly [K in BuiltinWidgetId]: Descriptors[K]['channel'] } = Object.freeze(\n Object.fromEntries(entries.map(([id, d]) => [id, d.channel])),\n) as { readonly [K in BuiltinWidgetId]: Descriptors[K]['channel'] };\n\n// Whether a built-in binds a DATASOURCE -- the entity whose data it reads. Derived from the\n// descriptor's datasource mode: `none` binds nothing (label, image, the entity selector).\nexport const WIDGET_BINDS_DATASOURCE: { readonly [K in BuiltinWidgetId]: boolean } = Object.freeze(\n Object.fromEntries(entries.map(([id, d]) => [id, d.datasource.mode !== 'none'])),\n) as { readonly [K in BuiltinWidgetId]: boolean };\n", "// Copyright The DeviceChain Authors\n// SPDX-License-Identifier: Apache-2.0\n\n// @devicechain/widgets \u2014 presentational dashboard widgets (ADR-039).\n//\n// Eleven built-ins over the DashboardHub's live data, themed via CSS custom\n// properties (no Tailwind leakage \u2014 embeddable in any React host). Each is a\n// registration declared with the public `defineWidget` from @devicechain/widget-sdk;\n// a renderer resolves a widget through a registry instance.\n\n// The view-only dashboard renderer: lays a parsed definition's widgets on the\n// canvas and binds each to the hub. The shared viewer for the console + external apps.\nexport { DashboardRenderer, resolveWidgets, widgetSubjectLabel, type DashboardRendererProps } from './dashboard-renderer';\nexport {\n DEFAULT_TIME_RANGE_LABELS,\n PausedIndicator,\n TimeRangeBar,\n useBoardTimeRange,\n type TimeRangeControls,\n type TimeRangeLabels,\n} from './time-range-bar';\n\n// Renderer entry point: binds the hub to a widget by type.\nexport { ConnectedWidget, type ConnectedWidgetProps } from './connected-widget';\n\n// The built-ins as registrations (the same descriptor + component pairing a third-party\n// package supplies), and the factory for a sealed registry holding exactly them.\nexport { builtinWidgetCatalog, builtinWidgetDescriptors } from './builtin-descriptors';\nexport { builtinWidgetDefinitions, createBuiltinWidgetRegistry } from './builtin-registry';\n\n// Read-only by-id views of the built-in descriptors (channel, datasource binding), and the\n// widget contract. The registrations above are the source of truth; these are derived.\nexport { WIDGET_CHANNEL, WIDGET_BINDS_DATASOURCE, type WidgetChannel } from './registry';\nexport { pickSample, optBoolean, type WidgetProps, type WidgetComponent } from '@devicechain/widget-sdk';\n\n// The tenant basemap seam. A host installs the provider; map widgets read it.\nexport { TenantBasemapProvider, useTenantBasemap } from './basemap-context';\n\n// The map RUNTIME seam \u2014 the MapLibre pieces only the host's bundler can emit.\n//\n// \uD83D\uDD34 Unlike the basemap provider above, this one is REQUIRED by any host that renders a\n// map widget: without it the widget shows a notice instead of a map. That is deliberate.\n// The alternative to a host-supplied worker URL is MapLibre's own runtime derivation,\n// which no bundler can follow, and which fails as a map that renders nothing at all.\nexport { MapRuntimeProvider, useMapRuntime, type MapRuntime } from './map-runtime-context';\n\n// The typed schema for each widget's options bag: what the renderer reads, at what type,\n// with what legal values. WidgetOptions<T> types code that BUILDS options;\n// validateWidgetOptions reports where a stored bag disagrees with the renderer.\nexport {\n WIDGET_OPTIONS,\n validateWidgetOptions,\n numberOptionSpec,\n clampNumberOption,\n enumOptionValues,\n type WidgetOptions,\n type WidgetOptionSpecs,\n type OptionSpec,\n type StringOptionSpec,\n type NumberOptionSpec,\n type BooleanOptionSpec,\n type EnumOptionSpec,\n type ListItemFieldSpec,\n type ListOptionSpec,\n type OptionIssue,\n type OptionIssueCode,\n} from './options';\n\n// The same schemas applied to a whole board: what a producer of definitions asks\n// before it publishes one, plus the repair for the one issue an author cannot fix in\n// a config panel.\nexport {\n validateDefinitionOptions,\n stripUnknownOptions,\n type DefinitionOptionIssue,\n type DefinitionValidationOptions,\n} from './definition-options';\n\n// Individual widgets (for direct/custom use).\nexport { LatestCard } from './widgets/latest-card';\nexport { Gauge } from './widgets/gauge';\nexport { TimeSeriesChart } from './widgets/time-series-chart';\nexport { Table } from './widgets/table';\nexport { Label } from './widgets/label';\nexport { Image } from './widgets/image';\nexport { AlarmTable } from './widgets/alarm-table';\nexport { AlarmCount } from './widgets/alarm-count';\nexport { CommandButton } from './widgets/command-button';\nexport { EntitySelector } from './widgets/entity-selector';\nexport { MapWidget } from './widgets/map';\n// The map's pure parts: which samples can be placed, where they land on a tile-less\n// panel, and how a fix is described without inventing the fields it does not carry.\n//\n// loadLandStyle is the bundled world basemap \u2014 the style used when no tile source\n// is configured. Exported so the console's fence editor and this package's map\n// widget cannot end up drawing two different worlds; the geometry itself stays\n// behind a dynamic import inside that module, so naming it here costs nothing.\nexport {\n placeable,\n projectToPanel,\n describePosition,\n formatDegrees,\n rasterStyleFor,\n landStyleFrom,\n loadLandStyle,\n BUNDLED_BASEMAP_ATTRIBUTION,\n type PlaceableLocation,\n type PanelPoint,\n} from './widgets/map-geometry';\nexport {\n severityColor,\n severityLabel,\n severityRank,\n highestSeverity,\n} from './widgets/severity';\nexport { commandStatusColor, commandStatusLabel, isTerminalStatus } from './widgets/command-status';\nexport {\n parseParameterSchema,\n defaultValues,\n validateParams,\n buildPayload,\n isScalar,\n} from './widgets/command-params';\n\n// Building blocks for custom widgets. They live in @devicechain/widget-sdk (the one place the\n// ambient host contexts may be defined) and are re-exported so existing imports keep resolving;\n// the chart helpers come from its `/echarts` subpath.\nexport {\n WidgetFrame,\n WidgetSubjectProvider,\n WidgetSelectProvider,\n useWidgetSelect,\n WidgetTimeZoneProvider,\n useWidgetTimeZone,\n WidgetThemeRootProvider,\n useWidgetThemeRoot,\n WidgetCandidatesProvider,\n useWidgetCandidates,\n useFlashOnChange,\n flashTextStyle,\n flashBackgroundStyle,\n FlashValue,\n fitValueFont,\n useMeasurementStream,\n useAlarmStream,\n useCommandStream,\n useLocationStream,\n useDatasourceAvailability,\n useDashboardHub,\n useHubConnectionState,\n HubConnectionBadge,\n useResolvedBindings,\n useSlotCandidates,\n useCandidates,\n css,\n type FlashDirection,\n type WidgetFrameProps,\n type WidgetSelect,\n type WidgetCandidates,\n type MeasurementStreamState,\n type AlarmStreamState,\n type CommandStreamState,\n type LocationStreamState,\n type CandidatesState,\n type DatasourceAvailability,\n type HubConnectionBadgeProps,\n type ThemeVar,\n} from '@devicechain/widget-sdk';\nexport {\n EChart,\n buildLineOption,\n buildGaugeOption,\n resolveChartTheme,\n useChartTheme,\n type EChartOption,\n type LineChartOptions,\n type GaugeChartOptions,\n type ChartTheme,\n} from '@devicechain/widget-sdk/echarts';\n", "// Copyright The DeviceChain Authors\n// SPDX-License-Identifier: Apache-2.0\n\n// WIDGET_OPTIONS \u2014 the typed schema for each widget type's `options` bag, as a by-id view.\n//\n// A WidgetInstance's `options` is `Record<string, unknown>` in the stored definition:\n// dashboard-management keeps a definition as opaque JSON, and the definition parser does\n// not look inside `options` at all. Each built-in's descriptor (builtin-descriptors.ts)\n// declares every option the RENDERER actually reads, with its type and legal values; this\n// module projects those schemas by id and wraps the shared engine under the by-type names\n// the console and fixtures use:\n// \u2022 validateWidgetOptions() \u2014 the runtime check, for anything that PRODUCES a definition\n// (a generated dashboard must not ship an options blob the renderer ignores).\n// \u2022 WidgetOptions<T> \u2014 the compile-time shape, for code that builds options.\n//\n// The schema describes the RENDERER, because that is the contract deciding what a viewer\n// actually sees. Where the console's authoring UI offers fewer keys than this \u2014 it does:\n// `align`, `fontSize`, `fit`, `window` and `measurement` are all honored by the renderer\n// and not authorable in the config panel \u2014 the gap is in the panel, not here.\n//\n// The spec VOCABULARY and the engine that checks a bag against a schema live in\n// @devicechain/dashboards (option-schema.ts) \u2014 they know no widget type, so the SDK's\n// registry validates an extension's schema with the very code that validates this one.\n\nimport {\n clampNumberOption,\n enumValues,\n numberSpec,\n validateOptions,\n type NumberOptionSpec,\n type OptionConstraint,\n type OptionIssueCode,\n type BuiltinWidgetId,\n type OptionsOf,\n type WidgetOptionSpecs,\n type WidgetType,\n} from '@devicechain/dashboards';\n\nimport { builtinWidgetCatalog, builtinWidgetDescriptors } from './builtin-descriptors';\n\nexport type {\n BooleanOptionSpec,\n EnumOptionSpec,\n ListItemFieldSpec,\n ListOptionSpec,\n NumberOptionSpec,\n OptionIssueCode,\n OptionSpec,\n StringOptionSpec,\n WidgetOptionSpecs,\n} from '@devicechain/dashboards';\nexport { clampNumberOption };\n\n// ---- The derived by-id view -------------------------------------------------\n\n// Every built-in's option schema, keyed by id. A frozen PROJECTION of the descriptors in\n// builtin-descriptors.ts (each schema is declared there, once, beside the widget's channel and\n// binding policy); it holds no schema of its own, so it cannot drift from what the registry\n// validates. The cross-field rules (gauge's max > min) travel on the descriptor as data.\ntype OptionsById = { readonly [K in BuiltinWidgetId]: (typeof builtinWidgetDescriptors)[K]['options'] };\n\nexport const WIDGET_OPTIONS: OptionsById = Object.freeze(\n Object.fromEntries(Object.entries(builtinWidgetDescriptors).map(([id, d]) => [id, d.options])),\n) as OptionsById;\n\nfunction constraintsFor(widgetType: WidgetType): readonly OptionConstraint[] {\n return builtinWidgetCatalog.get(widgetType)?.constraints ?? [];\n}\n\n// ---- Derived compile-time types ---------------------------------------------\n\n// WidgetOptions<'gauge'> is the typed options bag for a gauge: every declared key at its\n// declared type, required ones mandatory. Code that BUILDS a definition should type its\n// options with this \u2014 a typo is then a compile error rather than a key nothing reads.\n//\n// DISTRIBUTIVE over T, which is the whole reason it is written as a conditional. `keyof` a\n// union of the built-in tables is their INTERSECTION \u2014 only `title` \u2014 and the required-keys\n// computation over that union collapses to never, so the undistributed form silently\n// degenerates for any generic T: it would reject `{ text: 'body' }` as an excess property\n// while accepting `{}` for a widget that requires an option. That is exactly the position a\n// generator writing one widget of each type sits in. Distributing makes\n// WidgetOptions<WidgetType> the union of the per-type bags instead.\nexport type WidgetOptions<T extends WidgetType> = T extends WidgetType ? OptionsOf<(typeof WIDGET_OPTIONS)[T]> : never;\n\n// ---- Runtime validation -----------------------------------------------------\n\n// The by-type issue shape the console reads. `widgetType` keeps its name so existing\n// consumers compile unchanged; the engine's own issue calls the same value `widgetId`.\nexport interface OptionIssue {\n widgetType: WidgetType;\n // The offending option key. For a cross-field rule, the key the fix belongs on.\n key: string;\n code: OptionIssueCode;\n message: string;\n}\n\n// validateWidgetOptions reports every way a widget's stored options bag disagrees with\n// what the renderer reads. An empty result means every key present is one the renderer\n// honors, at a value it accepts, and no required option is missing.\n//\n// It is deliberately a REPORT rather than a throw: the renderer is tolerant by design and\n// must stay that way for a hand-edited definition, so the strictness belongs to whoever\n// produces definitions (fixtures, generators, the config panel) and to the tests that\n// gate them. Callers decide which codes are fatal \u2014 a stored dashboard carrying an\n// 'unknown' leftover is untidy; a generated one carrying 'missing' is broken.\nexport function validateWidgetOptions(\n widgetType: WidgetType,\n options: Record<string, unknown> | undefined,\n): OptionIssue[] {\n const specs: WidgetOptionSpecs = WIDGET_OPTIONS[widgetType];\n return validateOptions(specs, options, { constraints: constraintsFor(widgetType), label: widgetType }).map(\n ({ key, code, message }) => ({ widgetType, key, code, message }),\n );\n}\n\n// numberOptionSpec returns the declared bounds for a numeric option, so an authoring\n// UI can constrain its input from the schema rather than from a second, hand-written\n// copy of the same numbers. See numberSpec for why it exists.\nexport function numberOptionSpec(type: WidgetType, key: string): NumberOptionSpec | undefined {\n return numberSpec(WIDGET_OPTIONS[type], key);\n}\n\n// enumOptionValues returns the legal values of an enum option, so an authoring UI can\n// build its dropdown from the schema instead of a private copy of the same list.\nexport function enumOptionValues(type: WidgetType, key: string): readonly string[] | undefined {\n return enumValues(WIDGET_OPTIONS[type], key);\n}\n", "// Copyright The DeviceChain Authors\n// SPDX-License-Identifier: Apache-2.0\n\n// The definition-level layer over validateWidgetOptions: \"is every widget on this\n// board configured with options the renderer actually reads?\"\n//\n// WHY IT IS A SEPARATE FUNCTION RATHER THAN A LOOP AT EACH CALL SITE. Every consumer\n// wants the same three things \u2014 walk the widgets, keep the issues, and know WHICH\n// widget each belongs to \u2014 and the third is the one a hand-rolled loop forgets. An\n// issue reported without its widget id tells an author that `commandName` is missing\n// on a board with three command buttons, which is a report they cannot act on.\n//\n// \uD83D\uDD11 THE OPTION SCHEMAS ARE TYPESCRIPT, AND THAT DECIDES WHERE THE GATE CAN LIVE.\n// dashboard-management stores a definition as opaque JSON and checks only that it is\n// a JSON object; it is Go, so it cannot run these schemas, and a Go copy of them\n// would be a THIRD representation of the same table (the reason ADR-076 declined a\n// cross-language widget manifest). So the strictness belongs to whoever PRODUCES a\n// definition, and \uD83D\uDD34 EACH PRODUCER HAS TO WIRE IT FOR ITSELF \u2014 there is no chokepoint\n// downstream that would catch a producer nobody thought about:\n//\n// \u2022 the console, by its publish action (apps/console/src/lib/api/dashboards.ts);\n// \u2022 the sim, by the golden-fixture gate over frontend/testdata/sim-dashboards, which\n// covers every dashboard of every REGISTERED scenario. It was widgetlab-only when\n// this function was written, and the sentence here claimed otherwise \u2014 buildingpulse,\n// the demo board, was gated by nothing. Two reviewers found the same overclaim\n// independently. The gate walks sim.Registry now, so the claim is true by\n// construction rather than by a list someone has to remember to extend.\n//\n// Anything ELSE writing a definition \u2014 raw GraphQL, a future importer \u2014 is unchecked,\n// because dashboard-management deliberately validates nothing. This is not the\n// server-side, ADR-044-style publish gate it superficially resembles, and calling it one\n// would misdescribe exactly which documents are protected.\n\nimport {\n UNKNOWN_WIDGET_TYPE,\n validateOptions,\n type DashboardDefinition,\n type WidgetCatalog,\n type WidgetDescriptor,\n type WidgetInstance,\n} from '@devicechain/dashboards';\n\nimport { builtinWidgetCatalog } from './builtin-descriptors';\nimport type { OptionIssue } from './options';\n\n// A DefinitionOptionIssue is an OptionIssue plus the widget that carries it.\n//\n// It deliberately carries the ID and nothing friendlier. An earlier version also read\n// `options.title` so a consumer could label the issue \u2014 and that one read, purely for\n// presentation, put this file into the option-read scan in options.test.ts, where every\n// other entry is evidence that a RENDERER reads a key. It needed a paragraph explaining\n// why it did not mean what its neighbours meant. A consumer that wants a title already\n// holds the definition and can join on the id; the scan goes back to meaning one thing.\nexport interface DefinitionOptionIssue extends Omit<OptionIssue, 'widgetType'> {\n // The stored widget id: a built-in type, or an extension's namespaced id.\n widgetType: string;\n widgetId: string;\n}\n\n// A definition as this module reads it: only the widget list matters, so the fixture\n// tests and the console's in-flight editor state both satisfy it without either having\n// to be a fully parsed DashboardDefinition.\ntype WidgetCarrier = Pick<DashboardDefinition, 'widgets'>;\n\n// validateDefinitionOptions reports every option issue on the board, in widget order.\n// An empty result means every widget's bag is one the renderer honors in full.\n//\n// A placeholder for a widget type this build does not know reports nothing: it carries\n// no options of its own (its stored object is kept verbatim, options and all), and this\n// build has no schema to judge a newer widget's options against.\n//\n// `options.catalog` is the host's widget catalog (registry.catalog): an extension widget is\n// judged against ITS registered schema. Omitted = the built-ins only, so a board carrying an\n// extension widget must be validated with the catalog it was parsed with.\nexport interface DefinitionValidationOptions {\n catalog?: WidgetCatalog;\n}\n\nexport function validateDefinitionOptions(\n definition: WidgetCarrier,\n options: DefinitionValidationOptions = {},\n): DefinitionOptionIssue[] {\n return definition.widgets.flatMap((widget) => {\n if (widget.type === UNKNOWN_WIDGET_TYPE) return [];\n const type = widget.type;\n const descriptor = descriptorFor(type, options.catalog);\n return validateOptions(descriptor.options, widget.options, {\n constraints: descriptor.constraints,\n label: type,\n }).map(({ key, code, message }) => ({ widgetType: type, key, code, message, widgetId: widget.id }));\n });\n}\n\n// The schema a recognized widget is judged against comes from the built-in CATALOG \u2014 the\n// same descriptors a registry holds \u2014 rather than from a by-type table, so this gate is the\n// live consumer of the registry's data. Every built-in type is in the catalog by\n// construction (builtin-registry.test.ts), so a miss is a defect to surface, not a widget\n// to skip.\n//\n// A catalog the host supplies is consulted first (an extension lives only there); a built-in\n// the supplied catalog omits falls back to the built-in descriptor, since its schema is the\n// same everywhere. An id neither holds is a defect \u2014 the board was parsed against a catalog\n// other than the one it is validated with \u2014 so it throws rather than skipping the widget.\nfunction descriptorFor(type: string, catalog: WidgetCatalog | undefined): WidgetDescriptor {\n const descriptor = catalog?.get(type) ?? builtinWidgetCatalog.get(type);\n if (!descriptor) {\n throw new Error(`no widget descriptor for \"${type}\"; validate with the catalog the definition was parsed with`);\n }\n return descriptor;\n}\n\n// stripUnknownOptions removes every option key no widget of that type reads, leaving\n// everything else untouched.\n//\n// \uD83D\uDD34 IT EXISTS BECAUSE 'unknown' IS THE ONE ISSUE CODE AN AUTHOR CANNOT FIX IN THE UI.\n// This is the canonical statement of that reasoning; the call sites point here.\n// Every other code sits on a DECLARED key, so the config panel renders a control for it\n// and the author edits or clears it. An unknown key is by definition one the panel has\n// no control for \u2014 and the panel preserves the bag it did not write (it spreads\n// `widget.options` on every edit), so the key survives every subsequent change. Without\n// this, a publish gate that treats 'unknown' as fatal is a dead end: a dashboard that\n// acquired a leftover key \u2014 from a version predating an option rename, or from a\n// producer other than the console \u2014 could never be published again through the UI.\n//\n// Returns the SAME object when there is nothing to strip, so a caller can detect a\n// no-op with `next === before`.\n//\n// \uD83D\uDD34 THE OBVIOUS REASON TO WANT THIS IS NOT THE REAL ONE, and the first version of this\n// comment gave the wrong one: it claimed a fresh-but-equal object would read as an\n// unsaved edit. It would not \u2014 the console's isDirty compares SERIALIZATIONS\n// (dashboards/src/definition.ts), so an equal-but-new object is not dirty. What the\n// identity actually buys is smaller and still worth having: the caller can tell \"there\n// was nothing to remove\" from \"I removed something\" without diffing, and it avoids a\n// state write that would re-render the editor for no change.\nexport function stripUnknownOptions<T extends WidgetCarrier>(definition: T, options: DefinitionValidationOptions = {}): T {\n let changed = false;\n const widgets = definition.widgets.map((widget) => {\n const stripped = stripUnknownWidgetOptions(widget, options.catalog);\n if (stripped !== widget) changed = true;\n return stripped;\n });\n return changed ? { ...definition, widgets } : definition;\n}\n\nfunction stripUnknownWidgetOptions(widget: WidgetInstance, catalog: WidgetCatalog | undefined): WidgetInstance {\n // A placeholder for an unknown widget type carries no options (they stay in its raw\n // object, which is never rewritten), so it returns here unchanged.\n const bag = widget.options;\n if (!bag) return widget;\n const specs = descriptorFor(widget.type, catalog).options;\n // hasOwnProperty.call, not `in` \u2014 see validateWidgetOptions: every specs table\n // inherits Object.prototype, so `in` would report '__proto__' and 'constructor' as\n // declared and leave exactly the keys a JSON.parse'd definition can smuggle in.\n const keys = Object.keys(bag);\n const kept = keys.filter((key) => Object.prototype.hasOwnProperty.call(specs, key));\n if (kept.length === keys.length) return widget;\n const options: Record<string, unknown> = {};\n for (const key of kept) options[key] = bag[key];\n return { ...widget, options };\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["UNKNOWN_WIDGET_TYPE", "Fragment", "useCallback", "useEffect", "useMemo", "useRef", "useState", "useWidgetTimeRange", "useMemo", "useState", "Component", "css", "defineWidget", "jsx", "css", "defineWidget", "useState", "css", "fontVar", "defineWidget", "optString", "useSeverityColors", "WidgetFrame", "Fragment", "jsx", "jsxs", "css", "fontVar", "useSeverityColors", "optString", "WidgetFrame", "useState", "defineWidget", "useEffect", "useState", "css", "fontVar", "defineWidget", "formatDateTime", "optString", "useWidgetTimeZone", "WidgetFrame", "Fragment", "jsx", "jsxs", "optString", "useState", "useEffect", "WidgetFrame", "css", "fontVar", "useWidgetTimeZone", "formatDateTime", "defineWidget", "defineWidget", "chunk", "defineWidget", "useEffect", "useState", "css", "fontVar", "defineWidget", "optString", "useWidgetSelect", "WidgetFrame", "Fragment", "jsx", "jsxs", "fontVar", "css", "hint", "useWidgetSelect", "optString", "useState", "useEffect", "WidgetFrame", "defineWidget", "useMemo", "defineWidget", "optBoolean", "optNumber", "optString", "useWidgetScale", "WidgetFrame", "jsx", "jsxs", "WidgetFrame", "optString", "useWidgetScale", "optNumber", "useMemo", "optBoolean", "defineWidget", "css", "defineWidget", "fontVar", "optString", "WidgetFrame", "jsx", "optString", "WidgetFrame", "css", "fontVar", "defineWidget", "css", "defineWidget", "fontVar", "spaceVar", "optNumber", "optString", "WidgetFrame", "jsx", "optString", "optNumber", "fontVar", "WidgetFrame", "spaceVar", "css", "defineWidget", "useMemo", "css", "defineWidget", "fitValueFont", "fitValueFontCss", "FIT_MIN_FONT_PX", "fontVar", "formatValue", "optBoolean", "optNumber", "optString", "optThresholds", "pickSample", "primaryMeasurementName", "spaceVar", "useSeverityColors", "useStickyChars", "useFlashOnChange", "useWidgetTimeZone", "WidgetFrame", "jsx", "jsxs", "useSeverityColors", "useWidgetTimeZone", "primaryMeasurementName", "pickSample", "optString", "optNumber", "formatValue", "useMemo", "optThresholds", "css", "useFlashOnChange", "optBoolean", "useStickyChars", "WidgetFrame", "FIT_MIN_FONT_PX", "fitValueFont", "fitValueFontCss", "spaceVar", "fontVar", "defineWidget", "defineWidget", "chunk", "defineWidget", "useEffect", "useRef", "useState", "jsx", "createContext", "useContext", "jsx", "css", "fontVar", "defineWidget", "optString", "WidgetFrame", "jsx", "jsxs", "optString", "WidgetFrame", "css", "fontVar", "useRef", "useState", "useEffect", "defineWidget", "css", "defineWidget", "fontVar", "spaceVar", "FlashValue", "formatTimestamp", "optBoolean", "optNumber", "optString", "useWidgetTimeZone", "WidgetFrame", "jsx", "jsxs", "cell", "spaceVar", "headCell", "fontVar", "css", "useWidgetTimeZone", "optNumber", "optBoolean", "WidgetFrame", "optString", "FlashValue", "formatTimestamp", "defineWidget", "useMemo", "css", "defineWidget", "fontVar", "formatDateTime", "formatTimestamp", "optNumber", "optString", "optThresholds", "spaceVar", "useWidgetScale", "useWidgetTimeZone", "WidgetFrame", "EChart", "useChartTheme", "jsx", "jsxs", "WidgetFrame", "optString", "useChartTheme", "useWidgetScale", "optNumber", "useMemo", "optThresholds", "EChart", "useWidgetTimeZone", "formatDateTime", "formatTimestamp", "spaceVar", "fontVar", "css", "defineWidget", "optString", "useWidgetSelect", "WidgetFrame", "createContext", "useContext", "useState", "WidgetFrame", "jsx", "jsxs", "createContext", "useContext", "WidgetFrame", "useState", "jsx", "jsxs", "optString", "useWidgetSelect", "useMemo", "Component", "useWidgetTimeRange", "WidgetFrame", "WidgetCandidatesProvider", "WidgetSelectProvider", "Fragment", "jsx", "jsxs", "useMemo", "useCallback", "UNKNOWN_WIDGET_TYPE", "WidgetSelectProvider", "WidgetCandidatesProvider", "useRef", "useState", "useEffect", "initialTimeRange", "isValidSpanSeconds", "spanLabel", "useCallback", "useEffect", "useMemo", "useRef", "useState", "jsx", "jsxs", "pickSample", "optBoolean", "UNKNOWN_WIDGET_TYPE", "validateOptions", "UNKNOWN_WIDGET_TYPE", "validateOptions", "WidgetFrame", "WidgetSubjectProvider", "WidgetSelectProvider", "useWidgetSelect", "WidgetTimeZoneProvider", "useWidgetTimeZone", "WidgetThemeRootProvider", "WidgetCandidatesProvider", "useWidgetCandidates", "useFlashOnChange", "flashTextStyle", "flashBackgroundStyle", "FlashValue", "fitValueFont", "useMeasurementStream", "useAlarmStream", "useCommandStream", "useLocationStream", "useDatasourceAvailability", "useCandidates", "css", "EChart", "buildLineOption", "buildGaugeOption", "useChartTheme"]
|
|
7
7
|
}
|