@burdenoff/microfe-subscriberbot 2026.706.2 → 2026.706.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/subscriberbot/SubscriberBotRoutes.js +14 -6
- package/dist/subscriberbot/SubscriberBotRoutes.js.map +1 -1
- package/dist/subscriberbot/components/index.js +7 -0
- package/dist/subscriberbot/components/viz.js +196 -0
- package/dist/subscriberbot/components/viz.js.map +1 -0
- package/dist/subscriberbot/hooks/useSubscriberBotApi.js +38 -30
- package/dist/subscriberbot/hooks/useSubscriberBotApi.js.map +1 -1
- package/dist/subscriberbot/pages/AssetVaultPage.js +182 -0
- package/dist/subscriberbot/pages/AssetVaultPage.js.map +1 -0
- package/dist/subscriberbot/pages/DashboardPage.js +272 -199
- package/dist/subscriberbot/pages/DashboardPage.js.map +1 -1
- package/dist/subscriberbot/pages/InboxPage.js +517 -234
- package/dist/subscriberbot/pages/InboxPage.js.map +1 -1
- package/dist/subscriberbot/pages/InsightsPage.js +220 -0
- package/dist/subscriberbot/pages/InsightsPage.js.map +1 -0
- package/dist/subscriberbot/pages/InvoicesPage.js +325 -237
- package/dist/subscriberbot/pages/InvoicesPage.js.map +1 -1
- package/dist/subscriberbot/pages/WorkflowsPage.js +301 -112
- package/dist/subscriberbot/pages/WorkflowsPage.js.map +1 -1
- package/dist/subscriberbot/pages/agents/AgentDetailPage.js +311 -165
- package/dist/subscriberbot/pages/agents/AgentDetailPage.js.map +1 -1
- package/dist/subscriberbot/pages/agents/AgentsListPage.js +183 -93
- package/dist/subscriberbot/pages/agents/AgentsListPage.js.map +1 -1
- package/dist/subscriberbot/pages/providers/ProviderDetailPage.js +426 -293
- package/dist/subscriberbot/pages/providers/ProviderDetailPage.js.map +1 -1
- package/dist/subscriberbot/pages/providers/ProviderNewPage.js +217 -153
- package/dist/subscriberbot/pages/providers/ProviderNewPage.js.map +1 -1
- package/dist/subscriberbot/pages/providers/ProvidersListPage.js +215 -112
- package/dist/subscriberbot/pages/providers/ProvidersListPage.js.map +1 -1
- package/dist/subscriberbot/pages/relationships/RelationshipDetailPage.js +542 -428
- package/dist/subscriberbot/pages/relationships/RelationshipDetailPage.js.map +1 -1
- package/dist/subscriberbot/pages/relationships/RelationshipNewPage.js +242 -192
- package/dist/subscriberbot/pages/relationships/RelationshipNewPage.js.map +1 -1
- package/dist/subscriberbot/pages/relationships/RelationshipsListPage.js +174 -133
- package/dist/subscriberbot/pages/relationships/RelationshipsListPage.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,16 +1,18 @@
|
|
|
1
1
|
import { PageLayout as e } from "../components/PageLayout.js";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
2
|
+
import { MetricsCard as t } from "../components/MetricsCard.js";
|
|
3
|
+
import { formatRelativeTime as n } from "../utils/formatters.js";
|
|
4
|
+
import { StatusBadge as r } from "../components/StatusBadge.js";
|
|
5
|
+
import { EmptyState as i } from "../components/EmptyState.js";
|
|
6
|
+
import { Modal as a } from "../components/Modal.js";
|
|
7
|
+
import { ErrorView as o, LoadingView as s } from "../components/StateViews.js";
|
|
8
|
+
import "../components/index.js";
|
|
9
|
+
import { useActivateWorkflow as c, useCreateWorkflow as l, useWorkflows as u } from "../hooks/useSubscriberBotApi.js";
|
|
10
|
+
import { useState as d } from "react";
|
|
11
|
+
import { ArrowRight as f, CheckCircle2 as p, Clock as m, Play as h, Plus as g, Sparkles as _, Workflow as v, X as y, Zap as b } from "lucide-react";
|
|
12
|
+
import { Fragment as x, jsx as S, jsxs as C } from "react/jsx-runtime";
|
|
13
|
+
import { GlassCard as w, PagePurpose as T } from "@burdenoff/fe-libs/ui";
|
|
12
14
|
//#region src/subscriberbot/pages/WorkflowsPage.tsx
|
|
13
|
-
var
|
|
15
|
+
var E = [
|
|
14
16
|
{
|
|
15
17
|
value: "",
|
|
16
18
|
label: "All statuses"
|
|
@@ -31,183 +33,370 @@ var _ = [
|
|
|
31
33
|
value: "ARCHIVED",
|
|
32
34
|
label: "Archived"
|
|
33
35
|
}
|
|
34
|
-
],
|
|
35
|
-
function
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
36
|
+
], D = "w-full rounded-lg border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary placeholder:text-text-secondary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]", O = "mb-1 block text-xs font-medium text-text-secondary";
|
|
37
|
+
function k({ icon: e, kicker: t, title: n, sub: r, accent: i }) {
|
|
38
|
+
return /* @__PURE__ */ C("div", {
|
|
39
|
+
className: "w-48 shrink-0 overflow-hidden rounded-xl border border-border-subtle bg-bg-surface shadow-sm",
|
|
40
|
+
children: [/* @__PURE__ */ S("div", {
|
|
41
|
+
className: `h-1 w-full ${i === "done" ? "bg-status-success-text" : i === "run" ? "bg-status-warning-text" : "bg-[var(--color-accent-indigo)]"}`,
|
|
42
|
+
"aria-hidden": !0
|
|
43
|
+
}), /* @__PURE__ */ C("div", {
|
|
44
|
+
className: "p-3",
|
|
45
|
+
children: [
|
|
46
|
+
/* @__PURE__ */ S("span", {
|
|
47
|
+
className: "flex size-8 items-center justify-center rounded-lg bg-[var(--color-accent-soft)] text-text-primary",
|
|
48
|
+
children: e
|
|
49
|
+
}),
|
|
50
|
+
/* @__PURE__ */ S("p", {
|
|
51
|
+
className: "mt-2 text-[10px] font-medium uppercase tracking-wide text-text-secondary",
|
|
52
|
+
children: t
|
|
53
|
+
}),
|
|
54
|
+
/* @__PURE__ */ S("p", {
|
|
55
|
+
className: "truncate text-sm font-semibold text-text-primary",
|
|
56
|
+
title: n,
|
|
57
|
+
children: n
|
|
58
|
+
}),
|
|
59
|
+
r && /* @__PURE__ */ S("p", {
|
|
60
|
+
className: "mt-0.5 truncate text-xs text-text-secondary",
|
|
61
|
+
children: r
|
|
62
|
+
})
|
|
63
|
+
]
|
|
64
|
+
})]
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
function A({ workflow: e, onClose: t, onActivate: i, activating: a }) {
|
|
68
|
+
let o = /* @__PURE__ */ C("div", {
|
|
69
|
+
className: "flex shrink-0 items-center px-1 text-text-secondary",
|
|
70
|
+
"aria-hidden": !0,
|
|
71
|
+
children: [/* @__PURE__ */ S("span", { className: "h-px w-4 bg-border-seam sm:w-6" }), /* @__PURE__ */ S(f, { className: "h-4 w-4" })]
|
|
72
|
+
});
|
|
73
|
+
return /* @__PURE__ */ C(w, {
|
|
74
|
+
treatment: "glass",
|
|
75
|
+
glow: !0,
|
|
76
|
+
className: "mt-6 p-5",
|
|
77
|
+
children: [
|
|
78
|
+
/* @__PURE__ */ C("div", {
|
|
79
|
+
className: "flex flex-wrap items-start justify-between gap-3",
|
|
80
|
+
children: [/* @__PURE__ */ C("div", {
|
|
81
|
+
className: "min-w-0",
|
|
82
|
+
children: [/* @__PURE__ */ C("div", {
|
|
83
|
+
className: "flex flex-wrap items-center gap-2",
|
|
84
|
+
children: [/* @__PURE__ */ S("p", {
|
|
85
|
+
className: "text-base font-semibold text-text-primary",
|
|
86
|
+
children: e.name
|
|
87
|
+
}), /* @__PURE__ */ S(r, { status: e.status })]
|
|
88
|
+
}), /* @__PURE__ */ C("p", {
|
|
89
|
+
className: "mt-1 flex flex-wrap items-center gap-x-3 gap-y-1 text-xs text-text-secondary",
|
|
90
|
+
children: [/* @__PURE__ */ C("span", {
|
|
91
|
+
className: "tabular-nums",
|
|
92
|
+
children: [
|
|
93
|
+
"Ran ",
|
|
94
|
+
e.runCount,
|
|
95
|
+
"×"
|
|
96
|
+
]
|
|
97
|
+
}), e.lastRunAt && /* @__PURE__ */ C("span", {
|
|
98
|
+
className: "inline-flex items-center gap-1",
|
|
99
|
+
children: [
|
|
100
|
+
/* @__PURE__ */ S(m, {
|
|
101
|
+
className: "h-3 w-3",
|
|
102
|
+
"aria-hidden": !0
|
|
103
|
+
}),
|
|
104
|
+
" last",
|
|
105
|
+
" ",
|
|
106
|
+
n(e.lastRunAt)
|
|
107
|
+
]
|
|
108
|
+
})]
|
|
109
|
+
})]
|
|
110
|
+
}), /* @__PURE__ */ S("button", {
|
|
111
|
+
type: "button",
|
|
112
|
+
onClick: t,
|
|
113
|
+
"aria-label": "Close flow",
|
|
114
|
+
className: "rounded-lg border border-border-subtle p-1.5 text-text-secondary hover:bg-bg-sunken hover:text-text-primary",
|
|
115
|
+
children: /* @__PURE__ */ S(y, { className: "h-4 w-4" })
|
|
116
|
+
})]
|
|
117
|
+
}),
|
|
118
|
+
e.description && /* @__PURE__ */ S("p", {
|
|
119
|
+
className: "mt-2 max-w-3xl text-sm text-text-secondary",
|
|
120
|
+
children: e.description
|
|
121
|
+
}),
|
|
122
|
+
/* @__PURE__ */ S("div", {
|
|
123
|
+
className: "mt-4 overflow-x-auto pb-2",
|
|
124
|
+
children: /* @__PURE__ */ C("div", {
|
|
125
|
+
className: "flex min-w-max items-stretch",
|
|
126
|
+
children: [
|
|
127
|
+
/* @__PURE__ */ S(k, {
|
|
128
|
+
accent: "trigger",
|
|
129
|
+
kicker: "When",
|
|
130
|
+
icon: /* @__PURE__ */ S(b, { className: "h-4 w-4" }),
|
|
131
|
+
title: e.triggerEvent,
|
|
132
|
+
sub: "Trigger event"
|
|
133
|
+
}),
|
|
134
|
+
o,
|
|
135
|
+
/* @__PURE__ */ S(k, {
|
|
136
|
+
accent: "run",
|
|
137
|
+
kicker: "Run",
|
|
138
|
+
icon: /* @__PURE__ */ S(_, { className: "h-4 w-4" }),
|
|
139
|
+
title: e.name,
|
|
140
|
+
sub: "Automation"
|
|
141
|
+
}),
|
|
142
|
+
o,
|
|
143
|
+
/* @__PURE__ */ S(k, {
|
|
144
|
+
accent: "done",
|
|
145
|
+
kicker: "Then",
|
|
146
|
+
icon: /* @__PURE__ */ S(p, { className: "h-4 w-4" }),
|
|
147
|
+
title: e.status === "ACTIVE" ? "Live" : "Awaiting activation",
|
|
148
|
+
sub: `Status: ${e.status.charAt(0) + e.status.slice(1).toLowerCase()}`
|
|
149
|
+
})
|
|
150
|
+
]
|
|
151
|
+
})
|
|
152
|
+
}),
|
|
153
|
+
e.status !== "ACTIVE" && /* @__PURE__ */ S("div", {
|
|
154
|
+
className: "mt-3 flex justify-end",
|
|
155
|
+
children: /* @__PURE__ */ C("button", {
|
|
156
|
+
type: "button",
|
|
157
|
+
disabled: a,
|
|
158
|
+
onClick: i,
|
|
159
|
+
className: "inline-flex items-center gap-1.5 rounded-lg bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text hover:opacity-90 disabled:opacity-50",
|
|
160
|
+
children: [
|
|
161
|
+
/* @__PURE__ */ S(h, { className: "h-4 w-4" }),
|
|
162
|
+
" ",
|
|
163
|
+
a ? "Activating…" : "Activate workflow"
|
|
164
|
+
]
|
|
165
|
+
})
|
|
166
|
+
})
|
|
167
|
+
]
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
function j() {
|
|
171
|
+
let [f, p] = d(""), [m, _] = d(!1), [y, k] = d(null), { data: j, isLoading: M, isError: N, refetch: P } = u(f || void 0), F = l(), I = c(), [L, R] = d(""), [z, B] = d(""), [V, H] = d(""), [U, W] = d(null), G = j ?? [], K = G.find((e) => e.id === y) ?? null, q = G.filter((e) => e.status === "ACTIVE").length, J = G.reduce((e, t) => e + (t.runCount || 0), 0), Y = () => {
|
|
172
|
+
R(""), B(""), H(""), W(null);
|
|
173
|
+
}, X = () => {
|
|
174
|
+
_(!1), Y();
|
|
40
175
|
};
|
|
41
|
-
return /* @__PURE__ */
|
|
176
|
+
return /* @__PURE__ */ C(e, {
|
|
42
177
|
title: "Workflows",
|
|
43
178
|
description: "Event-driven automation across your portfolio",
|
|
44
|
-
actions: /* @__PURE__ */
|
|
179
|
+
actions: /* @__PURE__ */ C("button", {
|
|
45
180
|
type: "button",
|
|
46
|
-
onClick: () =>
|
|
181
|
+
onClick: () => _(!0),
|
|
47
182
|
className: "inline-flex items-center gap-2 rounded-lg bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text hover:opacity-90",
|
|
48
|
-
children: [/* @__PURE__ */
|
|
183
|
+
children: [/* @__PURE__ */ S(g, { className: "h-4 w-4" }), " New workflow"]
|
|
49
184
|
}),
|
|
50
185
|
children: [
|
|
51
|
-
/* @__PURE__ */
|
|
186
|
+
/* @__PURE__ */ S(T, {
|
|
52
187
|
className: "mb-4",
|
|
53
188
|
children: "Workflows react to domain events — a new invoice, a detected renewal, a cancelled relationship — and run multi-step automations. Draft a workflow, then activate it when you're ready."
|
|
54
189
|
}),
|
|
55
|
-
/* @__PURE__ */
|
|
190
|
+
/* @__PURE__ */ S("div", {
|
|
56
191
|
className: "flex flex-wrap items-center gap-3",
|
|
57
|
-
children: /* @__PURE__ */
|
|
192
|
+
children: /* @__PURE__ */ S("select", {
|
|
58
193
|
"aria-label": "Filter by status",
|
|
59
|
-
value:
|
|
60
|
-
onChange: (e) =>
|
|
194
|
+
value: f,
|
|
195
|
+
onChange: (e) => p(e.target.value),
|
|
61
196
|
className: "rounded-lg border border-border-subtle bg-bg-surface px-3 py-2 text-xs text-text-primary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]",
|
|
62
|
-
children:
|
|
197
|
+
children: E.map((e) => /* @__PURE__ */ S("option", {
|
|
63
198
|
value: e.value,
|
|
64
199
|
children: e.label
|
|
65
200
|
}, e.value))
|
|
66
201
|
})
|
|
67
202
|
}),
|
|
68
|
-
|
|
203
|
+
M ? /* @__PURE__ */ S(s, { label: "Loading workflows…" }) : N ? /* @__PURE__ */ S(o, {
|
|
69
204
|
message: "Could not load workflows.",
|
|
70
|
-
onRetry: () => void
|
|
71
|
-
}) :
|
|
205
|
+
onRetry: () => void P()
|
|
206
|
+
}) : G.length === 0 ? /* @__PURE__ */ S("div", {
|
|
72
207
|
className: "mt-6",
|
|
73
|
-
children: /* @__PURE__ */
|
|
208
|
+
children: /* @__PURE__ */ S(i, {
|
|
74
209
|
illustration: "empty-data",
|
|
75
|
-
icon: /* @__PURE__ */
|
|
210
|
+
icon: /* @__PURE__ */ S(v, { className: "h-12 w-12" }),
|
|
76
211
|
title: "No workflows yet",
|
|
77
212
|
description: "Create your first event-driven workflow to automate your recurring portfolio.",
|
|
78
|
-
action: /* @__PURE__ */
|
|
213
|
+
action: /* @__PURE__ */ S("button", {
|
|
79
214
|
type: "button",
|
|
80
|
-
onClick: () =>
|
|
215
|
+
onClick: () => _(!0),
|
|
81
216
|
className: "rounded-lg bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text hover:opacity-90",
|
|
82
217
|
children: "New workflow"
|
|
83
218
|
})
|
|
84
219
|
})
|
|
85
|
-
}) : /* @__PURE__ */
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
className: "flex flex-col rounded-lg border border-border-subtle bg-bg-surface p-4",
|
|
220
|
+
}) : /* @__PURE__ */ C(x, { children: [
|
|
221
|
+
/* @__PURE__ */ C("div", {
|
|
222
|
+
className: "mt-6 grid grid-cols-1 gap-4 sm:grid-cols-3",
|
|
89
223
|
children: [
|
|
90
|
-
/* @__PURE__ */
|
|
91
|
-
className: "
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
children: /* @__PURE__ */ m(p, { className: "h-4 w-4" })
|
|
95
|
-
}), /* @__PURE__ */ m(n, { status: e.status })]
|
|
96
|
-
}),
|
|
97
|
-
/* @__PURE__ */ m("p", {
|
|
98
|
-
className: "mt-3 truncate text-sm font-semibold text-text-primary",
|
|
99
|
-
children: e.name
|
|
224
|
+
/* @__PURE__ */ S(t, {
|
|
225
|
+
icon: /* @__PURE__ */ S(v, { className: "h-5 w-5" }),
|
|
226
|
+
value: G.length,
|
|
227
|
+
label: "Workflows"
|
|
100
228
|
}),
|
|
101
|
-
/* @__PURE__ */
|
|
102
|
-
className: "
|
|
103
|
-
|
|
229
|
+
/* @__PURE__ */ S(t, {
|
|
230
|
+
icon: /* @__PURE__ */ S(b, { className: "h-5 w-5" }),
|
|
231
|
+
value: q,
|
|
232
|
+
label: "Active"
|
|
104
233
|
}),
|
|
105
|
-
|
|
106
|
-
className: "
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
/* @__PURE__ */ h("p", {
|
|
110
|
-
className: "mt-2 text-xs text-text-secondary",
|
|
111
|
-
children: [
|
|
112
|
-
"Ran ",
|
|
113
|
-
e.runCount,
|
|
114
|
-
"×",
|
|
115
|
-
e.lastRunAt ? ` · last ${t(e.lastRunAt)}` : ""
|
|
116
|
-
]
|
|
117
|
-
}),
|
|
118
|
-
e.status !== "ACTIVE" && /* @__PURE__ */ h("button", {
|
|
119
|
-
type: "button",
|
|
120
|
-
disabled: k.isPending,
|
|
121
|
-
onClick: () => k.mutate(e.id),
|
|
122
|
-
className: "mt-3 inline-flex items-center justify-center gap-1.5 rounded-lg border border-border-subtle px-3 py-1.5 text-xs font-medium text-text-primary hover:bg-bg-sunken disabled:opacity-50",
|
|
123
|
-
children: [/* @__PURE__ */ m(d, { className: "h-3.5 w-3.5" }), " Activate"]
|
|
234
|
+
/* @__PURE__ */ S(t, {
|
|
235
|
+
icon: /* @__PURE__ */ S(h, { className: "h-5 w-5" }),
|
|
236
|
+
value: J,
|
|
237
|
+
label: "Total runs"
|
|
124
238
|
})
|
|
125
239
|
]
|
|
126
|
-
},
|
|
127
|
-
|
|
128
|
-
|
|
240
|
+
}),
|
|
241
|
+
K && /* @__PURE__ */ S(A, {
|
|
242
|
+
workflow: K,
|
|
243
|
+
onClose: () => k(null),
|
|
244
|
+
onActivate: () => I.mutate(K.id),
|
|
245
|
+
activating: I.isPending
|
|
246
|
+
}),
|
|
247
|
+
/* @__PURE__ */ S("div", {
|
|
248
|
+
className: "mt-6 grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3",
|
|
249
|
+
children: G.map((e) => {
|
|
250
|
+
let t = e.id === y;
|
|
251
|
+
return /* @__PURE__ */ C(w, {
|
|
252
|
+
treatment: "metric",
|
|
253
|
+
glow: t || e.status === "ACTIVE",
|
|
254
|
+
role: "button",
|
|
255
|
+
tabIndex: 0,
|
|
256
|
+
"aria-pressed": t,
|
|
257
|
+
"aria-label": `View flow for ${e.name}`,
|
|
258
|
+
onClick: () => k(t ? null : e.id),
|
|
259
|
+
onKeyDown: (n) => {
|
|
260
|
+
(n.key === "Enter" || n.key === " ") && (n.preventDefault(), k(t ? null : e.id));
|
|
261
|
+
},
|
|
262
|
+
className: "flex cursor-pointer flex-col p-5 focus:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-focus-ring)]",
|
|
263
|
+
children: [
|
|
264
|
+
/* @__PURE__ */ C("div", {
|
|
265
|
+
className: "flex items-start justify-between gap-2",
|
|
266
|
+
children: [/* @__PURE__ */ S("span", {
|
|
267
|
+
className: "flex size-10 items-center justify-center rounded-xl bg-[var(--color-accent-soft)] text-text-primary",
|
|
268
|
+
children: /* @__PURE__ */ S(v, { className: "h-5 w-5" })
|
|
269
|
+
}), /* @__PURE__ */ S(r, { status: e.status })]
|
|
270
|
+
}),
|
|
271
|
+
/* @__PURE__ */ S("p", {
|
|
272
|
+
className: "mt-3 truncate text-sm font-semibold text-text-primary",
|
|
273
|
+
children: e.name
|
|
274
|
+
}),
|
|
275
|
+
/* @__PURE__ */ C("p", {
|
|
276
|
+
className: "flex items-center gap-1 truncate text-xs text-text-secondary",
|
|
277
|
+
children: [
|
|
278
|
+
/* @__PURE__ */ S(b, {
|
|
279
|
+
className: "h-3 w-3 shrink-0",
|
|
280
|
+
"aria-hidden": !0
|
|
281
|
+
}),
|
|
282
|
+
" on ",
|
|
283
|
+
e.triggerEvent
|
|
284
|
+
]
|
|
285
|
+
}),
|
|
286
|
+
e.description && /* @__PURE__ */ S("p", {
|
|
287
|
+
className: "mt-2 line-clamp-2 min-h-[2rem] text-xs text-text-secondary",
|
|
288
|
+
children: e.description
|
|
289
|
+
}),
|
|
290
|
+
/* @__PURE__ */ C("p", {
|
|
291
|
+
className: "mt-3 flex items-center gap-1.5 text-xs text-text-secondary tabular-nums",
|
|
292
|
+
children: [
|
|
293
|
+
/* @__PURE__ */ S(h, {
|
|
294
|
+
className: "h-3.5 w-3.5",
|
|
295
|
+
"aria-hidden": !0
|
|
296
|
+
}),
|
|
297
|
+
" Ran ",
|
|
298
|
+
e.runCount,
|
|
299
|
+
"×",
|
|
300
|
+
e.lastRunAt ? ` · last ${n(e.lastRunAt)}` : ""
|
|
301
|
+
]
|
|
302
|
+
}),
|
|
303
|
+
e.status !== "ACTIVE" && /* @__PURE__ */ C("button", {
|
|
304
|
+
type: "button",
|
|
305
|
+
disabled: I.isPending,
|
|
306
|
+
onClick: (t) => {
|
|
307
|
+
t.stopPropagation(), I.mutate(e.id);
|
|
308
|
+
},
|
|
309
|
+
className: "mt-4 inline-flex items-center justify-center gap-1.5 rounded-lg border border-border-subtle px-3 py-1.5 text-xs font-medium text-text-primary hover:bg-bg-sunken disabled:opacity-50",
|
|
310
|
+
children: [/* @__PURE__ */ S(h, { className: "h-3.5 w-3.5" }), " Activate"]
|
|
311
|
+
})
|
|
312
|
+
]
|
|
313
|
+
}, e.id);
|
|
314
|
+
})
|
|
315
|
+
})
|
|
316
|
+
] }),
|
|
317
|
+
m && /* @__PURE__ */ S(a, {
|
|
129
318
|
title: "New workflow",
|
|
130
|
-
onClose:
|
|
131
|
-
children: /* @__PURE__ */
|
|
319
|
+
onClose: X,
|
|
320
|
+
children: /* @__PURE__ */ C("form", {
|
|
132
321
|
onSubmit: (e) => {
|
|
133
|
-
if (e.preventDefault(),
|
|
134
|
-
|
|
322
|
+
if (e.preventDefault(), W(null), !L.trim() || !z.trim()) {
|
|
323
|
+
W("Name and trigger event are required.");
|
|
135
324
|
return;
|
|
136
325
|
}
|
|
137
326
|
let t = {
|
|
138
|
-
name:
|
|
139
|
-
triggerEvent:
|
|
140
|
-
...
|
|
327
|
+
name: L.trim(),
|
|
328
|
+
triggerEvent: z.trim(),
|
|
329
|
+
...V.trim() ? { description: V.trim() } : {}
|
|
141
330
|
};
|
|
142
|
-
|
|
331
|
+
F.mutate(t, {
|
|
143
332
|
onSuccess: () => {
|
|
144
|
-
|
|
333
|
+
Y(), _(!1);
|
|
145
334
|
},
|
|
146
|
-
onError: (e) =>
|
|
335
|
+
onError: (e) => W(e instanceof Error ? e.message : "Could not create workflow.")
|
|
147
336
|
});
|
|
148
337
|
},
|
|
149
338
|
className: "space-y-4",
|
|
150
339
|
children: [
|
|
151
|
-
|
|
340
|
+
U && /* @__PURE__ */ S("div", {
|
|
152
341
|
className: "rounded-lg border border-status-error-text/30 bg-status-error-bg-subtle px-4 py-2 text-sm text-status-error-text",
|
|
153
|
-
children:
|
|
342
|
+
children: U
|
|
154
343
|
}),
|
|
155
|
-
/* @__PURE__ */
|
|
344
|
+
/* @__PURE__ */ C("div", { children: [/* @__PURE__ */ C("label", {
|
|
156
345
|
htmlFor: "wf-name",
|
|
157
|
-
className:
|
|
158
|
-
children: ["Name ", /* @__PURE__ */
|
|
346
|
+
className: O,
|
|
347
|
+
children: ["Name ", /* @__PURE__ */ S("span", {
|
|
159
348
|
className: "text-status-error-text",
|
|
160
349
|
children: "*"
|
|
161
350
|
})]
|
|
162
|
-
}), /* @__PURE__ */
|
|
351
|
+
}), /* @__PURE__ */ S("input", {
|
|
163
352
|
id: "wf-name",
|
|
164
353
|
type: "text",
|
|
165
|
-
value:
|
|
166
|
-
onChange: (e) =>
|
|
354
|
+
value: L,
|
|
355
|
+
onChange: (e) => R(e.target.value),
|
|
167
356
|
placeholder: "e.g. Invoice → notify finance",
|
|
168
|
-
className:
|
|
357
|
+
className: D,
|
|
169
358
|
required: !0
|
|
170
359
|
})] }),
|
|
171
|
-
/* @__PURE__ */
|
|
360
|
+
/* @__PURE__ */ C("div", { children: [/* @__PURE__ */ C("label", {
|
|
172
361
|
htmlFor: "wf-trigger",
|
|
173
|
-
className:
|
|
174
|
-
children: ["Trigger event ", /* @__PURE__ */
|
|
362
|
+
className: O,
|
|
363
|
+
children: ["Trigger event ", /* @__PURE__ */ S("span", {
|
|
175
364
|
className: "text-status-error-text",
|
|
176
365
|
children: "*"
|
|
177
366
|
})]
|
|
178
|
-
}), /* @__PURE__ */
|
|
367
|
+
}), /* @__PURE__ */ S("input", {
|
|
179
368
|
id: "wf-trigger",
|
|
180
369
|
type: "text",
|
|
181
|
-
value:
|
|
182
|
-
onChange: (e) =>
|
|
370
|
+
value: z,
|
|
371
|
+
onChange: (e) => B(e.target.value),
|
|
183
372
|
placeholder: "e.g. InvoiceReceived, RenewalDetected",
|
|
184
|
-
className:
|
|
373
|
+
className: D,
|
|
185
374
|
required: !0
|
|
186
375
|
})] }),
|
|
187
|
-
/* @__PURE__ */
|
|
376
|
+
/* @__PURE__ */ C("div", { children: [/* @__PURE__ */ S("label", {
|
|
188
377
|
htmlFor: "wf-desc",
|
|
189
|
-
className:
|
|
378
|
+
className: O,
|
|
190
379
|
children: "Description"
|
|
191
|
-
}), /* @__PURE__ */
|
|
380
|
+
}), /* @__PURE__ */ S("textarea", {
|
|
192
381
|
id: "wf-desc",
|
|
193
|
-
value:
|
|
194
|
-
onChange: (e) =>
|
|
382
|
+
value: V,
|
|
383
|
+
onChange: (e) => H(e.target.value),
|
|
195
384
|
rows: 3,
|
|
196
385
|
placeholder: "What should this workflow do when the event fires?",
|
|
197
|
-
className:
|
|
386
|
+
className: D
|
|
198
387
|
})] }),
|
|
199
|
-
/* @__PURE__ */
|
|
388
|
+
/* @__PURE__ */ C("div", {
|
|
200
389
|
className: "flex justify-end gap-3",
|
|
201
|
-
children: [/* @__PURE__ */
|
|
390
|
+
children: [/* @__PURE__ */ S("button", {
|
|
202
391
|
type: "button",
|
|
203
|
-
onClick:
|
|
392
|
+
onClick: X,
|
|
204
393
|
className: "rounded-lg border border-border-subtle px-4 py-2 text-sm font-medium text-text-primary hover:bg-bg-sunken",
|
|
205
394
|
children: "Cancel"
|
|
206
|
-
}), /* @__PURE__ */
|
|
395
|
+
}), /* @__PURE__ */ S("button", {
|
|
207
396
|
type: "submit",
|
|
208
|
-
disabled:
|
|
397
|
+
disabled: F.isPending,
|
|
209
398
|
className: "rounded-lg bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text hover:opacity-90 disabled:opacity-50",
|
|
210
|
-
children:
|
|
399
|
+
children: F.isPending ? "Creating…" : "Create workflow"
|
|
211
400
|
})]
|
|
212
401
|
})
|
|
213
402
|
]
|
|
@@ -217,6 +406,6 @@ function b() {
|
|
|
217
406
|
});
|
|
218
407
|
}
|
|
219
408
|
//#endregion
|
|
220
|
-
export {
|
|
409
|
+
export { j as WorkflowsPage };
|
|
221
410
|
|
|
222
411
|
//# sourceMappingURL=WorkflowsPage.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"WorkflowsPage.js","names":[],"sources":["../../../src/subscriberbot/pages/WorkflowsPage.tsx"],"sourcesContent":["/**\n * Workflows (Automation)\n * @module subscriberbot/pages\n *\n * The Workflow Engine — event-driven automation (\"when invoice arrives →\n * classify → update relationship → notify finance\"). List + create + activate.\n * Reads `subListWorkflows`; writes `subCreateWorkflow` / `subActivateWorkflow`.\n */\n\nimport { useState } from 'react';\nimport { Plus, Workflow as WorkflowIcon, Play } from 'lucide-react';\nimport { PagePurpose } from '@burdenoff/fe-libs/ui';\nimport { PageLayout } from '../components/PageLayout';\nimport { StatusBadge } from '../components/StatusBadge';\nimport { EmptyState } from '../components/EmptyState';\nimport { Modal } from '../components/Modal';\nimport { LoadingView, ErrorView } from '../components/StateViews';\nimport { useWorkflows, useCreateWorkflow, useActivateWorkflow } from '../hooks/useSubscriberBotApi';\nimport { formatRelativeTime } from '../utils/formatters';\nimport type { SubCreateWorkflowInput, SubWorkflowStatus } from '../types';\n\nconst STATUS_OPTIONS: Array<{ value: '' | SubWorkflowStatus; label: string }> = [\n { value: '', label: 'All statuses' },\n { value: 'ACTIVE', label: 'Active' },\n { value: 'DRAFT', label: 'Draft' },\n { value: 'PAUSED', label: 'Paused' },\n { value: 'ARCHIVED', label: 'Archived' },\n];\n\nconst inputCls =\n 'w-full rounded-lg border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary placeholder:text-text-secondary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]';\nconst labelCls = 'mb-1 block text-xs font-medium text-text-secondary';\n\nexport function WorkflowsPage() {\n const [statusFilter, setStatusFilter] = useState<'' | SubWorkflowStatus>('');\n const [showCreate, setShowCreate] = useState(false);\n\n const { data, isLoading, isError, refetch } = useWorkflows(statusFilter || undefined);\n const create = useCreateWorkflow();\n const activate = useActivateWorkflow();\n\n const [name, setName] = useState('');\n const [triggerEvent, setTriggerEvent] = useState('');\n const [description, setDescription] = useState('');\n const [formError, setFormError] = useState<string | null>(null);\n\n const workflows = data ?? [];\n\n const resetForm = () => {\n setName('');\n setTriggerEvent('');\n setDescription('');\n setFormError(null);\n };\n\n const closeCreate = () => {\n setShowCreate(false);\n resetForm();\n };\n\n const handleCreate = (e: React.FormEvent) => {\n e.preventDefault();\n setFormError(null);\n if (!name.trim() || !triggerEvent.trim()) {\n setFormError('Name and trigger event are required.');\n return;\n }\n const input: SubCreateWorkflowInput = {\n name: name.trim(),\n triggerEvent: triggerEvent.trim(),\n ...(description.trim() ? { description: description.trim() } : {}),\n };\n create.mutate(input, {\n onSuccess: () => {\n resetForm();\n setShowCreate(false);\n },\n onError: (err) =>\n setFormError(err instanceof Error ? err.message : 'Could not create workflow.'),\n });\n };\n\n return (\n <PageLayout\n title=\"Workflows\"\n description=\"Event-driven automation across your portfolio\"\n actions={\n <button\n type=\"button\"\n onClick={() => setShowCreate(true)}\n className=\"inline-flex items-center gap-2 rounded-lg bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text hover:opacity-90\"\n >\n <Plus className=\"h-4 w-4\" /> New workflow\n </button>\n }\n >\n <PagePurpose className=\"mb-4\">\n Workflows react to domain events — a new invoice, a detected renewal, a cancelled\n relationship — and run multi-step automations. Draft a workflow, then activate it when\n you're ready.\n </PagePurpose>\n\n <div className=\"flex flex-wrap items-center gap-3\">\n <select\n aria-label=\"Filter by status\"\n value={statusFilter}\n onChange={(e) => setStatusFilter(e.target.value as '' | SubWorkflowStatus)}\n className=\"rounded-lg border border-border-subtle bg-bg-surface px-3 py-2 text-xs text-text-primary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]\"\n >\n {STATUS_OPTIONS.map((o) => (\n <option key={o.value} value={o.value}>\n {o.label}\n </option>\n ))}\n </select>\n </div>\n\n {isLoading ? (\n <LoadingView label=\"Loading workflows…\" />\n ) : isError ? (\n <ErrorView message=\"Could not load workflows.\" onRetry={() => void refetch()} />\n ) : workflows.length === 0 ? (\n <div className=\"mt-6\">\n <EmptyState\n illustration=\"empty-data\"\n icon={<WorkflowIcon className=\"h-12 w-12\" />}\n title=\"No workflows yet\"\n description=\"Create your first event-driven workflow to automate your recurring portfolio.\"\n action={\n <button\n type=\"button\"\n onClick={() => setShowCreate(true)}\n className=\"rounded-lg bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text hover:opacity-90\"\n >\n New workflow\n </button>\n }\n />\n </div>\n ) : (\n <div className=\"mt-6 grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3\">\n {workflows.map((wf) => (\n <div\n key={wf.id}\n className=\"flex flex-col rounded-lg border border-border-subtle bg-bg-surface p-4\"\n >\n <div className=\"flex items-start justify-between gap-2\">\n <span className=\"flex size-9 items-center justify-center rounded-lg bg-[var(--color-accent-soft)] text-text-primary\">\n <WorkflowIcon className=\"h-4 w-4\" />\n </span>\n <StatusBadge status={wf.status} />\n </div>\n <p className=\"mt-3 truncate text-sm font-semibold text-text-primary\">{wf.name}</p>\n <p className=\"truncate text-xs text-text-secondary\">on {wf.triggerEvent}</p>\n {wf.description && (\n <p className=\"mt-2 line-clamp-2 text-xs text-text-secondary\">{wf.description}</p>\n )}\n <p className=\"mt-2 text-xs text-text-secondary\">\n Ran {wf.runCount}×\n {wf.lastRunAt ? ` · last ${formatRelativeTime(wf.lastRunAt)}` : ''}\n </p>\n {wf.status !== 'ACTIVE' && (\n <button\n type=\"button\"\n disabled={activate.isPending}\n onClick={() => activate.mutate(wf.id)}\n className=\"mt-3 inline-flex items-center justify-center gap-1.5 rounded-lg border border-border-subtle px-3 py-1.5 text-xs font-medium text-text-primary hover:bg-bg-sunken disabled:opacity-50\"\n >\n <Play className=\"h-3.5 w-3.5\" /> Activate\n </button>\n )}\n </div>\n ))}\n </div>\n )}\n\n {/* Create modal */}\n {showCreate && (\n <Modal title=\"New workflow\" onClose={closeCreate}>\n <form onSubmit={handleCreate} className=\"space-y-4\">\n {formError && (\n <div className=\"rounded-lg border border-status-error-text/30 bg-status-error-bg-subtle px-4 py-2 text-sm text-status-error-text\">\n {formError}\n </div>\n )}\n <div>\n <label htmlFor=\"wf-name\" className={labelCls}>\n Name <span className=\"text-status-error-text\">*</span>\n </label>\n <input\n id=\"wf-name\"\n type=\"text\"\n value={name}\n onChange={(e) => setName(e.target.value)}\n placeholder=\"e.g. Invoice → notify finance\"\n className={inputCls}\n required\n />\n </div>\n <div>\n <label htmlFor=\"wf-trigger\" className={labelCls}>\n Trigger event <span className=\"text-status-error-text\">*</span>\n </label>\n <input\n id=\"wf-trigger\"\n type=\"text\"\n value={triggerEvent}\n onChange={(e) => setTriggerEvent(e.target.value)}\n placeholder=\"e.g. InvoiceReceived, RenewalDetected\"\n className={inputCls}\n required\n />\n </div>\n <div>\n <label htmlFor=\"wf-desc\" className={labelCls}>\n Description\n </label>\n <textarea\n id=\"wf-desc\"\n value={description}\n onChange={(e) => setDescription(e.target.value)}\n rows={3}\n placeholder=\"What should this workflow do when the event fires?\"\n className={inputCls}\n />\n </div>\n <div className=\"flex justify-end gap-3\">\n <button\n type=\"button\"\n onClick={closeCreate}\n className=\"rounded-lg border border-border-subtle px-4 py-2 text-sm font-medium text-text-primary hover:bg-bg-sunken\"\n >\n Cancel\n </button>\n <button\n type=\"submit\"\n disabled={create.isPending}\n className=\"rounded-lg bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text hover:opacity-90 disabled:opacity-50\"\n >\n {create.isPending ? 'Creating…' : 'Create workflow'}\n </button>\n </div>\n </form>\n </Modal>\n )}\n </PageLayout>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"WorkflowsPage.js","names":[],"sources":["../../../src/subscriberbot/pages/WorkflowsPage.tsx"],"sourcesContent":["/**\n * Workflows (Automation)\n * @module subscriberbot/pages\n *\n * The Workflow Engine — event-driven automation (\"when invoice arrives →\n * classify → update relationship → notify finance\"). List + create + activate.\n * Reads `subListWorkflows`; writes `subCreateWorkflow` / `subActivateWorkflow`.\n *\n * Opening a workflow renders a READ-ONLY horizontal step-flow derived from the\n * workflow's real `triggerEvent`, `name` and `status` (the svc contract does\n * not expose an editable step array — this is a truthful visualisation, not a\n * builder).\n */\n\nimport { useState } from 'react';\nimport {\n Plus,\n Workflow as WorkflowIcon,\n Play,\n Zap,\n Sparkles,\n CheckCircle2,\n ArrowRight,\n Clock,\n X,\n} from 'lucide-react';\nimport { PagePurpose, GlassCard } from '@burdenoff/fe-libs/ui';\nimport {\n PageLayout,\n StatusBadge,\n EmptyState,\n Modal,\n MetricsCard,\n LoadingView,\n ErrorView,\n} from '../components';\nimport { useWorkflows, useCreateWorkflow, useActivateWorkflow } from '../hooks/useSubscriberBotApi';\nimport { formatRelativeTime } from '../utils/formatters';\nimport type { SubCreateWorkflowInput, SubWorkflow, SubWorkflowStatus } from '../types';\n\nconst STATUS_OPTIONS: Array<{ value: '' | SubWorkflowStatus; label: string }> = [\n { value: '', label: 'All statuses' },\n { value: 'ACTIVE', label: 'Active' },\n { value: 'DRAFT', label: 'Draft' },\n { value: 'PAUSED', label: 'Paused' },\n { value: 'ARCHIVED', label: 'Archived' },\n];\n\nconst inputCls =\n 'w-full rounded-lg border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary placeholder:text-text-secondary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]';\nconst labelCls = 'mb-1 block text-xs font-medium text-text-secondary';\n\n// ---------------------------------------------------------------------------\n// A single node in the read-only step flow.\n// ---------------------------------------------------------------------------\nfunction FlowNode({\n icon,\n kicker,\n title,\n sub,\n accent,\n}: {\n icon: React.ReactNode;\n kicker: string;\n title: string;\n sub?: string;\n /** Top accent bar tone. */\n accent: 'trigger' | 'run' | 'done';\n}) {\n const bar =\n accent === 'done'\n ? 'bg-status-success-text'\n : accent === 'run'\n ? 'bg-status-warning-text'\n : 'bg-[var(--color-accent-indigo)]';\n return (\n <div className=\"w-48 shrink-0 overflow-hidden rounded-xl border border-border-subtle bg-bg-surface shadow-sm\">\n <div className={`h-1 w-full ${bar}`} aria-hidden />\n <div className=\"p-3\">\n <span className=\"flex size-8 items-center justify-center rounded-lg bg-[var(--color-accent-soft)] text-text-primary\">\n {icon}\n </span>\n <p className=\"mt-2 text-[10px] font-medium uppercase tracking-wide text-text-secondary\">\n {kicker}\n </p>\n <p className=\"truncate text-sm font-semibold text-text-primary\" title={title}>\n {title}\n </p>\n {sub && <p className=\"mt-0.5 truncate text-xs text-text-secondary\">{sub}</p>}\n </div>\n </div>\n );\n}\n\n// ---------------------------------------------------------------------------\n// Read-only flow panel for the selected workflow.\n// ---------------------------------------------------------------------------\nfunction WorkflowFlowPanel({\n workflow,\n onClose,\n onActivate,\n activating,\n}: {\n workflow: SubWorkflow;\n onClose: () => void;\n onActivate: () => void;\n activating: boolean;\n}) {\n const connector = (\n <div className=\"flex shrink-0 items-center px-1 text-text-secondary\" aria-hidden>\n <span className=\"h-px w-4 bg-border-seam sm:w-6\" />\n <ArrowRight className=\"h-4 w-4\" />\n </div>\n );\n\n return (\n <GlassCard treatment=\"glass\" glow className=\"mt-6 p-5\">\n <div className=\"flex flex-wrap items-start justify-between gap-3\">\n <div className=\"min-w-0\">\n <div className=\"flex flex-wrap items-center gap-2\">\n <p className=\"text-base font-semibold text-text-primary\">{workflow.name}</p>\n <StatusBadge status={workflow.status} />\n </div>\n <p className=\"mt-1 flex flex-wrap items-center gap-x-3 gap-y-1 text-xs text-text-secondary\">\n <span className=\"tabular-nums\">Ran {workflow.runCount}×</span>\n {workflow.lastRunAt && (\n <span className=\"inline-flex items-center gap-1\">\n <Clock className=\"h-3 w-3\" aria-hidden /> last{' '}\n {formatRelativeTime(workflow.lastRunAt)}\n </span>\n )}\n </p>\n </div>\n <button\n type=\"button\"\n onClick={onClose}\n aria-label=\"Close flow\"\n className=\"rounded-lg border border-border-subtle p-1.5 text-text-secondary hover:bg-bg-sunken hover:text-text-primary\"\n >\n <X className=\"h-4 w-4\" />\n </button>\n </div>\n\n {workflow.description && (\n <p className=\"mt-2 max-w-3xl text-sm text-text-secondary\">{workflow.description}</p>\n )}\n\n {/* Horizontal read-only step flow (scrolls on small screens) */}\n <div className=\"mt-4 overflow-x-auto pb-2\">\n <div className=\"flex min-w-max items-stretch\">\n <FlowNode\n accent=\"trigger\"\n kicker=\"When\"\n icon={<Zap className=\"h-4 w-4\" />}\n title={workflow.triggerEvent}\n sub=\"Trigger event\"\n />\n {connector}\n <FlowNode\n accent=\"run\"\n kicker=\"Run\"\n icon={<Sparkles className=\"h-4 w-4\" />}\n title={workflow.name}\n sub=\"Automation\"\n />\n {connector}\n <FlowNode\n accent=\"done\"\n kicker=\"Then\"\n icon={<CheckCircle2 className=\"h-4 w-4\" />}\n title={workflow.status === 'ACTIVE' ? 'Live' : 'Awaiting activation'}\n sub={`Status: ${workflow.status.charAt(0) + workflow.status.slice(1).toLowerCase()}`}\n />\n </div>\n </div>\n\n {workflow.status !== 'ACTIVE' && (\n <div className=\"mt-3 flex justify-end\">\n <button\n type=\"button\"\n disabled={activating}\n onClick={onActivate}\n className=\"inline-flex items-center gap-1.5 rounded-lg bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text hover:opacity-90 disabled:opacity-50\"\n >\n <Play className=\"h-4 w-4\" /> {activating ? 'Activating…' : 'Activate workflow'}\n </button>\n </div>\n )}\n </GlassCard>\n );\n}\n\nexport function WorkflowsPage() {\n const [statusFilter, setStatusFilter] = useState<'' | SubWorkflowStatus>('');\n const [showCreate, setShowCreate] = useState(false);\n const [selectedId, setSelectedId] = useState<string | null>(null);\n\n const { data, isLoading, isError, refetch } = useWorkflows(statusFilter || undefined);\n const create = useCreateWorkflow();\n const activate = useActivateWorkflow();\n\n const [name, setName] = useState('');\n const [triggerEvent, setTriggerEvent] = useState('');\n const [description, setDescription] = useState('');\n const [formError, setFormError] = useState<string | null>(null);\n\n const workflows = data ?? [];\n const selected = workflows.find((w) => w.id === selectedId) ?? null;\n\n // --- Real, computed aggregates -------------------------------------------\n const activeCount = workflows.filter((w) => w.status === 'ACTIVE').length;\n const totalRuns = workflows.reduce((s, w) => s + (w.runCount || 0), 0);\n\n const resetForm = () => {\n setName('');\n setTriggerEvent('');\n setDescription('');\n setFormError(null);\n };\n\n const closeCreate = () => {\n setShowCreate(false);\n resetForm();\n };\n\n const handleCreate = (e: React.FormEvent) => {\n e.preventDefault();\n setFormError(null);\n if (!name.trim() || !triggerEvent.trim()) {\n setFormError('Name and trigger event are required.');\n return;\n }\n const input: SubCreateWorkflowInput = {\n name: name.trim(),\n triggerEvent: triggerEvent.trim(),\n ...(description.trim() ? { description: description.trim() } : {}),\n };\n create.mutate(input, {\n onSuccess: () => {\n resetForm();\n setShowCreate(false);\n },\n onError: (err) =>\n setFormError(err instanceof Error ? err.message : 'Could not create workflow.'),\n });\n };\n\n return (\n <PageLayout\n title=\"Workflows\"\n description=\"Event-driven automation across your portfolio\"\n actions={\n <button\n type=\"button\"\n onClick={() => setShowCreate(true)}\n className=\"inline-flex items-center gap-2 rounded-lg bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text hover:opacity-90\"\n >\n <Plus className=\"h-4 w-4\" /> New workflow\n </button>\n }\n >\n <PagePurpose className=\"mb-4\">\n Workflows react to domain events — a new invoice, a detected renewal, a cancelled\n relationship — and run multi-step automations. Draft a workflow, then activate it when\n you're ready.\n </PagePurpose>\n\n <div className=\"flex flex-wrap items-center gap-3\">\n <select\n aria-label=\"Filter by status\"\n value={statusFilter}\n onChange={(e) => setStatusFilter(e.target.value as '' | SubWorkflowStatus)}\n className=\"rounded-lg border border-border-subtle bg-bg-surface px-3 py-2 text-xs text-text-primary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]\"\n >\n {STATUS_OPTIONS.map((o) => (\n <option key={o.value} value={o.value}>\n {o.label}\n </option>\n ))}\n </select>\n </div>\n\n {isLoading ? (\n <LoadingView label=\"Loading workflows…\" />\n ) : isError ? (\n <ErrorView message=\"Could not load workflows.\" onRetry={() => void refetch()} />\n ) : workflows.length === 0 ? (\n <div className=\"mt-6\">\n <EmptyState\n illustration=\"empty-data\"\n icon={<WorkflowIcon className=\"h-12 w-12\" />}\n title=\"No workflows yet\"\n description=\"Create your first event-driven workflow to automate your recurring portfolio.\"\n action={\n <button\n type=\"button\"\n onClick={() => setShowCreate(true)}\n className=\"rounded-lg bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text hover:opacity-90\"\n >\n New workflow\n </button>\n }\n />\n </div>\n ) : (\n <>\n {/* Overview (computed) */}\n <div className=\"mt-6 grid grid-cols-1 gap-4 sm:grid-cols-3\">\n <MetricsCard\n icon={<WorkflowIcon className=\"h-5 w-5\" />}\n value={workflows.length}\n label=\"Workflows\"\n />\n <MetricsCard\n icon={<Zap className=\"h-5 w-5\" />}\n value={activeCount}\n label=\"Active\"\n />\n <MetricsCard\n icon={<Play className=\"h-5 w-5\" />}\n value={totalRuns}\n label=\"Total runs\"\n />\n </div>\n\n {/* Selected workflow flow */}\n {selected && (\n <WorkflowFlowPanel\n workflow={selected}\n onClose={() => setSelectedId(null)}\n onActivate={() => activate.mutate(selected.id)}\n activating={activate.isPending}\n />\n )}\n\n {/* Workflow cards */}\n <div className=\"mt-6 grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3\">\n {workflows.map((wf) => {\n const isSelected = wf.id === selectedId;\n return (\n <GlassCard\n key={wf.id}\n treatment=\"metric\"\n glow={isSelected || wf.status === 'ACTIVE'}\n role=\"button\"\n tabIndex={0}\n aria-pressed={isSelected}\n aria-label={`View flow for ${wf.name}`}\n onClick={() => setSelectedId(isSelected ? null : wf.id)}\n onKeyDown={(e) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n setSelectedId(isSelected ? null : wf.id);\n }\n }}\n className=\"flex cursor-pointer flex-col p-5 focus:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-focus-ring)]\"\n >\n <div className=\"flex items-start justify-between gap-2\">\n <span className=\"flex size-10 items-center justify-center rounded-xl bg-[var(--color-accent-soft)] text-text-primary\">\n <WorkflowIcon className=\"h-5 w-5\" />\n </span>\n <StatusBadge status={wf.status} />\n </div>\n <p className=\"mt-3 truncate text-sm font-semibold text-text-primary\">{wf.name}</p>\n <p className=\"flex items-center gap-1 truncate text-xs text-text-secondary\">\n <Zap className=\"h-3 w-3 shrink-0\" aria-hidden /> on {wf.triggerEvent}\n </p>\n {wf.description && (\n <p className=\"mt-2 line-clamp-2 min-h-[2rem] text-xs text-text-secondary\">\n {wf.description}\n </p>\n )}\n <p className=\"mt-3 flex items-center gap-1.5 text-xs text-text-secondary tabular-nums\">\n <Play className=\"h-3.5 w-3.5\" aria-hidden /> Ran {wf.runCount}×\n {wf.lastRunAt ? ` · last ${formatRelativeTime(wf.lastRunAt)}` : ''}\n </p>\n {wf.status !== 'ACTIVE' && (\n <button\n type=\"button\"\n disabled={activate.isPending}\n onClick={(e) => {\n e.stopPropagation();\n activate.mutate(wf.id);\n }}\n className=\"mt-4 inline-flex items-center justify-center gap-1.5 rounded-lg border border-border-subtle px-3 py-1.5 text-xs font-medium text-text-primary hover:bg-bg-sunken disabled:opacity-50\"\n >\n <Play className=\"h-3.5 w-3.5\" /> Activate\n </button>\n )}\n </GlassCard>\n );\n })}\n </div>\n </>\n )}\n\n {/* Create modal */}\n {showCreate && (\n <Modal title=\"New workflow\" onClose={closeCreate}>\n <form onSubmit={handleCreate} className=\"space-y-4\">\n {formError && (\n <div className=\"rounded-lg border border-status-error-text/30 bg-status-error-bg-subtle px-4 py-2 text-sm text-status-error-text\">\n {formError}\n </div>\n )}\n <div>\n <label htmlFor=\"wf-name\" className={labelCls}>\n Name <span className=\"text-status-error-text\">*</span>\n </label>\n <input\n id=\"wf-name\"\n type=\"text\"\n value={name}\n onChange={(e) => setName(e.target.value)}\n placeholder=\"e.g. Invoice → notify finance\"\n className={inputCls}\n required\n />\n </div>\n <div>\n <label htmlFor=\"wf-trigger\" className={labelCls}>\n Trigger event <span className=\"text-status-error-text\">*</span>\n </label>\n <input\n id=\"wf-trigger\"\n type=\"text\"\n value={triggerEvent}\n onChange={(e) => setTriggerEvent(e.target.value)}\n placeholder=\"e.g. InvoiceReceived, RenewalDetected\"\n className={inputCls}\n required\n />\n </div>\n <div>\n <label htmlFor=\"wf-desc\" className={labelCls}>\n Description\n </label>\n <textarea\n id=\"wf-desc\"\n value={description}\n onChange={(e) => setDescription(e.target.value)}\n rows={3}\n placeholder=\"What should this workflow do when the event fires?\"\n className={inputCls}\n />\n </div>\n <div className=\"flex justify-end gap-3\">\n <button\n type=\"button\"\n onClick={closeCreate}\n className=\"rounded-lg border border-border-subtle px-4 py-2 text-sm font-medium text-text-primary hover:bg-bg-sunken\"\n >\n Cancel\n </button>\n <button\n type=\"submit\"\n disabled={create.isPending}\n className=\"rounded-lg bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text hover:opacity-90 disabled:opacity-50\"\n >\n {create.isPending ? 'Creating…' : 'Create workflow'}\n </button>\n </div>\n </form>\n </Modal>\n )}\n </PageLayout>\n );\n}\n"],"mappings":"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"}
|