@burdenoff/microfe-bigconsole 2026.925.2 → 2026.928.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bigconsole/components/embed/EmbedWidgetRenderer.js +43 -13
- package/dist/bigconsole/components/embed/EmbedWidgetRenderer.js.map +1 -1
- package/dist/bigconsole/components/embed/renderer-manifest.js +14 -47
- package/dist/bigconsole/components/embed/renderer-manifest.js.map +1 -1
- package/dist/bigconsole/components/embed/widgetShim.js +28 -0
- package/dist/bigconsole/components/embed/widgetShim.js.map +1 -0
- package/dist/bigconsole/components/embed/widgets/CalendarEmbed.js +38 -0
- package/dist/bigconsole/components/embed/widgets/CalendarEmbed.js.map +1 -0
- package/dist/bigconsole/components/embed/widgets/ChartEmbed.js +225 -0
- package/dist/bigconsole/components/embed/widgets/ChartEmbed.js.map +1 -0
- package/dist/bigconsole/components/embed/widgets/EmbedFrame.js +18 -0
- package/dist/bigconsole/components/embed/widgets/EmbedFrame.js.map +1 -0
- package/dist/bigconsole/components/embed/widgets/FormEmbed.js +147 -0
- package/dist/bigconsole/components/embed/widgets/FormEmbed.js.map +1 -0
- package/dist/bigconsole/components/embed/widgets/GaugeEmbed.js +44 -0
- package/dist/bigconsole/components/embed/widgets/GaugeEmbed.js.map +1 -0
- package/dist/bigconsole/components/embed/widgets/HeatmapEmbed.js +35 -0
- package/dist/bigconsole/components/embed/widgets/HeatmapEmbed.js.map +1 -0
- package/dist/bigconsole/components/embed/widgets/KanbanEmbed.js +50 -0
- package/dist/bigconsole/components/embed/widgets/KanbanEmbed.js.map +1 -0
- package/dist/bigconsole/components/embed/widgets/PivotEmbed.js +146 -0
- package/dist/bigconsole/components/embed/widgets/PivotEmbed.js.map +1 -0
- package/dist/bigconsole/components/embed/widgets/ProgressEmbed.js +30 -0
- package/dist/bigconsole/components/embed/widgets/ProgressEmbed.js.map +1 -0
- package/dist/bigconsole/components/embed/widgets/RetentionEmbed.js +41 -0
- package/dist/bigconsole/components/embed/widgets/RetentionEmbed.js.map +1 -0
- package/dist/bigconsole/components/embed/widgets/TimelineEmbed.js +40 -0
- package/dist/bigconsole/components/embed/widgets/TimelineEmbed.js.map +1 -0
- package/dist/bigconsole/components/embed/widgets/shared.js +13 -1
- package/dist/bigconsole/components/embed/widgets/shared.js.map +1 -1
- package/dist/bigconsole/components/widgets/calendar/CalendarView.js +152 -0
- package/dist/bigconsole/components/widgets/calendar/CalendarView.js.map +1 -0
- package/dist/bigconsole/components/widgets/calendar/CalendarWidget.js +10 -147
- package/dist/bigconsole/components/widgets/calendar/CalendarWidget.js.map +1 -1
- package/dist/bigconsole/components/widgets/chart/ChartWidget.js +19 -19
- package/dist/bigconsole/components/widgets/chart/index.js +8 -8
- package/dist/bigconsole/components/widgets/index.js +5 -5
- package/dist/bigconsole/components/widgets/kanban/KanbanView.js +192 -0
- package/dist/bigconsole/components/widgets/kanban/KanbanView.js.map +1 -0
- package/dist/bigconsole/components/widgets/kanban/KanbanWidget.js +10 -187
- package/dist/bigconsole/components/widgets/kanban/KanbanWidget.js.map +1 -1
- package/dist/bigconsole/components/widgets/metric-card/MetricCardWidget.js +20 -20
- package/dist/bigconsole/components/widgets/timeline/TimelineWidget.js +23 -22
- package/dist/bigconsole/components/widgets/timeline/TimelineWidget.js.map +1 -1
- package/dist/bigconsole/components/widgets/utils/translate.js +9 -0
- package/dist/bigconsole/components/widgets/utils/translate.js.map +1 -0
- package/package.json +1 -1
|
@@ -5,32 +5,62 @@ import { KpiComparisonEmbed as r } from "./widgets/KpiComparisonEmbed.js";
|
|
|
5
5
|
import { TableEmbed as i } from "./widgets/TableEmbed.js";
|
|
6
6
|
import { ListEmbed as a } from "./widgets/ListEmbed.js";
|
|
7
7
|
import { TextEmbed as o } from "./widgets/TextEmbed.js";
|
|
8
|
-
import {
|
|
8
|
+
import { GaugeEmbed as s } from "./widgets/GaugeEmbed.js";
|
|
9
|
+
import { ProgressEmbed as c } from "./widgets/ProgressEmbed.js";
|
|
10
|
+
import { HeatmapEmbed as l } from "./widgets/HeatmapEmbed.js";
|
|
11
|
+
import { RetentionEmbed as u } from "./widgets/RetentionEmbed.js";
|
|
12
|
+
import { TimelineEmbed as d } from "./widgets/TimelineEmbed.js";
|
|
13
|
+
import { CalendarEmbed as f } from "./widgets/CalendarEmbed.js";
|
|
14
|
+
import { KanbanEmbed as p } from "./widgets/KanbanEmbed.js";
|
|
15
|
+
import { PivotEmbed as m } from "./widgets/PivotEmbed.js";
|
|
16
|
+
import { FormEmbed as h } from "./widgets/FormEmbed.js";
|
|
17
|
+
import { Suspense as g, lazy as _ } from "react";
|
|
18
|
+
import { jsx as v } from "react/jsx-runtime";
|
|
9
19
|
//#region src/bigconsole/components/embed/EmbedWidgetRenderer.tsx
|
|
10
|
-
var
|
|
20
|
+
var y = _(() => import("./widgets/ChartEmbed.js")), b = {
|
|
11
21
|
metric_card: n,
|
|
12
22
|
kpi_card_comparison: r,
|
|
13
23
|
table: i,
|
|
14
24
|
list: a,
|
|
15
|
-
text: o
|
|
25
|
+
text: o,
|
|
26
|
+
chart: y,
|
|
27
|
+
funnel_chart: y,
|
|
28
|
+
pivot_table: m,
|
|
29
|
+
gauge: s,
|
|
30
|
+
progress: c,
|
|
31
|
+
form: h,
|
|
32
|
+
heatmap: l,
|
|
33
|
+
calendar: f,
|
|
34
|
+
kanban: p,
|
|
35
|
+
timeline: d,
|
|
36
|
+
retention: u
|
|
16
37
|
};
|
|
17
|
-
function
|
|
18
|
-
return Object.keys(
|
|
38
|
+
function x() {
|
|
39
|
+
return Object.keys(b);
|
|
19
40
|
}
|
|
20
|
-
function
|
|
21
|
-
return /* @__PURE__ */
|
|
41
|
+
function S({ title: e }) {
|
|
42
|
+
return /* @__PURE__ */ v("div", {
|
|
22
43
|
className: "flex h-full w-full items-center justify-center bg-bg-surface p-4 text-center text-sm text-text-tertiary",
|
|
23
44
|
children: e ? `“${e}” is not available in this embed.` : "This widget is not available in this embed."
|
|
24
45
|
});
|
|
25
46
|
}
|
|
26
|
-
function
|
|
27
|
-
|
|
28
|
-
|
|
47
|
+
function C() {
|
|
48
|
+
return /* @__PURE__ */ v("div", {
|
|
49
|
+
className: "h-full w-full animate-pulse bg-bg-sunken/60",
|
|
50
|
+
"aria-busy": "true"
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
function w(n) {
|
|
54
|
+
let { widget: r } = n, i = e[r.type]?.support === "implemented" ? b[r.type] : void 0;
|
|
55
|
+
return i ? /* @__PURE__ */ v(t, {
|
|
29
56
|
label: "widget",
|
|
30
|
-
children: /* @__PURE__ */
|
|
31
|
-
|
|
57
|
+
children: /* @__PURE__ */ v(g, {
|
|
58
|
+
fallback: /* @__PURE__ */ v(C, {}),
|
|
59
|
+
children: /* @__PURE__ */ v(i, { ...n })
|
|
60
|
+
})
|
|
61
|
+
}) : /* @__PURE__ */ v(S, { title: r.title });
|
|
32
62
|
}
|
|
33
63
|
//#endregion
|
|
34
|
-
export {
|
|
64
|
+
export { w as EmbedWidgetRenderer, x as getImplementedRendererTypes };
|
|
35
65
|
|
|
36
66
|
//# sourceMappingURL=EmbedWidgetRenderer.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"EmbedWidgetRenderer.js","names":[],"sources":["../../../../src/bigconsole/components/embed/EmbedWidgetRenderer.tsx"],"sourcesContent":["/**\n * Strict embed widget dispatcher (BOFF-2986).\n *\n * Maps a sanitized widget DTO to its embed renderer via an EXACT registry.\n * There is NO silent fallback (unlike the authenticated WidgetRendererFactory):\n * a type that is not `implemented` in the coverage manifest renders a neutral\n * \"not available\" placeholder, never a guessed or partial widget. Each widget is\n * wrapped in its own error boundary so one failure can't take down the page.\n */\n\nimport type
|
|
1
|
+
{"version":3,"file":"EmbedWidgetRenderer.js","names":[],"sources":["../../../../src/bigconsole/components/embed/EmbedWidgetRenderer.tsx"],"sourcesContent":["/**\n * Strict embed widget dispatcher (BOFF-2986).\n *\n * Maps a sanitized widget DTO to its embed renderer via an EXACT registry.\n * There is NO silent fallback (unlike the authenticated WidgetRendererFactory):\n * a type that is not `implemented` in the coverage manifest renders a neutral\n * \"not available\" placeholder, never a guessed or partial widget. Each widget is\n * wrapped in its own error boundary so one failure can't take down the page.\n */\n\nimport { lazy, Suspense, type ComponentType } from 'react';\nimport type { WidgetType } from '../../types';\nimport type { EmbedWidgetRenderProps } from './types';\nimport { EMBED_WIDGET_COVERAGE } from './renderer-manifest';\nimport { EmbedErrorBoundary } from './EmbedErrorBoundary';\nimport { MetricCardEmbed } from './widgets/MetricCardEmbed';\nimport { KpiComparisonEmbed } from './widgets/KpiComparisonEmbed';\nimport { TableEmbed } from './widgets/TableEmbed';\nimport { ListEmbed } from './widgets/ListEmbed';\nimport { TextEmbed } from './widgets/TextEmbed';\nimport { GaugeEmbed } from './widgets/GaugeEmbed';\nimport { ProgressEmbed } from './widgets/ProgressEmbed';\nimport { HeatmapEmbed } from './widgets/HeatmapEmbed';\nimport { RetentionEmbed } from './widgets/RetentionEmbed';\nimport { TimelineEmbed } from './widgets/TimelineEmbed';\nimport { CalendarEmbed } from './widgets/CalendarEmbed';\nimport { KanbanEmbed } from './widgets/KanbanEmbed';\nimport { PivotEmbed } from './widgets/PivotEmbed';\nimport { FormEmbed } from './widgets/FormEmbed';\n\n// recharts is by far the largest dependency of the embed bundle — load it only\n// when a published dashboard actually contains a chart (BOFF-7926). The host\n// build must emit chunks relative to the entry (`base: './'`) so the chunk is\n// fetched from the asset origin the embed CSP allows.\nconst ChartEmbed = lazy(() => import('./widgets/ChartEmbed'));\n\n/**\n * Registry of implemented renderers. Every key here MUST be marked\n * `implemented` in EMBED_WIDGET_COVERAGE, and vice-versa — the completeness test\n * asserts the two stay in lockstep, so a renderer can never be silently missing\n * for a type the manifest claims to support.\n */\nconst IMPLEMENTED_RENDERERS: Partial<Record<WidgetType, ComponentType<EmbedWidgetRenderProps>>> = {\n metric_card: MetricCardEmbed,\n kpi_card_comparison: KpiComparisonEmbed,\n table: TableEmbed,\n list: ListEmbed,\n text: TextEmbed,\n chart: ChartEmbed,\n funnel_chart: ChartEmbed,\n pivot_table: PivotEmbed,\n gauge: GaugeEmbed,\n progress: ProgressEmbed,\n form: FormEmbed,\n heatmap: HeatmapEmbed,\n calendar: CalendarEmbed,\n kanban: KanbanEmbed,\n timeline: TimelineEmbed,\n retention: RetentionEmbed,\n};\n\nexport function getImplementedRendererTypes(): WidgetType[] {\n return Object.keys(IMPLEMENTED_RENDERERS) as WidgetType[];\n}\n\nfunction UnavailableWidget({ title }: { title?: string }) {\n return (\n <div className=\"flex h-full w-full items-center justify-center bg-bg-surface p-4 text-center text-sm text-text-tertiary\">\n {title ? `“${title}” is not available in this embed.` : 'This widget is not available in this embed.'}\n </div>\n );\n}\n\nfunction WidgetLoading() {\n return <div className=\"h-full w-full animate-pulse bg-bg-sunken/60\" aria-busy=\"true\" />;\n}\n\nexport function EmbedWidgetRenderer(props: EmbedWidgetRenderProps) {\n const { widget } = props;\n const coverage = EMBED_WIDGET_COVERAGE[widget.type];\n const Renderer = coverage?.support === 'implemented' ? IMPLEMENTED_RENDERERS[widget.type] : undefined;\n\n if (!Renderer) {\n return <UnavailableWidget title={widget.title} />;\n }\n\n return (\n <EmbedErrorBoundary label=\"widget\">\n <Suspense fallback={<WidgetLoading />}>\n <Renderer {...props} />\n </Suspense>\n </EmbedErrorBoundary>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAkCA,IAAM,IAAa,QAAW,OAAO,2BAAwB,EAQvD,IAA4F;CAChG,aAAa;CACb,qBAAqB;CACrB,OAAO;CACP,MAAM;CACN,MAAM;CACN,OAAO;CACP,cAAc;CACd,aAAa;CACb,OAAO;CACP,UAAU;CACV,MAAM;CACN,SAAS;CACT,UAAU;CACV,QAAQ;CACR,UAAU;CACV,WAAW;CACZ;AAED,SAAgB,IAA4C;AAC1D,QAAO,OAAO,KAAK,EAAsB;;AAG3C,SAAS,EAAkB,EAAE,YAA6B;AACxD,QACE,kBAAC,OAAD;EAAK,WAAU;YACZ,IAAQ,IAAI,EAAM,qCAAqC;EACpD,CAAA;;AAIV,SAAS,IAAgB;AACvB,QAAO,kBAAC,OAAD;EAAK,WAAU;EAA8C,aAAU;EAAS,CAAA;;AAGzF,SAAgB,EAAoB,GAA+B;CACjE,IAAM,EAAE,cAAW,GAEb,IADW,EAAsB,EAAO,OACnB,YAAY,gBAAgB,EAAsB,EAAO,QAAQ,KAAA;AAM5F,QAJK,IAKH,kBAAC,GAAD;EAAoB,OAAM;YACxB,kBAAC,GAAD;GAAU,UAAU,kBAAC,GAAD,EAAiB,CAAA;aACnC,kBAAC,GAAD,EAAU,GAAI,GAAS,CAAA;GACd,CAAA;EACQ,CAAA,GARd,kBAAC,GAAD,EAAmB,OAAO,EAAO,OAAS,CAAA"}
|
|
@@ -6,61 +6,28 @@ var e = {
|
|
|
6
6
|
table: { support: "implemented" },
|
|
7
7
|
list: { support: "implemented" },
|
|
8
8
|
text: { support: "implemented" },
|
|
9
|
-
chart: {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
},
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
},
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
},
|
|
21
|
-
gauge: {
|
|
22
|
-
support: "blocked",
|
|
23
|
-
reason: "gauge renderer pending"
|
|
24
|
-
},
|
|
25
|
-
progress: {
|
|
26
|
-
support: "blocked",
|
|
27
|
-
reason: "progress renderer pending"
|
|
28
|
-
},
|
|
29
|
-
form: {
|
|
30
|
-
support: "blocked",
|
|
31
|
-
reason: "requires side-effect action broker (post read-only MVP)"
|
|
32
|
-
},
|
|
9
|
+
chart: { support: "implemented" },
|
|
10
|
+
funnel_chart: { support: "implemented" },
|
|
11
|
+
pivot_table: { support: "implemented" },
|
|
12
|
+
gauge: { support: "implemented" },
|
|
13
|
+
progress: { support: "implemented" },
|
|
14
|
+
form: { support: "implemented" },
|
|
15
|
+
heatmap: { support: "implemented" },
|
|
16
|
+
calendar: { support: "implemented" },
|
|
17
|
+
kanban: { support: "implemented" },
|
|
18
|
+
timeline: { support: "implemented" },
|
|
19
|
+
retention: { support: "implemented" },
|
|
33
20
|
iframe: {
|
|
34
21
|
support: "blocked",
|
|
35
|
-
reason: "requires frozen exact-origin
|
|
22
|
+
reason: "requires publish-time frozen exact-origin + frame-src CSP (BOFF-7926 slice 9)"
|
|
36
23
|
},
|
|
37
24
|
map: {
|
|
38
25
|
support: "blocked",
|
|
39
|
-
reason: "requires
|
|
40
|
-
},
|
|
41
|
-
heatmap: {
|
|
42
|
-
support: "blocked",
|
|
43
|
-
reason: "heatmap renderer pending"
|
|
44
|
-
},
|
|
45
|
-
calendar: {
|
|
46
|
-
support: "blocked",
|
|
47
|
-
reason: "calendar renderer pending"
|
|
48
|
-
},
|
|
49
|
-
kanban: {
|
|
50
|
-
support: "blocked",
|
|
51
|
-
reason: "kanban renderer pending"
|
|
52
|
-
},
|
|
53
|
-
timeline: {
|
|
54
|
-
support: "blocked",
|
|
55
|
-
reason: "timeline renderer pending"
|
|
56
|
-
},
|
|
57
|
-
retention: {
|
|
58
|
-
support: "blocked",
|
|
59
|
-
reason: "retention/cohort renderer pending"
|
|
26
|
+
reason: "requires publish-time tile provider + img-src CSP (BOFF-7926 slice 9)"
|
|
60
27
|
},
|
|
61
28
|
custom: {
|
|
62
29
|
support: "blocked",
|
|
63
|
-
reason: "requires nested opaque-origin sandbox
|
|
30
|
+
reason: "requires nested opaque-origin sandbox document (BOFF-7926 slice 10)"
|
|
64
31
|
}
|
|
65
32
|
};
|
|
66
33
|
function t(t) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"renderer-manifest.js","names":[],"sources":["../../../../src/bigconsole/components/embed/renderer-manifest.ts"],"sourcesContent":["/**\n * Embed widget coverage manifest (BOFF-2986).\n *\n * A COMPLETE, explicit decision for every persisted widget type. There is no\n * silent fallback: a type is either `implemented` (has a sanitizer + embed\n * renderer + test) or `blocked` (publication containing it is rejected, and the\n * runtime renders a safe placeholder — never a wrong or partial widget).\n *\n * The completeness test (`renderer-manifest.test.ts`) enumerates the\n * `WidgetType` union and fails the build if any type is missing from this map,\n * so a newly-added widget type cannot ship without an explicit embed decision.\n */\n\nimport type { WidgetType } from '../../types';\nimport { EMBED_RENDER_MODEL_VERSION } from './types';\n\nexport type EmbedWidgetSupport = 'implemented' | 'blocked';\n\nexport interface EmbedWidgetCoverage {\n readonly support: EmbedWidgetSupport;\n /** Why a type is blocked (surfaced to publication validation + operators). */\n readonly reason?: string;\n}\n\n/**\n * Every `WidgetType` MUST appear here. Implemented set is the read-only MVP\n * native-data core; the rest are blocked with a concrete reason until their\n * sanitizer + renderer + tests land (each will flip to `implemented` in a\n * follow-up within this same renderer PR).\n */\nexport const EMBED_WIDGET_COVERAGE: Record<WidgetType, EmbedWidgetCoverage> = {\n // --- implemented (native data, no external fetch, no sandbox) ---\n metric_card: { support: 'implemented' },\n kpi_card_comparison: { support: 'implemented' },\n table: { support: 'implemented' },\n list: { support: 'implemented' },\n text: { support: 'implemented' },\n\n // --- blocked (pending sanitizer/renderer/tests in this PR) ---\n chart: { support: '
|
|
1
|
+
{"version":3,"file":"renderer-manifest.js","names":[],"sources":["../../../../src/bigconsole/components/embed/renderer-manifest.ts"],"sourcesContent":["/**\n * Embed widget coverage manifest (BOFF-2986).\n *\n * A COMPLETE, explicit decision for every persisted widget type. There is no\n * silent fallback: a type is either `implemented` (has a sanitizer + embed\n * renderer + test) or `blocked` (publication containing it is rejected, and the\n * runtime renders a safe placeholder — never a wrong or partial widget).\n *\n * The completeness test (`renderer-manifest.test.ts`) enumerates the\n * `WidgetType` union and fails the build if any type is missing from this map,\n * so a newly-added widget type cannot ship without an explicit embed decision.\n */\n\nimport type { WidgetType } from '../../types';\nimport { EMBED_RENDER_MODEL_VERSION } from './types';\n\nexport type EmbedWidgetSupport = 'implemented' | 'blocked';\n\nexport interface EmbedWidgetCoverage {\n readonly support: EmbedWidgetSupport;\n /** Why a type is blocked (surfaced to publication validation + operators). */\n readonly reason?: string;\n}\n\n/**\n * Every `WidgetType` MUST appear here. Implemented set is the read-only MVP\n * native-data core; the rest are blocked with a concrete reason until their\n * sanitizer + renderer + tests land (each will flip to `implemented` in a\n * follow-up within this same renderer PR).\n */\nexport const EMBED_WIDGET_COVERAGE: Record<WidgetType, EmbedWidgetCoverage> = {\n // --- implemented (native data, no external fetch, no sandbox) ---\n metric_card: { support: 'implemented' },\n kpi_card_comparison: { support: 'implemented' },\n table: { support: 'implemented' },\n list: { support: 'implemented' },\n text: { support: 'implemented' },\n\n // --- blocked (pending sanitizer/renderer/tests in this PR) ---\n chart: { support: 'implemented' },\n funnel_chart: { support: 'implemented' },\n pivot_table: { support: 'implemented' },\n gauge: { support: 'implemented' },\n progress: { support: 'implemented' },\n form: { support: 'implemented' },\n heatmap: { support: 'implemented' },\n calendar: { support: 'implemented' },\n kanban: { support: 'implemented' },\n timeline: { support: 'implemented' },\n retention: { support: 'implemented' },\n\n iframe: {\n support: 'blocked',\n reason: 'requires publish-time frozen exact-origin + frame-src CSP (BOFF-7926 slice 9)',\n },\n map: { support: 'blocked', reason: 'requires publish-time tile provider + img-src CSP (BOFF-7926 slice 9)' },\n custom: { support: 'blocked', reason: 'requires nested opaque-origin sandbox document (BOFF-7926 slice 10)' },\n};\n\nexport function isWidgetTypeEmbeddable(type: WidgetType): boolean {\n return EMBED_WIDGET_COVERAGE[type]?.support === 'implemented';\n}\n\n/** Immutable manifest emitted alongside the asset bundle for contract auditing. */\nexport const EMBED_RENDERER_MANIFEST = {\n renderModelVersion: EMBED_RENDER_MODEL_VERSION,\n implemented: Object.entries(EMBED_WIDGET_COVERAGE)\n .filter(([, v]) => v.support === 'implemented')\n .map(([k]) => k)\n .sort(),\n blocked: Object.entries(EMBED_WIDGET_COVERAGE)\n .filter(([, v]) => v.support === 'blocked')\n .map(([k]) => k)\n .sort(),\n} as const;\n"],"mappings":";;AA8BA,IAAa,IAAiE;CAE5E,aAAa,EAAE,SAAS,eAAe;CACvC,qBAAqB,EAAE,SAAS,eAAe;CAC/C,OAAO,EAAE,SAAS,eAAe;CACjC,MAAM,EAAE,SAAS,eAAe;CAChC,MAAM,EAAE,SAAS,eAAe;CAGhC,OAAO,EAAE,SAAS,eAAe;CACjC,cAAc,EAAE,SAAS,eAAe;CACxC,aAAa,EAAE,SAAS,eAAe;CACvC,OAAO,EAAE,SAAS,eAAe;CACjC,UAAU,EAAE,SAAS,eAAe;CACpC,MAAM,EAAE,SAAS,eAAe;CAChC,SAAS,EAAE,SAAS,eAAe;CACnC,UAAU,EAAE,SAAS,eAAe;CACpC,QAAQ,EAAE,SAAS,eAAe;CAClC,UAAU,EAAE,SAAS,eAAe;CACpC,WAAW,EAAE,SAAS,eAAe;CAErC,QAAQ;EACN,SAAS;EACT,QAAQ;EACT;CACD,KAAK;EAAE,SAAS;EAAW,QAAQ;EAAyE;CAC5G,QAAQ;EAAE,SAAS;EAAW,QAAQ;EAAuE;CAC9G;AAED,SAAgB,EAAuB,GAA2B;AAChE,QAAO,EAAsB,IAAO,YAAY;;AAIlD,IAAa,IAA0B;CACrC,oBAAA;CACA,aAAa,OAAO,QAAQ,EAAsB,CAC/C,QAAQ,GAAG,OAAO,EAAE,YAAY,cAAc,CAC9C,KAAK,CAAC,OAAO,EAAE,CACf,MAAM;CACT,SAAS,OAAO,QAAQ,EAAsB,CAC3C,QAAQ,GAAG,OAAO,EAAE,YAAY,UAAU,CAC1C,KAAK,CAAC,OAAO,EAAE,CACf,MAAM;CACV"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
//#region src/bigconsole/components/embed/widgetShim.ts
|
|
2
|
+
var e = "1970-01-01T00:00:00.000Z";
|
|
3
|
+
function t(t) {
|
|
4
|
+
let { x: n, y: r, w: i, h: a } = t.layout;
|
|
5
|
+
return {
|
|
6
|
+
id: t.id,
|
|
7
|
+
pageId: "",
|
|
8
|
+
type: t.type,
|
|
9
|
+
title: t.title ?? "",
|
|
10
|
+
config: { ...t.config },
|
|
11
|
+
position: {
|
|
12
|
+
x: n,
|
|
13
|
+
y: r,
|
|
14
|
+
width: i,
|
|
15
|
+
height: a
|
|
16
|
+
},
|
|
17
|
+
positionX: n,
|
|
18
|
+
positionY: r,
|
|
19
|
+
positionWidth: i,
|
|
20
|
+
positionHeight: a,
|
|
21
|
+
createdAt: e,
|
|
22
|
+
updatedAt: e
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
//#endregion
|
|
26
|
+
export { t as toWidgetShim };
|
|
27
|
+
|
|
28
|
+
//# sourceMappingURL=widgetShim.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"widgetShim.js","names":[],"sources":["../../../../src/bigconsole/components/embed/widgetShim.ts"],"sourcesContent":["/**\n * Adapter from a sanitized embed widget DTO to the in-app `Widget` shape\n * (BOFF-7926).\n *\n * Reused in-app widget components take a full `Widget`. The embed only has the\n * sanitized model, so this shim fills the structural fields with inert values:\n * no data-source ids, no parser, no drilldown(s), no actions. Components\n * rendered through it must also never receive `onClick`/`onDrilldown`/`onSubmit`\n * — every reused component gates interactivity on those props or on\n * `drilldown(s)`, both of which stay absent here.\n */\n\nimport type { Widget } from '../../types';\nimport type { EmbedWidgetModel } from './types';\n\nconst EPOCH = '1970-01-01T00:00:00.000Z';\n\nexport function toWidgetShim(model: EmbedWidgetModel): Widget {\n const { x, y, w, h } = model.layout;\n return {\n id: model.id,\n pageId: '',\n type: model.type,\n title: model.title ?? '',\n config: { ...model.config },\n position: { x, y, width: w, height: h },\n positionX: x,\n positionY: y,\n positionWidth: w,\n positionHeight: h,\n createdAt: EPOCH,\n updatedAt: EPOCH,\n };\n}\n"],"mappings":";AAeA,IAAM,IAAQ;AAEd,SAAgB,EAAa,GAAiC;CAC5D,IAAM,EAAE,MAAG,MAAG,MAAG,SAAM,EAAM;AAC7B,QAAO;EACL,IAAI,EAAM;EACV,QAAQ;EACR,MAAM,EAAM;EACZ,OAAO,EAAM,SAAS;EACtB,QAAQ,EAAE,GAAG,EAAM,QAAQ;EAC3B,UAAU;GAAE;GAAG;GAAG,OAAO;GAAG,QAAQ;GAAG;EACvC,WAAW;EACX,WAAW;EACX,eAAe;EACf,gBAAgB;EAChB,WAAW;EACX,WAAW;EACZ"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { asFiniteNumber as e, asOptionalString as t, asRecord as n, asRecordArray as r, displayValue as i, safeColor as a } from "./shared.js";
|
|
2
|
+
import { toWidgetShim as o } from "../widgetShim.js";
|
|
3
|
+
import { EmbedFrame as s } from "./EmbedFrame.js";
|
|
4
|
+
import c from "../../widgets/calendar/CalendarView.js";
|
|
5
|
+
import { fallbackTranslate as l } from "../../widgets/utils/translate.js";
|
|
6
|
+
import { useMemo as u } from "react";
|
|
7
|
+
import { jsx as d } from "react/jsx-runtime";
|
|
8
|
+
//#region src/bigconsole/components/embed/widgets/CalendarEmbed.tsx
|
|
9
|
+
var f = 1e3;
|
|
10
|
+
function p({ widget: p }) {
|
|
11
|
+
let m = u(() => o(p), [p]), h = u(() => {
|
|
12
|
+
let o = n(p.data), s = r(o.events, f).map((e, n) => ({
|
|
13
|
+
id: `e${n}`,
|
|
14
|
+
title: i(e.title),
|
|
15
|
+
start: i(e.start),
|
|
16
|
+
end: i(e.end) || i(e.start),
|
|
17
|
+
color: a(e.color),
|
|
18
|
+
allDay: e.allDay === !0,
|
|
19
|
+
category: t(e.category, 80)
|
|
20
|
+
})).filter((e) => e.start !== ""), c = e(o.eventCount);
|
|
21
|
+
return {
|
|
22
|
+
events: s,
|
|
23
|
+
eventCount: c !== null && c >= 0 ? Math.trunc(c) : void 0
|
|
24
|
+
};
|
|
25
|
+
}, [p.data]);
|
|
26
|
+
return /* @__PURE__ */ d(s, {
|
|
27
|
+
title: p.title,
|
|
28
|
+
children: /* @__PURE__ */ d(c, {
|
|
29
|
+
widget: m,
|
|
30
|
+
data: h,
|
|
31
|
+
t: l
|
|
32
|
+
})
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
//#endregion
|
|
36
|
+
export { p as CalendarEmbed };
|
|
37
|
+
|
|
38
|
+
//# sourceMappingURL=CalendarEmbed.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CalendarEmbed.js","names":[],"sources":["../../../../../src/bigconsole/components/embed/widgets/CalendarEmbed.tsx"],"sourcesContent":["/**\n * Read-only calendar embed renderer (BOFF-7926).\n *\n * Reuses the provider-free CalendarView with a static translator. The service\n * projects `{ events: [{id, title, start, end, color?, allDay?, category?}], eventCount }`\n * (events capped; `eventCount` is the true total).\n */\nimport { useMemo } from 'react';\nimport { CalendarView, type CalendarData } from '../../widgets/calendar/CalendarView';\nimport { fallbackTranslate } from '../../widgets/utils/translate';\nimport type { EmbedWidgetRenderProps } from '../types';\nimport { toWidgetShim } from '../widgetShim';\nimport { EmbedFrame } from './EmbedFrame';\nimport { asFiniteNumber, asOptionalString, asRecord, asRecordArray, displayValue, safeColor } from './shared';\n\nconst MAX_EVENTS = 1000;\n\nexport function CalendarEmbed({ widget }: EmbedWidgetRenderProps) {\n const shim = useMemo(() => toWidgetShim(widget), [widget]);\n const data = useMemo((): CalendarData => {\n const d = asRecord(widget.data);\n const events = asRecordArray(d.events, MAX_EVENTS)\n .map((e, i) => ({\n id: `e${i}`,\n title: displayValue(e.title),\n start: displayValue(e.start),\n end: displayValue(e.end) || displayValue(e.start),\n color: safeColor(e.color),\n allDay: e.allDay === true,\n category: asOptionalString(e.category, 80),\n }))\n .filter((e) => e.start !== '');\n const count = asFiniteNumber(d.eventCount);\n return { events, eventCount: count !== null && count >= 0 ? Math.trunc(count) : undefined };\n }, [widget.data]);\n return (\n <EmbedFrame title={widget.title}>\n <CalendarView widget={shim} data={data} t={fallbackTranslate} />\n </EmbedFrame>\n );\n}\n"],"mappings":";;;;;;;;AAeA,IAAM,IAAa;AAEnB,SAAgB,EAAc,EAAE,aAAkC;CAChE,IAAM,IAAO,QAAc,EAAa,EAAO,EAAE,CAAC,EAAO,CAAC,EACpD,IAAO,QAA4B;EACvC,IAAM,IAAI,EAAS,EAAO,KAAK,EACzB,IAAS,EAAc,EAAE,QAAQ,EAAW,CAC/C,KAAK,GAAG,OAAO;GACd,IAAI,IAAI;GACR,OAAO,EAAa,EAAE,MAAM;GAC5B,OAAO,EAAa,EAAE,MAAM;GAC5B,KAAK,EAAa,EAAE,IAAI,IAAI,EAAa,EAAE,MAAM;GACjD,OAAO,EAAU,EAAE,MAAM;GACzB,QAAQ,EAAE,WAAW;GACrB,UAAU,EAAiB,EAAE,UAAU,GAAG;GAC3C,EAAE,CACF,QAAQ,MAAM,EAAE,UAAU,GAAG,EAC1B,IAAQ,EAAe,EAAE,WAAW;AAC1C,SAAO;GAAE;GAAQ,YAAY,MAAU,QAAQ,KAAS,IAAI,KAAK,MAAM,EAAM,GAAG,KAAA;GAAW;IAC1F,CAAC,EAAO,KAAK,CAAC;AACjB,QACE,kBAAC,GAAD;EAAY,OAAO,EAAO;YACxB,kBAAC,GAAD;GAAc,QAAQ;GAAY;GAAM,GAAG;GAAqB,CAAA;EACrD,CAAA"}
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
import { asArray as e, asFiniteNumber as t, asOptionalString as n, asRecord as r, asRecordArray as i, safeColor as a } from "./shared.js";
|
|
2
|
+
import { EmbedFrame as o } from "./EmbedFrame.js";
|
|
3
|
+
import s from "../../widgets/chart/ChartLegend.js";
|
|
4
|
+
import c from "../../widgets/chart/charts/LineChart.js";
|
|
5
|
+
import l from "../../widgets/chart/charts/BarChart.js";
|
|
6
|
+
import u from "../../widgets/chart/charts/AreaChart.js";
|
|
7
|
+
import d from "../../widgets/chart/charts/PieChart.js";
|
|
8
|
+
import f from "../../widgets/chart/charts/FunnelChart.js";
|
|
9
|
+
import p from "../../widgets/chart/charts/ComboChart.js";
|
|
10
|
+
import m from "../../widgets/chart/charts/WaterfallChart.js";
|
|
11
|
+
import h from "../../widgets/chart/charts/ScatterChart.js";
|
|
12
|
+
import { useCallback as g, useMemo as _, useState as v } from "react";
|
|
13
|
+
import { jsx as y, jsxs as b } from "react/jsx-runtime";
|
|
14
|
+
//#region src/bigconsole/components/embed/widgets/ChartEmbed.tsx
|
|
15
|
+
var x = [
|
|
16
|
+
"line",
|
|
17
|
+
"bar",
|
|
18
|
+
"area",
|
|
19
|
+
"pie",
|
|
20
|
+
"funnel",
|
|
21
|
+
"combo",
|
|
22
|
+
"waterfall",
|
|
23
|
+
"scatter"
|
|
24
|
+
], S = [
|
|
25
|
+
"monotone",
|
|
26
|
+
"linear",
|
|
27
|
+
"step",
|
|
28
|
+
"stepAfter",
|
|
29
|
+
"stepBefore",
|
|
30
|
+
"natural"
|
|
31
|
+
], C = [
|
|
32
|
+
"top",
|
|
33
|
+
"bottom",
|
|
34
|
+
"left",
|
|
35
|
+
"right"
|
|
36
|
+
], w = [
|
|
37
|
+
"success",
|
|
38
|
+
"warning",
|
|
39
|
+
"danger",
|
|
40
|
+
"info",
|
|
41
|
+
"neutral"
|
|
42
|
+
], T = [
|
|
43
|
+
"var(--color-chart-1)",
|
|
44
|
+
"var(--color-chart-2)",
|
|
45
|
+
"var(--color-chart-3)",
|
|
46
|
+
"var(--color-chart-4)",
|
|
47
|
+
"var(--color-chart-5)"
|
|
48
|
+
], E = 1e3, D = 20;
|
|
49
|
+
function O(e, t) {
|
|
50
|
+
return typeof e == "string" && t.includes(e) ? e : void 0;
|
|
51
|
+
}
|
|
52
|
+
function k(e) {
|
|
53
|
+
return typeof e == "boolean" ? e : void 0;
|
|
54
|
+
}
|
|
55
|
+
function A(e) {
|
|
56
|
+
return typeof e == "string" && e.length > 0 && e.length <= 128 ? e : void 0;
|
|
57
|
+
}
|
|
58
|
+
function j(o, s) {
|
|
59
|
+
let c = typeof o.chartType == "string" ? o.chartType.toLowerCase() : "", l = c === "doughnut" || c === "donut", u = s ? "funnel" : l ? "pie" : O(c, x) ?? "line", d = e(o.colors).map(a).filter((e) => !!e).slice(0, 12), f = {}, p = o.seriesLabels;
|
|
60
|
+
if (Array.isArray(p)) for (let e of p.slice(0, D)) {
|
|
61
|
+
let t = r(e), i = A(t.key ?? t.field), a = n(t.label, 80);
|
|
62
|
+
i && a && (f[i] = a);
|
|
63
|
+
}
|
|
64
|
+
else for (let [e, t] of Object.entries(r(p)).slice(0, D)) A(e) && typeof t == "string" && (f[e] = t.slice(0, 80));
|
|
65
|
+
let m = i(o.referenceLines, 10).map((e) => {
|
|
66
|
+
let r = t(e.value);
|
|
67
|
+
return r === null ? null : {
|
|
68
|
+
axis: O(e.axis, ["x", "y"]),
|
|
69
|
+
value: r,
|
|
70
|
+
value2: t(e.value2) ?? void 0,
|
|
71
|
+
label: n(e.label, 80),
|
|
72
|
+
color: O(e.color, w),
|
|
73
|
+
dashed: k(e.dashed)
|
|
74
|
+
};
|
|
75
|
+
}).filter((e) => e !== null), h = i(o.series, D).map((e) => {
|
|
76
|
+
let t = A(e.field);
|
|
77
|
+
return t ? {
|
|
78
|
+
field: t,
|
|
79
|
+
label: n(e.label, 80),
|
|
80
|
+
type: O(e.type, ["bar", "line"]),
|
|
81
|
+
axis: O(e.axis, ["left", "right"]),
|
|
82
|
+
color: a(e.color)
|
|
83
|
+
} : null;
|
|
84
|
+
}).filter((e) => e !== null);
|
|
85
|
+
return {
|
|
86
|
+
type: u,
|
|
87
|
+
xAxisKey: A(o.xAxisField) ?? "name",
|
|
88
|
+
xAxisLabel: n(o.xAxisLabel, 80),
|
|
89
|
+
yAxisLabel: n(o.yAxisLabel, 80),
|
|
90
|
+
yAxisRightLabel: n(o.yAxisRightLabel, 80),
|
|
91
|
+
showGrid: k(o.showGrid),
|
|
92
|
+
showLegend: k(o.showLegend),
|
|
93
|
+
legendPosition: O(o.legendPosition, C),
|
|
94
|
+
showDots: k(o.showDataPoints),
|
|
95
|
+
curveType: O(o.curveType, S),
|
|
96
|
+
colors: d.length > 0 ? d : void 0,
|
|
97
|
+
seriesNames: Object.keys(f).length > 0 ? f : void 0,
|
|
98
|
+
stacked: k(o.stacked),
|
|
99
|
+
isDonut: l || k(o.showAsDonut),
|
|
100
|
+
innerRadius: t(o.innerRadius) ?? void 0,
|
|
101
|
+
outerRadius: t(o.outerRadius) ?? void 0,
|
|
102
|
+
referenceLines: m.length > 0 ? m : void 0,
|
|
103
|
+
series: h.length > 0 ? h : void 0,
|
|
104
|
+
dualAxis: k(o.dualAxis),
|
|
105
|
+
logScale: k(o.logScale),
|
|
106
|
+
valueField: A(o.valueField),
|
|
107
|
+
labelField: A(o.labelField),
|
|
108
|
+
showTotal: k(o.showTotal),
|
|
109
|
+
totalLabel: n(o.totalLabel, 80),
|
|
110
|
+
xField: A(o.xField),
|
|
111
|
+
yField: A(o.yField),
|
|
112
|
+
sizeField: A(o.sizeField),
|
|
113
|
+
colorField: A(o.colorField)
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
function M(e) {
|
|
117
|
+
return i(r(e).rows, E).map((e) => {
|
|
118
|
+
let t = {};
|
|
119
|
+
for (let [n, r] of Object.entries(e).slice(0, D + 4)) typeof r == "string" ? t[n] = r.slice(0, 200) : typeof r == "number" && Number.isFinite(r) && (t[n] = r);
|
|
120
|
+
return t;
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
function N({ widget: t }) {
|
|
124
|
+
let n = t.config, r = _(() => j(n, t.type === "funnel_chart"), [n, t.type]), i = _(() => M(t.data), [t.data]), [a, x] = v([]), S = _(() => e(n.selectedFields).map(A).filter((e) => !!e), [n.selectedFields]), C = _(() => {
|
|
125
|
+
let e = i[0];
|
|
126
|
+
return !e || [
|
|
127
|
+
"pie",
|
|
128
|
+
"funnel",
|
|
129
|
+
"scatter",
|
|
130
|
+
"waterfall"
|
|
131
|
+
].includes(r.type ?? "") ? [] : Object.keys(e).filter((t) => {
|
|
132
|
+
let n = t !== r.xAxisKey && typeof e[t] == "number";
|
|
133
|
+
return S.length > 0 ? n && S.includes(t) : n;
|
|
134
|
+
}).map((e, t) => ({
|
|
135
|
+
dataKey: e,
|
|
136
|
+
name: r.seriesNames?.[e] || e,
|
|
137
|
+
color: r.colors?.[t] || T[t % T.length],
|
|
138
|
+
hidden: a.includes(e)
|
|
139
|
+
}));
|
|
140
|
+
}, [
|
|
141
|
+
i,
|
|
142
|
+
r,
|
|
143
|
+
a,
|
|
144
|
+
S
|
|
145
|
+
]), w = g((e) => {
|
|
146
|
+
x((t) => t.includes(e) ? t.filter((t) => t !== e) : [...t, e]);
|
|
147
|
+
}, []);
|
|
148
|
+
if (i.length === 0) return /* @__PURE__ */ y(o, {
|
|
149
|
+
title: t.title,
|
|
150
|
+
children: /* @__PURE__ */ y("div", {
|
|
151
|
+
className: "flex h-full w-full items-center justify-center p-4 text-sm text-text-tertiary",
|
|
152
|
+
children: "No data"
|
|
153
|
+
})
|
|
154
|
+
});
|
|
155
|
+
let E = r.type === "combo" || r.dualAxis === !0 || ((r.series?.some((e) => e.axis === "right" || e.type === "bar") && r.series?.some((e) => e.type === "line")) ?? !1), D = (() => {
|
|
156
|
+
if (E) return /* @__PURE__ */ y(p, {
|
|
157
|
+
data: i,
|
|
158
|
+
config: r,
|
|
159
|
+
hiddenSeries: a
|
|
160
|
+
});
|
|
161
|
+
switch (r.type) {
|
|
162
|
+
case "waterfall": return /* @__PURE__ */ y(m, {
|
|
163
|
+
data: i,
|
|
164
|
+
config: r
|
|
165
|
+
});
|
|
166
|
+
case "scatter": return /* @__PURE__ */ y(h, {
|
|
167
|
+
data: i,
|
|
168
|
+
config: r
|
|
169
|
+
});
|
|
170
|
+
case "bar": return /* @__PURE__ */ y(l, {
|
|
171
|
+
data: i,
|
|
172
|
+
config: r,
|
|
173
|
+
hiddenSeries: a
|
|
174
|
+
});
|
|
175
|
+
case "area": return /* @__PURE__ */ y(u, {
|
|
176
|
+
data: i,
|
|
177
|
+
config: r,
|
|
178
|
+
hiddenSeries: a
|
|
179
|
+
});
|
|
180
|
+
case "pie": return /* @__PURE__ */ y(d, {
|
|
181
|
+
data: i,
|
|
182
|
+
config: r,
|
|
183
|
+
dataKey: r.valueField || "value",
|
|
184
|
+
nameKey: r.labelField || "name"
|
|
185
|
+
});
|
|
186
|
+
case "funnel": return /* @__PURE__ */ y(f, {
|
|
187
|
+
data: i,
|
|
188
|
+
config: r,
|
|
189
|
+
dataKey: r.valueField || "value",
|
|
190
|
+
nameKey: r.labelField || "name"
|
|
191
|
+
});
|
|
192
|
+
default: return /* @__PURE__ */ y(c, {
|
|
193
|
+
data: i,
|
|
194
|
+
config: r,
|
|
195
|
+
hiddenSeries: a
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
})(), O = r.showLegend !== !1 && C.length > 0;
|
|
199
|
+
return /* @__PURE__ */ y(o, {
|
|
200
|
+
title: t.title,
|
|
201
|
+
children: /* @__PURE__ */ b("div", {
|
|
202
|
+
className: "flex h-full w-full flex-col p-4",
|
|
203
|
+
children: [
|
|
204
|
+
O && r.legendPosition === "top" && /* @__PURE__ */ y(s, {
|
|
205
|
+
items: C,
|
|
206
|
+
position: "top",
|
|
207
|
+
onItemClick: w
|
|
208
|
+
}),
|
|
209
|
+
/* @__PURE__ */ y("div", {
|
|
210
|
+
className: "min-h-0 flex-1",
|
|
211
|
+
children: D
|
|
212
|
+
}),
|
|
213
|
+
O && r.legendPosition === "bottom" && /* @__PURE__ */ y(s, {
|
|
214
|
+
items: C,
|
|
215
|
+
position: "bottom",
|
|
216
|
+
onItemClick: w
|
|
217
|
+
})
|
|
218
|
+
]
|
|
219
|
+
})
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
//#endregion
|
|
223
|
+
export { N as ChartEmbed, N as default, j as toEmbedChartConfig, M as toEmbedChartRows };
|
|
224
|
+
|
|
225
|
+
//# sourceMappingURL=ChartEmbed.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ChartEmbed.js","names":[],"sources":["../../../../../src/bigconsole/components/embed/widgets/ChartEmbed.tsx"],"sourcesContent":["/**\n * Read-only chart embed renderer (BOFF-7926) — covers `chart` (line, bar, area,\n * pie, funnel, combo, waterfall, scatter) and `funnel_chart`.\n *\n * Reuses the in-app chart primitives (`widgets/chart/charts/*`, ChartLegend,\n * ChartTooltip) for visual parity but deliberately NOT ChartWidget: that pulls\n * the cross-filter context (router + store) into the isolated embed bundle.\n * No data-click handler is ever passed, so there is no drilldown/cross-filter.\n * Legend toggles only hide series locally.\n *\n * Data: `{ rows: [{ <field>: string | number }] }`, already projected by the\n * service to the x/label field plus the selected/series fields. Config: the\n * presentation whitelist (see sanitizeChartConfig), re-narrowed here.\n *\n * Loaded lazily (recharts is the largest dependency of the embed bundle).\n */\nimport { useCallback, useMemo, useState } from 'react';\nimport { ChartLegend, type LegendItem } from '../../widgets/chart/ChartLegend';\nimport { LineChart } from '../../widgets/chart/charts/LineChart';\nimport { BarChart } from '../../widgets/chart/charts/BarChart';\nimport { AreaChart } from '../../widgets/chart/charts/AreaChart';\nimport { PieChart } from '../../widgets/chart/charts/PieChart';\nimport { FunnelChart } from '../../widgets/chart/charts/FunnelChart';\nimport { ComboChart } from '../../widgets/chart/charts/ComboChart';\nimport { WaterfallChart } from '../../widgets/chart/charts/WaterfallChart';\nimport { ScatterChart } from '../../widgets/chart/charts/ScatterChart';\nimport type {\n ChartConfig,\n ChartData,\n ChartType,\n CurveType,\n ReferenceLineConfig,\n SeriesConfig,\n} from '../../widgets/chart/charts/types';\nimport type { EmbedWidgetRenderProps } from '../types';\nimport { EmbedFrame } from './EmbedFrame';\nimport { asArray, asFiniteNumber, asOptionalString, asRecord, asRecordArray, safeColor } from './shared';\n\nconst CHART_TYPES: readonly ChartType[] = ['line', 'bar', 'area', 'pie', 'funnel', 'combo', 'waterfall', 'scatter'];\nconst CURVES: readonly CurveType[] = ['monotone', 'linear', 'step', 'stepAfter', 'stepBefore', 'natural'];\nconst LEGEND_POSITIONS = ['top', 'bottom', 'left', 'right'] as const;\nconst INTENTS = ['success', 'warning', 'danger', 'info', 'neutral'] as const;\nconst DEFAULT_COLORS = [\n 'var(--color-chart-1)',\n 'var(--color-chart-2)',\n 'var(--color-chart-3)',\n 'var(--color-chart-4)',\n 'var(--color-chart-5)',\n];\nconst MAX_ROWS = 1000;\nconst MAX_SERIES = 20;\n\nfunction oneOf<T extends string>(value: unknown, allowed: readonly T[]): T | undefined {\n return typeof value === 'string' && (allowed as readonly string[]).includes(value) ? (value as T) : undefined;\n}\nfunction asBool(value: unknown): boolean | undefined {\n return typeof value === 'boolean' ? value : undefined;\n}\nfunction fieldName(value: unknown): string | undefined {\n return typeof value === 'string' && value.length > 0 && value.length <= 128 ? value : undefined;\n}\n\n/** Narrow the (already server-whitelisted) config into the primitives' ChartConfig. */\nexport function toEmbedChartConfig(raw: Record<string, unknown>, forceFunnel: boolean): ChartConfig {\n const requested = typeof raw.chartType === 'string' ? raw.chartType.toLowerCase() : '';\n // `doughnut`/`donut` are stored by older builders; render them as a donut pie.\n const isDoughnut = requested === 'doughnut' || requested === 'donut';\n const type: ChartType = forceFunnel ? 'funnel' : isDoughnut ? 'pie' : (oneOf(requested, CHART_TYPES) ?? 'line');\n\n const colors = asArray(raw.colors)\n .map(safeColor)\n .filter((c): c is string => !!c)\n .slice(0, 12);\n\n const seriesNames: Record<string, string> = {};\n const labels = raw.seriesLabels;\n // A bare string[] carries no field mapping (the in-app chart ignores it too),\n // so only `{key|field, label}` entries or a `{field: label}` record apply.\n if (Array.isArray(labels)) {\n for (const entry of labels.slice(0, MAX_SERIES)) {\n const r = asRecord(entry);\n const key = fieldName(r.key ?? r.field);\n const label = asOptionalString(r.label, 80);\n if (key && label) seriesNames[key] = label;\n }\n } else {\n for (const [key, label] of Object.entries(asRecord(labels)).slice(0, MAX_SERIES)) {\n if (fieldName(key) && typeof label === 'string') seriesNames[key] = label.slice(0, 80);\n }\n }\n\n const referenceLines: ReferenceLineConfig[] = asRecordArray(raw.referenceLines, 10)\n .map((r) => {\n const value = asFiniteNumber(r.value);\n if (value === null) return null;\n return {\n axis: oneOf(r.axis, ['x', 'y'] as const),\n value,\n value2: asFiniteNumber(r.value2) ?? undefined,\n label: asOptionalString(r.label, 80),\n color: oneOf(r.color, INTENTS),\n dashed: asBool(r.dashed),\n };\n })\n .filter((r): r is NonNullable<typeof r> => r !== null);\n\n const series: SeriesConfig[] = asRecordArray(raw.series, MAX_SERIES)\n .map((s) => {\n const field = fieldName(s.field);\n if (!field) return null;\n return {\n field,\n label: asOptionalString(s.label, 80),\n type: oneOf(s.type, ['bar', 'line'] as const),\n axis: oneOf(s.axis, ['left', 'right'] as const),\n color: safeColor(s.color),\n };\n })\n .filter((s): s is NonNullable<typeof s> => s !== null);\n\n return {\n type,\n xAxisKey: fieldName(raw.xAxisField) ?? 'name',\n xAxisLabel: asOptionalString(raw.xAxisLabel, 80),\n yAxisLabel: asOptionalString(raw.yAxisLabel, 80),\n yAxisRightLabel: asOptionalString(raw.yAxisRightLabel, 80),\n showGrid: asBool(raw.showGrid),\n showLegend: asBool(raw.showLegend),\n legendPosition: oneOf(raw.legendPosition, LEGEND_POSITIONS),\n showDots: asBool(raw.showDataPoints),\n curveType: oneOf(raw.curveType, CURVES),\n colors: colors.length > 0 ? colors : undefined,\n seriesNames: Object.keys(seriesNames).length > 0 ? seriesNames : undefined,\n stacked: asBool(raw.stacked),\n isDonut: isDoughnut || asBool(raw.showAsDonut),\n innerRadius: asFiniteNumber(raw.innerRadius) ?? undefined,\n outerRadius: asFiniteNumber(raw.outerRadius) ?? undefined,\n referenceLines: referenceLines.length > 0 ? referenceLines : undefined,\n series: series.length > 0 ? series : undefined,\n dualAxis: asBool(raw.dualAxis),\n logScale: asBool(raw.logScale),\n valueField: fieldName(raw.valueField),\n labelField: fieldName(raw.labelField),\n showTotal: asBool(raw.showTotal),\n totalLabel: asOptionalString(raw.totalLabel, 80),\n xField: fieldName(raw.xField),\n yField: fieldName(raw.yField),\n sizeField: fieldName(raw.sizeField),\n colorField: fieldName(raw.colorField),\n };\n}\n\n/** Rows with scalar cells only (string/finite number); anything else is dropped. */\nexport function toEmbedChartRows(data: unknown): ChartData[] {\n return asRecordArray(asRecord(data).rows, MAX_ROWS).map((row) => {\n const out: ChartData = {};\n for (const [key, value] of Object.entries(row).slice(0, MAX_SERIES + 4)) {\n if (typeof value === 'string') out[key] = value.slice(0, 200);\n else if (typeof value === 'number' && Number.isFinite(value)) out[key] = value;\n }\n return out;\n });\n}\n\nexport function ChartEmbed({ widget }: EmbedWidgetRenderProps) {\n const rawConfig = widget.config;\n const chartConfig = useMemo(\n () => toEmbedChartConfig(rawConfig, widget.type === 'funnel_chart'),\n [rawConfig, widget.type]\n );\n const data = useMemo(() => toEmbedChartRows(widget.data), [widget.data]);\n const [hiddenSeries, setHiddenSeries] = useState<string[]>([]);\n\n const selectedFields = useMemo(\n () =>\n asArray(rawConfig.selectedFields)\n .map(fieldName)\n .filter((f): f is string => !!f),\n [rawConfig.selectedFields]\n );\n\n // Same legend derivation as the in-app ChartWidget.\n const legendItems: LegendItem[] = useMemo(() => {\n const first = data[0];\n if (!first || ['pie', 'funnel', 'scatter', 'waterfall'].includes(chartConfig.type ?? '')) return [];\n const keys = Object.keys(first).filter((key) => {\n const numeric = key !== chartConfig.xAxisKey && typeof first[key] === 'number';\n return selectedFields.length > 0 ? numeric && selectedFields.includes(key) : numeric;\n });\n return keys.map((key, index) => ({\n dataKey: key,\n name: chartConfig.seriesNames?.[key] || key,\n color: chartConfig.colors?.[index] || DEFAULT_COLORS[index % DEFAULT_COLORS.length],\n hidden: hiddenSeries.includes(key),\n }));\n }, [data, chartConfig, hiddenSeries, selectedFields]);\n\n const toggleSeries = useCallback((key: string) => {\n setHiddenSeries((prev) => (prev.includes(key) ? prev.filter((k) => k !== key) : [...prev, key]));\n }, []);\n\n if (data.length === 0) {\n return (\n <EmbedFrame title={widget.title}>\n <div className=\"flex h-full w-full items-center justify-center p-4 text-sm text-text-tertiary\">No data</div>\n </EmbedFrame>\n );\n }\n\n const isCombo =\n chartConfig.type === 'combo' ||\n chartConfig.dualAxis === true ||\n ((chartConfig.series?.some((s) => s.axis === 'right' || s.type === 'bar') &&\n chartConfig.series?.some((s) => s.type === 'line')) ??\n false);\n\n const chart = (() => {\n if (isCombo) return <ComboChart data={data} config={chartConfig} hiddenSeries={hiddenSeries} />;\n switch (chartConfig.type) {\n case 'waterfall':\n return <WaterfallChart data={data} config={chartConfig} />;\n case 'scatter':\n return <ScatterChart data={data} config={chartConfig} />;\n case 'bar':\n return <BarChart data={data} config={chartConfig} hiddenSeries={hiddenSeries} />;\n case 'area':\n return <AreaChart data={data} config={chartConfig} hiddenSeries={hiddenSeries} />;\n case 'pie':\n return (\n <PieChart\n data={data}\n config={chartConfig}\n dataKey={chartConfig.valueField || 'value'}\n nameKey={chartConfig.labelField || 'name'}\n />\n );\n case 'funnel':\n return (\n <FunnelChart\n data={data}\n config={chartConfig}\n dataKey={chartConfig.valueField || 'value'}\n nameKey={chartConfig.labelField || 'name'}\n />\n );\n case 'line':\n default:\n return <LineChart data={data} config={chartConfig} hiddenSeries={hiddenSeries} />;\n }\n })();\n\n // The owner's \"Show Legend\" switch governs the external top/bottom legend too\n // (the primitives' own legend already honors it).\n const showExternalLegend = chartConfig.showLegend !== false && legendItems.length > 0;\n\n return (\n <EmbedFrame title={widget.title}>\n <div className=\"flex h-full w-full flex-col p-4\">\n {showExternalLegend && chartConfig.legendPosition === 'top' && (\n <ChartLegend items={legendItems} position=\"top\" onItemClick={toggleSeries} />\n )}\n <div className=\"min-h-0 flex-1\">{chart}</div>\n {showExternalLegend && chartConfig.legendPosition === 'bottom' && (\n <ChartLegend items={legendItems} position=\"bottom\" onItemClick={toggleSeries} />\n )}\n </div>\n </EmbedFrame>\n );\n}\n\nexport default ChartEmbed;\n"],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { jsx as e, jsxs as t } from "react/jsx-runtime";
|
|
2
|
+
//#region src/bigconsole/components/embed/widgets/EmbedFrame.tsx
|
|
3
|
+
function n({ title: n, children: r }) {
|
|
4
|
+
return /* @__PURE__ */ t("div", {
|
|
5
|
+
className: "flex h-full w-full flex-col overflow-hidden bg-bg-surface",
|
|
6
|
+
children: [n && /* @__PURE__ */ e("div", {
|
|
7
|
+
className: "shrink-0 truncate border-b border-border-subtle px-3 py-2 text-sm font-medium text-text-primary",
|
|
8
|
+
children: n
|
|
9
|
+
}), /* @__PURE__ */ e("div", {
|
|
10
|
+
className: "min-h-0 flex-1 overflow-auto",
|
|
11
|
+
children: r
|
|
12
|
+
})]
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
//#endregion
|
|
16
|
+
export { n as EmbedFrame };
|
|
17
|
+
|
|
18
|
+
//# sourceMappingURL=EmbedFrame.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"EmbedFrame.js","names":[],"sources":["../../../../../src/bigconsole/components/embed/widgets/EmbedFrame.tsx"],"sourcesContent":["/**\n * Title bar + body frame for embed renderers that reuse in-app widget bodies\n * (BOFF-7926). In the app the widget header is drawn by WidgetWrapper, not the\n * widget, so reused bodies need the same title bar the Table/List embeds draw.\n */\nimport type { ReactNode } from 'react';\n\nexport function EmbedFrame({ title, children }: { title?: string; children: ReactNode }) {\n return (\n <div className=\"flex h-full w-full flex-col overflow-hidden bg-bg-surface\">\n {title && (\n <div className=\"shrink-0 truncate border-b border-border-subtle px-3 py-2 text-sm font-medium text-text-primary\">\n {title}\n </div>\n )}\n <div className=\"min-h-0 flex-1 overflow-auto\">{children}</div>\n </div>\n );\n}\n"],"mappings":";;AAOA,SAAgB,EAAW,EAAE,UAAO,eAAqD;AACvF,QACE,kBAAC,OAAD;EAAK,WAAU;YAAf,CACG,KACC,kBAAC,OAAD;GAAK,WAAU;aACZ;GACG,CAAA,EAER,kBAAC,OAAD;GAAK,WAAU;GAAgC;GAAe,CAAA,CAC1D"}
|