@burdenoff/microfe-bigconsole 2026.925.1 → 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/dashboard/ShareDialog/EmbedTab.js +142 -145
- package/dist/bigconsole/components/dashboard/ShareDialog/EmbedTab.js.map +1 -1
- package/dist/bigconsole/components/embed/EmbedWidgetRenderer.js +43 -13
- package/dist/bigconsole/components/embed/EmbedWidgetRenderer.js.map +1 -1
- package/dist/bigconsole/components/embed/ReadOnlyDashboardRenderer.js +5 -5
- package/dist/bigconsole/components/embed/ReadOnlyDashboardRenderer.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/types.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/dist/bigconsole/hooks/useDashboardEmbedPolicy.js +2 -4
- package/dist/bigconsole/hooks/useDashboardEmbedPolicy.js.map +1 -1
- package/dist/generated/wspace-operations.js +0 -1
- package/dist/generated/wspace-operations.js.map +1 -1
- package/package.json +1 -1
|
@@ -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"}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import { asFiniteNumber as e, asOptionalString as t, asRecord as n, asRecordArray as r, displayValue as i } from "./shared.js";
|
|
2
|
+
import { EmbedFrame as a } from "./EmbedFrame.js";
|
|
3
|
+
import { jsx as o, jsxs as s } from "react/jsx-runtime";
|
|
4
|
+
//#region src/bigconsole/components/embed/widgets/FormEmbed.tsx
|
|
5
|
+
var c = new Set([
|
|
6
|
+
"text",
|
|
7
|
+
"number",
|
|
8
|
+
"email",
|
|
9
|
+
"tel",
|
|
10
|
+
"url",
|
|
11
|
+
"date",
|
|
12
|
+
"datetime-local",
|
|
13
|
+
"time"
|
|
14
|
+
]), l = new Set([
|
|
15
|
+
"hidden",
|
|
16
|
+
"password",
|
|
17
|
+
"file"
|
|
18
|
+
]);
|
|
19
|
+
function u(e) {
|
|
20
|
+
return r(e, 100).map((e) => ({
|
|
21
|
+
value: i(e.value),
|
|
22
|
+
label: i(e.label) || i(e.value)
|
|
23
|
+
}));
|
|
24
|
+
}
|
|
25
|
+
function d({ widget: d }) {
|
|
26
|
+
let f = d.config, p = n(d.data), m = n(p.values), h = n(p.options), g = r(f.fields, 50).map((n) => ({
|
|
27
|
+
name: i(n.name),
|
|
28
|
+
label: i(n.label) || i(n.name),
|
|
29
|
+
type: i(n.type) || "text",
|
|
30
|
+
placeholder: t(n.placeholder, 120),
|
|
31
|
+
helpText: t(n.helpText, 300),
|
|
32
|
+
required: n.required === !0,
|
|
33
|
+
options: u(n.options),
|
|
34
|
+
rows: Math.min(Math.max(e(n.rows) ?? 4, 1), 20)
|
|
35
|
+
})).filter((e) => e.name !== "" && !l.has(e.type)), _ = f.layout === "grid" ? Math.min(Math.max(e(f.columns) ?? 2, 1), 4) : 1, v = t(f.submitLabel, 60) ?? "Submit", y = t(f.resetLabel, 60) ?? "Reset", b = "w-full rounded-md border border-border-default bg-bg-sunken px-3 py-2 text-sm text-text-primary opacity-80 cursor-not-allowed", x = (e) => {
|
|
36
|
+
let t = m[e.name], n = h[e.name] === void 0 ? e.options : u(h[e.name]);
|
|
37
|
+
switch (e.type) {
|
|
38
|
+
case "textarea": return /* @__PURE__ */ o("textarea", {
|
|
39
|
+
id: e.name,
|
|
40
|
+
className: b,
|
|
41
|
+
rows: e.rows,
|
|
42
|
+
value: i(t),
|
|
43
|
+
placeholder: e.placeholder,
|
|
44
|
+
disabled: !0,
|
|
45
|
+
readOnly: !0
|
|
46
|
+
});
|
|
47
|
+
case "select": return /* @__PURE__ */ s("select", {
|
|
48
|
+
id: e.name,
|
|
49
|
+
className: b,
|
|
50
|
+
value: i(t),
|
|
51
|
+
disabled: !0,
|
|
52
|
+
children: [/* @__PURE__ */ o("option", {
|
|
53
|
+
value: "",
|
|
54
|
+
children: e.placeholder ?? `Select ${e.label}…`
|
|
55
|
+
}), n.map((e) => /* @__PURE__ */ o("option", {
|
|
56
|
+
value: e.value,
|
|
57
|
+
children: e.label
|
|
58
|
+
}, e.value))]
|
|
59
|
+
});
|
|
60
|
+
case "checkbox": return /* @__PURE__ */ s("label", {
|
|
61
|
+
className: "flex items-center gap-2 text-sm text-text-primary",
|
|
62
|
+
children: [/* @__PURE__ */ o("input", {
|
|
63
|
+
type: "checkbox",
|
|
64
|
+
checked: t === !0,
|
|
65
|
+
disabled: !0,
|
|
66
|
+
readOnly: !0
|
|
67
|
+
}), e.label]
|
|
68
|
+
});
|
|
69
|
+
case "radio": return /* @__PURE__ */ o("div", {
|
|
70
|
+
className: "flex flex-col gap-2",
|
|
71
|
+
children: n.map((e) => /* @__PURE__ */ s("label", {
|
|
72
|
+
className: "flex items-center gap-2 text-sm text-text-primary",
|
|
73
|
+
children: [/* @__PURE__ */ o("input", {
|
|
74
|
+
type: "radio",
|
|
75
|
+
checked: i(t) === e.value,
|
|
76
|
+
disabled: !0,
|
|
77
|
+
readOnly: !0
|
|
78
|
+
}), e.label]
|
|
79
|
+
}, e.value))
|
|
80
|
+
});
|
|
81
|
+
default: return /* @__PURE__ */ o("input", {
|
|
82
|
+
id: e.name,
|
|
83
|
+
type: c.has(e.type) ? e.type : "text",
|
|
84
|
+
className: b,
|
|
85
|
+
value: i(t),
|
|
86
|
+
placeholder: e.placeholder,
|
|
87
|
+
disabled: !0,
|
|
88
|
+
readOnly: !0
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
return /* @__PURE__ */ o(a, {
|
|
93
|
+
title: d.title,
|
|
94
|
+
children: /* @__PURE__ */ s("div", {
|
|
95
|
+
className: "flex flex-col gap-4 p-4",
|
|
96
|
+
children: [
|
|
97
|
+
g.length === 0 ? /* @__PURE__ */ o("div", {
|
|
98
|
+
className: "text-sm text-text-tertiary",
|
|
99
|
+
children: "This form has no fields."
|
|
100
|
+
}) : /* @__PURE__ */ o("div", {
|
|
101
|
+
className: "grid gap-4",
|
|
102
|
+
style: { gridTemplateColumns: `repeat(${_}, minmax(0, 1fr))` },
|
|
103
|
+
children: g.map((e) => /* @__PURE__ */ s("div", {
|
|
104
|
+
className: "flex flex-col gap-1",
|
|
105
|
+
children: [
|
|
106
|
+
e.type !== "checkbox" && /* @__PURE__ */ s("label", {
|
|
107
|
+
htmlFor: e.name,
|
|
108
|
+
className: "text-sm font-medium text-text-primary",
|
|
109
|
+
children: [e.label, e.required && /* @__PURE__ */ o("span", {
|
|
110
|
+
className: "ml-0.5 text-status-error-text",
|
|
111
|
+
children: "*"
|
|
112
|
+
})]
|
|
113
|
+
}),
|
|
114
|
+
x(e),
|
|
115
|
+
e.helpText && /* @__PURE__ */ o("p", {
|
|
116
|
+
className: "text-xs text-text-tertiary",
|
|
117
|
+
children: e.helpText
|
|
118
|
+
})
|
|
119
|
+
]
|
|
120
|
+
}, e.name))
|
|
121
|
+
}),
|
|
122
|
+
/* @__PURE__ */ s("div", {
|
|
123
|
+
className: "flex items-center gap-2",
|
|
124
|
+
children: [/* @__PURE__ */ o("button", {
|
|
125
|
+
type: "button",
|
|
126
|
+
disabled: !0,
|
|
127
|
+
className: "cursor-not-allowed rounded-md bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text opacity-60",
|
|
128
|
+
children: v
|
|
129
|
+
}), f.showReset === !0 && /* @__PURE__ */ o("button", {
|
|
130
|
+
type: "button",
|
|
131
|
+
disabled: !0,
|
|
132
|
+
className: "cursor-not-allowed rounded-md border border-border-default px-4 py-2 text-sm text-text-secondary opacity-60",
|
|
133
|
+
children: y
|
|
134
|
+
})]
|
|
135
|
+
}),
|
|
136
|
+
/* @__PURE__ */ o("p", {
|
|
137
|
+
className: "text-xs text-text-tertiary",
|
|
138
|
+
children: "Interactive form disabled in embed."
|
|
139
|
+
})
|
|
140
|
+
]
|
|
141
|
+
})
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
//#endregion
|
|
145
|
+
export { d as FormEmbed };
|
|
146
|
+
|
|
147
|
+
//# sourceMappingURL=FormEmbed.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FormEmbed.js","names":[],"sources":["../../../../../src/bigconsole/components/embed/widgets/FormEmbed.tsx"],"sourcesContent":["/**\n * Read-only form embed renderer (BOFF-7926).\n *\n * Public embeds never accept anonymous submissions: there is no <form> element,\n * every control is `disabled`, the submit button is disabled, and a note says\n * so. The embed document CSP also sets `form-action 'none'`.\n *\n * Config (service whitelist): layout, columns, submitLabel, resetLabel,\n * showReset, fields[{name, label, type, placeholder, helpText, required,\n * options[{value, label}], rows}] — hidden/password fields and submitAction are\n * never sent (and are dropped here too). Data: `{ values: {name: scalar},\n * options: {name: [{value, label}]} }`.\n */\nimport type { EmbedWidgetRenderProps } from '../types';\nimport { EmbedFrame } from './EmbedFrame';\nimport { asFiniteNumber, asOptionalString, asRecord, asRecordArray, displayValue } from './shared';\n\nconst INPUT_TYPES = new Set(['text', 'number', 'email', 'tel', 'url', 'date', 'datetime-local', 'time']);\nconst EXCLUDED_TYPES = new Set(['hidden', 'password', 'file']);\n\ninterface EmbedFormOption {\n value: string;\n label: string;\n}\ninterface EmbedFormField {\n name: string;\n label: string;\n type: string;\n placeholder?: string;\n helpText?: string;\n required: boolean;\n options: EmbedFormOption[];\n rows: number;\n}\n\nfunction toOptions(value: unknown): EmbedFormOption[] {\n return asRecordArray(value, 100).map((o) => ({\n value: displayValue(o.value),\n label: displayValue(o.label) || displayValue(o.value),\n }));\n}\n\nexport function FormEmbed({ widget }: EmbedWidgetRenderProps) {\n const config = widget.config;\n const data = asRecord(widget.data);\n const values = asRecord(data.values);\n const dataOptions = asRecord(data.options);\n\n const fields: EmbedFormField[] = asRecordArray(config.fields, 50)\n .map((f) => ({\n name: displayValue(f.name),\n label: displayValue(f.label) || displayValue(f.name),\n type: displayValue(f.type) || 'text',\n placeholder: asOptionalString(f.placeholder, 120),\n helpText: asOptionalString(f.helpText, 300),\n required: f.required === true,\n options: toOptions(f.options),\n rows: Math.min(Math.max(asFiniteNumber(f.rows) ?? 4, 1), 20),\n }))\n .filter((f) => f.name !== '' && !EXCLUDED_TYPES.has(f.type));\n\n const gridColumns = config.layout === 'grid' ? Math.min(Math.max(asFiniteNumber(config.columns) ?? 2, 1), 4) : 1;\n const submitLabel = asOptionalString(config.submitLabel, 60) ?? 'Submit';\n const resetLabel = asOptionalString(config.resetLabel, 60) ?? 'Reset';\n const control =\n 'w-full rounded-md border border-border-default bg-bg-sunken px-3 py-2 text-sm text-text-primary opacity-80 cursor-not-allowed';\n\n const renderControl = (f: EmbedFormField) => {\n const value = values[f.name];\n const options = dataOptions[f.name] !== undefined ? toOptions(dataOptions[f.name]) : f.options;\n switch (f.type) {\n case 'textarea':\n return (\n <textarea\n id={f.name}\n className={control}\n rows={f.rows}\n value={displayValue(value)}\n placeholder={f.placeholder}\n disabled\n readOnly\n />\n );\n case 'select':\n return (\n <select id={f.name} className={control} value={displayValue(value)} disabled>\n <option value=\"\">{f.placeholder ?? `Select ${f.label}…`}</option>\n {options.map((o) => (\n <option key={o.value} value={o.value}>\n {o.label}\n </option>\n ))}\n </select>\n );\n case 'checkbox':\n return (\n <label className=\"flex items-center gap-2 text-sm text-text-primary\">\n <input type=\"checkbox\" checked={value === true} disabled readOnly />\n {f.label}\n </label>\n );\n case 'radio':\n return (\n <div className=\"flex flex-col gap-2\">\n {options.map((o) => (\n <label key={o.value} className=\"flex items-center gap-2 text-sm text-text-primary\">\n <input type=\"radio\" checked={displayValue(value) === o.value} disabled readOnly />\n {o.label}\n </label>\n ))}\n </div>\n );\n default:\n return (\n <input\n id={f.name}\n type={INPUT_TYPES.has(f.type) ? f.type : 'text'}\n className={control}\n value={displayValue(value)}\n placeholder={f.placeholder}\n disabled\n readOnly\n />\n );\n }\n };\n\n return (\n <EmbedFrame title={widget.title}>\n <div className=\"flex flex-col gap-4 p-4\">\n {fields.length === 0 ? (\n <div className=\"text-sm text-text-tertiary\">This form has no fields.</div>\n ) : (\n <div className=\"grid gap-4\" style={{ gridTemplateColumns: `repeat(${gridColumns}, minmax(0, 1fr))` }}>\n {fields.map((f) => (\n <div key={f.name} className=\"flex flex-col gap-1\">\n {f.type !== 'checkbox' && (\n <label htmlFor={f.name} className=\"text-sm font-medium text-text-primary\">\n {f.label}\n {f.required && <span className=\"ml-0.5 text-status-error-text\">*</span>}\n </label>\n )}\n {renderControl(f)}\n {f.helpText && <p className=\"text-xs text-text-tertiary\">{f.helpText}</p>}\n </div>\n ))}\n </div>\n )}\n <div className=\"flex items-center gap-2\">\n <button\n type=\"button\"\n disabled\n className=\"cursor-not-allowed rounded-md bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text opacity-60\"\n >\n {submitLabel}\n </button>\n {config.showReset === true && (\n <button\n type=\"button\"\n disabled\n className=\"cursor-not-allowed rounded-md border border-border-default px-4 py-2 text-sm text-text-secondary opacity-60\"\n >\n {resetLabel}\n </button>\n )}\n </div>\n <p className=\"text-xs text-text-tertiary\">Interactive form disabled in embed.</p>\n </div>\n </EmbedFrame>\n );\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { asArray as e, asFiniteNumber as t, asOptionalString as n, asRecord as r, safeColor as i } from "./shared.js";
|
|
2
|
+
import a from "../../widgets/gauge/GaugeWidget.js";
|
|
3
|
+
import { toWidgetShim as o } from "../widgetShim.js";
|
|
4
|
+
import { EmbedFrame as s } from "./EmbedFrame.js";
|
|
5
|
+
import { useMemo as c } from "react";
|
|
6
|
+
import { jsx as l } from "react/jsx-runtime";
|
|
7
|
+
//#region src/bigconsole/components/embed/widgets/GaugeEmbed.tsx
|
|
8
|
+
var u = /^[a-z][a-z-]{0,19}$/i;
|
|
9
|
+
function d(a) {
|
|
10
|
+
return e(a).slice(0, 10).map((e) => {
|
|
11
|
+
let a = r(e), o = t(a.value), s = typeof a.color == "string" ? a.color.trim() : "", c = u.test(s) ? s : i(s);
|
|
12
|
+
return o === null || !c ? null : {
|
|
13
|
+
value: o,
|
|
14
|
+
color: c,
|
|
15
|
+
label: n(a.label, 80)
|
|
16
|
+
};
|
|
17
|
+
}).filter((e) => e !== null);
|
|
18
|
+
}
|
|
19
|
+
function f({ widget: e }) {
|
|
20
|
+
let i = c(() => {
|
|
21
|
+
let t = o(e), n = d(e.config.thresholds);
|
|
22
|
+
return t.config = {
|
|
23
|
+
...t.config,
|
|
24
|
+
thresholds: n.length > 0 ? n : void 0
|
|
25
|
+
}, t;
|
|
26
|
+
}, [e]), u = c(() => {
|
|
27
|
+
let i = r(e.data), a = t(i.value);
|
|
28
|
+
return a === null ? void 0 : {
|
|
29
|
+
value: a,
|
|
30
|
+
label: n(i.label, 120)
|
|
31
|
+
};
|
|
32
|
+
}, [e.data]);
|
|
33
|
+
return /* @__PURE__ */ l(s, {
|
|
34
|
+
title: e.title,
|
|
35
|
+
children: /* @__PURE__ */ l(a, {
|
|
36
|
+
widget: i,
|
|
37
|
+
data: u
|
|
38
|
+
})
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
//#endregion
|
|
42
|
+
export { f as GaugeEmbed };
|
|
43
|
+
|
|
44
|
+
//# sourceMappingURL=GaugeEmbed.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"GaugeEmbed.js","names":[],"sources":["../../../../../src/bigconsole/components/embed/widgets/GaugeEmbed.tsx"],"sourcesContent":["/**\n * Read-only gauge embed renderer (BOFF-7926).\n *\n * Reuses the in-app GaugeWidget for visual parity. The service projects the\n * final `{ value, label? }`; config is the presentation whitelist\n * (variant, min, max, unit(s), format, decimals, showZones, size, thresholds).\n */\nimport { useMemo } from 'react';\nimport { GaugeWidget, type GaugeData } from '../../widgets/gauge/GaugeWidget';\nimport type { EmbedWidgetRenderProps } from '../types';\nimport { toWidgetShim } from '../widgetShim';\nimport { EmbedFrame } from './EmbedFrame';\nimport { asArray, asFiniteNumber, asOptionalString, asRecord, safeColor } from './shared';\n\nconst THRESHOLD_WORD = /^[a-z][a-z-]{0,19}$/i;\n\n/** Thresholds: numeric value + a token word (success/warning/…) or an inert CSS color. */\nfunction sanitizeThresholds(value: unknown) {\n return asArray(value)\n .slice(0, 10)\n .map((t) => {\n const r = asRecord(t);\n const v = asFiniteNumber(r.value);\n const raw = typeof r.color === 'string' ? r.color.trim() : '';\n const color = THRESHOLD_WORD.test(raw) ? raw : safeColor(raw);\n return v === null || !color ? null : { value: v, color, label: asOptionalString(r.label, 80) };\n })\n .filter((t): t is { value: number; color: string; label: string | undefined } => t !== null);\n}\n\nexport function GaugeEmbed({ widget }: EmbedWidgetRenderProps) {\n const shim = useMemo(() => {\n const s = toWidgetShim(widget);\n const thresholds = sanitizeThresholds(widget.config.thresholds);\n s.config = { ...s.config, thresholds: thresholds.length > 0 ? thresholds : undefined };\n return s;\n }, [widget]);\n\n const data = useMemo((): GaugeData | undefined => {\n const d = asRecord(widget.data);\n const value = asFiniteNumber(d.value);\n return value === null ? undefined : { value, label: asOptionalString(d.label, 120) };\n }, [widget.data]);\n\n return (\n <EmbedFrame title={widget.title}>\n <GaugeWidget widget={shim} data={data} />\n </EmbedFrame>\n );\n}\n"],"mappings":";;;;;;;AAcA,IAAM,IAAiB;AAGvB,SAAS,EAAmB,GAAgB;AAC1C,QAAO,EAAQ,EAAM,CAClB,MAAM,GAAG,GAAG,CACZ,KAAK,MAAM;EACV,IAAM,IAAI,EAAS,EAAE,EACf,IAAI,EAAe,EAAE,MAAM,EAC3B,IAAM,OAAO,EAAE,SAAU,WAAW,EAAE,MAAM,MAAM,GAAG,IACrD,IAAQ,EAAe,KAAK,EAAI,GAAG,IAAM,EAAU,EAAI;AAC7D,SAAO,MAAM,QAAQ,CAAC,IAAQ,OAAO;GAAE,OAAO;GAAG;GAAO,OAAO,EAAiB,EAAE,OAAO,GAAG;GAAE;GAC9F,CACD,QAAQ,MAAwE,MAAM,KAAK;;AAGhG,SAAgB,EAAW,EAAE,aAAkC;CAC7D,IAAM,IAAO,QAAc;EACzB,IAAM,IAAI,EAAa,EAAO,EACxB,IAAa,EAAmB,EAAO,OAAO,WAAW;AAE/D,SADA,EAAE,SAAS;GAAE,GAAG,EAAE;GAAQ,YAAY,EAAW,SAAS,IAAI,IAAa,KAAA;GAAW,EAC/E;IACN,CAAC,EAAO,CAAC,EAEN,IAAO,QAAqC;EAChD,IAAM,IAAI,EAAS,EAAO,KAAK,EACzB,IAAQ,EAAe,EAAE,MAAM;AACrC,SAAO,MAAU,OAAO,KAAA,IAAY;GAAE;GAAO,OAAO,EAAiB,EAAE,OAAO,IAAI;GAAE;IACnF,CAAC,EAAO,KAAK,CAAC;AAEjB,QACE,kBAAC,GAAD;EAAY,OAAO,EAAO;YACxB,kBAAC,GAAD;GAAa,QAAQ;GAAY;GAAQ,CAAA;EAC9B,CAAA"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { asArray as e, asFiniteNumber as t, asRecord as n, asRecordArray as r, displayValue as i } from "./shared.js";
|
|
2
|
+
import { toWidgetShim as a } from "../widgetShim.js";
|
|
3
|
+
import { EmbedFrame as o } from "./EmbedFrame.js";
|
|
4
|
+
import s from "../../widgets/heatmap/HeatmapWidget.js";
|
|
5
|
+
import { useMemo as c } from "react";
|
|
6
|
+
import { jsx as l } from "react/jsx-runtime";
|
|
7
|
+
//#region src/bigconsole/components/embed/widgets/HeatmapEmbed.tsx
|
|
8
|
+
var u = 50, d = 2500;
|
|
9
|
+
function f({ widget: f }) {
|
|
10
|
+
let p = c(() => a(f), [f]), m = c(() => {
|
|
11
|
+
let a = n(f.data), o = e(a.rows).map(i).filter(Boolean).slice(0, u), s = e(a.columns).map(i).filter(Boolean).slice(0, u);
|
|
12
|
+
if (!(o.length === 0 || s.length === 0)) return {
|
|
13
|
+
rows: o,
|
|
14
|
+
columns: s,
|
|
15
|
+
cells: r(a.cells, d).map((e) => ({
|
|
16
|
+
row: i(e.row),
|
|
17
|
+
column: i(e.column),
|
|
18
|
+
value: t(e.value)
|
|
19
|
+
})).filter((e) => e.value !== null),
|
|
20
|
+
minValue: t(a.minValue) ?? void 0,
|
|
21
|
+
maxValue: t(a.maxValue) ?? void 0
|
|
22
|
+
};
|
|
23
|
+
}, [f.data]);
|
|
24
|
+
return /* @__PURE__ */ l(o, {
|
|
25
|
+
title: f.title,
|
|
26
|
+
children: /* @__PURE__ */ l(s, {
|
|
27
|
+
widget: p,
|
|
28
|
+
data: m
|
|
29
|
+
})
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
//#endregion
|
|
33
|
+
export { f as HeatmapEmbed };
|
|
34
|
+
|
|
35
|
+
//# sourceMappingURL=HeatmapEmbed.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"HeatmapEmbed.js","names":[],"sources":["../../../../../src/bigconsole/components/embed/widgets/HeatmapEmbed.tsx"],"sourcesContent":["/**\n * Read-only heatmap embed renderer (BOFF-7926).\n *\n * Reuses the in-app HeatmapWidget. The service projects\n * `{ rows: string[], columns: string[], cells: [{row, column, value}], minValue?, maxValue? }`.\n */\nimport { useMemo } from 'react';\nimport { HeatmapWidget, type HeatmapData } from '../../widgets/heatmap/HeatmapWidget';\nimport type { EmbedWidgetRenderProps } from '../types';\nimport { toWidgetShim } from '../widgetShim';\nimport { EmbedFrame } from './EmbedFrame';\nimport { asArray, asFiniteNumber, asRecord, asRecordArray, displayValue } from './shared';\n\nconst MAX_AXIS = 50;\nconst MAX_CELLS = 2500;\n\nexport function HeatmapEmbed({ widget }: EmbedWidgetRenderProps) {\n const shim = useMemo(() => toWidgetShim(widget), [widget]);\n const data = useMemo((): HeatmapData | undefined => {\n const d = asRecord(widget.data);\n const rows = asArray(d.rows).map(displayValue).filter(Boolean).slice(0, MAX_AXIS);\n const columns = asArray(d.columns).map(displayValue).filter(Boolean).slice(0, MAX_AXIS);\n if (rows.length === 0 || columns.length === 0) return undefined;\n const cells = asRecordArray(d.cells, MAX_CELLS)\n .map((c) => ({ row: displayValue(c.row), column: displayValue(c.column), value: asFiniteNumber(c.value) }))\n .filter((c): c is { row: string; column: string; value: number } => c.value !== null);\n return {\n rows,\n columns,\n cells,\n minValue: asFiniteNumber(d.minValue) ?? undefined,\n maxValue: asFiniteNumber(d.maxValue) ?? undefined,\n };\n }, [widget.data]);\n return (\n <EmbedFrame title={widget.title}>\n <HeatmapWidget widget={shim} data={data} />\n </EmbedFrame>\n );\n}\n"],"mappings":";;;;;;;AAaA,IAAM,IAAW,IACX,IAAY;AAElB,SAAgB,EAAa,EAAE,aAAkC;CAC/D,IAAM,IAAO,QAAc,EAAa,EAAO,EAAE,CAAC,EAAO,CAAC,EACpD,IAAO,QAAuC;EAClD,IAAM,IAAI,EAAS,EAAO,KAAK,EACzB,IAAO,EAAQ,EAAE,KAAK,CAAC,IAAI,EAAa,CAAC,OAAO,QAAQ,CAAC,MAAM,GAAG,EAAS,EAC3E,IAAU,EAAQ,EAAE,QAAQ,CAAC,IAAI,EAAa,CAAC,OAAO,QAAQ,CAAC,MAAM,GAAG,EAAS;AACnF,UAAK,WAAW,KAAK,EAAQ,WAAW,GAI5C,QAAO;GACL;GACA;GACA,OANY,EAAc,EAAE,OAAO,EAAU,CAC5C,KAAK,OAAO;IAAE,KAAK,EAAa,EAAE,IAAI;IAAE,QAAQ,EAAa,EAAE,OAAO;IAAE,OAAO,EAAe,EAAE,MAAM;IAAE,EAAE,CAC1G,QAAQ,MAA2D,EAAE,UAAU,KAAK;GAKrF,UAAU,EAAe,EAAE,SAAS,IAAI,KAAA;GACxC,UAAU,EAAe,EAAE,SAAS,IAAI,KAAA;GACzC;IACA,CAAC,EAAO,KAAK,CAAC;AACjB,QACE,kBAAC,GAAD;EAAY,OAAO,EAAO;YACxB,kBAAC,GAAD;GAAe,QAAQ;GAAY;GAAQ,CAAA;EAChC,CAAA"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { asArray as e, asRecord as t, asRecordArray as n, displayValue as r, safeColor as i } from "./shared.js";
|
|
2
|
+
import { toWidgetShim as a } from "../widgetShim.js";
|
|
3
|
+
import { EmbedFrame as o } from "./EmbedFrame.js";
|
|
4
|
+
import { fallbackTranslate as s } from "../../widgets/utils/translate.js";
|
|
5
|
+
import c from "../../widgets/kanban/KanbanView.js";
|
|
6
|
+
import { useMemo as l } from "react";
|
|
7
|
+
import { jsx as u } from "react/jsx-runtime";
|
|
8
|
+
//#region src/bigconsole/components/embed/widgets/KanbanEmbed.tsx
|
|
9
|
+
var d = 20, f = 1e3, p = new Set([
|
|
10
|
+
"high",
|
|
11
|
+
"medium",
|
|
12
|
+
"low"
|
|
13
|
+
]);
|
|
14
|
+
function m({ widget: m }) {
|
|
15
|
+
let h = l(() => ({
|
|
16
|
+
...a(m),
|
|
17
|
+
config: {}
|
|
18
|
+
}), [m]), g = l(() => {
|
|
19
|
+
let a = t(m.data);
|
|
20
|
+
return {
|
|
21
|
+
columns: n(a.columns, d).map((e, t) => ({
|
|
22
|
+
id: r(e.id) || `c${t}`,
|
|
23
|
+
title: r(e.title) || r(e.id),
|
|
24
|
+
color: i(e.color)
|
|
25
|
+
})).filter((e) => e.title !== ""),
|
|
26
|
+
tasks: n(a.tasks, f).map((t, n) => {
|
|
27
|
+
let i = typeof t.priority == "string" && p.has(t.priority) ? t.priority : void 0, a = e(t.labels).filter((e) => typeof e == "string").slice(0, 10);
|
|
28
|
+
return {
|
|
29
|
+
id: `t${n}`,
|
|
30
|
+
title: r(t.title),
|
|
31
|
+
column: r(t.column),
|
|
32
|
+
priority: i,
|
|
33
|
+
labels: a.length > 0 ? a : void 0
|
|
34
|
+
};
|
|
35
|
+
})
|
|
36
|
+
};
|
|
37
|
+
}, [m.data]);
|
|
38
|
+
return /* @__PURE__ */ u(o, {
|
|
39
|
+
title: m.title,
|
|
40
|
+
children: /* @__PURE__ */ u(c, {
|
|
41
|
+
widget: h,
|
|
42
|
+
data: g,
|
|
43
|
+
t: s
|
|
44
|
+
})
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
//#endregion
|
|
48
|
+
export { m as KanbanEmbed };
|
|
49
|
+
|
|
50
|
+
//# sourceMappingURL=KanbanEmbed.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"KanbanEmbed.js","names":[],"sources":["../../../../../src/bigconsole/components/embed/widgets/KanbanEmbed.tsx"],"sourcesContent":["/**\n * Read-only kanban embed renderer (BOFF-7926).\n *\n * Reuses the provider-free KanbanView with a static translator. No drag, no\n * click. The service projects `{ columns: [{id, title}], tasks: [{title, column,\n * priority?, labels?}] }` and never sends `assignee` (people's names/emails stay\n * out of public embeds) — the renderer drops it too, defensively.\n */\nimport { useMemo } from 'react';\nimport { KanbanView, type KanbanData, type KanbanTask } from '../../widgets/kanban/KanbanView';\nimport { fallbackTranslate } from '../../widgets/utils/translate';\nimport type { EmbedWidgetRenderProps } from '../types';\nimport { toWidgetShim } from '../widgetShim';\nimport { EmbedFrame } from './EmbedFrame';\nimport { asArray, asRecord, asRecordArray, displayValue, safeColor } from './shared';\n\nconst MAX_COLUMNS = 20;\nconst MAX_TASKS = 1000;\nconst PRIORITIES = new Set(['high', 'medium', 'low']);\n\nexport function KanbanEmbed({ widget }: EmbedWidgetRenderProps) {\n // The view's row-normalisation reads field-mapping config; the service already\n // produced the canonical board, so pass only the title through.\n const shim = useMemo(() => ({ ...toWidgetShim(widget), config: {} }), [widget]);\n const data = useMemo((): KanbanData => {\n const d = asRecord(widget.data);\n const columns = asRecordArray(d.columns, MAX_COLUMNS)\n .map((c, i) => ({\n id: displayValue(c.id) || `c${i}`,\n title: displayValue(c.title) || displayValue(c.id),\n color: safeColor(c.color),\n }))\n .filter((c) => c.title !== '');\n const tasks: KanbanTask[] = asRecordArray(d.tasks, MAX_TASKS).map((t, i) => {\n const priority = typeof t.priority === 'string' && PRIORITIES.has(t.priority) ? t.priority : undefined;\n const labels = asArray(t.labels)\n .filter((l): l is string => typeof l === 'string')\n .slice(0, 10);\n return {\n id: `t${i}`,\n title: displayValue(t.title),\n column: displayValue(t.column),\n priority: priority as KanbanTask['priority'],\n labels: labels.length > 0 ? labels : undefined,\n };\n });\n return { columns, tasks };\n }, [widget.data]);\n return (\n <EmbedFrame title={widget.title}>\n <KanbanView widget={shim} data={data} t={fallbackTranslate} />\n </EmbedFrame>\n );\n}\n"],"mappings":";;;;;;;;AAgBA,IAAM,IAAc,IACd,IAAY,KACZ,IAAa,IAAI,IAAI;CAAC;CAAQ;CAAU;CAAM,CAAC;AAErD,SAAgB,EAAY,EAAE,aAAkC;CAG9D,IAAM,IAAO,SAAe;EAAE,GAAG,EAAa,EAAO;EAAE,QAAQ,EAAE;EAAE,GAAG,CAAC,EAAO,CAAC,EACzE,IAAO,QAA0B;EACrC,IAAM,IAAI,EAAS,EAAO,KAAK;AAqB/B,SAAO;GAAE,SApBO,EAAc,EAAE,SAAS,EAAY,CAClD,KAAK,GAAG,OAAO;IACd,IAAI,EAAa,EAAE,GAAG,IAAI,IAAI;IAC9B,OAAO,EAAa,EAAE,MAAM,IAAI,EAAa,EAAE,GAAG;IAClD,OAAO,EAAU,EAAE,MAAM;IAC1B,EAAE,CACF,QAAQ,MAAM,EAAE,UAAU,GAAG;GAcd,OAbU,EAAc,EAAE,OAAO,EAAU,CAAC,KAAK,GAAG,MAAM;IAC1E,IAAM,IAAW,OAAO,EAAE,YAAa,YAAY,EAAW,IAAI,EAAE,SAAS,GAAG,EAAE,WAAW,KAAA,GACvF,IAAS,EAAQ,EAAE,OAAO,CAC7B,QAAQ,MAAmB,OAAO,KAAM,SAAS,CACjD,MAAM,GAAG,GAAG;AACf,WAAO;KACL,IAAI,IAAI;KACR,OAAO,EAAa,EAAE,MAAM;KAC5B,QAAQ,EAAa,EAAE,OAAO;KACpB;KACV,QAAQ,EAAO,SAAS,IAAI,IAAS,KAAA;KACtC;KACD;GACuB;IACxB,CAAC,EAAO,KAAK,CAAC;AACjB,QACE,kBAAC,GAAD;EAAY,OAAO,EAAO;YACxB,kBAAC,GAAD;GAAY,QAAQ;GAAY;GAAM,GAAG;GAAqB,CAAA;EACnD,CAAA"}
|