@burdenoff/microfe-bigconsole 2026.1004.6 → 2026.1004.8

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 (38) hide show
  1. package/dist/bigconsole/BigConsoleRoutes.d.ts.map +1 -1
  2. package/dist/bigconsole/BigConsoleRoutes.js +35 -31
  3. package/dist/bigconsole/BigConsoleRoutes.js.map +1 -1
  4. package/dist/bigconsole/components/datasink/AlertExecutionHistory.d.ts +11 -0
  5. package/dist/bigconsole/components/datasink/AlertExecutionHistory.d.ts.map +1 -0
  6. package/dist/bigconsole/components/datasink/AlertExecutionHistory.js +248 -0
  7. package/dist/bigconsole/components/datasink/AlertExecutionHistory.js.map +1 -0
  8. package/dist/bigconsole/components/datasink/AlertRuleEditor.d.ts +23 -0
  9. package/dist/bigconsole/components/datasink/AlertRuleEditor.d.ts.map +1 -0
  10. package/dist/bigconsole/components/datasink/AlertRuleEditor.js +357 -0
  11. package/dist/bigconsole/components/datasink/AlertRuleEditor.js.map +1 -0
  12. package/dist/bigconsole/components/widgets/kanban/KanbanView.d.ts.map +1 -1
  13. package/dist/bigconsole/components/widgets/kanban/KanbanView.js +1 -1
  14. package/dist/bigconsole/components/widgets/kanban/KanbanView.js.map +1 -1
  15. package/dist/bigconsole/hooks/useDataSinkAlerts.d.ts +146 -0
  16. package/dist/bigconsole/hooks/useDataSinkAlerts.d.ts.map +1 -0
  17. package/dist/bigconsole/hooks/useDataSinkAlerts.js +221 -0
  18. package/dist/bigconsole/hooks/useDataSinkAlerts.js.map +1 -0
  19. package/dist/bigconsole/pages/DataSinkAlertsPage.d.ts +2 -0
  20. package/dist/bigconsole/pages/DataSinkAlertsPage.d.ts.map +1 -0
  21. package/dist/bigconsole/pages/DataSinkAlertsPage.js +422 -0
  22. package/dist/bigconsole/pages/DataSinkAlertsPage.js.map +1 -0
  23. package/dist/bigconsole/pages/DataSinkViewPage.d.ts.map +1 -1
  24. package/dist/bigconsole/pages/DataSinkViewPage.js +235 -229
  25. package/dist/bigconsole/pages/DataSinkViewPage.js.map +1 -1
  26. package/dist/bigconsole/utils/alertRules.d.ts +40 -0
  27. package/dist/bigconsole/utils/alertRules.d.ts.map +1 -0
  28. package/dist/bigconsole/utils/alertRules.js +83 -0
  29. package/dist/bigconsole/utils/alertRules.js.map +1 -0
  30. package/dist/generated/wspace-operations.d.ts +376 -0
  31. package/dist/generated/wspace-operations.d.ts.map +1 -1
  32. package/dist/generated/wspace-operations.js +321 -200
  33. package/dist/generated/wspace-operations.js.map +1 -1
  34. package/dist/generated/wspace-types.d.ts +122 -0
  35. package/dist/generated/wspace-types.d.ts.map +1 -1
  36. package/dist/generated/wspace-types.js +7 -1
  37. package/dist/generated/wspace-types.js.map +1 -1
  38. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"BigConsoleRoutes.d.ts","sourceRoot":"","sources":["../../src/bigconsole/BigConsoleRoutes.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,mBAAmB,EAAE,MAAM,SAAS,CAAC;AAsDnD,kEAAkE;AAClE,eAAO,MAAM,eAAe,cAAwD,CAAC;AA4PrF,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,mBAAmB,+BAgF1D"}
1
+ {"version":3,"file":"BigConsoleRoutes.d.ts","sourceRoot":"","sources":["../../src/bigconsole/BigConsoleRoutes.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,mBAAmB,EAAE,MAAM,SAAS,CAAC;AAuDnD,kEAAkE;AAClE,eAAO,MAAM,eAAe,cAAwD,CAAC;AA4PrF,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,mBAAmB,+BAiF1D"}
@@ -10,21 +10,21 @@ import { useApolloClient as g } from "@apollo/client/react";
10
10
  import { jsx as _, jsxs as v } from "react/jsx-runtime";
11
11
  import { ExecutionDetailPage as y, ExecutionsListPage as b, HistoryPage as x, NodesPage as S, SettingsPage as C, TemplatesPage as w, WorkflowBuilderPage as T } from "@burdenoff/fluidgrids-fe-sdk";
12
12
  //#region src/bigconsole/BigConsoleRoutes.tsx
13
- var E = a(() => import("./pages/OverviewPage.js")), D = a(() => import("./pages/DashboardsPage.js")), O = a(() => import("./pages/DashboardViewPage.js")), k = a(() => import("./pages/DashboardBuilderPage.js")), A = a(() => import("./pages/DataSourcesPage.js")), j = a(() => import("./pages/InsightsPage.js")), M = a(() => import("./pages/SettingsPage.js")), N = a(() => import("./pages/WidgetDemoPage.js")), P = a(() => import("./pages/WorkflowsPage.js").then((e) => ({ default: e.WorkflowsPage }))), F = a(() => import("./pages/WorkflowViewPage.js").then((e) => ({ default: e.WorkflowViewPage }))), I = a(() => import("./pages/DataSinksPage.js")), L = a(() => import("./pages/DataSinkViewPage.js")), R = a(() => import("./pages/DataSinkBuilderPage.js")), z = a(() => import("./pages/DataParsersPage.js")), B = a(() => import("./pages/ParserViewPage.js")), V = a(() => import("./pages/ParserBuilderPage.js")), H = a(() => import("./pages/PipelinesPage.js")), U = a(() => import("./pages/PipelineViewPage.js")), W = a(() => import("./pages/PipelineBuilderPage.js"));
14
- function G() {
13
+ var E = a(() => import("./pages/OverviewPage.js")), D = a(() => import("./pages/DashboardsPage.js")), O = a(() => import("./pages/DashboardViewPage.js")), k = a(() => import("./pages/DashboardBuilderPage.js")), A = a(() => import("./pages/DataSourcesPage.js")), j = a(() => import("./pages/InsightsPage.js")), M = a(() => import("./pages/SettingsPage.js")), N = a(() => import("./pages/WidgetDemoPage.js")), P = a(() => import("./pages/WorkflowsPage.js").then((e) => ({ default: e.WorkflowsPage }))), F = a(() => import("./pages/WorkflowViewPage.js").then((e) => ({ default: e.WorkflowViewPage }))), I = a(() => import("./pages/DataSinksPage.js")), L = a(() => import("./pages/DataSinkViewPage.js")), R = a(() => import("./pages/DataSinkAlertsPage.js")), z = a(() => import("./pages/DataSinkBuilderPage.js")), B = a(() => import("./pages/DataParsersPage.js")), V = a(() => import("./pages/ParserViewPage.js")), H = a(() => import("./pages/ParserBuilderPage.js")), U = a(() => import("./pages/PipelinesPage.js")), W = a(() => import("./pages/PipelineViewPage.js")), G = a(() => import("./pages/PipelineBuilderPage.js"));
14
+ function K() {
15
15
  return /* @__PURE__ */ _("div", {
16
16
  className: "flex items-center justify-center min-h-[400px]",
17
17
  children: /* @__PURE__ */ _(h, { className: "h-8 w-8" })
18
18
  });
19
19
  }
20
- var K = () => `/workflows/workflow/${crypto.randomUUID()}/v1`;
21
- function q() {
20
+ var q = () => `/workflows/workflow/${crypto.randomUUID()}/v1`;
21
+ function J() {
22
22
  return /* @__PURE__ */ _(d, {
23
- to: c(() => K(), []),
23
+ to: c(() => q(), []),
24
24
  replace: !0
25
25
  });
26
26
  }
27
- var J = o(function() {
27
+ var Y = o(function() {
28
28
  let { workflowId: t } = m(), i = e(), { fetchWorkflow: a } = n({ skipFetch: !0 }), [o, c] = u(null), d = l(0);
29
29
  return s(() => {
30
30
  if (!t) {
@@ -63,8 +63,8 @@ var J = o(function() {
63
63
  className: "flex items-center justify-center min-h-[400px]",
64
64
  children: /* @__PURE__ */ _(h, { className: "h-8 w-8" })
65
65
  });
66
- }), Y = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i, X = o(function() {
67
- let { id: n, version: i } = m(), a = e(), o = g(), c = !!n && Y.test(n), [d, f] = u(null), [p, y] = u(null), [b, x] = u(0), S = l(0);
66
+ }), X = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i, Z = o(function() {
67
+ let { id: n, version: i } = m(), a = e(), o = g(), c = !!n && X.test(n), [d, f] = u(null), [p, y] = u(null), [b, x] = u(0), S = l(0);
68
68
  return s(() => {
69
69
  if (!n || !c) return;
70
70
  S.current = 0;
@@ -119,15 +119,15 @@ var J = o(function() {
119
119
  children: /* @__PURE__ */ _(h, { className: "h-8 w-8" })
120
120
  });
121
121
  });
122
- function Z(e) {
122
+ function Q(e) {
123
123
  return e.routePage === "workflow-feeds" ? /* @__PURE__ */ _(i, {
124
- fallback: /* @__PURE__ */ _(G, {}),
124
+ fallback: /* @__PURE__ */ _(K, {}),
125
125
  children: /* @__PURE__ */ _(P, {})
126
126
  }) : e.routePage === "workflow-detail" ? /* @__PURE__ */ _(i, {
127
- fallback: /* @__PURE__ */ _(G, {}),
127
+ fallback: /* @__PURE__ */ _(K, {}),
128
128
  children: /* @__PURE__ */ _(F, {})
129
129
  }) : /* @__PURE__ */ _(i, {
130
- fallback: /* @__PURE__ */ _(G, {}),
130
+ fallback: /* @__PURE__ */ _(K, {}),
131
131
  children: /* @__PURE__ */ v(p, { children: [
132
132
  /* @__PURE__ */ _(f, {
133
133
  path: "/",
@@ -167,7 +167,7 @@ function Z(e) {
167
167
  }),
168
168
  /* @__PURE__ */ _(f, {
169
169
  path: "/datasinks/new",
170
- element: /* @__PURE__ */ _(R, {})
170
+ element: /* @__PURE__ */ _(z, {})
171
171
  }),
172
172
  /* @__PURE__ */ _(f, {
173
173
  path: "/datasinks/:dataSinkId",
@@ -175,39 +175,43 @@ function Z(e) {
175
175
  }),
176
176
  /* @__PURE__ */ _(f, {
177
177
  path: "/datasinks/:dataSinkId/edit",
178
+ element: /* @__PURE__ */ _(z, {})
179
+ }),
180
+ /* @__PURE__ */ _(f, {
181
+ path: "/datasinks/:dataSinkId/alerts",
178
182
  element: /* @__PURE__ */ _(R, {})
179
183
  }),
180
184
  /* @__PURE__ */ _(f, {
181
185
  path: "/parsers",
182
- element: /* @__PURE__ */ _(z, {})
186
+ element: /* @__PURE__ */ _(B, {})
183
187
  }),
184
188
  /* @__PURE__ */ _(f, {
185
189
  path: "/parsers/new",
186
- element: /* @__PURE__ */ _(V, {})
190
+ element: /* @__PURE__ */ _(H, {})
187
191
  }),
188
192
  /* @__PURE__ */ _(f, {
189
193
  path: "/parsers/:parserId",
190
- element: /* @__PURE__ */ _(B, {})
194
+ element: /* @__PURE__ */ _(V, {})
191
195
  }),
192
196
  /* @__PURE__ */ _(f, {
193
197
  path: "/parsers/:parserId/edit",
194
- element: /* @__PURE__ */ _(V, {})
198
+ element: /* @__PURE__ */ _(H, {})
195
199
  }),
196
200
  /* @__PURE__ */ _(f, {
197
201
  path: "/dashboards/:consoleId/parsers",
198
- element: /* @__PURE__ */ _(z, {})
202
+ element: /* @__PURE__ */ _(B, {})
199
203
  }),
200
204
  /* @__PURE__ */ _(f, {
201
205
  path: "/dashboards/:consoleId/parsers/new",
202
- element: /* @__PURE__ */ _(V, {})
206
+ element: /* @__PURE__ */ _(H, {})
203
207
  }),
204
208
  /* @__PURE__ */ _(f, {
205
209
  path: "/dashboards/:consoleId/parsers/:parserId",
206
- element: /* @__PURE__ */ _(B, {})
210
+ element: /* @__PURE__ */ _(V, {})
207
211
  }),
208
212
  /* @__PURE__ */ _(f, {
209
213
  path: "/dashboards/:consoleId/parsers/:parserId/edit",
210
- element: /* @__PURE__ */ _(V, {})
214
+ element: /* @__PURE__ */ _(H, {})
211
215
  }),
212
216
  /* @__PURE__ */ _(f, {
213
217
  path: "/workflows",
@@ -227,7 +231,7 @@ function Z(e) {
227
231
  }),
228
232
  /* @__PURE__ */ _(f, {
229
233
  path: "/workflows/new",
230
- element: /* @__PURE__ */ _(q, {})
234
+ element: /* @__PURE__ */ _(J, {})
231
235
  }),
232
236
  /* @__PURE__ */ _(f, {
233
237
  path: "/workflows/builder",
@@ -235,11 +239,11 @@ function Z(e) {
235
239
  }),
236
240
  /* @__PURE__ */ _(f, {
237
241
  path: "/workflows/builder/:id/:version",
238
- element: /* @__PURE__ */ _(X, {})
242
+ element: /* @__PURE__ */ _(Z, {})
239
243
  }),
240
244
  /* @__PURE__ */ _(f, {
241
245
  path: "/workflows/workflow/:id/:version",
242
- element: /* @__PURE__ */ _(X, {})
246
+ element: /* @__PURE__ */ _(Z, {})
243
247
  }),
244
248
  /* @__PURE__ */ _(f, {
245
249
  path: "/workflows/runs",
@@ -271,11 +275,11 @@ function Z(e) {
271
275
  }),
272
276
  /* @__PURE__ */ _(f, {
273
277
  path: "/workflows/:workflowId/edit",
274
- element: /* @__PURE__ */ _(J, {})
278
+ element: /* @__PURE__ */ _(Y, {})
275
279
  }),
276
280
  /* @__PURE__ */ _(f, {
277
281
  path: "/workflow/:id/:version",
278
- element: /* @__PURE__ */ _(X, {})
282
+ element: /* @__PURE__ */ _(Z, {})
279
283
  }),
280
284
  /* @__PURE__ */ _(f, {
281
285
  path: "/list",
@@ -286,24 +290,24 @@ function Z(e) {
286
290
  }),
287
291
  /* @__PURE__ */ _(f, {
288
292
  path: "/pipelines",
289
- element: /* @__PURE__ */ _(H, {})
293
+ element: /* @__PURE__ */ _(U, {})
290
294
  }),
291
295
  /* @__PURE__ */ _(f, {
292
296
  path: "/pipelines/new",
293
- element: /* @__PURE__ */ _(W, {})
297
+ element: /* @__PURE__ */ _(G, {})
294
298
  }),
295
299
  /* @__PURE__ */ _(f, {
296
300
  path: "/pipelines/:pipelineId",
297
- element: /* @__PURE__ */ _(U, {})
301
+ element: /* @__PURE__ */ _(W, {})
298
302
  }),
299
303
  /* @__PURE__ */ _(f, {
300
304
  path: "/pipelines/:pipelineId/edit",
301
- element: /* @__PURE__ */ _(W, {})
305
+ element: /* @__PURE__ */ _(G, {})
302
306
  })
303
307
  ] })
304
308
  });
305
309
  }
306
310
  //#endregion
307
- export { Z as BigConsoleRoutes, K as newWorkflowPath };
311
+ export { Q as BigConsoleRoutes, q as newWorkflowPath };
308
312
 
309
313
  //# sourceMappingURL=BigConsoleRoutes.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"BigConsoleRoutes.js","names":[],"sources":["../../src/bigconsole/BigConsoleRoutes.tsx"],"sourcesContent":["import { lazy, Suspense, memo, useState, useMemo, useEffect, useRef } from 'react';\nimport { Route, Routes, Navigate, useParams } from 'react-router';\nimport { type BigConsoleRootProps } from './types';\nimport { Spinner } from '@burdenoff/fe-libs/ui';\nimport { useApolloClient } from '@apollo/client/react';\nimport { useAppNavigate } from './contexts';\nimport { useWorkflowOperations } from './hooks/useWorkflowOperations';\nimport { GetWorkflowDocument } from '../generated/wspace-operations';\nimport { BOOTSTRAP_RETRY_DELAY_MS } from './constants';\n\n// Import FluidGrids SDK workflow components (EXACT same as microfe-workflows)\nimport {\n WorkflowBuilderPage as SDKWorkflowBuilderPage,\n ExecutionsListPage,\n ExecutionDetailPage,\n HistoryPage,\n TemplatesPage,\n NodesPage,\n SettingsPage as WorkflowSettingsPage,\n} from '@burdenoff/fluidgrids-fe-sdk';\n\n// Lazy-loaded pages\nconst OverviewPage = lazy(() => import('./pages/OverviewPage'));\nconst DashboardsPage = lazy(() => import('./pages/DashboardsPage'));\nconst DashboardViewPage = lazy(() => import('./pages/DashboardViewPage'));\nconst DashboardBuilderPage = lazy(() => import('./pages/DashboardBuilderPage'));\nconst DataSourcesPage = lazy(() => import('./pages/DataSourcesPage'));\nconst InsightsPage = lazy(() => import('./pages/InsightsPage'));\nconst SettingsPage = lazy(() => import('./pages/SettingsPage'));\nconst WidgetDemoPage = lazy(() => import('./pages/WidgetDemoPage'));\n// BigConsole-native workflow pages (query bigconsole-svc, not workflow-svc)\n// These use named exports (no default export), so we remap via .then()\nconst WorkflowsPage = lazy(() => import('./pages/WorkflowsPage').then((m) => ({ default: m.WorkflowsPage })));\nconst WorkflowViewPage = lazy(() => import('./pages/WorkflowViewPage').then((m) => ({ default: m.WorkflowViewPage })));\n// DataSink Pages\nconst DataSinksPage = lazy(() => import('./pages/DataSinksPage'));\nconst DataSinkViewPage = lazy(() => import('./pages/DataSinkViewPage'));\nconst DataSinkBuilderPage = lazy(() => import('./pages/DataSinkBuilderPage'));\n// Parser Pages\nconst DataParsersPage = lazy(() => import('./pages/DataParsersPage'));\nconst ParserViewPage = lazy(() => import('./pages/ParserViewPage'));\nconst ParserBuilderPage = lazy(() => import('./pages/ParserBuilderPage'));\n// Pipeline Pages\nconst PipelinesPage = lazy(() => import('./pages/PipelinesPage'));\nconst PipelineViewPage = lazy(() => import('./pages/PipelineViewPage'));\nconst PipelineBuilderPage = lazy(() => import('./pages/PipelineBuilderPage'));\n\n// Loading fallback component\nfunction PageLoader() {\n return (\n <div className=\"flex items-center justify-center min-h-[400px]\">\n <Spinner className=\"h-8 w-8\" />\n </div>\n );\n}\n\n/** Generate a new workflow builder path with a fresh UUID key. */\nexport const newWorkflowPath = () => `/workflows/workflow/${crypto.randomUUID()}/v1`;\n\n/**\n * Redirect /workflows/new to a UUID-based URL.\n * Uses <Navigate> for synchronous redirect (no blank frame).\n */\nfunction WorkflowNewRedirect() {\n const path = useMemo(() => newWorkflowPath(), []);\n return <Navigate to={path} replace />;\n}\n\n/**\n * Bridge component: resolves a BigConsole workflow ID to its externalWorkflowId\n * and navigates to the SDK's visual builder route.\n *\n * Route: /workflows/:workflowId/edit\n * Redirects to: /workflows/workflow/{workflowKey}/v1\n */\nconst WorkflowEditBridge = memo(function WorkflowEditBridge() {\n const { workflowId } = useParams<{ workflowId: string }>();\n const navigate = useAppNavigate();\n const { fetchWorkflow } = useWorkflowOperations({ skipFetch: true });\n const [error, setError] = useState<string | null>(null);\n const retryCount = useRef(0);\n\n useEffect(() => {\n if (!workflowId) {\n setError('No workflow ID provided');\n return;\n }\n\n // Reset retry budget and error when workflowId changes so a\n // previous failed attempt doesn't consume the new workflow's retry.\n retryCount.current = 0;\n setError(null);\n let cancelled = false;\n\n const handleResult = (workflow: Awaited<ReturnType<typeof fetchWorkflow>>) => {\n if (cancelled) return;\n\n if (workflow?.key) {\n // Navigate to the SDK builder route using the workflow key (e.g. \"github_user_profile\")\n // and default version \"v1\". The FluidGrids SDK fetches the definition by workflowKey.\n // Replace history so the bridge doesn't trap the back button.\n navigate(`/workflows/workflow/${workflow.key}/v1`, { replace: true });\n } else if (workflow) {\n // Workflow exists but has no key — open SDK builder in create mode\n navigate(`/workflows/builder`, { replace: true });\n } else if (retryCount.current < 1) {\n // On full-page loads the auth/workspace context may not be bootstrapped yet,\n // causing a false null. Retry once after a short delay (same pattern as WorkflowViewPage).\n retryCount.current += 1;\n setTimeout(() => {\n if (!cancelled) {\n fetchWorkflow(workflowId)\n .then(handleResult)\n .catch((err) => {\n if (!cancelled) setError(err?.message ?? 'Failed to load workflow');\n });\n }\n }, BOOTSTRAP_RETRY_DELAY_MS);\n } else {\n setError('Workflow not found');\n }\n };\n\n fetchWorkflow(workflowId)\n .then(handleResult)\n .catch((err) => {\n if (!cancelled) setError(err?.message ?? 'Failed to load workflow');\n });\n\n return () => {\n cancelled = true;\n };\n }, [workflowId, fetchWorkflow, navigate]);\n\n if (error) {\n return (\n <div className=\"p-6 flex flex-col items-center justify-center min-h-[400px] text-center gap-4\">\n <p className=\"text-sm text-text-secondary\">{error}</p>\n <button\n type=\"button\"\n onClick={() => navigate('/workflows')}\n className=\"px-4 py-2 text-sm font-medium text-text-primary bg-bg-sunken hover:bg-border-default rounded-md transition-colors\"\n >\n Back to Workflows\n </button>\n </div>\n );\n }\n\n return (\n <div className=\"flex items-center justify-center min-h-[400px]\">\n <Spinner className=\"h-8 w-8\" />\n </div>\n );\n});\n\n/**\n * Matches a canonical v4-style UUID. BigConsole workflow RECORD ids are UUIDs;\n * workflow KEYS are human slugs (e.g. \"users_analytics\"). New-workflow URLs also\n * use a fresh `crypto.randomUUID()` as the builder key. We only attempt record\n * resolution for UUID-shaped `:id`s — slugs are always real keys and skip the\n * lookup entirely (no extra round-trip, no spinner flash).\n */\nconst UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;\n\n/** Minimal shape of the GetWorkflow query — the resolver only needs the key. */\ntype WorkflowKeyLookup = { workflow: { key: string | null } | null };\n\n/**\n * Guards the SDK visual builder route.\n *\n * The SDK builder loads its definition from workflow-svc using the URL `:id` as\n * the `workflowKey`. That only works when `:id` is the workflow KEY. When a\n * BigConsole workflow RECORD id (a UUID) reaches the builder — via the SDK\n * card's `navigate(\"../workflow/\" + workflow.workflow_key + ...)`, a bookmarked\n * record-id URL, etc. — no definition matches that key, so the canvas is empty\n * AND the SDK silently creates a phantom 0-node definition keyed by the UUID.\n *\n * This resolver closes that gap centrally (the same id→key resolution the\n * `/workflows/:workflowId/edit` `WorkflowEditBridge` does, but applied to the\n * builder route itself so EVERY entry point is covered):\n * - `:id` is a slug → it's already a key → render the builder as-is.\n * - `:id` is a UUID that maps to a BigConsole record with a different key →\n * redirect to `/workflows/workflow/<key>/<version>`.\n * - `:id` is a UUID that is NOT a record (a fresh new-workflow id) → render\n * the builder as-is (create mode).\n */\nconst WorkflowBuilderResolver = memo(function WorkflowBuilderResolver() {\n const { id, version } = useParams<{ id: string; version: string }>();\n const navigate = useAppNavigate();\n const client = useApolloClient();\n // Slugs (real keys) render the builder immediately (derived below); only\n // UUID-shaped ids need a record lookup first.\n const isUuid = !!id && UUID_RE.test(id);\n // A UUID is only safe to open in the SDK builder once the lookup POSITIVELY\n // confirms it is not a BigConsole record (a clean not-found — e.g. a fresh\n // new-workflow id). Both verdicts are keyed by the id they describe so that\n // navigating between workflows re-resolves instead of reusing a stale answer.\n const [confirmedAbsentId, setConfirmedAbsentId] = useState<string | null>(null);\n const [failedId, setFailedId] = useState<string | null>(null);\n // Bumped by the \"Try again\" button to re-run the lookup effect after a failure.\n const [retryNonce, setRetryNonce] = useState(0);\n const retryCount = useRef(0);\n\n useEffect(() => {\n if (!id || !isUuid) return;\n\n retryCount.current = 0;\n let cancelled = false;\n const targetVersion = version ?? 'v1';\n\n const attempt = () => {\n // Query directly (not via fetchWorkflow, which swallows Apollo errors and\n // returns null) so we can tell a genuine \"no such record\" apart from a\n // transient lookup failure. Treating a failure as not-found would re-open\n // the builder with the record id and recreate a phantom 0-node definition.\n client\n .query<WorkflowKeyLookup>({\n query: GetWorkflowDocument,\n variables: { id },\n fetchPolicy: 'network-only',\n })\n .then((result) => {\n if (cancelled) return;\n const record = result.data?.workflow;\n if (record) {\n // The UUID IS a BigConsole record.\n if (record.key && record.key !== id) {\n // Open the builder under its real key (where the definition + nodes\n // live). encodeURIComponent guards against URL-unsafe key chars.\n // Replace history so the resolver doesn't trap the back button.\n navigate(`/workflows/workflow/${encodeURIComponent(record.key)}/${targetVersion}`, {\n replace: true,\n });\n } else {\n // Record exists but has no usable key — open a blank builder rather\n // than reusing the record UUID as the key (which would phantom).\n navigate('/workflows/builder', { replace: true });\n }\n } else {\n // Query succeeded with no record → a genuine new-workflow id.\n setConfirmedAbsentId(id);\n }\n })\n .catch(() => {\n if (cancelled) return;\n if (retryCount.current < 1) {\n // On a cold full-page load the auth/workspace context may not be\n // bootstrapped yet. Retry once before giving up.\n retryCount.current += 1;\n setTimeout(() => {\n if (!cancelled) attempt();\n }, BOOTSTRAP_RETRY_DELAY_MS);\n } else {\n // Lookup failed — do NOT assume create mode (the id may be a record);\n // surface a retry instead of risking a phantom definition.\n setFailedId(id);\n }\n });\n };\n\n attempt();\n\n return () => {\n cancelled = true;\n };\n }, [id, isUuid, version, client, navigate, retryNonce]);\n\n // Slug keys, and UUIDs confirmed not to be records, render the builder.\n if (!isUuid || confirmedAbsentId === id) {\n return <SDKWorkflowBuilderPage />;\n }\n\n // A lookup that ultimately failed: surface a retry rather than silently\n // opening the builder with what may be a record id.\n if (failedId === id) {\n return (\n <div className=\"p-6 flex flex-col items-center justify-center min-h-[400px] text-center gap-4\">\n <p className=\"text-sm text-text-secondary\">Couldn&apos;t load this workflow. Please try again.</p>\n <div className=\"flex items-center gap-2\">\n <button\n type=\"button\"\n onClick={() => {\n setFailedId(null);\n setRetryNonce((n) => n + 1);\n }}\n className=\"px-4 py-2 text-sm font-medium text-action-primary-fg bg-action-primary-bg hover:bg-action-primary-bgHover rounded-md transition-colors\"\n >\n Try again\n </button>\n <button\n type=\"button\"\n onClick={() => navigate('/workflows')}\n className=\"px-4 py-2 text-sm font-medium text-text-primary bg-bg-sunken hover:bg-border-default rounded-md transition-colors\"\n >\n Back to Workflows\n </button>\n </div>\n </div>\n );\n }\n\n return (\n <div className=\"flex items-center justify-center min-h-[400px]\">\n <Spinner className=\"h-8 w-8\" />\n </div>\n );\n});\n\nexport function BigConsoleRoutes(props: BigConsoleRootProps) {\n if (props.routePage === 'workflow-feeds')\n return (\n <Suspense fallback={<PageLoader />}>\n <WorkflowsPage />\n </Suspense>\n );\n if (props.routePage === 'workflow-detail')\n return (\n <Suspense fallback={<PageLoader />}>\n <WorkflowViewPage />\n </Suspense>\n );\n return (\n <Suspense fallback={<PageLoader />}>\n <Routes>\n <Route path=\"/\" element={<OverviewPage />} />\n <Route path=\"/dashboards\" element={<DashboardsPage />} />\n <Route path=\"/dashboards/:dashboardId\" element={<DashboardViewPage />} />\n <Route path=\"/dashboards/:dashboardId/builder\" element={<DashboardBuilderPage />} />\n <Route path=\"/datasources\" element={<DataSourcesPage />} />\n <Route path=\"/insights\" element={<InsightsPage />} />\n <Route path=\"/settings\" element={<SettingsPage />} />\n <Route path=\"/widgets/demo\" element={<WidgetDemoPage />} />\n {/* DataSink Routes */}\n <Route path=\"/datasinks\" element={<DataSinksPage />} />\n <Route path=\"/datasinks/new\" element={<DataSinkBuilderPage />} />\n <Route path=\"/datasinks/:dataSinkId\" element={<DataSinkViewPage />} />\n <Route path=\"/datasinks/:dataSinkId/edit\" element={<DataSinkBuilderPage />} />\n {/* Parser Routes */}\n <Route path=\"/parsers\" element={<DataParsersPage />} />\n <Route path=\"/parsers/new\" element={<ParserBuilderPage />} />\n <Route path=\"/parsers/:parserId\" element={<ParserViewPage />} />\n <Route path=\"/parsers/:parserId/edit\" element={<ParserBuilderPage />} />\n {/* Dashboard-scoped Parser Routes */}\n <Route path=\"/dashboards/:consoleId/parsers\" element={<DataParsersPage />} />\n <Route path=\"/dashboards/:consoleId/parsers/new\" element={<ParserBuilderPage />} />\n <Route path=\"/dashboards/:consoleId/parsers/:parserId\" element={<ParserViewPage />} />\n <Route path=\"/dashboards/:consoleId/parsers/:parserId/edit\" element={<ParserBuilderPage />} />\n {/* Workflow Routes — list/view use BigConsole-native pages (query bigconsole-svc).\n All static routes are grouped before the dynamic :workflowId catch-all.\n React Router v6 prioritizes static segments regardless of declaration order,\n but keeping them above the param routes makes intent unambiguous for maintainers. */}\n <Route path=\"/workflows\" element={<WorkflowsPage />} />\n <Route path=\"/workflows/feeds\" element={<WorkflowsPage />} />\n <Route path=\"/workflows/details/:workflowId\" element={<WorkflowViewPage />} />\n <Route path=\"/workflows/list\" element={<WorkflowsPage />} />\n {/* New workflow — redirect to UUID-based URL (matches FluidGrids pattern) */}\n <Route path=\"/workflows/new\" element={<WorkflowNewRedirect />} />\n {/* SDK visual workflow builder — design existing workflows */}\n <Route path=\"/workflows/builder\" element={<SDKWorkflowBuilderPage />} />\n {/* All parameterised builder routes go through WorkflowBuilderResolver so a\n record-id `:id` is resolved to its workflow key first (slugs/new-workflow\n UUIDs pass straight through); otherwise the SDK opens an empty canvas and\n creates a phantom 0-node definition keyed by the record id. */}\n <Route path=\"/workflows/builder/:id/:version\" element={<WorkflowBuilderResolver />} />\n <Route path=\"/workflows/workflow/:id/:version\" element={<WorkflowBuilderResolver />} />\n {/* SDK sub-pages (runs, history, templates, nodes, settings) */}\n <Route path=\"/workflows/runs\" element={<ExecutionsListPage />} />\n <Route path=\"/workflows/runs/:runId\" element={<ExecutionDetailPage />} />\n <Route path=\"/workflows/history\" element={<HistoryPage />} />\n <Route path=\"/workflows/templates\" element={<TemplatesPage />} />\n <Route path=\"/workflows/nodes\" element={<NodesPage />} />\n <Route path=\"/workflows/settings\" element={<WorkflowSettingsPage />} />\n {/* Dynamic routes — :workflowId catch-all AFTER all static segments */}\n <Route path=\"/workflows/:workflowId\" element={<WorkflowViewPage />} />\n <Route path=\"/workflows/:workflowId/edit\" element={<WorkflowEditBridge />} />\n {/* Support SDK's navigation pattern (without /workflows/ prefix) — also\n resolves record-id → key via WorkflowBuilderResolver. */}\n <Route path=\"/workflow/:id/:version\" element={<WorkflowBuilderResolver />} />\n {/* Redirect /list to /workflows/list (SDK uses relative navigation) */}\n <Route path=\"/list\" element={<Navigate to=\"/bigconsole/workflows/list\" replace />} />\n {/* Pipeline Routes */}\n <Route path=\"/pipelines\" element={<PipelinesPage />} />\n <Route path=\"/pipelines/new\" element={<PipelineBuilderPage />} />\n <Route path=\"/pipelines/:pipelineId\" element={<PipelineViewPage />} />\n <Route path=\"/pipelines/:pipelineId/edit\" element={<PipelineBuilderPage />} />\n </Routes>\n </Suspense>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"BigConsoleRoutes.js","names":[],"sources":["../../src/bigconsole/BigConsoleRoutes.tsx"],"sourcesContent":["import { lazy, Suspense, memo, useState, useMemo, useEffect, useRef } from 'react';\nimport { Route, Routes, Navigate, useParams } from 'react-router';\nimport { type BigConsoleRootProps } from './types';\nimport { Spinner } from '@burdenoff/fe-libs/ui';\nimport { useApolloClient } from '@apollo/client/react';\nimport { useAppNavigate } from './contexts';\nimport { useWorkflowOperations } from './hooks/useWorkflowOperations';\nimport { GetWorkflowDocument } from '../generated/wspace-operations';\nimport { BOOTSTRAP_RETRY_DELAY_MS } from './constants';\n\n// Import FluidGrids SDK workflow components (EXACT same as microfe-workflows)\nimport {\n WorkflowBuilderPage as SDKWorkflowBuilderPage,\n ExecutionsListPage,\n ExecutionDetailPage,\n HistoryPage,\n TemplatesPage,\n NodesPage,\n SettingsPage as WorkflowSettingsPage,\n} from '@burdenoff/fluidgrids-fe-sdk';\n\n// Lazy-loaded pages\nconst OverviewPage = lazy(() => import('./pages/OverviewPage'));\nconst DashboardsPage = lazy(() => import('./pages/DashboardsPage'));\nconst DashboardViewPage = lazy(() => import('./pages/DashboardViewPage'));\nconst DashboardBuilderPage = lazy(() => import('./pages/DashboardBuilderPage'));\nconst DataSourcesPage = lazy(() => import('./pages/DataSourcesPage'));\nconst InsightsPage = lazy(() => import('./pages/InsightsPage'));\nconst SettingsPage = lazy(() => import('./pages/SettingsPage'));\nconst WidgetDemoPage = lazy(() => import('./pages/WidgetDemoPage'));\n// BigConsole-native workflow pages (query bigconsole-svc, not workflow-svc)\n// These use named exports (no default export), so we remap via .then()\nconst WorkflowsPage = lazy(() => import('./pages/WorkflowsPage').then((m) => ({ default: m.WorkflowsPage })));\nconst WorkflowViewPage = lazy(() => import('./pages/WorkflowViewPage').then((m) => ({ default: m.WorkflowViewPage })));\n// DataSink Pages\nconst DataSinksPage = lazy(() => import('./pages/DataSinksPage'));\nconst DataSinkViewPage = lazy(() => import('./pages/DataSinkViewPage'));\nconst DataSinkAlertsPage = lazy(() => import('./pages/DataSinkAlertsPage'));\nconst DataSinkBuilderPage = lazy(() => import('./pages/DataSinkBuilderPage'));\n// Parser Pages\nconst DataParsersPage = lazy(() => import('./pages/DataParsersPage'));\nconst ParserViewPage = lazy(() => import('./pages/ParserViewPage'));\nconst ParserBuilderPage = lazy(() => import('./pages/ParserBuilderPage'));\n// Pipeline Pages\nconst PipelinesPage = lazy(() => import('./pages/PipelinesPage'));\nconst PipelineViewPage = lazy(() => import('./pages/PipelineViewPage'));\nconst PipelineBuilderPage = lazy(() => import('./pages/PipelineBuilderPage'));\n\n// Loading fallback component\nfunction PageLoader() {\n return (\n <div className=\"flex items-center justify-center min-h-[400px]\">\n <Spinner className=\"h-8 w-8\" />\n </div>\n );\n}\n\n/** Generate a new workflow builder path with a fresh UUID key. */\nexport const newWorkflowPath = () => `/workflows/workflow/${crypto.randomUUID()}/v1`;\n\n/**\n * Redirect /workflows/new to a UUID-based URL.\n * Uses <Navigate> for synchronous redirect (no blank frame).\n */\nfunction WorkflowNewRedirect() {\n const path = useMemo(() => newWorkflowPath(), []);\n return <Navigate to={path} replace />;\n}\n\n/**\n * Bridge component: resolves a BigConsole workflow ID to its externalWorkflowId\n * and navigates to the SDK's visual builder route.\n *\n * Route: /workflows/:workflowId/edit\n * Redirects to: /workflows/workflow/{workflowKey}/v1\n */\nconst WorkflowEditBridge = memo(function WorkflowEditBridge() {\n const { workflowId } = useParams<{ workflowId: string }>();\n const navigate = useAppNavigate();\n const { fetchWorkflow } = useWorkflowOperations({ skipFetch: true });\n const [error, setError] = useState<string | null>(null);\n const retryCount = useRef(0);\n\n useEffect(() => {\n if (!workflowId) {\n setError('No workflow ID provided');\n return;\n }\n\n // Reset retry budget and error when workflowId changes so a\n // previous failed attempt doesn't consume the new workflow's retry.\n retryCount.current = 0;\n setError(null);\n let cancelled = false;\n\n const handleResult = (workflow: Awaited<ReturnType<typeof fetchWorkflow>>) => {\n if (cancelled) return;\n\n if (workflow?.key) {\n // Navigate to the SDK builder route using the workflow key (e.g. \"github_user_profile\")\n // and default version \"v1\". The FluidGrids SDK fetches the definition by workflowKey.\n // Replace history so the bridge doesn't trap the back button.\n navigate(`/workflows/workflow/${workflow.key}/v1`, { replace: true });\n } else if (workflow) {\n // Workflow exists but has no key — open SDK builder in create mode\n navigate(`/workflows/builder`, { replace: true });\n } else if (retryCount.current < 1) {\n // On full-page loads the auth/workspace context may not be bootstrapped yet,\n // causing a false null. Retry once after a short delay (same pattern as WorkflowViewPage).\n retryCount.current += 1;\n setTimeout(() => {\n if (!cancelled) {\n fetchWorkflow(workflowId)\n .then(handleResult)\n .catch((err) => {\n if (!cancelled) setError(err?.message ?? 'Failed to load workflow');\n });\n }\n }, BOOTSTRAP_RETRY_DELAY_MS);\n } else {\n setError('Workflow not found');\n }\n };\n\n fetchWorkflow(workflowId)\n .then(handleResult)\n .catch((err) => {\n if (!cancelled) setError(err?.message ?? 'Failed to load workflow');\n });\n\n return () => {\n cancelled = true;\n };\n }, [workflowId, fetchWorkflow, navigate]);\n\n if (error) {\n return (\n <div className=\"p-6 flex flex-col items-center justify-center min-h-[400px] text-center gap-4\">\n <p className=\"text-sm text-text-secondary\">{error}</p>\n <button\n type=\"button\"\n onClick={() => navigate('/workflows')}\n className=\"px-4 py-2 text-sm font-medium text-text-primary bg-bg-sunken hover:bg-border-default rounded-md transition-colors\"\n >\n Back to Workflows\n </button>\n </div>\n );\n }\n\n return (\n <div className=\"flex items-center justify-center min-h-[400px]\">\n <Spinner className=\"h-8 w-8\" />\n </div>\n );\n});\n\n/**\n * Matches a canonical v4-style UUID. BigConsole workflow RECORD ids are UUIDs;\n * workflow KEYS are human slugs (e.g. \"users_analytics\"). New-workflow URLs also\n * use a fresh `crypto.randomUUID()` as the builder key. We only attempt record\n * resolution for UUID-shaped `:id`s — slugs are always real keys and skip the\n * lookup entirely (no extra round-trip, no spinner flash).\n */\nconst UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;\n\n/** Minimal shape of the GetWorkflow query — the resolver only needs the key. */\ntype WorkflowKeyLookup = { workflow: { key: string | null } | null };\n\n/**\n * Guards the SDK visual builder route.\n *\n * The SDK builder loads its definition from workflow-svc using the URL `:id` as\n * the `workflowKey`. That only works when `:id` is the workflow KEY. When a\n * BigConsole workflow RECORD id (a UUID) reaches the builder — via the SDK\n * card's `navigate(\"../workflow/\" + workflow.workflow_key + ...)`, a bookmarked\n * record-id URL, etc. — no definition matches that key, so the canvas is empty\n * AND the SDK silently creates a phantom 0-node definition keyed by the UUID.\n *\n * This resolver closes that gap centrally (the same id→key resolution the\n * `/workflows/:workflowId/edit` `WorkflowEditBridge` does, but applied to the\n * builder route itself so EVERY entry point is covered):\n * - `:id` is a slug → it's already a key → render the builder as-is.\n * - `:id` is a UUID that maps to a BigConsole record with a different key →\n * redirect to `/workflows/workflow/<key>/<version>`.\n * - `:id` is a UUID that is NOT a record (a fresh new-workflow id) → render\n * the builder as-is (create mode).\n */\nconst WorkflowBuilderResolver = memo(function WorkflowBuilderResolver() {\n const { id, version } = useParams<{ id: string; version: string }>();\n const navigate = useAppNavigate();\n const client = useApolloClient();\n // Slugs (real keys) render the builder immediately (derived below); only\n // UUID-shaped ids need a record lookup first.\n const isUuid = !!id && UUID_RE.test(id);\n // A UUID is only safe to open in the SDK builder once the lookup POSITIVELY\n // confirms it is not a BigConsole record (a clean not-found — e.g. a fresh\n // new-workflow id). Both verdicts are keyed by the id they describe so that\n // navigating between workflows re-resolves instead of reusing a stale answer.\n const [confirmedAbsentId, setConfirmedAbsentId] = useState<string | null>(null);\n const [failedId, setFailedId] = useState<string | null>(null);\n // Bumped by the \"Try again\" button to re-run the lookup effect after a failure.\n const [retryNonce, setRetryNonce] = useState(0);\n const retryCount = useRef(0);\n\n useEffect(() => {\n if (!id || !isUuid) return;\n\n retryCount.current = 0;\n let cancelled = false;\n const targetVersion = version ?? 'v1';\n\n const attempt = () => {\n // Query directly (not via fetchWorkflow, which swallows Apollo errors and\n // returns null) so we can tell a genuine \"no such record\" apart from a\n // transient lookup failure. Treating a failure as not-found would re-open\n // the builder with the record id and recreate a phantom 0-node definition.\n client\n .query<WorkflowKeyLookup>({\n query: GetWorkflowDocument,\n variables: { id },\n fetchPolicy: 'network-only',\n })\n .then((result) => {\n if (cancelled) return;\n const record = result.data?.workflow;\n if (record) {\n // The UUID IS a BigConsole record.\n if (record.key && record.key !== id) {\n // Open the builder under its real key (where the definition + nodes\n // live). encodeURIComponent guards against URL-unsafe key chars.\n // Replace history so the resolver doesn't trap the back button.\n navigate(`/workflows/workflow/${encodeURIComponent(record.key)}/${targetVersion}`, {\n replace: true,\n });\n } else {\n // Record exists but has no usable key — open a blank builder rather\n // than reusing the record UUID as the key (which would phantom).\n navigate('/workflows/builder', { replace: true });\n }\n } else {\n // Query succeeded with no record → a genuine new-workflow id.\n setConfirmedAbsentId(id);\n }\n })\n .catch(() => {\n if (cancelled) return;\n if (retryCount.current < 1) {\n // On a cold full-page load the auth/workspace context may not be\n // bootstrapped yet. Retry once before giving up.\n retryCount.current += 1;\n setTimeout(() => {\n if (!cancelled) attempt();\n }, BOOTSTRAP_RETRY_DELAY_MS);\n } else {\n // Lookup failed — do NOT assume create mode (the id may be a record);\n // surface a retry instead of risking a phantom definition.\n setFailedId(id);\n }\n });\n };\n\n attempt();\n\n return () => {\n cancelled = true;\n };\n }, [id, isUuid, version, client, navigate, retryNonce]);\n\n // Slug keys, and UUIDs confirmed not to be records, render the builder.\n if (!isUuid || confirmedAbsentId === id) {\n return <SDKWorkflowBuilderPage />;\n }\n\n // A lookup that ultimately failed: surface a retry rather than silently\n // opening the builder with what may be a record id.\n if (failedId === id) {\n return (\n <div className=\"p-6 flex flex-col items-center justify-center min-h-[400px] text-center gap-4\">\n <p className=\"text-sm text-text-secondary\">Couldn&apos;t load this workflow. Please try again.</p>\n <div className=\"flex items-center gap-2\">\n <button\n type=\"button\"\n onClick={() => {\n setFailedId(null);\n setRetryNonce((n) => n + 1);\n }}\n className=\"px-4 py-2 text-sm font-medium text-action-primary-fg bg-action-primary-bg hover:bg-action-primary-bgHover rounded-md transition-colors\"\n >\n Try again\n </button>\n <button\n type=\"button\"\n onClick={() => navigate('/workflows')}\n className=\"px-4 py-2 text-sm font-medium text-text-primary bg-bg-sunken hover:bg-border-default rounded-md transition-colors\"\n >\n Back to Workflows\n </button>\n </div>\n </div>\n );\n }\n\n return (\n <div className=\"flex items-center justify-center min-h-[400px]\">\n <Spinner className=\"h-8 w-8\" />\n </div>\n );\n});\n\nexport function BigConsoleRoutes(props: BigConsoleRootProps) {\n if (props.routePage === 'workflow-feeds')\n return (\n <Suspense fallback={<PageLoader />}>\n <WorkflowsPage />\n </Suspense>\n );\n if (props.routePage === 'workflow-detail')\n return (\n <Suspense fallback={<PageLoader />}>\n <WorkflowViewPage />\n </Suspense>\n );\n return (\n <Suspense fallback={<PageLoader />}>\n <Routes>\n <Route path=\"/\" element={<OverviewPage />} />\n <Route path=\"/dashboards\" element={<DashboardsPage />} />\n <Route path=\"/dashboards/:dashboardId\" element={<DashboardViewPage />} />\n <Route path=\"/dashboards/:dashboardId/builder\" element={<DashboardBuilderPage />} />\n <Route path=\"/datasources\" element={<DataSourcesPage />} />\n <Route path=\"/insights\" element={<InsightsPage />} />\n <Route path=\"/settings\" element={<SettingsPage />} />\n <Route path=\"/widgets/demo\" element={<WidgetDemoPage />} />\n {/* DataSink Routes */}\n <Route path=\"/datasinks\" element={<DataSinksPage />} />\n <Route path=\"/datasinks/new\" element={<DataSinkBuilderPage />} />\n <Route path=\"/datasinks/:dataSinkId\" element={<DataSinkViewPage />} />\n <Route path=\"/datasinks/:dataSinkId/edit\" element={<DataSinkBuilderPage />} />\n <Route path=\"/datasinks/:dataSinkId/alerts\" element={<DataSinkAlertsPage />} />\n {/* Parser Routes */}\n <Route path=\"/parsers\" element={<DataParsersPage />} />\n <Route path=\"/parsers/new\" element={<ParserBuilderPage />} />\n <Route path=\"/parsers/:parserId\" element={<ParserViewPage />} />\n <Route path=\"/parsers/:parserId/edit\" element={<ParserBuilderPage />} />\n {/* Dashboard-scoped Parser Routes */}\n <Route path=\"/dashboards/:consoleId/parsers\" element={<DataParsersPage />} />\n <Route path=\"/dashboards/:consoleId/parsers/new\" element={<ParserBuilderPage />} />\n <Route path=\"/dashboards/:consoleId/parsers/:parserId\" element={<ParserViewPage />} />\n <Route path=\"/dashboards/:consoleId/parsers/:parserId/edit\" element={<ParserBuilderPage />} />\n {/* Workflow Routes — list/view use BigConsole-native pages (query bigconsole-svc).\n All static routes are grouped before the dynamic :workflowId catch-all.\n React Router v6 prioritizes static segments regardless of declaration order,\n but keeping them above the param routes makes intent unambiguous for maintainers. */}\n <Route path=\"/workflows\" element={<WorkflowsPage />} />\n <Route path=\"/workflows/feeds\" element={<WorkflowsPage />} />\n <Route path=\"/workflows/details/:workflowId\" element={<WorkflowViewPage />} />\n <Route path=\"/workflows/list\" element={<WorkflowsPage />} />\n {/* New workflow — redirect to UUID-based URL (matches FluidGrids pattern) */}\n <Route path=\"/workflows/new\" element={<WorkflowNewRedirect />} />\n {/* SDK visual workflow builder — design existing workflows */}\n <Route path=\"/workflows/builder\" element={<SDKWorkflowBuilderPage />} />\n {/* All parameterised builder routes go through WorkflowBuilderResolver so a\n record-id `:id` is resolved to its workflow key first (slugs/new-workflow\n UUIDs pass straight through); otherwise the SDK opens an empty canvas and\n creates a phantom 0-node definition keyed by the record id. */}\n <Route path=\"/workflows/builder/:id/:version\" element={<WorkflowBuilderResolver />} />\n <Route path=\"/workflows/workflow/:id/:version\" element={<WorkflowBuilderResolver />} />\n {/* SDK sub-pages (runs, history, templates, nodes, settings) */}\n <Route path=\"/workflows/runs\" element={<ExecutionsListPage />} />\n <Route path=\"/workflows/runs/:runId\" element={<ExecutionDetailPage />} />\n <Route path=\"/workflows/history\" element={<HistoryPage />} />\n <Route path=\"/workflows/templates\" element={<TemplatesPage />} />\n <Route path=\"/workflows/nodes\" element={<NodesPage />} />\n <Route path=\"/workflows/settings\" element={<WorkflowSettingsPage />} />\n {/* Dynamic routes — :workflowId catch-all AFTER all static segments */}\n <Route path=\"/workflows/:workflowId\" element={<WorkflowViewPage />} />\n <Route path=\"/workflows/:workflowId/edit\" element={<WorkflowEditBridge />} />\n {/* Support SDK's navigation pattern (without /workflows/ prefix) — also\n resolves record-id → key via WorkflowBuilderResolver. */}\n <Route path=\"/workflow/:id/:version\" element={<WorkflowBuilderResolver />} />\n {/* Redirect /list to /workflows/list (SDK uses relative navigation) */}\n <Route path=\"/list\" element={<Navigate to=\"/bigconsole/workflows/list\" replace />} />\n {/* Pipeline Routes */}\n <Route path=\"/pipelines\" element={<PipelinesPage />} />\n <Route path=\"/pipelines/new\" element={<PipelineBuilderPage />} />\n <Route path=\"/pipelines/:pipelineId\" element={<PipelineViewPage />} />\n <Route path=\"/pipelines/:pipelineId/edit\" element={<PipelineBuilderPage />} />\n </Routes>\n </Suspense>\n );\n}\n"],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ import { AlertExecution, AlertRule } from '../../hooks/useDataSinkAlerts';
2
+
3
+ interface Props {
4
+ owner: string;
5
+ rules: AlertRule[];
6
+ load: (alertId?: string, after?: string) => Promise<AlertExecution[] | null>;
7
+ refreshVersion: number;
8
+ }
9
+ export declare function AlertExecutionHistory({ owner, rules, load, refreshVersion }: Props): import("react").JSX.Element;
10
+ export {};
11
+ //# sourceMappingURL=AlertExecutionHistory.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AlertExecutionHistory.d.ts","sourceRoot":"","sources":["../../../../src/bigconsole/components/datasink/AlertExecutionHistory.tsx"],"names":[],"mappings":"AAKA,OAAO,EAAqB,KAAK,cAAc,EAAE,KAAK,SAAS,EAAE,MAAM,+BAA+B,CAAC;AAEvG,UAAU,KAAK;IACb,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,SAAS,EAAE,CAAC;IACnB,IAAI,EAAE,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,cAAc,EAAE,GAAG,IAAI,CAAC,CAAC;IAC7E,cAAc,EAAE,MAAM,CAAC;CACxB;AAUD,wBAAgB,qBAAqB,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,cAAc,EAAE,EAAE,KAAK,+BA2LlF"}
@@ -0,0 +1,248 @@
1
+ import { SECTION_FOCUS_RING as e } from "../common/sectionStyles.js";
2
+ import { Section as t } from "../common/Section.js";
3
+ import "../common/index.js";
4
+ import { alertErrorMessage as n } from "../../hooks/useDataSinkAlerts.js";
5
+ import { useCallback as r, useEffect as i, useLayoutEffect as a, useRef as o, useState as s } from "react";
6
+ import { Loader2 as c, RefreshCw as l } from "lucide-react";
7
+ import { Button as u } from "@burdenoff/fe-libs/ui";
8
+ import { jsx as d, jsxs as f } from "react/jsx-runtime";
9
+ import { useI18n as p } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
10
+ //#region src/bigconsole/components/datasink/AlertExecutionHistory.tsx
11
+ var m = {
12
+ owner: "",
13
+ rows: [],
14
+ loading: !1,
15
+ hasMore: !1,
16
+ error: null
17
+ };
18
+ function h({ owner: h, rules: g, load: _, refreshVersion: v }) {
19
+ let { t: y } = p(), [b, x] = s(""), [S, C] = s([]), w = S.at(-1), T = `${h}|${b}|${w ?? ""}`, E = o(null), D = o(null);
20
+ a(() => (E.current = T, () => {
21
+ E.current = null, D.current = null;
22
+ }), [T]);
23
+ let [O, k] = s(m), A = r(async () => {
24
+ if (E.current !== T || D.current) return;
25
+ let e = {};
26
+ D.current = e, k((e) => ({
27
+ ...e.owner === T ? e : m,
28
+ owner: T,
29
+ loading: !0,
30
+ error: null
31
+ }));
32
+ try {
33
+ let t = await _(b || void 0, w);
34
+ if (E.current !== T || D.current !== e || !t) return;
35
+ k({
36
+ owner: T,
37
+ rows: t.slice(0, 20),
38
+ loading: !1,
39
+ hasMore: t.length > 20,
40
+ error: null
41
+ });
42
+ } catch (t) {
43
+ E.current === T && D.current === e && k((e) => ({
44
+ ...e,
45
+ owner: T,
46
+ loading: !1,
47
+ error: n(t)
48
+ }));
49
+ } finally {
50
+ D.current === e && (D.current = null);
51
+ }
52
+ }, [
53
+ _,
54
+ b,
55
+ w,
56
+ T
57
+ ]);
58
+ i(() => {
59
+ Promise.resolve().then(() => A());
60
+ let e = window.setInterval(() => {
61
+ document.visibilityState === "visible" && A();
62
+ }, 1e4);
63
+ return () => window.clearInterval(e);
64
+ }, [A, v]);
65
+ let j = O.owner === T ? O : {
66
+ ...m,
67
+ loading: !0
68
+ };
69
+ return /* @__PURE__ */ f(t, {
70
+ title: y("bigconsole.alerts.history.title", "Execution history"),
71
+ headingLevel: 2,
72
+ description: y("bigconsole.alerts.history.description", "Actual evaluations and notification delivery status. Refreshes every 10 seconds while this page is visible."),
73
+ actions: /* @__PURE__ */ f(u, {
74
+ type: "button",
75
+ variant: "secondary",
76
+ size: "sm",
77
+ onClick: () => void A(),
78
+ disabled: j.loading,
79
+ children: [j.loading ? /* @__PURE__ */ d(c, { className: "mr-2 h-4 w-4 animate-spin" }) : /* @__PURE__ */ d(l, { className: "mr-2 h-4 w-4" }), y("bigconsole.alerts.history.refresh", "Refresh history")]
80
+ }),
81
+ children: [
82
+ /* @__PURE__ */ d("label", {
83
+ htmlFor: "alert-history-filter",
84
+ className: "mb-1 block text-xs font-medium text-text-primary",
85
+ children: y("bigconsole.alerts.history.filter", "Filter by rule")
86
+ }),
87
+ /* @__PURE__ */ f("select", {
88
+ id: "alert-history-filter",
89
+ className: `mb-4 w-full min-w-0 rounded-control border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary ${e}`,
90
+ value: b,
91
+ onChange: (e) => {
92
+ x(e.target.value), C([]);
93
+ },
94
+ children: [
95
+ /* @__PURE__ */ d("option", {
96
+ value: "",
97
+ children: y("bigconsole.alerts.history.all", "All rules")
98
+ }),
99
+ b && !g.some((e) => e.id === b) && /* @__PURE__ */ d("option", {
100
+ value: b,
101
+ children: b
102
+ }),
103
+ g.map((e) => /* @__PURE__ */ d("option", {
104
+ value: e.id,
105
+ children: e.name
106
+ }, e.id))
107
+ ]
108
+ }),
109
+ j.error && /* @__PURE__ */ d("p", {
110
+ role: "alert",
111
+ className: "mb-4 break-words text-sm text-status-error-text",
112
+ children: j.error
113
+ }),
114
+ j.loading && !j.rows.length && /* @__PURE__ */ d("p", {
115
+ role: "status",
116
+ className: "text-sm text-text-secondary",
117
+ children: y("bigconsole.alerts.history.loading", "Loading execution history…")
118
+ }),
119
+ !j.loading && !j.error && !j.rows.length && /* @__PURE__ */ d("p", {
120
+ className: "text-sm text-text-secondary",
121
+ children: y("bigconsole.alerts.history.empty", "No evaluations recorded yet. Enabled rules evaluate when the sink data is updated or refreshed.")
122
+ }),
123
+ /* @__PURE__ */ d("ol", {
124
+ className: "divide-y divide-border-subtle",
125
+ children: j.rows.map((e) => /* @__PURE__ */ f("li", {
126
+ className: "min-w-0 py-4 first:pt-0",
127
+ children: [
128
+ /* @__PURE__ */ f("div", {
129
+ className: "flex flex-wrap items-start justify-between gap-2",
130
+ children: [/* @__PURE__ */ f("div", {
131
+ className: "min-w-0",
132
+ children: [/* @__PURE__ */ d("p", {
133
+ className: "break-words text-sm font-medium text-text-primary",
134
+ children: g.find((t) => t.id === e.alertId)?.name ?? e.alertId
135
+ }), /* @__PURE__ */ d("time", {
136
+ dateTime: e.createdAt,
137
+ className: "text-xs text-text-secondary",
138
+ children: new Date(e.createdAt).toLocaleString()
139
+ })]
140
+ }), /* @__PURE__ */ d("span", {
141
+ className: "rounded-pill border border-border-subtle bg-bg-sunken px-2 py-1 text-xs font-medium text-text-primary",
142
+ children: y(`bigconsole.alerts.history.status.${e.status}`, e.status.replaceAll("_", " "))
143
+ })]
144
+ }),
145
+ /* @__PURE__ */ f("p", {
146
+ className: "mt-2 break-words text-xs text-text-secondary",
147
+ children: [
148
+ y("bigconsole.alerts.history.dataVersion", "Data version"),
149
+ " ",
150
+ e.version,
151
+ " · ",
152
+ e.source,
153
+ " ·",
154
+ " ",
155
+ e.durationMs,
156
+ " ms"
157
+ ]
158
+ }),
159
+ e.error && /* @__PURE__ */ d("p", {
160
+ className: "mt-2 break-words text-sm text-status-error-text",
161
+ children: e.error
162
+ }),
163
+ e.deliveries.length > 0 && /* @__PURE__ */ d("ul", {
164
+ className: "mt-3 space-y-2",
165
+ children: e.deliveries.map((e, t) => /* @__PURE__ */ f("li", {
166
+ className: "min-w-0 rounded-control border border-border-subtle bg-bg-sunken p-3 text-xs",
167
+ children: [
168
+ /* @__PURE__ */ f("div", {
169
+ className: "flex flex-wrap justify-between gap-2",
170
+ children: [/* @__PURE__ */ f("span", {
171
+ className: "break-all text-text-primary",
172
+ children: [
173
+ e.channel,
174
+ " · ",
175
+ e.recipient
176
+ ]
177
+ }), /* @__PURE__ */ d("span", {
178
+ className: "font-medium text-text-primary",
179
+ children: e.status
180
+ })]
181
+ }),
182
+ e.attemptedAt && /* @__PURE__ */ f("p", {
183
+ className: "mt-1 text-text-secondary",
184
+ children: [
185
+ y("bigconsole.alerts.history.attempted", "Attempted"),
186
+ " ",
187
+ /* @__PURE__ */ d("time", {
188
+ dateTime: e.attemptedAt,
189
+ children: new Date(e.attemptedAt).toLocaleString()
190
+ })
191
+ ]
192
+ }),
193
+ e.notificationId && /* @__PURE__ */ f("p", {
194
+ className: "mt-1 break-all text-text-muted",
195
+ children: [
196
+ y("bigconsole.alerts.history.notification", "Notification"),
197
+ " · ",
198
+ e.notificationId
199
+ ]
200
+ }),
201
+ e.error && /* @__PURE__ */ d("p", {
202
+ className: "mt-1 break-words text-status-error-text",
203
+ children: e.error
204
+ })
205
+ ]
206
+ }, `${e.channelId}|${e.recipient}|${t}`))
207
+ })
208
+ ]
209
+ }, e.id))
210
+ }),
211
+ /* @__PURE__ */ f("div", {
212
+ className: "mt-4 flex flex-wrap items-center justify-between gap-control-gap border-t border-border-subtle pt-3",
213
+ children: [/* @__PURE__ */ f("span", {
214
+ className: "text-xs text-text-secondary",
215
+ children: [
216
+ j.rows.length,
217
+ " ",
218
+ y("bigconsole.alerts.history.count", "executions on this page")
219
+ ]
220
+ }), /* @__PURE__ */ f("div", {
221
+ className: "flex gap-control-gap",
222
+ children: [/* @__PURE__ */ d(u, {
223
+ type: "button",
224
+ variant: "secondary",
225
+ size: "sm",
226
+ onClick: () => C((e) => e.slice(0, -1)),
227
+ disabled: !S.length || j.loading,
228
+ children: y("bigconsole.alerts.history.newer", "Newer")
229
+ }), /* @__PURE__ */ d(u, {
230
+ type: "button",
231
+ variant: "secondary",
232
+ size: "sm",
233
+ onClick: () => {
234
+ let e = j.rows.at(-1);
235
+ e && C((t) => [...t, e.id]);
236
+ },
237
+ disabled: !j.hasMore || j.loading,
238
+ children: y("bigconsole.alerts.history.older", "Older")
239
+ })]
240
+ })]
241
+ })
242
+ ]
243
+ });
244
+ }
245
+ //#endregion
246
+ export { h as AlertExecutionHistory };
247
+
248
+ //# sourceMappingURL=AlertExecutionHistory.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AlertExecutionHistory.js","names":[],"sources":["../../../../src/bigconsole/components/datasink/AlertExecutionHistory.tsx"],"sourcesContent":["import { useCallback, useEffect, useLayoutEffect, useRef, useState } from 'react';\nimport { Button } from '@burdenoff/fe-libs/ui';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { Loader2, RefreshCw } from 'lucide-react';\nimport { Section, SECTION_FOCUS_RING } from '../common';\nimport { alertErrorMessage, type AlertExecution, type AlertRule } from '../../hooks/useDataSinkAlerts';\n\ninterface Props {\n owner: string;\n rules: AlertRule[];\n load: (alertId?: string, after?: string) => Promise<AlertExecution[] | null>;\n refreshVersion: number;\n}\ninterface HistoryPage {\n owner: string;\n rows: AlertExecution[];\n loading: boolean;\n hasMore: boolean;\n error: string | null;\n}\nconst EMPTY: HistoryPage = { owner: '', rows: [], loading: false, hasMore: false, error: null };\n\nexport function AlertExecutionHistory({ owner, rules, load, refreshVersion }: Props) {\n const { t } = useI18n();\n const [alertId, setAlertId] = useState('');\n const [cursors, setCursors] = useState<string[]>([]);\n const after = cursors.at(-1);\n const requestOwner = `${owner}|${alertId}|${after ?? ''}`;\n const activeOwner = useRef<string | null>(null);\n const activeRequest = useRef<object | null>(null);\n useLayoutEffect(() => {\n activeOwner.current = requestOwner;\n return () => {\n activeOwner.current = null;\n activeRequest.current = null;\n };\n }, [requestOwner]);\n const [state, setState] = useState<HistoryPage>(EMPTY);\n const reload = useCallback(async () => {\n if (activeOwner.current !== requestOwner || activeRequest.current) return;\n const request = {};\n activeRequest.current = request;\n setState((previous) => ({\n ...(previous.owner === requestOwner ? previous : EMPTY),\n owner: requestOwner,\n loading: true,\n error: null,\n }));\n try {\n const rows = await load(alertId || undefined, after);\n if (activeOwner.current !== requestOwner || activeRequest.current !== request || !rows) return;\n setState({\n owner: requestOwner,\n rows: rows.slice(0, 20),\n loading: false,\n hasMore: rows.length > 20,\n error: null,\n });\n } catch (error) {\n if (activeOwner.current === requestOwner && activeRequest.current === request)\n setState((previous) => ({ ...previous, owner: requestOwner, loading: false, error: alertErrorMessage(error) }));\n } finally {\n if (activeRequest.current === request) activeRequest.current = null;\n }\n }, [load, alertId, after, requestOwner]);\n useEffect(() => {\n void Promise.resolve().then(() => reload());\n const timer = window.setInterval(() => {\n if (document.visibilityState === 'visible') void reload();\n }, 10000);\n return () => window.clearInterval(timer);\n }, [reload, refreshVersion]);\n const current = state.owner === requestOwner ? state : { ...EMPTY, loading: true };\n return (\n <Section\n title={t('bigconsole.alerts.history.title', 'Execution history')}\n headingLevel={2}\n description={t(\n 'bigconsole.alerts.history.description',\n 'Actual evaluations and notification delivery status. Refreshes every 10 seconds while this page is visible.'\n )}\n actions={\n <Button type=\"button\" variant=\"secondary\" size=\"sm\" onClick={() => void reload()} disabled={current.loading}>\n {current.loading ? <Loader2 className=\"mr-2 h-4 w-4 animate-spin\" /> : <RefreshCw className=\"mr-2 h-4 w-4\" />}\n {t('bigconsole.alerts.history.refresh', 'Refresh history')}\n </Button>\n }\n >\n <label htmlFor=\"alert-history-filter\" className=\"mb-1 block text-xs font-medium text-text-primary\">\n {t('bigconsole.alerts.history.filter', 'Filter by rule')}\n </label>\n <select\n id=\"alert-history-filter\"\n className={`mb-4 w-full min-w-0 rounded-control border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary ${SECTION_FOCUS_RING}`}\n value={alertId}\n onChange={(event) => {\n setAlertId(event.target.value);\n setCursors([]);\n }}\n >\n <option value=\"\">{t('bigconsole.alerts.history.all', 'All rules')}</option>\n {alertId && !rules.some((rule) => rule.id === alertId) && <option value={alertId}>{alertId}</option>}\n {rules.map((rule) => (\n <option key={rule.id} value={rule.id}>\n {rule.name}\n </option>\n ))}\n </select>\n {current.error && (\n <p role=\"alert\" className=\"mb-4 break-words text-sm text-status-error-text\">\n {current.error}\n </p>\n )}\n {current.loading && !current.rows.length && (\n <p role=\"status\" className=\"text-sm text-text-secondary\">\n {t('bigconsole.alerts.history.loading', 'Loading execution history…')}\n </p>\n )}\n {!current.loading && !current.error && !current.rows.length && (\n <p className=\"text-sm text-text-secondary\">\n {t(\n 'bigconsole.alerts.history.empty',\n 'No evaluations recorded yet. Enabled rules evaluate when the sink data is updated or refreshed.'\n )}\n </p>\n )}\n <ol className=\"divide-y divide-border-subtle\">\n {current.rows.map((execution) => (\n <li key={execution.id} className=\"min-w-0 py-4 first:pt-0\">\n <div className=\"flex flex-wrap items-start justify-between gap-2\">\n <div className=\"min-w-0\">\n <p className=\"break-words text-sm font-medium text-text-primary\">\n {rules.find((rule) => rule.id === execution.alertId)?.name ?? execution.alertId}\n </p>\n <time dateTime={execution.createdAt} className=\"text-xs text-text-secondary\">\n {new Date(execution.createdAt).toLocaleString()}\n </time>\n </div>\n <span className=\"rounded-pill border border-border-subtle bg-bg-sunken px-2 py-1 text-xs font-medium text-text-primary\">\n {t(`bigconsole.alerts.history.status.${execution.status}`, execution.status.replaceAll('_', ' '))}\n </span>\n </div>\n <p className=\"mt-2 break-words text-xs text-text-secondary\">\n {t('bigconsole.alerts.history.dataVersion', 'Data version')} {execution.version} · {execution.source} ·{' '}\n {execution.durationMs} ms\n </p>\n {execution.error && <p className=\"mt-2 break-words text-sm text-status-error-text\">{execution.error}</p>}\n {execution.deliveries.length > 0 && (\n <ul className=\"mt-3 space-y-2\">\n {execution.deliveries.map((delivery, index) => (\n <li\n key={`${delivery.channelId}|${delivery.recipient}|${index}`}\n className=\"min-w-0 rounded-control border border-border-subtle bg-bg-sunken p-3 text-xs\"\n >\n <div className=\"flex flex-wrap justify-between gap-2\">\n <span className=\"break-all text-text-primary\">\n {delivery.channel} · {delivery.recipient}\n </span>\n <span className=\"font-medium text-text-primary\">{delivery.status}</span>\n </div>\n {delivery.attemptedAt && (\n <p className=\"mt-1 text-text-secondary\">\n {t('bigconsole.alerts.history.attempted', 'Attempted')}{' '}\n <time dateTime={delivery.attemptedAt}>{new Date(delivery.attemptedAt).toLocaleString()}</time>\n </p>\n )}\n {delivery.notificationId && (\n <p className=\"mt-1 break-all text-text-muted\">\n {t('bigconsole.alerts.history.notification', 'Notification')} · {delivery.notificationId}\n </p>\n )}\n {delivery.error && <p className=\"mt-1 break-words text-status-error-text\">{delivery.error}</p>}\n </li>\n ))}\n </ul>\n )}\n </li>\n ))}\n </ol>\n <div className=\"mt-4 flex flex-wrap items-center justify-between gap-control-gap border-t border-border-subtle pt-3\">\n <span className=\"text-xs text-text-secondary\">\n {current.rows.length} {t('bigconsole.alerts.history.count', 'executions on this page')}\n </span>\n <div className=\"flex gap-control-gap\">\n <Button\n type=\"button\"\n variant=\"secondary\"\n size=\"sm\"\n onClick={() => setCursors((previous) => previous.slice(0, -1))}\n disabled={!cursors.length || current.loading}\n >\n {t('bigconsole.alerts.history.newer', 'Newer')}\n </Button>\n <Button\n type=\"button\"\n variant=\"secondary\"\n size=\"sm\"\n onClick={() => {\n const last = current.rows.at(-1);\n if (last) setCursors((previous) => [...previous, last.id]);\n }}\n disabled={!current.hasMore || current.loading}\n >\n {t('bigconsole.alerts.history.older', 'Older')}\n </Button>\n </div>\n </div>\n </Section>\n );\n}\n"],"mappings":";;;;;;;;;;AAoBA,IAAM,IAAqB;CAAE,OAAO;CAAI,MAAM,EAAE;CAAE,SAAS;CAAO,SAAS;CAAO,OAAO;CAAM;AAE/F,SAAgB,EAAsB,EAAE,UAAO,UAAO,SAAM,qBAAyB;CACnF,IAAM,EAAE,SAAM,GAAS,EACjB,CAAC,GAAS,KAAc,EAAS,GAAG,EACpC,CAAC,GAAS,KAAc,EAAmB,EAAE,CAAC,EAC9C,IAAQ,EAAQ,GAAG,GAAG,EACtB,IAAe,GAAG,EAAM,GAAG,EAAQ,GAAG,KAAS,MAC/C,IAAc,EAAsB,KAAK,EACzC,IAAgB,EAAsB,KAAK;AACjD,UACE,EAAY,UAAU,SACT;AAEX,EADA,EAAY,UAAU,MACtB,EAAc,UAAU;KAEzB,CAAC,EAAa,CAAC;CAClB,IAAM,CAAC,GAAO,KAAY,EAAsB,EAAM,EAChD,IAAS,EAAY,YAAY;AACrC,MAAI,EAAY,YAAY,KAAgB,EAAc,QAAS;EACnE,IAAM,IAAU,EAAE;AAElB,EADA,EAAc,UAAU,GACxB,GAAU,OAAc;GACtB,GAAI,EAAS,UAAU,IAAe,IAAW;GACjD,OAAO;GACP,SAAS;GACT,OAAO;GACR,EAAE;AACH,MAAI;GACF,IAAM,IAAO,MAAM,EAAK,KAAW,KAAA,GAAW,EAAM;AACpD,OAAI,EAAY,YAAY,KAAgB,EAAc,YAAY,KAAW,CAAC,EAAM;AACxF,KAAS;IACP,OAAO;IACP,MAAM,EAAK,MAAM,GAAG,GAAG;IACvB,SAAS;IACT,SAAS,EAAK,SAAS;IACvB,OAAO;IACR,CAAC;WACK,GAAO;AACd,GAAI,EAAY,YAAY,KAAgB,EAAc,YAAY,KACpE,GAAU,OAAc;IAAE,GAAG;IAAU,OAAO;IAAc,SAAS;IAAO,OAAO,EAAkB,EAAM;IAAE,EAAE;YACzG;AACR,GAAI,EAAc,YAAY,MAAS,EAAc,UAAU;;IAEhE;EAAC;EAAM;EAAS;EAAO;EAAa,CAAC;AACxC,SAAgB;AACT,UAAQ,SAAS,CAAC,WAAW,GAAQ,CAAC;EAC3C,IAAM,IAAQ,OAAO,kBAAkB;AACrC,GAAI,SAAS,oBAAoB,aAAgB,GAAQ;KACxD,IAAM;AACT,eAAa,OAAO,cAAc,EAAM;IACvC,CAAC,GAAQ,EAAe,CAAC;CAC5B,IAAM,IAAU,EAAM,UAAU,IAAe,IAAQ;EAAE,GAAG;EAAO,SAAS;EAAM;AAClF,QACE,kBAAC,GAAD;EACE,OAAO,EAAE,mCAAmC,oBAAoB;EAChE,cAAc;EACd,aAAa,EACX,yCACA,8GACD;EACD,SACE,kBAAC,GAAD;GAAQ,MAAK;GAAS,SAAQ;GAAY,MAAK;GAAK,eAAe,KAAK,GAAQ;GAAE,UAAU,EAAQ;aAApG,CACG,EAAQ,UAAU,kBAAC,GAAD,EAAS,WAAU,6BAA8B,CAAA,GAAG,kBAAC,GAAD,EAAW,WAAU,gBAAiB,CAAA,EAC5G,EAAE,qCAAqC,kBAAkB,CACnD;;YAXb;GAcE,kBAAC,SAAD;IAAO,SAAQ;IAAuB,WAAU;cAC7C,EAAE,oCAAoC,iBAAiB;IAClD,CAAA;GACR,kBAAC,UAAD;IACE,IAAG;IACH,WAAW,qHAAqH;IAChI,OAAO;IACP,WAAW,MAAU;AAEnB,KADA,EAAW,EAAM,OAAO,MAAM,EAC9B,EAAW,EAAE,CAAC;;cANlB;KASE,kBAAC,UAAD;MAAQ,OAAM;gBAAI,EAAE,iCAAiC,YAAY;MAAU,CAAA;KAC1E,KAAW,CAAC,EAAM,MAAM,MAAS,EAAK,OAAO,EAAQ,IAAI,kBAAC,UAAD;MAAQ,OAAO;gBAAU;MAAiB,CAAA;KACnG,EAAM,KAAK,MACV,kBAAC,UAAD;MAAsB,OAAO,EAAK;gBAC/B,EAAK;MACC,EAFI,EAAK,GAET,CACT;KACK;;GACR,EAAQ,SACP,kBAAC,KAAD;IAAG,MAAK;IAAQ,WAAU;cACvB,EAAQ;IACP,CAAA;GAEL,EAAQ,WAAW,CAAC,EAAQ,KAAK,UAChC,kBAAC,KAAD;IAAG,MAAK;IAAS,WAAU;cACxB,EAAE,qCAAqC,6BAA6B;IACnE,CAAA;GAEL,CAAC,EAAQ,WAAW,CAAC,EAAQ,SAAS,CAAC,EAAQ,KAAK,UACnD,kBAAC,KAAD;IAAG,WAAU;cACV,EACC,mCACA,kGACD;IACC,CAAA;GAEN,kBAAC,MAAD;IAAI,WAAU;cACX,EAAQ,KAAK,KAAK,MACjB,kBAAC,MAAD;KAAuB,WAAU;eAAjC;MACE,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,OAAD;QAAK,WAAU;kBAAf,CACE,kBAAC,KAAD;SAAG,WAAU;mBACV,EAAM,MAAM,MAAS,EAAK,OAAO,EAAU,QAAQ,EAAE,QAAQ,EAAU;SACtE,CAAA,EACJ,kBAAC,QAAD;SAAM,UAAU,EAAU;SAAW,WAAU;mBAC5C,IAAI,KAAK,EAAU,UAAU,CAAC,gBAAgB;SAC1C,CAAA,CACH;WACN,kBAAC,QAAD;QAAM,WAAU;kBACb,EAAE,oCAAoC,EAAU,UAAU,EAAU,OAAO,WAAW,KAAK,IAAI,CAAC;QAC5F,CAAA,CACH;;MACN,kBAAC,KAAD;OAAG,WAAU;iBAAb;QACG,EAAE,yCAAyC,eAAe;QAAC;QAAE,EAAU;QAAQ;QAAI,EAAU;QAAO;QAAG;QACvG,EAAU;QAAW;QACpB;;MACH,EAAU,SAAS,kBAAC,KAAD;OAAG,WAAU;iBAAmD,EAAU;OAAU,CAAA;MACvG,EAAU,WAAW,SAAS,KAC7B,kBAAC,MAAD;OAAI,WAAU;iBACX,EAAU,WAAW,KAAK,GAAU,MACnC,kBAAC,MAAD;QAEE,WAAU;kBAFZ;SAIE,kBAAC,OAAD;UAAK,WAAU;oBAAf,CACE,kBAAC,QAAD;WAAM,WAAU;qBAAhB;YACG,EAAS;YAAQ;YAAI,EAAS;YAC1B;cACP,kBAAC,QAAD;WAAM,WAAU;qBAAiC,EAAS;WAAc,CAAA,CACpE;;SACL,EAAS,eACR,kBAAC,KAAD;UAAG,WAAU;oBAAb;WACG,EAAE,uCAAuC,YAAY;WAAE;WACxD,kBAAC,QAAD;YAAM,UAAU,EAAS;sBAAc,IAAI,KAAK,EAAS,YAAY,CAAC,gBAAgB;YAAQ,CAAA;WAC5F;;SAEL,EAAS,kBACR,kBAAC,KAAD;UAAG,WAAU;oBAAb;WACG,EAAE,0CAA0C,eAAe;WAAC;WAAI,EAAS;WACxE;;SAEL,EAAS,SAAS,kBAAC,KAAD;UAAG,WAAU;oBAA2C,EAAS;UAAU,CAAA;SAC3F;UArBE,GAAG,EAAS,UAAU,GAAG,EAAS,UAAU,GAAG,IAqBjD,CACL;OACC,CAAA;MAEJ;OAhDI,EAAU,GAgDd,CACL;IACC,CAAA;GACL,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,QAAD;KAAM,WAAU;eAAhB;MACG,EAAQ,KAAK;MAAO;MAAE,EAAE,mCAAmC,0BAA0B;MACjF;QACP,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,GAAD;MACE,MAAK;MACL,SAAQ;MACR,MAAK;MACL,eAAe,GAAY,MAAa,EAAS,MAAM,GAAG,GAAG,CAAC;MAC9D,UAAU,CAAC,EAAQ,UAAU,EAAQ;gBAEpC,EAAE,mCAAmC,QAAQ;MACvC,CAAA,EACT,kBAAC,GAAD;MACE,MAAK;MACL,SAAQ;MACR,MAAK;MACL,eAAe;OACb,IAAM,IAAO,EAAQ,KAAK,GAAG,GAAG;AAChC,OAAI,KAAM,GAAY,MAAa,CAAC,GAAG,GAAU,EAAK,GAAG,CAAC;;MAE5D,UAAU,CAAC,EAAQ,WAAW,EAAQ;gBAErC,EAAE,mCAAmC,QAAQ;MACvC,CAAA,CACL;OACF;;GACE"}