@burdenoff/microfe-bigconsole 2026.929.2 → 2026.930.2

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.
Files changed (50) hide show
  1. package/dist/bigconsole/assistant/assistantRunPersistence.js +111 -0
  2. package/dist/bigconsole/assistant/assistantRunPersistence.js.map +1 -0
  3. package/dist/bigconsole/assistant/assistantRunStore.js +87 -48
  4. package/dist/bigconsole/assistant/assistantRunStore.js.map +1 -1
  5. package/dist/bigconsole/assistant/previewController.js +19 -50
  6. package/dist/bigconsole/assistant/previewController.js.map +1 -1
  7. package/dist/bigconsole/assistant/useAssistantRunWorkspace.js +14 -0
  8. package/dist/bigconsole/assistant/useAssistantRunWorkspace.js.map +1 -0
  9. package/dist/bigconsole/components/DrilldownDashboardRenderer.js +74 -50
  10. package/dist/bigconsole/components/DrilldownDashboardRenderer.js.map +1 -1
  11. package/dist/bigconsole/components/dashboard/DrilldownBreadcrumb.js +9 -4
  12. package/dist/bigconsole/components/dashboard/DrilldownBreadcrumb.js.map +1 -1
  13. package/dist/bigconsole/components/embed/ReadOnlyDashboardRenderer.js +68 -40
  14. package/dist/bigconsole/components/embed/ReadOnlyDashboardRenderer.js.map +1 -1
  15. package/dist/bigconsole/components/embed/drilldown.js +26 -0
  16. package/dist/bigconsole/components/embed/drilldown.js.map +1 -0
  17. package/dist/bigconsole/components/embed/index.js +4 -3
  18. package/dist/bigconsole/components/embed/types.js.map +1 -1
  19. package/dist/bigconsole/components/preview/AiPreviewMiniPanel.js +32 -30
  20. package/dist/bigconsole/components/preview/AiPreviewMiniPanel.js.map +1 -1
  21. package/dist/bigconsole/components/preview/AiPreviewPanel.js +38 -36
  22. package/dist/bigconsole/components/preview/AiPreviewPanel.js.map +1 -1
  23. package/dist/bigconsole/components/preview/previewShared.js +1 -1
  24. package/dist/bigconsole/components/preview/previewShared.js.map +1 -1
  25. package/dist/bigconsole/components/widgets/DrilldownConfigPanel.js +307 -233
  26. package/dist/bigconsole/components/widgets/DrilldownConfigPanel.js.map +1 -1
  27. package/dist/bigconsole/components/widgets/PropertiesPanel.js +230 -220
  28. package/dist/bigconsole/components/widgets/PropertiesPanel.js.map +1 -1
  29. package/dist/bigconsole/components/widgets/WidgetWrapper.js +18 -19
  30. package/dist/bigconsole/components/widgets/WidgetWrapper.js.map +1 -1
  31. package/dist/bigconsole/context/BigConsoleContext.js +4 -1
  32. package/dist/bigconsole/context/BigConsoleContext.js.map +1 -1
  33. package/dist/bigconsole/hooks/useActivePage.js +25 -0
  34. package/dist/bigconsole/hooks/useActivePage.js.map +1 -0
  35. package/dist/bigconsole/hooks/useDrilldown.js +118 -71
  36. package/dist/bigconsole/hooks/useDrilldown.js.map +1 -1
  37. package/dist/bigconsole/hooks/useDrilldownOperations.js +32 -26
  38. package/dist/bigconsole/hooks/useDrilldownOperations.js.map +1 -1
  39. package/dist/bigconsole/hooks/useFilterUrlSync.js +1 -1
  40. package/dist/bigconsole/hooks/useFilterUrlSync.js.map +1 -1
  41. package/dist/bigconsole/pages/DashboardBuilderPage.js +190 -185
  42. package/dist/bigconsole/pages/DashboardBuilderPage.js.map +1 -1
  43. package/dist/bigconsole/pages/DashboardViewPage.js +224 -217
  44. package/dist/bigconsole/pages/DashboardViewPage.js.map +1 -1
  45. package/dist/generated/wspace-operations.js +132 -86
  46. package/dist/generated/wspace-operations.js.map +1 -1
  47. package/dist/generated/wspace-types.js.map +1 -1
  48. package/package.json +3 -3
  49. package/dist/bigconsole/assistant/useAssistantPanelShowsPreview.js +0 -25
  50. package/dist/bigconsole/assistant/useAssistantPanelShowsPreview.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"previewShared.js","names":[],"sources":["../../../../src/bigconsole/components/preview/previewShared.tsx"],"sourcesContent":["/**\n * What is still BigConsole's about the AI preview surfaces.\n *\n * ★★★ THE SHELL, DIVIDERS AND STEP RAIL HAVE MOVED TO fe-libs\n * (`AssistantEntityPreview` / `AssistantStepRail`). They existed here so the\n * full panel and the mini panel could not drift apart; the shared component now\n * guarantees that for both, and for every other product that adopts it.\n *\n * What remains is genuinely local: BigConsole's relationship to the assistant\n * DOCK, and how it words a relative timestamp.\n *\n * Nothing here touches Apollo, React Query, BigConsole context — or, since BC4,\n * the DOM: the dock clearance is a CSS custom property fe-libs publishes, so\n * what is left is one constant plus formatting, which is why the mini panel can\n * live in the app shell without dragging the data layer along.\n */\nimport { useEffect, useState } from 'react';\n\nimport type { AssistantEntityPreviewProps } from '@burdenoff/fe-libs/shared/assistant';\n\nimport type { PreviewStepKey } from '../../assistant/assistantRunStore';\n\n/** The `t` both panels already hold — accepted rather than imported, so this\n * file keeps no provider requirement of its own. */\ntype Translate = (key: string, fallback: string, params?: Record<string, string | number>) => string;\n\n/**\n * \"just now\" / \"40s ago\" / \"12m ago\" / \"3h ago\".\n *\n * ★★ TRANSLATED, and it now has an hour bucket. It used to return English in\n * all three locales (en, hi, ta), and a panel left open past an hour read \"240m ago\" rather\n * than \"4h ago\" — both of which were only visible on the surface that outlives\n * a build, which is exactly the one people leave sitting there.\n */\nexport function formatAgo(seconds: number, t: Translate): string {\n if (seconds < 5) return t('bigconsole.widget.aiPreview.agoJustNow', 'just now');\n if (seconds < 60) {\n return t('bigconsole.widget.aiPreview.agoSeconds', '{{n}}s ago', { n: seconds });\n }\n if (seconds < 3600) {\n return t('bigconsole.widget.aiPreview.agoMinutes', '{{n}}m ago', { n: Math.floor(seconds / 60) });\n }\n // ★ `{{n}}`, not `{n}` — fe-libs' single-brace interpolation was broken until\n // 2026.910.7 and shipped raw braces to users across the fleet. Double braces\n // are what this repo already uses (see `…aiPreviewMini.linkReady`).\n return t('bigconsole.widget.aiPreview.agoHours', '{{n}}h ago', { n: Math.floor(seconds / 3600) });\n}\n\n/**\n * Clearance for the assistant dock, as a CSS length.\n *\n * ★★★ THIS REPLACED A 500ms `querySelector` POLL (BC4, BOFF-7337). The old hook\n * measured `[data-testid=\"assistant-widget-window\"][data-layout=\"sidebar\"]` on an\n * interval because the legacy widget lived in fe-libs, was mounted by the app\n * shell, and emitted nothing when it opened or closed — reading the DOM really\n * was the only signal available.\n *\n * The shared overlay publishes its width instead. fe-libs sets\n * `--assistant-dock-width` on `<html>` from\n * `publishedAssistantDockWidth({ isOpen, docked, isDesktop })` — 440px only when\n * the panel is open AND docked AND the viewport is at least 640px — and REMOVES\n * the property on unmount. So the `0px` fallback covers closed, floating,\n * phone-width and absent alike, which is exactly the set of cases the poll\n * hand-rolled, including its `rect.width < innerWidth * 0.75` phone guard.\n *\n * ★★★ THE FALLBACK FAILS OPEN, SO THE VERSIONS ARE COUPLED. A host shell that\n * pins this package but still mounts the LEGACY `AssistantWidget` publishes no\n * variable at all, this resolves to `0px`, and the preview renders underneath a\n * fixed 440px dock where tabs and Open buttons silently stop taking clicks.\n * Nothing throws and no test fails. bigconsole-app therefore bumps this\n * dependency and mounts `AssistantOverlay` in the SAME commit.\n *\n * ★★ A STRING, NOT A HOOK. It needs no React context and no provider ancestry —\n * which matters because the mini panel is mounted by the app shell, outside the\n * assistant's own tree — and the browser recomputes the margin on open/close\n * with no re-render at all.\n *\n * ★ APPLIED TWO WAYS, DELIBERATELY. The collapsed bars carry only `px-*`, so\n * they take it as `marginRight` and a closed dock reproduces the old `0`\n * exactly. The open panels carry `mx-4 md:mx-6`, so they take it as\n * `paddingRight` and leave those margins alone: the old\n * `assistantWidth ? assistantWidth + 16 : undefined` fell through to the\n * RESPONSIVE 24px gutter at md when closed, and folding a flat `+ 16px` into a\n * calc would have quietly shrunk it on every desktop width. Padding keeps the\n * closed state pixel-identical and only adds clearance while docked.\n */\nexport const DOCK_CLEARANCE = 'var(--assistant-dock-width, 0px)';\n\n/**\n * Step labels, reusing the TAB keys.\n *\n * ★★ They used to be English constants in the store (`PREVIEW_STEP_LABEL`), so\n * the rail rendered \"Data Sink / Dashboard / Parser / Widget\" in every locale —\n * directly beside the SAME four names rendered translated as tab labels. The\n * keys already exist and are already seeded; nothing new was needed to fix it.\n *\n * ★ Lives here because BOTH panels render the rail. It was defined twice, which\n * is the exact duplication this migration exists to remove.\n */\nexport const STEP_LABEL: Record<PreviewStepKey, { key: string; fallback: string }> = {\n datasink: { key: 'bigconsole.widget.aiPreview.tab.dataSink', fallback: 'Data Sink' },\n dashboard: { key: 'bigconsole.widget.aiPreview.tab.dashboard', fallback: 'Dashboard' },\n parser: { key: 'bigconsole.widget.aiPreview.tab.parser', fallback: 'Parser' },\n widget: { key: 'bigconsole.widget.aiPreview.tab.widget', fallback: 'Widget' },\n};\n\n/**\n * The shared surface's chrome strings, already translated.\n *\n * ★★ ONE copy, deliberately. BOTH defects this migration produced were the same\n * bug written twice — the failure caption and the reopen clock each had to be\n * fixed in the full panel AND the mini panel — so anything the two pass\n * identically belongs here rather than inlined in each. That is the same reason\n * the shell lived in this file before it moved to fe-libs.\n *\n * ★ Both surfaces use the `aiPreview` namespace, not `aiPreviewMini`: the rail\n * says the same thing wherever it is rendered, and splitting the keys would mean\n * translating \"running\" and \"failed\" twice per locale for no difference.\n *\n * `AssistantEntityPreviewProps['labels']` rather than a hand-written shape, so a\n * new label added upstream is a type error here instead of a silently missing\n * string.\n */\nexport function previewLabels(t: Translate): AssistantEntityPreviewProps['labels'] {\n const buildProgress = t('bigconsole.widget.aiPreview.buildProgress', 'Build progress');\n const skipped = t('bigconsole.widget.aiPreview.stepSkipped', 'skipped');\n return {\n // ★ main named the failure \"Build stopped\" in a hardcoded English <h3>. The\n // shared surface cannot know that word — it takes it as a label — so this\n // both restores the name AND makes it translatable for the first time.\n errorHeading: t('bigconsole.widget.aiPreview.errorHeading', 'Build stopped'),\n steps: buildProgress,\n stepsHeading: buildProgress,\n skipped,\n stepStatus: {\n pending: t('bigconsole.widget.aiPreview.stepPending', 'not started'),\n running: t('bigconsole.widget.aiPreview.stepRunning', 'running'),\n done: t('bigconsole.widget.aiPreview.stepDone', 'completed'),\n failed: t('bigconsole.widget.aiPreview.stepFailed', 'failed'),\n skipped,\n },\n };\n}\n\n/**\n * The status strip both panels hand to the shared surface as `meta`.\n *\n * ★★★ ONE copy, and this one is not a tidiness argument — the SAME DEFECT was\n * written into both panels twice over. The migration changed this chip from\n * `bg-status-success-bg` to `bg-status-success-bgSubtle` in both files, and that\n * utility DOES NOT EXIST: the token is `--color-status-success-bgSubtle` but the\n * Tailwind preset exposes it as `status-success-bg-subtle`. The app shell emits\n * `.bg-status-success-bg-subtle` and never `.bg-status-success-bgSubtle`, so the\n * \"Live\" pill lost its background entirely and became transparent text.\n * Nothing failed: an unknown utility is simply absent from the stylesheet.\n *\n * ★ Fixed with the ARBITRARY-VALUE form, `bg-[var(--color-status-…-bgSubtle)]`,\n * which is what the other ~30 sites in this repo use. It names the token\n * directly, so it cannot be broken by a preset key being spelled differently\n * from the variable — which is the entire mechanism of the bug above.\n *\n * ★★ It also carries the FAILED state, which the caption cannot. The shared\n * surface blanks `caption` whenever `error` is set — deliberately, so a rotating\n * \"Creating…\" cannot sit under a dead run — so a product that wants the failure\n * NAMED (as this one did on main, with \"Stopped\") has to say it somewhere the\n * error does not suppress. `meta` is that place: `PreviewHeader` renders it\n * without consulting `error`.\n *\n * Labels are passed in already translated, so the `t('literal.key', …)` calls\n * stay greppable at each call site and each panel keeps its own namespace.\n */\nexport function PreviewMeta({\n state,\n stateLabel,\n updatedLabel,\n updatedAt,\n ago,\n}: {\n state: 'running' | 'stopped' | 'idle';\n stateLabel: string | null;\n updatedLabel: string;\n /** When the run last changed, or null when there is nothing to age. */\n updatedAt: number | null;\n /** Renders the elapsed seconds — `formatAgo` bound to the caller's `t`. */\n ago: (seconds: number) => string;\n}) {\n /**\n * ★★★ THE CLOCK LIVES HERE, in the one element that displays it.\n *\n * It used to live in each panel, and that made a 1 Hz `setState` on the PANEL\n * — which re-rendered everything below it. `AssistantEntityPreview` calls\n * `activeTab.render()` on every render with no memo, so the Widgets tab's live\n * dashboard and every Recharts widget inside it re-rendered once a second, for\n * as long as the preview stayed open. main did not: its ticker was gated on\n * `isRunning`, so it stopped when the build did. Ungating it to fix the frozen\n * timestamp is right, but it has to cost one <span>, not the whole subtree.\n *\n * ★★ Mounting is also the gate now. The mini panel is mounted on EVERY route\n * and returns null when the full panel is up — but a hook cannot sit below an\n * early return, so its interval ran on every page regardless of whether\n * anything was shown. Owning the timer here means \"not rendered\" is \"not\n * ticking\", by construction rather than by remembering to pass a flag.\n */\n const [now, setNow] = useState(() => Date.now());\n useEffect(() => {\n if (updatedAt === null) return;\n // ★ Re-read on mount so a reopened panel cannot show the previous open's\n // reading for up to a second. See the note on lint in the git history:\n // reading the clock in render is an ESLint error (Date.now is impure).\n setNow(Date.now());\n const id = window.setInterval(() => setNow(Date.now()), 1000);\n return () => window.clearInterval(id);\n }, [updatedAt]);\n\n const agoSeconds = updatedAt === null ? 0 : Math.max(0, Math.floor((now - updatedAt) / 1000));\n\n const chip =\n 'inline-flex items-center gap-1.5 rounded-full px-2 py-0.5 text-[11px] font-semibold uppercase tracking-wide';\n return (\n <span className=\"inline-flex items-center gap-2\" data-testid=\"ai-preview-ago\">\n {state !== 'idle' && stateLabel ? (\n <span\n className={\n state === 'running'\n ? `${chip} bg-[var(--color-status-success-bgSubtle)] text-status-success-text`\n : `${chip} bg-[var(--color-status-error-bgSubtle)] text-status-error-text`\n }\n data-testid={state === 'running' ? 'ai-preview-live' : 'ai-preview-stopped'}\n >\n {state === 'running' ? (\n <span className=\"relative flex size-2\">\n <span className=\"absolute inline-flex size-full rounded-full bg-status-success-text opacity-75 motion-safe:animate-ping\" />\n <span className=\"relative inline-flex size-2 rounded-full bg-status-success-text\" />\n </span>\n ) : (\n /* ★ Still, not pulsing: the ping says \"this is happening now\", which\n is the opposite of what a stopped run means. */\n <span className=\"relative inline-flex size-2 rounded-full bg-status-error-text\" />\n )}\n {stateLabel}\n </span>\n ) : null}\n <span>\n {updatedLabel} {ago(agoSeconds)}\n </span>\n </span>\n );\n}\n"],"mappings":";;;AAkCA,SAAgB,EAAU,GAAiB,GAAsB;AAW/D,QAVI,IAAU,IAAU,EAAE,0CAA0C,WAAW,GAC3E,IAAU,KACL,EAAE,0CAA0C,cAAc,EAAE,GAAG,GAAS,CAAC,GAE9E,IAAU,OACL,EAAE,0CAA0C,cAAc,EAAE,GAAG,KAAK,MAAM,IAAU,GAAG,EAAE,CAAC,GAK5F,EAAE,wCAAwC,cAAc,EAAE,GAAG,KAAK,MAAM,IAAU,KAAK,EAAE,CAAC;;AAyCnG,IAAa,IAAiB,oCAajB,IAAwE;CACnF,UAAU;EAAE,KAAK;EAA4C,UAAU;EAAa;CACpF,WAAW;EAAE,KAAK;EAA6C,UAAU;EAAa;CACtF,QAAQ;EAAE,KAAK;EAA0C,UAAU;EAAU;CAC7E,QAAQ;EAAE,KAAK;EAA0C,UAAU;EAAU;CAC9E;AAmBD,SAAgB,EAAc,GAAqD;CACjF,IAAM,IAAgB,EAAE,6CAA6C,iBAAiB,EAChF,IAAU,EAAE,2CAA2C,UAAU;AACvE,QAAO;EAIL,cAAc,EAAE,4CAA4C,gBAAgB;EAC5E,OAAO;EACP,cAAc;EACd;EACA,YAAY;GACV,SAAS,EAAE,2CAA2C,cAAc;GACpE,SAAS,EAAE,2CAA2C,UAAU;GAChE,MAAM,EAAE,wCAAwC,YAAY;GAC5D,QAAQ,EAAE,0CAA0C,SAAS;GAC7D;GACD;EACF;;AA8BH,SAAgB,EAAY,EAC1B,UACA,eACA,iBACA,cACA,UASC;CAkBD,IAAM,CAAC,GAAK,KAAU,QAAe,KAAK,KAAK,CAAC;AAChD,SAAgB;AACd,MAAI,MAAc,KAAM;AAIxB,IAAO,KAAK,KAAK,CAAC;EAClB,IAAM,IAAK,OAAO,kBAAkB,EAAO,KAAK,KAAK,CAAC,EAAE,IAAK;AAC7D,eAAa,OAAO,cAAc,EAAG;IACpC,CAAC,EAAU,CAAC;CAEf,IAAM,IAAa,MAAc,OAAO,IAAI,KAAK,IAAI,GAAG,KAAK,OAAO,IAAM,KAAa,IAAK,CAAC,EAEvF,IACJ;AACF,QACE,kBAAC,QAAD;EAAM,WAAU;EAAiC,eAAY;YAA7D,CACG,MAAU,UAAU,IACnB,kBAAC,QAAD;GACE,WACE,MAAU,YACN,GAAG,EAAK,uEACR,GAAG,EAAK;GAEd,eAAa,MAAU,YAAY,oBAAoB;aANzD,CAQG,MAAU,YACT,kBAAC,QAAD;IAAM,WAAU;cAAhB,CACE,kBAAC,QAAD,EAAM,WAAU,0GAA2G,CAAA,EAC3H,kBAAC,QAAD,EAAM,WAAU,mEAAoE,CAAA,CAC/E;QAIP,kBAAC,QAAD,EAAM,WAAU,iEAAkE,CAAA,EAEnF,EACI;OACL,MACJ,kBAAC,QAAD,EAAA,UAAA;GACG;GAAa;GAAE,EAAI,EAAW;GAC1B,EAAA,CAAA,CACF"}
1
+ {"version":3,"file":"previewShared.js","names":[],"sources":["../../../../src/bigconsole/components/preview/previewShared.tsx"],"sourcesContent":["/**\n * What is still BigConsole's about the AI preview surfaces.\n *\n * ★★★ THE SHELL, DIVIDERS AND STEP RAIL HAVE MOVED TO fe-libs\n * (`AssistantEntityPreview` / `AssistantStepRail`). They existed here so the\n * full panel and the mini panel could not drift apart; the shared component now\n * guarantees that for both, and for every other product that adopts it.\n *\n * What remains is genuinely local: BigConsole's relationship to the assistant\n * DOCK, and how it words a relative timestamp.\n *\n * Nothing here touches Apollo, React Query, BigConsole context — or, since BC4,\n * the DOM: the dock clearance is a CSS custom property fe-libs publishes, so\n * what is left is one constant plus formatting, which is why the mini panel can\n * live in the app shell without dragging the data layer along.\n */\nimport { useEffect, useState } from 'react';\n\nimport type { AssistantEntityPreviewProps } from '@burdenoff/fe-libs/shared/assistant';\n\nimport type { PreviewStepKey } from '../../assistant/assistantRunStore';\n\n/** The `t` both panels already hold — accepted rather than imported, so this\n * file keeps no provider requirement of its own. */\ntype Translate = (key: string, fallback: string, params?: Record<string, string | number>) => string;\n\n/**\n * \"just now\" / \"40s ago\" / \"12m ago\" / \"3h ago\".\n *\n * ★★ TRANSLATED, and it now has an hour bucket. It used to return English in\n * all three locales (en, hi, ta), and a panel left open past an hour read \"240m ago\" rather\n * than \"4h ago\" — both of which were only visible on the surface that outlives\n * a build, which is exactly the one people leave sitting there.\n */\nexport function formatAgo(seconds: number, t: Translate): string {\n if (seconds < 5) return t('bigconsole.widget.aiPreview.agoJustNow', 'just now');\n if (seconds < 60) {\n return t('bigconsole.widget.aiPreview.agoSeconds', '{{n}}s ago', { n: seconds });\n }\n if (seconds < 3600) {\n return t('bigconsole.widget.aiPreview.agoMinutes', '{{n}}m ago', { n: Math.floor(seconds / 60) });\n }\n // ★ `{{n}}`, not `{n}` — fe-libs' single-brace interpolation was broken until\n // 2026.910.7 and shipped raw braces to users across the fleet. Double braces\n // are what this repo already uses (see `…aiPreviewMini.linkReady`).\n return t('bigconsole.widget.aiPreview.agoHours', '{{n}}h ago', { n: Math.floor(seconds / 3600) });\n}\n\n/**\n * Clearance for the assistant dock, as a CSS length.\n *\n * ★★★ THIS REPLACED A 500ms `querySelector` POLL (BC4, BOFF-7337). The old hook\n * measured `[data-testid=\"assistant-widget-window\"][data-layout=\"sidebar\"]` on an\n * interval because the legacy widget lived in fe-libs, was mounted by the app\n * shell, and emitted nothing when it opened or closed — reading the DOM really\n * was the only signal available.\n *\n * The shared overlay publishes its width instead. fe-libs sets\n * `--assistant-dock-width` on `<html>` from\n * `publishedAssistantDockWidth({ isOpen, docked, isDesktop })` — 440px only when\n * the panel is open AND docked AND the viewport is at least 640px — and REMOVES\n * the property on unmount.\n *\n * ★★★ THE FLOATING PANEL NEEDS CLEARANCE TOO (BOFF-7799, fe-libs 2026.930.3).\n * The dock width is `0px` while the panel FLOATS, which is the default, so\n * reading it alone left the right 45 % of the preview (its close button, its\n * \"Live · updated\" status and the tabs' Open buttons) under the open chat.\n * fe-libs now also publishes `--assistant-panel-inset` from\n * `publishedAssistantPanelInset`: 440px docked, 544px floating (the 520px\n * window plus its 24px right gap), and `0px` closed or below 640px, where the\n * panel is a bottom sheet. It is read FIRST, with the dock width as the fallback\n * for an fe-libs that does not publish it, and `0px` after that for a host with\n * no overlay mounted at all.\n *\n * ★★★ THE FALLBACK FAILS OPEN, SO THE VERSIONS ARE COUPLED. A host shell that\n * pins this package but still mounts the LEGACY `AssistantWidget` publishes no\n * variable at all, this resolves to `0px`, and the preview renders underneath a\n * fixed 440px dock where tabs and Open buttons silently stop taking clicks.\n * Nothing throws and no test fails. bigconsole-app therefore bumps this\n * dependency and mounts `AssistantOverlay` in the SAME commit.\n *\n * ★★ A STRING, NOT A HOOK. It needs no React context and no provider ancestry —\n * which matters because the mini panel is mounted by the app shell, outside the\n * assistant's own tree — and the browser recomputes the margin on open/close\n * with no re-render at all.\n *\n * ★ APPLIED TWO WAYS, DELIBERATELY. The collapsed bars carry only `px-*`, so\n * they take it as `marginRight` and a closed dock reproduces the old `0`\n * exactly. The open panels carry `mx-4 md:mx-6`, so they take it as\n * `paddingRight` and leave those margins alone: the old\n * `assistantWidth ? assistantWidth + 16 : undefined` fell through to the\n * RESPONSIVE 24px gutter at md when closed, and folding a flat `+ 16px` into a\n * calc would have quietly shrunk it on every desktop width. Padding keeps the\n * closed state pixel-identical and only adds clearance while the panel is open.\n */\nexport const DOCK_CLEARANCE = 'var(--assistant-panel-inset, var(--assistant-dock-width, 0px))';\n\n/**\n * Step labels, reusing the TAB keys.\n *\n * ★★ They used to be English constants in the store (`PREVIEW_STEP_LABEL`), so\n * the rail rendered \"Data Sink / Dashboard / Parser / Widget\" in every locale —\n * directly beside the SAME four names rendered translated as tab labels. The\n * keys already exist and are already seeded; nothing new was needed to fix it.\n *\n * ★ Lives here because BOTH panels render the rail. It was defined twice, which\n * is the exact duplication this migration exists to remove.\n */\nexport const STEP_LABEL: Record<PreviewStepKey, { key: string; fallback: string }> = {\n datasink: { key: 'bigconsole.widget.aiPreview.tab.dataSink', fallback: 'Data Sink' },\n dashboard: { key: 'bigconsole.widget.aiPreview.tab.dashboard', fallback: 'Dashboard' },\n parser: { key: 'bigconsole.widget.aiPreview.tab.parser', fallback: 'Parser' },\n widget: { key: 'bigconsole.widget.aiPreview.tab.widget', fallback: 'Widget' },\n};\n\n/**\n * The shared surface's chrome strings, already translated.\n *\n * ★★ ONE copy, deliberately. BOTH defects this migration produced were the same\n * bug written twice — the failure caption and the reopen clock each had to be\n * fixed in the full panel AND the mini panel — so anything the two pass\n * identically belongs here rather than inlined in each. That is the same reason\n * the shell lived in this file before it moved to fe-libs.\n *\n * ★ Both surfaces use the `aiPreview` namespace, not `aiPreviewMini`: the rail\n * says the same thing wherever it is rendered, and splitting the keys would mean\n * translating \"running\" and \"failed\" twice per locale for no difference.\n *\n * `AssistantEntityPreviewProps['labels']` rather than a hand-written shape, so a\n * new label added upstream is a type error here instead of a silently missing\n * string.\n */\nexport function previewLabels(t: Translate): AssistantEntityPreviewProps['labels'] {\n const buildProgress = t('bigconsole.widget.aiPreview.buildProgress', 'Build progress');\n const skipped = t('bigconsole.widget.aiPreview.stepSkipped', 'skipped');\n return {\n // ★ main named the failure \"Build stopped\" in a hardcoded English <h3>. The\n // shared surface cannot know that word — it takes it as a label — so this\n // both restores the name AND makes it translatable for the first time.\n errorHeading: t('bigconsole.widget.aiPreview.errorHeading', 'Build stopped'),\n steps: buildProgress,\n stepsHeading: buildProgress,\n skipped,\n stepStatus: {\n pending: t('bigconsole.widget.aiPreview.stepPending', 'not started'),\n running: t('bigconsole.widget.aiPreview.stepRunning', 'running'),\n done: t('bigconsole.widget.aiPreview.stepDone', 'completed'),\n failed: t('bigconsole.widget.aiPreview.stepFailed', 'failed'),\n skipped,\n },\n };\n}\n\n/**\n * The status strip both panels hand to the shared surface as `meta`.\n *\n * ★★★ ONE copy, and this one is not a tidiness argument — the SAME DEFECT was\n * written into both panels twice over. The migration changed this chip from\n * `bg-status-success-bg` to `bg-status-success-bgSubtle` in both files, and that\n * utility DOES NOT EXIST: the token is `--color-status-success-bgSubtle` but the\n * Tailwind preset exposes it as `status-success-bg-subtle`. The app shell emits\n * `.bg-status-success-bg-subtle` and never `.bg-status-success-bgSubtle`, so the\n * \"Live\" pill lost its background entirely and became transparent text.\n * Nothing failed: an unknown utility is simply absent from the stylesheet.\n *\n * ★ Fixed with the ARBITRARY-VALUE form, `bg-[var(--color-status-…-bgSubtle)]`,\n * which is what the other ~30 sites in this repo use. It names the token\n * directly, so it cannot be broken by a preset key being spelled differently\n * from the variable — which is the entire mechanism of the bug above.\n *\n * ★★ It also carries the FAILED state, which the caption cannot. The shared\n * surface blanks `caption` whenever `error` is set — deliberately, so a rotating\n * \"Creating…\" cannot sit under a dead run — so a product that wants the failure\n * NAMED (as this one did on main, with \"Stopped\") has to say it somewhere the\n * error does not suppress. `meta` is that place: `PreviewHeader` renders it\n * without consulting `error`.\n *\n * Labels are passed in already translated, so the `t('literal.key', …)` calls\n * stay greppable at each call site and each panel keeps its own namespace.\n */\nexport function PreviewMeta({\n state,\n stateLabel,\n updatedLabel,\n updatedAt,\n ago,\n}: {\n state: 'running' | 'stopped' | 'idle';\n stateLabel: string | null;\n updatedLabel: string;\n /** When the run last changed, or null when there is nothing to age. */\n updatedAt: number | null;\n /** Renders the elapsed seconds — `formatAgo` bound to the caller's `t`. */\n ago: (seconds: number) => string;\n}) {\n /**\n * ★★★ THE CLOCK LIVES HERE, in the one element that displays it.\n *\n * It used to live in each panel, and that made a 1 Hz `setState` on the PANEL\n * — which re-rendered everything below it. `AssistantEntityPreview` calls\n * `activeTab.render()` on every render with no memo, so the Widgets tab's live\n * dashboard and every Recharts widget inside it re-rendered once a second, for\n * as long as the preview stayed open. main did not: its ticker was gated on\n * `isRunning`, so it stopped when the build did. Ungating it to fix the frozen\n * timestamp is right, but it has to cost one <span>, not the whole subtree.\n *\n * ★★ Mounting is also the gate now. The mini panel is mounted on EVERY route\n * and returns null when the full panel is up — but a hook cannot sit below an\n * early return, so its interval ran on every page regardless of whether\n * anything was shown. Owning the timer here means \"not rendered\" is \"not\n * ticking\", by construction rather than by remembering to pass a flag.\n */\n const [now, setNow] = useState(() => Date.now());\n useEffect(() => {\n if (updatedAt === null) return;\n // ★ Re-read on mount so a reopened panel cannot show the previous open's\n // reading for up to a second. See the note on lint in the git history:\n // reading the clock in render is an ESLint error (Date.now is impure).\n setNow(Date.now());\n const id = window.setInterval(() => setNow(Date.now()), 1000);\n return () => window.clearInterval(id);\n }, [updatedAt]);\n\n const agoSeconds = updatedAt === null ? 0 : Math.max(0, Math.floor((now - updatedAt) / 1000));\n\n const chip =\n 'inline-flex items-center gap-1.5 rounded-full px-2 py-0.5 text-[11px] font-semibold uppercase tracking-wide';\n return (\n <span className=\"inline-flex items-center gap-2\" data-testid=\"ai-preview-ago\">\n {state !== 'idle' && stateLabel ? (\n <span\n className={\n state === 'running'\n ? `${chip} bg-[var(--color-status-success-bgSubtle)] text-status-success-text`\n : `${chip} bg-[var(--color-status-error-bgSubtle)] text-status-error-text`\n }\n data-testid={state === 'running' ? 'ai-preview-live' : 'ai-preview-stopped'}\n >\n {state === 'running' ? (\n <span className=\"relative flex size-2\">\n <span className=\"absolute inline-flex size-full rounded-full bg-status-success-text opacity-75 motion-safe:animate-ping\" />\n <span className=\"relative inline-flex size-2 rounded-full bg-status-success-text\" />\n </span>\n ) : (\n /* ★ Still, not pulsing: the ping says \"this is happening now\", which\n is the opposite of what a stopped run means. */\n <span className=\"relative inline-flex size-2 rounded-full bg-status-error-text\" />\n )}\n {stateLabel}\n </span>\n ) : null}\n <span>\n {updatedLabel} {ago(agoSeconds)}\n </span>\n </span>\n );\n}\n"],"mappings":";;;AAkCA,SAAgB,EAAU,GAAiB,GAAsB;AAW/D,QAVI,IAAU,IAAU,EAAE,0CAA0C,WAAW,GAC3E,IAAU,KACL,EAAE,0CAA0C,cAAc,EAAE,GAAG,GAAS,CAAC,GAE9E,IAAU,OACL,EAAE,0CAA0C,cAAc,EAAE,GAAG,KAAK,MAAM,IAAU,GAAG,EAAE,CAAC,GAK5F,EAAE,wCAAwC,cAAc,EAAE,GAAG,KAAK,MAAM,IAAU,KAAK,EAAE,CAAC;;AAkDnG,IAAa,IAAiB,kEAajB,IAAwE;CACnF,UAAU;EAAE,KAAK;EAA4C,UAAU;EAAa;CACpF,WAAW;EAAE,KAAK;EAA6C,UAAU;EAAa;CACtF,QAAQ;EAAE,KAAK;EAA0C,UAAU;EAAU;CAC7E,QAAQ;EAAE,KAAK;EAA0C,UAAU;EAAU;CAC9E;AAmBD,SAAgB,EAAc,GAAqD;CACjF,IAAM,IAAgB,EAAE,6CAA6C,iBAAiB,EAChF,IAAU,EAAE,2CAA2C,UAAU;AACvE,QAAO;EAIL,cAAc,EAAE,4CAA4C,gBAAgB;EAC5E,OAAO;EACP,cAAc;EACd;EACA,YAAY;GACV,SAAS,EAAE,2CAA2C,cAAc;GACpE,SAAS,EAAE,2CAA2C,UAAU;GAChE,MAAM,EAAE,wCAAwC,YAAY;GAC5D,QAAQ,EAAE,0CAA0C,SAAS;GAC7D;GACD;EACF;;AA8BH,SAAgB,EAAY,EAC1B,UACA,eACA,iBACA,cACA,UASC;CAkBD,IAAM,CAAC,GAAK,KAAU,QAAe,KAAK,KAAK,CAAC;AAChD,SAAgB;AACd,MAAI,MAAc,KAAM;AAIxB,IAAO,KAAK,KAAK,CAAC;EAClB,IAAM,IAAK,OAAO,kBAAkB,EAAO,KAAK,KAAK,CAAC,EAAE,IAAK;AAC7D,eAAa,OAAO,cAAc,EAAG;IACpC,CAAC,EAAU,CAAC;CAEf,IAAM,IAAa,MAAc,OAAO,IAAI,KAAK,IAAI,GAAG,KAAK,OAAO,IAAM,KAAa,IAAK,CAAC,EAEvF,IACJ;AACF,QACE,kBAAC,QAAD;EAAM,WAAU;EAAiC,eAAY;YAA7D,CACG,MAAU,UAAU,IACnB,kBAAC,QAAD;GACE,WACE,MAAU,YACN,GAAG,EAAK,uEACR,GAAG,EAAK;GAEd,eAAa,MAAU,YAAY,oBAAoB;aANzD,CAQG,MAAU,YACT,kBAAC,QAAD;IAAM,WAAU;cAAhB,CACE,kBAAC,QAAD,EAAM,WAAU,0GAA2G,CAAA,EAC3H,kBAAC,QAAD,EAAM,WAAU,mEAAoE,CAAA,CAC/E;QAIP,kBAAC,QAAD,EAAM,WAAU,iEAAkE,CAAA,EAEnF,EACI;OACL,MACJ,kBAAC,QAAD,EAAA,UAAA;GACG;GAAa;GAAE,EAAI,EAAW;GAC1B,EAAA,CAAA,CACF"}