@aglyn/plugins-workflows 1.0.0-beta.143

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 (75) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +52 -0
  3. package/package.json +53 -0
  4. package/src/index.d.ts +18 -0
  5. package/src/index.js +19 -0
  6. package/src/index.js.map +1 -0
  7. package/src/lib/components/automation-step-fields.component.d.ts +74 -0
  8. package/src/lib/components/automation-step-fields.component.js +1210 -0
  9. package/src/lib/components/automation-step-fields.component.js.map +1 -0
  10. package/src/lib/components/host-actions-card.component.d.ts +15 -0
  11. package/src/lib/components/host-actions-card.component.js +1229 -0
  12. package/src/lib/components/host-actions-card.component.js.map +1 -0
  13. package/src/lib/components/host-activity-card.component.d.ts +84 -0
  14. package/src/lib/components/host-activity-card.component.js +280 -0
  15. package/src/lib/components/host-activity-card.component.js.map +1 -0
  16. package/src/lib/components/host-run-history-card.component.d.ts +40 -0
  17. package/src/lib/components/host-run-history-card.component.js +284 -0
  18. package/src/lib/components/host-run-history-card.component.js.map +1 -0
  19. package/src/lib/components/host-webhooks-card.component.d.ts +15 -0
  20. package/src/lib/components/host-webhooks-card.component.js +421 -0
  21. package/src/lib/components/host-webhooks-card.component.js.map +1 -0
  22. package/src/lib/components/host-workflows-card.component.d.ts +18 -0
  23. package/src/lib/components/host-workflows-card.component.js +952 -0
  24. package/src/lib/components/host-workflows-card.component.js.map +1 -0
  25. package/src/lib/components/run-quota-line.component.d.ts +27 -0
  26. package/src/lib/components/run-quota-line.component.js +72 -0
  27. package/src/lib/components/run-quota-line.component.js.map +1 -0
  28. package/src/lib/components/use-automation-step-pickers.d.ts +27 -0
  29. package/src/lib/components/use-automation-step-pickers.js +205 -0
  30. package/src/lib/components/use-automation-step-pickers.js.map +1 -0
  31. package/src/lib/components/workflow-zones.d.ts +36 -0
  32. package/src/lib/components/workflow-zones.js +19 -0
  33. package/src/lib/components/workflow-zones.js.map +1 -0
  34. package/src/lib/components/workflows-console-page.d.ts +25 -0
  35. package/src/lib/components/workflows-console-page.js +112 -0
  36. package/src/lib/components/workflows-console-page.js.map +1 -0
  37. package/src/lib/components/workflows-console-sections.d.ts +34 -0
  38. package/src/lib/components/workflows-console-sections.js +50 -0
  39. package/src/lib/components/workflows-console-sections.js.map +1 -0
  40. package/src/lib/constants/bundle-common.d.ts +8 -0
  41. package/src/lib/constants/bundle-common.js +9 -0
  42. package/src/lib/constants/bundle-common.js.map +1 -0
  43. package/src/lib/declarations.server.d.ts +41 -0
  44. package/src/lib/declarations.server.js +54 -0
  45. package/src/lib/declarations.server.js.map +1 -0
  46. package/src/lib/engine/crm-action-steps.d.ts +129 -0
  47. package/src/lib/engine/crm-action-steps.js +432 -0
  48. package/src/lib/engine/crm-action-steps.js.map +1 -0
  49. package/src/lib/engine/flow-enrollments.d.ts +264 -0
  50. package/src/lib/engine/flow-enrollments.js +386 -0
  51. package/src/lib/engine/flow-enrollments.js.map +1 -0
  52. package/src/lib/engine/run-event-actions.d.ts +232 -0
  53. package/src/lib/engine/run-event-actions.js +1392 -0
  54. package/src/lib/engine/run-event-actions.js.map +1 -0
  55. package/src/lib/engine/run-event-automations.d.ts +28 -0
  56. package/src/lib/engine/run-event-automations.js +37 -0
  57. package/src/lib/engine/run-event-automations.js.map +1 -0
  58. package/src/lib/engine/run-event-workflows.d.ts +75 -0
  59. package/src/lib/engine/run-event-workflows.js +311 -0
  60. package/src/lib/engine/run-event-workflows.js.map +1 -0
  61. package/src/lib/engine/workflow-steps.d.ts +107 -0
  62. package/src/lib/engine/workflow-steps.js +124 -0
  63. package/src/lib/engine/workflow-steps.js.map +1 -0
  64. package/src/lib/plugin.d.ts +33 -0
  65. package/src/lib/plugin.js +94 -0
  66. package/src/lib/plugin.js.map +1 -0
  67. package/src/lib/server-automation-drafts.d.ts +90 -0
  68. package/src/lib/server-automation-drafts.js +429 -0
  69. package/src/lib/server-automation-drafts.js.map +1 -0
  70. package/src/lib/server-console.d.ts +27 -0
  71. package/src/lib/server-console.js +35 -0
  72. package/src/lib/server-console.js.map +1 -0
  73. package/src/lib/server.d.ts +29 -0
  74. package/src/lib/server.js +298 -0
  75. package/src/lib/server.js.map +1 -0
@@ -0,0 +1,40 @@
1
+ import type { ConsoleAutomationTarget } from '@aglyn/aglyn/plugin-manager/feature-plugins';
2
+ import { type HelpTipContent } from '@aglyn/shared-ui-jsx';
3
+ export interface HostRunHistoryCardProps {
4
+ hostId: string;
5
+ /** The org the page names, for what other plugins add to a failed run. */
6
+ orgId?: string;
7
+ /** Show only runs of this action/workflow. */
8
+ targetId?: string;
9
+ /**
10
+ * What `targetId` names, and its name. A run row records its automation's id
11
+ * but not whether it is an action or a workflow, so the card that opened the
12
+ * history says; without it, a failed run offers nothing beside its summary.
13
+ */
14
+ targetType?: ConsoleAutomationTarget['type'];
15
+ targetName?: string;
16
+ header?: string;
17
+ /** Overrides the default help affordance on the card header. */
18
+ help?: HelpTipContent;
19
+ }
20
+ /**
21
+ * The run-history table `/product/workflows` advertises (AGL-2171):
22
+ * `Time | Trigger | Result | What happened`.
23
+ *
24
+ * A separate component from `HostActivityCard` on purpose. That card is
25
+ * the site's general feed — publishes, media saves, member changes — and
26
+ * a run is a different record with different columns. Pointing the Runs
27
+ * dialog at the general feed is what produced a list of
28
+ * `Action ran on formSubmission — My automation` where the mockup shows
29
+ * four columns.
30
+ *
31
+ * `actionRunResult` returning `undefined` is the filter: the activity
32
+ * collection holds far more than runs, and a publish has no verdict. An
33
+ * entry that is not a run simply does not appear, rather than appearing
34
+ * under a `Succeeded` that means nothing for it.
35
+ */
36
+ export declare function HostRunHistoryCard(props: HostRunHistoryCardProps): import("react").JSX.Element;
37
+ export declare namespace HostRunHistoryCard {
38
+ var displayName: string;
39
+ }
40
+ export default HostRunHistoryCard;
@@ -0,0 +1,284 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Aglyn LLC
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */ 'use client';
17
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
18
+ import { actionRunResult, actionRunSummary, actionTriggerLabel } from "@aglyn/aglyn/app-utils/activity-presenter";
19
+ import { useConsoleWidgetSlot } from "@aglyn/aglyn/app-utils/console-widget-slot-context";
20
+ import { CardDisplay } from "@aglyn/shared-ui-jsx";
21
+ import { ListPagination } from "@aglyn/shared-ui-jsx/components/list-pagination.component";
22
+ import { TABLE_PAGE_SIZE_DEFAULT } from "@aglyn/shared-ui-jsx/const/table-pagination";
23
+ import { ScrollTable } from "@aglyn/shared-ui-jsx/components/scroll-table.component";
24
+ import { Alert, Chip, Stack, TableBody, TableCell, TableHead, TableRow, Tooltip, Typography } from "@mui/material";
25
+ import { collection, limit, orderBy, query, where } from "firebase/firestore";
26
+ import { useEffect, useMemo, useState } from "react";
27
+ import { useFirestore, useFirestoreCollection } from "@aglyn/tenant-feature-instance";
28
+ import { pluginDocsHelp } from "@aglyn/aglyn";
29
+ /**
30
+ * Activity rows read before the run filter.
31
+ *
32
+ * A CEILING rather than a page, and the difference is the client-side filter
33
+ * below. `activity` holds publishes, media saves and member changes as well as
34
+ * runs, and only a document carrying a run verdict is a row here — so a
35
+ * server page of ten activity entries might contain two runs, one, or none,
36
+ * and paging the QUERY would hand the reader pages of wildly different
37
+ * heights with no way to tell a short page from the end of the history.
38
+ *
39
+ * The filter cannot move to the server either: `actionRunResult` falls back to
40
+ * reading the prose `action` for entries written before AGL-2171, which have
41
+ * no `result` field, and `where('result','in',…)` excludes exactly those. That
42
+ * is the same field-presence trap as ordering on an optional field, and it
43
+ * would silently drop every historic run.
44
+ */ const WINDOW = 200;
45
+ const RESULT_COLOR = {
46
+ succeeded: 'success',
47
+ failed: 'error',
48
+ skipped: 'warning'
49
+ };
50
+ const RESULT_LABEL = {
51
+ succeeded: 'Succeeded',
52
+ failed: 'Failed',
53
+ skipped: 'Skipped'
54
+ };
55
+ /**
56
+ * The run-history table `/product/workflows` advertises (AGL-2171):
57
+ * `Time | Trigger | Result | What happened`.
58
+ *
59
+ * A separate component from `HostActivityCard` on purpose. That card is
60
+ * the site's general feed — publishes, media saves, member changes — and
61
+ * a run is a different record with different columns. Pointing the Runs
62
+ * dialog at the general feed is what produced a list of
63
+ * `Action ran on formSubmission — My automation` where the mockup shows
64
+ * four columns.
65
+ *
66
+ * `actionRunResult` returning `undefined` is the filter: the activity
67
+ * collection holds far more than runs, and a publish has no verdict. An
68
+ * entry that is not a run simply does not appear, rather than appearing
69
+ * under a `Succeeded` that means nothing for it.
70
+ */ export function HostRunHistoryCard(props) {
71
+ var _ref;
72
+ const { hostId, orgId, targetId, targetType, targetName = '', header = 'Run history', help = pluginDocsHelp('buildAWorkflow', {
73
+ anchor: '#4-save-and-test',
74
+ excerpt: 'Every run of this automation, including the ones a trigger ' + 'condition skipped — which is the answer to "why did it not fire?".'
75
+ }) } = props;
76
+ const firestore = useFirestore();
77
+ /**
78
+ * The shell's zone renderer (AGL-2919), for what other plugins add to a
79
+ * failed run; `null` outside the console shell.
80
+ */ const RunZone = useConsoleWidgetSlot();
81
+ /** The automation a failed run belongs to, as the `automationRun` zone names it. */ const zoneTarget = useMemo(()=>targetId && targetType ? {
82
+ type: targetType,
83
+ id: targetId,
84
+ name: targetName
85
+ } : null, [
86
+ targetId,
87
+ targetType,
88
+ targetName
89
+ ]);
90
+ /*
91
+ * The window is NARROWED BY THE SERVER, not by the client (AGL-2292).
92
+ *
93
+ * A bare `limit(200)` with no ordering is not "the most recent 200 runs" —
94
+ * Firestore answers an unordered limit in `__name__` order, so it is an
95
+ * arbitrary slice of the host's whole activity feed. `activity` also holds
96
+ * publishes, media saves and member changes, and only entries carrying a
97
+ * run result survive the filter below, so a busy site could fill all 200
98
+ * places with rows this card discards and report "No runs yet" for a
99
+ * workflow that had run all day.
100
+ *
101
+ * `target.id` equality is what makes the read proportional to the card:
102
+ * it asks for this workflow's rows rather than the site's. It carries no
103
+ * `orderBy` deliberately — an equality plus an ordering on a second field
104
+ * needs a composite index, and the client sort below already puts the
105
+ * newest first. The untargeted case has no equality to pair, so it orders
106
+ * server-side instead.
107
+ */ const { data: entries } = useFirestoreCollection(()=>{
108
+ if (!hostId) return null;
109
+ const base = collection(firestore, 'hosts', hostId, 'activity');
110
+ /*
111
+ * `WINDOW + 1` is a PROBE, not an off-by-one (AGL-2501).
112
+ *
113
+ * The card used to say "showing what we read" by saying nothing at all.
114
+ * Reading one document more than the ceiling turns "there is older
115
+ * history than this" into a fact for the price of a single read;
116
+ * comparing `length === WINDOW` cannot, because it is wrong in both
117
+ * directions at exactly the count that equals the ceiling. The probe row
118
+ * is dropped below and never rendered.
119
+ */ return targetId ? query(base, where('target.id', '==', targetId), limit(WINDOW + 1)) : query(base, orderBy('createdAt', 'desc'), limit(WINDOW + 1));
120
+ }, // `targetId` belongs here: it now shapes the query, so a card that
121
+ // switched workflows without it would go on showing the first one's runs.
122
+ [
123
+ firestore,
124
+ hostId,
125
+ targetId
126
+ ], {
127
+ idField: '$id'
128
+ });
129
+ /** The activity ceiling bit — there are older entries than were read. */ const truncated = ((_ref = entries == null ? void 0 : entries.length) != null ? _ref : 0) > WINDOW;
130
+ const runs = useMemo(()=>[
131
+ ...entries != null ? entries : []
132
+ ].slice(0, WINDOW).filter((entry)=>{
133
+ var _entry_target;
134
+ return !targetId || ((_entry_target = entry.target) == null ? void 0 : _entry_target.id) === targetId;
135
+ }).map((entry)=>({
136
+ entry,
137
+ result: actionRunResult(entry)
138
+ })).filter((row)=>Boolean(row.result)).sort((a, b)=>{
139
+ var _ref, _ref1;
140
+ var _b_entry_createdAt, _a_entry_createdAt;
141
+ return ((_ref = (_b_entry_createdAt = b.entry.createdAt) == null ? void 0 : _b_entry_createdAt.seconds) != null ? _ref : 0) - ((_ref1 = (_a_entry_createdAt = a.entry.createdAt) == null ? void 0 : _a_entry_createdAt.seconds) != null ? _ref1 : 0);
142
+ }), [
143
+ entries,
144
+ targetId
145
+ ]);
146
+ /*
147
+ * The page is a SLICE, because the rows are already in hand.
148
+ *
149
+ * Every run in the window has been read and paid for by the query above, so
150
+ * a second query per page would buy nothing and cost a read. What the card
151
+ * lacked was not a cheaper read but a control: it sliced the newest
152
+ * twenty-five off the window and rendered them in one wall, so run
153
+ * twenty-six was read, discarded, and unreachable — on the surface a reader
154
+ * opens precisely to ask "why did it not fire the time before last?".
155
+ */ const [page, setPage] = useState(0);
156
+ const [pageSize, setPageSize] = useState(TABLE_PAGE_SIZE_DEFAULT);
157
+ // A different workflow is a different history: page three of the last one
158
+ // is not a position in this one, and an out-of-range page renders empty
159
+ // with no explanation, which reads as the runs having gone.
160
+ useEffect(()=>setPage(0), [
161
+ targetId,
162
+ hostId
163
+ ]);
164
+ const shown = useMemo(()=>runs.slice(page * pageSize, page * pageSize + pageSize), [
165
+ runs,
166
+ page,
167
+ pageSize
168
+ ]);
169
+ return /*#__PURE__*/ _jsx(CardDisplay, {
170
+ header: header,
171
+ help: help,
172
+ contentGutterX: true,
173
+ contentGutterY: true,
174
+ contentBordered: "all",
175
+ children: runs.length === 0 ? /*#__PURE__*/ _jsx(Typography, {
176
+ variant: "body2",
177
+ color: "text.secondary",
178
+ children: 'No runs yet — every run of this automation is logged here, ' + 'including the ones a condition skipped.'
179
+ }) : /*#__PURE__*/ _jsxs(Stack, {
180
+ spacing: 1.5,
181
+ children: [
182
+ /*#__PURE__*/ _jsxs(ScrollTable, {
183
+ size: "small",
184
+ "aria-label": "Run history",
185
+ children: [
186
+ /*#__PURE__*/ _jsx(TableHead, {
187
+ children: /*#__PURE__*/ _jsxs(TableRow, {
188
+ children: [
189
+ /*#__PURE__*/ _jsx(TableCell, {
190
+ children: 'Time'
191
+ }),
192
+ /*#__PURE__*/ _jsx(TableCell, {
193
+ children: 'Trigger'
194
+ }),
195
+ /*#__PURE__*/ _jsx(TableCell, {
196
+ children: 'Result'
197
+ }),
198
+ /*#__PURE__*/ _jsx(TableCell, {
199
+ children: 'What happened'
200
+ })
201
+ ]
202
+ })
203
+ }),
204
+ /*#__PURE__*/ _jsx(TableBody, {
205
+ children: shown.map(({ entry, result })=>{
206
+ var _entry_createdAt_toDate, _entry_createdAt;
207
+ const at = (_entry_createdAt = entry.createdAt) == null ? void 0 : (_entry_createdAt_toDate = _entry_createdAt.toDate) == null ? void 0 : _entry_createdAt_toDate.call(_entry_createdAt);
208
+ return /*#__PURE__*/ _jsxs(TableRow, {
209
+ children: [
210
+ /*#__PURE__*/ _jsx(TableCell, {
211
+ sx: {
212
+ whiteSpace: 'nowrap'
213
+ },
214
+ children: /*#__PURE__*/ _jsx(Tooltip, {
215
+ title: at ? at.toLocaleString() : '',
216
+ children: /*#__PURE__*/ _jsx("span", {
217
+ children: at ? at.toLocaleTimeString() : '--'
218
+ })
219
+ })
220
+ }),
221
+ /*#__PURE__*/ _jsx(TableCell, {
222
+ sx: {
223
+ whiteSpace: 'nowrap'
224
+ },
225
+ children: actionTriggerLabel(entry.trigger)
226
+ }),
227
+ /*#__PURE__*/ _jsx(TableCell, {
228
+ children: /*#__PURE__*/ _jsx(Chip, {
229
+ size: "small",
230
+ variant: "outlined",
231
+ color: RESULT_COLOR[result],
232
+ label: RESULT_LABEL[result]
233
+ })
234
+ }),
235
+ /*#__PURE__*/ _jsxs(TableCell, {
236
+ children: [
237
+ /*#__PURE__*/ _jsx(Typography, {
238
+ variant: "body2",
239
+ children: actionRunSummary(entry)
240
+ }),
241
+ entry.durationMs != null ? /*#__PURE__*/ _jsx(Typography, {
242
+ variant: "caption",
243
+ color: "text.secondary",
244
+ children: `${entry.durationMs}ms`
245
+ }) : null,
246
+ RunZone && zoneTarget && result === 'failed' ? /*#__PURE__*/ _jsx(RunZone, {
247
+ slot: "automationRun",
248
+ hostId: hostId,
249
+ orgId: orgId,
250
+ target: zoneTarget,
251
+ runId: entry.$id
252
+ }) : null
253
+ ]
254
+ })
255
+ ]
256
+ }, entry.$id);
257
+ })
258
+ })
259
+ ]
260
+ }),
261
+ /*#__PURE__*/ _jsx(ListPagination, {
262
+ page: page,
263
+ pageSize: pageSize,
264
+ rowCount: shown.length,
265
+ // The runs in the window, which is a number this card genuinely
266
+ // holds. What it does not know is how many runs are OLDER than the
267
+ // window, and the notice below says so rather than letting the
268
+ // count line imply a total it cannot see.
269
+ count: runs.length,
270
+ onPageChange: setPage,
271
+ onPageSizeChange: setPageSize
272
+ }),
273
+ truncated ? /*#__PURE__*/ _jsx(Alert, {
274
+ severity: "info",
275
+ children: `Runs found in the ${WINDOW} most recent activity entries for ` + 'this site. Older runs than that are recorded and are not ' + 'listed here.'
276
+ }) : null
277
+ ]
278
+ })
279
+ });
280
+ }
281
+ HostRunHistoryCard.displayName = 'HostRunHistoryCard';
282
+ export default HostRunHistoryCard;
283
+
284
+ //# sourceMappingURL=host-run-history-card.component.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/workflows/src/lib/components/host-run-history-card.component.tsx"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n'use client'\n\nimport {\n actionRunResult,\n actionRunSummary,\n actionTriggerLabel,\n} from '@aglyn/aglyn/app-utils/activity-presenter'\nimport { useConsoleWidgetSlot } from '@aglyn/aglyn/app-utils/console-widget-slot-context'\nimport type { ConsoleAutomationTarget } from '@aglyn/aglyn/plugin-manager/feature-plugins'\nimport { CardDisplay, type HelpTipContent } from '@aglyn/shared-ui-jsx'\nimport { ListPagination } from '@aglyn/shared-ui-jsx/components/list-pagination.component'\nimport { TABLE_PAGE_SIZE_DEFAULT } from '@aglyn/shared-ui-jsx/const/table-pagination'\nimport { ScrollTable } from '@aglyn/shared-ui-jsx/components/scroll-table.component'\nimport {\n Alert,\n Chip,\n Stack,\n TableBody,\n TableCell,\n TableHead,\n TableRow,\n Tooltip,\n Typography,\n} from '@mui/material'\nimport { collection, limit, orderBy, query, where } from 'firebase/firestore'\nimport { useEffect, useMemo, useState } from 'react'\nimport {\n useFirestore,\n useFirestoreCollection,\n} from '@aglyn/tenant-feature-instance'\nimport { pluginDocsHelp } from '@aglyn/aglyn'\n\nexport interface HostRunHistoryCardProps {\n hostId: string\n /** The org the page names, for what other plugins add to a failed run. */\n orgId?: string\n /** Show only runs of this action/workflow. */\n targetId?: string\n /**\n * What `targetId` names, and its name. A run row records its automation's id\n * but not whether it is an action or a workflow, so the card that opened the\n * history says; without it, a failed run offers nothing beside its summary.\n */\n targetType?: ConsoleAutomationTarget['type']\n targetName?: string\n header?: string\n /** Overrides the default help affordance on the card header. */\n help?: HelpTipContent\n}\n\n/**\n * Activity rows read before the run filter.\n *\n * A CEILING rather than a page, and the difference is the client-side filter\n * below. `activity` holds publishes, media saves and member changes as well as\n * runs, and only a document carrying a run verdict is a row here — so a\n * server page of ten activity entries might contain two runs, one, or none,\n * and paging the QUERY would hand the reader pages of wildly different\n * heights with no way to tell a short page from the end of the history.\n *\n * The filter cannot move to the server either: `actionRunResult` falls back to\n * reading the prose `action` for entries written before AGL-2171, which have\n * no `result` field, and `where('result','in',…)` excludes exactly those. That\n * is the same field-presence trap as ordering on an optional field, and it\n * would silently drop every historic run.\n */\nconst WINDOW = 200\n\nconst RESULT_COLOR = {\n succeeded: 'success',\n failed: 'error',\n skipped: 'warning',\n} as const\n\nconst RESULT_LABEL = {\n succeeded: 'Succeeded',\n failed: 'Failed',\n skipped: 'Skipped',\n} as const\n\n/**\n * The run-history table `/product/workflows` advertises (AGL-2171):\n * `Time | Trigger | Result | What happened`.\n *\n * A separate component from `HostActivityCard` on purpose. That card is\n * the site's general feed — publishes, media saves, member changes — and\n * a run is a different record with different columns. Pointing the Runs\n * dialog at the general feed is what produced a list of\n * `Action ran on formSubmission — My automation` where the mockup shows\n * four columns.\n *\n * `actionRunResult` returning `undefined` is the filter: the activity\n * collection holds far more than runs, and a publish has no verdict. An\n * entry that is not a run simply does not appear, rather than appearing\n * under a `Succeeded` that means nothing for it.\n */\nexport function HostRunHistoryCard(props: HostRunHistoryCardProps) {\n const {\n hostId,\n orgId,\n targetId,\n targetType,\n targetName = '',\n header = 'Run history',\n help = pluginDocsHelp('buildAWorkflow', {\n anchor: '#4-save-and-test',\n excerpt:\n 'Every run of this automation, including the ones a trigger ' +\n 'condition skipped — which is the answer to \"why did it not fire?\".',\n }),\n } = props\n const firestore = useFirestore()\n /**\n * The shell's zone renderer (AGL-2919), for what other plugins add to a\n * failed run; `null` outside the console shell.\n */\n const RunZone = useConsoleWidgetSlot()\n /** The automation a failed run belongs to, as the `automationRun` zone names it. */\n const zoneTarget = useMemo<ConsoleAutomationTarget | null>(\n () => (targetId && targetType ? { type: targetType, id: targetId, name: targetName } : null),\n [targetId, targetType, targetName],\n )\n /*\n * The window is NARROWED BY THE SERVER, not by the client (AGL-2292).\n *\n * A bare `limit(200)` with no ordering is not \"the most recent 200 runs\" —\n * Firestore answers an unordered limit in `__name__` order, so it is an\n * arbitrary slice of the host's whole activity feed. `activity` also holds\n * publishes, media saves and member changes, and only entries carrying a\n * run result survive the filter below, so a busy site could fill all 200\n * places with rows this card discards and report \"No runs yet\" for a\n * workflow that had run all day.\n *\n * `target.id` equality is what makes the read proportional to the card:\n * it asks for this workflow's rows rather than the site's. It carries no\n * `orderBy` deliberately — an equality plus an ordering on a second field\n * needs a composite index, and the client sort below already puts the\n * newest first. The untargeted case has no equality to pair, so it orders\n * server-side instead.\n */\n const { data: entries } = useFirestoreCollection<any>(\n () => {\n if (!hostId) return null\n const base = collection(firestore, 'hosts', hostId, 'activity')\n /*\n * `WINDOW + 1` is a PROBE, not an off-by-one (AGL-2501).\n *\n * The card used to say \"showing what we read\" by saying nothing at all.\n * Reading one document more than the ceiling turns \"there is older\n * history than this\" into a fact for the price of a single read;\n * comparing `length === WINDOW` cannot, because it is wrong in both\n * directions at exactly the count that equals the ceiling. The probe row\n * is dropped below and never rendered.\n */\n return targetId\n ? query(base, where('target.id', '==', targetId), limit(WINDOW + 1))\n : query(base, orderBy('createdAt', 'desc'), limit(WINDOW + 1))\n },\n // `targetId` belongs here: it now shapes the query, so a card that\n // switched workflows without it would go on showing the first one's runs.\n [firestore, hostId, targetId],\n { idField: '$id' },\n )\n /** The activity ceiling bit — there are older entries than were read. */\n const truncated = (entries?.length ?? 0) > WINDOW\n\n const runs = useMemo(\n () =>\n [...(entries ?? [])]\n .slice(0, WINDOW)\n .filter((entry) => !targetId || entry.target?.id === targetId)\n .map((entry) => ({ entry, result: actionRunResult(entry) }))\n .filter(\n (row): row is { entry: any; result: keyof typeof RESULT_LABEL } =>\n Boolean(row.result),\n )\n .sort(\n (a, b) =>\n (b.entry.createdAt?.seconds ?? 0) -\n (a.entry.createdAt?.seconds ?? 0),\n ),\n [entries, targetId],\n )\n\n /*\n * The page is a SLICE, because the rows are already in hand.\n *\n * Every run in the window has been read and paid for by the query above, so\n * a second query per page would buy nothing and cost a read. What the card\n * lacked was not a cheaper read but a control: it sliced the newest\n * twenty-five off the window and rendered them in one wall, so run\n * twenty-six was read, discarded, and unreachable — on the surface a reader\n * opens precisely to ask \"why did it not fire the time before last?\".\n */\n const [page, setPage] = useState(0)\n const [pageSize, setPageSize] = useState(TABLE_PAGE_SIZE_DEFAULT)\n // A different workflow is a different history: page three of the last one\n // is not a position in this one, and an out-of-range page renders empty\n // with no explanation, which reads as the runs having gone.\n useEffect(() => setPage(0), [targetId, hostId])\n const shown = useMemo(\n () => runs.slice(page * pageSize, page * pageSize + pageSize),\n [runs, page, pageSize],\n )\n\n return (\n <CardDisplay\n header={header}\n help={help}\n contentGutterX\n contentGutterY\n contentBordered=\"all\"\n >\n {runs.length === 0 ? (\n <Typography variant=\"body2\" color=\"text.secondary\">\n {'No runs yet — every run of this automation is logged here, ' +\n 'including the ones a condition skipped.'}\n </Typography>\n ) : (\n <Stack spacing={1.5}>\n <ScrollTable size=\"small\" aria-label=\"Run history\">\n <TableHead>\n <TableRow>\n <TableCell>{'Time'}</TableCell>\n <TableCell>{'Trigger'}</TableCell>\n <TableCell>{'Result'}</TableCell>\n <TableCell>{'What happened'}</TableCell>\n </TableRow>\n </TableHead>\n <TableBody>\n {shown.map(({ entry, result }) => {\n const at = entry.createdAt?.toDate?.()\n return (\n <TableRow key={entry.$id}>\n <TableCell sx={{ whiteSpace: 'nowrap' }}>\n <Tooltip title={at ? at.toLocaleString() : ''}>\n <span>{at ? at.toLocaleTimeString() : '--'}</span>\n </Tooltip>\n </TableCell>\n <TableCell sx={{ whiteSpace: 'nowrap' }}>\n {/* `formSubmission` → `Form submitted`. */}\n {actionTriggerLabel(entry.trigger)}\n </TableCell>\n <TableCell>\n <Chip\n size=\"small\"\n variant=\"outlined\"\n color={RESULT_COLOR[result]}\n label={RESULT_LABEL[result]}\n />\n </TableCell>\n <TableCell>\n <Typography variant=\"body2\">\n {actionRunSummary(entry)}\n </Typography>\n {entry.durationMs != null ? (\n <Typography variant=\"caption\" color=\"text.secondary\">\n {`${entry.durationMs}ms`}\n </Typography>\n ) : null}\n {/*\n What other plugins add to a failed run (AGL-2919): the\n `automationRun` zone, through the shell's gated slot.\n */}\n {RunZone && zoneTarget && result === 'failed' ? (\n <RunZone\n slot=\"automationRun\"\n hostId={hostId}\n orgId={orgId}\n target={zoneTarget}\n runId={entry.$id}\n />\n ) : null}\n </TableCell>\n </TableRow>\n )\n })}\n </TableBody>\n </ScrollTable>\n <ListPagination\n page={page}\n pageSize={pageSize}\n rowCount={shown.length}\n // The runs in the window, which is a number this card genuinely\n // holds. What it does not know is how many runs are OLDER than the\n // window, and the notice below says so rather than letting the\n // count line imply a total it cannot see.\n count={runs.length}\n onPageChange={setPage}\n onPageSizeChange={setPageSize}\n />\n {truncated ? (\n <Alert severity=\"info\">\n {`Runs found in the ${WINDOW} most recent activity entries for ` +\n 'this site. Older runs than that are recorded and are not ' +\n 'listed here.'}\n </Alert>\n ) : null}\n </Stack>\n )}\n </CardDisplay>\n )\n}\nHostRunHistoryCard.displayName = 'HostRunHistoryCard'\n\nexport default HostRunHistoryCard\n"],"names":["actionRunResult","actionRunSummary","actionTriggerLabel","useConsoleWidgetSlot","CardDisplay","ListPagination","TABLE_PAGE_SIZE_DEFAULT","ScrollTable","Alert","Chip","Stack","TableBody","TableCell","TableHead","TableRow","Tooltip","Typography","collection","limit","orderBy","query","where","useEffect","useMemo","useState","useFirestore","useFirestoreCollection","pluginDocsHelp","WINDOW","RESULT_COLOR","succeeded","failed","skipped","RESULT_LABEL","HostRunHistoryCard","props","hostId","orgId","targetId","targetType","targetName","header","help","anchor","excerpt","firestore","RunZone","zoneTarget","type","id","name","data","entries","base","idField","truncated","length","runs","slice","filter","entry","target","map","result","row","Boolean","sort","a","b","createdAt","seconds","page","setPage","pageSize","setPageSize","shown","contentGutterX","contentGutterY","contentBordered","variant","color","spacing","size","aria-label","at","toDate","sx","whiteSpace","title","toLocaleString","span","toLocaleTimeString","trigger","label","durationMs","slot","runId","$id","rowCount","count","onPageChange","onPageSizeChange","severity","displayName"],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ import { type AglynOrgBilling } from '@aglyn/aglyn';
2
+ /**
3
+ * Webhooks manager (AGL-149): outbound targets (used by the actions
4
+ * builder's "Send a webhook" step, HMAC-signed) and inbound endpoints
5
+ * (`/api/hooks/{hostId}/{hookId}`, secret-verified, run a workflow with
6
+ * the payload in scope). Business tier.
7
+ */
8
+ export declare function HostWebhooksCard(props: {
9
+ hostId: string;
10
+ org?: Partial<AglynOrgBilling>;
11
+ }): import("react").JSX.Element;
12
+ export declare namespace HostWebhooksCard {
13
+ var displayName: string;
14
+ }
15
+ export default HostWebhooksCard;