@burdenoff/microfe-bigconsole 2026.613.2 → 2026.613.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/components/dashboard/DashboardCanvas.js +142 -135
- package/dist/bigconsole/components/dashboard/DashboardCanvas.js.map +1 -1
- package/dist/bigconsole/components/dashboard/WidgetPalette.js +124 -120
- package/dist/bigconsole/components/dashboard/WidgetPalette.js.map +1 -1
- package/dist/bigconsole/components/widgets/PropertiesPanel.js +9 -9
- package/dist/bigconsole/components/widgets/WidgetRegistry.js +65 -8
- package/dist/bigconsole/components/widgets/WidgetRegistry.js.map +1 -1
- package/dist/bigconsole/components/widgets/WidgetTypeSelector.js +32 -27
- package/dist/bigconsole/components/widgets/WidgetTypeSelector.js.map +1 -1
- package/dist/bigconsole/components/widgets/WidgetWrapper.js +9 -9
- package/dist/bigconsole/components/widgets/WidgetWrapper.js.map +1 -1
- package/dist/bigconsole/components/widgets/chart/ChartWidget.js +123 -91
- package/dist/bigconsole/components/widgets/chart/ChartWidget.js.map +1 -1
- package/dist/bigconsole/components/widgets/chart/charts/AreaChart.js +40 -35
- package/dist/bigconsole/components/widgets/chart/charts/AreaChart.js.map +1 -1
- package/dist/bigconsole/components/widgets/chart/charts/BarChart.js +30 -25
- package/dist/bigconsole/components/widgets/chart/charts/BarChart.js.map +1 -1
- package/dist/bigconsole/components/widgets/chart/charts/ComboChart.js +139 -0
- package/dist/bigconsole/components/widgets/chart/charts/ComboChart.js.map +1 -0
- package/dist/bigconsole/components/widgets/chart/charts/LineChart.js +35 -30
- package/dist/bigconsole/components/widgets/chart/charts/LineChart.js.map +1 -1
- package/dist/bigconsole/components/widgets/chart/charts/ScatterChart.js +128 -0
- package/dist/bigconsole/components/widgets/chart/charts/ScatterChart.js.map +1 -0
- package/dist/bigconsole/components/widgets/chart/charts/WaterfallChart.js +111 -0
- package/dist/bigconsole/components/widgets/chart/charts/WaterfallChart.js.map +1 -0
- package/dist/bigconsole/components/widgets/chart/charts/index.js +4 -0
- package/dist/bigconsole/components/widgets/chart/charts/referenceElements.js +49 -0
- package/dist/bigconsole/components/widgets/chart/charts/referenceElements.js.map +1 -0
- package/dist/bigconsole/components/widgets/kpi-comparison/KPIComparisonWidget.js +72 -68
- package/dist/bigconsole/components/widgets/kpi-comparison/KPIComparisonWidget.js.map +1 -1
- package/dist/bigconsole/components/widgets/map-widget/MapWidget.js +74 -24
- package/dist/bigconsole/components/widgets/map-widget/MapWidget.js.map +1 -1
- package/dist/bigconsole/components/widgets/metric-card/MetricCardWidget.js +87 -86
- package/dist/bigconsole/components/widgets/metric-card/MetricCardWidget.js.map +1 -1
- package/dist/bigconsole/components/widgets/table/TableCell.js +55 -26
- package/dist/bigconsole/components/widgets/table/TableCell.js.map +1 -1
- package/dist/bigconsole/components/widgets/table/TableHeader.js +25 -18
- package/dist/bigconsole/components/widgets/table/TableHeader.js.map +1 -1
- package/dist/bigconsole/components/widgets/table/TableWidget.js +255 -107
- package/dist/bigconsole/components/widgets/table/TableWidget.js.map +1 -1
- package/dist/bigconsole/components/widgets/utils/conditionalFormat.js +91 -0
- package/dist/bigconsole/components/widgets/utils/conditionalFormat.js.map +1 -0
- package/dist/bigconsole/hooks/index.js +2 -0
- package/dist/bigconsole/hooks/useDashboardImageExport.js +1 -0
- package/dist/bigconsole/hooks/useWidgetCatalog.js +82 -0
- package/dist/bigconsole/hooks/useWidgetCatalog.js.map +1 -0
- package/dist/bigconsole/pages/DashboardBuilderPage.js +172 -163
- package/dist/bigconsole/pages/DashboardBuilderPage.js.map +1 -1
- package/dist/bigconsole/utils/widgetTypeMapping.js +1 -0
- package/dist/bigconsole/utils/widgetTypeMapping.js.map +1 -1
- package/dist/generated/wspace-operations.js +17 -17
- package/dist/generated/wspace-operations.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
//#region src/bigconsole/components/widgets/utils/conditionalFormat.ts
|
|
2
|
+
function e(e) {
|
|
3
|
+
if (typeof e == "number") return Number.isNaN(e) ? null : e;
|
|
4
|
+
if (typeof e == "string" && e.trim() !== "") {
|
|
5
|
+
let t = Number(e);
|
|
6
|
+
return Number.isNaN(t) ? null : t;
|
|
7
|
+
}
|
|
8
|
+
return null;
|
|
9
|
+
}
|
|
10
|
+
function t(t, n, r) {
|
|
11
|
+
let i = n.field != null && r ? r[n.field] : t;
|
|
12
|
+
switch (n.operator) {
|
|
13
|
+
case "isEmpty": return i == null || i === "";
|
|
14
|
+
case "isNotEmpty": return i != null && i !== "";
|
|
15
|
+
case "contains": return String(i ?? "").toLowerCase().includes(String(n.value ?? "").toLowerCase());
|
|
16
|
+
case "notContains": return !String(i ?? "").toLowerCase().includes(String(n.value ?? "").toLowerCase());
|
|
17
|
+
case "startsWith": return String(i ?? "").toLowerCase().startsWith(String(n.value ?? "").toLowerCase());
|
|
18
|
+
case "endsWith": return String(i ?? "").toLowerCase().endsWith(String(n.value ?? "").toLowerCase());
|
|
19
|
+
default: break;
|
|
20
|
+
}
|
|
21
|
+
if (n.operator === "eq" || n.operator === "neq") {
|
|
22
|
+
let t = e(i), r = e(n.value), a = t != null && r != null ? t === r : String(i ?? "") === String(n.value ?? "");
|
|
23
|
+
return n.operator === "eq" ? a : !a;
|
|
24
|
+
}
|
|
25
|
+
let a = e(i);
|
|
26
|
+
if (a == null) return !1;
|
|
27
|
+
let o = e(n.value);
|
|
28
|
+
switch (n.operator) {
|
|
29
|
+
case "gt": return o != null && a > o;
|
|
30
|
+
case "gte": return o != null && a >= o;
|
|
31
|
+
case "lt": return o != null && a < o;
|
|
32
|
+
case "lte": return o != null && a <= o;
|
|
33
|
+
case "between": {
|
|
34
|
+
let t = e(n.value2);
|
|
35
|
+
return o == null || t == null ? !1 : a >= Math.min(o, t) && a <= Math.max(o, t);
|
|
36
|
+
}
|
|
37
|
+
case "outside": {
|
|
38
|
+
let t = e(n.value2);
|
|
39
|
+
return o == null || t == null ? !1 : a < Math.min(o, t) || a > Math.max(o, t);
|
|
40
|
+
}
|
|
41
|
+
default: return !1;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
function n(e, n, r) {
|
|
45
|
+
if (!n?.length) return;
|
|
46
|
+
let i;
|
|
47
|
+
for (let a of n) t(e, a, r) && (i = {
|
|
48
|
+
...i,
|
|
49
|
+
...a.style
|
|
50
|
+
});
|
|
51
|
+
return i;
|
|
52
|
+
}
|
|
53
|
+
function r(e) {
|
|
54
|
+
switch (e) {
|
|
55
|
+
case "success": return "var(--color-status-success)";
|
|
56
|
+
case "warning": return "var(--color-status-warning)";
|
|
57
|
+
case "danger": return "var(--color-status-error)";
|
|
58
|
+
case "info": return "var(--color-status-info)";
|
|
59
|
+
default: return "var(--color-text-secondary)";
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
var i = {
|
|
63
|
+
success: "text-status-success-text",
|
|
64
|
+
warning: "text-status-warning-text",
|
|
65
|
+
danger: "text-status-error-text",
|
|
66
|
+
info: "text-status-info-text",
|
|
67
|
+
neutral: "text-text-secondary"
|
|
68
|
+
}, a = {
|
|
69
|
+
success: "bg-status-success-bg",
|
|
70
|
+
warning: "bg-status-warning-bg",
|
|
71
|
+
danger: "bg-status-error-bg",
|
|
72
|
+
info: "bg-status-info-bg",
|
|
73
|
+
neutral: "bg-bg-muted"
|
|
74
|
+
};
|
|
75
|
+
function o(e) {
|
|
76
|
+
if (!e) return "";
|
|
77
|
+
let t = [];
|
|
78
|
+
return e.textColor && t.push(i[e.textColor]), e.bgColor && t.push(a[e.bgColor]), e.bold && t.push("font-semibold"), t.join(" ");
|
|
79
|
+
}
|
|
80
|
+
var s = {
|
|
81
|
+
"arrow-up": "M5 15l7-7 7 7",
|
|
82
|
+
"arrow-down": "M19 9l-7 7-7-7",
|
|
83
|
+
flag: "M3 21V5a2 2 0 012-2h11l-2 4 2 4H5",
|
|
84
|
+
check: "M5 13l4 4L19 7",
|
|
85
|
+
alert: "M12 9v4m0 4h.01M10.29 3.86L1.82 18a2 2 0 001.71 3h16.94a2 2 0 001.71-3L13.71 3.86a2 2 0 00-3.42 0z",
|
|
86
|
+
dot: "M12 12m-4 0a4 4 0 108 0a4 4 0 10-8 0"
|
|
87
|
+
};
|
|
88
|
+
//#endregion
|
|
89
|
+
export { s as CONDITIONAL_ICON_PATHS, o as conditionalStyleToClassName, r as intentToCssVar, n as resolveConditionalStyle };
|
|
90
|
+
|
|
91
|
+
//# sourceMappingURL=conditionalFormat.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"conditionalFormat.js","names":[],"sources":["../../../../../src/bigconsole/components/widgets/utils/conditionalFormat.ts"],"sourcesContent":["/**\n * Conditional Formatting Engine (shared)\n *\n * Rule-based styling shared across Table, Chart, KPI and Metric widgets.\n * Rules are stored on the widget `config` (e.g. `config.conditionalRules`) and\n * evaluated per data point. Colors are expressed as *semantic intents*\n * (success/warning/danger/info/neutral) — never raw hex — so theming and\n * dark-mode keep working. The intent is resolved to either a Tailwind class\n * (for DOM cells) or a CSS variable (for SVG charts) at render time.\n */\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/** Comparison operators supported by a conditional rule. */\nexport type ConditionalOperator =\n | 'gt'\n | 'gte'\n | 'lt'\n | 'lte'\n | 'eq'\n | 'neq'\n | 'between'\n | 'outside'\n | 'contains'\n | 'notContains'\n | 'startsWith'\n | 'endsWith'\n | 'isEmpty'\n | 'isNotEmpty';\n\n/**\n * Semantic color intent. Maps to `--color-status-*` / neutral tokens so the\n * result is theme-aware. Raw colors are intentionally NOT allowed here.\n */\nexport type SemanticIntent = 'success' | 'warning' | 'danger' | 'info' | 'neutral';\n\n/** Icon hint rendered alongside a matched value. */\nexport type ConditionalIcon = 'arrow-up' | 'arrow-down' | 'flag' | 'check' | 'alert' | 'dot';\n\nexport interface ConditionalStyle {\n /** Text color intent. */\n textColor?: SemanticIntent;\n /** Background color intent (subtle fill). */\n bgColor?: SemanticIntent;\n /** Bold the matched value. */\n bold?: boolean;\n /** Icon hint to render before the value. */\n icon?: ConditionalIcon;\n /** Render an in-cell data bar scaled against `dataBarMax`. */\n dataBar?: boolean;\n /** Color intent for the data bar (defaults to `info`). */\n dataBarColor?: SemanticIntent;\n}\n\nexport interface ConditionalRule {\n /** Optional stable id (UI keying). */\n id?: string;\n /**\n * Field to test. When omitted, the rule tests the value it is applied to\n * (e.g. the current cell value or series value).\n */\n field?: string;\n /** Comparison operator. */\n operator: ConditionalOperator;\n /** Comparison operand (primary). */\n value?: string | number;\n /** Second operand for `between` / `outside`. */\n value2?: string | number;\n /** Styling applied when the rule matches. */\n style: ConditionalStyle;\n}\n\n// ============================================================================\n// Evaluation\n// ============================================================================\n\nfunction toNumber(v: unknown): number | null {\n if (typeof v === 'number') return Number.isNaN(v) ? null : v;\n if (typeof v === 'string' && v.trim() !== '') {\n const n = Number(v);\n return Number.isNaN(n) ? null : n;\n }\n return null;\n}\n\n/** Evaluate a single rule against a candidate value. */\nexport function evaluateRule(rawValue: unknown, rule: ConditionalRule, rowData?: Record<string, unknown>): boolean {\n // Resolve the value being tested: explicit field on the row, else the raw value.\n const candidate = rule.field != null && rowData ? rowData[rule.field] : rawValue;\n\n switch (rule.operator) {\n case 'isEmpty':\n return candidate == null || candidate === '';\n case 'isNotEmpty':\n return candidate != null && candidate !== '';\n case 'contains':\n return String(candidate ?? '')\n .toLowerCase()\n .includes(String(rule.value ?? '').toLowerCase());\n case 'notContains':\n return !String(candidate ?? '')\n .toLowerCase()\n .includes(String(rule.value ?? '').toLowerCase());\n case 'startsWith':\n return String(candidate ?? '')\n .toLowerCase()\n .startsWith(String(rule.value ?? '').toLowerCase());\n case 'endsWith':\n return String(candidate ?? '')\n .toLowerCase()\n .endsWith(String(rule.value ?? '').toLowerCase());\n default:\n break;\n }\n\n // Equality works for both strings and numbers.\n if (rule.operator === 'eq' || rule.operator === 'neq') {\n const num = toNumber(candidate);\n const ruleNum = toNumber(rule.value);\n const equal =\n num != null && ruleNum != null ? num === ruleNum : String(candidate ?? '') === String(rule.value ?? '');\n return rule.operator === 'eq' ? equal : !equal;\n }\n\n // Remaining operators are numeric.\n const num = toNumber(candidate);\n if (num == null) return false;\n const a = toNumber(rule.value);\n\n switch (rule.operator) {\n case 'gt':\n return a != null && num > a;\n case 'gte':\n return a != null && num >= a;\n case 'lt':\n return a != null && num < a;\n case 'lte':\n return a != null && num <= a;\n case 'between': {\n const b = toNumber(rule.value2);\n if (a == null || b == null) return false;\n const lo = Math.min(a, b);\n const hi = Math.max(a, b);\n return num >= lo && num <= hi;\n }\n case 'outside': {\n const b = toNumber(rule.value2);\n if (a == null || b == null) return false;\n const lo = Math.min(a, b);\n const hi = Math.max(a, b);\n return num < lo || num > hi;\n }\n default:\n return false;\n }\n}\n\n/**\n * Resolve the merged style for a value given an ordered rule list.\n * Later matching rules override earlier ones (last-wins), so order rules from\n * general to specific. Returns `undefined` when nothing matches.\n */\nexport function resolveConditionalStyle(\n rawValue: unknown,\n rules: ConditionalRule[] | undefined,\n rowData?: Record<string, unknown>\n): ConditionalStyle | undefined {\n if (!rules?.length) return undefined;\n let merged: ConditionalStyle | undefined;\n for (const rule of rules) {\n if (evaluateRule(rawValue, rule, rowData)) {\n merged = { ...merged, ...rule.style };\n }\n }\n return merged;\n}\n\n// ============================================================================\n// Intent → presentation mapping (theme-safe)\n// ============================================================================\n\n/** CSS variable for a semantic intent's solid color (charts/SVG). */\nexport function intentToCssVar(intent: SemanticIntent): string {\n switch (intent) {\n case 'success':\n return 'var(--color-status-success)';\n case 'warning':\n return 'var(--color-status-warning)';\n case 'danger':\n return 'var(--color-status-error)';\n case 'info':\n return 'var(--color-status-info)';\n case 'neutral':\n default:\n return 'var(--color-text-secondary)';\n }\n}\n\nconst TEXT_CLASS: Record<SemanticIntent, string> = {\n success: 'text-status-success-text',\n warning: 'text-status-warning-text',\n danger: 'text-status-error-text',\n info: 'text-status-info-text',\n neutral: 'text-text-secondary',\n};\n\nconst BG_CLASS: Record<SemanticIntent, string> = {\n success: 'bg-status-success-bg',\n warning: 'bg-status-warning-bg',\n danger: 'bg-status-error-bg',\n info: 'bg-status-info-bg',\n neutral: 'bg-bg-muted',\n};\n\n/** Build the Tailwind className fragment for a resolved style (DOM cells). */\nexport function conditionalStyleToClassName(style: ConditionalStyle | undefined): string {\n if (!style) return '';\n const parts: string[] = [];\n if (style.textColor) parts.push(TEXT_CLASS[style.textColor]);\n if (style.bgColor) parts.push(BG_CLASS[style.bgColor]);\n if (style.bold) parts.push('font-semibold');\n return parts.join(' ');\n}\n\n/** SVG paths for the supported conditional icons (16x16 viewBox 0 0 24 24). */\nexport const CONDITIONAL_ICON_PATHS: Record<ConditionalIcon, string> = {\n 'arrow-up': 'M5 15l7-7 7 7',\n 'arrow-down': 'M19 9l-7 7-7-7',\n flag: 'M3 21V5a2 2 0 012-2h11l-2 4 2 4H5',\n check: 'M5 13l4 4L19 7',\n alert: 'M12 9v4m0 4h.01M10.29 3.86L1.82 18a2 2 0 001.71 3h16.94a2 2 0 001.71-3L13.71 3.86a2 2 0 00-3.42 0z',\n dot: 'M12 12m-4 0a4 4 0 108 0a4 4 0 10-8 0',\n};\n"],"mappings":"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"}
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import "./useCrossFilter.js";
|
|
2
2
|
import "./useWorkflowOperations.js";
|
|
3
3
|
import "./useWidgetData.js";
|
|
4
|
+
import "./useWidgetCatalog.js";
|
|
4
5
|
import "./useAutoRefresh.js";
|
|
5
6
|
import "./useWidgetOperations.js";
|
|
6
7
|
import "./useDashboardOperations.js";
|
|
7
8
|
import "./useWidgetExport.js";
|
|
9
|
+
import "./useDashboardImageExport.js";
|
|
8
10
|
import "./useDrilldown.js";
|
|
9
11
|
import "./useDrilldownOperations.js";
|
|
10
12
|
import "./useWidgetEvents.js";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import "react";
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { GetWidgetTypesDocument as e } from "../../generated/wspace-operations.js";
|
|
2
|
+
import t, { WIDGET_CATEGORY_LABELS as n, getAllWidgetDefinitions as r, getWidgetDefinition as i } from "../components/widgets/WidgetRegistry.js";
|
|
3
|
+
import { mapFromFederationWidgetType as a } from "../utils/widgetTypeMapping.js";
|
|
4
|
+
import { useEffect as o, useMemo as s } from "react";
|
|
5
|
+
import { useQuery as c } from "@tanstack/react-query";
|
|
6
|
+
import { print as l } from "graphql";
|
|
7
|
+
//#region src/bigconsole/hooks/useWidgetCatalog.ts
|
|
8
|
+
var u = new Set(Object.keys(n));
|
|
9
|
+
function d(e) {
|
|
10
|
+
let n = String(e).toLowerCase();
|
|
11
|
+
return Object.prototype.hasOwnProperty.call(t, n) ? n : a(e);
|
|
12
|
+
}
|
|
13
|
+
function f(e) {
|
|
14
|
+
let t = d(e.type), n = i(t), r = u.has(e.category) ? e.category : n.category;
|
|
15
|
+
return {
|
|
16
|
+
type: t,
|
|
17
|
+
name: e.label,
|
|
18
|
+
description: e.description,
|
|
19
|
+
icon: e.icon,
|
|
20
|
+
category: r,
|
|
21
|
+
component: null,
|
|
22
|
+
defaultConfig: e.defaultConfig ?? n.defaultConfig,
|
|
23
|
+
defaultSize: {
|
|
24
|
+
width: e.defaultSize.width,
|
|
25
|
+
height: e.defaultSize.height
|
|
26
|
+
},
|
|
27
|
+
minSize: {
|
|
28
|
+
width: e.minSize.width,
|
|
29
|
+
height: e.minSize.height
|
|
30
|
+
},
|
|
31
|
+
maxSize: {
|
|
32
|
+
width: e.maxSize.width,
|
|
33
|
+
height: e.maxSize.height
|
|
34
|
+
},
|
|
35
|
+
defaultResponsive: n.defaultResponsive,
|
|
36
|
+
supportsDataBinding: n.supportsDataBinding,
|
|
37
|
+
supportsDrilldown: n.supportsDrilldown,
|
|
38
|
+
supportsAutoRefresh: n.supportsAutoRefresh,
|
|
39
|
+
tags: n.tags
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
function p(t = {}) {
|
|
43
|
+
let { workspaceId: n, apiGatewayUrl: i, authToken: a, enabled: u = !0 } = t, { data: d, isLoading: p, error: m } = c({
|
|
44
|
+
queryKey: ["widgetCatalog", n],
|
|
45
|
+
queryFn: async () => {
|
|
46
|
+
let t = { "Content-Type": "application/json" };
|
|
47
|
+
n && (t["x-workspace-id"] = n), a && (t.Authorization = `Bearer ${a}`);
|
|
48
|
+
let r = i ? `${i}/workspaces/graphql` : "/workspaces/graphql", o = await fetch(r, {
|
|
49
|
+
method: "POST",
|
|
50
|
+
headers: t,
|
|
51
|
+
body: JSON.stringify({ query: l(e) })
|
|
52
|
+
});
|
|
53
|
+
if (!o.ok) throw Error(`Failed to fetch widget catalog: ${o.status}`);
|
|
54
|
+
let s = await o.json();
|
|
55
|
+
if (s.errors?.length) throw Error(s.errors[0].message);
|
|
56
|
+
return s.data?.getWidgetTypes ?? [];
|
|
57
|
+
},
|
|
58
|
+
enabled: u && !!n,
|
|
59
|
+
staleTime: 600 * 1e3
|
|
60
|
+
});
|
|
61
|
+
return o(() => {
|
|
62
|
+
m && console.warn("Falling back to bundled widget registry:", m.message);
|
|
63
|
+
}, [m]), s(() => d && d.length > 0 ? {
|
|
64
|
+
definitions: d.map(f),
|
|
65
|
+
source: "backend",
|
|
66
|
+
loading: p,
|
|
67
|
+
error: m ?? void 0
|
|
68
|
+
} : {
|
|
69
|
+
definitions: r(),
|
|
70
|
+
source: "static",
|
|
71
|
+
loading: p,
|
|
72
|
+
error: m ?? void 0
|
|
73
|
+
}, [
|
|
74
|
+
d,
|
|
75
|
+
p,
|
|
76
|
+
m
|
|
77
|
+
]);
|
|
78
|
+
}
|
|
79
|
+
//#endregion
|
|
80
|
+
export { p as default };
|
|
81
|
+
|
|
82
|
+
//# sourceMappingURL=useWidgetCatalog.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useWidgetCatalog.js","names":[],"sources":["../../../src/bigconsole/hooks/useWidgetCatalog.ts"],"sourcesContent":["/**\n * Hook to fetch the widget-type catalog from the backend (`getWidgetTypes`) and\n * merge it over the bundled static registry.\n *\n * The backend is the source of truth for which widget types exist and their\n * palette metadata (label, description, icon, category, defaultConfig, sizes).\n * A few presentational fields the backend doesn't model — defaultResponsive,\n * supports* capability flags, tags, and the (always-null) `component` — are\n * filled in from the matching static `WIDGET_DEFINITIONS` entry.\n *\n * Resilient by design: while the query is loading, or if it errors / returns\n * nothing (e.g. an older supergraph that hasn't picked up the schema yet), the\n * hook returns the full bundled registry so the palette always works.\n *\n * Follows the same fetch/auth convention as {@link useInstalledWidgets}:\n * workspaceId, apiGatewayUrl, and authToken come from BigConsoleProvider context.\n */\n\nimport { useEffect, useMemo } from 'react';\nimport { useQuery } from '@tanstack/react-query';\nimport { print } from 'graphql';\nimport { GetWidgetTypesDocument } from '../../generated/wspace-operations';\nimport type { GetWidgetTypesQuery } from '../../generated/wspace-operations';\nimport {\n WIDGET_CATEGORY_LABELS,\n WIDGET_DEFINITIONS,\n getAllWidgetDefinitions,\n getWidgetDefinition,\n type WidgetDefinition,\n} from '../components/widgets/WidgetRegistry';\nimport { mapFromFederationWidgetType } from '../utils/widgetTypeMapping';\nimport type { WidgetType, WidgetCategory } from '../types';\n\ntype BackendWidgetType = GetWidgetTypesQuery['getWidgetTypes'][number];\n\nconst KNOWN_CATEGORIES = new Set<string>(Object.keys(WIDGET_CATEGORY_LABELS));\n\n/**\n * Resolve a backend `type` value to a valid internal widget-type key.\n *\n * Handles both shapes the field can take:\n * - canonical front-end keys (`metric_card`, `chart`, `map`, …) once the\n * supergraph serves `WidgetTypeInfo.type` as String — used as-is; and\n * - federation `WidgetType` enum values (`KPI`, `LINE_CHART`, `FUNNEL`, …)\n * if an older supergraph still serves the enum — reverse-mapped to the\n * internal key via the shared widgetTypeMapping util.\n *\n * Naive lowercasing alone is wrong: `KPI` -> `kpi`, `LINE_CHART` -> `line_chart`\n * are not internal types and would render as the \"unknown\" definition.\n */\nfunction resolveInternalType(rawType: string): WidgetType {\n const lower = String(rawType).toLowerCase();\n if (Object.prototype.hasOwnProperty.call(WIDGET_DEFINITIONS, lower)) {\n return lower as WidgetType;\n }\n return mapFromFederationWidgetType(rawType);\n}\n\nexport interface UseWidgetCatalogParams {\n workspaceId?: string;\n apiGatewayUrl?: string;\n authToken?: string;\n /** When false, the query is skipped and the static registry is returned. */\n enabled?: boolean;\n}\n\nexport interface UseWidgetCatalogResult {\n /** Merged catalog (backend metadata over static), or the static registry as fallback. */\n definitions: WidgetDefinition[];\n /** Whether the catalog came from the backend (`backend`) or the bundled registry (`static`). */\n source: 'backend' | 'static';\n loading: boolean;\n error: Error | undefined;\n}\n\n/**\n * Build a WidgetDefinition from one backend catalog entry, filling presentational\n * gaps from the matching static definition.\n */\nfunction mergeBackendType(entry: BackendWidgetType): WidgetDefinition {\n // Resolve to a valid internal widget-type key, whether the backend returns a\n // canonical key (\"metric_card\") or a federation enum value (\"KPI\").\n const typeKey = resolveInternalType(entry.type);\n const staticDef = getWidgetDefinition(typeKey);\n\n const category: WidgetCategory = KNOWN_CATEGORIES.has(entry.category)\n ? (entry.category as WidgetCategory)\n : staticDef.category;\n\n return {\n type: typeKey,\n name: entry.label,\n description: entry.description,\n icon: entry.icon,\n category,\n component: null,\n defaultConfig: (entry.defaultConfig as Record<string, unknown>) ?? staticDef.defaultConfig,\n defaultSize: { width: entry.defaultSize.width, height: entry.defaultSize.height },\n minSize: { width: entry.minSize.width, height: entry.minSize.height },\n maxSize: { width: entry.maxSize.width, height: entry.maxSize.height },\n // Fields the backend WidgetTypeInfo does not model — keep the static values.\n defaultResponsive: staticDef.defaultResponsive,\n supportsDataBinding: staticDef.supportsDataBinding,\n supportsDrilldown: staticDef.supportsDrilldown,\n supportsAutoRefresh: staticDef.supportsAutoRefresh,\n tags: staticDef.tags,\n };\n}\n\nexport function useWidgetCatalog(params: UseWidgetCatalogParams = {}): UseWidgetCatalogResult {\n const { workspaceId, apiGatewayUrl, authToken, enabled = true } = params;\n\n const {\n data: backendTypes,\n isLoading: loading,\n error,\n } = useQuery<BackendWidgetType[], Error>({\n // Only workspaceId is part of the cache key; token/url are used inside queryFn\n // but should not invalidate the cache on rotation.\n queryKey: ['widgetCatalog', workspaceId],\n queryFn: async () => {\n const headers: Record<string, string> = { 'Content-Type': 'application/json' };\n if (workspaceId) headers['x-workspace-id'] = workspaceId;\n if (authToken) headers['Authorization'] = `Bearer ${authToken}`;\n\n const url = apiGatewayUrl ? `${apiGatewayUrl}/workspaces/graphql` : '/workspaces/graphql';\n\n const response = await fetch(url, {\n method: 'POST',\n headers,\n body: JSON.stringify({ query: print(GetWidgetTypesDocument) }),\n });\n\n if (!response.ok) {\n throw new Error(`Failed to fetch widget catalog: ${response.status}`);\n }\n\n const result: { data?: GetWidgetTypesQuery; errors?: { message: string }[] } = await response.json();\n\n if (result.errors?.length) {\n throw new Error(result.errors[0].message);\n }\n\n return result.data?.getWidgetTypes ?? [];\n },\n enabled: enabled && !!workspaceId,\n // The catalog is effectively static config; avoid refetching on every remount.\n staleTime: 10 * 60 * 1000,\n });\n\n useEffect(() => {\n if (error) {\n // Non-fatal: the palette falls back to the bundled registry.\n console.warn('Falling back to bundled widget registry:', error.message);\n }\n }, [error]);\n\n return useMemo<UseWidgetCatalogResult>(() => {\n if (backendTypes && backendTypes.length > 0) {\n return {\n definitions: backendTypes.map(mergeBackendType),\n source: 'backend',\n loading,\n error: error ?? undefined,\n };\n }\n return {\n definitions: getAllWidgetDefinitions(),\n source: 'static',\n loading,\n error: error ?? undefined,\n };\n }, [backendTypes, loading, error]);\n}\n\nexport default useWidgetCatalog;\n"],"mappings":";;;;;;;AAmCA,IAAM,IAAmB,IAAI,IAAY,OAAO,KAAK,EAAuB,CAAC;AAe7E,SAAS,EAAoB,GAA6B;CACxD,IAAM,IAAQ,OAAO,EAAQ,CAAC,aAAa;AAI3C,QAHI,OAAO,UAAU,eAAe,KAAK,GAAoB,EAAM,GAC1D,IAEF,EAA4B,EAAQ;;AAwB7C,SAAS,EAAiB,GAA4C;CAGpE,IAAM,IAAU,EAAoB,EAAM,KAAK,EACzC,IAAY,EAAoB,EAAQ,EAExC,IAA2B,EAAiB,IAAI,EAAM,SAAS,GAChE,EAAM,WACP,EAAU;AAEd,QAAO;EACL,MAAM;EACN,MAAM,EAAM;EACZ,aAAa,EAAM;EACnB,MAAM,EAAM;EACZ;EACA,WAAW;EACX,eAAgB,EAAM,iBAA6C,EAAU;EAC7E,aAAa;GAAE,OAAO,EAAM,YAAY;GAAO,QAAQ,EAAM,YAAY;GAAQ;EACjF,SAAS;GAAE,OAAO,EAAM,QAAQ;GAAO,QAAQ,EAAM,QAAQ;GAAQ;EACrE,SAAS;GAAE,OAAO,EAAM,QAAQ;GAAO,QAAQ,EAAM,QAAQ;GAAQ;EAErE,mBAAmB,EAAU;EAC7B,qBAAqB,EAAU;EAC/B,mBAAmB,EAAU;EAC7B,qBAAqB,EAAU;EAC/B,MAAM,EAAU;EACjB;;AAGH,SAAgB,EAAiB,IAAiC,EAAE,EAA0B;CAC5F,IAAM,EAAE,gBAAa,kBAAe,cAAW,aAAU,OAAS,GAE5D,EACJ,MAAM,GACN,WAAW,GACX,aACE,EAAqC;EAGvC,UAAU,CAAC,iBAAiB,EAAY;EACxC,SAAS,YAAY;GACnB,IAAM,IAAkC,EAAE,gBAAgB,oBAAoB;AAE9E,GADI,MAAa,EAAQ,oBAAoB,IACzC,MAAW,EAAQ,gBAAmB,UAAU;GAEpD,IAAM,IAAM,IAAgB,GAAG,EAAc,uBAAuB,uBAE9D,IAAW,MAAM,MAAM,GAAK;IAChC,QAAQ;IACR;IACA,MAAM,KAAK,UAAU,EAAE,OAAO,EAAM,EAAuB,EAAE,CAAC;IAC/D,CAAC;AAEF,OAAI,CAAC,EAAS,GACZ,OAAU,MAAM,mCAAmC,EAAS,SAAS;GAGvE,IAAM,IAAyE,MAAM,EAAS,MAAM;AAEpG,OAAI,EAAO,QAAQ,OACjB,OAAU,MAAM,EAAO,OAAO,GAAG,QAAQ;AAG3C,UAAO,EAAO,MAAM,kBAAkB,EAAE;;EAE1C,SAAS,KAAW,CAAC,CAAC;EAEtB,WAAW,MAAU;EACtB,CAAC;AASF,QAPA,QAAgB;AACd,EAAI,KAEF,QAAQ,KAAK,4CAA4C,EAAM,QAAQ;IAExE,CAAC,EAAM,CAAC,EAEJ,QACD,KAAgB,EAAa,SAAS,IACjC;EACL,aAAa,EAAa,IAAI,EAAiB;EAC/C,QAAQ;EACR;EACA,OAAO,KAAS,KAAA;EACjB,GAEI;EACL,aAAa,GAAyB;EACtC,QAAQ;EACR;EACA,OAAO,KAAS,KAAA;EACjB,EACA;EAAC;EAAc;EAAS;EAAM,CAAC"}
|