@flamingo-stack/openframe-frontend-core 0.0.762 → 0.0.764

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 (69) hide show
  1. package/dist/build/export-map.json +1 -1
  2. package/dist/{chunk-J4P47JHM.cjs → chunk-3FC6AKEJ.cjs} +7 -7
  3. package/dist/{chunk-CZ3OVWUL.cjs → chunk-5AV5R5RC.cjs} +6 -6
  4. package/dist/{chunk-TQPQKBBL.cjs → chunk-74ALTXXC.cjs} +34 -34
  5. package/dist/{chunk-DZ6BYXQF.cjs → chunk-7GUWPGB4.cjs} +9 -9
  6. package/dist/{chunk-PE26VSWT.cjs → chunk-BIA77I6B.cjs} +8 -2
  7. package/dist/{chunk-3WPWUUFU.cjs → chunk-FQWBIKF4.cjs} +17 -17
  8. package/dist/{chunk-NSR7K57R.cjs → chunk-IDGOMHTC.cjs} +43 -43
  9. package/dist/{chunk-PFXR3RF3.cjs → chunk-JD7CL2I6.cjs} +4 -4
  10. package/dist/{chunk-N52HFJTK.cjs → chunk-JJ2S6C5U.cjs} +36 -36
  11. package/dist/{chunk-AXGTRPF6.cjs → chunk-L2V7K7RR.cjs} +11 -11
  12. package/dist/{chunk-TGVV7STM.cjs → chunk-LNGR4DXA.cjs} +10 -10
  13. package/dist/{chunk-QCO32MEE.cjs → chunk-NJS7FQRW.cjs} +4 -4
  14. package/dist/{chunk-4NGXJA3V.cjs → chunk-PERN37KO.cjs} +4 -4
  15. package/dist/{chunk-DYJWZIPU.cjs → chunk-RYSNH2VY.cjs} +72 -72
  16. package/dist/{chunk-CEJDHCFZ.cjs → chunk-T5FRANE6.cjs} +21 -21
  17. package/dist/{chunk-72XMAKDA.cjs → chunk-VL6IXTAI.cjs} +174 -144
  18. package/dist/{chunk-TWAHPTWW.cjs → chunk-XFNWHCRM.cjs} +3 -3
  19. package/dist/{chunk-E4LA4BEH.cjs → chunk-ZCU2PYCW.cjs} +9 -9
  20. package/dist/{chunk-4VAMNI27.cjs → chunk-ZG6F5A3A.cjs} +27 -27
  21. package/dist/{cloud-tenants-M5SIL6QZ.cjs → cloud-tenants-N5CLYDPU.cjs} +6 -6
  22. package/dist/components/case-studies/index.cjs +16 -16
  23. package/dist/components/chat/index.cjs +4 -4
  24. package/dist/components/contact/index.cjs +7 -7
  25. package/dist/components/docs/index.cjs +10 -10
  26. package/dist/components/embeds/index.cjs +7 -7
  27. package/dist/components/faq/index.cjs +8 -8
  28. package/dist/components/features/index.cjs +8 -6
  29. package/dist/components/features/walkthrough-video.d.ts +7 -0
  30. package/dist/components/features/walkthrough-video.d.ts.map +1 -1
  31. package/dist/components/features/walkthrough-video.js +9 -1
  32. package/dist/components/help-center-pages/index.cjs +58 -58
  33. package/dist/components/index.cjs +43 -39
  34. package/dist/components/meeting-scheduler/index.cjs +24 -24
  35. package/dist/components/navigation/index.cjs +9 -9
  36. package/dist/components/onboarding-guides/index.cjs +8 -8
  37. package/dist/components/product-demo/index.cjs +8 -8
  38. package/dist/components/tickets/index.cjs +11 -11
  39. package/dist/components/ui/date-picker.d.ts.map +1 -1
  40. package/dist/components/ui/date-picker.js +2 -2
  41. package/dist/components/ui/device-card.d.ts.map +1 -1
  42. package/dist/components/ui/device-card.js +3 -2
  43. package/dist/components/ui/index.cjs +8 -6
  44. package/dist/components/ui/index.d.ts +1 -0
  45. package/dist/components/ui/index.d.ts.map +1 -1
  46. package/dist/components/ui/index.js +1 -0
  47. package/dist/components/ui/super-user-banner-view.d.ts +24 -0
  48. package/dist/components/ui/super-user-banner-view.d.ts.map +1 -0
  49. package/dist/components/ui/super-user-banner-view.js +28 -0
  50. package/dist/{devices-TZY7RF7M.cjs → devices-557PMFDC.cjs} +7 -7
  51. package/dist/{embeddable-chat-HWQSP3DY.cjs → embeddable-chat-YFUCVDMV.cjs} +69 -69
  52. package/dist/index.cjs +14 -10
  53. package/dist/{knowledge-UKC2BLQP.cjs → knowledge-4JTOUDAR.cjs} +7 -7
  54. package/dist/{logs-MFVTQ5NN.cjs → logs-7YWAOPZ2.cjs} +14 -14
  55. package/dist/{policies-BETELENB.cjs → policies-W5JEPQTA.cjs} +10 -10
  56. package/dist/{scripts-XDT3ZAXU.cjs → scripts-FY5IPOIM.cjs} +11 -11
  57. package/dist/{software-update-EW5X7R2X.cjs → software-update-5BOGZOHG.cjs} +9 -9
  58. package/dist/{tickets-board-4PBXPSGJ.cjs → tickets-board-DXMF7IKL.cjs} +7 -7
  59. package/dist/utils/date-utils.d.ts +7 -2
  60. package/dist/utils/date-utils.d.ts.map +1 -1
  61. package/dist/utils/date-utils.js +8 -3
  62. package/dist/utils/index.cjs +7 -2
  63. package/package.json +1 -1
  64. package/src/components/features/walkthrough-video.tsx +17 -0
  65. package/src/components/ui/date-picker.tsx +6 -3
  66. package/src/components/ui/device-card.tsx +5 -6
  67. package/src/components/ui/index.ts +1 -0
  68. package/src/components/ui/super-user-banner-view.tsx +52 -0
  69. package/src/utils/date-utils.ts +17 -8
@@ -8,8 +8,8 @@ var _chunkSTEJZPIOcjs = require('./chunk-STEJZPIO.cjs');
8
8
  var _chunkDKOLQPE7cjs = require('./chunk-DKOLQPE7.cjs');
9
9
 
10
10
 
11
- var _chunk72XMAKDAcjs = require('./chunk-72XMAKDA.cjs');
12
- require('./chunk-E4LA4BEH.cjs');
11
+ var _chunkVL6IXTAIcjs = require('./chunk-VL6IXTAI.cjs');
12
+ require('./chunk-ZCU2PYCW.cjs');
13
13
  require('./chunk-GY2JESOC.cjs');
14
14
  require('./chunk-2IFCRPNP.cjs');
15
15
  require('./chunk-HQQE74RO.cjs');
@@ -21,11 +21,11 @@ require('./chunk-A6P6DHEZ.cjs');
21
21
  require('./chunk-MZ4KBSH7.cjs');
22
22
  require('./chunk-RO72PRQI.cjs');
23
23
  require('./chunk-YUMFVQIN.cjs');
24
- require('./chunk-CEJDHCFZ.cjs');
24
+ require('./chunk-T5FRANE6.cjs');
25
25
 
26
26
 
27
- var _chunkTQPQKBBLcjs = require('./chunk-TQPQKBBL.cjs');
28
- require('./chunk-PE26VSWT.cjs');
27
+ var _chunk74ALTXXCcjs = require('./chunk-74ALTXXC.cjs');
28
+ require('./chunk-BIA77I6B.cjs');
29
29
  require('./chunk-3RFQPQ7Z.cjs');
30
30
  require('./chunk-GZKWF6NH.cjs');
31
31
  require('./chunk-EFTUFJS2.cjs');
@@ -1907,10 +1907,10 @@ function KnowledgeScreen(_props) {
1907
1907
  const cast = _chunkSTEJZPIOcjs.useProductDemoCast.call(void 0, );
1908
1908
  const fixture = _react.useMemo.call(void 0, () => buildKnowledgeFixture(cast), [cast]);
1909
1909
  return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "h-full bg-ods-bg", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1910
- _chunk72XMAKDAcjs.KnowledgeBaseArticleView,
1910
+ _chunkVL6IXTAIcjs.KnowledgeBaseArticleView,
1911
1911
  {
1912
1912
  ...fixture.article,
1913
- content: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkTQPQKBBLcjs.SimpleMarkdownRenderer, { content: fixture.content, textSize: "compact" })
1913
+ content: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk74ALTXXCcjs.SimpleMarkdownRenderer, { content: fixture.content, textSize: "compact" })
1914
1914
  }
1915
1915
  ) });
1916
1916
  }
@@ -16,8 +16,8 @@ var _chunkDKOLQPE7cjs = require('./chunk-DKOLQPE7.cjs');
16
16
 
17
17
 
18
18
 
19
- var _chunk72XMAKDAcjs = require('./chunk-72XMAKDA.cjs');
20
- require('./chunk-E4LA4BEH.cjs');
19
+ var _chunkVL6IXTAIcjs = require('./chunk-VL6IXTAI.cjs');
20
+ require('./chunk-ZCU2PYCW.cjs');
21
21
  require('./chunk-GY2JESOC.cjs');
22
22
  require('./chunk-2IFCRPNP.cjs');
23
23
  require('./chunk-HQQE74RO.cjs');
@@ -31,9 +31,9 @@ require('./chunk-RO72PRQI.cjs');
31
31
  require('./chunk-YUMFVQIN.cjs');
32
32
 
33
33
 
34
- var _chunkCEJDHCFZcjs = require('./chunk-CEJDHCFZ.cjs');
35
- require('./chunk-TQPQKBBL.cjs');
36
- require('./chunk-PE26VSWT.cjs');
34
+ var _chunkT5FRANE6cjs = require('./chunk-T5FRANE6.cjs');
35
+ require('./chunk-74ALTXXC.cjs');
36
+ require('./chunk-BIA77I6B.cjs');
37
37
  require('./chunk-3RFQPQ7Z.cjs');
38
38
  require('./chunk-GZKWF6NH.cjs');
39
39
  require('./chunk-EFTUFJS2.cjs');
@@ -1888,7 +1888,7 @@ function entry(logId, minutesAgo, severity, toolType, device2, summary) {
1888
1888
  id: logId,
1889
1889
  logId,
1890
1890
  timestamp: displayTime(_chunkDKOLQPE7cjs.demoMinutesAgo.call(void 0, minutesAgo)),
1891
- status: { label: severity, variant: _chunk72XMAKDAcjs.logSeverityVariant.call(void 0, severity) },
1891
+ status: { label: severity, variant: _chunkVL6IXTAIcjs.logSeverityVariant.call(void 0, severity) },
1892
1892
  source: { name: toolType, toolType },
1893
1893
  device: device2,
1894
1894
  description: { title: summary }
@@ -1960,13 +1960,13 @@ var NO_FILTERS = {};
1960
1960
  var ACTION_COLUMNS = ["copy", "quickView", "open"];
1961
1961
  var BESIDE_DRAWER_HIDDEN = [...ACTION_COLUMNS, "tool", "source"];
1962
1962
  var logHref = () => "#";
1963
- var copyAction = () => /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk72XMAKDAcjs.LogCopyIconButton, {});
1963
+ var copyAction = () => /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkVL6IXTAIcjs.LogCopyIconButton, {});
1964
1964
  function LogsScreen({ compact = false }) {
1965
1965
  const [dock, setDock] = _react.useState.call(void 0, null);
1966
1966
  const selected = LOGS_FIXTURE_SELECTED;
1967
1967
  return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex h-full bg-ods-bg", children: [
1968
1968
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "min-w-0 flex-1 overflow-clip", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1969
- _chunk72XMAKDAcjs.LogsPageView,
1969
+ _chunkVL6IXTAIcjs.LogsPageView,
1970
1970
  {
1971
1971
  showHeader: false,
1972
1972
  className: "p-[var(--spacing-system-l)]",
@@ -1974,7 +1974,7 @@ function LogsScreen({ compact = false }) {
1974
1974
  onSearchChange: noop,
1975
1975
  onOpenFilters: noop,
1976
1976
  children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1977
- _chunk72XMAKDAcjs.LogsTableView,
1977
+ _chunkVL6IXTAIcjs.LogsTableView,
1978
1978
  {
1979
1979
  logs: LOGS_FIXTURE_ENTRIES,
1980
1980
  facets: LOGS_FIXTURE_FACETS,
@@ -1988,8 +1988,8 @@ function LogsScreen({ compact = false }) {
1988
1988
  )
1989
1989
  }
1990
1990
  ) }),
1991
- !compact && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { ref: setDock, className: "relative w-[calc(400px+var(--spacing-system-m))] shrink-0", children: dock && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk72XMAKDAcjs.AppLayoutDrawerContainerContext.Provider, { value: dock, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1992
- _chunk72XMAKDAcjs.LogDrawer,
1991
+ !compact && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { ref: setDock, className: "relative w-[calc(400px+var(--spacing-system-m))] shrink-0", children: dock && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkVL6IXTAIcjs.AppLayoutDrawerContainerContext.Provider, { value: dock, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1992
+ _chunkVL6IXTAIcjs.LogDrawer,
1993
1993
  {
1994
1994
  docked: true,
1995
1995
  isOpen: true,
@@ -2001,12 +2001,12 @@ function LogsScreen({ compact = false }) {
2001
2001
  { label: "Log ID", value: selected.logId },
2002
2002
  {
2003
2003
  label: "Source",
2004
- value: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk72XMAKDAcjs.ToolBadge, { toolType: _chunkCEJDHCFZcjs.normalizeToolTypeWithFallback.call(void 0, selected.source.toolType) })
2004
+ value: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkVL6IXTAIcjs.ToolBadge, { toolType: _chunkT5FRANE6cjs.normalizeToolTypeWithFallback.call(void 0, selected.source.toolType) })
2005
2005
  },
2006
- { label: "Device", value: _chunk72XMAKDAcjs.logSourceLabels.call(void 0, selected.device).deviceName }
2006
+ { label: "Device", value: _chunkVL6IXTAIcjs.logSourceLabels.call(void 0, selected.device).deviceName }
2007
2007
  ],
2008
2008
  deviceCard: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2009
- _chunk72XMAKDAcjs.DeviceCard,
2009
+ _chunkVL6IXTAIcjs.DeviceCard,
2010
2010
  {
2011
2011
  ...LOGS_FIXTURE_DEVICE,
2012
2012
  actions: {
@@ -10,8 +10,8 @@ var _chunkDKOLQPE7cjs = require('./chunk-DKOLQPE7.cjs');
10
10
 
11
11
 
12
12
 
13
- var _chunk72XMAKDAcjs = require('./chunk-72XMAKDA.cjs');
14
- require('./chunk-E4LA4BEH.cjs');
13
+ var _chunkVL6IXTAIcjs = require('./chunk-VL6IXTAI.cjs');
14
+ require('./chunk-ZCU2PYCW.cjs');
15
15
  require('./chunk-GY2JESOC.cjs');
16
16
  require('./chunk-2IFCRPNP.cjs');
17
17
  require('./chunk-HQQE74RO.cjs');
@@ -23,9 +23,9 @@ require('./chunk-A6P6DHEZ.cjs');
23
23
  require('./chunk-MZ4KBSH7.cjs');
24
24
  require('./chunk-RO72PRQI.cjs');
25
25
  require('./chunk-YUMFVQIN.cjs');
26
- require('./chunk-CEJDHCFZ.cjs');
27
- require('./chunk-TQPQKBBL.cjs');
28
- require('./chunk-PE26VSWT.cjs');
26
+ require('./chunk-T5FRANE6.cjs');
27
+ require('./chunk-74ALTXXC.cjs');
28
+ require('./chunk-BIA77I6B.cjs');
29
29
  require('./chunk-3RFQPQ7Z.cjs');
30
30
  require('./chunk-GZKWF6NH.cjs');
31
31
  require('./chunk-EFTUFJS2.cjs');
@@ -1893,14 +1893,14 @@ var POLICIES = [
1893
1893
  policy("policy-local-admins", "No local admins", "No everyday account is a local administrator.", false, 0)
1894
1894
  ];
1895
1895
  var POLICIES_FIXTURE = {
1896
- summary: _chunk72XMAKDAcjs.computePolicySummary.call(void 0, POLICIES),
1896
+ summary: _chunkVL6IXTAIcjs.computePolicySummary.call(void 0, POLICIES),
1897
1897
  rows: POLICIES.map((item) => ({
1898
1898
  id: item.id,
1899
1899
  name: item.name,
1900
1900
  description: item.description,
1901
1901
  critical: item.critical,
1902
1902
  severityLabel: item.critical ? "Critical" : "Low",
1903
- status: _chunk72XMAKDAcjs.getPolicyTableStatus.call(void 0, item),
1903
+ status: _chunkVL6IXTAIcjs.getPolicyTableStatus.call(void 0, item),
1904
1904
  actions: [
1905
1905
  { label: "Policy Details", onClick: noop },
1906
1906
  { label: "Delete Policy", onClick: noop }
@@ -1914,16 +1914,16 @@ var POLICIES_FIXTURE = {
1914
1914
  var _jsxruntime = require('react/jsx-runtime');
1915
1915
  function PoliciesScreen({ compact = false }) {
1916
1916
  const table = /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1917
- _chunk72XMAKDAcjs.PoliciesTable,
1917
+ _chunkVL6IXTAIcjs.PoliciesTable,
1918
1918
  {
1919
1919
  rows: POLICIES_FIXTURE.rows,
1920
1920
  rowAsLink: true,
1921
- rightSlot: compact ? void 0 : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk72XMAKDAcjs.DataTable.RowCount, {}),
1921
+ rightSlot: compact ? void 0 : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkVL6IXTAIcjs.DataTable.RowCount, {}),
1922
1922
  emptyMessage: "No policies found."
1923
1923
  }
1924
1924
  );
1925
1925
  return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex h-full flex-col gap-[var(--spacing-system-l)] bg-ods-bg p-[var(--spacing-system-l)]", children: [
1926
- !compact && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk72XMAKDAcjs.PolicySummaryCards, { summary: POLICIES_FIXTURE.summary, now: POLICIES_FIXTURE.now }),
1926
+ !compact && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkVL6IXTAIcjs.PolicySummaryCards, { summary: POLICIES_FIXTURE.summary, now: POLICIES_FIXTURE.now }),
1927
1927
  table
1928
1928
  ] });
1929
1929
  }
@@ -13,8 +13,8 @@ var _chunkDKOLQPE7cjs = require('./chunk-DKOLQPE7.cjs');
13
13
 
14
14
 
15
15
 
16
- var _chunk72XMAKDAcjs = require('./chunk-72XMAKDA.cjs');
17
- require('./chunk-E4LA4BEH.cjs');
16
+ var _chunkVL6IXTAIcjs = require('./chunk-VL6IXTAI.cjs');
17
+ require('./chunk-ZCU2PYCW.cjs');
18
18
  require('./chunk-GY2JESOC.cjs');
19
19
 
20
20
 
@@ -28,9 +28,9 @@ require('./chunk-A6P6DHEZ.cjs');
28
28
  require('./chunk-MZ4KBSH7.cjs');
29
29
  require('./chunk-RO72PRQI.cjs');
30
30
  require('./chunk-YUMFVQIN.cjs');
31
- require('./chunk-CEJDHCFZ.cjs');
32
- require('./chunk-TQPQKBBL.cjs');
33
- require('./chunk-PE26VSWT.cjs');
31
+ require('./chunk-T5FRANE6.cjs');
32
+ require('./chunk-74ALTXXC.cjs');
33
+ require('./chunk-BIA77I6B.cjs');
34
34
  require('./chunk-3RFQPQ7Z.cjs');
35
35
  require('./chunk-GZKWF6NH.cjs');
36
36
  require('./chunk-EFTUFJS2.cjs');
@@ -1997,8 +1997,8 @@ function buildScriptsFixture(cast) {
1997
1997
  var _jsxruntime = require('react/jsx-runtime');
1998
1998
  var WIDE_HIDDEN_COLUMNS = ["result", "open"];
1999
1999
  var COMPACT_COLUMNS = [
2000
- { ..._chunk72XMAKDAcjs.EXECUTION_COLUMNS.machineId, width: "flex-1 min-w-0", hideAt: void 0 },
2001
- _chunk72XMAKDAcjs.EXECUTION_COLUMNS.status
2000
+ { ..._chunkVL6IXTAIcjs.EXECUTION_COLUMNS.machineId, width: "flex-1 min-w-0", hideAt: void 0 },
2001
+ _chunkVL6IXTAIcjs.EXECUTION_COLUMNS.status
2002
2002
  ];
2003
2003
  var COMPACT_ROWS = 4;
2004
2004
  var TOKEN_CLASS = {
@@ -2057,7 +2057,7 @@ function ScriptCodePicture({ script }) {
2057
2057
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex min-w-0 items-center justify-between gap-[var(--spacing-system-m)]", children: [
2058
2058
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk2IFCRPNPcjs.TruncateText, { variant: "h6", tone: "secondary", children: `Written by ${provenance.author} \xB7 approved by ${provenance.approver}` }),
2059
2059
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2060
- _chunk72XMAKDAcjs.ScriptShellBadge,
2060
+ _chunkVL6IXTAIcjs.ScriptShellBadge,
2061
2061
  {
2062
2062
  value: script.shellType,
2063
2063
  className: "shrink-0 text-ods-text-secondary text-h6",
@@ -2081,7 +2081,7 @@ function ScriptsScreen({ compact = false }) {
2081
2081
  return (
2082
2082
  // Four runs of the card's row height fill the frame; the padding is what is left round them.
2083
2083
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "h-full overflow-hidden bg-ods-bg p-[var(--spacing-system-xsf)]", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2084
- _chunk72XMAKDAcjs.ScriptExecutionsTable,
2084
+ _chunkVL6IXTAIcjs.ScriptExecutionsTable,
2085
2085
  {
2086
2086
  rows: fixture.executions.slice(0, COMPACT_ROWS),
2087
2087
  columns: COMPACT_COLUMNS,
@@ -2091,13 +2091,13 @@ function ScriptsScreen({ compact = false }) {
2091
2091
  ) })
2092
2092
  );
2093
2093
  }
2094
- const renderOutput = (row) => row.id === fixture.openExecutionId ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk72XMAKDAcjs.ScriptExecutionResult, { result: row.result, empty: "\u2014" }) : null;
2094
+ const renderOutput = (row) => row.id === fixture.openExecutionId ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkVL6IXTAIcjs.ScriptExecutionResult, { result: row.result, empty: "\u2014" }) : null;
2095
2095
  return (
2096
2096
  // The frame's tighter padding and no header row: the output opened under a run needs the height.
2097
2097
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex h-full gap-[var(--spacing-system-m)] overflow-hidden bg-ods-bg p-[var(--spacing-system-m)]", children: [
2098
2098
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "w-[39%] shrink-0", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, ScriptCodePicture, { script: fixture.script }) }),
2099
2099
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "min-w-0 flex-1 overflow-hidden", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2100
- _chunk72XMAKDAcjs.ScriptExecutionsTable,
2100
+ _chunkVL6IXTAIcjs.ScriptExecutionsTable,
2101
2101
  {
2102
2102
  rows: fixture.executions,
2103
2103
  hideColumns: WIDE_HIDDEN_COLUMNS,
@@ -15,8 +15,8 @@ var _chunkDKOLQPE7cjs = require('./chunk-DKOLQPE7.cjs');
15
15
 
16
16
 
17
17
 
18
- var _chunk72XMAKDAcjs = require('./chunk-72XMAKDA.cjs');
19
- require('./chunk-E4LA4BEH.cjs');
18
+ var _chunkVL6IXTAIcjs = require('./chunk-VL6IXTAI.cjs');
19
+ require('./chunk-ZCU2PYCW.cjs');
20
20
  require('./chunk-GY2JESOC.cjs');
21
21
 
22
22
 
@@ -30,9 +30,9 @@ require('./chunk-A6P6DHEZ.cjs');
30
30
  require('./chunk-MZ4KBSH7.cjs');
31
31
  require('./chunk-RO72PRQI.cjs');
32
32
  require('./chunk-YUMFVQIN.cjs');
33
- require('./chunk-CEJDHCFZ.cjs');
34
- require('./chunk-TQPQKBBL.cjs');
35
- require('./chunk-PE26VSWT.cjs');
33
+ require('./chunk-T5FRANE6.cjs');
34
+ require('./chunk-74ALTXXC.cjs');
35
+ require('./chunk-BIA77I6B.cjs');
36
36
  require('./chunk-3RFQPQ7Z.cjs');
37
37
  require('./chunk-GZKWF6NH.cjs');
38
38
  require('./chunk-EFTUFJS2.cjs');
@@ -1924,12 +1924,12 @@ function StaticPackageField({ value }) {
1924
1924
  return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1925
1925
  _chunk2IFCRPNPcjs.Autocomplete,
1926
1926
  {
1927
- label: _chunk72XMAKDAcjs.PACKAGE_SEARCH_LABEL,
1927
+ label: _chunkVL6IXTAIcjs.PACKAGE_SEARCH_LABEL,
1928
1928
  labelVariant: "large",
1929
1929
  options: value ? [{ value: value.id, label: value.name, description: _nullishCoalesce(value.description, () => ( void 0)) }] : [],
1930
1930
  value: _nullishCoalesce(_optionalChain([value, 'optionalAccess', _ => _.id]), () => ( null)),
1931
1931
  onChange: noop,
1932
- placeholder: _chunk72XMAKDAcjs.PACKAGE_SEARCH_PLACEHOLDER
1932
+ placeholder: _chunkVL6IXTAIcjs.PACKAGE_SEARCH_PLACEHOLDER
1933
1933
  }
1934
1934
  );
1935
1935
  }
@@ -1943,7 +1943,7 @@ function SoftwareUpdateScreen({ compact = false }) {
1943
1943
  [fixture.devices, fixture.selectedIds]
1944
1944
  );
1945
1945
  return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "h-full bg-ods-bg pt-[var(--spacing-system-l)]", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "h-full", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1946
- _chunk72XMAKDAcjs.SoftwareActionForm,
1946
+ _chunkVL6IXTAIcjs.SoftwareActionForm,
1947
1947
  {
1948
1948
  action: fixture.action,
1949
1949
  showHeader: false,
@@ -1955,7 +1955,7 @@ function SoftwareUpdateScreen({ compact = false }) {
1955
1955
  initialValues: fixture.initialValues,
1956
1956
  renderPackageSearch,
1957
1957
  renderDevicePicker: () => /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1958
- _chunk72XMAKDAcjs.DeviceSelector,
1958
+ _chunkVL6IXTAIcjs.DeviceSelector,
1959
1959
  {
1960
1960
  devices: selected,
1961
1961
  loading: false,
@@ -10,9 +10,9 @@ var _chunkDKOLQPE7cjs = require('./chunk-DKOLQPE7.cjs');
10
10
 
11
11
 
12
12
 
13
- var _chunkE4LA4BEHcjs = require('./chunk-E4LA4BEH.cjs');
13
+ var _chunkZCU2PYCWcjs = require('./chunk-ZCU2PYCW.cjs');
14
14
  require('./chunk-FQSXZC2K.cjs');
15
- require('./chunk-PE26VSWT.cjs');
15
+ require('./chunk-BIA77I6B.cjs');
16
16
  require('./chunk-EFTUFJS2.cjs');
17
17
  require('./chunk-ZOZR3QI2.cjs');
18
18
  require('./chunk-OMV5S5PI.cjs');
@@ -1840,7 +1840,7 @@ function buildTicketsBoardFixture(cast) {
1840
1840
  const dana = assignee(cast.person("dana"));
1841
1841
  const alex = assignee(cast.person("alex"));
1842
1842
  return [
1843
- _chunkE4LA4BEHcjs.columnFromTicketStatus.call(void 0, "ACTIVE", [
1843
+ _chunkZCU2PYCWcjs.columnFromTicketStatus.call(void 0, "ACTIVE", [
1844
1844
  ticket("tk-1051", "Printer offline at the front desk", "ACTIVE", {
1845
1845
  ticketNumber: "1051",
1846
1846
  agent: "fae",
@@ -1858,7 +1858,7 @@ function buildTicketsBoardFixture(cast) {
1858
1858
  tags: ["onboarding"]
1859
1859
  })
1860
1860
  ]),
1861
- _chunkE4LA4BEHcjs.columnFromTicketStatus.call(void 0, "TECH_REQUIRED", [
1861
+ _chunkZCU2PYCWcjs.columnFromTicketStatus.call(void 0, "TECH_REQUIRED", [
1862
1862
  ticket("tk-1049", "Acrobat Pro for Maya", "TECH_REQUIRED", {
1863
1863
  ticketNumber: "1049",
1864
1864
  agent: "fae",
@@ -1882,7 +1882,7 @@ function buildTicketsBoardFixture(cast) {
1882
1882
  escalatedByUser: true
1883
1883
  })
1884
1884
  ]),
1885
- _chunkE4LA4BEHcjs.columnFromTicketStatus.call(void 0, "ON_HOLD", [
1885
+ _chunkZCU2PYCWcjs.columnFromTicketStatus.call(void 0, "ON_HOLD", [
1886
1886
  ticket("tk-1046", "Replace the conference room display", "ON_HOLD", {
1887
1887
  ticketNumber: "1046",
1888
1888
  organizationName: _chunkDKOLQPE7cjs.DEMO_ORGANIZATIONS.acme.name,
@@ -1891,7 +1891,7 @@ function buildTicketsBoardFixture(cast) {
1891
1891
  activity: { kind: "waiting-external" }
1892
1892
  })
1893
1893
  ]),
1894
- _chunkE4LA4BEHcjs.columnFromTicketStatus.call(void 0,
1894
+ _chunkZCU2PYCWcjs.columnFromTicketStatus.call(void 0,
1895
1895
  "RESOLVED",
1896
1896
  [
1897
1897
  ticket("tk-1048", "Slow laptop", "RESOLVED", {
@@ -1927,7 +1927,7 @@ function TicketsBoardScreen({ compact = false }) {
1927
1927
  const cast = _chunkSTEJZPIOcjs.useProductDemoCast.call(void 0, );
1928
1928
  const board = _react.useMemo.call(void 0, () => buildTicketsBoardFixture(cast), [cast]);
1929
1929
  const columns = compact ? board.filter((column) => column.id !== "ON_HOLD") : board;
1930
- return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "h-full bg-ods-bg p-[var(--spacing-system-m)]", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkE4LA4BEHcjs.Board, { columns, onChange: noop, initialCollapsed: compact ? void 0 : FOLDED }) });
1930
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "h-full bg-ods-bg p-[var(--spacing-system-m)]", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkZCU2PYCWcjs.Board, { columns, onChange: noop, initialCollapsed: compact ? void 0 : FOLDED }) });
1931
1931
  }
1932
1932
 
1933
1933
 
@@ -7,11 +7,16 @@
7
7
  */
8
8
  /**
9
9
  * Relative display label for a ticket timestamp (ISO string).
10
- * < 1 min → "Just now" | 1-59 min → "X min ago" | 1-23 h → "X hour(s) ago" | 24+ h → "MM/DD/YYYY"
10
+ * < 1 min → "Just now" | 1-59 min → "X min ago" | 1-23 h → "X hour(s) ago" | 24+ h → the
11
+ * calendar day as the viewer writes it (`03/20/2026` in en-US, `20/03/2026` in en-AU).
11
12
  */
12
13
  export declare function formatTicketRelativeTime(iso: string): string;
13
14
  /**
14
- * Full tooltip timestamp in "MM/DD/YYYY, H:MM AM/PM" format.
15
+ * Full tooltip timestamp for a ticket — the numeric date and the clock in the
16
+ * viewer's own zone and locale (`03/20/2026, 1:05 PM` in en-US,
17
+ * `20/03/2026, 13:05` in en-AU). A ticket's "created at" is read by the person
18
+ * looking at it, not by a server, so it is not UTC-pinned like content dates.
19
+ * The locale's own 12/24-hour convention applies — no `hour12` is forced.
15
20
  */
16
21
  export declare function formatTicketFullTimestamp(iso: string): string;
17
22
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"date-utils.d.ts","sourceRoot":"","sources":["../../src/utils/date-utils.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAaH;;;GAGG;AACH,wBAAgB,wBAAwB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAY5D;AAED;;GAEG;AACH,wBAAgB,yBAAyB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAI7D;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,CAEnE;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,EAAE,GAAG,EAAE,IAAI,GAAG,MAAM,CA6ClF;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,EAAE,OAAO,GAAE,IAAI,CAAC,qBAA0B,GAAG,MAAM,CAe7G;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,EAAE,OAAO,GAAE,IAAI,CAAC,qBAA0B,GAAG,MAAM,CAYzG;AAED;;;;;GAKG;AACH,wBAAgB,yBAAyB,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,CAwB1E;AAED;;GAEG;AACH,wBAAgB,OAAO,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAKzD;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAOlF;AAED;;GAEG;AACH,wBAAgB,kBAAkB,IAAI,MAAM,CAE3C"}
1
+ {"version":3,"file":"date-utils.d.ts","sourceRoot":"","sources":["../../src/utils/date-utils.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAaH;;;;GAIG;AACH,wBAAgB,wBAAwB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAa5D;AAED;;;;;;GAMG;AACH,wBAAgB,yBAAyB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAO7D;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,CAEnE;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,EAAE,GAAG,EAAE,IAAI,GAAG,MAAM,CA6ClF;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,EAAE,OAAO,GAAE,IAAI,CAAC,qBAA0B,GAAG,MAAM,CAe7G;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,EAAE,OAAO,GAAE,IAAI,CAAC,qBAA0B,GAAG,MAAM,CAYzG;AAED;;;;;GAKG;AACH,wBAAgB,yBAAyB,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,CAwB1E;AAED;;GAEG;AACH,wBAAgB,OAAO,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAKzD;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAOlF;AAED;;GAEG;AACH,wBAAgB,kBAAkB,IAAI,MAAM,CAE3C"}
@@ -1,4 +1,4 @@
1
- import { formatDateWithTimezone } from "./format.js";
1
+ import { formatDateWithTimezone, VIEWER_TIMEZONE } from "./format.js";
2
2
  const ZONED_DATE_FIELDS_MEDIUM_DATETIME = {
3
3
  year: "numeric",
4
4
  month: "short",
@@ -16,10 +16,15 @@ function formatTicketRelativeTime(iso) {
16
16
  if (diffMin < 60) return `${diffMin} min ago`;
17
17
  const diffHours = Math.floor(diffMin / 60);
18
18
  if (diffHours < 24) return diffHours === 1 ? "1 hour ago" : `${diffHours} hours ago`;
19
- return formatDateWithTimezone(date, null, "numeric");
19
+ return formatDateWithTimezone(date, VIEWER_TIMEZONE, "numeric", { viewerLocale: true });
20
20
  }
21
21
  function formatTicketFullTimestamp(iso) {
22
- return formatDateWithTimezone(iso, null, "numericDateTime");
22
+ return formatDateWithTimezone(
23
+ iso,
24
+ VIEWER_TIMEZONE,
25
+ { year: "numeric", month: "2-digit", day: "2-digit", hour: "numeric", minute: "2-digit" },
26
+ { viewerLocale: true }
27
+ );
23
28
  }
24
29
  function formatRelativeTime(timestamp) {
25
30
  return formatRelativeTimeFrom(timestamp, /* @__PURE__ */ new Date());
@@ -82841,10 +82841,15 @@ function formatTicketRelativeTime(iso) {
82841
82841
  if (diffMin < 60) return `${diffMin} min ago`;
82842
82842
  const diffHours = Math.floor(diffMin / 60);
82843
82843
  if (diffHours < 24) return diffHours === 1 ? "1 hour ago" : `${diffHours} hours ago`;
82844
- return formatDateWithTimezone(date, null, "numeric");
82844
+ return formatDateWithTimezone(date, VIEWER_TIMEZONE, "numeric", { viewerLocale: true });
82845
82845
  }
82846
82846
  function formatTicketFullTimestamp(iso) {
82847
- return formatDateWithTimezone(iso, null, "numericDateTime");
82847
+ return formatDateWithTimezone(
82848
+ iso,
82849
+ VIEWER_TIMEZONE,
82850
+ { year: "numeric", month: "2-digit", day: "2-digit", hour: "numeric", minute: "2-digit" },
82851
+ { viewerLocale: true }
82852
+ );
82848
82853
  }
82849
82854
  function formatRelativeTime(timestamp) {
82850
82855
  return formatRelativeTimeFrom(timestamp, /* @__PURE__ */ new Date());
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flamingo-stack/openframe-frontend-core",
3
- "version": "0.0.762",
3
+ "version": "0.0.764",
4
4
  "description": "Shared design system and components for all Flamingo platforms",
5
5
  "type": "module",
6
6
  "sideEffects": [
@@ -79,6 +79,7 @@ import { VolumeXmarkIcon } from '../icons-v2-generated/audio-and-visual/volume-x
79
79
  import { PauseIcon } from '../icons-v2-generated/media-playback/pause-icon';
80
80
  import { PlayIcon } from '../icons-v2-generated/media-playback/play-icon';
81
81
  import { XmarkIcon } from '../icons-v2-generated/signs-and-symbols/xmark-icon';
82
+ import { UnifiedSkeleton } from '../loading/unified-skeleton';
82
83
  import { Button } from '../ui/button';
83
84
  import { DialogPortal, DialogOverlay } from '../ui/dialog';
84
85
  import { SquareAvatar } from '../ui/square-avatar';
@@ -87,6 +88,10 @@ import { Video, type VideoPlayerHandle, type VideoMutedFallbackState } from './v
87
88
  import { VideoPlayBadge, VideoUnmuteGlyph } from './video-center-badge';
88
89
  import { VideoHoverPreviewSurface } from './video-hover-preview';
89
90
 
91
+ /** The inline card's box: 16:9 across the host's width, rounded and bordered. ONE string, read by the card and
92
+ * its skeleton, so the page keeps the same height before and after the player mounts. */
93
+ const INLINE_CARD_BOX_CLASS = 'aspect-video w-full rounded-md border border-ods-border';
94
+
90
95
  /** Wire-shape data for the widget. Kept as the shared contract the hub DAL
91
96
  * re-exports as `PublicWalkthroughVideo & { id }`. `mainVideoUrl`/`youtubeUrl`
92
97
  * stay SEPARATE — YouTube wins when both are set (card matches theater). */
@@ -967,6 +972,7 @@ function WalkthroughVideo({
967
972
  // receives pointer events — the media layer is pointer-events-none, so
968
973
  // a group inside it can never match :hover.
969
974
  'group/card pointer-events-auto relative overflow-hidden rounded-md border border-ods-border bg-ods-card',
975
+ inline && INLINE_CARD_BOX_CLASS,
970
976
  // The lift is what separates a FLOATING card from the page beneath it;
971
977
  // an in-flow block sitting inside a host card needs no shadow at all.
972
978
  !inline && 'shadow-2xl',
@@ -1195,6 +1201,9 @@ function WalkthroughVideo({
1195
1201
 
1196
1202
  return (
1197
1203
  <>
1204
+ {/* Inline, the card mounts after hydration: until then its skeleton holds the same box, so the page below
1205
+ does not jump when the player appears. A floating card is an overlay and takes no space. */}
1206
+ {inline && !showCard && !dismissed && <InlineWalkthroughVideoSkeleton className={className} />}
1198
1207
  {showCard &&
1199
1208
  (inline ? (
1200
1209
  // No wrapper: a positioning / z-index / safe-area shell around an
@@ -1314,3 +1323,11 @@ export function FloatingWalkthroughVideo(props: FloatingWalkthroughVideoProps):
1314
1323
  export function InlineWalkthroughVideo(props: InlineWalkthroughVideoProps): React.ReactElement {
1315
1324
  return <WalkthroughVideo {...props} placement="inline" appearDelayMs={0} dismissal={false} />;
1316
1325
  }
1326
+
1327
+ /**
1328
+ * The inline video's loading state: the shared skeleton in the card's own box. The inline card draws it itself
1329
+ * until its player mounts; a host whose video data is still loading draws it in the same slot.
1330
+ */
1331
+ export function InlineWalkthroughVideoSkeleton({ className }: { className?: string }): React.ReactElement {
1332
+ return <UnifiedSkeleton className={cn(INLINE_CARD_BOX_CLASS, className)} />;
1333
+ }
@@ -64,8 +64,10 @@ export type DatePickerProps = SingleDatePickerProps | RangeDatePickerProps;
64
64
 
65
65
  // A picked date is a LOCAL calendar date (the grid builds it from y/m/d in the
66
66
  // browser's zone), so it renders in the viewer's zone — UTC would move it a day
67
- // for anyone east of Greenwich.
68
- const defaultFormatDate = (date: Date): string => formatDateWithTimezone(date, VIEWER_TIMEZONE, 'numeric');
67
+ // for anyone east of Greenwich — and in the viewer's locale: the field reads the
68
+ // way its user writes dates (`03/20/2026` in en-US, `20/03/2026` in en-AU).
69
+ const defaultFormatDate = (date: Date): string =>
70
+ formatDateWithTimezone(date, VIEWER_TIMEZONE, 'numeric', { viewerLocale: true });
69
71
 
70
72
  const formatDateRange = (range: DateRange | undefined, formatFn: (date: Date) => string): string => {
71
73
  if (!range?.from) return '';
@@ -464,7 +466,8 @@ export function DatePickerCalendar({
464
466
  const handlePreviousMonth = () => shiftMonth(-1);
465
467
  const handleNextMonth = () => shiftMonth(1);
466
468
 
467
- const formatMonthYear = (date: Date): string => formatDateWithTimezone(date, VIEWER_TIMEZONE, 'monthYear');
469
+ const formatMonthYear = (date: Date): string =>
470
+ formatDateWithTimezone(date, VIEWER_TIMEZONE, 'monthYear', { viewerLocale: true });
468
471
 
469
472
  const getSecondMonth = (date: Date): Date => {
470
473
  const next = new Date(date);
@@ -2,7 +2,7 @@
2
2
 
3
3
  import type React from 'react';
4
4
  import { cn } from '../../utils/cn';
5
- import { formatDateTimeYmd } from '../../utils/format';
5
+ import { formatDate, formatTime } from '../../utils/format-date';
6
6
  import type { OSPlatformId } from '../../utils/os-platforms';
7
7
  import { OSTypeIcon } from '../features/os-type-badge';
8
8
  import { MonitorIcon } from '../icons-v2-generated/devices/monitor-icon';
@@ -61,13 +61,12 @@ export function DeviceCard({
61
61
  className,
62
62
  ...props
63
63
  }: DeviceCardProps) {
64
- // Format date for last seen
64
+ // "Last seen" is read as "your local time", the same way the devices table
65
+ // column renders it: the viewer's zone and locale, never UTC.
65
66
  const formatLastSeen = (lastSeen?: string | Date) => {
66
67
  if (!lastSeen) return null;
67
-
68
- // UTC-pinned so the server and every client agree (React #418), through the
69
- // one renderer rather than hand-built `getUTC*` strings.
70
- return formatDateTimeYmd(lastSeen, null) || null;
68
+ const date = formatDate(lastSeen);
69
+ return date === '—' ? null : `${date} ${formatTime(lastSeen)}`;
71
70
  };
72
71
 
73
72
  return (
@@ -249,6 +249,7 @@ export * from './incident-feed';
249
249
  export * from './status-line';
250
250
  export * from './snap-carousel';
251
251
  export * from './sticky-action-bar';
252
+ export * from './super-user-banner-view';
252
253
  export { RequiredMark } from './required-mark';
253
254
  export { IconTile } from './icon-tile';
254
255
  export { PolicyLink } from './policy-link';
@@ -0,0 +1,52 @@
1
+ 'use client';
2
+
3
+ import { cn } from '../../utils/cn';
4
+ import { AlertTriangleIcon } from '../icons-v2-generated';
5
+ import { AnnouncementBarView } from './announcement-bar-view';
6
+ import { Tag } from './tag';
7
+
8
+ export interface SuperUserBannerViewProps {
9
+ /** The tenant whose data is on screen - never the super tenant the session belongs to. */
10
+ tenantName: string;
11
+ /**
12
+ * Trailing environment chip ("Production environment"). Omit it where the
13
+ * host has no environment to name; the strip then ends at the text.
14
+ */
15
+ environmentLabel?: string;
16
+ className?: string;
17
+ }
18
+
19
+ /**
20
+ * The strip a super user sees over every page while looking at a tenant that
21
+ * is not their own: who you are acting as, and whose data it is. Props-only;
22
+ * the host decides when it shows (a super user session) and what it names
23
+ * (the tenant of the current host, not the one on `/me`).
24
+ *
25
+ * A skin over `AnnouncementBarView` rather than a strip of its own: the slots,
26
+ * the one-line truncation and the touch-width behaviour are that bar's. What
27
+ * this adds is the design's error surface - error-secondary fill, an error
28
+ * rule along the bottom, the triangle in error, the role in error and the
29
+ * tenant in primary text at body scale - and the environment chip at the end.
30
+ */
31
+ export function SuperUserBannerView({ tenantName, environmentLabel, className }: SuperUserBannerViewProps) {
32
+ return (
33
+ <AnnouncementBarView
34
+ className={cn('shrink-0 border-b border-ods-error bg-ods-error-secondary text-ods-text-primary', className)}
35
+ contentClassName="gap-[var(--spacing-system-s)] py-[var(--spacing-system-m)] pl-[var(--spacing-system-m)]"
36
+ startAdornment={<AlertTriangleIcon className="size-6 shrink-0 text-ods-error" aria-hidden="true" />}
37
+ title={
38
+ <p className="mb-0 min-w-0 max-w-full truncate text-h4">
39
+ <span className="text-ods-error">Super user access: </span>
40
+ <span>{tenantName}</span>
41
+ </p>
42
+ }
43
+ endAdornment={
44
+ // Below `md` the chip would take the width the tenant name needs, and
45
+ // the name is the point of the strip: the chip waits for `md`.
46
+ environmentLabel ? (
47
+ <Tag variant="critical" label={environmentLabel} className="uppercase max-md:hidden" />
48
+ ) : undefined
49
+ }
50
+ />
51
+ );
52
+ }