@aglyn/plugins-workflows 1.0.0-beta.183 → 1.0.0-beta.185

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
@@ -58,7 +58,9 @@ the core's own compose path read it too.
58
58
 
59
59
  - `.` — the console extension (nav, the Automation page, the activity widget).
60
60
  - `./server` — the tenant and console API surfaces: the inbound webhook, the
61
- flow-resume job, the automation draft writer.
61
+ flow-resume job, the automation draft writer, the org automation doors, and
62
+ the Actions card's test run (`automations/actions/test-run`, console only —
63
+ the page runtime's `events/dispatch` is a tenant route).
62
64
  - `./declarations.server` — the boot registration above.
63
65
 
64
66
  ## License
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aglyn/plugins-workflows",
3
- "version": "1.0.0-beta.183",
3
+ "version": "1.0.0-beta.185",
4
4
  "license": "Apache-2.0",
5
5
  "homepage": "https://aglyn.com",
6
6
  "repository": {
@@ -25,17 +25,17 @@
25
25
  "./package.json": "./package.json"
26
26
  },
27
27
  "dependencies": {
28
- "@aglyn/aglyn": "1.0.0-beta.183",
29
- "@aglyn/shared-data-mdi": "1.0.0-beta.183",
30
- "@aglyn/shared-ui-jsx": "1.0.0-beta.183",
31
- "@aglyn/shared-ui-next": "1.0.0-beta.183",
32
- "@aglyn/shared-ui-snackstack": "1.0.0-beta.183",
33
- "@aglyn/shared-util-email": "1.0.0-beta.183",
34
- "@aglyn/shared-util-http": "1.0.0-beta.183",
35
- "@aglyn/shared-util-timestamp": "1.0.0-beta.183",
36
- "@aglyn/tenant-data-admin": "1.0.0-beta.183",
37
- "@aglyn/tenant-feature-instance": "1.0.0-beta.183",
38
- "@aglyn/tenant-runtime": "1.0.0-beta.183",
28
+ "@aglyn/aglyn": "1.0.0-beta.185",
29
+ "@aglyn/shared-data-mdi": "1.0.0-beta.185",
30
+ "@aglyn/shared-ui-jsx": "1.0.0-beta.185",
31
+ "@aglyn/shared-ui-next": "1.0.0-beta.185",
32
+ "@aglyn/shared-ui-snackstack": "1.0.0-beta.185",
33
+ "@aglyn/shared-util-email": "1.0.0-beta.185",
34
+ "@aglyn/shared-util-http": "1.0.0-beta.185",
35
+ "@aglyn/shared-util-timestamp": "1.0.0-beta.185",
36
+ "@aglyn/tenant-data-admin": "1.0.0-beta.185",
37
+ "@aglyn/tenant-feature-instance": "1.0.0-beta.185",
38
+ "@aglyn/tenant-runtime": "1.0.0-beta.185",
39
39
  "@swc/helpers": "0.5.23"
40
40
  },
41
41
  "peerDependencies": {
@@ -23,11 +23,13 @@ import { CardDisplay, useConfirmationContext } from "@aglyn/shared-ui-jsx";
23
23
  import { ListPagination } from "@aglyn/shared-ui-jsx/components/list-pagination.component";
24
24
  import { TABLE_PAGE_SIZE_DEFAULT } from "@aglyn/shared-ui-jsx/const/table-pagination";
25
25
  import { useSnackbar } from "@aglyn/shared-ui-snackstack";
26
+ import { authorizedFetch } from "@aglyn/shared-util-http/authorized-token";
26
27
  import { Timestamp } from "@aglyn/shared-util-timestamp";
27
28
  import { Alert, Button, Dialog, DialogActions, DialogContent, DialogTitle, ListItemText, Menu, MenuItem, Stack, Switch, TextField, Typography } from "@mui/material";
28
29
  import { collection, doc, setDoc, updateDoc } from "firebase/firestore";
29
30
  import { useCallback, useMemo, useRef, useState } from "react";
30
- import { ceilingedWindow, collectionCeiling, useFirestore, useFirestoreCollection, useHostResourceApi, writeGuardedBySeed } from "@aglyn/tenant-feature-instance";
31
+ import { ceilingedWindow, collectionCeiling, useFirestore, useFirestoreCollection, useHostResourceApi, useUser, writeGuardedBySeed } from "@aglyn/tenant-feature-instance";
32
+ import { ACTION_TEST_RUN_API_ROUTE } from "../model/action-test-run.js";
31
33
  import { AutomationStepFields, defaultStep } from "./automation-step-fields.component.js";
32
34
  import { conditionRowsFromTrigger, conditionsFromRows, EMPTY_CONDITION_ROW, TriggerConditionRows } from "./automation-trigger-conditions.component.js";
33
35
  import HostRunHistoryCard from "./host-run-history-card.component.js";
@@ -104,6 +106,8 @@ const CUSTOM_EVENT_VALUE = '__custom__';
104
106
  // Action creation is server-owned since AGL-2266 (the cap); every other
105
107
  // action write on this surface stays client-direct.
106
108
  const createResource = useHostResourceApi();
109
+ // The caller's token, for the test run's console door.
110
+ const { data: user } = useUser();
107
111
  const { enqueueSnackbar } = useSnackbar();
108
112
  const { confirm } = useConfirmationContext();
109
113
  /**
@@ -331,20 +335,19 @@ const CUSTOM_EVENT_VALUE = '__custom__';
331
335
  const [runsFor, setRunsFor] = useState(null);
332
336
  const handleTestRun = useCallback(async (action)=>{
333
337
  try {
334
- var _action_trigger;
335
- const response = await fetch('/api/events/dispatch', {
338
+ /*
339
+ * The console's own door, signed: a page's `events/dispatch` is a
340
+ * tenant route this origin does not serve. The route reads the
341
+ * trigger off the stored action and marks the run as a test, so the
342
+ * body names only which action on which site.
343
+ */ const response = await authorizedFetch(user, `/api/${ACTION_TEST_RUN_API_ROUTE}`, {
336
344
  method: 'POST',
337
345
  headers: {
338
346
  'Content-Type': 'application/json'
339
347
  },
340
348
  body: JSON.stringify({
341
349
  hostId,
342
- actionId: action.$id,
343
- event: (_action_trigger = action.trigger) == null ? void 0 : _action_trigger.event,
344
- payload: {
345
- path: '/console-test',
346
- test: 'true'
347
- }
350
+ actionId: action.$id
348
351
  })
349
352
  });
350
353
  const payload = await response.json().catch(()=>({}));
@@ -368,6 +371,7 @@ const CUSTOM_EVENT_VALUE = '__custom__';
368
371
  }
369
372
  }, [
370
373
  hostId,
374
+ user,
371
375
  enqueueSnackbar
372
376
  ]);
373
377
  const handleSave = useCallback(async ()=>{
@@ -606,7 +610,8 @@ const CUSTOM_EVENT_VALUE = '__custom__';
606
610
  onClick: ()=>setDraft(draftFromAction(action, action.$id)),
607
611
  children: 'Edit'
608
612
  }),
609
- isSiteEventType(String((_ref = (_action_trigger1 = action.trigger) == null ? void 0 : _action_trigger1.event) != null ? _ref : '')) ? // Test run (AGL-266): server steps only, via the dispatch API.
613
+ isSiteEventType(String((_ref = (_action_trigger1 = action.trigger) == null ? void 0 : _action_trigger1.event) != null ? _ref : '')) ? // Test run (AGL-266): the server steps only, run now as a real
614
+ // run through the console's test-run door.
610
615
  /*#__PURE__*/ _jsx(Button, {
611
616
  size: "small",
612
617
  onClick: ()=>void handleTestRun(action),
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../../libs/plugins/workflows/src/lib/components/host-actions-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 ACTION_MAX_STEPS,\n type AglynOrgBilling,\n checkEntitlement,\n createResourceUid,\n CRM_ACTION_RECIPES,\n type CrmActionRecipe,\n type CrmActionRecipeId,\n ELEMENT_SCOPED_SITE_EVENTS,\n HOST_ACTION_STEP_LABELS,\n HOST_EVENT_TYPES,\n type HostAction,\n hostActionDocument,\n hostActionRecipeId,\n type HostActionStepType,\n hostEventLabel,\n hostEventPayloadHint,\n isSiteEventType,\n pluginDocsHelp,\n SITE_EVENT_TYPES,\n type TriggerCombinator,\n validateHostAction,\n} from '@aglyn/aglyn'\nimport {\n automationPlaceholders,\n describeAutomationPlaceholder,\n} from '@aglyn/aglyn/app-utils/automation-placeholders'\nimport { useConsoleWidgetSlot } from '@aglyn/aglyn/app-utils/console-widget-slot-context'\nimport type { ConsoleAutomationTarget } from '@aglyn/aglyn/plugin-manager/feature-plugins'\nimport { CardDisplay, useConfirmationContext } 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 { useSnackbar } from '@aglyn/shared-ui-snackstack'\nimport { Timestamp } from '@aglyn/shared-util-timestamp'\nimport {\n Alert,\n Button,\n Dialog,\n DialogActions,\n DialogContent,\n DialogTitle,\n ListItemText,\n Menu,\n MenuItem,\n Stack,\n Switch,\n TextField,\n Typography,\n} from '@mui/material'\nimport {\n collection,\n doc,\n setDoc,\n updateDoc,\n} from 'firebase/firestore'\nimport { useCallback, useMemo, useRef, useState } from 'react'\nimport {\n ceilingedWindow,\n collectionCeiling,\n useFirestore,\n useFirestoreCollection,\n useHostResourceApi,\n writeGuardedBySeed,\n} from '@aglyn/tenant-feature-instance'\nimport {\n AutomationStepFields,\n type AutomationStepKind,\n defaultStep,\n} from './automation-step-fields.component'\nimport {\n conditionRowsFromTrigger,\n conditionsFromRows,\n type ConditionRowDraft,\n EMPTY_CONDITION_ROW,\n TriggerConditionRows,\n} from './automation-trigger-conditions.component'\nimport HostRunHistoryCard from './host-run-history-card.component'\nimport {\n EDITOR_OPTION_CEILING,\n useAutomationStepPickers,\n} from './use-automation-step-pickers'\n\nconst CUSTOM_EVENT_VALUE = '__custom__'\n\n/**\n * How many action documents the card reads.\n *\n * A CEILING, not a page size — see the query, which explains why this one\n * collection cannot be sliced by the server without making the count beneath\n * the list a per-page number.\n *\n * `ACTIONS_MAX_PER_HOST` is 500, so the ceiling really can bite and the probe\n * beside it is what says when it has.\n */\nconst ACTION_CEILING = 100\n\ninterface ActionDraft extends HostAction {\n id: string | null\n /** Raw custom-event text when the trigger select is on \"custom\". */\n customEvent: string\n // Structured payload conditions (AGL-557), chainable with AND/OR\n // (AGL-565) — held as rows like the steps list; legacy\n // single-`condition` docs hydrate through normalizeTriggerConditions.\n conditionRows: ConditionRowDraft[]\n conditionCombinator: TriggerCombinator\n /**\n * The recipe this draft started from (AGL-2626), so the editor can say\n * so, and what Save writes back as the action's stamp (AGL-2639): null\n * for an action begun blank, and `undefined` for a stored action from\n * before the stamp existed — which Save leaves as it found it, so an\n * edit never turns \"unknown\" into \"no recipe\".\n */\n recipe: CrmActionRecipeId | null | undefined\n}\n\n\n/** Every Actions step, as the builder's \"Do\" picker offers it. */\nconst ACTION_STEP_KINDS: AutomationStepKind[] = Object.entries(\n HOST_ACTION_STEP_LABELS,\n).map(([value, label]) => ({ value, label }))\n\n\n/**\n * A stored action — or one a recipe just built — as the editor holds it.\n *\n * One conversion for both doors, because they must agree: an action that\n * round-trips through Edit and one a recipe hands over are the same shape\n * to the editor, and a field the Edit path hydrated that the recipe path\n * forgot would be a recipe whose conditions vanished on open. Site events\n * are first-class (AGL-256/266): their selector/threshold/path config is\n * kept through an edit. Structured conditions (AGL-557; chained AGL-565)\n * become rows; a legacy single-condition doc normalizes to one row.\n */\nfunction draftFromAction(\n action: Record<string, any>,\n id: string | null,\n): ActionDraft {\n const builtIn =\n HOST_EVENT_TYPES.includes(action.trigger?.event) ||\n isSiteEventType(String(action.trigger?.event ?? ''))\n return {\n id,\n name: action.name ?? '',\n trigger: {\n event: builtIn ? action.trigger.event : CUSTOM_EVENT_VALUE,\n filter: action.trigger?.filter ?? '',\n selector: action.trigger?.selector ?? '',\n threshold: action.trigger?.threshold,\n pathPattern: action.trigger?.pathPattern ?? '',\n oncePerVisitor: action.trigger?.oncePerVisitor === true,\n oncePerSession: action.trigger?.oncePerSession === true,\n everyTime: action.trigger?.everyTime === true,\n ...(Number(action.trigger?.cooldownMinutes) >= 1\n ? { cooldownMinutes: Number(action.trigger?.cooldownMinutes) }\n : {}),\n },\n steps: action.steps ?? [],\n enabled: action.enabled !== false,\n customEvent: builtIn ? '' : (action.trigger?.event ?? ''),\n conditionRows: conditionRowsFromTrigger(action.trigger),\n conditionCombinator: action.trigger?.combinator === 'or' ? 'or' : 'and',\n // A recipe stamps what it builds, and a stored action carries what it\n // was saved with — one reader for both doors, unknown kept unknown.\n recipe: hostActionRecipeId(action),\n }\n}\n\n/** A trigger bound to one element, which makes the row an interaction. */\nconst LEAF_SELECTOR = /^\\[data-aglyn=\"leaf:.+\"\\]$/\n\n/**\n * Actions builder (AGL-148): HubSpot-style enrollment — trigger event →\n * optional filter → ordered steps (run workflow, site alert, custom\n * event, dataset append). Runs server-side via runEventActions; paid\n * feature (`actions` flag, Pro+, `actionRunsPerMonth` metered).\n */\nexport function HostActionsCard(props: {\n hostId: string\n org?: Partial<AglynOrgBilling>\n}) {\n const { hostId, org } = props\n // Org-shared data root (AGL-237). Null until the org lookup settles\n // (AGL-1061), and for a host with no owning org — the pre-migration host\n // path is gone (AGL-1050), so the dataset and list pickers stay empty\n // instead of offering rows from a path nothing else reads.\n const firestore = useFirestore()\n // Action creation is server-owned since AGL-2266 (the cap); every other\n // action write on this surface stays client-direct.\n const createResource = useHostResourceApi()\n const { enqueueSnackbar } = useSnackbar()\n const { confirm } = useConfirmationContext()\n /**\n * The shell's zone renderer, for what other plugins add to automations\n * (AGL-2919); `null` outside the console shell, where there is no workspace\n * to gate on.\n */\n const ExtensionZone = useConsoleWidgetSlot()\n\n const {\n data: actionDocs,\n status: actionsStatus,\n /**\n * The action rows this card's editor is seeded from are unconfirmed by\n * the server (AGL-1358). Editing an action copies the whole stored row\n * into `draft` — name, trigger and every step — and writes all of it\n * back, so `merge: true` protects nothing and a cached seed reverts a\n * colleague's newer version of the steps nobody here touched.\n *\n * The same shape the interaction builder guards (AGL-1066); this is its\n * card twin, and it was the one that never got the guard.\n */\n fromCache: actionsFromCache,\n } = useFirestoreCollection<any>(\n /*\n * ORDERED AND CEILINGED, deliberately not paged by the query (AGL-2501) —\n * the same decision as the workflows card beside it.\n *\n * `limit(100)` alone is answered in DOCUMENT-ID order, so the window was a\n * pseudo-random hundred that the `localeCompare` below arranged\n * alphabetically, and nothing said the list was bounded.\n *\n * `collectionCeiling` does not change WHICH hundred — document-id order is\n * what the bare cap already returned. What it changes is that the order is\n * NAMED, so the obvious next edit is caught: ordering on `name` would HIDE\n * every action written without one rather than mis-sorting the list, and\n * `/api/hosts/resources` validates no field for presence while\n * `IMPORTABLE_FIELDS.actions` copies one only if the export carried it.\n *\n * The QUERY is not paged because this collection holds TWO audiences. A\n * row whose trigger names a leaf selector is an element interaction, which\n * belongs to its document and is reported below as a count rather than\n * listed; the rest are the site's actions. Both partitions are derived\n * from the rows in hand, so a server page would make \"3 interactions are\n * set up on their own elements\" mean \"3 on this page\" — a count that is a\n * window length, which is the defect this sweep keeps finding rather than\n * a shape it should add.\n */\n () =>\n collectionCeiling(\n collection(firestore, 'hosts', hostId, 'actions'),\n ACTION_CEILING,\n ),\n [firestore, hostId],\n { idField: '$id' },\n )\n const { rows: readActions, truncated: actionsTruncated } =\n ceilingedWindow<any>(actionDocs, ACTION_CEILING)\n const [draft, setDraft] = useState<ActionDraft | null>(null)\n /**\n * The editor has been opened at least once in this session.\n *\n * A LATCH rather than `draft` itself, because the pickers below key their\n * listeners on it. Tracking the dialog would tear those subscriptions down\n * on Cancel and pay for them again on the next Edit, so a merchant working\n * through ten actions would buy the same six windows ten times — worse than\n * the mount-time read this replaces. Latched, a reader who never edits pays\n * nothing and a reader who edits pays once.\n */\n const [editorOpened, setEditorOpened] = useState(false)\n if (draft && !editorOpened) setEditorOpened(true)\n /*\n * The step editor's six option lists, read on the same latch as the\n * Workflows builder's — one hook, because the two editors offer one set of\n * steps and a second copy would be a second read cost to keep in agreement.\n */\n const { pickers: stepPickers, truncated: truncatedPickers } =\n useAutomationStepPickers(hostId, editorOpened)\n const liveActions = readActions.filter((action: any) => !action.deletedAt)\n /*\n * Opens a listed action in the editor, for a widget in the `hostAutomations`\n * zone — one that drafted an action and offers to open it. Read through a\n * ref so the callback keeps one identity while the list changes beneath it,\n * and answers `false` for an id the list has not read yet.\n */\n const listedRef = useRef<any[]>(liveActions)\n listedRef.current = liveActions\n const openAction = useCallback((actionId: string) => {\n const action = listedRef.current.find((row: any) => row.$id === actionId)\n if (!action) return false\n setDraft(draftFromAction(action, action.$id))\n return true\n }, [])\n /**\n * Element interactions are not listed here.\n *\n * An ACTION is something the SITE does — an order was placed, a form was\n * submitted. An INTERACTION is something an ELEMENT does, and it belongs to\n * the document that holds the element: it publishes and rolls back with it,\n * travels with it, and is deleted with it. This page is the site's\n * automation list, and a nav menu's hover timing sitting in it beside \"when\n * an order is placed\" was the tell that the two had been conflated.\n *\n * These rows are the ones written BEFORE the move, still bound by selector.\n * They keep running and stay editable — on their element, in the besigner,\n * which is now the only place they appear. Counted rather than hidden\n * outright, so the page can say where they went instead of appearing to\n * have lost them.\n */\n const elementScoped = liveActions.filter((action: any) =>\n LEAF_SELECTOR.test(String(action?.trigger?.selector ?? '')),\n )\n // Sorting is safe here in a way it is not on a paged list: these rows are\n // the whole collection below the ceiling, not a slice of one.\n const actions = liveActions\n .filter((action: any) => !elementScoped.includes(action))\n .sort((a: any, b: any) =>\n String(a.name ?? '').localeCompare(String(b.name ?? '')),\n )\n // The page is a SLICE: the rows are already in hand, and both the element\n // interaction count and the alphabetical order need all of them.\n const [page, setPage] = useState(0)\n const [pageSize, setPageSize] = useState(TABLE_PAGE_SIZE_DEFAULT)\n const visibleActions = useMemo(\n () => actions.slice(page * pageSize, page * pageSize + pageSize),\n [actions, page, pageSize],\n )\n\n const patch = useCallback(\n (updater: (previous: ActionDraft) => ActionDraft) =>\n setDraft((previous) => (previous ? updater(previous) : previous)),\n [],\n )\n\n /** The saved action the editor has open, as the `automationEditor` zone names it. */\n const draftId = draft?.id ?? null\n const draftName = draft?.name ?? ''\n const editorTarget = useMemo<ConsoleAutomationTarget | null>(\n () => (draftId ? { type: 'action', id: draftId, name: draftName } : null),\n // The name the editor opened with: the zone reads the automation as it is\n // stored, so a rename being typed does not make it a different one.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [draftId],\n )\n\n /**\n * Whether this workspace may open the editor at all. One gate for the\n * blank action and the recipes: a recipe is an action, so the plan that\n * carries one carries the other, and the refusal reads the same.\n */\n const actionsEntitled = useCallback(() => {\n if (checkEntitlement(org, 'actions')) return true\n enqueueSnackbar(\n 'The actions builder requires a Pro plan — see Billing to upgrade',\n { variant: 'warning', persist: false },\n )\n return false\n }, [org, enqueueSnackbar])\n\n const handleAdd = useCallback(() => {\n if (!actionsEntitled()) return\n setDraft({\n id: null,\n name: '',\n trigger: { event: 'formSubmission', filter: '' },\n steps: [defaultStep('siteAlert')],\n enabled: true,\n customEvent: '',\n conditionRows: [EMPTY_CONDITION_ROW],\n conditionCombinator: 'and',\n recipe: null,\n })\n }, [actionsEntitled])\n\n /*\n * THE RECIPES (AGL-2626).\n *\n * A recipe opens the editor prefilled and writes nothing: the draft it\n * builds is the one Save would persist, and until then it is state in\n * this card and nowhere else. Three recipes open at once; \"Tag by form\"\n * needs a form first, and the form is this site's — `hosts/{hostId}/forms`\n * — so the picker is the one host-scoped piece of the feature, held here\n * rather than in the catalog.\n */\n const [recipesAnchor, setRecipesAnchor] = useState<HTMLElement | null>(null)\n const [formPickFor, setFormPickFor] = useState<CrmActionRecipe | null>(null)\n const [pickedFormId, setPickedFormId] = useState('')\n /**\n * The form picker has been opened at least once — the `editorOpened`\n * latch's twin, and for the same reason: the forms window is read for\n * this picker only, and a reader who never opens it pays nothing.\n */\n const [formPickerOpened, setFormPickerOpened] = useState(false)\n if (formPickFor && !formPickerOpened) setFormPickerOpened(true)\n const { data: formRead } = useFirestoreCollection<any>(\n () =>\n formPickerOpened\n ? collectionCeiling(\n collection(firestore, 'hosts', hostId, 'forms'),\n EDITOR_OPTION_CEILING,\n )\n : null,\n [firestore, hostId, formPickerOpened],\n { idField: '$id' },\n )\n const { rows: formDocs, truncated: formsTruncated } = ceilingedWindow<any>(\n formRead,\n EDITOR_OPTION_CEILING,\n )\n // An archived form collects nothing, so a recipe keyed on it would never\n // fire; the name falls back to the id the way every form list's does.\n const formOptions = (formDocs ?? [])\n .filter((form: any) => !form.archivedAt)\n .map((form: any) => ({\n id: form.$id as string,\n name: (String(form.displayName ?? '').trim() || form.$id) as string,\n }))\n .sort((a: { name: string }, b: { name: string }) =>\n a.name.localeCompare(b.name),\n )\n\n const handleRecipe = useCallback(\n (recipe: CrmActionRecipe) => {\n setRecipesAnchor(null)\n if (!actionsEntitled()) return\n if (recipe.needs === 'form') {\n setPickedFormId('')\n setFormPickFor(recipe)\n return\n }\n setDraft(draftFromAction(recipe.build(), null))\n },\n [actionsEntitled],\n )\n\n const handleFormPicked = useCallback(() => {\n const recipe = formPickFor\n const form = formOptions.find((option) => option.id === pickedFormId)\n if (!recipe || !form) return\n setFormPickFor(null)\n setDraft(draftFromAction(recipe.build({ form }), null))\n }, [formPickFor, formOptions, pickedFormId])\n\n // Run log + test runs (AGL-266).\n const [runsFor, setRunsFor] = useState<any | null>(null)\n const handleTestRun = useCallback(\n async (action: any) => {\n try {\n const response = await fetch('/api/events/dispatch', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n hostId,\n actionId: action.$id,\n event: action.trigger?.event,\n payload: { path: '/console-test', test: 'true' },\n }),\n })\n const payload = await response.json().catch(() => ({}))\n if (!response.ok) {\n return void enqueueSnackbar(payload?.error ?? 'Test run failed', {\n variant: 'warning',\n persist: false,\n })\n }\n const alerts = Array.isArray(payload?.alerts) ? payload.alerts : []\n enqueueSnackbar(\n alerts.length\n ? `Test ran — first alert: ${alerts[0].message}`\n : 'Test ran — server steps executed (see Runs)',\n { variant: 'success', persist: false },\n )\n } catch (error) {\n console.error(error)\n enqueueSnackbar('Test run failed', { variant: 'error' })\n }\n },\n [hostId, enqueueSnackbar],\n )\n\n const handleSave = useCallback(async () => {\n if (!draft) return\n const isCustom = draft.trigger.event === CUSTOM_EVENT_VALUE\n const candidate: HostAction = {\n name: draft.name.trim().slice(0, 60),\n trigger: {\n event: isCustom ? draft.customEvent.trim() : draft.trigger.event,\n ...(draft.trigger.filter?.trim()\n ? { filter: draft.trigger.filter.trim() }\n : {}),\n // Site-event config (AGL-256).\n ...(draft.trigger.selector?.trim()\n ? { selector: draft.trigger.selector.trim() }\n : {}),\n ...(Number(draft.trigger.threshold) > 0\n ? { threshold: Number(draft.trigger.threshold) }\n : {}),\n ...(draft.trigger.pathPattern?.trim()\n ? { pathPattern: draft.trigger.pathPattern.trim() }\n : {}),\n // Frequency caps (AGL-274).\n ...(draft.trigger.oncePerVisitor === true\n ? { oncePerVisitor: true }\n : {}),\n ...(draft.trigger.oncePerSession === true\n ? { oncePerSession: true }\n : {}),\n ...(Number(draft.trigger.cooldownMinutes) >= 1\n ? { cooldownMinutes: Number(draft.trigger.cooldownMinutes) }\n : {}),\n ...(draft.trigger.everyTime === true ? { everyTime: true } : {}),\n // Structured payload conditions (AGL-557; chained AGL-565):\n // rows keep their blank fields so validateHostAction surfaces\n // the miss. Saves always write the list shape — the legacy\n // single `condition` is only ever read, never written back.\n ...conditionsFromRows(draft.conditionRows, draft.conditionCombinator),\n },\n steps: draft.steps,\n enabled: draft.enabled !== false,\n // The stamp travels only when the draft knows one way or the other;\n // an older action's silence is kept (see hostActionRecipeId).\n ...(draft.recipe !== undefined ? { recipe: draft.recipe } : {}),\n }\n const problem = validateHostAction(candidate)\n if (problem) {\n return void enqueueSnackbar(problem, {\n variant: 'warning',\n persist: false,\n })\n }\n try {\n const id = draft.id ?? createResourceUid()\n /**\n * Refuse an EDIT whose seed the server never confirmed (AGL-1358).\n *\n * The payload is the whole action. `merge: true` is here so the\n * frequency caps and conditions can be nulled explicitly, not to\n * protect untouched fields — there are none, they are all in the\n * payload. So a cached seed does not lose one edit, it reverts the\n * trigger and every step to whatever the cache last held, on an\n * automation that is running on a live site.\n *\n * Only the edit path. A NEW action is built from `EMPTY_*` defaults at\n * a fresh uid and can overwrite nothing; the first snapshot of any\n * listener is `fromCache: true`, so guarding a create would refuse a\n * save that was never unsafe.\n *\n * The guard WRAPS the write — the interaction builder's early return\n * is the shape you can keep while losing the protection.\n */\n /**\n * The action DOCUMENT is created by the server (AGL-2266).\n *\n * `hosts/{hostId}/actions` was in none of the host catch-all's exclusion\n * lists, so any editor could create one client-direct on any plan and\n * nothing counted them. /api/hosts/resources now owns the create and\n * holds `ACTIONS_MAX_PER_HOST` from a server read.\n *\n * Only the create moves, and it writes a SHELL. The merge-set below is\n * untouched and still carries the whole candidate — trigger, steps,\n * conditions, the explicit nulls AGL-274/557 depend on — so no field can\n * be lost to the route's allow-list, and for an existing action this\n * path does not run at all.\n */\n if (!draft.id) {\n try {\n await createResource({\n hostId,\n resource: 'action',\n id,\n data: { name: candidate.name ?? draft.name ?? 'Untitled action' },\n })\n } catch (error: any) {\n return void enqueueSnackbar(\n error?.message ?? 'Could not create the interaction',\n { variant: 'error' },\n )\n }\n }\n const verdict = await writeGuardedBySeed(\n {\n subject: 'action',\n unreadable: Boolean(draft.id) && actionsStatus === 'error',\n fromCache: Boolean(draft.id) && actionsFromCache,\n },\n async () => {\n await setDoc(\n doc(firestore, 'hosts', hostId, 'actions', id),\n {\n // The stored shape (AGL-2639), shared with the recipe-install\n // route: frequency caps overwrite explicitly (AGL-274) because\n // a merge-set keeps omitted keys, so switching one off must\n // write it out; conditions follow suit (AGL-557/565) — the\n // list + combinator write null when cleared, and the legacy\n // single `condition` is always nulled.\n ...hostActionDocument(candidate),\n updatedAt: Timestamp.now(),\n ...(draft.id ? {} : { createdAt: Timestamp.now() }),\n },\n { merge: true },\n )\n },\n )\n // A refusal keeps the editor open with everything that was typed.\n if (!verdict.ok) {\n return void enqueueSnackbar(verdict.message, {\n variant: 'warning',\n persist: false,\n })\n }\n setDraft(null)\n enqueueSnackbar('Action saved', { variant: 'success', persist: false })\n } catch (error) {\n console.error(error)\n enqueueSnackbar('An error has occurred', {\n variant: 'error',\n allowDuplicate: true,\n })\n }\n }, [\n draft,\n firestore,\n createResource,\n hostId,\n enqueueSnackbar,\n actionsFromCache,\n actionsStatus,\n ])\n\n const handleDelete = useCallback(\n (action: any) => async () => {\n const confirmed = await confirm({\n title: 'Delete this action?',\n description: `\"${action.name}\" stops running on its trigger.`,\n confirmationText: 'Delete',\n confirmationButtonProps: { color: 'error' },\n })\n .then(() => true)\n .catch(() => false)\n if (!confirmed) return\n await updateDoc(doc(firestore, 'hosts', hostId, 'actions', action.$id), {\n deletedAt: Timestamp.now(),\n })\n },\n [confirm, firestore, hostId],\n )\n\n const handleToggle = useCallback(\n (action: any) => async (event: { target: { checked: boolean } }) => {\n const enabled = event.target.checked\n /*\n * A placeholder is a value nobody has supplied yet. Switched on, the\n * step holding it fails every run and a condition holding one never\n * matches, so turning such an automation on is confirmed, naming what\n * is still missing.\n */\n const missing = enabled ? automationPlaceholders(action) : []\n if (missing.length) {\n const confirmed = await confirm({\n title: 'Switch on with placeholders?',\n description:\n `\"${action.name}\" still has ${missing.length === 1 ? 'a placeholder' : `${missing.length} placeholders`} ` +\n `to fill in: ${missing.slice(0, 3).map(describeAutomationPlaceholder).join('; ')}` +\n `${missing.length > 3 ? '; …' : ''}. Open it with Edit to fill ` +\n `${missing.length === 1 ? 'it' : 'them'} in first.`,\n confirmationText: 'Switch on anyway',\n })\n .then(() => true)\n .catch(() => false)\n if (!confirmed) return\n }\n await updateDoc(doc(firestore, 'hosts', hostId, 'actions', action.$id), {\n enabled,\n })\n },\n [confirm, firestore, hostId],\n )\n\n return (\n <CardDisplay\n header={'Actions'}\n help={pluginDocsHelp('actionsBuilder', { anchor: '#create-an-action' })}\n contentGutterX\n contentGutterY\n >\n <Stack spacing={1}>\n <Typography variant=\"body2\" color=\"text.secondary\">\n {'When a site event fires, run automations in order — trigger a ' +\n 'workflow, show the visitor an alert, chain a custom event, or ' +\n 'write to a dataset. Pro plans and up.'}\n </Typography>\n {visibleActions.map((action: any) => {\n const missing = automationPlaceholders(action).length\n return (\n <Stack\n key={action.$id}\n direction=\"row\"\n spacing={1}\n sx={{ alignItems: 'center' }}\n >\n <Switch\n size=\"small\"\n checked={action.enabled !== false}\n onChange={handleToggle(action)}\n />\n <Stack sx={{ flex: 1, minWidth: 0 }}>\n <Typography variant=\"body2\" noWrap>\n {action.name}\n </Typography>\n <Typography variant=\"caption\" color=\"text.secondary\" noWrap>\n {`on ${hostEventLabel(action.trigger?.event)}` +\n ` · ${(action.steps ?? [])\n .map(\n (step: any) =>\n HOST_ACTION_STEP_LABELS[\n step.type as HostActionStepType\n ] ?? step.type,\n )\n .join(' → ')}`}\n </Typography>\n {missing ? (\n <Typography variant=\"caption\" color=\"warning.main\" noWrap>\n {missing === 1\n ? '1 placeholder to fill in'\n : `${missing} placeholders to fill in`}\n </Typography>\n ) : null}\n </Stack>\n <Button\n size=\"small\"\n onClick={() => setDraft(draftFromAction(action, action.$id))}\n >\n {'Edit'}\n </Button>\n {isSiteEventType(String(action.trigger?.event ?? '')) ? (\n // Test run (AGL-266): server steps only, via the dispatch API.\n <Button size=\"small\" onClick={() => void handleTestRun(action)}>\n {'Test'}\n </Button>\n ) : null}\n <Button size=\"small\" onClick={() => setRunsFor(action)}>\n {'Runs'}\n </Button>\n <Button size=\"small\" color=\"error\" onClick={handleDelete(action)}>\n {'Delete'}\n </Button>\n </Stack>\n )\n })}\n {actions.length === 0 ? null : (\n <ListPagination\n page={page}\n pageSize={pageSize}\n rowCount={visibleActions.length}\n // The actions the card HOLDS, which is what the reader is paging\n // through — not the collection, whose other half is the element\n // interactions counted below.\n count={actions.length}\n onPageChange={setPage}\n onPageSizeChange={setPageSize}\n />\n )}\n {actionsTruncated ? (\n <Alert severity=\"info\">\n {`Showing the first ${ACTION_CEILING} rows of this site’s ` +\n 'automations, ordered by id. There are more — both the list ' +\n 'above and the interaction count below describe only what was ' +\n 'read.'}\n </Alert>\n ) : null}\n <Stack direction=\"row\" spacing={1} sx={{ alignSelf: 'flex-start' }}>\n <Button size=\"small\" color=\"primary\" onClick={handleAdd}>\n {'Add action'}\n </Button>\n <Button\n size=\"small\"\n color=\"primary\"\n aria-haspopup=\"menu\"\n aria-controls={recipesAnchor ? 'host-action-recipes' : undefined}\n aria-expanded={recipesAnchor ? true : undefined}\n onClick={(event) => setRecipesAnchor(event.currentTarget)}\n >\n {'Recipes'}\n </Button>\n {/*\n Other ways to start an automation, from plugins (AGL-2919): the\n `hostAutomations` zone, drawn through the shell's own gated slot. A\n plugin page cannot mount that slot itself, so the shell hands it\n down, and a widget here passes the gates a console page's would.\n */}\n {ExtensionZone ? (\n <ExtensionZone\n slot=\"hostAutomations\"\n hostId={hostId}\n orgId={org?.$id}\n openAction={openAction}\n />\n ) : null}\n </Stack>\n <Menu\n id=\"host-action-recipes\"\n anchorEl={recipesAnchor}\n open={Boolean(recipesAnchor)}\n onClose={() => setRecipesAnchor(null)}\n >\n {CRM_ACTION_RECIPES.map((recipe) => (\n <MenuItem key={recipe.id} onClick={() => handleRecipe(recipe)}>\n <ListItemText\n primary={recipe.title}\n secondary={recipe.description}\n slotProps={{ secondary: { sx: { whiteSpace: 'normal', maxWidth: 360 } } }}\n />\n </MenuItem>\n ))}\n </Menu>\n {/* Says where they went. A list that silently drops rows\n a reader saw last week is a list they stop trusting; this is the\n one sentence that makes the absence deliberate. */}\n {elementScoped.length ? (\n <Typography variant=\"caption\" color=\"text.secondary\">\n {elementScoped.length === 1\n ? '1 interaction is set up on its own element — '\n : `${elementScoped.length} interactions are set up on their own elements — `}\n {'open the element in the besigner to edit it. Interactions ' +\n 'belong to the page they are on, so they publish and roll back ' +\n 'with it.'}\n </Typography>\n ) : null}\n </Stack>\n\n <Dialog\n open={Boolean(draft)}\n onClose={() => setDraft(null)}\n maxWidth=\"sm\"\n fullWidth\n >\n <DialogTitle>{draft?.id ? 'Edit action' : 'Add action'}</DialogTitle>\n <DialogContent\n sx={{ display: 'flex', flexDirection: 'column', gap: 1.5, pt: 1 }}\n >\n {ExtensionZone && editorTarget ? (\n <ExtensionZone\n slot=\"automationEditor\"\n hostId={hostId}\n orgId={org?.$id}\n target={editorTarget}\n />\n ) : null}\n {draft?.recipe ? (\n <Typography variant=\"body2\" color=\"text.secondary\">\n {`Started from the “${\n CRM_ACTION_RECIPES.find((recipe) => recipe.id === draft.recipe)\n ?.title ?? 'recipe'\n }” recipe — change anything, then save.`}\n </Typography>\n ) : null}\n {/*\n A short picker is worse than an empty one, because it looks\n complete: the target an author cannot find reads as deleted, and\n the step gets pointed somewhere else.\n */}\n {truncatedPickers.length > 0 ? (\n <Alert severity=\"info\" sx={{ mt: 1 }}>\n {`Offering the first ${EDITOR_OPTION_CEILING} rows, ordered by ` +\n `id, for: ${truncatedPickers.join(', ')}. This site has ` +\n 'more, so a step target may not be listed below.'}\n </Alert>\n ) : null}\n <TextField\n label=\"Name\"\n value={draft?.name ?? ''}\n onChange={(event) =>\n patch((previous) => ({ ...previous, name: event.target.value }))\n }\n size=\"small\"\n autoFocus\n sx={{ mt: 1 }}\n />\n <Stack direction=\"row\" spacing={1}>\n <TextField\n select\n label=\"Trigger event\"\n value={draft?.trigger.event ?? ''}\n onChange={(event) =>\n patch((previous) => ({\n ...previous,\n trigger: { ...previous.trigger, event: event.target.value },\n }))\n }\n size=\"small\"\n sx={{ minWidth: 180 }}\n >\n {HOST_EVENT_TYPES.map((eventType) => (\n <MenuItem key={eventType} value={eventType}>\n {hostEventLabel(eventType)}\n </MenuItem>\n ))}\n {SITE_EVENT_TYPES.map((eventType) => (\n <MenuItem key={eventType} value={eventType}>\n {`${eventType} (on page)`}\n </MenuItem>\n ))}\n <MenuItem value={CUSTOM_EVENT_VALUE}>{'Custom event…'}</MenuItem>\n </TextField>\n {draft?.trigger.event === CUSTOM_EVENT_VALUE ? (\n <TextField\n label=\"Custom event name\"\n value={draft?.customEvent ?? ''}\n onChange={(event) =>\n patch((previous) => ({\n ...previous,\n customEvent: event.target.value,\n }))\n }\n size=\"small\"\n sx={{ flex: 1 }}\n />\n ) : (\n <TextField\n label=\"Filter (optional)\"\n placeholder={'path == \"/pricing\"'}\n // What the expression — and the conditions below — can name\n // for this event; nothing for an event whose payload is not\n // written down, rather than a guess.\n helperText={hostEventPayloadHint(draft?.trigger.event) ?? undefined}\n value={draft?.trigger.filter ?? ''}\n onChange={(event) =>\n patch((previous) => ({\n ...previous,\n trigger: {\n ...previous.trigger,\n filter: event.target.value,\n },\n }))\n }\n size=\"small\"\n sx={{ flex: 1 }}\n />\n )}\n </Stack>\n {/* Structured payload conditions (AGL-557): the no-code sibling\n of the filter — e.g. only when `subscribe` is not empty.\n Chainable with AND/OR (AGL-565), rows styled like steps. */}\n <TriggerConditionRows\n rows={draft?.conditionRows ?? []}\n combinator={draft?.conditionCombinator ?? 'and'}\n onRowsChange={(update) =>\n patch((previous) => ({\n ...previous,\n conditionRows: update(previous.conditionRows),\n }))\n }\n onCombinatorChange={(combinator) =>\n patch((previous) => ({\n ...previous,\n conditionCombinator: combinator,\n }))\n }\n />\n {isSiteEventType(draft?.trigger.event ?? '') ? (\n // Site-event config (AGL-256): what/where the trigger watches.\n <Stack direction=\"row\" spacing={1}>\n {(ELEMENT_SCOPED_SITE_EVENTS as readonly string[]).includes(\n draft?.trigger.event ?? '',\n ) ? (\n <TextField\n label=\"CSS selector\"\n placeholder=\"#pricing-table\"\n value={draft?.trigger.selector ?? ''}\n onChange={(event) =>\n patch((previous) => ({\n ...previous,\n trigger: {\n ...previous.trigger,\n selector: event.target.value,\n },\n }))\n }\n size=\"small\"\n sx={{ flex: 1 }}\n />\n ) : null}\n {['scrollDepth', 'timeOnPage'].includes(\n draft?.trigger.event ?? '',\n ) ? (\n <TextField\n type=\"number\"\n label={\n draft?.trigger.event === 'scrollDepth'\n ? 'Scroll %'\n : 'Seconds'\n }\n value={draft?.trigger.threshold ?? ''}\n onChange={(event) =>\n patch((previous) => ({\n ...previous,\n trigger: {\n ...previous.trigger,\n threshold: Number(event.target.value),\n },\n }))\n }\n size=\"small\"\n sx={{ width: 120 }}\n />\n ) : null}\n <TextField\n label=\"Only on pages (optional)\"\n placeholder=\"/pricing or /blog/*\"\n value={draft?.trigger.pathPattern ?? ''}\n onChange={(event) =>\n patch((previous) => ({\n ...previous,\n trigger: {\n ...previous.trigger,\n pathPattern: event.target.value,\n },\n }))\n }\n size=\"small\"\n sx={{ flex: 1 }}\n />\n {/* Frequency caps (AGL-274). */}\n <TextField\n select\n label=\"Frequency\"\n size=\"small\"\n sx={{ minWidth: 170 }}\n value={\n draft?.trigger.oncePerVisitor\n ? 'visitor'\n : draft?.trigger.oncePerSession\n ? 'session'\n : Number(draft?.trigger.cooldownMinutes) >= 1\n ? 'cooldown'\n : draft?.trigger.everyTime\n ? 'every'\n : ''\n }\n onChange={(event) => {\n const mode = event.target.value\n patch((previous) => ({\n ...previous,\n trigger: {\n ...previous.trigger,\n // Every occurrence (AGL-562): repeatable UI\n // choreography (menu/drawer toggles).\n everyTime: mode === 'every',\n oncePerVisitor: mode === 'visitor',\n oncePerSession: mode === 'session',\n cooldownMinutes:\n mode === 'cooldown'\n ? Number(previous.trigger.cooldownMinutes) >= 1\n ? Number(previous.trigger.cooldownMinutes)\n : 60\n : undefined,\n },\n }))\n }}\n >\n <MenuItem value=\"\">{'Every matching pageview'}</MenuItem>\n <MenuItem value=\"every\">\n {'Every occurrence (repeatable)'}\n </MenuItem>\n <MenuItem value=\"session\">{'Once per session'}</MenuItem>\n <MenuItem value=\"visitor\">{'Once per visitor'}</MenuItem>\n <MenuItem value=\"cooldown\">{'With a cooldown'}</MenuItem>\n </TextField>\n {Number(draft?.trigger.cooldownMinutes) >= 1 &&\n !draft?.trigger.oncePerVisitor &&\n !draft?.trigger.oncePerSession ? (\n <TextField\n type=\"number\"\n label=\"Cooldown (minutes)\"\n size=\"small\"\n sx={{ width: 150 }}\n value={draft?.trigger.cooldownMinutes ?? 60}\n onChange={(event) =>\n patch((previous) => ({\n ...previous,\n trigger: {\n ...previous.trigger,\n cooldownMinutes: Number(event.target.value),\n },\n }))\n }\n />\n ) : null}\n </Stack>\n ) : null}\n <Typography variant=\"overline\" color=\"text.secondary\">\n {'Steps (run in order)'}\n </Typography>\n {(draft?.steps ?? []).map((step, index) => (\n <AutomationStepFields\n key={index}\n step={step}\n index={index}\n kind={step.type}\n kinds={ACTION_STEP_KINDS}\n stepForKind={(value) => defaultStep(value as HostActionStepType)}\n pickers={stepPickers}\n onSteps={(update) =>\n patch((previous) => ({\n ...previous,\n steps: update(previous.steps),\n }))\n }\n />\n ))}\n <Button\n size=\"small\"\n sx={{ alignSelf: 'flex-start' }}\n disabled={(draft?.steps.length ?? 0) >= ACTION_MAX_STEPS}\n onClick={() =>\n patch((previous) => ({\n ...previous,\n steps: [...previous.steps, defaultStep('siteAlert')],\n }))\n }\n >\n {'Add step'}\n </Button>\n </DialogContent>\n <DialogActions>\n <Button onClick={() => setDraft(null)}>{'Cancel'}</Button>\n <Button\n variant=\"contained\"\n color=\"primary\"\n disabled={!draft?.name.trim()}\n onClick={handleSave}\n >\n {'Save action'}\n </Button>\n </DialogActions>\n </Dialog>\n <Dialog\n open={Boolean(formPickFor)}\n onClose={() => setFormPickFor(null)}\n maxWidth=\"xs\"\n fullWidth\n >\n <DialogTitle>{formPickFor?.title ?? ''}</DialogTitle>\n <DialogContent\n sx={{ display: 'flex', flexDirection: 'column', gap: 1.5, pt: 1 }}\n >\n <Typography variant=\"body2\" color=\"text.secondary\">\n {'Pick the form whose new contacts get the tag. The action opens ' +\n 'ready to edit; nothing is saved until you save it.'}\n </Typography>\n {formsTruncated ? (\n <Alert severity=\"info\">\n {`Offering the first ${EDITOR_OPTION_CEILING} forms, ordered by ` +\n 'id. This site has more, so the form you want may not be listed.'}\n </Alert>\n ) : null}\n {formOptions.length ? (\n <TextField\n select\n label=\"Form\"\n value={pickedFormId}\n onChange={(event) => setPickedFormId(event.target.value)}\n size=\"small\"\n sx={{ mt: 1 }}\n >\n {formOptions.map((option) => (\n <MenuItem key={option.id} value={option.id}>\n {option.name}\n </MenuItem>\n ))}\n </TextField>\n ) : (\n <Typography variant=\"body2\" color=\"text.secondary\">\n {'This site has no forms yet. Add one in the besigner, then come back.'}\n </Typography>\n )}\n </DialogContent>\n <DialogActions>\n <Button color=\"inherit\" onClick={() => setFormPickFor(null)}>\n {'Cancel'}\n </Button>\n <Button\n variant=\"contained\"\n disabled={!pickedFormId}\n onClick={handleFormPicked}\n >\n {'Use recipe'}\n </Button>\n </DialogActions>\n </Dialog>\n <Dialog\n open={Boolean(runsFor)}\n onClose={() => setRunsFor(null)}\n maxWidth=\"sm\"\n fullWidth\n >\n <DialogTitle>{`Runs — ${runsFor?.name ?? ''}`}</DialogTitle>\n <DialogContent>\n {runsFor ? (\n <HostRunHistoryCard\n hostId={hostId}\n orgId={org?.$id}\n targetId={runsFor.$id}\n targetType=\"action\"\n targetName={runsFor.name ?? ''}\n header=\"Recent runs\"\n />\n ) : null}\n </DialogContent>\n <DialogActions>\n <Button color=\"inherit\" onClick={() => setRunsFor(null)}>\n {'Close'}\n </Button>\n </DialogActions>\n </Dialog>\n </CardDisplay>\n )\n}\nHostActionsCard.displayName = 'HostActionsCard'\n\nexport default HostActionsCard\n"],"names":["ACTION_MAX_STEPS","checkEntitlement","createResourceUid","CRM_ACTION_RECIPES","ELEMENT_SCOPED_SITE_EVENTS","HOST_ACTION_STEP_LABELS","HOST_EVENT_TYPES","hostActionDocument","hostActionRecipeId","hostEventLabel","hostEventPayloadHint","isSiteEventType","pluginDocsHelp","SITE_EVENT_TYPES","validateHostAction","automationPlaceholders","describeAutomationPlaceholder","useConsoleWidgetSlot","CardDisplay","useConfirmationContext","ListPagination","TABLE_PAGE_SIZE_DEFAULT","useSnackbar","Timestamp","Alert","Button","Dialog","DialogActions","DialogContent","DialogTitle","ListItemText","Menu","MenuItem","Stack","Switch","TextField","Typography","collection","doc","setDoc","updateDoc","useCallback","useMemo","useRef","useState","ceilingedWindow","collectionCeiling","useFirestore","useFirestoreCollection","useHostResourceApi","writeGuardedBySeed","AutomationStepFields","defaultStep","conditionRowsFromTrigger","conditionsFromRows","EMPTY_CONDITION_ROW","TriggerConditionRows","HostRunHistoryCard","EDITOR_OPTION_CEILING","useAutomationStepPickers","CUSTOM_EVENT_VALUE","ACTION_CEILING","ACTION_STEP_KINDS","Object","entries","map","value","label","draftFromAction","action","id","builtIn","includes","trigger","event","String","name","filter","selector","threshold","pathPattern","oncePerVisitor","oncePerSession","everyTime","Number","cooldownMinutes","steps","enabled","customEvent","conditionRows","conditionCombinator","combinator","recipe","LEAF_SELECTOR","HostActionsCard","props","runsFor","hostId","org","firestore","createResource","enqueueSnackbar","confirm","ExtensionZone","data","actionDocs","status","actionsStatus","fromCache","actionsFromCache","idField","rows","readActions","truncated","actionsTruncated","draft","setDraft","editorOpened","setEditorOpened","pickers","stepPickers","truncatedPickers","liveActions","deletedAt","listedRef","current","openAction","actionId","find","row","$id","elementScoped","test","actions","sort","a","b","localeCompare","page","setPage","pageSize","setPageSize","visibleActions","slice","patch","updater","previous","draftId","draftName","editorTarget","type","actionsEntitled","variant","persist","handleAdd","recipesAnchor","setRecipesAnchor","formPickFor","setFormPickFor","pickedFormId","setPickedFormId","formPickerOpened","setFormPickerOpened","formRead","formDocs","formsTruncated","formOptions","form","archivedAt","displayName","trim","handleRecipe","needs","build","handleFormPicked","option","setRunsFor","handleTestRun","response","fetch","method","headers","body","JSON","stringify","payload","path","json","catch","ok","error","alerts","Array","isArray","length","message","console","handleSave","isCustom","candidate","undefined","problem","resource","verdict","subject","unreadable","Boolean","updatedAt","now","createdAt","merge","allowDuplicate","handleDelete","confirmed","title","description","confirmationText","confirmationButtonProps","color","then","handleToggle","target","checked","missing","join","header","help","anchor","contentGutterX","contentGutterY","spacing","direction","sx","alignItems","size","onChange","flex","minWidth","noWrap","step","onClick","rowCount","count","onPageChange","onPageSizeChange","severity","alignSelf","aria-haspopup","aria-controls","aria-expanded","currentTarget","slot","orgId","anchorEl","open","onClose","primary","secondary","slotProps","whiteSpace","maxWidth","fullWidth","display","flexDirection","gap","pt","mt","autoFocus","select","eventType","placeholder","helperText","onRowsChange","update","onCombinatorChange","width","mode","index","kind","kinds","stepForKind","onSteps","disabled","targetId","targetType","targetName"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/workflows/src/lib/components/host-actions-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 ACTION_MAX_STEPS,\n type AglynOrgBilling,\n checkEntitlement,\n createResourceUid,\n CRM_ACTION_RECIPES,\n type CrmActionRecipe,\n type CrmActionRecipeId,\n ELEMENT_SCOPED_SITE_EVENTS,\n HOST_ACTION_STEP_LABELS,\n HOST_EVENT_TYPES,\n type HostAction,\n hostActionDocument,\n hostActionRecipeId,\n type HostActionStepType,\n hostEventLabel,\n hostEventPayloadHint,\n isSiteEventType,\n pluginDocsHelp,\n SITE_EVENT_TYPES,\n type TriggerCombinator,\n validateHostAction,\n} from '@aglyn/aglyn'\nimport {\n automationPlaceholders,\n describeAutomationPlaceholder,\n} from '@aglyn/aglyn/app-utils/automation-placeholders'\nimport { useConsoleWidgetSlot } from '@aglyn/aglyn/app-utils/console-widget-slot-context'\nimport type { ConsoleAutomationTarget } from '@aglyn/aglyn/plugin-manager/feature-plugins'\nimport { CardDisplay, useConfirmationContext } 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 { useSnackbar } from '@aglyn/shared-ui-snackstack'\nimport { authorizedFetch } from '@aglyn/shared-util-http/authorized-token'\nimport { Timestamp } from '@aglyn/shared-util-timestamp'\nimport {\n Alert,\n Button,\n Dialog,\n DialogActions,\n DialogContent,\n DialogTitle,\n ListItemText,\n Menu,\n MenuItem,\n Stack,\n Switch,\n TextField,\n Typography,\n} from '@mui/material'\nimport {\n collection,\n doc,\n setDoc,\n updateDoc,\n} from 'firebase/firestore'\nimport { useCallback, useMemo, useRef, useState } from 'react'\nimport {\n ceilingedWindow,\n collectionCeiling,\n useFirestore,\n useFirestoreCollection,\n useHostResourceApi,\n useUser,\n writeGuardedBySeed,\n} from '@aglyn/tenant-feature-instance'\nimport { ACTION_TEST_RUN_API_ROUTE } from '../model/action-test-run'\nimport {\n AutomationStepFields,\n type AutomationStepKind,\n defaultStep,\n} from './automation-step-fields.component'\nimport {\n conditionRowsFromTrigger,\n conditionsFromRows,\n type ConditionRowDraft,\n EMPTY_CONDITION_ROW,\n TriggerConditionRows,\n} from './automation-trigger-conditions.component'\nimport HostRunHistoryCard from './host-run-history-card.component'\nimport {\n EDITOR_OPTION_CEILING,\n useAutomationStepPickers,\n} from './use-automation-step-pickers'\n\nconst CUSTOM_EVENT_VALUE = '__custom__'\n\n/**\n * How many action documents the card reads.\n *\n * A CEILING, not a page size — see the query, which explains why this one\n * collection cannot be sliced by the server without making the count beneath\n * the list a per-page number.\n *\n * `ACTIONS_MAX_PER_HOST` is 500, so the ceiling really can bite and the probe\n * beside it is what says when it has.\n */\nconst ACTION_CEILING = 100\n\ninterface ActionDraft extends HostAction {\n id: string | null\n /** Raw custom-event text when the trigger select is on \"custom\". */\n customEvent: string\n // Structured payload conditions (AGL-557), chainable with AND/OR\n // (AGL-565) — held as rows like the steps list; legacy\n // single-`condition` docs hydrate through normalizeTriggerConditions.\n conditionRows: ConditionRowDraft[]\n conditionCombinator: TriggerCombinator\n /**\n * The recipe this draft started from (AGL-2626), so the editor can say\n * so, and what Save writes back as the action's stamp (AGL-2639): null\n * for an action begun blank, and `undefined` for a stored action from\n * before the stamp existed — which Save leaves as it found it, so an\n * edit never turns \"unknown\" into \"no recipe\".\n */\n recipe: CrmActionRecipeId | null | undefined\n}\n\n\n/** Every Actions step, as the builder's \"Do\" picker offers it. */\nconst ACTION_STEP_KINDS: AutomationStepKind[] = Object.entries(\n HOST_ACTION_STEP_LABELS,\n).map(([value, label]) => ({ value, label }))\n\n\n/**\n * A stored action — or one a recipe just built — as the editor holds it.\n *\n * One conversion for both doors, because they must agree: an action that\n * round-trips through Edit and one a recipe hands over are the same shape\n * to the editor, and a field the Edit path hydrated that the recipe path\n * forgot would be a recipe whose conditions vanished on open. Site events\n * are first-class (AGL-256/266): their selector/threshold/path config is\n * kept through an edit. Structured conditions (AGL-557; chained AGL-565)\n * become rows; a legacy single-condition doc normalizes to one row.\n */\nfunction draftFromAction(\n action: Record<string, any>,\n id: string | null,\n): ActionDraft {\n const builtIn =\n HOST_EVENT_TYPES.includes(action.trigger?.event) ||\n isSiteEventType(String(action.trigger?.event ?? ''))\n return {\n id,\n name: action.name ?? '',\n trigger: {\n event: builtIn ? action.trigger.event : CUSTOM_EVENT_VALUE,\n filter: action.trigger?.filter ?? '',\n selector: action.trigger?.selector ?? '',\n threshold: action.trigger?.threshold,\n pathPattern: action.trigger?.pathPattern ?? '',\n oncePerVisitor: action.trigger?.oncePerVisitor === true,\n oncePerSession: action.trigger?.oncePerSession === true,\n everyTime: action.trigger?.everyTime === true,\n ...(Number(action.trigger?.cooldownMinutes) >= 1\n ? { cooldownMinutes: Number(action.trigger?.cooldownMinutes) }\n : {}),\n },\n steps: action.steps ?? [],\n enabled: action.enabled !== false,\n customEvent: builtIn ? '' : (action.trigger?.event ?? ''),\n conditionRows: conditionRowsFromTrigger(action.trigger),\n conditionCombinator: action.trigger?.combinator === 'or' ? 'or' : 'and',\n // A recipe stamps what it builds, and a stored action carries what it\n // was saved with — one reader for both doors, unknown kept unknown.\n recipe: hostActionRecipeId(action),\n }\n}\n\n/** A trigger bound to one element, which makes the row an interaction. */\nconst LEAF_SELECTOR = /^\\[data-aglyn=\"leaf:.+\"\\]$/\n\n/**\n * Actions builder (AGL-148): HubSpot-style enrollment — trigger event →\n * optional filter → ordered steps (run workflow, site alert, custom\n * event, dataset append). Runs server-side via runEventActions; paid\n * feature (`actions` flag, Pro+, `actionRunsPerMonth` metered).\n */\nexport function HostActionsCard(props: {\n hostId: string\n org?: Partial<AglynOrgBilling>\n}) {\n const { hostId, org } = props\n // Org-shared data root (AGL-237). Null until the org lookup settles\n // (AGL-1061), and for a host with no owning org — the pre-migration host\n // path is gone (AGL-1050), so the dataset and list pickers stay empty\n // instead of offering rows from a path nothing else reads.\n const firestore = useFirestore()\n // Action creation is server-owned since AGL-2266 (the cap); every other\n // action write on this surface stays client-direct.\n const createResource = useHostResourceApi()\n // The caller's token, for the test run's console door.\n const { data: user } = useUser()\n const { enqueueSnackbar } = useSnackbar()\n const { confirm } = useConfirmationContext()\n /**\n * The shell's zone renderer, for what other plugins add to automations\n * (AGL-2919); `null` outside the console shell, where there is no workspace\n * to gate on.\n */\n const ExtensionZone = useConsoleWidgetSlot()\n\n const {\n data: actionDocs,\n status: actionsStatus,\n /**\n * The action rows this card's editor is seeded from are unconfirmed by\n * the server (AGL-1358). Editing an action copies the whole stored row\n * into `draft` — name, trigger and every step — and writes all of it\n * back, so `merge: true` protects nothing and a cached seed reverts a\n * colleague's newer version of the steps nobody here touched.\n *\n * The same shape the interaction builder guards (AGL-1066); this is its\n * card twin, and it was the one that never got the guard.\n */\n fromCache: actionsFromCache,\n } = useFirestoreCollection<any>(\n /*\n * ORDERED AND CEILINGED, deliberately not paged by the query (AGL-2501) —\n * the same decision as the workflows card beside it.\n *\n * `limit(100)` alone is answered in DOCUMENT-ID order, so the window was a\n * pseudo-random hundred that the `localeCompare` below arranged\n * alphabetically, and nothing said the list was bounded.\n *\n * `collectionCeiling` does not change WHICH hundred — document-id order is\n * what the bare cap already returned. What it changes is that the order is\n * NAMED, so the obvious next edit is caught: ordering on `name` would HIDE\n * every action written without one rather than mis-sorting the list, and\n * `/api/hosts/resources` validates no field for presence while\n * `IMPORTABLE_FIELDS.actions` copies one only if the export carried it.\n *\n * The QUERY is not paged because this collection holds TWO audiences. A\n * row whose trigger names a leaf selector is an element interaction, which\n * belongs to its document and is reported below as a count rather than\n * listed; the rest are the site's actions. Both partitions are derived\n * from the rows in hand, so a server page would make \"3 interactions are\n * set up on their own elements\" mean \"3 on this page\" — a count that is a\n * window length, which is the defect this sweep keeps finding rather than\n * a shape it should add.\n */\n () =>\n collectionCeiling(\n collection(firestore, 'hosts', hostId, 'actions'),\n ACTION_CEILING,\n ),\n [firestore, hostId],\n { idField: '$id' },\n )\n const { rows: readActions, truncated: actionsTruncated } =\n ceilingedWindow<any>(actionDocs, ACTION_CEILING)\n const [draft, setDraft] = useState<ActionDraft | null>(null)\n /**\n * The editor has been opened at least once in this session.\n *\n * A LATCH rather than `draft` itself, because the pickers below key their\n * listeners on it. Tracking the dialog would tear those subscriptions down\n * on Cancel and pay for them again on the next Edit, so a merchant working\n * through ten actions would buy the same six windows ten times — worse than\n * the mount-time read this replaces. Latched, a reader who never edits pays\n * nothing and a reader who edits pays once.\n */\n const [editorOpened, setEditorOpened] = useState(false)\n if (draft && !editorOpened) setEditorOpened(true)\n /*\n * The step editor's six option lists, read on the same latch as the\n * Workflows builder's — one hook, because the two editors offer one set of\n * steps and a second copy would be a second read cost to keep in agreement.\n */\n const { pickers: stepPickers, truncated: truncatedPickers } =\n useAutomationStepPickers(hostId, editorOpened)\n const liveActions = readActions.filter((action: any) => !action.deletedAt)\n /*\n * Opens a listed action in the editor, for a widget in the `hostAutomations`\n * zone — one that drafted an action and offers to open it. Read through a\n * ref so the callback keeps one identity while the list changes beneath it,\n * and answers `false` for an id the list has not read yet.\n */\n const listedRef = useRef<any[]>(liveActions)\n listedRef.current = liveActions\n const openAction = useCallback((actionId: string) => {\n const action = listedRef.current.find((row: any) => row.$id === actionId)\n if (!action) return false\n setDraft(draftFromAction(action, action.$id))\n return true\n }, [])\n /**\n * Element interactions are not listed here.\n *\n * An ACTION is something the SITE does — an order was placed, a form was\n * submitted. An INTERACTION is something an ELEMENT does, and it belongs to\n * the document that holds the element: it publishes and rolls back with it,\n * travels with it, and is deleted with it. This page is the site's\n * automation list, and a nav menu's hover timing sitting in it beside \"when\n * an order is placed\" was the tell that the two had been conflated.\n *\n * These rows are the ones written BEFORE the move, still bound by selector.\n * They keep running and stay editable — on their element, in the besigner,\n * which is now the only place they appear. Counted rather than hidden\n * outright, so the page can say where they went instead of appearing to\n * have lost them.\n */\n const elementScoped = liveActions.filter((action: any) =>\n LEAF_SELECTOR.test(String(action?.trigger?.selector ?? '')),\n )\n // Sorting is safe here in a way it is not on a paged list: these rows are\n // the whole collection below the ceiling, not a slice of one.\n const actions = liveActions\n .filter((action: any) => !elementScoped.includes(action))\n .sort((a: any, b: any) =>\n String(a.name ?? '').localeCompare(String(b.name ?? '')),\n )\n // The page is a SLICE: the rows are already in hand, and both the element\n // interaction count and the alphabetical order need all of them.\n const [page, setPage] = useState(0)\n const [pageSize, setPageSize] = useState(TABLE_PAGE_SIZE_DEFAULT)\n const visibleActions = useMemo(\n () => actions.slice(page * pageSize, page * pageSize + pageSize),\n [actions, page, pageSize],\n )\n\n const patch = useCallback(\n (updater: (previous: ActionDraft) => ActionDraft) =>\n setDraft((previous) => (previous ? updater(previous) : previous)),\n [],\n )\n\n /** The saved action the editor has open, as the `automationEditor` zone names it. */\n const draftId = draft?.id ?? null\n const draftName = draft?.name ?? ''\n const editorTarget = useMemo<ConsoleAutomationTarget | null>(\n () => (draftId ? { type: 'action', id: draftId, name: draftName } : null),\n // The name the editor opened with: the zone reads the automation as it is\n // stored, so a rename being typed does not make it a different one.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [draftId],\n )\n\n /**\n * Whether this workspace may open the editor at all. One gate for the\n * blank action and the recipes: a recipe is an action, so the plan that\n * carries one carries the other, and the refusal reads the same.\n */\n const actionsEntitled = useCallback(() => {\n if (checkEntitlement(org, 'actions')) return true\n enqueueSnackbar(\n 'The actions builder requires a Pro plan — see Billing to upgrade',\n { variant: 'warning', persist: false },\n )\n return false\n }, [org, enqueueSnackbar])\n\n const handleAdd = useCallback(() => {\n if (!actionsEntitled()) return\n setDraft({\n id: null,\n name: '',\n trigger: { event: 'formSubmission', filter: '' },\n steps: [defaultStep('siteAlert')],\n enabled: true,\n customEvent: '',\n conditionRows: [EMPTY_CONDITION_ROW],\n conditionCombinator: 'and',\n recipe: null,\n })\n }, [actionsEntitled])\n\n /*\n * THE RECIPES (AGL-2626).\n *\n * A recipe opens the editor prefilled and writes nothing: the draft it\n * builds is the one Save would persist, and until then it is state in\n * this card and nowhere else. Three recipes open at once; \"Tag by form\"\n * needs a form first, and the form is this site's — `hosts/{hostId}/forms`\n * — so the picker is the one host-scoped piece of the feature, held here\n * rather than in the catalog.\n */\n const [recipesAnchor, setRecipesAnchor] = useState<HTMLElement | null>(null)\n const [formPickFor, setFormPickFor] = useState<CrmActionRecipe | null>(null)\n const [pickedFormId, setPickedFormId] = useState('')\n /**\n * The form picker has been opened at least once — the `editorOpened`\n * latch's twin, and for the same reason: the forms window is read for\n * this picker only, and a reader who never opens it pays nothing.\n */\n const [formPickerOpened, setFormPickerOpened] = useState(false)\n if (formPickFor && !formPickerOpened) setFormPickerOpened(true)\n const { data: formRead } = useFirestoreCollection<any>(\n () =>\n formPickerOpened\n ? collectionCeiling(\n collection(firestore, 'hosts', hostId, 'forms'),\n EDITOR_OPTION_CEILING,\n )\n : null,\n [firestore, hostId, formPickerOpened],\n { idField: '$id' },\n )\n const { rows: formDocs, truncated: formsTruncated } = ceilingedWindow<any>(\n formRead,\n EDITOR_OPTION_CEILING,\n )\n // An archived form collects nothing, so a recipe keyed on it would never\n // fire; the name falls back to the id the way every form list's does.\n const formOptions = (formDocs ?? [])\n .filter((form: any) => !form.archivedAt)\n .map((form: any) => ({\n id: form.$id as string,\n name: (String(form.displayName ?? '').trim() || form.$id) as string,\n }))\n .sort((a: { name: string }, b: { name: string }) =>\n a.name.localeCompare(b.name),\n )\n\n const handleRecipe = useCallback(\n (recipe: CrmActionRecipe) => {\n setRecipesAnchor(null)\n if (!actionsEntitled()) return\n if (recipe.needs === 'form') {\n setPickedFormId('')\n setFormPickFor(recipe)\n return\n }\n setDraft(draftFromAction(recipe.build(), null))\n },\n [actionsEntitled],\n )\n\n const handleFormPicked = useCallback(() => {\n const recipe = formPickFor\n const form = formOptions.find((option) => option.id === pickedFormId)\n if (!recipe || !form) return\n setFormPickFor(null)\n setDraft(draftFromAction(recipe.build({ form }), null))\n }, [formPickFor, formOptions, pickedFormId])\n\n // Run log + test runs (AGL-266).\n const [runsFor, setRunsFor] = useState<any | null>(null)\n const handleTestRun = useCallback(\n async (action: any) => {\n try {\n /*\n * The console's own door, signed: a page's `events/dispatch` is a\n * tenant route this origin does not serve. The route reads the\n * trigger off the stored action and marks the run as a test, so the\n * body names only which action on which site.\n */\n const response = await authorizedFetch(\n user,\n `/api/${ACTION_TEST_RUN_API_ROUTE}`,\n {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ hostId, actionId: action.$id }),\n },\n )\n const payload = await response.json().catch(() => ({}))\n if (!response.ok) {\n return void enqueueSnackbar(payload?.error ?? 'Test run failed', {\n variant: 'warning',\n persist: false,\n })\n }\n const alerts = Array.isArray(payload?.alerts) ? payload.alerts : []\n enqueueSnackbar(\n alerts.length\n ? `Test ran — first alert: ${alerts[0].message}`\n : 'Test ran — server steps executed (see Runs)',\n { variant: 'success', persist: false },\n )\n } catch (error) {\n console.error(error)\n enqueueSnackbar('Test run failed', { variant: 'error' })\n }\n },\n [hostId, user, enqueueSnackbar],\n )\n\n const handleSave = useCallback(async () => {\n if (!draft) return\n const isCustom = draft.trigger.event === CUSTOM_EVENT_VALUE\n const candidate: HostAction = {\n name: draft.name.trim().slice(0, 60),\n trigger: {\n event: isCustom ? draft.customEvent.trim() : draft.trigger.event,\n ...(draft.trigger.filter?.trim()\n ? { filter: draft.trigger.filter.trim() }\n : {}),\n // Site-event config (AGL-256).\n ...(draft.trigger.selector?.trim()\n ? { selector: draft.trigger.selector.trim() }\n : {}),\n ...(Number(draft.trigger.threshold) > 0\n ? { threshold: Number(draft.trigger.threshold) }\n : {}),\n ...(draft.trigger.pathPattern?.trim()\n ? { pathPattern: draft.trigger.pathPattern.trim() }\n : {}),\n // Frequency caps (AGL-274).\n ...(draft.trigger.oncePerVisitor === true\n ? { oncePerVisitor: true }\n : {}),\n ...(draft.trigger.oncePerSession === true\n ? { oncePerSession: true }\n : {}),\n ...(Number(draft.trigger.cooldownMinutes) >= 1\n ? { cooldownMinutes: Number(draft.trigger.cooldownMinutes) }\n : {}),\n ...(draft.trigger.everyTime === true ? { everyTime: true } : {}),\n // Structured payload conditions (AGL-557; chained AGL-565):\n // rows keep their blank fields so validateHostAction surfaces\n // the miss. Saves always write the list shape — the legacy\n // single `condition` is only ever read, never written back.\n ...conditionsFromRows(draft.conditionRows, draft.conditionCombinator),\n },\n steps: draft.steps,\n enabled: draft.enabled !== false,\n // The stamp travels only when the draft knows one way or the other;\n // an older action's silence is kept (see hostActionRecipeId).\n ...(draft.recipe !== undefined ? { recipe: draft.recipe } : {}),\n }\n const problem = validateHostAction(candidate)\n if (problem) {\n return void enqueueSnackbar(problem, {\n variant: 'warning',\n persist: false,\n })\n }\n try {\n const id = draft.id ?? createResourceUid()\n /**\n * Refuse an EDIT whose seed the server never confirmed (AGL-1358).\n *\n * The payload is the whole action. `merge: true` is here so the\n * frequency caps and conditions can be nulled explicitly, not to\n * protect untouched fields — there are none, they are all in the\n * payload. So a cached seed does not lose one edit, it reverts the\n * trigger and every step to whatever the cache last held, on an\n * automation that is running on a live site.\n *\n * Only the edit path. A NEW action is built from `EMPTY_*` defaults at\n * a fresh uid and can overwrite nothing; the first snapshot of any\n * listener is `fromCache: true`, so guarding a create would refuse a\n * save that was never unsafe.\n *\n * The guard WRAPS the write — the interaction builder's early return\n * is the shape you can keep while losing the protection.\n */\n /**\n * The action DOCUMENT is created by the server (AGL-2266).\n *\n * `hosts/{hostId}/actions` was in none of the host catch-all's exclusion\n * lists, so any editor could create one client-direct on any plan and\n * nothing counted them. /api/hosts/resources now owns the create and\n * holds `ACTIONS_MAX_PER_HOST` from a server read.\n *\n * Only the create moves, and it writes a SHELL. The merge-set below is\n * untouched and still carries the whole candidate — trigger, steps,\n * conditions, the explicit nulls AGL-274/557 depend on — so no field can\n * be lost to the route's allow-list, and for an existing action this\n * path does not run at all.\n */\n if (!draft.id) {\n try {\n await createResource({\n hostId,\n resource: 'action',\n id,\n data: { name: candidate.name ?? draft.name ?? 'Untitled action' },\n })\n } catch (error: any) {\n return void enqueueSnackbar(\n error?.message ?? 'Could not create the interaction',\n { variant: 'error' },\n )\n }\n }\n const verdict = await writeGuardedBySeed(\n {\n subject: 'action',\n unreadable: Boolean(draft.id) && actionsStatus === 'error',\n fromCache: Boolean(draft.id) && actionsFromCache,\n },\n async () => {\n await setDoc(\n doc(firestore, 'hosts', hostId, 'actions', id),\n {\n // The stored shape (AGL-2639), shared with the recipe-install\n // route: frequency caps overwrite explicitly (AGL-274) because\n // a merge-set keeps omitted keys, so switching one off must\n // write it out; conditions follow suit (AGL-557/565) — the\n // list + combinator write null when cleared, and the legacy\n // single `condition` is always nulled.\n ...hostActionDocument(candidate),\n updatedAt: Timestamp.now(),\n ...(draft.id ? {} : { createdAt: Timestamp.now() }),\n },\n { merge: true },\n )\n },\n )\n // A refusal keeps the editor open with everything that was typed.\n if (!verdict.ok) {\n return void enqueueSnackbar(verdict.message, {\n variant: 'warning',\n persist: false,\n })\n }\n setDraft(null)\n enqueueSnackbar('Action saved', { variant: 'success', persist: false })\n } catch (error) {\n console.error(error)\n enqueueSnackbar('An error has occurred', {\n variant: 'error',\n allowDuplicate: true,\n })\n }\n }, [\n draft,\n firestore,\n createResource,\n hostId,\n enqueueSnackbar,\n actionsFromCache,\n actionsStatus,\n ])\n\n const handleDelete = useCallback(\n (action: any) => async () => {\n const confirmed = await confirm({\n title: 'Delete this action?',\n description: `\"${action.name}\" stops running on its trigger.`,\n confirmationText: 'Delete',\n confirmationButtonProps: { color: 'error' },\n })\n .then(() => true)\n .catch(() => false)\n if (!confirmed) return\n await updateDoc(doc(firestore, 'hosts', hostId, 'actions', action.$id), {\n deletedAt: Timestamp.now(),\n })\n },\n [confirm, firestore, hostId],\n )\n\n const handleToggle = useCallback(\n (action: any) => async (event: { target: { checked: boolean } }) => {\n const enabled = event.target.checked\n /*\n * A placeholder is a value nobody has supplied yet. Switched on, the\n * step holding it fails every run and a condition holding one never\n * matches, so turning such an automation on is confirmed, naming what\n * is still missing.\n */\n const missing = enabled ? automationPlaceholders(action) : []\n if (missing.length) {\n const confirmed = await confirm({\n title: 'Switch on with placeholders?',\n description:\n `\"${action.name}\" still has ${missing.length === 1 ? 'a placeholder' : `${missing.length} placeholders`} ` +\n `to fill in: ${missing.slice(0, 3).map(describeAutomationPlaceholder).join('; ')}` +\n `${missing.length > 3 ? '; …' : ''}. Open it with Edit to fill ` +\n `${missing.length === 1 ? 'it' : 'them'} in first.`,\n confirmationText: 'Switch on anyway',\n })\n .then(() => true)\n .catch(() => false)\n if (!confirmed) return\n }\n await updateDoc(doc(firestore, 'hosts', hostId, 'actions', action.$id), {\n enabled,\n })\n },\n [confirm, firestore, hostId],\n )\n\n return (\n <CardDisplay\n header={'Actions'}\n help={pluginDocsHelp('actionsBuilder', { anchor: '#create-an-action' })}\n contentGutterX\n contentGutterY\n >\n <Stack spacing={1}>\n <Typography variant=\"body2\" color=\"text.secondary\">\n {'When a site event fires, run automations in order — trigger a ' +\n 'workflow, show the visitor an alert, chain a custom event, or ' +\n 'write to a dataset. Pro plans and up.'}\n </Typography>\n {visibleActions.map((action: any) => {\n const missing = automationPlaceholders(action).length\n return (\n <Stack\n key={action.$id}\n direction=\"row\"\n spacing={1}\n sx={{ alignItems: 'center' }}\n >\n <Switch\n size=\"small\"\n checked={action.enabled !== false}\n onChange={handleToggle(action)}\n />\n <Stack sx={{ flex: 1, minWidth: 0 }}>\n <Typography variant=\"body2\" noWrap>\n {action.name}\n </Typography>\n <Typography variant=\"caption\" color=\"text.secondary\" noWrap>\n {`on ${hostEventLabel(action.trigger?.event)}` +\n ` · ${(action.steps ?? [])\n .map(\n (step: any) =>\n HOST_ACTION_STEP_LABELS[\n step.type as HostActionStepType\n ] ?? step.type,\n )\n .join(' → ')}`}\n </Typography>\n {missing ? (\n <Typography variant=\"caption\" color=\"warning.main\" noWrap>\n {missing === 1\n ? '1 placeholder to fill in'\n : `${missing} placeholders to fill in`}\n </Typography>\n ) : null}\n </Stack>\n <Button\n size=\"small\"\n onClick={() => setDraft(draftFromAction(action, action.$id))}\n >\n {'Edit'}\n </Button>\n {isSiteEventType(String(action.trigger?.event ?? '')) ? (\n // Test run (AGL-266): the server steps only, run now as a real\n // run through the console's test-run door.\n <Button size=\"small\" onClick={() => void handleTestRun(action)}>\n {'Test'}\n </Button>\n ) : null}\n <Button size=\"small\" onClick={() => setRunsFor(action)}>\n {'Runs'}\n </Button>\n <Button size=\"small\" color=\"error\" onClick={handleDelete(action)}>\n {'Delete'}\n </Button>\n </Stack>\n )\n })}\n {actions.length === 0 ? null : (\n <ListPagination\n page={page}\n pageSize={pageSize}\n rowCount={visibleActions.length}\n // The actions the card HOLDS, which is what the reader is paging\n // through — not the collection, whose other half is the element\n // interactions counted below.\n count={actions.length}\n onPageChange={setPage}\n onPageSizeChange={setPageSize}\n />\n )}\n {actionsTruncated ? (\n <Alert severity=\"info\">\n {`Showing the first ${ACTION_CEILING} rows of this site’s ` +\n 'automations, ordered by id. There are more — both the list ' +\n 'above and the interaction count below describe only what was ' +\n 'read.'}\n </Alert>\n ) : null}\n <Stack direction=\"row\" spacing={1} sx={{ alignSelf: 'flex-start' }}>\n <Button size=\"small\" color=\"primary\" onClick={handleAdd}>\n {'Add action'}\n </Button>\n <Button\n size=\"small\"\n color=\"primary\"\n aria-haspopup=\"menu\"\n aria-controls={recipesAnchor ? 'host-action-recipes' : undefined}\n aria-expanded={recipesAnchor ? true : undefined}\n onClick={(event) => setRecipesAnchor(event.currentTarget)}\n >\n {'Recipes'}\n </Button>\n {/*\n Other ways to start an automation, from plugins (AGL-2919): the\n `hostAutomations` zone, drawn through the shell's own gated slot. A\n plugin page cannot mount that slot itself, so the shell hands it\n down, and a widget here passes the gates a console page's would.\n */}\n {ExtensionZone ? (\n <ExtensionZone\n slot=\"hostAutomations\"\n hostId={hostId}\n orgId={org?.$id}\n openAction={openAction}\n />\n ) : null}\n </Stack>\n <Menu\n id=\"host-action-recipes\"\n anchorEl={recipesAnchor}\n open={Boolean(recipesAnchor)}\n onClose={() => setRecipesAnchor(null)}\n >\n {CRM_ACTION_RECIPES.map((recipe) => (\n <MenuItem key={recipe.id} onClick={() => handleRecipe(recipe)}>\n <ListItemText\n primary={recipe.title}\n secondary={recipe.description}\n slotProps={{ secondary: { sx: { whiteSpace: 'normal', maxWidth: 360 } } }}\n />\n </MenuItem>\n ))}\n </Menu>\n {/* Says where they went. A list that silently drops rows\n a reader saw last week is a list they stop trusting; this is the\n one sentence that makes the absence deliberate. */}\n {elementScoped.length ? (\n <Typography variant=\"caption\" color=\"text.secondary\">\n {elementScoped.length === 1\n ? '1 interaction is set up on its own element — '\n : `${elementScoped.length} interactions are set up on their own elements — `}\n {'open the element in the besigner to edit it. Interactions ' +\n 'belong to the page they are on, so they publish and roll back ' +\n 'with it.'}\n </Typography>\n ) : null}\n </Stack>\n\n <Dialog\n open={Boolean(draft)}\n onClose={() => setDraft(null)}\n maxWidth=\"sm\"\n fullWidth\n >\n <DialogTitle>{draft?.id ? 'Edit action' : 'Add action'}</DialogTitle>\n <DialogContent\n sx={{ display: 'flex', flexDirection: 'column', gap: 1.5, pt: 1 }}\n >\n {ExtensionZone && editorTarget ? (\n <ExtensionZone\n slot=\"automationEditor\"\n hostId={hostId}\n orgId={org?.$id}\n target={editorTarget}\n />\n ) : null}\n {draft?.recipe ? (\n <Typography variant=\"body2\" color=\"text.secondary\">\n {`Started from the “${\n CRM_ACTION_RECIPES.find((recipe) => recipe.id === draft.recipe)\n ?.title ?? 'recipe'\n }” recipe — change anything, then save.`}\n </Typography>\n ) : null}\n {/*\n A short picker is worse than an empty one, because it looks\n complete: the target an author cannot find reads as deleted, and\n the step gets pointed somewhere else.\n */}\n {truncatedPickers.length > 0 ? (\n <Alert severity=\"info\" sx={{ mt: 1 }}>\n {`Offering the first ${EDITOR_OPTION_CEILING} rows, ordered by ` +\n `id, for: ${truncatedPickers.join(', ')}. This site has ` +\n 'more, so a step target may not be listed below.'}\n </Alert>\n ) : null}\n <TextField\n label=\"Name\"\n value={draft?.name ?? ''}\n onChange={(event) =>\n patch((previous) => ({ ...previous, name: event.target.value }))\n }\n size=\"small\"\n autoFocus\n sx={{ mt: 1 }}\n />\n <Stack direction=\"row\" spacing={1}>\n <TextField\n select\n label=\"Trigger event\"\n value={draft?.trigger.event ?? ''}\n onChange={(event) =>\n patch((previous) => ({\n ...previous,\n trigger: { ...previous.trigger, event: event.target.value },\n }))\n }\n size=\"small\"\n sx={{ minWidth: 180 }}\n >\n {HOST_EVENT_TYPES.map((eventType) => (\n <MenuItem key={eventType} value={eventType}>\n {hostEventLabel(eventType)}\n </MenuItem>\n ))}\n {SITE_EVENT_TYPES.map((eventType) => (\n <MenuItem key={eventType} value={eventType}>\n {`${eventType} (on page)`}\n </MenuItem>\n ))}\n <MenuItem value={CUSTOM_EVENT_VALUE}>{'Custom event…'}</MenuItem>\n </TextField>\n {draft?.trigger.event === CUSTOM_EVENT_VALUE ? (\n <TextField\n label=\"Custom event name\"\n value={draft?.customEvent ?? ''}\n onChange={(event) =>\n patch((previous) => ({\n ...previous,\n customEvent: event.target.value,\n }))\n }\n size=\"small\"\n sx={{ flex: 1 }}\n />\n ) : (\n <TextField\n label=\"Filter (optional)\"\n placeholder={'path == \"/pricing\"'}\n // What the expression — and the conditions below — can name\n // for this event; nothing for an event whose payload is not\n // written down, rather than a guess.\n helperText={hostEventPayloadHint(draft?.trigger.event) ?? undefined}\n value={draft?.trigger.filter ?? ''}\n onChange={(event) =>\n patch((previous) => ({\n ...previous,\n trigger: {\n ...previous.trigger,\n filter: event.target.value,\n },\n }))\n }\n size=\"small\"\n sx={{ flex: 1 }}\n />\n )}\n </Stack>\n {/* Structured payload conditions (AGL-557): the no-code sibling\n of the filter — e.g. only when `subscribe` is not empty.\n Chainable with AND/OR (AGL-565), rows styled like steps. */}\n <TriggerConditionRows\n rows={draft?.conditionRows ?? []}\n combinator={draft?.conditionCombinator ?? 'and'}\n onRowsChange={(update) =>\n patch((previous) => ({\n ...previous,\n conditionRows: update(previous.conditionRows),\n }))\n }\n onCombinatorChange={(combinator) =>\n patch((previous) => ({\n ...previous,\n conditionCombinator: combinator,\n }))\n }\n />\n {isSiteEventType(draft?.trigger.event ?? '') ? (\n // Site-event config (AGL-256): what/where the trigger watches.\n <Stack direction=\"row\" spacing={1}>\n {(ELEMENT_SCOPED_SITE_EVENTS as readonly string[]).includes(\n draft?.trigger.event ?? '',\n ) ? (\n <TextField\n label=\"CSS selector\"\n placeholder=\"#pricing-table\"\n value={draft?.trigger.selector ?? ''}\n onChange={(event) =>\n patch((previous) => ({\n ...previous,\n trigger: {\n ...previous.trigger,\n selector: event.target.value,\n },\n }))\n }\n size=\"small\"\n sx={{ flex: 1 }}\n />\n ) : null}\n {['scrollDepth', 'timeOnPage'].includes(\n draft?.trigger.event ?? '',\n ) ? (\n <TextField\n type=\"number\"\n label={\n draft?.trigger.event === 'scrollDepth'\n ? 'Scroll %'\n : 'Seconds'\n }\n value={draft?.trigger.threshold ?? ''}\n onChange={(event) =>\n patch((previous) => ({\n ...previous,\n trigger: {\n ...previous.trigger,\n threshold: Number(event.target.value),\n },\n }))\n }\n size=\"small\"\n sx={{ width: 120 }}\n />\n ) : null}\n <TextField\n label=\"Only on pages (optional)\"\n placeholder=\"/pricing or /blog/*\"\n value={draft?.trigger.pathPattern ?? ''}\n onChange={(event) =>\n patch((previous) => ({\n ...previous,\n trigger: {\n ...previous.trigger,\n pathPattern: event.target.value,\n },\n }))\n }\n size=\"small\"\n sx={{ flex: 1 }}\n />\n {/* Frequency caps (AGL-274). */}\n <TextField\n select\n label=\"Frequency\"\n size=\"small\"\n sx={{ minWidth: 170 }}\n value={\n draft?.trigger.oncePerVisitor\n ? 'visitor'\n : draft?.trigger.oncePerSession\n ? 'session'\n : Number(draft?.trigger.cooldownMinutes) >= 1\n ? 'cooldown'\n : draft?.trigger.everyTime\n ? 'every'\n : ''\n }\n onChange={(event) => {\n const mode = event.target.value\n patch((previous) => ({\n ...previous,\n trigger: {\n ...previous.trigger,\n // Every occurrence (AGL-562): repeatable UI\n // choreography (menu/drawer toggles).\n everyTime: mode === 'every',\n oncePerVisitor: mode === 'visitor',\n oncePerSession: mode === 'session',\n cooldownMinutes:\n mode === 'cooldown'\n ? Number(previous.trigger.cooldownMinutes) >= 1\n ? Number(previous.trigger.cooldownMinutes)\n : 60\n : undefined,\n },\n }))\n }}\n >\n <MenuItem value=\"\">{'Every matching pageview'}</MenuItem>\n <MenuItem value=\"every\">\n {'Every occurrence (repeatable)'}\n </MenuItem>\n <MenuItem value=\"session\">{'Once per session'}</MenuItem>\n <MenuItem value=\"visitor\">{'Once per visitor'}</MenuItem>\n <MenuItem value=\"cooldown\">{'With a cooldown'}</MenuItem>\n </TextField>\n {Number(draft?.trigger.cooldownMinutes) >= 1 &&\n !draft?.trigger.oncePerVisitor &&\n !draft?.trigger.oncePerSession ? (\n <TextField\n type=\"number\"\n label=\"Cooldown (minutes)\"\n size=\"small\"\n sx={{ width: 150 }}\n value={draft?.trigger.cooldownMinutes ?? 60}\n onChange={(event) =>\n patch((previous) => ({\n ...previous,\n trigger: {\n ...previous.trigger,\n cooldownMinutes: Number(event.target.value),\n },\n }))\n }\n />\n ) : null}\n </Stack>\n ) : null}\n <Typography variant=\"overline\" color=\"text.secondary\">\n {'Steps (run in order)'}\n </Typography>\n {(draft?.steps ?? []).map((step, index) => (\n <AutomationStepFields\n key={index}\n step={step}\n index={index}\n kind={step.type}\n kinds={ACTION_STEP_KINDS}\n stepForKind={(value) => defaultStep(value as HostActionStepType)}\n pickers={stepPickers}\n onSteps={(update) =>\n patch((previous) => ({\n ...previous,\n steps: update(previous.steps),\n }))\n }\n />\n ))}\n <Button\n size=\"small\"\n sx={{ alignSelf: 'flex-start' }}\n disabled={(draft?.steps.length ?? 0) >= ACTION_MAX_STEPS}\n onClick={() =>\n patch((previous) => ({\n ...previous,\n steps: [...previous.steps, defaultStep('siteAlert')],\n }))\n }\n >\n {'Add step'}\n </Button>\n </DialogContent>\n <DialogActions>\n <Button onClick={() => setDraft(null)}>{'Cancel'}</Button>\n <Button\n variant=\"contained\"\n color=\"primary\"\n disabled={!draft?.name.trim()}\n onClick={handleSave}\n >\n {'Save action'}\n </Button>\n </DialogActions>\n </Dialog>\n <Dialog\n open={Boolean(formPickFor)}\n onClose={() => setFormPickFor(null)}\n maxWidth=\"xs\"\n fullWidth\n >\n <DialogTitle>{formPickFor?.title ?? ''}</DialogTitle>\n <DialogContent\n sx={{ display: 'flex', flexDirection: 'column', gap: 1.5, pt: 1 }}\n >\n <Typography variant=\"body2\" color=\"text.secondary\">\n {'Pick the form whose new contacts get the tag. The action opens ' +\n 'ready to edit; nothing is saved until you save it.'}\n </Typography>\n {formsTruncated ? (\n <Alert severity=\"info\">\n {`Offering the first ${EDITOR_OPTION_CEILING} forms, ordered by ` +\n 'id. This site has more, so the form you want may not be listed.'}\n </Alert>\n ) : null}\n {formOptions.length ? (\n <TextField\n select\n label=\"Form\"\n value={pickedFormId}\n onChange={(event) => setPickedFormId(event.target.value)}\n size=\"small\"\n sx={{ mt: 1 }}\n >\n {formOptions.map((option) => (\n <MenuItem key={option.id} value={option.id}>\n {option.name}\n </MenuItem>\n ))}\n </TextField>\n ) : (\n <Typography variant=\"body2\" color=\"text.secondary\">\n {'This site has no forms yet. Add one in the besigner, then come back.'}\n </Typography>\n )}\n </DialogContent>\n <DialogActions>\n <Button color=\"inherit\" onClick={() => setFormPickFor(null)}>\n {'Cancel'}\n </Button>\n <Button\n variant=\"contained\"\n disabled={!pickedFormId}\n onClick={handleFormPicked}\n >\n {'Use recipe'}\n </Button>\n </DialogActions>\n </Dialog>\n <Dialog\n open={Boolean(runsFor)}\n onClose={() => setRunsFor(null)}\n maxWidth=\"sm\"\n fullWidth\n >\n <DialogTitle>{`Runs — ${runsFor?.name ?? ''}`}</DialogTitle>\n <DialogContent>\n {runsFor ? (\n <HostRunHistoryCard\n hostId={hostId}\n orgId={org?.$id}\n targetId={runsFor.$id}\n targetType=\"action\"\n targetName={runsFor.name ?? ''}\n header=\"Recent runs\"\n />\n ) : null}\n </DialogContent>\n <DialogActions>\n <Button color=\"inherit\" onClick={() => setRunsFor(null)}>\n {'Close'}\n </Button>\n </DialogActions>\n </Dialog>\n </CardDisplay>\n )\n}\nHostActionsCard.displayName = 'HostActionsCard'\n\nexport default HostActionsCard\n"],"names":["ACTION_MAX_STEPS","checkEntitlement","createResourceUid","CRM_ACTION_RECIPES","ELEMENT_SCOPED_SITE_EVENTS","HOST_ACTION_STEP_LABELS","HOST_EVENT_TYPES","hostActionDocument","hostActionRecipeId","hostEventLabel","hostEventPayloadHint","isSiteEventType","pluginDocsHelp","SITE_EVENT_TYPES","validateHostAction","automationPlaceholders","describeAutomationPlaceholder","useConsoleWidgetSlot","CardDisplay","useConfirmationContext","ListPagination","TABLE_PAGE_SIZE_DEFAULT","useSnackbar","authorizedFetch","Timestamp","Alert","Button","Dialog","DialogActions","DialogContent","DialogTitle","ListItemText","Menu","MenuItem","Stack","Switch","TextField","Typography","collection","doc","setDoc","updateDoc","useCallback","useMemo","useRef","useState","ceilingedWindow","collectionCeiling","useFirestore","useFirestoreCollection","useHostResourceApi","useUser","writeGuardedBySeed","ACTION_TEST_RUN_API_ROUTE","AutomationStepFields","defaultStep","conditionRowsFromTrigger","conditionsFromRows","EMPTY_CONDITION_ROW","TriggerConditionRows","HostRunHistoryCard","EDITOR_OPTION_CEILING","useAutomationStepPickers","CUSTOM_EVENT_VALUE","ACTION_CEILING","ACTION_STEP_KINDS","Object","entries","map","value","label","draftFromAction","action","id","builtIn","includes","trigger","event","String","name","filter","selector","threshold","pathPattern","oncePerVisitor","oncePerSession","everyTime","Number","cooldownMinutes","steps","enabled","customEvent","conditionRows","conditionCombinator","combinator","recipe","LEAF_SELECTOR","HostActionsCard","props","runsFor","hostId","org","firestore","createResource","data","user","enqueueSnackbar","confirm","ExtensionZone","actionDocs","status","actionsStatus","fromCache","actionsFromCache","idField","rows","readActions","truncated","actionsTruncated","draft","setDraft","editorOpened","setEditorOpened","pickers","stepPickers","truncatedPickers","liveActions","deletedAt","listedRef","current","openAction","actionId","find","row","$id","elementScoped","test","actions","sort","a","b","localeCompare","page","setPage","pageSize","setPageSize","visibleActions","slice","patch","updater","previous","draftId","draftName","editorTarget","type","actionsEntitled","variant","persist","handleAdd","recipesAnchor","setRecipesAnchor","formPickFor","setFormPickFor","pickedFormId","setPickedFormId","formPickerOpened","setFormPickerOpened","formRead","formDocs","formsTruncated","formOptions","form","archivedAt","displayName","trim","handleRecipe","needs","build","handleFormPicked","option","setRunsFor","handleTestRun","response","method","headers","body","JSON","stringify","payload","json","catch","ok","error","alerts","Array","isArray","length","message","console","handleSave","isCustom","candidate","undefined","problem","resource","verdict","subject","unreadable","Boolean","updatedAt","now","createdAt","merge","allowDuplicate","handleDelete","confirmed","title","description","confirmationText","confirmationButtonProps","color","then","handleToggle","target","checked","missing","join","header","help","anchor","contentGutterX","contentGutterY","spacing","direction","sx","alignItems","size","onChange","flex","minWidth","noWrap","step","onClick","rowCount","count","onPageChange","onPageSizeChange","severity","alignSelf","aria-haspopup","aria-controls","aria-expanded","currentTarget","slot","orgId","anchorEl","open","onClose","primary","secondary","slotProps","whiteSpace","maxWidth","fullWidth","display","flexDirection","gap","pt","mt","autoFocus","select","eventType","placeholder","helperText","onRowsChange","update","onCombinatorChange","width","mode","index","kind","kinds","stepForKind","onSteps","disabled","targetId","targetType","targetName"],"mappings":"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"}
@@ -237,6 +237,26 @@ export declare function executeWorkflow(env: ActionRunEnv, run: AutomationRun, w
237
237
  * AS this site — and on the same meter.
238
238
  */
239
239
  export declare function runEventActions(hostId: string, event: string, payload?: HostEventPayload, depth?: number): Promise<HostActionAlert[]>;
240
+ /**
241
+ * Why a dispatched action ran nothing (AGL-3309).
242
+ *
243
+ * A page's dispatch has nobody to tell: a visitor's scroll is not answered
244
+ * with "the plan lapsed", so for it every refusal is the same empty list of
245
+ * alerts. The console's test run does have somebody to tell, and a test that
246
+ * ran nothing must not read as one that ran.
247
+ */
248
+ export type SingleActionSkip = 'missing' | 'disabled' | 'event' | 'conditions' | 'plan' | 'allowance' | 'failed';
249
+ /** What one dispatched action did, for a caller that has to say so. */
250
+ export interface SingleActionOutcome {
251
+ /** Its steps ran, and the run counted on the site's meter. */
252
+ ran: boolean;
253
+ /** Why nothing ran; `null` when it ran. */
254
+ skipped: SingleActionSkip | null;
255
+ /** The site alerts its steps produced. */
256
+ alerts: HostActionAlert[];
257
+ /** The month's allowance, when the allowance is what refused. */
258
+ limit?: number;
259
+ }
240
260
  /**
241
261
  * Runs ONE action's server steps (AGL-256): the tenant page runtime
242
262
  * evaluates site-event trigger conditions (scroll thresholds, selectors)
@@ -245,6 +265,15 @@ export declare function runEventActions(hostId: string, event: string, payload?:
245
265
  * thresholds. Same gates and metering as the event runner.
246
266
  */
247
267
  export declare function runSingleAction(hostId: string, actionId: string, event: string, payload?: HostEventPayload): Promise<HostActionAlert[]>;
268
+ /**
269
+ * {@link runSingleAction}, answering what it did as well as the alerts: whether
270
+ * the steps ran and, when they did not, which gate stopped them.
271
+ *
272
+ * One body for both, so the console's test run meets exactly the gates a
273
+ * page's dispatch meets — the switch, the event, the conditions, the plan and
274
+ * the month's allowance — and is metered and recorded the same way.
275
+ */
276
+ export declare function runSingleActionOutcome(hostId: string, actionId: string, event: string, payload?: HostEventPayload): Promise<SingleActionOutcome>;
248
277
  /**
249
278
  * Ends an enrollment its automation may no longer run, and says why in the
250
279
  * run history — the automation was deleted or switched off, or the plan that