@burdenoff/microfe-bigconsole 2026.1008.11 → 2026.1008.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (140) hide show
  1. package/dist/bigconsole/BigConsoleRoutes.d.ts.map +1 -1
  2. package/dist/bigconsole/BigConsoleRoutes.js +136 -127
  3. package/dist/bigconsole/BigConsoleRoutes.js.map +1 -1
  4. package/dist/bigconsole/assistant/assistantProduct.d.ts.map +1 -1
  5. package/dist/bigconsole/assistant/assistantProduct.js +3 -1
  6. package/dist/bigconsole/assistant/assistantProduct.js.map +1 -1
  7. package/dist/bigconsole/components/builder/inspector/DataBindingSection.js +31 -31
  8. package/dist/bigconsole/components/dashboard/CreateDashboardDialog.js +44 -44
  9. package/dist/bigconsole/components/dashboard/CreateDashboardDialog.js.map +1 -1
  10. package/dist/bigconsole/components/dashboard/DashboardCanvas.js +36 -36
  11. package/dist/bigconsole/components/dashboard/DashboardCanvas.js.map +1 -1
  12. package/dist/bigconsole/components/dashboard/DashboardToolbar.js +59 -59
  13. package/dist/bigconsole/components/dashboard/DrilldownBreadcrumb.js +15 -15
  14. package/dist/bigconsole/components/dashboard/GlobalFiltersBar/FilterChip.js +30 -30
  15. package/dist/bigconsole/components/dashboard/GlobalFiltersBar/FilterEditor.js +41 -41
  16. package/dist/bigconsole/components/dashboard/GlobalFiltersBar/FilterPresetSelector.js +34 -34
  17. package/dist/bigconsole/components/dashboard/GlobalFiltersBar/GlobalFiltersBar.js +34 -34
  18. package/dist/bigconsole/components/dashboard/ImportDashboardDialog.js +110 -110
  19. package/dist/bigconsole/components/dashboard/ImportDashboardDialog.js.map +1 -1
  20. package/dist/bigconsole/components/dashboard/PublishToStoreDialog.js +21 -21
  21. package/dist/bigconsole/components/dashboard/SavedViewsDropdown/SavedViewsDropdown.js +46 -46
  22. package/dist/bigconsole/components/dashboard/ShareDialog/EmbedTab.js +91 -91
  23. package/dist/bigconsole/components/dashboard/ShareDialog/EmbedTab.js.map +1 -1
  24. package/dist/bigconsole/components/dashboard/ShareDialog/ShareDialog.js +101 -101
  25. package/dist/bigconsole/components/dashboard/ShareDialog/ShareDialog.js.map +1 -1
  26. package/dist/bigconsole/components/dashboard/TemplateInstallOptions.js +31 -31
  27. package/dist/bigconsole/components/dashboard/TemplateLayoutPreview.js +15 -15
  28. package/dist/bigconsole/components/dashboard/TemplatePicker/TemplatePicker.js +1 -1
  29. package/dist/bigconsole/components/dashboard/WidgetPalette.js +46 -46
  30. package/dist/bigconsole/components/datasink/AlertExecutionHistory.js +37 -37
  31. package/dist/bigconsole/components/datasink/AlertRuleEditor.js +66 -66
  32. package/dist/bigconsole/components/datasink/CacheTTLSelector.js +35 -35
  33. package/dist/bigconsole/components/datasink/DataSinkCard.js +29 -29
  34. package/dist/bigconsole/components/datasink/DataSinkDeleteDialog.js +18 -18
  35. package/dist/bigconsole/components/datasink/DataSinkRefreshDialog.js +20 -20
  36. package/dist/bigconsole/components/datasink/ImportDataGuideDialog.js +47 -47
  37. package/dist/bigconsole/components/datasink/ImportDataSinkDialog.js +91 -91
  38. package/dist/bigconsole/components/datasink/RefreshTypeSelector.js +35 -35
  39. package/dist/bigconsole/components/parser/DataSinkSelector.js +40 -40
  40. package/dist/bigconsole/components/parser/ImportParserDialog.js +120 -120
  41. package/dist/bigconsole/components/parser/ImportParserDialog.js.map +1 -1
  42. package/dist/bigconsole/components/parser/ParserSelector.js +51 -51
  43. package/dist/bigconsole/components/pipeline/PipelineScopePicker.js +10 -10
  44. package/dist/bigconsole/components/preview/AiPreviewMiniPanel.js +27 -27
  45. package/dist/bigconsole/components/preview/AiPreviewPanel.js +30 -30
  46. package/dist/bigconsole/components/widgets/ActionConfigDialog.js +4 -4
  47. package/dist/bigconsole/components/widgets/DrilldownConfigPanel.js +93 -93
  48. package/dist/bigconsole/components/widgets/DrilldownConfigPanel.js.map +1 -1
  49. package/dist/bigconsole/components/widgets/PropertiesPanel.d.ts.map +1 -1
  50. package/dist/bigconsole/components/widgets/PropertiesPanel.js +507 -499
  51. package/dist/bigconsole/components/widgets/PropertiesPanel.js.map +1 -1
  52. package/dist/bigconsole/components/widgets/calendar/CalendarWidget.js +4 -4
  53. package/dist/bigconsole/components/widgets/chart/ChartConfig.js +48 -48
  54. package/dist/bigconsole/components/widgets/comments/WidgetComments.js +46 -46
  55. package/dist/bigconsole/components/widgets/event-logs/EventLogViewer.js +61 -61
  56. package/dist/bigconsole/components/widgets/form/FormWidget.js +36 -36
  57. package/dist/bigconsole/components/widgets/gauge/GaugeConfig.js +42 -42
  58. package/dist/bigconsole/components/widgets/heatmap/HeatmapConfig.js +25 -25
  59. package/dist/bigconsole/components/widgets/kanban/KanbanWidget.js +4 -4
  60. package/dist/bigconsole/components/widgets/list/ListConfig.js +30 -30
  61. package/dist/bigconsole/components/widgets/metric-card/MetricCardConfig.js +38 -38
  62. package/dist/bigconsole/components/widgets/metric-card/SparklineChart.js +9 -9
  63. package/dist/bigconsole/components/widgets/metric-card/TrendIndicator.js +9 -9
  64. package/dist/bigconsole/components/widgets/pivot-table/PivotTableWidget.js +49 -49
  65. package/dist/bigconsole/components/widgets/progress/ProgressConfig.js +39 -39
  66. package/dist/bigconsole/components/widgets/table/TableConfig.js +73 -73
  67. package/dist/bigconsole/components/widgets/webhook-config/WebhookConfigPanel.js +64 -64
  68. package/dist/bigconsole/components/workflow/WorkflowOpenGuard.js +15 -15
  69. package/dist/bigconsole/components/workflow/WorkflowSinkLinkForm.js +15 -15
  70. package/dist/bigconsole/customWidget/CustomWidgetBuilderSheet.js +9 -9
  71. package/dist/bigconsole/customWidget/CustomWidgetProposalPanel.js +67 -67
  72. package/dist/bigconsole/customWidget/CustomWidgetProposalPanel.js.map +1 -1
  73. package/dist/bigconsole/hooks/useDashboardLayoutBaseline.d.ts +15 -0
  74. package/dist/bigconsole/hooks/useDashboardLayoutBaseline.d.ts.map +1 -0
  75. package/dist/bigconsole/hooks/useDashboardLayoutBaseline.js +34 -0
  76. package/dist/bigconsole/hooks/useDashboardLayoutBaseline.js.map +1 -0
  77. package/dist/bigconsole/hooks/useDrilldown.js +3 -3
  78. package/dist/bigconsole/hooks/useGlobalFilters.js +3 -3
  79. package/dist/bigconsole/pages/AdminPage.js +130 -130
  80. package/dist/bigconsole/pages/DashboardBuilderPage.d.ts.map +1 -1
  81. package/dist/bigconsole/pages/DashboardBuilderPage.js +72 -60
  82. package/dist/bigconsole/pages/DashboardBuilderPage.js.map +1 -1
  83. package/dist/bigconsole/pages/DashboardViewPage.js +1 -1
  84. package/dist/bigconsole/pages/DataSinkAlertsPage.d.ts.map +1 -1
  85. package/dist/bigconsole/pages/DataSinkAlertsPage.js +30 -23
  86. package/dist/bigconsole/pages/DataSinkAlertsPage.js.map +1 -1
  87. package/dist/bigconsole/pages/DataSinkBuilderPage.d.ts.map +1 -1
  88. package/dist/bigconsole/pages/DataSinkBuilderPage.js +273 -264
  89. package/dist/bigconsole/pages/DataSinkBuilderPage.js.map +1 -1
  90. package/dist/bigconsole/pages/DataSinkViewPage.js +1 -1
  91. package/dist/bigconsole/pages/DataSinksPage.js +1 -1
  92. package/dist/bigconsole/pages/DataSourcesPage.js +5 -5
  93. package/dist/bigconsole/pages/InsightsPage.d.ts.map +1 -1
  94. package/dist/bigconsole/pages/InsightsPage.js +279 -265
  95. package/dist/bigconsole/pages/InsightsPage.js.map +1 -1
  96. package/dist/bigconsole/pages/OverviewPage.js +47 -47
  97. package/dist/bigconsole/pages/OverviewPage.js.map +1 -1
  98. package/dist/bigconsole/pages/ParserBuilderPage.d.ts.map +1 -1
  99. package/dist/bigconsole/pages/ParserBuilderPage.js +229 -213
  100. package/dist/bigconsole/pages/ParserBuilderPage.js.map +1 -1
  101. package/dist/bigconsole/pages/ParserViewPage.js +97 -97
  102. package/dist/bigconsole/pages/PipelineBuilderPage.d.ts.map +1 -1
  103. package/dist/bigconsole/pages/PipelineBuilderPage.js +256 -214
  104. package/dist/bigconsole/pages/PipelineBuilderPage.js.map +1 -1
  105. package/dist/bigconsole/pages/PipelineViewPage.js +146 -146
  106. package/dist/bigconsole/pages/PipelinesPage.js +88 -88
  107. package/dist/bigconsole/pages/PipelinesPage.js.map +1 -1
  108. package/dist/bigconsole/pages/SettingsPage.d.ts.map +1 -1
  109. package/dist/bigconsole/pages/SettingsPage.js +179 -173
  110. package/dist/bigconsole/pages/SettingsPage.js.map +1 -1
  111. package/dist/bigconsole/pages/WidgetDemoPage.js +42 -42
  112. package/dist/bigconsole/pages/WorkflowViewPage.js +1 -1
  113. package/dist/bigconsole/pages/WorkflowsPage.js +141 -141
  114. package/dist/bigconsole/pages/WorkflowsPage.js.map +1 -1
  115. package/dist/bigconsole/providers/BigConsoleQuotaProvider.js +12 -12
  116. package/dist/bigconsole/renderers/adapters/AdaptiveCardRenderer.js +34 -34
  117. package/dist/bigconsole/renderers/adapters/BlockKitRenderer.js +79 -79
  118. package/dist/bigconsole/renderers/adapters/CustomRenderer.js +46 -46
  119. package/dist/bigconsole/store/widgetStore.d.ts +12 -0
  120. package/dist/bigconsole/store/widgetStore.d.ts.map +1 -1
  121. package/dist/bigconsole/store/widgetStore.js +3 -1
  122. package/dist/bigconsole/store/widgetStore.js.map +1 -1
  123. package/dist/bigconsole/utils/formDirty.d.ts +83 -0
  124. package/dist/bigconsole/utils/formDirty.d.ts.map +1 -0
  125. package/dist/bigconsole/utils/formDirty.js +23 -0
  126. package/dist/bigconsole/utils/formDirty.js.map +1 -0
  127. package/dist/bigconsole/utils/insightsDraft.d.ts +30 -0
  128. package/dist/bigconsole/utils/insightsDraft.d.ts.map +1 -0
  129. package/dist/bigconsole/utils/insightsDraft.js +10 -0
  130. package/dist/bigconsole/utils/insightsDraft.js.map +1 -0
  131. package/dist/bigconsole/utils/layoutBaseline.d.ts +131 -0
  132. package/dist/bigconsole/utils/layoutBaseline.d.ts.map +1 -0
  133. package/dist/bigconsole/utils/layoutBaseline.js +98 -0
  134. package/dist/bigconsole/utils/layoutBaseline.js.map +1 -0
  135. package/dist/bigconsole/utils/widgetFormDirty.d.ts +17 -0
  136. package/dist/bigconsole/utils/widgetFormDirty.d.ts.map +1 -0
  137. package/dist/bigconsole/utils/widgetFormDirty.js +15 -0
  138. package/dist/bigconsole/utils/widgetFormDirty.js.map +1 -0
  139. package/dist/translations/en.d.ts.map +1 -1
  140. package/package.json +1 -1
@@ -0,0 +1,131 @@
1
+ /**
2
+ * Dashboard layout baseline (BOFF-8060, N3/N4: the dashboard leave guard).
3
+ *
4
+ * The dashboard builder keeps moved and resized widgets only in the widget store
5
+ * until the toolbar Save runs (`DashboardBuilderPage.handleSave`, step 2). To tell
6
+ * the assistant "this editor holds unsaved work" the builder needs one honest
7
+ * boolean, and the store has none: `widgetStore.dirtyWidgetIds` is never marked and
8
+ * `dashboardStore.hasUnsavedChanges` is never cleared. This module is that boolean,
9
+ * as plain functions with no React, so it can be tested without a DOM.
10
+ *
11
+ * ★★ "A layout event happened" is NOT a dirty signal. Positions reach the store on
12
+ * load (`setWidgets`), when a widget is created or deleted, and when a save writes
13
+ * its own positions back, none of which is the person's work. Only a PERSON'S
14
+ * placement is. So the baseline FLOATS (it is re-taken on every observation)
15
+ * until the first placement by a person, and from then on it is FROZEN: it holds
16
+ * the last layout the server is known to have, and "dirty" means the current
17
+ * layout differs from it BY VALUE:
18
+ *
19
+ * load / refetch / add / delete / save write-back -> baseline follows, clean
20
+ * first drag, resize, or typed placement -> baseline freezes
21
+ * a drag that moves and moves back -> equal again, clean
22
+ * a successful save -> baseline = what was saved
23
+ * a failed save -> nothing happens, still dirty
24
+ *
25
+ * ★★ The "placement by a person" signal is `layoutEditRevision` on the widget
26
+ * store, a counter bumped by `updateWidgetPosition` and by nothing else. It is the
27
+ * ONE writer shared by the canvas (drag stop, resize stop) and the inspector's
28
+ * "Position & size" fields, so a placement typed into the inspector, which never
29
+ * touches the grid, freezes the baseline too. A signal taken from the grid alone
30
+ * would let a floating baseline silently absorb it.
31
+ *
32
+ * Every function here is pure. `useDashboardLayoutBaseline` is the React shell.
33
+ */
34
+ /** One widget's grid cell, in grid units (columns / rows). */
35
+ export interface LayoutRect {
36
+ readonly x: number;
37
+ readonly y: number;
38
+ readonly w: number;
39
+ readonly h: number;
40
+ }
41
+ export interface LayoutItem extends LayoutRect {
42
+ readonly id: string;
43
+ }
44
+ /**
45
+ * Widget id -> cell, keys in sorted order. A `Map` (not a plain object) so an
46
+ * id such as `"1"` or `"__proto__"` is only ever a key.
47
+ */
48
+ export type NormalisedLayout = ReadonlyMap<string, LayoutRect>;
49
+ interface PositionLike {
50
+ readonly x?: number | null;
51
+ readonly y?: number | null;
52
+ readonly width?: number | null;
53
+ readonly height?: number | null;
54
+ }
55
+ /**
56
+ * What a widget must carry for its cell to be read. Structural, so the store's
57
+ * `Widget` satisfies it and a test can pass a plain object.
58
+ */
59
+ export interface LayoutSourceWidget {
60
+ readonly id: string;
61
+ readonly position?: PositionLike | null;
62
+ readonly positionX?: number | null;
63
+ readonly positionY?: number | null;
64
+ readonly positionWidth?: number | null;
65
+ readonly positionHeight?: number | null;
66
+ }
67
+ /**
68
+ * The cell a widget with no stored size falls back to. These mirror
69
+ * `DashboardGrid.widgetToLayout` exactly, so the baseline reads a widget the same
70
+ * way the grid draws it.
71
+ */
72
+ export declare const DEFAULT_LAYOUT_CELL: LayoutRect;
73
+ /**
74
+ * Items -> a sorted `id -> x,y,w,h` map. Order of the input does not matter, a
75
+ * repeated id keeps the last one, and a non-finite number becomes 0 so a stray
76
+ * `NaN` (which is never equal to itself) cannot make a layout permanently dirty.
77
+ */
78
+ export declare function normaliseLayout(items: Iterable<LayoutItem>): NormalisedLayout;
79
+ /** The widget store's widgets -> a normalised layout (every widget in the store, which is what Save sends). */
80
+ export declare function layoutFromWidgets(widgets: Iterable<LayoutSourceWidget>): NormalisedLayout;
81
+ /** The `{ id, position }` list `batchUpdatePositions` sends -> layout items (exactly what reached the server). */
82
+ export declare function layoutItemsFromPositionUpdates(updates: ReadonlyArray<{
83
+ readonly id: string;
84
+ readonly position: PositionLike;
85
+ }>): LayoutItem[];
86
+ /** Same widgets in the same cells (by value; key order and object identity are irrelevant). */
87
+ export declare function layoutEquals(a: NormalisedLayout, b: NormalisedLayout): boolean;
88
+ /**
89
+ * Does `current` differ from `baseline`? Different cells, a widget present on only
90
+ * one side, or both, all count. With no baseline there is nothing to differ from,
91
+ * so the answer is no: this never claims unsaved work it cannot point to.
92
+ */
93
+ export declare function layoutDirty(current: NormalisedLayout, baseline: NormalisedLayout | null): boolean;
94
+ export interface LayoutBaselineState {
95
+ /** The layout the server is known to hold, or the last loaded one while floating. `null` until first observed. */
96
+ readonly baseline: NormalisedLayout | null;
97
+ /** True once a person has placed something since the baseline was taken. Frozen baselines do not follow the store. */
98
+ readonly frozen: boolean;
99
+ /** The last `layoutEditRevision` seen, to notice the next placement. `null` until first observed. */
100
+ readonly seenRevision: number | null;
101
+ }
102
+ export declare const INITIAL_LAYOUT_BASELINE: LayoutBaselineState;
103
+ export type LayoutBaselineAction =
104
+ /** The store changed (or the page mounted): here is the layout and the placement counter now. */
105
+ {
106
+ readonly type: 'observe';
107
+ readonly layout: NormalisedLayout;
108
+ readonly editRevision: number;
109
+ }
110
+ /**
111
+ * The positions reached the server. `layout` is exactly what was sent;
112
+ * `editRevision` is the counter read BEFORE the request started, so a
113
+ * placement made while it was in flight is not mistaken for saved.
114
+ */
115
+ | {
116
+ readonly type: 'saved';
117
+ readonly layout: NormalisedLayout;
118
+ readonly editRevision: number;
119
+ }
120
+ /** A different dashboard: forget everything. */
121
+ | {
122
+ readonly type: 'reset';
123
+ };
124
+ export declare function reduceLayoutBaseline(state: LayoutBaselineState, action: LayoutBaselineAction): LayoutBaselineState;
125
+ /**
126
+ * The one boolean the builder reports. A floating baseline is never dirty by
127
+ * definition: it follows the store, so whatever differs is not the person's work.
128
+ */
129
+ export declare function isLayoutBaselineDirty(state: LayoutBaselineState, current: NormalisedLayout): boolean;
130
+ export {};
131
+ //# sourceMappingURL=layoutBaseline.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"layoutBaseline.d.ts","sourceRoot":"","sources":["../../../src/bigconsole/utils/layoutBaseline.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,98 @@
1
+ //#region src/bigconsole/utils/layoutBaseline.ts
2
+ var e = {
3
+ x: 0,
4
+ y: 0,
5
+ w: 4,
6
+ h: 4
7
+ }, t = (e) => typeof e == "number" && Number.isFinite(e) ? e : void 0, n = (e) => Number.isFinite(e) ? e : 0;
8
+ function r(e, n, r) {
9
+ return t(e) ?? t(n) ?? r;
10
+ }
11
+ var i = (e, t) => e < t ? -1 : +(e > t);
12
+ function a(e) {
13
+ let t = /* @__PURE__ */ new Map();
14
+ for (let r of e) t.set(r.id, {
15
+ x: n(r.x),
16
+ y: n(r.y),
17
+ w: n(r.w),
18
+ h: n(r.h)
19
+ });
20
+ return new Map([...t.entries()].sort(([e], [t]) => i(e, t)));
21
+ }
22
+ function o(t) {
23
+ let n = [];
24
+ for (let i of t) n.push({
25
+ id: i.id,
26
+ x: r(i.position?.x, i.positionX, e.x),
27
+ y: r(i.position?.y, i.positionY, e.y),
28
+ w: r(i.position?.width, i.positionWidth, e.w),
29
+ h: r(i.position?.height, i.positionHeight, e.h)
30
+ });
31
+ return a(n);
32
+ }
33
+ function s(t) {
34
+ return t.map((t) => ({
35
+ id: t.id,
36
+ x: r(t.position.x, void 0, e.x),
37
+ y: r(t.position.y, void 0, e.y),
38
+ w: r(t.position.width, void 0, e.w),
39
+ h: r(t.position.height, void 0, e.h)
40
+ }));
41
+ }
42
+ function c(e, t) {
43
+ if (e.size !== t.size) return !1;
44
+ for (let [n, r] of e) {
45
+ let e = t.get(n);
46
+ if (!e || r.x !== e.x || r.y !== e.y || r.w !== e.w || r.h !== e.h) return !1;
47
+ }
48
+ return !0;
49
+ }
50
+ function l(e, t) {
51
+ return t !== null && !c(e, t);
52
+ }
53
+ var u = {
54
+ baseline: null,
55
+ frozen: !1,
56
+ seenRevision: null
57
+ };
58
+ function d(e, t) {
59
+ switch (t.type) {
60
+ case "reset": return u;
61
+ case "observe": {
62
+ if (e.baseline === null) return {
63
+ baseline: t.layout,
64
+ frozen: !1,
65
+ seenRevision: t.editRevision
66
+ };
67
+ let n = t.editRevision !== e.seenRevision;
68
+ return e.frozen ? n ? {
69
+ ...e,
70
+ seenRevision: t.editRevision
71
+ } : e : n ? {
72
+ baseline: e.baseline,
73
+ frozen: !0,
74
+ seenRevision: t.editRevision
75
+ } : c(t.layout, e.baseline) ? e : {
76
+ baseline: t.layout,
77
+ frozen: !1,
78
+ seenRevision: t.editRevision
79
+ };
80
+ }
81
+ case "saved": return e.baseline === null ? {
82
+ baseline: t.layout,
83
+ frozen: !1,
84
+ seenRevision: t.editRevision
85
+ } : {
86
+ baseline: t.layout,
87
+ frozen: e.seenRevision !== null && e.seenRevision > t.editRevision,
88
+ seenRevision: e.seenRevision
89
+ };
90
+ }
91
+ }
92
+ function f(e, t) {
93
+ return e.frozen && l(t, e.baseline);
94
+ }
95
+ //#endregion
96
+ export { u as INITIAL_LAYOUT_BASELINE, f as isLayoutBaselineDirty, o as layoutFromWidgets, s as layoutItemsFromPositionUpdates, a as normaliseLayout, d as reduceLayoutBaseline };
97
+
98
+ //# sourceMappingURL=layoutBaseline.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"layoutBaseline.js","names":[],"sources":["../../../src/bigconsole/utils/layoutBaseline.ts"],"sourcesContent":["/**\n * Dashboard layout baseline (BOFF-8060, N3/N4: the dashboard leave guard).\n *\n * The dashboard builder keeps moved and resized widgets only in the widget store\n * until the toolbar Save runs (`DashboardBuilderPage.handleSave`, step 2). To tell\n * the assistant \"this editor holds unsaved work\" the builder needs one honest\n * boolean, and the store has none: `widgetStore.dirtyWidgetIds` is never marked and\n * `dashboardStore.hasUnsavedChanges` is never cleared. This module is that boolean,\n * as plain functions with no React, so it can be tested without a DOM.\n *\n * ★★ \"A layout event happened\" is NOT a dirty signal. Positions reach the store on\n * load (`setWidgets`), when a widget is created or deleted, and when a save writes\n * its own positions back, none of which is the person's work. Only a PERSON'S\n * placement is. So the baseline FLOATS (it is re-taken on every observation)\n * until the first placement by a person, and from then on it is FROZEN: it holds\n * the last layout the server is known to have, and \"dirty\" means the current\n * layout differs from it BY VALUE:\n *\n * load / refetch / add / delete / save write-back -> baseline follows, clean\n * first drag, resize, or typed placement -> baseline freezes\n * a drag that moves and moves back -> equal again, clean\n * a successful save -> baseline = what was saved\n * a failed save -> nothing happens, still dirty\n *\n * ★★ The \"placement by a person\" signal is `layoutEditRevision` on the widget\n * store, a counter bumped by `updateWidgetPosition` and by nothing else. It is the\n * ONE writer shared by the canvas (drag stop, resize stop) and the inspector's\n * \"Position & size\" fields, so a placement typed into the inspector, which never\n * touches the grid, freezes the baseline too. A signal taken from the grid alone\n * would let a floating baseline silently absorb it.\n *\n * Every function here is pure. `useDashboardLayoutBaseline` is the React shell.\n */\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/** One widget's grid cell, in grid units (columns / rows). */\nexport interface LayoutRect {\n readonly x: number;\n readonly y: number;\n readonly w: number;\n readonly h: number;\n}\n\nexport interface LayoutItem extends LayoutRect {\n readonly id: string;\n}\n\n/**\n * Widget id -> cell, keys in sorted order. A `Map` (not a plain object) so an\n * id such as `\"1\"` or `\"__proto__\"` is only ever a key.\n */\nexport type NormalisedLayout = ReadonlyMap<string, LayoutRect>;\n\ninterface PositionLike {\n readonly x?: number | null;\n readonly y?: number | null;\n readonly width?: number | null;\n readonly height?: number | null;\n}\n\n/**\n * What a widget must carry for its cell to be read. Structural, so the store's\n * `Widget` satisfies it and a test can pass a plain object.\n */\nexport interface LayoutSourceWidget {\n readonly id: string;\n readonly position?: PositionLike | null;\n readonly positionX?: number | null;\n readonly positionY?: number | null;\n readonly positionWidth?: number | null;\n readonly positionHeight?: number | null;\n}\n\n// ============================================================================\n// Normalising and comparing\n// ============================================================================\n\n/**\n * The cell a widget with no stored size falls back to. These mirror\n * `DashboardGrid.widgetToLayout` exactly, so the baseline reads a widget the same\n * way the grid draws it.\n */\nexport const DEFAULT_LAYOUT_CELL: LayoutRect = { x: 0, y: 0, w: 4, h: 4 };\n\nconst finiteOrUndefined = (value: number | null | undefined): number | undefined =>\n typeof value === 'number' && Number.isFinite(value) ? value : undefined;\n\nconst finiteOrZero = (value: number): number => (Number.isFinite(value) ? value : 0);\n\n/** `position` is canonical, the flat `positionX|Y|Width|Height` mirrors are the fallback. */\nfunction pick(primary: number | null | undefined, mirror: number | null | undefined, fallback: number): number {\n return finiteOrUndefined(primary) ?? finiteOrUndefined(mirror) ?? fallback;\n}\n\nconst compareIds = (a: string, b: string): number => (a < b ? -1 : a > b ? 1 : 0);\n\n/**\n * Items -> a sorted `id -> x,y,w,h` map. Order of the input does not matter, a\n * repeated id keeps the last one, and a non-finite number becomes 0 so a stray\n * `NaN` (which is never equal to itself) cannot make a layout permanently dirty.\n */\nexport function normaliseLayout(items: Iterable<LayoutItem>): NormalisedLayout {\n const byId = new Map<string, LayoutRect>();\n for (const item of items) {\n byId.set(item.id, {\n x: finiteOrZero(item.x),\n y: finiteOrZero(item.y),\n w: finiteOrZero(item.w),\n h: finiteOrZero(item.h),\n });\n }\n return new Map([...byId.entries()].sort(([a], [b]) => compareIds(a, b)));\n}\n\n/** The widget store's widgets -> a normalised layout (every widget in the store, which is what Save sends). */\nexport function layoutFromWidgets(widgets: Iterable<LayoutSourceWidget>): NormalisedLayout {\n const items: LayoutItem[] = [];\n for (const widget of widgets) {\n items.push({\n id: widget.id,\n x: pick(widget.position?.x, widget.positionX, DEFAULT_LAYOUT_CELL.x),\n y: pick(widget.position?.y, widget.positionY, DEFAULT_LAYOUT_CELL.y),\n w: pick(widget.position?.width, widget.positionWidth, DEFAULT_LAYOUT_CELL.w),\n h: pick(widget.position?.height, widget.positionHeight, DEFAULT_LAYOUT_CELL.h),\n });\n }\n return normaliseLayout(items);\n}\n\n/** The `{ id, position }` list `batchUpdatePositions` sends -> layout items (exactly what reached the server). */\nexport function layoutItemsFromPositionUpdates(\n updates: ReadonlyArray<{ readonly id: string; readonly position: PositionLike }>\n): LayoutItem[] {\n return updates.map((update) => ({\n id: update.id,\n x: pick(update.position.x, undefined, DEFAULT_LAYOUT_CELL.x),\n y: pick(update.position.y, undefined, DEFAULT_LAYOUT_CELL.y),\n w: pick(update.position.width, undefined, DEFAULT_LAYOUT_CELL.w),\n h: pick(update.position.height, undefined, DEFAULT_LAYOUT_CELL.h),\n }));\n}\n\n/** Same widgets in the same cells (by value; key order and object identity are irrelevant). */\nexport function layoutEquals(a: NormalisedLayout, b: NormalisedLayout): boolean {\n if (a.size !== b.size) return false;\n for (const [id, left] of a) {\n const right = b.get(id);\n if (!right) return false;\n if (left.x !== right.x || left.y !== right.y || left.w !== right.w || left.h !== right.h) return false;\n }\n return true;\n}\n\n/**\n * Does `current` differ from `baseline`? Different cells, a widget present on only\n * one side, or both, all count. With no baseline there is nothing to differ from,\n * so the answer is no: this never claims unsaved work it cannot point to.\n */\nexport function layoutDirty(current: NormalisedLayout, baseline: NormalisedLayout | null): boolean {\n return baseline !== null && !layoutEquals(current, baseline);\n}\n\n// ============================================================================\n// The float-then-freeze state machine\n// ============================================================================\n\nexport interface LayoutBaselineState {\n /** The layout the server is known to hold, or the last loaded one while floating. `null` until first observed. */\n readonly baseline: NormalisedLayout | null;\n /** True once a person has placed something since the baseline was taken. Frozen baselines do not follow the store. */\n readonly frozen: boolean;\n /** The last `layoutEditRevision` seen, to notice the next placement. `null` until first observed. */\n readonly seenRevision: number | null;\n}\n\nexport const INITIAL_LAYOUT_BASELINE: LayoutBaselineState = {\n baseline: null,\n frozen: false,\n seenRevision: null,\n};\n\nexport type LayoutBaselineAction =\n /** The store changed (or the page mounted): here is the layout and the placement counter now. */\n | { readonly type: 'observe'; readonly layout: NormalisedLayout; readonly editRevision: number }\n /**\n * The positions reached the server. `layout` is exactly what was sent;\n * `editRevision` is the counter read BEFORE the request started, so a\n * placement made while it was in flight is not mistaken for saved.\n */\n | { readonly type: 'saved'; readonly layout: NormalisedLayout; readonly editRevision: number }\n /** A different dashboard: forget everything. */\n | { readonly type: 'reset' };\n\nexport function reduceLayoutBaseline(state: LayoutBaselineState, action: LayoutBaselineAction): LayoutBaselineState {\n switch (action.type) {\n case 'reset':\n return INITIAL_LAYOUT_BASELINE;\n\n case 'observe': {\n if (state.baseline === null) {\n return { baseline: action.layout, frozen: false, seenRevision: action.editRevision };\n }\n const placed = action.editRevision !== state.seenRevision;\n if (state.frozen) {\n // Already holding the person's work: only keep count of the placements.\n return placed ? { ...state, seenRevision: action.editRevision } : state;\n }\n if (placed) {\n // Freeze with the baseline that was current BEFORE this change. The\n // placement and the layout it produced arrive together, so the baseline\n // must not be re-taken from them.\n return { baseline: state.baseline, frozen: true, seenRevision: action.editRevision };\n }\n // Floating: follow the store (load, refetch, add, delete, save write-back).\n if (layoutEquals(action.layout, state.baseline)) return state;\n return { baseline: action.layout, frozen: false, seenRevision: action.editRevision };\n }\n\n case 'saved': {\n if (state.baseline === null) {\n return { baseline: action.layout, frozen: false, seenRevision: action.editRevision };\n }\n // Frozen again only if a placement was seen AFTER the request began. A\n // placement not seen yet (the observation lags the store by one effect)\n // will freeze on its own next `observe`, against this baseline.\n return {\n baseline: action.layout,\n frozen: state.seenRevision !== null && state.seenRevision > action.editRevision,\n seenRevision: state.seenRevision,\n };\n }\n }\n}\n\n/**\n * The one boolean the builder reports. A floating baseline is never dirty by\n * definition: it follows the store, so whatever differs is not the person's work.\n */\nexport function isLayoutBaselineDirty(state: LayoutBaselineState, current: NormalisedLayout): boolean {\n return state.frozen && layoutDirty(current, state.baseline);\n}\n"],"mappings":";AAqFA,IAAa,IAAkC;CAAE,GAAG;CAAG,GAAG;CAAG,GAAG;CAAG,GAAG;CAAG,EAEnE,KAAqB,MACzB,OAAO,KAAU,YAAY,OAAO,SAAS,EAAM,GAAG,IAAQ,KAAA,GAE1D,KAAgB,MAA2B,OAAO,SAAS,EAAM,GAAG,IAAQ;AAGlF,SAAS,EAAK,GAAoC,GAAmC,GAA0B;AAC7G,QAAO,EAAkB,EAAQ,IAAI,EAAkB,EAAO,IAAI;;AAGpE,IAAM,KAAc,GAAW,MAAuB,IAAI,IAAI,KAAK,MAAI;AAOvE,SAAgB,EAAgB,GAA+C;CAC7E,IAAM,oBAAO,IAAI,KAAyB;AAC1C,MAAK,IAAM,KAAQ,EACjB,GAAK,IAAI,EAAK,IAAI;EAChB,GAAG,EAAa,EAAK,EAAE;EACvB,GAAG,EAAa,EAAK,EAAE;EACvB,GAAG,EAAa,EAAK,EAAE;EACvB,GAAG,EAAa,EAAK,EAAE;EACxB,CAAC;AAEJ,QAAO,IAAI,IAAI,CAAC,GAAG,EAAK,SAAS,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,EAAW,GAAG,EAAE,CAAC,CAAC;;AAI1E,SAAgB,EAAkB,GAAyD;CACzF,IAAM,IAAsB,EAAE;AAC9B,MAAK,IAAM,KAAU,EACnB,GAAM,KAAK;EACT,IAAI,EAAO;EACX,GAAG,EAAK,EAAO,UAAU,GAAG,EAAO,WAAW,EAAoB,EAAE;EACpE,GAAG,EAAK,EAAO,UAAU,GAAG,EAAO,WAAW,EAAoB,EAAE;EACpE,GAAG,EAAK,EAAO,UAAU,OAAO,EAAO,eAAe,EAAoB,EAAE;EAC5E,GAAG,EAAK,EAAO,UAAU,QAAQ,EAAO,gBAAgB,EAAoB,EAAE;EAC/E,CAAC;AAEJ,QAAO,EAAgB,EAAM;;AAI/B,SAAgB,EACd,GACc;AACd,QAAO,EAAQ,KAAK,OAAY;EAC9B,IAAI,EAAO;EACX,GAAG,EAAK,EAAO,SAAS,GAAG,KAAA,GAAW,EAAoB,EAAE;EAC5D,GAAG,EAAK,EAAO,SAAS,GAAG,KAAA,GAAW,EAAoB,EAAE;EAC5D,GAAG,EAAK,EAAO,SAAS,OAAO,KAAA,GAAW,EAAoB,EAAE;EAChE,GAAG,EAAK,EAAO,SAAS,QAAQ,KAAA,GAAW,EAAoB,EAAE;EAClE,EAAE;;AAIL,SAAgB,EAAa,GAAqB,GAA8B;AAC9E,KAAI,EAAE,SAAS,EAAE,KAAM,QAAO;AAC9B,MAAK,IAAM,CAAC,GAAI,MAAS,GAAG;EAC1B,IAAM,IAAQ,EAAE,IAAI,EAAG;AAEvB,MADI,CAAC,KACD,EAAK,MAAM,EAAM,KAAK,EAAK,MAAM,EAAM,KAAK,EAAK,MAAM,EAAM,KAAK,EAAK,MAAM,EAAM,EAAG,QAAO;;AAEnG,QAAO;;AAQT,SAAgB,EAAY,GAA2B,GAA4C;AACjG,QAAO,MAAa,QAAQ,CAAC,EAAa,GAAS,EAAS;;AAgB9D,IAAa,IAA+C;CAC1D,UAAU;CACV,QAAQ;CACR,cAAc;CACf;AAcD,SAAgB,EAAqB,GAA4B,GAAmD;AAClH,SAAQ,EAAO,MAAf;EACE,KAAK,QACH,QAAO;EAET,KAAK,WAAW;AACd,OAAI,EAAM,aAAa,KACrB,QAAO;IAAE,UAAU,EAAO;IAAQ,QAAQ;IAAO,cAAc,EAAO;IAAc;GAEtF,IAAM,IAAS,EAAO,iBAAiB,EAAM;AAa7C,UAZI,EAAM,SAED,IAAS;IAAE,GAAG;IAAO,cAAc,EAAO;IAAc,GAAG,IAEhE,IAIK;IAAE,UAAU,EAAM;IAAU,QAAQ;IAAM,cAAc,EAAO;IAAc,GAGlF,EAAa,EAAO,QAAQ,EAAM,SAAS,GAAS,IACjD;IAAE,UAAU,EAAO;IAAQ,QAAQ;IAAO,cAAc,EAAO;IAAc;;EAGtF,KAAK,QAOH,QANI,EAAM,aAAa,OACd;GAAE,UAAU,EAAO;GAAQ,QAAQ;GAAO,cAAc,EAAO;GAAc,GAK/E;GACL,UAAU,EAAO;GACjB,QAAQ,EAAM,iBAAiB,QAAQ,EAAM,eAAe,EAAO;GACnE,cAAc,EAAM;GACrB;;;AASP,SAAgB,EAAsB,GAA4B,GAAoC;AACpG,QAAO,EAAM,UAAU,EAAY,GAAS,EAAM,SAAS"}
@@ -0,0 +1,17 @@
1
+ /** True when `form` differs by value from `baseline`. Either side missing is clean. */
2
+ export declare function isWidgetFormEdited<T>(form: T | null | undefined, baseline: T | null | undefined): boolean;
3
+ /**
4
+ * Adds an inferred DataSink binding to a form that is bound to `parserId` and has none.
5
+ *
6
+ * The widget inspector infers an absent `dataSinkId` from the parser's input sink key once the
7
+ * parser resolves (AI-created widgets bind a parser without duplicating its input sink id). That
8
+ * is the panel filling in what the widget already means, not an edit by the person. It is
9
+ * applied to the form AND to the baseline with this one function, so the value compare of
10
+ * `isWidgetFormEdited` reads clean. Returns the same object when nothing applies, so a state
11
+ * updater using it does not trigger a re-render.
12
+ */
13
+ export declare function withInferredDataSink<T extends {
14
+ parserId?: string | null;
15
+ dataSinkId?: string | null;
16
+ }>(form: T | null | undefined, parserId: string, dataSinkId: string): T | null;
17
+ //# sourceMappingURL=widgetFormDirty.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"widgetFormDirty.d.ts","sourceRoot":"","sources":["../../../src/bigconsole/utils/widgetFormDirty.ts"],"names":[],"mappings":"AAsBA,uFAAuF;AACvF,wBAAgB,kBAAkB,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,GAAG,IAAI,GAAG,SAAS,EAAE,QAAQ,EAAE,CAAC,GAAG,IAAI,GAAG,SAAS,GAAG,OAAO,CAKzG;AAED;;;;;;;;;GASG;AACH,wBAAgB,oBAAoB,CAAC,CAAC,SAAS;IAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,EACrG,IAAI,EAAE,CAAC,GAAG,IAAI,GAAG,SAAS,EAC1B,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,GACjB,CAAC,GAAG,IAAI,CAIV"}
@@ -0,0 +1,15 @@
1
+ import { isDirty as e } from "./formDirty.js";
2
+ //#region src/bigconsole/utils/widgetFormDirty.ts
3
+ function t(t, n) {
4
+ return t == null || n == null ? !1 : e(t, n);
5
+ }
6
+ function n(e, t, n) {
7
+ return e == null ? null : e.parserId !== t || e.dataSinkId ? e : {
8
+ ...e,
9
+ dataSinkId: n
10
+ };
11
+ }
12
+ //#endregion
13
+ export { t as isWidgetFormEdited, n as withInferredDataSink };
14
+
15
+ //# sourceMappingURL=widgetFormDirty.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"widgetFormDirty.js","names":[],"sources":["../../../src/bigconsole/utils/widgetFormDirty.ts"],"sourcesContent":["/**\n * Widget inspector edit signal for the assistant's leave guard (BOFF-8060, N3/N4).\n *\n * The properties panel keeps a sticky boolean (`hasUnsavedChanges`) that every edit\n * handler sets and only a save, a discard or a widget switch clears. It drives the\n * panel's own prompts (the \"unsaved\" pill, the Save buttons, the re-seed bail-out)\n * and stays as it is. It is the wrong signal for the leave guard: typing a title and\n * then typing the original title back leaves it set, so the assistant would refuse a\n * navigation over a form that equals what is saved.\n *\n * The leave guard therefore asks a different question, by value: does the form the\n * person is editing differ from the baseline of the widget as it was opened (or as it\n * was last saved or discarded)? Pure functions, no React, so it is testable without a\n * DOM. Comparison is the stable JSON of `formDirty.isDirty` (sorted keys, `undefined`\n * dropped), so key order, object identity and an `undefined` that reads as missing\n * never count as an edit.\n *\n * A missing form (nothing selected) or a missing baseline (the seed has not landed)\n * is CLEAN: there is nothing the person could lose.\n */\nimport { isDirty } from './formDirty';\n\n/** True when `form` differs by value from `baseline`. Either side missing is clean. */\nexport function isWidgetFormEdited<T>(form: T | null | undefined, baseline: T | null | undefined): boolean {\n if (form === null || form === undefined || baseline === null || baseline === undefined) {\n return false;\n }\n return isDirty(form, baseline);\n}\n\n/**\n * Adds an inferred DataSink binding to a form that is bound to `parserId` and has none.\n *\n * The widget inspector infers an absent `dataSinkId` from the parser's input sink key once the\n * parser resolves (AI-created widgets bind a parser without duplicating its input sink id). That\n * is the panel filling in what the widget already means, not an edit by the person. It is\n * applied to the form AND to the baseline with this one function, so the value compare of\n * `isWidgetFormEdited` reads clean. Returns the same object when nothing applies, so a state\n * updater using it does not trigger a re-render.\n */\nexport function withInferredDataSink<T extends { parserId?: string | null; dataSinkId?: string | null }>(\n form: T | null | undefined,\n parserId: string,\n dataSinkId: string\n): T | null {\n if (form === null || form === undefined) return null;\n if (form.parserId !== parserId || form.dataSinkId) return form;\n return { ...form, dataSinkId };\n}\n"],"mappings":";;AAuBA,SAAgB,EAAsB,GAA4B,GAAyC;AAIzG,QAHI,KAAS,QAA8B,KAAa,OAC/C,KAEF,EAAQ,GAAM,EAAS;;AAahC,SAAgB,EACd,GACA,GACA,GACU;AAGV,QAFI,KAAS,OAAmC,OAC5C,EAAK,aAAa,KAAY,EAAK,aAAmB,IACnD;EAAE,GAAG;EAAM;EAAY"}
@@ -1 +1 @@
1
- {"version":3,"file":"en.d.ts","sourceRoot":"","sources":["../../src/translations/en.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,eAAO,MAAM,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAqvEjD,CAAC;AAEF,eAAe,cAAc,CAAC"}
1
+ {"version":3,"file":"en.d.ts","sourceRoot":"","sources":["../../src/translations/en.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,eAAO,MAAM,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAgwEjD,CAAC;AAEF,eAAe,cAAc,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@burdenoff/microfe-bigconsole",
3
- "version": "2026.1008.11",
3
+ "version": "2026.1008.13",
4
4
  "description": "BigConsole - AI-powered analytics and dashboard platform",
5
5
  "type": "module",
6
6
  "files": [