@burdenoff/microfe-workflows 2026.923.3 → 2026.1008.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,88 +1,66 @@
1
- # @burdenoff/micro-fe
2
-
3
- Microfrontend packages for Burdenoff products.
4
-
5
- ## Architecture
6
-
7
- This is a **Layer 2 package** - a monolithic package with subpath exports for all microfrontends.
8
-
9
- ## Package Structure
10
-
11
- ```
12
- @burdenoff/micro-fe/
13
- ├── /workflows - Complete workflow builder and management microfrontend
14
- ├── /tags - Tag management system (to be implemented)
15
- └── /auth - Authentication flows (to be implemented)
1
+ # @burdenoff/microfe-workflows
2
+
3
+ Shared Layer 2 workflow UI for Fluidgrids and product shells. This package hosts
4
+ `@burdenoff/fluidgrids-fe-sdk`; product MFEs must not initialize a parallel SDK.
5
+
6
+ ## Host integration
7
+
8
+ Mount inside the shell's gateway providers, router and permission context. The
9
+ shell supplies both workspace and global gateway clients. Wait until workspace
10
+ selection has issued a workspace JWT before mounting:
11
+
12
+ ```tsx
13
+ import { WorkflowsRoot } from '@burdenoff/microfe-workflows';
14
+
15
+ return workspaceId && workspaceToken ? (
16
+ <WorkflowsRoot
17
+ basePath="/myproduct/workflows"
18
+ navigate={navigate}
19
+ currentUser={user}
20
+ productId="myproduct"
21
+ productName="My Product"
22
+ workspaceId={workspaceId}
23
+ workspaceToken={workspaceToken}
24
+ tenantId={tenantId}
25
+ apiGatewayUrl={workspaceGatewayUrl}
26
+ authToken={authToken}
27
+ />
28
+ ) : <div role="status">Loading your workspace…</div>;
16
29
  ```
17
30
 
18
- ## Usage
31
+ `workspaceToken` is required. Upgrading hosts must pass it explicitly and gate
32
+ mounting until it is available; `authToken` alone cannot authorize workspace
33
+ operations. The shell client sends both `Authorization` and
34
+ `X-Workspace-Authorization`. Product selection narrows access; the gateway
35
+ still enforces authentication, product access and RBAC.
19
36
 
20
- ```typescript
21
- import { WorkflowsRoot } from '@burdenoff/micro-fe/workflows';
37
+ Pin the same SDK version in the shell as this package's peer dependency. Include
38
+ this package's published files in Tailwind's source scan. Do not use local source
39
+ aliases to validate a production package build.
22
40
 
23
- // In your host shell
24
- <WorkflowsRoot
25
- basePath="/workflows"
26
- navigate={(path) => navigate(path)}
27
- currentUser={user}
28
- workspaceId={workspaceId}
29
- apiGatewayUrl={apiGatewayUrl}
30
- authToken={authToken}
31
- />
32
- ```
33
-
34
- ## Development
41
+ The provider initializes configuration before the node palette. Gateway, tenant,
42
+ workspace, product or user changes end the execution session and clear old
43
+ selections and local run state. Token and callback refreshes preserve the current
44
+ view. Mount one workflow host at a time.
35
45
 
36
- ```bash
37
- # Install dependencies
38
- bun install
46
+ ## Routes
39
47
 
40
- # Generate GraphQL types
41
- bun run codegen
48
+ Routes are relative to `basePath`:
42
49
 
43
- # Build library
44
- bun run build
50
+ - `list`: workflow definitions
51
+ - `new`: new workflow builder
52
+ - `workflow/:id/:version`: existing workflow builder
53
+ - `runs` and `runs/:runId`: current user's product-scoped runs
54
+ - `insights`, `templates`, `nodes`, `settings`: shared SDK pages
45
55
 
46
- # Type check
47
- bun run type:check
48
-
49
- # Run all checks
50
- bun run sanity
51
- ```
56
+ Product-specific bot or application bindings use the workspace gateway and
57
+ navigate to these routes; they do not own SDK configuration.
52
58
 
53
- ## Workflows Microfrontend
54
-
55
- Complete workflow automation microfrontend with:
56
-
57
- - **WorkflowsList** - List all workflows
58
- - **WorkflowBuilder** - Visual workflow builder with node palette
59
- - **WorkflowRuns** - Execution history
60
- - **WorkflowRunDetails** - Detailed run monitoring
61
-
62
- ### Routes
63
-
64
- - `/` - Workflows list
65
- - `/builder/:workflowKey?` - Workflow builder (create/edit)
66
- - `/runs` - Workflow runs history
67
- - `/runs/:runId` - Run details
68
-
69
- ## GraphQL Integration
70
-
71
- Uses GraphQL Codegen to generate typed hooks from operations:
72
-
73
- ```typescript
74
- import { useGetWorkflowDefinitionsQuery } from './graphql/generated/operations';
75
-
76
- const { data, loading } = useGetWorkflowDefinitionsQuery({
77
- variables: { input: { limit: 10 } }
78
- });
79
- ```
59
+ ## Development
80
60
 
81
- ## Tech Stack
61
+ Run `bun install` and `bun run sanity` to validate lint, formatting, types and the
62
+ published library build. GraphQL operations are owned by the SDK; this wrapper
63
+ has no separate generated operation layer.
82
64
 
83
- - React 19 with TypeScript
84
- - React Router v7
85
- - Apollo Client for GraphQL
86
- - Zustand for state management
87
- - @burdenoff/fe-libs for UI primitives
88
- - TailwindCSS v4 for styling
65
+ The complete reusable guide is in the dev repository:
66
+ `platform/context/automation/fluidgrids/HOW_TO_INTEGRATE_FLUIDGRIDS.md`.
@@ -4,127 +4,134 @@ import { WorkflowsRoutes as n } from "./WorkflowsRoutes.js";
4
4
  import { useEffect as r } from "react";
5
5
  import { ErrorBoundary as i } from "@burdenoff/fe-libs/shared/components";
6
6
  import { AuroraBackground as a, Button as o, IllustratedEmptyState as s } from "@burdenoff/fe-libs/ui";
7
- import { BarChart3 as c, Boxes as l, Database as u, FileCode2 as d, History as f, LayoutDashboard as p, Network as m, PlayCircle as h, RefreshCw as g, Settings as _, Variable as v, Workflow as y } from "lucide-react";
8
- import { jsx as b, jsxs as x } from "react/jsx-runtime";
7
+ import { BarChart3 as c, Boxes as l, Database as u, FileCode2 as d, History as f, LayoutDashboard as p, Network as m, PlayCircle as h, RefreshCw as g, Settings as _, Table2 as v, Variable as y, Workflow as b } from "lucide-react";
8
+ import { jsx as x, jsxs as S } from "react/jsx-runtime";
9
9
  //#region src/WorkflowsRoot.tsx
10
- function S(S) {
11
- let { basePath: C = "/", registerNavItems: w, registerFooterItems: T } = S, E = e();
10
+ function C(C) {
11
+ let { basePath: w = "/", registerNavItems: T, registerFooterItems: E } = C, D = e();
12
12
  return r(() => {
13
- if (!w) return;
13
+ if (!T) return;
14
14
  let e = (e, t) => `${e.endsWith("/") ? e.slice(0, -1) : e}/${t}`, t = [
15
15
  {
16
16
  id: "workflows-list",
17
- label: E("workflows.nav.myWorkflows", "My Workflows"),
18
- path: e(C, "list"),
19
- icon: /* @__PURE__ */ b(y, { size: 18 }),
17
+ label: D("workflows.nav.myWorkflows", "My Workflows"),
18
+ path: e(w, "list"),
19
+ icon: /* @__PURE__ */ x(b, { size: 18 }),
20
20
  order: 2
21
21
  },
22
22
  {
23
23
  id: "workflows-builder",
24
- label: E("workflows.nav.builder", "Builder"),
25
- path: e(C, "new"),
26
- icon: /* @__PURE__ */ b(l, { size: 18 }),
24
+ label: D("workflows.nav.builder", "Builder"),
25
+ path: e(w, "new"),
26
+ icon: /* @__PURE__ */ x(l, { size: 18 }),
27
27
  order: 3
28
28
  },
29
29
  {
30
30
  id: "workflows-runs",
31
- label: E("workflows.nav.runs", "Runs"),
32
- path: e(C, "runs"),
33
- icon: /* @__PURE__ */ b(h, { size: 18 }),
31
+ label: D("workflows.nav.runs", "Runs"),
32
+ path: e(w, "runs"),
33
+ icon: /* @__PURE__ */ x(h, { size: 18 }),
34
34
  order: 4
35
35
  },
36
36
  {
37
37
  id: "workflows-insights",
38
- label: E("workflows.nav.insights", "Insights"),
39
- path: e(C, "insights"),
40
- icon: /* @__PURE__ */ b(c, { size: 18 }),
38
+ label: D("workflows.nav.insights", "Insights"),
39
+ path: e(w, "insights"),
40
+ icon: /* @__PURE__ */ x(c, { size: 18 }),
41
41
  order: 5
42
42
  },
43
43
  {
44
44
  id: "workflows-data-sinks",
45
- label: E("workflows.nav.dataSinks", "DataSinks"),
46
- path: e(C, "data-sinks"),
47
- icon: /* @__PURE__ */ b(u, { size: 18 }),
45
+ label: D("workflows.nav.dataSinks", "DataSinks"),
46
+ path: e(w, "data-sinks"),
47
+ icon: /* @__PURE__ */ x(u, { size: 18 }),
48
48
  order: 6
49
49
  },
50
+ {
51
+ id: "workflows-data-tables",
52
+ label: D("workflows.nav.dataTables", "Data Tables"),
53
+ path: e(w, "data-tables"),
54
+ icon: /* @__PURE__ */ x(v, { size: 18 }),
55
+ order: 7
56
+ },
50
57
  {
51
58
  id: "workflows-history",
52
- label: E("workflows.nav.history", "History"),
53
- path: e(C, "history"),
54
- icon: /* @__PURE__ */ b(f, { size: 18 }),
59
+ label: D("workflows.nav.history", "History"),
60
+ path: e(w, "history"),
61
+ icon: /* @__PURE__ */ x(f, { size: 18 }),
55
62
  order: 7
56
63
  },
57
64
  {
58
65
  id: "workflows-templates",
59
- label: E("workflows.nav.templates", "Templates"),
60
- path: e(C, "templates"),
61
- icon: /* @__PURE__ */ b(p, { size: 18 }),
66
+ label: D("workflows.nav.templates", "Templates"),
67
+ path: e(w, "templates"),
68
+ icon: /* @__PURE__ */ x(p, { size: 18 }),
62
69
  order: 8
63
70
  },
64
71
  {
65
72
  id: "workflows-nodes",
66
- label: E("workflows.nav.nodes", "Nodes"),
67
- path: e(C, "nodes"),
68
- icon: /* @__PURE__ */ b(m, { size: 18 }),
73
+ label: D("workflows.nav.nodes", "Nodes"),
74
+ path: e(w, "nodes"),
75
+ icon: /* @__PURE__ */ x(m, { size: 18 }),
69
76
  order: 9
70
77
  },
71
78
  {
72
79
  id: "workflows-variables",
73
- label: E("workflows.nav.variables", "Variables"),
74
- path: e(C, "variables"),
75
- icon: /* @__PURE__ */ b(v, { size: 18 }),
80
+ label: D("workflows.nav.variables", "Variables"),
81
+ path: e(w, "variables"),
82
+ icon: /* @__PURE__ */ x(y, { size: 18 }),
76
83
  order: 10
77
84
  },
78
85
  {
79
86
  id: "workflows-settings",
80
- label: E("workflows.nav.settings", "Settings"),
81
- path: e(C, "settings"),
82
- icon: /* @__PURE__ */ b(_, { size: 18 }),
87
+ label: D("workflows.nav.settings", "Settings"),
88
+ path: e(w, "settings"),
89
+ icon: /* @__PURE__ */ x(_, { size: 18 }),
83
90
  order: 11
84
91
  }
85
92
  ];
86
- return w([{
93
+ return T([{
87
94
  id: "workflows",
88
- label: E("workflows.nav.title", "Workflows"),
89
- path: C,
90
- icon: /* @__PURE__ */ b(d, { size: 20 }),
95
+ label: D("workflows.nav.title", "Workflows"),
96
+ path: w,
97
+ icon: /* @__PURE__ */ x(d, { size: 20 }),
91
98
  order: 200,
92
99
  group: "workflows",
93
100
  children: t
94
101
  }]);
95
102
  }, [
103
+ T,
96
104
  w,
97
- C,
98
- E
105
+ D
99
106
  ]), r(() => {
100
- if (T) return T([{
107
+ if (E) return E([{
101
108
  id: "workflows-status",
102
- label: E("workflows.footer.status", "Workflows Ready"),
109
+ label: D("workflows.footer.status", "Workflows Ready"),
103
110
  type: "status",
104
111
  order: 10,
105
112
  section: "left"
106
113
  }]);
107
- }, [T, E]), /* @__PURE__ */ b(i, {
108
- fallback: /* @__PURE__ */ x("div", {
114
+ }, [E, D]), /* @__PURE__ */ x(i, {
115
+ fallback: /* @__PURE__ */ S("div", {
109
116
  className: "relative flex min-h-[60vh] w-full items-center justify-center overflow-hidden px-4 py-10",
110
- children: [/* @__PURE__ */ b(a, { intensity: "subtle" }), /* @__PURE__ */ b(s, {
117
+ children: [/* @__PURE__ */ x(a, { intensity: "subtle" }), /* @__PURE__ */ x(s, {
111
118
  illustration: "empty-generic",
112
- title: E("workflows.error.title", "Workflows hit a snag"),
113
- description: E("workflows.error.loadFailed", "Something went wrong loading this module. Please refresh the page."),
114
- action: /* @__PURE__ */ x(o, {
119
+ title: D("workflows.error.title", "Workflows hit a snag"),
120
+ description: D("workflows.error.loadFailed", "Something went wrong loading this module. Please refresh the page."),
121
+ action: /* @__PURE__ */ S(o, {
115
122
  onClick: () => window.location.reload(),
116
- children: [/* @__PURE__ */ b(g, {
123
+ children: [/* @__PURE__ */ x(g, {
117
124
  className: "size-4",
118
125
  "aria-hidden": "true"
119
- }), E("workflows.error.refresh", "Refresh page")]
126
+ }), D("workflows.error.refresh", "Refresh page")]
120
127
  })
121
128
  })]
122
129
  }),
123
- children: /* @__PURE__ */ b(t, {
124
- ...S,
125
- children: /* @__PURE__ */ b(n, {})
126
- })
130
+ children: /* @__PURE__ */ x(t, {
131
+ ...C,
132
+ children: /* @__PURE__ */ x(n, {})
133
+ }, `${C.apiGatewayUrl ?? ""}:${C.tenantId ?? ""}:${C.workspaceId ?? ""}:${C.productId ?? ""}:${C.currentUser?.id ?? ""}`)
127
134
  });
128
135
  }
129
136
  //#endregion
130
- export { S as WorkflowsRoot };
137
+ export { C as WorkflowsRoot };
@@ -3,36 +3,36 @@ import { WORKFLOW_PERMISSIONS as t } from "./constants/permissions.js";
3
3
  import { Suspense as n } from "react";
4
4
  import { AccessDenied as r, PermissionGate as i } from "@burdenoff/fe-libs/shared/components";
5
5
  import { GlassCard as a } from "@burdenoff/fe-libs/ui";
6
- import { ApprovalInboxPage as o, DataSinkDashboardPage as s, ErrorAnalyticsPage as c, ExecutionDetailPage as l, ExecutionsListPage as u, HistoryPage as d, InsightsPage as f, NodesPage as p, SettingsPage as m, TemplatePreview as h, TemplatesPage as g, VariablesPage as _, WorkflowBuilderPage as v, WorkflowSearchRedirect as y, WorkflowsList as b } from "@burdenoff/fluidgrids-fe-sdk";
7
- import { jsx as x, jsxs as S } from "react/jsx-runtime";
8
- import { Navigate as C, Route as w, Routes as T, useParams as E } from "react-router";
6
+ import { ApprovalInboxPage as o, DataSinkDashboardPage as s, DataTablesPage as c, ErrorAnalyticsPage as l, ExecutionDetailPage as u, ExecutionsListPage as d, HistoryPage as f, InsightsPage as p, NodesPage as m, SettingsPage as h, TemplatePreview as g, TemplatesPage as _, VariablesPage as v, WorkflowBuilderPage as y, WorkflowSearchRedirect as b, WorkflowsList as x } from "@burdenoff/fluidgrids-fe-sdk";
7
+ import { jsx as S, jsxs as C } from "react/jsx-runtime";
8
+ import { Navigate as w, Route as T, Routes as E, useParams as D } from "react-router";
9
9
  //#region src/WorkflowsRoutes.tsx
10
- function D() {
10
+ function O() {
11
11
  let t = e();
12
- return /* @__PURE__ */ S("div", {
12
+ return /* @__PURE__ */ C("div", {
13
13
  className: "mx-auto flex w-full max-w-6xl flex-col gap-6 px-4 py-6 sm:px-6",
14
14
  role: "status",
15
15
  "aria-live": "polite",
16
16
  "aria-busy": "true",
17
17
  "aria-label": t("workflows.routes.loading.ariaLabel", "Loading workflow page"),
18
18
  children: [
19
- /* @__PURE__ */ S("div", {
19
+ /* @__PURE__ */ C("div", {
20
20
  className: "flex flex-col gap-3",
21
- children: [/* @__PURE__ */ x("div", { className: "h-7 w-48 rounded-md bg-muted/60 motion-safe:animate-vc-shimmer" }), /* @__PURE__ */ x("div", { className: "h-4 w-72 max-w-full rounded bg-muted/40 motion-safe:animate-vc-shimmer" })]
21
+ children: [/* @__PURE__ */ S("div", { className: "h-7 w-48 rounded-md bg-muted/60 motion-safe:animate-vc-shimmer" }), /* @__PURE__ */ S("div", { className: "h-4 w-72 max-w-full rounded bg-muted/40 motion-safe:animate-vc-shimmer" })]
22
22
  }),
23
- /* @__PURE__ */ x("div", {
23
+ /* @__PURE__ */ S("div", {
24
24
  className: "grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3",
25
25
  children: [
26
26
  0,
27
27
  1,
28
28
  2
29
- ].map((e) => /* @__PURE__ */ S(a, {
29
+ ].map((e) => /* @__PURE__ */ C(a, {
30
30
  treatment: "metric",
31
31
  className: "flex flex-col gap-3 border-border-seam p-5",
32
- children: [/* @__PURE__ */ x("div", { className: "h-3 w-20 rounded bg-muted/50 motion-safe:animate-vc-shimmer" }), /* @__PURE__ */ x("div", { className: "h-8 w-24 rounded-md bg-muted/60 motion-safe:animate-vc-shimmer" })]
32
+ children: [/* @__PURE__ */ S("div", { className: "h-3 w-20 rounded bg-muted/50 motion-safe:animate-vc-shimmer" }), /* @__PURE__ */ S("div", { className: "h-8 w-24 rounded-md bg-muted/60 motion-safe:animate-vc-shimmer" })]
33
33
  }, e))
34
34
  }),
35
- /* @__PURE__ */ x(a, {
35
+ /* @__PURE__ */ S(a, {
36
36
  treatment: "glass",
37
37
  className: "flex flex-col gap-4 border-border-seam p-6",
38
38
  children: [
@@ -40,162 +40,166 @@ function D() {
40
40
  1,
41
41
  2,
42
42
  3
43
- ].map((e) => /* @__PURE__ */ S("div", {
43
+ ].map((e) => /* @__PURE__ */ C("div", {
44
44
  className: "flex items-center gap-4",
45
- children: [/* @__PURE__ */ x("div", { className: "h-10 w-10 shrink-0 rounded-full bg-muted/50 motion-safe:animate-vc-shimmer" }), /* @__PURE__ */ S("div", {
45
+ children: [/* @__PURE__ */ S("div", { className: "h-10 w-10 shrink-0 rounded-full bg-muted/50 motion-safe:animate-vc-shimmer" }), /* @__PURE__ */ C("div", {
46
46
  className: "flex flex-1 flex-col gap-2",
47
- children: [/* @__PURE__ */ x("div", { className: "h-4 w-1/3 rounded bg-muted/50 motion-safe:animate-vc-shimmer" }), /* @__PURE__ */ x("div", { className: "h-3 w-2/3 rounded bg-muted/30 motion-safe:animate-vc-shimmer" })]
47
+ children: [/* @__PURE__ */ S("div", { className: "h-4 w-1/3 rounded bg-muted/50 motion-safe:animate-vc-shimmer" }), /* @__PURE__ */ S("div", { className: "h-3 w-2/3 rounded bg-muted/30 motion-safe:animate-vc-shimmer" })]
48
48
  })]
49
49
  }, e))
50
50
  }),
51
- /* @__PURE__ */ x("p", {
51
+ /* @__PURE__ */ S("p", {
52
52
  className: "text-center text-sm text-text-secondary",
53
53
  children: t("workflows.routes.loading.message", "Loading workflow page...")
54
54
  })
55
55
  ]
56
56
  });
57
57
  }
58
- function O() {
59
- let { runId: e } = E();
60
- return /* @__PURE__ */ x(C, {
58
+ function k() {
59
+ let { runId: e } = D();
60
+ return /* @__PURE__ */ S(w, {
61
61
  to: `../runs/${e}`,
62
62
  replace: !0
63
63
  });
64
64
  }
65
- function k() {
66
- return /* @__PURE__ */ x(n, {
67
- fallback: /* @__PURE__ */ x(D, {}),
68
- children: /* @__PURE__ */ S(T, { children: [
69
- /* @__PURE__ */ x(w, {
65
+ function A() {
66
+ return /* @__PURE__ */ S(n, {
67
+ fallback: /* @__PURE__ */ S(O, {}),
68
+ children: /* @__PURE__ */ C(E, { children: [
69
+ /* @__PURE__ */ S(T, {
70
70
  index: !0,
71
- element: /* @__PURE__ */ x(C, {
71
+ element: /* @__PURE__ */ S(w, {
72
72
  to: "list",
73
73
  replace: !0
74
74
  })
75
75
  }),
76
- /* @__PURE__ */ x(w, {
76
+ /* @__PURE__ */ S(T, {
77
77
  path: "list",
78
- element: /* @__PURE__ */ x(b, {})
78
+ element: /* @__PURE__ */ S(x, {})
79
79
  }),
80
- /* @__PURE__ */ x(w, {
80
+ /* @__PURE__ */ S(T, {
81
81
  path: "new",
82
- element: /* @__PURE__ */ x(v, {})
82
+ element: /* @__PURE__ */ S(y, {})
83
83
  }),
84
- /* @__PURE__ */ x(w, {
84
+ /* @__PURE__ */ S(T, {
85
85
  path: "workflow/:id/:version",
86
- element: /* @__PURE__ */ x(v, {})
86
+ element: /* @__PURE__ */ S(y, {})
87
87
  }),
88
- /* @__PURE__ */ x(w, {
88
+ /* @__PURE__ */ S(T, {
89
89
  path: "builder",
90
- element: /* @__PURE__ */ x(C, {
90
+ element: /* @__PURE__ */ S(w, {
91
91
  to: "../new",
92
92
  replace: !0
93
93
  })
94
94
  }),
95
- /* @__PURE__ */ x(w, {
95
+ /* @__PURE__ */ S(T, {
96
96
  path: "builder/:id/:version",
97
- element: /* @__PURE__ */ x(v, {})
97
+ element: /* @__PURE__ */ S(y, {})
98
98
  }),
99
- /* @__PURE__ */ x(w, {
99
+ /* @__PURE__ */ S(T, {
100
100
  path: "resolve/:id",
101
- element: /* @__PURE__ */ x(y, {})
101
+ element: /* @__PURE__ */ S(b, {})
102
102
  }),
103
- /* @__PURE__ */ x(w, {
103
+ /* @__PURE__ */ S(T, {
104
104
  path: "runs",
105
- element: /* @__PURE__ */ x(u, {})
105
+ element: /* @__PURE__ */ S(d, {})
106
106
  }),
107
- /* @__PURE__ */ x(w, {
107
+ /* @__PURE__ */ S(T, {
108
108
  path: "runs/:runId",
109
- element: /* @__PURE__ */ x(l, {})
109
+ element: /* @__PURE__ */ S(u, {})
110
110
  }),
111
- /* @__PURE__ */ x(w, {
111
+ /* @__PURE__ */ S(T, {
112
112
  path: "insights",
113
- element: /* @__PURE__ */ x(f, {})
113
+ element: /* @__PURE__ */ S(p, {})
114
114
  }),
115
- /* @__PURE__ */ x(w, {
115
+ /* @__PURE__ */ S(T, {
116
116
  path: "insights/errors",
117
- element: /* @__PURE__ */ x(c, {})
117
+ element: /* @__PURE__ */ S(l, {})
118
118
  }),
119
- /* @__PURE__ */ x(w, {
119
+ /* @__PURE__ */ S(T, {
120
120
  path: "data-sinks",
121
- element: /* @__PURE__ */ x(s, {})
121
+ element: /* @__PURE__ */ S(s, {})
122
+ }),
123
+ /* @__PURE__ */ S(T, {
124
+ path: "data-tables",
125
+ element: /* @__PURE__ */ S(c, {})
122
126
  }),
123
- /* @__PURE__ */ x(w, {
127
+ /* @__PURE__ */ S(T, {
124
128
  path: "approvals",
125
- element: /* @__PURE__ */ x(i, {
129
+ element: /* @__PURE__ */ S(i, {
126
130
  permission: t.WORKFLOW_RUN_READ,
127
- fallback: /* @__PURE__ */ x(r, {}),
128
- children: /* @__PURE__ */ x(o, {})
131
+ fallback: /* @__PURE__ */ S(r, {}),
132
+ children: /* @__PURE__ */ S(o, {})
129
133
  })
130
134
  }),
131
- /* @__PURE__ */ x(w, {
135
+ /* @__PURE__ */ S(T, {
132
136
  path: "history",
133
- element: /* @__PURE__ */ x(d, {})
137
+ element: /* @__PURE__ */ S(f, {})
134
138
  }),
135
- /* @__PURE__ */ x(w, {
139
+ /* @__PURE__ */ S(T, {
136
140
  path: "templates",
137
- element: /* @__PURE__ */ x(g, {})
141
+ element: /* @__PURE__ */ S(_, {})
138
142
  }),
139
- /* @__PURE__ */ x(w, {
143
+ /* @__PURE__ */ S(T, {
140
144
  path: "templates/:productId/preview",
141
- element: /* @__PURE__ */ x(h, {})
145
+ element: /* @__PURE__ */ S(g, {})
142
146
  }),
143
- /* @__PURE__ */ x(w, {
147
+ /* @__PURE__ */ S(T, {
144
148
  path: "nodes",
145
- element: /* @__PURE__ */ x(p, {})
149
+ element: /* @__PURE__ */ S(m, {})
146
150
  }),
147
- /* @__PURE__ */ x(w, {
151
+ /* @__PURE__ */ S(T, {
148
152
  path: "settings",
149
- element: /* @__PURE__ */ x(i, {
153
+ element: /* @__PURE__ */ S(i, {
150
154
  permission: t.SYSTEM_CONFIG_READ,
151
- fallback: /* @__PURE__ */ x(r, {}),
152
- children: /* @__PURE__ */ x(m, {})
155
+ fallback: /* @__PURE__ */ S(r, {}),
156
+ children: /* @__PURE__ */ S(h, {})
153
157
  })
154
158
  }),
155
- /* @__PURE__ */ x(w, {
159
+ /* @__PURE__ */ S(T, {
156
160
  path: "settings/:workflowKey",
157
- element: /* @__PURE__ */ x(i, {
161
+ element: /* @__PURE__ */ S(i, {
158
162
  permission: t.SYSTEM_CONFIG_READ,
159
- fallback: /* @__PURE__ */ x(r, {}),
160
- children: /* @__PURE__ */ x(m, {})
163
+ fallback: /* @__PURE__ */ S(r, {}),
164
+ children: /* @__PURE__ */ S(h, {})
161
165
  })
162
166
  }),
163
- /* @__PURE__ */ x(w, {
167
+ /* @__PURE__ */ S(T, {
164
168
  path: "variables",
165
- element: /* @__PURE__ */ x(i, {
169
+ element: /* @__PURE__ */ S(i, {
166
170
  permission: t.VARIABLE_READ,
167
- fallback: /* @__PURE__ */ x(r, {}),
168
- children: /* @__PURE__ */ x(_, {})
171
+ fallback: /* @__PURE__ */ S(r, {}),
172
+ children: /* @__PURE__ */ S(v, {})
169
173
  })
170
174
  }),
171
- /* @__PURE__ */ x(w, {
175
+ /* @__PURE__ */ S(T, {
172
176
  path: "executions",
173
- element: /* @__PURE__ */ x(C, {
177
+ element: /* @__PURE__ */ S(w, {
174
178
  to: "../runs",
175
179
  replace: !0
176
180
  })
177
181
  }),
178
- /* @__PURE__ */ x(w, {
182
+ /* @__PURE__ */ S(T, {
179
183
  path: "executions/:runId",
180
- element: /* @__PURE__ */ x(O, {})
184
+ element: /* @__PURE__ */ S(k, {})
181
185
  }),
182
- /* @__PURE__ */ x(w, {
186
+ /* @__PURE__ */ S(T, {
183
187
  path: "credentials",
184
- element: /* @__PURE__ */ x(C, {
188
+ element: /* @__PURE__ */ S(w, {
185
189
  to: "/integrations/connections",
186
190
  replace: !0
187
191
  })
188
192
  }),
189
- /* @__PURE__ */ x(w, {
193
+ /* @__PURE__ */ S(T, {
190
194
  path: "oauth/callback",
191
- element: /* @__PURE__ */ x(C, {
195
+ element: /* @__PURE__ */ S(w, {
192
196
  to: "/integrations/connections",
193
197
  replace: !0
194
198
  })
195
199
  }),
196
- /* @__PURE__ */ x(w, {
200
+ /* @__PURE__ */ S(T, {
197
201
  path: "*",
198
- element: /* @__PURE__ */ x(C, {
202
+ element: /* @__PURE__ */ S(w, {
199
203
  to: "list",
200
204
  replace: !0
201
205
  })
@@ -204,4 +208,4 @@ function k() {
204
208
  });
205
209
  }
206
210
  //#endregion
207
- export { k as WorkflowsRoutes };
211
+ export { A as WorkflowsRoutes };
@@ -1,85 +1,102 @@
1
1
  import { setWorkflowsConfig as e } from "../config/index.js";
2
2
  import { useWorkflowsTranslation as t } from "../i18n.js";
3
- import { createContext as n, useEffect as r, useState as i } from "react";
4
- import { EmphasisPanel as a, GlassCard as o, IllustratedEmptyState as s, NextSteps as c, PagePurpose as l } from "@burdenoff/fe-libs/ui";
5
- import { Boxes as u, LayoutDashboard as d, Workflow as f } from "lucide-react";
6
- import { FluidGridsPermissionsProvider as p, FluidGridsTranslationProvider as m, refetchStoreNodes as h, resetFluidGridsClient as g, resetGlobalStoreClient as _, setFluidGridsClient as v, setFluidGridsConfig as y, setGlobalStoreClient as b } from "@burdenoff/fluidgrids-fe-sdk";
7
- import { useGatewayClient as x } from "@burdenoff/fe-libs/shared/graphql";
8
- import { PermissionProvider as S, usePermissions as C } from "@burdenoff/fe-libs/shared/providers/shell";
9
- import { jsx as w, jsxs as T } from "react/jsx-runtime";
3
+ import { createContext as n, useEffect as r, useState as i, useSyncExternalStore as a } from "react";
4
+ import { EmphasisPanel as o, GlassCard as s, IllustratedEmptyState as c, NextSteps as l, PagePurpose as u } from "@burdenoff/fe-libs/ui";
5
+ import { Boxes as d, LayoutDashboard as f, Workflow as p } from "lucide-react";
6
+ import { FluidGridsPermissionsProvider as m, FluidGridsTranslationProvider as h, refetchStoreNodes as g, resetFluidGridsClient as _, resetFluidGridsConfig as v, resetFluidGridsExecutionState as y, resetGlobalStoreClient as b, setFluidGridsClient as x, setFluidGridsConfig as S, setGlobalStoreClient as C } from "@burdenoff/fluidgrids-fe-sdk";
7
+ import { useGatewayClient as w } from "@burdenoff/fe-libs/shared/graphql";
8
+ import { PermissionProvider as T, usePermissions as E } from "@burdenoff/fe-libs/shared/providers/shell";
9
+ import { jsx as D, jsxs as O } from "react/jsx-runtime";
10
10
  //#region src/providers/WorkflowsProvider.tsx
11
- var E = n(null);
12
- function D({ children: e }) {
13
- let { hasPermission: t, isLoading: n } = C();
14
- return /* @__PURE__ */ w(p, {
11
+ var k = n(null);
12
+ function A({ children: e }) {
13
+ let { hasPermission: t, isLoading: n } = E();
14
+ return /* @__PURE__ */ D(m, {
15
15
  hasPermission: t,
16
16
  isLoading: n,
17
17
  children: e
18
18
  });
19
19
  }
20
- function O(e) {
20
+ function j(e) {
21
21
  let t = e.endsWith("/") ? e.slice(0, -1) : e;
22
22
  return t.endsWith("/graphql") ? t : `${t}/workspaces/graphql`;
23
23
  }
24
- function k({ children: n, ...p }) {
25
- let C = t(), k = x("workspace"), A = x("global"), [j, M] = i(!1);
26
- if (r(() => (k && A && (v(k), b(A), h(), M(!0)), () => {
27
- g(), _(), M(!1);
28
- }), [k, A]), r(() => {
29
- if (p.apiGatewayUrl) {
30
- let t = O(p.apiGatewayUrl), n = p.apiGatewayUrl.endsWith("/") ? p.apiGatewayUrl.slice(0, -1) : p.apiGatewayUrl;
31
- e({
32
- workflowSvcUrl: t,
33
- apiGatewayUrl: n
34
- });
35
- let r = p.callbacks?.onWorkflowSaved;
36
- y({
37
- apiGatewayUrl: n,
38
- authToken: p.authToken,
39
- workspaceId: p.workspaceId ?? "",
40
- tenantId: p.tenantId,
41
- productId: p.productId,
42
- productName: p.productName,
43
- onWorkflowSaved: r
44
- });
45
- }
24
+ function M({ children: n, ...m }) {
25
+ let E = t(), M = w("workspace"), N = w("global"), [P] = i(() => {
26
+ let e = !1, t = /* @__PURE__ */ new Set();
27
+ return {
28
+ subscribe: (e) => (t.add(e), () => {
29
+ t.delete(e);
30
+ }),
31
+ snapshot: () => e,
32
+ set: (n) => {
33
+ e = n;
34
+ for (let e of t) e();
35
+ }
36
+ };
37
+ }), F = a(P.subscribe, P.snapshot, () => !1);
38
+ if (r(() => (y(), y), []), r(() => {
39
+ if (!m.apiGatewayUrl || !m.productId || !m.workspaceId || !m.workspaceToken || !M || !N) return;
40
+ let t = m.apiGatewayUrl.replace(/\/+$/, "");
41
+ e({
42
+ workflowSvcUrl: j(t),
43
+ apiGatewayUrl: t
44
+ });
45
+ let n = m.callbacks?.onWorkflowSaved;
46
+ return S({
47
+ apiGatewayUrl: t,
48
+ authToken: m.authToken,
49
+ workspaceId: m.workspaceId,
50
+ tenantId: m.tenantId,
51
+ productId: m.productId,
52
+ productName: m.productName,
53
+ onWorkflowSaved: n
54
+ }), x(M), C(N), g().catch((e) => {
55
+ console.warn("[Workflows] Could not refresh installed nodes", e);
56
+ }), P.set(!0), () => {
57
+ P.set(!1), _(), b(), v();
58
+ };
46
59
  }, [
47
- p.apiGatewayUrl,
48
- p.authToken,
49
- p.workspaceId,
50
- p.tenantId,
51
- p.productId,
52
- p.productName,
53
- p.callbacks
54
- ]), !p.workspaceId) {
55
- let e = (e, t) => `${e.endsWith("/") ? e.slice(0, -1) : e}/${t}`, t = (t) => p.navigate(e(p.basePath ?? "/", t));
56
- return /* @__PURE__ */ T("div", {
60
+ P,
61
+ M,
62
+ N,
63
+ m.apiGatewayUrl,
64
+ m.authToken,
65
+ m.workspaceToken,
66
+ m.workspaceId,
67
+ m.tenantId,
68
+ m.productId,
69
+ m.productName,
70
+ m.callbacks
71
+ ]), !m.workspaceId) {
72
+ let e = (e, t) => `${e.endsWith("/") ? e.slice(0, -1) : e}/${t}`, t = (t) => m.navigate(e(m.basePath ?? "/", t));
73
+ return /* @__PURE__ */ O("div", {
57
74
  className: "mx-auto flex h-full min-h-[60vh] w-full max-w-2xl flex-col justify-center gap-6 px-4 py-10",
58
75
  children: [
59
- /* @__PURE__ */ w(l, {
60
- icon: /* @__PURE__ */ w(f, {
76
+ /* @__PURE__ */ D(u, {
77
+ icon: /* @__PURE__ */ D(p, {
61
78
  className: "size-4",
62
79
  "aria-hidden": "true"
63
80
  }),
64
- children: C("workflows.provider.purpose", "Workflows let you automate multi-step processes — for example, sync a new signup into your CRM, post run results to Slack, or transform and route data between apps. You build them visually by wiring nodes together, then trigger them on a schedule, a webhook, or on demand.")
81
+ children: E("workflows.provider.purpose", "Workflows let you automate multi-step processes — for example, sync a new signup into your CRM, post run results to Slack, or transform and route data between apps. You build them visually by wiring nodes together, then trigger them on a schedule, a webhook, or on demand.")
65
82
  }),
66
- /* @__PURE__ */ w(a, {
83
+ /* @__PURE__ */ D(o, {
67
84
  className: "p-6",
68
- children: /* @__PURE__ */ w(s, {
85
+ children: /* @__PURE__ */ D(c, {
69
86
  illustration: "onboarding",
70
- title: C("workflows.provider.workspaceRequired.title", "Pick a workspace to start building"),
71
- description: C("workflows.provider.workspaceRequired.description", "Workflows live inside a workspace so your automations, runs, and connections stay scoped to the right team. Select or create an active workspace from the shell to load your workflows.")
87
+ title: E("workflows.provider.workspaceRequired.title", "Pick a workspace to start building"),
88
+ description: E("workflows.provider.workspaceRequired.description", "Workflows live inside a workspace so your automations, runs, and connections stay scoped to the right team. Select or create an active workspace from the shell to load your workflows.")
72
89
  })
73
90
  }),
74
- /* @__PURE__ */ w(c, {
91
+ /* @__PURE__ */ D(l, {
75
92
  storageKey: "workflows-get-started",
76
- title: C("workflows.provider.nextSteps.title", "Once your workspace is active"),
93
+ title: E("workflows.provider.nextSteps.title", "Once your workspace is active"),
77
94
  steps: [
78
95
  {
79
96
  id: "open-workflows",
80
- label: C("workflows.provider.nextSteps.open.label", "Open your workflows"),
81
- description: C("workflows.provider.nextSteps.open.description", "Browse, search, and manage every automation in this workspace."),
82
- icon: /* @__PURE__ */ w(f, {
97
+ label: E("workflows.provider.nextSteps.open.label", "Open your workflows"),
98
+ description: E("workflows.provider.nextSteps.open.description", "Browse, search, and manage every automation in this workspace."),
99
+ icon: /* @__PURE__ */ D(p, {
83
100
  className: "size-4",
84
101
  "aria-hidden": "true"
85
102
  }),
@@ -87,9 +104,9 @@ function k({ children: n, ...p }) {
87
104
  },
88
105
  {
89
106
  id: "start-template",
90
- label: C("workflows.provider.nextSteps.template.label", "Start from a template"),
91
- description: C("workflows.provider.nextSteps.template.description", "Skip the blank canvas — adapt a ready-made workflow to your use-case."),
92
- icon: /* @__PURE__ */ w(d, {
107
+ label: E("workflows.provider.nextSteps.template.label", "Start from a template"),
108
+ description: E("workflows.provider.nextSteps.template.description", "Skip the blank canvas — adapt a ready-made workflow to your use-case."),
109
+ icon: /* @__PURE__ */ D(f, {
93
110
  className: "size-4",
94
111
  "aria-hidden": "true"
95
112
  }),
@@ -97,9 +114,9 @@ function k({ children: n, ...p }) {
97
114
  },
98
115
  {
99
116
  id: "build-new",
100
- label: C("workflows.provider.nextSteps.build.label", "Build a workflow from scratch"),
101
- description: C("workflows.provider.nextSteps.build.description", "Open the visual builder and wire nodes together step by step."),
102
- icon: /* @__PURE__ */ w(u, {
117
+ label: E("workflows.provider.nextSteps.build.label", "Build a workflow from scratch"),
118
+ description: E("workflows.provider.nextSteps.build.description", "Open the visual builder and wire nodes together step by step."),
119
+ icon: /* @__PURE__ */ D(d, {
103
120
  className: "size-4",
104
121
  "aria-hidden": "true"
105
122
  }),
@@ -110,35 +127,35 @@ function k({ children: n, ...p }) {
110
127
  ]
111
128
  });
112
129
  }
113
- return j ? /* @__PURE__ */ w(E.Provider, {
114
- value: p,
115
- children: /* @__PURE__ */ w(m, {
116
- t: C,
117
- children: /* @__PURE__ */ w(S, {
118
- scopeId: p.workspaceId ?? null,
119
- gateway: "workspace",
120
- children: /* @__PURE__ */ w(D, { children: n })
121
- })
122
- })
123
- }) : /* @__PURE__ */ T("div", {
130
+ return !F || !m.workspaceToken || !m.productId ? /* @__PURE__ */ O("div", {
124
131
  className: "mx-auto flex h-full min-h-[60vh] w-full max-w-md flex-col items-center justify-center gap-4 px-4 py-10 text-center",
125
132
  role: "status",
126
133
  "aria-live": "polite",
127
134
  "aria-busy": "true",
128
- "aria-label": C("workflows.provider.loading.ariaLabel", "Loading workflows"),
129
- children: [/* @__PURE__ */ T(o, {
135
+ "aria-label": E("workflows.provider.loading.ariaLabel", "Loading workflows"),
136
+ children: [/* @__PURE__ */ O(s, {
130
137
  treatment: "glass",
131
138
  className: "flex w-full flex-col items-center gap-4 border-border-seam p-6",
132
139
  children: [
133
- /* @__PURE__ */ w("div", { className: "h-12 w-12 rounded-full bg-muted/60 motion-safe:animate-vc-shimmer" }),
134
- /* @__PURE__ */ w("div", { className: "h-4 w-40 rounded bg-muted/50 motion-safe:animate-vc-shimmer" }),
135
- /* @__PURE__ */ w("div", { className: "h-3 w-56 max-w-full rounded bg-muted/30 motion-safe:animate-vc-shimmer" })
140
+ /* @__PURE__ */ D("div", { className: "h-12 w-12 rounded-full bg-muted/60 motion-safe:animate-vc-shimmer" }),
141
+ /* @__PURE__ */ D("div", { className: "h-4 w-40 rounded bg-muted/50 motion-safe:animate-vc-shimmer" }),
142
+ /* @__PURE__ */ D("div", { className: "h-3 w-56 max-w-full rounded bg-muted/30 motion-safe:animate-vc-shimmer" })
136
143
  ]
137
- }), /* @__PURE__ */ w("p", {
144
+ }), /* @__PURE__ */ D("p", {
138
145
  className: "text-sm text-text-secondary",
139
- children: C("workflows.provider.loading.message", "Connecting workflows...")
146
+ children: E("workflows.provider.loading.message", "Connecting workflows...")
140
147
  })]
148
+ }) : /* @__PURE__ */ D(k.Provider, {
149
+ value: m,
150
+ children: /* @__PURE__ */ D(h, {
151
+ t: E,
152
+ children: /* @__PURE__ */ D(T, {
153
+ scopeId: m.workspaceId ?? null,
154
+ gateway: "workspace",
155
+ children: /* @__PURE__ */ D(A, { children: n })
156
+ })
157
+ })
141
158
  });
142
159
  }
143
160
  //#endregion
144
- export { k as WorkflowsProvider };
161
+ export { M as WorkflowsProvider };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@burdenoff/microfe-workflows",
3
- "version": "2026.923.3",
3
+ "version": "2026.1008.1",
4
4
  "description": "Workflows microfrontend for Burdenoff products - thin shell over @burdenoff/fluidgrids-fe-sdk",
5
5
  "type": "module",
6
6
  "exports": {
@@ -35,7 +35,7 @@
35
35
  "react-router": "^8.3.0"
36
36
  },
37
37
  "devDependencies": {
38
- "@burdenoff/fluidgrids-fe-sdk": "2026.923.2",
38
+ "@burdenoff/fluidgrids-fe-sdk": "2026.1008.3",
39
39
  "@eslint/js": "^9.39.2",
40
40
  "@types/react": "^19.0.2",
41
41
  "@types/react-dom": "^19.0.2",
@@ -55,7 +55,7 @@
55
55
  "vite-plugin-dts": "3.9.1"
56
56
  },
57
57
  "peerDependencies": {
58
- "@burdenoff/fluidgrids-fe-sdk": "2026.923.2",
58
+ "@burdenoff/fluidgrids-fe-sdk": "2026.1008.3",
59
59
  "react": "^19.0.0",
60
60
  "react-dom": "^19.0.0"
61
61
  },