@burdenoff/microfe-bigconsole 2026.1012.3 → 2026.1012.4
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/assistant/assistantApi.js +5 -5
- package/dist/bigconsole/components/builder/inspector/AppearanceSection.js +33 -18
- package/dist/bigconsole/components/dashboard/WidgetPalette.js +154 -150
- package/dist/bigconsole/components/embed/renderer-manifest.js +12 -0
- package/dist/bigconsole/components/widgets/WidgetRegistry.js +122 -1
- package/dist/bigconsole/components/widgets/WidgetWrapper.js +227 -224
- package/dist/bigconsole/components/widgets/advanced/AdvancedWidgetConfig.d.ts +10 -0
- package/dist/bigconsole/components/widgets/advanced/AdvancedWidgetConfig.js +113 -0
- package/dist/bigconsole/components/widgets/advanced/AdvancedWidgets.d.ts +10 -0
- package/dist/bigconsole/components/widgets/advanced/AdvancedWidgets.js +186 -0
- package/dist/bigconsole/components/widgets/advanced/data.d.ts +36 -0
- package/dist/bigconsole/components/widgets/advanced/data.js +113 -0
- package/dist/bigconsole/components/widgets/advanced/mapData.d.ts +10 -0
- package/dist/bigconsole/components/widgets/advanced/mapData.js +22 -0
- package/dist/bigconsole/components/widgets/advanced/waterfallData.d.ts +15 -0
- package/dist/bigconsole/components/widgets/advanced/waterfallData.js +28 -0
- package/dist/bigconsole/components/widgets/chart/charts/WaterfallChart.js +34 -37
- package/dist/bigconsole/components/widgets/index.js +1 -1
- package/dist/bigconsole/components/widgets/map-widget/MapWidget.d.ts +2 -0
- package/dist/bigconsole/components/widgets/map-widget/MapWidget.js +64 -63
- package/dist/bigconsole/graphql/widgetCapabilities.d.ts +7 -0
- package/dist/bigconsole/graphql/widgetCapabilities.js +37 -0
- package/dist/bigconsole/hooks/useWidgetCatalog.js +46 -41
- package/dist/bigconsole/hooks/useWidgetOperations.js +113 -88
- package/dist/bigconsole/renderers/adapters/BigConsoleRenderer.js +8 -5
- package/dist/bigconsole/types/index.d.ts +1 -1
- package/dist/bigconsole/utils/advancedWidgetCapabilities.d.ts +14 -0
- package/dist/bigconsole/utils/advancedWidgetCapabilities.js +36 -0
- package/dist/bigconsole/utils/widgetTypeMapping.d.ts +1 -1
- package/dist/bigconsole/utils/widgetTypeMapping.js +13 -2
- package/dist/generated/wspace-operations.d.ts +61 -2
- package/dist/generated/wspace-operations.js +44 -18
- package/dist/generated/wspace-types.d.ts +34 -3
- package/package.json +1 -1
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { WidgetType } from '../../../types';
|
|
2
|
+
|
|
3
|
+
interface Props {
|
|
4
|
+
type: WidgetType;
|
|
5
|
+
config: Record<string, unknown>;
|
|
6
|
+
onChange: (config: Record<string, unknown>) => void;
|
|
7
|
+
}
|
|
8
|
+
/** Field mappings are data contracts, not source fetches or transform expressions. */
|
|
9
|
+
export declare function AdvancedWidgetConfig({ type, config, onChange }: Props): import("react").JSX.Element;
|
|
10
|
+
export {};
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { Fragment as e, jsx as t, jsxs as n } from "react/jsx-runtime";
|
|
2
|
+
import { useI18n as r } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
|
|
3
|
+
//#region src/bigconsole/components/widgets/advanced/AdvancedWidgetConfig.tsx
|
|
4
|
+
function i({ type: i, config: a, onChange: o }) {
|
|
5
|
+
let { t: s } = r();
|
|
6
|
+
return /* @__PURE__ */ n("div", {
|
|
7
|
+
className: "space-y-form-gap",
|
|
8
|
+
children: [
|
|
9
|
+
(i === "map" ? [
|
|
10
|
+
[
|
|
11
|
+
"latitudeField",
|
|
12
|
+
"Latitude field",
|
|
13
|
+
"lat"
|
|
14
|
+
],
|
|
15
|
+
[
|
|
16
|
+
"longitudeField",
|
|
17
|
+
"Longitude field",
|
|
18
|
+
"lng"
|
|
19
|
+
],
|
|
20
|
+
[
|
|
21
|
+
"labelField",
|
|
22
|
+
"Label field",
|
|
23
|
+
"name"
|
|
24
|
+
],
|
|
25
|
+
[
|
|
26
|
+
"valueField",
|
|
27
|
+
"Value field",
|
|
28
|
+
"value"
|
|
29
|
+
]
|
|
30
|
+
] : i === "sankey" ? [
|
|
31
|
+
[
|
|
32
|
+
"sourceField",
|
|
33
|
+
"Source field",
|
|
34
|
+
"source"
|
|
35
|
+
],
|
|
36
|
+
[
|
|
37
|
+
"targetField",
|
|
38
|
+
"Target field",
|
|
39
|
+
"target"
|
|
40
|
+
],
|
|
41
|
+
[
|
|
42
|
+
"valueField",
|
|
43
|
+
"Value field",
|
|
44
|
+
"value"
|
|
45
|
+
]
|
|
46
|
+
] : i === "waterfall" ? [[
|
|
47
|
+
"labelField",
|
|
48
|
+
"Label field",
|
|
49
|
+
"name"
|
|
50
|
+
], [
|
|
51
|
+
"valueField",
|
|
52
|
+
"Value field",
|
|
53
|
+
"value"
|
|
54
|
+
]] : [[
|
|
55
|
+
"groupField",
|
|
56
|
+
"Group field",
|
|
57
|
+
"group"
|
|
58
|
+
], [
|
|
59
|
+
"valueField",
|
|
60
|
+
"Value field",
|
|
61
|
+
"value"
|
|
62
|
+
]]).map(([e = "", r = "", i = ""]) => /* @__PURE__ */ n("label", {
|
|
63
|
+
className: "block text-sm text-text-primary",
|
|
64
|
+
children: [s(`bigconsole.widget.advanced.${e}`, r), /* @__PURE__ */ t("input", {
|
|
65
|
+
className: "mt-1 w-full rounded-md border border-border-default bg-bg-base px-3 py-2",
|
|
66
|
+
value: typeof a[e] == "string" ? a[e] : i,
|
|
67
|
+
onChange: (t) => o({
|
|
68
|
+
...a,
|
|
69
|
+
[e]: t.target.value
|
|
70
|
+
})
|
|
71
|
+
})]
|
|
72
|
+
}, e)),
|
|
73
|
+
i === "box_plot" && /* @__PURE__ */ n(e, { children: [/* @__PURE__ */ n("label", {
|
|
74
|
+
className: "block text-sm text-text-primary",
|
|
75
|
+
children: [s("bigconsole.widget.boxPlot.mode", "Input format"), /* @__PURE__ */ n("select", {
|
|
76
|
+
className: "mt-1 w-full rounded-md border border-border-default bg-bg-base px-3 py-2",
|
|
77
|
+
value: a.mode === "summary" ? "summary" : "observations",
|
|
78
|
+
onChange: (e) => o({
|
|
79
|
+
...a,
|
|
80
|
+
mode: e.target.value
|
|
81
|
+
}),
|
|
82
|
+
children: [/* @__PURE__ */ t("option", {
|
|
83
|
+
value: "observations",
|
|
84
|
+
children: s("bigconsole.widget.boxPlot.observations", "Individual observations")
|
|
85
|
+
}), /* @__PURE__ */ t("option", {
|
|
86
|
+
value: "summary",
|
|
87
|
+
children: s("bigconsole.widget.boxPlot.summary", "Five-number summaries")
|
|
88
|
+
})]
|
|
89
|
+
})]
|
|
90
|
+
}), /* @__PURE__ */ t("p", {
|
|
91
|
+
className: "text-xs text-text-secondary",
|
|
92
|
+
children: s("bigconsole.widget.boxPlot.summaryHelp", "Summary rows require min, q1, median, q3 and max. Observation rows require the configured group and numeric value fields.")
|
|
93
|
+
})] }),
|
|
94
|
+
i === "waterfall" && /* @__PURE__ */ n("label", {
|
|
95
|
+
className: "flex items-center gap-2 text-sm text-text-primary",
|
|
96
|
+
children: [/* @__PURE__ */ t("input", {
|
|
97
|
+
type: "checkbox",
|
|
98
|
+
checked: a.showTotal !== !1,
|
|
99
|
+
onChange: (e) => o({
|
|
100
|
+
...a,
|
|
101
|
+
showTotal: e.target.checked
|
|
102
|
+
})
|
|
103
|
+
}), s("bigconsole.widget.waterfall.showTotal", "Show cumulative total")]
|
|
104
|
+
}),
|
|
105
|
+
i === "sankey" && /* @__PURE__ */ t("p", {
|
|
106
|
+
className: "text-xs text-text-secondary",
|
|
107
|
+
children: s("bigconsole.widget.sankey.inputHelp", "Each row connects a source to a target with a nonnegative numeric value. Circular flows cannot be displayed.")
|
|
108
|
+
})
|
|
109
|
+
]
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
//#endregion
|
|
113
|
+
export { i as AdvancedWidgetConfig };
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { Widget } from '../../../types';
|
|
2
|
+
|
|
3
|
+
interface Props {
|
|
4
|
+
widget: Widget;
|
|
5
|
+
data?: unknown;
|
|
6
|
+
}
|
|
7
|
+
export declare const SankeyWidget: import('react').NamedExoticComponent<Props>;
|
|
8
|
+
export declare const BoxPlotWidget: import('react').NamedExoticComponent<Props>;
|
|
9
|
+
export declare const WaterfallWidget: import('react').NamedExoticComponent<Props>;
|
|
10
|
+
export {};
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
import e from "../chart/ChartWidget.js";
|
|
2
|
+
import { normalizeBoxPlot as t, normalizeSankey as n } from "./data.js";
|
|
3
|
+
import { memo as r, useMemo as i } from "react";
|
|
4
|
+
import { jsx as a, jsxs as o } from "react/jsx-runtime";
|
|
5
|
+
import { useI18n as s } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
|
|
6
|
+
import { ResponsiveContainer as c, Sankey as l, Tooltip as u } from "recharts";
|
|
7
|
+
//#region src/bigconsole/components/widgets/advanced/AdvancedWidgets.tsx
|
|
8
|
+
function d(e) {
|
|
9
|
+
try {
|
|
10
|
+
return { data: e() };
|
|
11
|
+
} catch (e) {
|
|
12
|
+
return { error: e instanceof Error ? e.message : "Invalid chart data." };
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
function f({ message: e, error: t = !1 }) {
|
|
16
|
+
return /* @__PURE__ */ a("div", {
|
|
17
|
+
role: t ? "alert" : "status",
|
|
18
|
+
className: "h-full flex items-center justify-center p-4 text-sm text-secondary",
|
|
19
|
+
children: e
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
function p({ x: e, y: t, width: n, height: r, payload: i }) {
|
|
23
|
+
return /* @__PURE__ */ o("g", { children: [/* @__PURE__ */ a("rect", {
|
|
24
|
+
x: e,
|
|
25
|
+
y: t,
|
|
26
|
+
width: n,
|
|
27
|
+
height: r,
|
|
28
|
+
fill: "var(--color-chart-1)"
|
|
29
|
+
}), /* @__PURE__ */ o("text", {
|
|
30
|
+
x: e + n + 6,
|
|
31
|
+
y: t + r / 2,
|
|
32
|
+
dominantBaseline: "middle",
|
|
33
|
+
fill: "var(--color-text-primary)",
|
|
34
|
+
fontSize: 12,
|
|
35
|
+
children: [i.name.length > 24 ? i.name.slice(0, 23) + "…" : i.name, /* @__PURE__ */ a("title", { children: i.name })]
|
|
36
|
+
})] });
|
|
37
|
+
}
|
|
38
|
+
var m = r(function({ widget: e, data: t = [] }) {
|
|
39
|
+
let { t: r } = s(), m = e.config, h = i(() => d(() => n(t, m)), [t, m]);
|
|
40
|
+
return h.error ? /* @__PURE__ */ a(f, {
|
|
41
|
+
message: h.error,
|
|
42
|
+
error: !0
|
|
43
|
+
}) : h.data?.links.length ? /* @__PURE__ */ o("div", {
|
|
44
|
+
role: "img",
|
|
45
|
+
"aria-label": `${r("bigconsole.widget.sankey.label", "Sankey flow chart")}: ${e.title}`,
|
|
46
|
+
className: "h-full w-full",
|
|
47
|
+
children: [/* @__PURE__ */ a(c, {
|
|
48
|
+
width: "100%",
|
|
49
|
+
height: "100%",
|
|
50
|
+
children: /* @__PURE__ */ a(l, {
|
|
51
|
+
data: h.data,
|
|
52
|
+
nodePadding: 24,
|
|
53
|
+
nodeWidth: 12,
|
|
54
|
+
margin: {
|
|
55
|
+
top: 20,
|
|
56
|
+
bottom: 20,
|
|
57
|
+
left: 100,
|
|
58
|
+
right: 100
|
|
59
|
+
},
|
|
60
|
+
link: {
|
|
61
|
+
stroke: "var(--color-chart-1)",
|
|
62
|
+
strokeOpacity: .35
|
|
63
|
+
},
|
|
64
|
+
node: p,
|
|
65
|
+
children: /* @__PURE__ */ a(u, {})
|
|
66
|
+
})
|
|
67
|
+
}), /* @__PURE__ */ a("span", {
|
|
68
|
+
className: "sr-only",
|
|
69
|
+
children: h.data.links.map((e) => `${h.data.nodes[e.source]?.name} to ${h.data.nodes[e.target]?.name}: ${e.value}`).join("; ")
|
|
70
|
+
})]
|
|
71
|
+
}) : /* @__PURE__ */ a(f, { message: r("bigconsole.widget.sankey.empty", "No positive flows to display.") });
|
|
72
|
+
}), h = r(function({ widget: e, data: n = [] }) {
|
|
73
|
+
let { t: r } = s(), c = e.config, l = i(() => d(() => t(n, c)), [n, c]);
|
|
74
|
+
if (l.error) return /* @__PURE__ */ a(f, {
|
|
75
|
+
message: l.error,
|
|
76
|
+
error: !0
|
|
77
|
+
});
|
|
78
|
+
if (!l.data?.length) return /* @__PURE__ */ a(f, { message: r("bigconsole.widget.boxPlot.empty", "No observations to display.") });
|
|
79
|
+
let u = l.data, p = u.flatMap((e) => [
|
|
80
|
+
e.min,
|
|
81
|
+
e.max,
|
|
82
|
+
...e.outliers
|
|
83
|
+
]), m = p.reduce((e, t) => Math.min(e, t), Infinity), h = p.reduce((e, t) => Math.max(e, t), -Infinity), g = h / 2 - m / 2 || 1, _ = (e) => 140 + (e / 2 - m / 2) / g * 610, v = Math.max(160, u.length * 65 + 55);
|
|
84
|
+
return /* @__PURE__ */ o("svg", {
|
|
85
|
+
role: "img",
|
|
86
|
+
"aria-label": `${r("bigconsole.widget.boxPlot.label", "Box plot")}: ${e.title}`,
|
|
87
|
+
viewBox: `0 0 800 ${v}`,
|
|
88
|
+
className: "h-full w-full",
|
|
89
|
+
preserveAspectRatio: "xMidYMid meet",
|
|
90
|
+
children: [
|
|
91
|
+
/* @__PURE__ */ a("title", { children: e.title }),
|
|
92
|
+
/* @__PURE__ */ a("desc", { children: r("bigconsole.widget.boxPlot.description", "Boxes show the first and third quartiles with the median. Whiskers use the 1.5 interquartile-range rule; circles show outliers.") }),
|
|
93
|
+
u.map((e, t) => {
|
|
94
|
+
let n = t * 65 + 40;
|
|
95
|
+
return /* @__PURE__ */ o("g", { children: [
|
|
96
|
+
/* @__PURE__ */ a("title", { children: `${e.label}: min ${e.min}, Q1 ${e.q1}, median ${e.median}, Q3 ${e.q3}, max ${e.max}${e.count === void 0 ? "" : `; ${e.count} observations`}` }),
|
|
97
|
+
/* @__PURE__ */ a("text", {
|
|
98
|
+
x: 130,
|
|
99
|
+
y: n + 5,
|
|
100
|
+
textAnchor: "end",
|
|
101
|
+
fill: "var(--color-text-secondary)",
|
|
102
|
+
fontSize: 13,
|
|
103
|
+
children: e.label
|
|
104
|
+
}),
|
|
105
|
+
/* @__PURE__ */ a("line", {
|
|
106
|
+
x1: _(e.min),
|
|
107
|
+
x2: _(e.max),
|
|
108
|
+
y1: n,
|
|
109
|
+
y2: n,
|
|
110
|
+
stroke: "var(--color-chart-1)"
|
|
111
|
+
}),
|
|
112
|
+
/* @__PURE__ */ a("line", {
|
|
113
|
+
x1: _(e.min),
|
|
114
|
+
x2: _(e.min),
|
|
115
|
+
y1: n - 10,
|
|
116
|
+
y2: n + 10,
|
|
117
|
+
stroke: "var(--color-chart-1)"
|
|
118
|
+
}),
|
|
119
|
+
/* @__PURE__ */ a("line", {
|
|
120
|
+
x1: _(e.max),
|
|
121
|
+
x2: _(e.max),
|
|
122
|
+
y1: n - 10,
|
|
123
|
+
y2: n + 10,
|
|
124
|
+
stroke: "var(--color-chart-1)"
|
|
125
|
+
}),
|
|
126
|
+
/* @__PURE__ */ a("rect", {
|
|
127
|
+
x: _(e.q1),
|
|
128
|
+
y: n - 16,
|
|
129
|
+
width: Math.max(1, _(e.q3) - _(e.q1)),
|
|
130
|
+
height: 32,
|
|
131
|
+
fill: "var(--color-chart-1)",
|
|
132
|
+
fillOpacity: .25,
|
|
133
|
+
stroke: "var(--color-chart-1)"
|
|
134
|
+
}),
|
|
135
|
+
/* @__PURE__ */ a("line", {
|
|
136
|
+
x1: _(e.median),
|
|
137
|
+
x2: _(e.median),
|
|
138
|
+
y1: n - 16,
|
|
139
|
+
y2: n + 16,
|
|
140
|
+
stroke: "var(--color-text-primary)",
|
|
141
|
+
strokeWidth: 2
|
|
142
|
+
}),
|
|
143
|
+
e.outliers.map((e, t) => /* @__PURE__ */ a("circle", {
|
|
144
|
+
cx: _(e),
|
|
145
|
+
cy: n,
|
|
146
|
+
r: 3,
|
|
147
|
+
fill: "var(--color-chart-2)",
|
|
148
|
+
children: /* @__PURE__ */ a("title", { children: `${r("bigconsole.widget.boxPlot.outlier", "Outlier")}: ${e}` })
|
|
149
|
+
}, t))
|
|
150
|
+
] }, `${e.label}-${t}`);
|
|
151
|
+
}),
|
|
152
|
+
/* @__PURE__ */ a("text", {
|
|
153
|
+
x: 140,
|
|
154
|
+
y: v - 12,
|
|
155
|
+
fill: "var(--color-text-secondary)",
|
|
156
|
+
fontSize: 12,
|
|
157
|
+
children: m
|
|
158
|
+
}),
|
|
159
|
+
/* @__PURE__ */ a("text", {
|
|
160
|
+
x: 750,
|
|
161
|
+
y: v - 12,
|
|
162
|
+
textAnchor: "end",
|
|
163
|
+
fill: "var(--color-text-secondary)",
|
|
164
|
+
fontSize: 12,
|
|
165
|
+
children: h
|
|
166
|
+
})
|
|
167
|
+
]
|
|
168
|
+
});
|
|
169
|
+
}), g = r(function({ widget: t, data: n = [] }) {
|
|
170
|
+
let { t: r } = s(), o = i(() => ({
|
|
171
|
+
...t,
|
|
172
|
+
config: {
|
|
173
|
+
...t.config,
|
|
174
|
+
chartType: "waterfall"
|
|
175
|
+
}
|
|
176
|
+
}), [t]), c = n && typeof n == "object" && !Array.isArray(n) && "rows" in n ? n.rows : n;
|
|
177
|
+
return Array.isArray(c) ? /* @__PURE__ */ a(e, {
|
|
178
|
+
widget: o,
|
|
179
|
+
data: c
|
|
180
|
+
}) : /* @__PURE__ */ a(f, {
|
|
181
|
+
message: r("bigconsole.widget.waterfall.invalidData", "Waterfall data must be an array of rows."),
|
|
182
|
+
error: !0
|
|
183
|
+
});
|
|
184
|
+
});
|
|
185
|
+
//#endregion
|
|
186
|
+
export { h as BoxPlotWidget, m as SankeyWidget, g as WaterfallWidget };
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/** Normalizers operate only on rows already supplied by the governed widget data hub. */
|
|
2
|
+
export interface SankeyNode {
|
|
3
|
+
name: string;
|
|
4
|
+
}
|
|
5
|
+
export interface SankeyLink {
|
|
6
|
+
source: number;
|
|
7
|
+
target: number;
|
|
8
|
+
value: number;
|
|
9
|
+
}
|
|
10
|
+
export interface SankeyData {
|
|
11
|
+
nodes: SankeyNode[];
|
|
12
|
+
links: SankeyLink[];
|
|
13
|
+
}
|
|
14
|
+
export interface SankeyFields {
|
|
15
|
+
sourceField?: string;
|
|
16
|
+
targetField?: string;
|
|
17
|
+
valueField?: string;
|
|
18
|
+
}
|
|
19
|
+
export interface BoxPlotFields {
|
|
20
|
+
groupField?: string;
|
|
21
|
+
valueField?: string;
|
|
22
|
+
mode?: 'observations' | 'summary';
|
|
23
|
+
}
|
|
24
|
+
export interface BoxPlotRow {
|
|
25
|
+
label: string;
|
|
26
|
+
min: number;
|
|
27
|
+
q1: number;
|
|
28
|
+
median: number;
|
|
29
|
+
q3: number;
|
|
30
|
+
max: number;
|
|
31
|
+
outliers: number[];
|
|
32
|
+
count?: number;
|
|
33
|
+
}
|
|
34
|
+
/** Recharts Sankey requires a directed acyclic graph, so reject cycles before layout. */
|
|
35
|
+
export declare function normalizeSankey(data: unknown, fields?: SankeyFields): SankeyData;
|
|
36
|
+
export declare function normalizeBoxPlot(data: unknown, fields?: BoxPlotFields): BoxPlotRow[];
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
//#region src/bigconsole/components/widgets/advanced/data.ts
|
|
2
|
+
function e(e) {
|
|
3
|
+
if (e && typeof e == "object" && !Array.isArray(e) && "rows" in e && (e = e.rows), !Array.isArray(e)) throw Error("Expected an array of data rows.");
|
|
4
|
+
if (e.length > 1e5) throw Error("Too many chart rows; aggregate the source before displaying it.");
|
|
5
|
+
if (!e.every((e) => typeof e == "object" && !!e && !Array.isArray(e))) throw Error("Every data row must be an object.");
|
|
6
|
+
return e;
|
|
7
|
+
}
|
|
8
|
+
function t(e) {
|
|
9
|
+
return typeof e == "number" && Number.isFinite(e);
|
|
10
|
+
}
|
|
11
|
+
function n(e) {
|
|
12
|
+
if (typeof e != "string" && typeof e != "number") throw Error("Labels must be text or numbers.");
|
|
13
|
+
let t = String(e).trim();
|
|
14
|
+
if (!t) throw Error("Labels cannot be empty.");
|
|
15
|
+
return t;
|
|
16
|
+
}
|
|
17
|
+
function r(r, i = {}) {
|
|
18
|
+
let a = i.sourceField || "source", o = i.targetField || "target", s = i.valueField || "value", c = /* @__PURE__ */ new Map(), l = /* @__PURE__ */ new Map();
|
|
19
|
+
function u(e) {
|
|
20
|
+
let t = c.get(e);
|
|
21
|
+
if (t !== void 0) return t;
|
|
22
|
+
let n = c.size;
|
|
23
|
+
if (n >= 200) throw Error("Too many Sankey nodes; aggregate categories before displaying them.");
|
|
24
|
+
return c.set(e, n), n;
|
|
25
|
+
}
|
|
26
|
+
for (let i of e(r)) {
|
|
27
|
+
let e = u(n(i[a])), r = u(n(i[o])), c = i[s];
|
|
28
|
+
if (!t(c) || c < 0) throw Error("Flow values must be finite nonnegative numbers.");
|
|
29
|
+
if (e === r) throw Error("A flow cannot connect a node to itself.");
|
|
30
|
+
let d = `${e}:${r}`, f = l.get(d), p = (f?.value ?? 0) + c;
|
|
31
|
+
if (!Number.isFinite(p)) throw Error("Combined flow value is too large.");
|
|
32
|
+
if (!f && l.size >= 1e3) throw Error("Too many Sankey links; aggregate flows before displaying them.");
|
|
33
|
+
l.set(d, {
|
|
34
|
+
source: e,
|
|
35
|
+
target: r,
|
|
36
|
+
value: p
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
let d = [...l.values()].filter((e) => e.value > 0), f = /* @__PURE__ */ new Map();
|
|
40
|
+
for (let e of d) for (let t of [`${e.source}:out`, `${e.target}:in`]) {
|
|
41
|
+
let n = (f.get(t) ?? 0) + e.value;
|
|
42
|
+
if (!Number.isFinite(n)) throw Error("Total flow value is too large.");
|
|
43
|
+
f.set(t, n);
|
|
44
|
+
}
|
|
45
|
+
let p = Array.from({ length: c.size }, () => /* @__PURE__ */ new Set()), m = Array.from({ length: c.size }, () => 0);
|
|
46
|
+
for (let e of d) p[e.source]?.add(e.target), m[e.target] = (m[e.target] ?? 0) + 1;
|
|
47
|
+
let h = m.flatMap((e, t) => e === 0 ? [t] : []), g = 0;
|
|
48
|
+
for (let e = 0; e < h.length; e++) {
|
|
49
|
+
let t = h[e];
|
|
50
|
+
if (t !== void 0) {
|
|
51
|
+
g++;
|
|
52
|
+
for (let e of p[t] ?? []) m[e] = (m[e] ?? 0) - 1, m[e] === 0 && h.push(e);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
if (g !== c.size) throw Error("Sankey data must not contain cycles.");
|
|
56
|
+
return {
|
|
57
|
+
nodes: [...c.keys()].map((e) => ({ name: e })),
|
|
58
|
+
links: d
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
function i(e, t) {
|
|
62
|
+
let n = (e.length - 1) * t, r = Math.floor(n), i = e[r] ?? 0, a = n - r;
|
|
63
|
+
return i * (1 - a) + (e[r + 1] ?? i) * a;
|
|
64
|
+
}
|
|
65
|
+
function a(r, a = {}) {
|
|
66
|
+
let o = a.groupField || "group", s = a.valueField || "value", c = e(r);
|
|
67
|
+
if (a.mode === "summary" && c.length > 50) throw Error("Too many box plot groups; filter to 50 groups or fewer.");
|
|
68
|
+
if (a.mode === "summary") return c.map((e) => {
|
|
69
|
+
let r = [
|
|
70
|
+
e.min,
|
|
71
|
+
e.q1,
|
|
72
|
+
e.median,
|
|
73
|
+
e.q3,
|
|
74
|
+
e.max
|
|
75
|
+
];
|
|
76
|
+
if (!r.every(t)) throw Error("Box plot summaries require five finite numeric values.");
|
|
77
|
+
if (r.some((e, t) => t > 0 && e < (r[t - 1] ?? e))) throw Error("Box plot summary values must satisfy min ≤ q1 ≤ median ≤ q3 ≤ max.");
|
|
78
|
+
let [i = 0, a = 0, s = 0, c = 0, l = 0] = r;
|
|
79
|
+
return {
|
|
80
|
+
label: n(e[o]),
|
|
81
|
+
min: i,
|
|
82
|
+
q1: a,
|
|
83
|
+
median: s,
|
|
84
|
+
q3: c,
|
|
85
|
+
max: l,
|
|
86
|
+
outliers: []
|
|
87
|
+
};
|
|
88
|
+
});
|
|
89
|
+
let l = /* @__PURE__ */ new Map();
|
|
90
|
+
for (let e of c) {
|
|
91
|
+
let r = n(e[o]), i = e[s];
|
|
92
|
+
if (!t(i)) throw Error("Box plot observations must be finite numbers.");
|
|
93
|
+
let a = l.get(r) ?? [];
|
|
94
|
+
if (a.push(i), !l.has(r) && l.size >= 50) throw Error("Too many box plot groups; filter to 50 groups or fewer.");
|
|
95
|
+
l.set(r, a);
|
|
96
|
+
}
|
|
97
|
+
return [...l].map(([e, t]) => {
|
|
98
|
+
t.sort((e, t) => e - t);
|
|
99
|
+
let n = i(t, .25), r = i(t, .5), a = i(t, .75), o = a - n, s = t.filter((e) => e >= n - 1.5 * o && e <= a + 1.5 * o);
|
|
100
|
+
return {
|
|
101
|
+
label: e,
|
|
102
|
+
min: s[0] ?? n,
|
|
103
|
+
q1: n,
|
|
104
|
+
median: r,
|
|
105
|
+
q3: a,
|
|
106
|
+
max: s[s.length - 1] ?? a,
|
|
107
|
+
outliers: t.filter((e) => e < n - 1.5 * o || e > a + 1.5 * o),
|
|
108
|
+
count: t.length
|
|
109
|
+
};
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
//#endregion
|
|
113
|
+
export { a as normalizeBoxPlot, r as normalizeSankey };
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export interface BoundMapMarker {
|
|
2
|
+
name: string;
|
|
3
|
+
lat: number;
|
|
4
|
+
lng: number;
|
|
5
|
+
value?: number;
|
|
6
|
+
popup?: string;
|
|
7
|
+
color?: string;
|
|
8
|
+
}
|
|
9
|
+
/** Accept standard marker rows or configured raw source fields, without inventing coordinates. */
|
|
10
|
+
export declare function normalizeMapMarkers(input: unknown, config?: Record<string, unknown>): BoundMapMarker[];
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
//#region src/bigconsole/components/widgets/advanced/mapData.ts
|
|
2
|
+
function e(e, t = {}) {
|
|
3
|
+
if (!Array.isArray(e)) return [];
|
|
4
|
+
let n = typeof t.latitudeField == "string" ? t.latitudeField : "lat", r = typeof t.longitudeField == "string" ? t.longitudeField : "lng", i = typeof t.labelField == "string" ? t.labelField : "name", a = typeof t.valueField == "string" ? t.valueField : "value", o = [];
|
|
5
|
+
for (let t of e) {
|
|
6
|
+
if (!t || typeof t != "object" || Array.isArray(t)) continue;
|
|
7
|
+
let e = t[n], s = t[r];
|
|
8
|
+
if (typeof e != "number" || typeof s != "number" || !Number.isFinite(e) || !Number.isFinite(s) || Math.abs(e) > 90 || Math.abs(s) > 180) continue;
|
|
9
|
+
let c = t[i], l = t[a];
|
|
10
|
+
o.push({
|
|
11
|
+
name: typeof c == "string" || typeof c == "number" ? String(c) : "",
|
|
12
|
+
lat: e,
|
|
13
|
+
lng: s,
|
|
14
|
+
value: typeof l == "number" && Number.isFinite(l) ? l : void 0,
|
|
15
|
+
popup: typeof t.popup == "string" ? t.popup : void 0,
|
|
16
|
+
color: typeof t.color == "string" ? t.color : void 0
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
return o;
|
|
20
|
+
}
|
|
21
|
+
//#endregion
|
|
22
|
+
export { e as normalizeMapMarkers };
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export interface WaterfallRow {
|
|
2
|
+
name: string;
|
|
3
|
+
range: [number, number];
|
|
4
|
+
delta: number;
|
|
5
|
+
cumulative: number;
|
|
6
|
+
isTotal: boolean;
|
|
7
|
+
sign: 'up' | 'down' | 'total';
|
|
8
|
+
original?: Record<string, unknown>;
|
|
9
|
+
}
|
|
10
|
+
export declare function buildWaterfallRows(data: Record<string, unknown>[], options?: {
|
|
11
|
+
labelField?: string;
|
|
12
|
+
valueField?: string;
|
|
13
|
+
showTotal?: boolean;
|
|
14
|
+
totalLabel?: string;
|
|
15
|
+
}): WaterfallRow[];
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
//#region src/bigconsole/components/widgets/advanced/waterfallData.ts
|
|
2
|
+
function e(e, t = {}) {
|
|
3
|
+
let n = t.labelField || "name", r = t.valueField || "value", i = 0, a = e.map((e) => {
|
|
4
|
+
let t = e[r], a = typeof t == "number" ? t : typeof t == "string" && t.trim() ? Number(t) : NaN;
|
|
5
|
+
if (!Number.isFinite(a)) throw Error("Waterfall changes must be finite numbers.");
|
|
6
|
+
let o = i;
|
|
7
|
+
if (i += a, !Number.isFinite(i)) throw Error("The cumulative waterfall value is too large.");
|
|
8
|
+
return {
|
|
9
|
+
name: String(e[n] ?? ""),
|
|
10
|
+
range: [Math.min(o, i), Math.max(o, i)],
|
|
11
|
+
delta: a,
|
|
12
|
+
cumulative: i,
|
|
13
|
+
isTotal: !1,
|
|
14
|
+
sign: a >= 0 ? "up" : "down",
|
|
15
|
+
original: e
|
|
16
|
+
};
|
|
17
|
+
});
|
|
18
|
+
return t.showTotal && a.length && a.push({
|
|
19
|
+
name: t.totalLabel || "Total",
|
|
20
|
+
range: [Math.min(0, i), Math.max(0, i)],
|
|
21
|
+
delta: i,
|
|
22
|
+
cumulative: i,
|
|
23
|
+
isTotal: !0,
|
|
24
|
+
sign: "total"
|
|
25
|
+
}), a;
|
|
26
|
+
}
|
|
27
|
+
//#endregion
|
|
28
|
+
export { e as buildWaterfallRows };
|
|
@@ -1,46 +1,46 @@
|
|
|
1
|
-
import e from "
|
|
2
|
-
import {
|
|
1
|
+
import { buildReferenceElements as e } from "./referenceElements.js";
|
|
2
|
+
import { buildWaterfallRows as t } from "../../advanced/waterfallData.js";
|
|
3
3
|
import { memo as n, useMemo as r } from "react";
|
|
4
4
|
import { jsx as i, jsxs as a } from "react/jsx-runtime";
|
|
5
5
|
import { Bar as o, BarChart as s, CartesianGrid as c, Cell as l, ResponsiveContainer as u, Tooltip as d, XAxis as f, YAxis as p } from "recharts";
|
|
6
6
|
//#region src/bigconsole/components/widgets/chart/charts/WaterfallChart.tsx
|
|
7
7
|
var m = "var(--color-status-success)", h = "var(--color-status-error)", g = "var(--color-chart-1)", _ = n(function({ data: n = [], config: _, onDataClick: v }) {
|
|
8
8
|
let y = _.labelField || _.xAxisKey || "name", b = _.valueField || "value", x = r(() => {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
9
|
+
try {
|
|
10
|
+
return {
|
|
11
|
+
rows: t(n, {
|
|
12
|
+
labelField: y,
|
|
13
|
+
valueField: b,
|
|
14
|
+
showTotal: _.showTotal,
|
|
15
|
+
totalLabel: _.totalLabel
|
|
16
|
+
}),
|
|
17
|
+
error: void 0
|
|
18
|
+
};
|
|
19
|
+
} catch (e) {
|
|
20
|
+
return {
|
|
21
|
+
rows: [],
|
|
22
|
+
error: e instanceof Error ? e.message : "Invalid waterfall data."
|
|
19
23
|
};
|
|
20
|
-
}
|
|
21
|
-
return _.showTotal && t.push({
|
|
22
|
-
name: _.totalLabel || "Total",
|
|
23
|
-
base: 0,
|
|
24
|
-
delta: e,
|
|
25
|
-
cumulative: e,
|
|
26
|
-
isTotal: !0,
|
|
27
|
-
sign: "total"
|
|
28
|
-
}), t;
|
|
24
|
+
}
|
|
29
25
|
}, [
|
|
30
26
|
n,
|
|
31
27
|
y,
|
|
32
28
|
b,
|
|
33
29
|
_.showTotal,
|
|
34
30
|
_.totalLabel
|
|
35
|
-
]), S = (e) => typeof e == "number" ? new Intl.NumberFormat("en-US", {
|
|
31
|
+
]), S = x.rows, C = (e) => typeof e == "number" ? new Intl.NumberFormat("en-US", {
|
|
36
32
|
notation: Math.abs(e) >= 1e4 ? "compact" : "standard",
|
|
37
33
|
maximumFractionDigits: 2
|
|
38
34
|
}).format(e) : String(e);
|
|
39
|
-
return x.
|
|
35
|
+
return x.error ? /* @__PURE__ */ i("div", {
|
|
36
|
+
role: "alert",
|
|
37
|
+
className: "p-4 text-sm text-secondary",
|
|
38
|
+
children: x.error
|
|
39
|
+
}) : S.length ? /* @__PURE__ */ i(u, {
|
|
40
40
|
width: "100%",
|
|
41
41
|
height: "100%",
|
|
42
42
|
children: /* @__PURE__ */ a(s, {
|
|
43
|
-
data:
|
|
43
|
+
data: S,
|
|
44
44
|
margin: {
|
|
45
45
|
top: 10,
|
|
46
46
|
right: 10,
|
|
@@ -48,7 +48,10 @@ var m = "var(--color-status-success)", h = "var(--color-status-error)", g = "var
|
|
|
48
48
|
bottom: 0
|
|
49
49
|
},
|
|
50
50
|
onClick: (e) => {
|
|
51
|
-
e?.activePayload?.[0] && v
|
|
51
|
+
if (e?.activePayload?.[0] && v) {
|
|
52
|
+
let t = e.activePayload[0].payload;
|
|
53
|
+
t.original && v(t.original, e.activeTooltipIndex || 0);
|
|
54
|
+
}
|
|
52
55
|
},
|
|
53
56
|
children: [
|
|
54
57
|
_.showGrid !== !1 && /* @__PURE__ */ i(c, {
|
|
@@ -73,25 +76,18 @@ var m = "var(--color-status-success)", h = "var(--color-status-error)", g = "var
|
|
|
73
76
|
},
|
|
74
77
|
tickLine: { stroke: "var(--color-border-default)" },
|
|
75
78
|
axisLine: { stroke: "var(--color-border-default)" },
|
|
76
|
-
tickFormatter:
|
|
79
|
+
tickFormatter: C
|
|
77
80
|
}),
|
|
78
81
|
/* @__PURE__ */ i(d, {
|
|
79
|
-
|
|
82
|
+
formatter: (e, t, n) => C(typeof n.payload?.delta == "number" ? n.payload.delta : 0),
|
|
80
83
|
cursor: {
|
|
81
84
|
fill: "var(--color-bg-muted)",
|
|
82
85
|
opacity: .5
|
|
83
86
|
}
|
|
84
87
|
}),
|
|
85
|
-
|
|
86
|
-
/* @__PURE__ */ i(o, {
|
|
87
|
-
dataKey: "base",
|
|
88
|
-
stackId: "wf",
|
|
89
|
-
fill: "transparent",
|
|
90
|
-
isAnimationActive: !1
|
|
91
|
-
}),
|
|
88
|
+
e(_.referenceLines),
|
|
92
89
|
/* @__PURE__ */ i(o, {
|
|
93
|
-
dataKey: "
|
|
94
|
-
stackId: "wf",
|
|
90
|
+
dataKey: "range",
|
|
95
91
|
radius: [
|
|
96
92
|
4,
|
|
97
93
|
4,
|
|
@@ -99,7 +95,8 @@ var m = "var(--color-status-success)", h = "var(--color-status-error)", g = "var
|
|
|
99
95
|
0
|
|
100
96
|
],
|
|
101
97
|
name: "Change",
|
|
102
|
-
|
|
98
|
+
isAnimationActive: !1,
|
|
99
|
+
children: S.map((e, t) => /* @__PURE__ */ i(l, { fill: e.sign === "total" ? g : e.sign === "up" ? m : h }, t))
|
|
103
100
|
})
|
|
104
101
|
]
|
|
105
102
|
})
|