@aglyn/plugins-workflows 1.0.0-beta.221 → 1.0.0-beta.223
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 +22 -14
- package/package.json +12 -12
- package/src/lib/components/automation-step-fields.component.d.ts +16 -16
- package/src/lib/components/automation-step-fields.component.js +146 -12
- package/src/lib/components/automation-step-fields.component.js.map +1 -1
- package/src/lib/components/automation-trigger-conditions.component.d.ts +25 -3
- package/src/lib/components/automation-trigger-conditions.component.js +89 -10
- package/src/lib/components/automation-trigger-conditions.component.js.map +1 -1
- package/src/lib/components/host-actions-card.component.js +126 -84
- package/src/lib/components/host-actions-card.component.js.map +1 -1
- package/src/lib/components/host-webhooks-card.component.js +2 -1
- package/src/lib/components/host-webhooks-card.component.js.map +1 -1
- package/src/lib/components/host-workflows-card.component.js +31 -10
- package/src/lib/components/host-workflows-card.component.js.map +1 -1
- package/src/lib/components/org-automation-editor.component.d.ts +2 -1
- package/src/lib/components/org-automation-editor.component.js +20 -11
- package/src/lib/components/org-automation-editor.component.js.map +1 -1
- package/src/lib/components/org-automations-card.component.js +2 -1
- package/src/lib/components/org-automations-card.component.js.map +1 -1
- package/src/lib/components/run-quota-line.component.d.ts +17 -4
- package/src/lib/components/run-quota-line.component.js +16 -7
- package/src/lib/components/run-quota-line.component.js.map +1 -1
- package/src/lib/components/site-org-automations-panel.component.js +2 -1
- package/src/lib/components/site-org-automations-panel.component.js.map +1 -1
- package/src/lib/components/workflows-console-page.js +18 -7
- package/src/lib/components/workflows-console-page.js.map +1 -1
- package/src/lib/declarations.d.ts +28 -0
- package/src/lib/declarations.js +37 -0
- package/src/lib/declarations.js.map +1 -0
- package/src/lib/declarations.server.js +17 -0
- package/src/lib/declarations.server.js.map +1 -1
- package/src/lib/engine/email-merge.d.ts +69 -0
- package/src/lib/engine/email-merge.js +98 -0
- package/src/lib/engine/email-merge.js.map +1 -0
- package/src/lib/engine/run-event-actions.d.ts +35 -10
- package/src/lib/engine/run-event-actions.js +256 -369
- package/src/lib/engine/run-event-actions.js.map +1 -1
- package/src/lib/engine/run-event-automations.d.ts +1 -1
- package/src/lib/engine/run-event-automations.js.map +1 -1
- package/src/lib/engine/run-event-workflows.d.ts +2 -1
- package/src/lib/engine/run-event-workflows.js +71 -30
- package/src/lib/engine/run-event-workflows.js.map +1 -1
- package/src/lib/engine/run-meter.d.ts +98 -0
- package/src/lib/engine/run-meter.js +121 -0
- package/src/lib/engine/run-meter.js.map +1 -0
- package/src/lib/engine/run-org-automations.d.ts +3 -2
- package/src/lib/engine/run-org-automations.js +17 -12
- package/src/lib/engine/run-org-automations.js.map +1 -1
- package/src/lib/engine/triggered-docs.d.ts +39 -0
- package/src/lib/engine/triggered-docs.js +47 -0
- package/src/lib/engine/triggered-docs.js.map +1 -0
- package/src/lib/engine/workflow-steps.d.ts +1 -1
- package/src/lib/engine/workflow-steps.js +3 -2
- package/src/lib/engine/workflow-steps.js.map +1 -1
- package/src/lib/model/host-actions.d.ts +284 -0
- package/src/lib/model/host-actions.js +316 -0
- package/src/lib/model/host-actions.js.map +1 -0
- package/src/lib/model/org-automations.d.ts +8 -5
- package/src/lib/model/org-automations.js +14 -8
- package/src/lib/model/org-automations.js.map +1 -1
- package/src/lib/model/step-outcomes.d.ts +2 -2
- package/src/lib/model/step-outcomes.js +1 -1
- package/src/lib/model/step-outcomes.js.map +1 -1
- package/src/lib/plugin.js +10 -0
- package/src/lib/plugin.js.map +1 -1
- package/src/lib/server/action-test-run-route.d.ts +3 -2
- package/src/lib/server/action-test-run-route.js +3 -2
- package/src/lib/server/action-test-run-route.js.map +1 -1
- package/src/lib/server/org-automations-routes.d.ts +42 -1
- package/src/lib/server/org-automations-routes.js +120 -72
- package/src/lib/server/org-automations-routes.js.map +1 -1
- package/src/lib/server-automation-drafts.d.ts +2 -2
- package/src/lib/server-automation-drafts.js +11 -7
- package/src/lib/server-automation-drafts.js.map +1 -1
- package/src/lib/server.js +19 -13
- package/src/lib/server.js.map +1 -1
- package/src/lib/testing/stand-in-crm-steps.d.ts +45 -0
- package/src/lib/testing/stand-in-crm-steps.js +97 -0
- package/src/lib/testing/stand-in-crm-steps.js.map +1 -0
- package/src/lib/testing/stand-in-dataset-list.js +11 -3
- package/src/lib/testing/stand-in-dataset-list.js.map +1 -1
- package/src/lib/testing/stand-in-dataset-steps.d.ts +43 -0
- package/src/lib/testing/stand-in-dataset-steps.js +65 -0
- package/src/lib/testing/stand-in-dataset-steps.js.map +1 -0
- package/src/lib/testing/stand-in-person-records.d.ts +35 -0
- package/src/lib/testing/stand-in-person-records.js +54 -0
- package/src/lib/testing/stand-in-person-records.js.map +1 -0
- package/src/lib/testing/stand-in-recipes.d.ts +36 -0
- package/src/lib/testing/stand-in-recipes.js +206 -0
- package/src/lib/testing/stand-in-recipes.js.map +1 -0
- package/src/lib/transfer/org-automations-package.d.ts +54 -0
- package/src/lib/transfer/org-automations-package.js +167 -0
- package/src/lib/transfer/org-automations-package.js.map +1 -0
- package/src/lib/transfer/org-automations-package.server.d.ts +38 -0
- package/src/lib/transfer/org-automations-package.server.js +296 -0
- package/src/lib/transfer/org-automations-package.server.js.map +1 -0
- package/src/lib/usage-axes.js +5 -1
- package/src/lib/usage-axes.js.map +1 -1
- package/src/lib/engine/crm-action-steps.d.ts +0 -142
- package/src/lib/engine/crm-action-steps.js +0 -452
- package/src/lib/engine/crm-action-steps.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../../libs/plugins/workflows/src/lib/components/org-automation-editor.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 HostActionStep,\n type HostActionStepType,\n hostEventLabel,\n hostEventPayloadHint,\n type TriggerCombinator,\n} from '@aglyn/aglyn'\nimport {\n hostIdsFromScope,\n hostScopeToken,\n isOrgWideScope,\n MAX_SCOPE_HOSTS,\n ORG_SCOPE_TOKEN,\n} from '@aglyn/aglyn/app-utils/scope-tokens'\nimport {\n Alert,\n Button,\n Checkbox,\n Dialog,\n DialogActions,\n DialogContent,\n DialogTitle,\n FormControlLabel,\n FormGroup,\n MenuItem,\n Radio,\n RadioGroup,\n Stack,\n Switch,\n TextField,\n Typography,\n} from '@mui/material'\nimport { useMemo } from 'react'\nimport {\n isOrgAutomationTriggerEvent,\n ORG_AUTOMATION_STEP_KINDS,\n ORG_AUTOMATION_TRIGGER_EVENTS,\n type OrgAutomationRow,\n type OrgAutomationTriggerEvent,\n} from '../model/org-automations'\nimport {\n AutomationStepFields,\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 { EDITOR_OPTION_CEILING } from './use-automation-step-pickers'\nimport { useOrgAutomationStepPickers } from './use-org-automation-step-pickers'\nimport { orgSiteOptions, type WorkflowsOrgMount } from './workflows-org-mount'\n\n/** An org automation as the editor holds it. */\nexport interface OrgAutomationDraft {\n /** The stored document's id, or null for a new one. */\n id: string | null\n name: string\n event: OrgAutomationTriggerEvent\n filter: string\n conditionRows: ConditionRowDraft[]\n conditionCombinator: TriggerCombinator\n steps: HostActionStep[]\n enabled: boolean\n /** `org` runs on every site; `sites` on the ones in `siteIds`. */\n placement: 'org' | 'sites'\n siteIds: string[]\n}\n\n/** A blank draft: every site, one email step, switched on. */\nexport function newOrgAutomationDraft(): OrgAutomationDraft {\n return {\n id: null,\n name: '',\n event: 'formSubmission',\n filter: '',\n conditionRows: [EMPTY_CONDITION_ROW],\n conditionCombinator: 'and',\n steps: [defaultStep('sendEmail')],\n enabled: true,\n placement: 'org',\n siteIds: [],\n }\n}\n\n/** A stored org automation as the editor opens it. */\nexport function orgAutomationDraft(row: OrgAutomationRow): OrgAutomationDraft {\n const event = isOrgAutomationTriggerEvent(row.trigger?.event)\n ? row.trigger.event\n : 'formSubmission'\n return {\n id: row.$id,\n name: row.name ?? '',\n event,\n filter: row.trigger?.filter ?? '',\n conditionRows: conditionRowsFromTrigger(row.trigger),\n conditionCombinator: row.trigger?.combinator === 'or' ? 'or' : 'and',\n steps: [...(row.steps ?? [])],\n enabled: row.enabled !== false,\n placement: isOrgWideScope(row.visibleTo) ? 'org' : 'sites',\n siteIds: hostIdsFromScope(row.visibleTo),\n }\n}\n\n/** The placement a draft stores, as scope tokens. */\nexport function draftPlacement(draft: OrgAutomationDraft): string[] {\n return draft.placement === 'org'\n ? [ORG_SCOPE_TOKEN]\n : draft.siteIds.map(hostScopeToken)\n}\n\n/** The body `automations/manage` reads, from a draft. */\nexport function orgAutomationBody(\n draft: OrgAutomationDraft,\n): Record<string, unknown> {\n return {\n name: draft.name.trim(),\n trigger: {\n event: draft.event,\n ...(draft.filter.trim() ? { filter: draft.filter.trim() } : {}),\n ...conditionsFromRows(draft.conditionRows, draft.conditionCombinator),\n },\n steps: draft.steps,\n enabled: draft.enabled,\n visibleTo: draftPlacement(draft),\n }\n}\n\nexport interface OrgAutomationEditorProps {\n mount: WorkflowsOrgMount\n /** The draft being edited, or null when the dialog is closed. */\n draft: OrgAutomationDraft | null\n onDraft: (update: (previous: OrgAutomationDraft) => OrgAutomationDraft) => void\n /** The editor has been opened at least once: the latch the pickers read on. */\n opened: boolean\n saving: boolean\n onSave: () => void\n onClose: () => void\n}\n\n/**\n * The org automation editor (AGL-3302): a name, a trigger an org automation\n * can start on, the conditions, the steps from the org vocabulary, and the\n * sites it runs on.\n *\n * The same step rows and condition rows the actions builder uses, offered\n * only what an org automation may hold. Nothing is written from here: Save\n * hands the draft to `automations/manage`, which checks it again.\n */\nexport function OrgAutomationEditor(props: OrgAutomationEditorProps) {\n const { mount, draft, onDraft, opened, saving, onSave, onClose } = props\n const placement = useMemo(\n () => (draft ? draftPlacement(draft) : [ORG_SCOPE_TOKEN]),\n [draft],\n )\n const { pickers, truncated } = useOrgAutomationStepPickers(\n mount.orgId,\n opened,\n placement,\n )\n const sites = useMemo(() => orgSiteOptions(mount), [mount])\n const tooManySites = (draft?.siteIds.length ?? 0) > MAX_SCOPE_HOSTS\n return (\n <Dialog open={Boolean(draft)} onClose={onClose} maxWidth=\"md\" fullWidth>\n <DialogTitle>\n {draft?.id ? 'Edit org automation' : 'Add org automation'}\n </DialogTitle>\n <DialogContent\n sx={{ display: 'flex', flexDirection: 'column', gap: 1.5, pt: 1 }}\n >\n <Typography variant=\"body2\" color=\"text.secondary\">\n {'Runs on every site you place it on, as that site: its email goes ' +\n 'from that site, its runs count on that site’s action runs, and ' +\n 'the site can pause it for itself.'}\n </Typography>\n {truncated.length > 0 ? (\n <Alert severity=\"info\">\n {`Offering the first ${EDITOR_OPTION_CEILING} rows, ordered by id, ` +\n `for: ${truncated.join(', ')}. The organization has more, so a ` +\n 'step target may not be listed below.'}\n </Alert>\n ) : null}\n <TextField\n label=\"Name\"\n value={draft?.name ?? ''}\n onChange={(event) =>\n onDraft((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?.event ?? 'formSubmission'}\n onChange={(event) =>\n onDraft((previous) => ({\n ...previous,\n event: event.target.value as OrgAutomationTriggerEvent,\n }))\n }\n size=\"small\"\n sx={{ minWidth: 200 }}\n >\n {ORG_AUTOMATION_TRIGGER_EVENTS.map((eventType) => (\n <MenuItem key={eventType} value={eventType}>\n {hostEventLabel(eventType)}\n </MenuItem>\n ))}\n </TextField>\n <TextField\n label=\"Filter (optional)\"\n placeholder={'source == \"form\"'}\n helperText={hostEventPayloadHint(draft?.event) ?? undefined}\n value={draft?.filter ?? ''}\n onChange={(event) =>\n onDraft((previous) => ({ ...previous, filter: event.target.value }))\n }\n size=\"small\"\n sx={{ flex: 1 }}\n />\n </Stack>\n <TriggerConditionRows\n rows={draft?.conditionRows ?? []}\n combinator={draft?.conditionCombinator ?? 'and'}\n onRowsChange={(update) =>\n onDraft((previous) => ({\n ...previous,\n conditionRows: update(previous.conditionRows),\n }))\n }\n onCombinatorChange={(combinator) =>\n onDraft((previous) => ({\n ...previous,\n conditionCombinator: combinator,\n }))\n }\n />\n <Typography variant=\"overline\" color=\"text.secondary\">\n {'Runs on'}\n </Typography>\n <RadioGroup\n row\n value={draft?.placement ?? 'org'}\n onChange={(event) =>\n onDraft((previous) => ({\n ...previous,\n placement: event.target.value === 'sites' ? 'sites' : 'org',\n }))\n }\n >\n <FormControlLabel\n value=\"org\"\n control={<Radio size=\"small\" />}\n label=\"Every site\"\n />\n <FormControlLabel\n value=\"sites\"\n control={<Radio size=\"small\" />}\n label=\"Chosen sites\"\n />\n </RadioGroup>\n {draft?.placement === 'sites' ? (\n <FormGroup aria-label=\"Sites it runs on\">\n {!mount.hostsReady ? (\n <Typography variant=\"caption\" color=\"text.secondary\">\n {'…'}\n </Typography>\n ) : !sites.length ? (\n <Typography variant=\"body2\" color=\"text.secondary\">\n {'This organization has no sites yet.'}\n </Typography>\n ) : (\n sites.map((site) => (\n <FormControlLabel\n key={site.value}\n control={\n <Checkbox\n size=\"small\"\n checked={draft.siteIds.includes(site.value)}\n onChange={(event) =>\n onDraft((previous) => ({\n ...previous,\n siteIds: event.target.checked\n ? [...previous.siteIds, site.value]\n : previous.siteIds.filter((id) => id !== site.value),\n }))\n }\n />\n }\n label={site.label}\n />\n ))\n )}\n {tooManySites ? (\n <Typography variant=\"caption\" color=\"error\">\n {`Choose ${MAX_SCOPE_HOSTS} sites or fewer, or run it on every site.`}\n </Typography>\n ) : null}\n </FormGroup>\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={ORG_AUTOMATION_STEP_KINDS}\n stepForKind={(value) => defaultStep(value as HostActionStepType)}\n pickers={pickers}\n onSteps={(update) =>\n onDraft((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 onDraft((previous) => ({\n ...previous,\n steps: [...previous.steps, defaultStep('sendEmail')],\n }))\n }\n >\n {'Add step'}\n </Button>\n <FormControlLabel\n control={\n <Switch\n size=\"small\"\n checked={draft?.enabled !== false}\n onChange={(event) =>\n onDraft((previous) => ({\n ...previous,\n enabled: event.target.checked,\n }))\n }\n />\n }\n label=\"Switched on\"\n />\n </DialogContent>\n <DialogActions>\n <Button color=\"inherit\" onClick={onClose}>\n {'Cancel'}\n </Button>\n <Button\n variant=\"contained\"\n color=\"primary\"\n disabled={!draft?.name.trim() || saving}\n onClick={onSave}\n >\n {saving ? 'Saving…' : 'Save org automation'}\n </Button>\n </DialogActions>\n </Dialog>\n )\n}\nOrgAutomationEditor.displayName = 'OrgAutomationEditor'\n"],"names":["ACTION_MAX_STEPS","hostEventLabel","hostEventPayloadHint","hostIdsFromScope","hostScopeToken","isOrgWideScope","MAX_SCOPE_HOSTS","ORG_SCOPE_TOKEN","Alert","Button","Checkbox","Dialog","DialogActions","DialogContent","DialogTitle","FormControlLabel","FormGroup","MenuItem","Radio","RadioGroup","Stack","Switch","TextField","Typography","useMemo","isOrgAutomationTriggerEvent","ORG_AUTOMATION_STEP_KINDS","ORG_AUTOMATION_TRIGGER_EVENTS","AutomationStepFields","defaultStep","conditionRowsFromTrigger","conditionsFromRows","EMPTY_CONDITION_ROW","TriggerConditionRows","EDITOR_OPTION_CEILING","useOrgAutomationStepPickers","orgSiteOptions","newOrgAutomationDraft","id","name","event","filter","conditionRows","conditionCombinator","steps","enabled","placement","siteIds","orgAutomationDraft","row","trigger","$id","combinator","visibleTo","draftPlacement","draft","map","orgAutomationBody","trim","OrgAutomationEditor","props","mount","onDraft","opened","saving","onSave","onClose","pickers","truncated","orgId","sites","tooManySites","length","open","Boolean","maxWidth","fullWidth","sx","display","flexDirection","gap","pt","variant","color","severity","join","label","value","onChange","previous","target","size","autoFocus","mt","direction","spacing","select","minWidth","eventType","placeholder","helperText","undefined","flex","rows","onRowsChange","update","onCombinatorChange","control","aria-label","hostsReady","site","checked","includes","step","index","kind","type","kinds","stepForKind","onSteps","alignSelf","disabled","onClick","displayName"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/plugins/workflows/src/lib/components/org-automation-editor.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 hostEventLabel,\n hostEventPayloadHint,\n type TriggerCombinator,\n triggerFilterProblem,\n} from '@aglyn/aglyn'\nimport {\n hostIdsFromScope,\n hostScopeToken,\n isOrgWideScope,\n MAX_SCOPE_HOSTS,\n ORG_SCOPE_TOKEN,\n} from '@aglyn/aglyn/app-utils/scope-tokens'\nimport {\n Alert,\n Button,\n Checkbox,\n Dialog,\n DialogActions,\n DialogContent,\n DialogTitle,\n FormControlLabel,\n FormGroup,\n MenuItem,\n Radio,\n RadioGroup,\n Stack,\n Switch,\n TextField,\n Typography,\n} from '@mui/material'\nimport { useMemo } from 'react'\nimport {\n isOrgAutomationTriggerEvent,\n ORG_AUTOMATION_STEP_KINDS,\n ORG_AUTOMATION_TRIGGER_EVENTS,\n type OrgAutomationRow,\n type OrgAutomationTriggerEvent,\n} from '../model/org-automations'\nimport {\n AutomationStepFields,\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 { EDITOR_OPTION_CEILING } from './use-automation-step-pickers'\nimport { useOrgAutomationStepPickers } from './use-org-automation-step-pickers'\nimport { orgSiteOptions, type WorkflowsOrgMount } from './workflows-org-mount'\nimport {\n type HostActionStep,\n type HostActionStepType,\n stepRunsAfterWait,\n} from '../model/host-actions'\n\n/** An org automation as the editor holds it. */\nexport interface OrgAutomationDraft {\n /** The stored document's id, or null for a new one. */\n id: string | null\n name: string\n event: OrgAutomationTriggerEvent\n filter: string\n conditionRows: ConditionRowDraft[]\n conditionCombinator: TriggerCombinator\n steps: HostActionStep[]\n enabled: boolean\n /** `org` runs on every site; `sites` on the ones in `siteIds`. */\n placement: 'org' | 'sites'\n siteIds: string[]\n}\n\n/** A blank draft: every site, one email step, switched on. */\nexport function newOrgAutomationDraft(): OrgAutomationDraft {\n return {\n id: null,\n name: '',\n event: 'formSubmission',\n filter: '',\n conditionRows: [EMPTY_CONDITION_ROW],\n conditionCombinator: 'and',\n steps: [defaultStep('sendEmail')],\n enabled: true,\n placement: 'org',\n siteIds: [],\n }\n}\n\n/** A stored org automation as the editor opens it. */\nexport function orgAutomationDraft(row: OrgAutomationRow): OrgAutomationDraft {\n const event = isOrgAutomationTriggerEvent(row.trigger?.event)\n ? row.trigger.event\n : 'formSubmission'\n return {\n id: row.$id,\n name: row.name ?? '',\n event,\n filter: row.trigger?.filter ?? '',\n conditionRows: conditionRowsFromTrigger(row.trigger),\n conditionCombinator: row.trigger?.combinator === 'or' ? 'or' : 'and',\n steps: [...(row.steps ?? [])],\n enabled: row.enabled !== false,\n placement: isOrgWideScope(row.visibleTo) ? 'org' : 'sites',\n siteIds: hostIdsFromScope(row.visibleTo),\n }\n}\n\n/** The placement a draft stores, as scope tokens. */\nexport function draftPlacement(draft: OrgAutomationDraft): string[] {\n return draft.placement === 'org'\n ? [ORG_SCOPE_TOKEN]\n : draft.siteIds.map(hostScopeToken)\n}\n\n/** The body `automations/manage` reads, from a draft. */\nexport function orgAutomationBody(\n draft: OrgAutomationDraft,\n): Record<string, unknown> {\n return {\n name: draft.name.trim(),\n trigger: {\n event: draft.event,\n ...(draft.filter.trim() ? { filter: draft.filter.trim() } : {}),\n ...conditionsFromRows(draft.conditionRows, draft.conditionCombinator),\n },\n steps: draft.steps,\n enabled: draft.enabled,\n visibleTo: draftPlacement(draft),\n }\n}\n\nexport interface OrgAutomationEditorProps {\n mount: WorkflowsOrgMount\n /** The draft being edited, or null when the dialog is closed. */\n draft: OrgAutomationDraft | null\n onDraft: (update: (previous: OrgAutomationDraft) => OrgAutomationDraft) => void\n /** The editor has been opened at least once: the latch the pickers read on. */\n opened: boolean\n saving: boolean\n onSave: () => void\n onClose: () => void\n}\n\n/**\n * The org automation editor (AGL-3302): a name, a trigger an org automation\n * can start on, the conditions, the steps from the org vocabulary, and the\n * sites it runs on.\n *\n * The same step rows and condition rows the actions builder uses, offered\n * only what an org automation may hold. Nothing is written from here: Save\n * hands the draft to `automations/manage`, which checks it again.\n */\nexport function OrgAutomationEditor(props: OrgAutomationEditorProps) {\n const { mount, draft, onDraft, opened, saving, onSave, onClose } = props\n const placement = useMemo(\n () => (draft ? draftPlacement(draft) : [ORG_SCOPE_TOKEN]),\n [draft],\n )\n const { pickers, truncated } = useOrgAutomationStepPickers(\n mount.orgId,\n opened,\n placement,\n )\n const sites = useMemo(() => orgSiteOptions(mount), [mount])\n const tooManySites = (draft?.siteIds.length ?? 0) > MAX_SCOPE_HOSTS\n return (\n <Dialog open={Boolean(draft)} onClose={onClose} maxWidth=\"md\" fullWidth>\n <DialogTitle>\n {draft?.id ? 'Edit org automation' : 'Add org automation'}\n </DialogTitle>\n <DialogContent\n sx={{ display: 'flex', flexDirection: 'column', gap: 1.5, pt: 1 }}\n >\n <Typography variant=\"body2\" color=\"text.secondary\">\n {'Runs on every site you place it on, as that site: its email goes ' +\n 'from that site, its runs count on that site’s action runs, and ' +\n 'the site can pause it for itself.'}\n </Typography>\n {truncated.length > 0 ? (\n <Alert severity=\"info\">\n {`Offering the first ${EDITOR_OPTION_CEILING} rows, ordered by id, ` +\n `for: ${truncated.join(', ')}. The organization has more, so a ` +\n 'step target may not be listed below.'}\n </Alert>\n ) : null}\n <TextField\n label=\"Name\"\n value={draft?.name ?? ''}\n onChange={(event) =>\n onDraft((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?.event ?? 'formSubmission'}\n onChange={(event) =>\n onDraft((previous) => ({\n ...previous,\n event: event.target.value as OrgAutomationTriggerEvent,\n }))\n }\n size=\"small\"\n sx={{ minWidth: 200 }}\n >\n {ORG_AUTOMATION_TRIGGER_EVENTS.map((eventType) => (\n <MenuItem key={eventType} value={eventType}>\n {hostEventLabel(eventType)}\n </MenuItem>\n ))}\n </TextField>\n <TextField\n label=\"Filter (optional)\"\n placeholder=\"subscribe\"\n // A comparison belongs in the conditions below (AGL-3458): the\n // filter's evaluator is arithmetic, and `source == \"form\"` throws\n // on every event, so it is refused here.\n error={Boolean(triggerFilterProblem(draft?.filter))}\n helperText={\n triggerFilterProblem(draft?.filter) ?? hostEventPayloadHint(draft?.event) ?? undefined\n }\n value={draft?.filter ?? ''}\n onChange={(event) =>\n onDraft((previous) => ({ ...previous, filter: event.target.value }))\n }\n size=\"small\"\n sx={{ flex: 1 }}\n />\n </Stack>\n <TriggerConditionRows\n rows={draft?.conditionRows ?? []}\n combinator={draft?.conditionCombinator ?? 'and'}\n onRowsChange={(update) =>\n onDraft((previous) => ({\n ...previous,\n conditionRows: update(previous.conditionRows),\n }))\n }\n onCombinatorChange={(combinator) =>\n onDraft((previous) => ({\n ...previous,\n conditionCombinator: combinator,\n }))\n }\n />\n <Typography variant=\"overline\" color=\"text.secondary\">\n {'Runs on'}\n </Typography>\n <RadioGroup\n row\n value={draft?.placement ?? 'org'}\n onChange={(event) =>\n onDraft((previous) => ({\n ...previous,\n placement: event.target.value === 'sites' ? 'sites' : 'org',\n }))\n }\n >\n <FormControlLabel\n value=\"org\"\n control={<Radio size=\"small\" />}\n label=\"Every site\"\n />\n <FormControlLabel\n value=\"sites\"\n control={<Radio size=\"small\" />}\n label=\"Chosen sites\"\n />\n </RadioGroup>\n {draft?.placement === 'sites' ? (\n <FormGroup aria-label=\"Sites it runs on\">\n {!mount.hostsReady ? (\n <Typography variant=\"caption\" color=\"text.secondary\">\n {'…'}\n </Typography>\n ) : !sites.length ? (\n <Typography variant=\"body2\" color=\"text.secondary\">\n {'This organization has no sites yet.'}\n </Typography>\n ) : (\n sites.map((site) => (\n <FormControlLabel\n key={site.value}\n control={\n <Checkbox\n size=\"small\"\n checked={draft.siteIds.includes(site.value)}\n onChange={(event) =>\n onDraft((previous) => ({\n ...previous,\n siteIds: event.target.checked\n ? [...previous.siteIds, site.value]\n : previous.siteIds.filter((id) => id !== site.value),\n }))\n }\n />\n }\n label={site.label}\n />\n ))\n )}\n {tooManySites ? (\n <Typography variant=\"caption\" color=\"error\">\n {`Choose ${MAX_SCOPE_HOSTS} sites or fewer, or run it on every site.`}\n </Typography>\n ) : null}\n </FormGroup>\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={ORG_AUTOMATION_STEP_KINDS}\n stepForKind={(value) => defaultStep(value as HostActionStepType)}\n pickers={pickers}\n onSteps={(update) =>\n onDraft((previous) => ({\n ...previous,\n steps: update(previous.steps),\n }))\n }\n replyContext={{\n event: draft?.event,\n afterWait: stepRunsAfterWait(draft?.steps, index),\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 onDraft((previous) => ({\n ...previous,\n steps: [...previous.steps, defaultStep('sendEmail')],\n }))\n }\n >\n {'Add step'}\n </Button>\n <FormControlLabel\n control={\n <Switch\n size=\"small\"\n checked={draft?.enabled !== false}\n onChange={(event) =>\n onDraft((previous) => ({\n ...previous,\n enabled: event.target.checked,\n }))\n }\n />\n }\n label=\"Switched on\"\n />\n </DialogContent>\n <DialogActions>\n <Button color=\"inherit\" onClick={onClose}>\n {'Cancel'}\n </Button>\n <Button\n variant=\"contained\"\n color=\"primary\"\n disabled={!draft?.name.trim() || saving}\n onClick={onSave}\n >\n {saving ? 'Saving…' : 'Save org automation'}\n </Button>\n </DialogActions>\n </Dialog>\n )\n}\nOrgAutomationEditor.displayName = 'OrgAutomationEditor'\n"],"names":["ACTION_MAX_STEPS","hostEventLabel","hostEventPayloadHint","triggerFilterProblem","hostIdsFromScope","hostScopeToken","isOrgWideScope","MAX_SCOPE_HOSTS","ORG_SCOPE_TOKEN","Alert","Button","Checkbox","Dialog","DialogActions","DialogContent","DialogTitle","FormControlLabel","FormGroup","MenuItem","Radio","RadioGroup","Stack","Switch","TextField","Typography","useMemo","isOrgAutomationTriggerEvent","ORG_AUTOMATION_STEP_KINDS","ORG_AUTOMATION_TRIGGER_EVENTS","AutomationStepFields","defaultStep","conditionRowsFromTrigger","conditionsFromRows","EMPTY_CONDITION_ROW","TriggerConditionRows","EDITOR_OPTION_CEILING","useOrgAutomationStepPickers","orgSiteOptions","stepRunsAfterWait","newOrgAutomationDraft","id","name","event","filter","conditionRows","conditionCombinator","steps","enabled","placement","siteIds","orgAutomationDraft","row","trigger","$id","combinator","visibleTo","draftPlacement","draft","map","orgAutomationBody","trim","OrgAutomationEditor","props","mount","onDraft","opened","saving","onSave","onClose","pickers","truncated","orgId","sites","tooManySites","length","open","Boolean","maxWidth","fullWidth","sx","display","flexDirection","gap","pt","variant","color","severity","join","label","value","onChange","previous","target","size","autoFocus","mt","direction","spacing","select","minWidth","eventType","placeholder","error","helperText","undefined","flex","rows","onRowsChange","update","onCombinatorChange","control","aria-label","hostsReady","site","checked","includes","step","index","kind","type","kinds","stepForKind","onSteps","replyContext","afterWait","alignSelf","disabled","onClick","displayName"],"mappings":"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"}
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
*/ 'use client';
|
|
17
17
|
import { _ as _extends } from "@swc/helpers/_/_extends";
|
|
18
18
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
19
|
-
import { checkEntitlement,
|
|
19
|
+
import { checkEntitlement, hostEventLabel, pluginDocsHelp } from "@aglyn/aglyn";
|
|
20
20
|
import { hostIdsFromScope, isOrgWideScope } from "@aglyn/aglyn/app-utils/scope-tokens";
|
|
21
21
|
import { CardDisplay, useConfirmationContext } from "@aglyn/shared-ui-jsx";
|
|
22
22
|
import { ListPagination } from "@aglyn/shared-ui-jsx/components/list-pagination.component";
|
|
@@ -30,6 +30,7 @@ import { ORG_AUTOMATIONS_COLLECTION, ORG_AUTOMATIONS_MAX, orgAutomationPausedHos
|
|
|
30
30
|
import { newOrgAutomationDraft, OrgAutomationEditor, orgAutomationBody, orgAutomationDraft } from "./org-automation-editor.component.js";
|
|
31
31
|
import { useOrgAutomationsApi } from "./use-org-automations-api.js";
|
|
32
32
|
import { orgSiteName } from "./workflows-org-mount.js";
|
|
33
|
+
import { HOST_ACTION_STEP_LABELS } from "../model/host-actions.js";
|
|
33
34
|
/** The sites an automation runs on, by id: every org site for `['org']`. */ function placedSiteIds(row, mount) {
|
|
34
35
|
return isOrgWideScope(row.visibleTo) ? mount.hosts.map((host)=>host.id) : hostIdsFromScope(row.visibleTo);
|
|
35
36
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../../libs/plugins/workflows/src/lib/components/org-automations-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 type AglynOrgBilling,\n checkEntitlement,\n HOST_ACTION_STEP_LABELS,\n type HostActionStepType,\n hostEventLabel,\n pluginDocsHelp,\n} from '@aglyn/aglyn'\nimport {\n hostIdsFromScope,\n isOrgWideScope,\n} from '@aglyn/aglyn/app-utils/scope-tokens'\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 {\n useFirestore,\n useFirestoreCollection,\n} from '@aglyn/tenant-feature-instance'\nimport {\n Alert,\n Button,\n Chip,\n Menu,\n MenuItem,\n Stack,\n Switch,\n Typography,\n} from '@mui/material'\nimport {\n collection,\n documentId,\n limit,\n orderBy,\n query,\n where,\n} from 'firebase/firestore'\nimport { useCallback, useMemo, useState } from 'react'\nimport {\n ORG_AUTOMATIONS_COLLECTION,\n ORG_AUTOMATIONS_MAX,\n orgAutomationPausedHostIds,\n type OrgAutomationRow,\n readOrgAutomation,\n} from '../model/org-automations'\nimport {\n newOrgAutomationDraft,\n OrgAutomationEditor,\n orgAutomationBody,\n type OrgAutomationDraft,\n orgAutomationDraft,\n} from './org-automation-editor.component'\nimport { useOrgAutomationsApi } from './use-org-automations-api'\nimport { orgSiteName, type WorkflowsOrgMount } from './workflows-org-mount'\n\nexport interface OrgAutomationsCardProps {\n mount: WorkflowsOrgMount\n org?: Partial<AglynOrgBilling>\n /**\n * Whether the reader may write the organization's automations — an owner,\n * admin or editor. The route decides; this keeps a viewer from being\n * offered controls that are about to refuse them.\n */\n canEdit: boolean\n}\n\n/** The sites an automation runs on, by id: every org site for `['org']`. */\nfunction placedSiteIds(\n row: Pick<OrgAutomationRow, 'visibleTo'>,\n mount: WorkflowsOrgMount,\n): string[] {\n return isOrgWideScope(row.visibleTo)\n ? mount.hosts.map((host) => host.id)\n : hostIdsFromScope(row.visibleTo)\n}\n\n/** \"Runs on every site\" or \"Runs on Shop, Blog\". */\nfunction placementLine(\n row: Pick<OrgAutomationRow, 'visibleTo'>,\n mount: WorkflowsOrgMount,\n): string {\n if (isOrgWideScope(row.visibleTo)) return 'Runs on every site'\n const names = hostIdsFromScope(row.visibleTo).map((id) => orgSiteName(mount, id))\n return names.length ? `Runs on ${names.join(', ')}` : 'Runs on no site'\n}\n\n/**\n * THE ORGANIZATION'S AUTOMATIONS (AGL-3302): what the organization runs on\n * the sites it chooses.\n *\n * One ceilinged read of the live automations — the org hub admits only\n * org-wide members, who read every one — and every write through\n * `automations/manage` or `automations/pause`, because the collection is\n * closed to client writes. Each row says where it runs and where it is\n * paused; a paused site is resumed from its chip, and any placed site can be\n * paused from the row, which is the same control the site's own hub offers.\n */\nexport function OrgAutomationsCard(props: OrgAutomationsCardProps) {\n const { mount, org, canEdit } = props\n const firestore = useFirestore()\n const api = useOrgAutomationsApi()\n const { enqueueSnackbar } = useSnackbar()\n const { confirm } = useConfirmationContext()\n\n /*\n * Every LIVE automation, ceilinged at the organization's cap plus the probe\n * row. `deletedAt` is always written — `null` while live — so equality asks\n * for exactly the live ones and deleted documents never take a place in the\n * window. Ordered by document id, which the automatic single-field index\n * carries behind the equality, so the window is named rather than whatever\n * order Firestore returns; the list is sorted by name once it is in hand.\n */\n const { data: rows } = useFirestoreCollection<OrgAutomationRow>(\n () =>\n query(\n collection(firestore, 'orgs', mount.orgId, ORG_AUTOMATIONS_COLLECTION),\n where('deletedAt', '==', null),\n orderBy(documentId()),\n limit(ORG_AUTOMATIONS_MAX + 1),\n ),\n [firestore, mount.orgId],\n { idField: '$id' },\n )\n const automations = useMemo(\n () =>\n [...(rows ?? [])]\n .slice(0, ORG_AUTOMATIONS_MAX)\n .sort((a, b) => String(a.name ?? '').localeCompare(String(b.name ?? ''))),\n [rows],\n )\n const [page, setPage] = useState(0)\n const [pageSize, setPageSize] = useState(TABLE_PAGE_SIZE_DEFAULT)\n const shown = useMemo(\n () => automations.slice(page * pageSize, page * pageSize + pageSize),\n [automations, page, pageSize],\n )\n\n const [draft, setDraft] = useState<OrgAutomationDraft | null>(null)\n /**\n * The editor has been opened at least once — the latch the pickers key on,\n * so Cancel and the next Edit do not buy the option lists twice.\n */\n const [editorOpened, setEditorOpened] = useState(false)\n if (draft && !editorOpened) setEditorOpened(true)\n const [saving, setSaving] = useState(false)\n const [pauseMenu, setPauseMenu] = useState<{\n anchor: HTMLElement\n row: OrgAutomationRow\n } | null>(null)\n\n const entitled = checkEntitlement(org, 'actions')\n const fail = useCallback(\n (error: unknown) =>\n enqueueSnackbar((error as Error)?.message || 'The request could not be completed', {\n variant: 'warning',\n persist: false,\n }),\n [enqueueSnackbar],\n )\n\n const handleAdd = useCallback(() => {\n if (!entitled) {\n enqueueSnackbar(\n 'Org automations are built from the actions builder, which requires a Pro plan — see Billing to upgrade',\n { variant: 'warning', persist: false },\n )\n return\n }\n setDraft(newOrgAutomationDraft())\n }, [entitled, enqueueSnackbar])\n\n const handleSave = useCallback(async () => {\n if (!draft) return\n const body = orgAutomationBody(draft)\n // The route's own reader, asked first so a mistake reads the same here as\n // it would coming back from the server — and costs no round trip.\n const read = readOrgAutomation(body)\n if (read.ok === false) {\n return void enqueueSnackbar(read.problem, { variant: 'warning', persist: false })\n }\n setSaving(true)\n try {\n await api('manage', {\n orgId: mount.orgId,\n action: draft.id ? 'update' : 'create',\n ...(draft.id ? { automationId: draft.id } : {}),\n automation: body,\n })\n setDraft(null)\n enqueueSnackbar('Org automation saved', { variant: 'success', persist: false })\n } catch (error) {\n fail(error)\n } finally {\n setSaving(false)\n }\n }, [draft, api, mount.orgId, enqueueSnackbar, fail])\n\n const handleToggle = useCallback(\n (row: OrgAutomationRow) => async (event: { target: { checked: boolean } }) => {\n try {\n await api('manage', {\n orgId: mount.orgId,\n action: 'setEnabled',\n automationId: row.$id,\n enabled: event.target.checked,\n })\n } catch (error) {\n fail(error)\n }\n },\n [api, mount.orgId, fail],\n )\n\n const handleDelete = useCallback(\n (row: OrgAutomationRow) => async () => {\n const confirmed = await confirm({\n title: 'Delete this org automation?',\n description:\n `\"${row.name}\" stops running on every site it is placed on, and ` +\n 'anyone waiting inside it stops too.',\n confirmationText: 'Delete',\n confirmationButtonProps: { color: 'error' },\n })\n .then(() => true)\n .catch(() => false)\n if (!confirmed) return\n try {\n await api('manage', {\n orgId: mount.orgId,\n action: 'delete',\n automationId: row.$id,\n })\n } catch (error) {\n fail(error)\n }\n },\n [confirm, api, mount.orgId, fail],\n )\n\n const setPaused = useCallback(\n async (row: OrgAutomationRow, hostId: string, paused: boolean) => {\n setPauseMenu(null)\n try {\n await api('pause', { hostId, automationId: row.$id, paused })\n } catch (error) {\n fail(error)\n }\n },\n [api, fail],\n )\n\n return (\n <CardDisplay\n header={'Org automations'}\n help={pluginDocsHelp('orgAutomations', { anchor: '#what-an-org-automation-is' })}\n contentGutterX\n contentGutterY\n >\n <Stack spacing={1}>\n <Typography variant=\"body2\" color=\"text.secondary\">\n {'Write an automation once and run it on every site you choose. ' +\n 'Each run is that site’s own: its email goes from that site, it ' +\n 'counts on that site’s action runs, and the site can pause it ' +\n 'for itself. Pro plans and up.'}\n </Typography>\n {shown.map((row) => {\n const paused = orgAutomationPausedHostIds(row)\n const placed = placedSiteIds(row, mount)\n const pausable = placed.filter((hostId) => !paused.includes(hostId))\n return (\n <Stack\n key={row.$id}\n direction=\"row\"\n spacing={1}\n sx={{ alignItems: 'center' }}\n >\n <Switch\n size=\"small\"\n checked={row.enabled !== false}\n disabled={!canEdit}\n onChange={handleToggle(row)}\n slotProps={{ input: { 'aria-label': `Switch ${row.name} on or off` } }}\n />\n <Stack sx={{ flex: 1, minWidth: 0 }} spacing={0.25}>\n <Typography variant=\"body2\" noWrap>\n {row.name}\n </Typography>\n <Typography variant=\"caption\" color=\"text.secondary\" noWrap>\n {`on ${hostEventLabel(row.trigger?.event)} · ${(row.steps ?? [])\n .map(\n (step) =>\n HOST_ACTION_STEP_LABELS[step.type as HostActionStepType] ??\n step.type,\n )\n .join(' → ')}`}\n </Typography>\n <Typography variant=\"caption\" color=\"text.secondary\" noWrap>\n {placementLine(row, mount)}\n </Typography>\n {paused.length ? (\n <Stack direction=\"row\" spacing={0.5} sx={{ flexWrap: 'wrap', gap: 0.5 }}>\n {paused.map((hostId) => (\n <Chip\n key={hostId}\n size=\"small\"\n variant=\"outlined\"\n color=\"warning\"\n label={`Paused on ${orgSiteName(mount, hostId)}`}\n {...(canEdit\n ? { onDelete: () => void setPaused(row, hostId, false) }\n : {})}\n />\n ))}\n </Stack>\n ) : null}\n </Stack>\n {canEdit ? (\n <>\n <Button size=\"small\" onClick={() => setDraft(orgAutomationDraft(row))}>\n {'Edit'}\n </Button>\n <Button\n size=\"small\"\n disabled={!pausable.length}\n aria-haspopup=\"menu\"\n onClick={(event) =>\n setPauseMenu({ anchor: event.currentTarget, row })\n }\n >\n {'Pause on…'}\n </Button>\n <Button size=\"small\" color=\"error\" onClick={handleDelete(row)}>\n {'Delete'}\n </Button>\n </>\n ) : null}\n </Stack>\n )\n })}\n {automations.length === 0 ? (\n <Typography variant=\"body2\" color=\"text.secondary\">\n {'No org automations yet.'}\n </Typography>\n ) : (\n <ListPagination\n page={page}\n pageSize={pageSize}\n rowCount={shown.length}\n count={automations.length}\n onPageChange={setPage}\n onPageSizeChange={setPageSize}\n />\n )}\n {(rows?.length ?? 0) > ORG_AUTOMATIONS_MAX ? (\n <Alert severity=\"info\">\n {`Showing ${ORG_AUTOMATIONS_MAX} org automations, the most an ` +\n 'organization holds.'}\n </Alert>\n ) : null}\n {canEdit ? (\n <Button\n size=\"small\"\n color=\"primary\"\n sx={{ alignSelf: 'flex-start' }}\n onClick={handleAdd}\n >\n {'Add org automation'}\n </Button>\n ) : null}\n </Stack>\n <Menu\n anchorEl={pauseMenu?.anchor ?? null}\n open={Boolean(pauseMenu)}\n onClose={() => setPauseMenu(null)}\n >\n {pauseMenu\n ? placedSiteIds(pauseMenu.row, mount)\n .filter(\n (hostId) =>\n !orgAutomationPausedHostIds(pauseMenu.row).includes(hostId),\n )\n .map((hostId) => (\n <MenuItem\n key={hostId}\n onClick={() => void setPaused(pauseMenu.row, hostId, true)}\n >\n {`Pause on ${orgSiteName(mount, hostId)}`}\n </MenuItem>\n ))\n : null}\n </Menu>\n <OrgAutomationEditor\n mount={mount}\n draft={draft}\n onDraft={(update) =>\n setDraft((previous) => (previous ? update(previous) : previous))\n }\n opened={editorOpened}\n saving={saving}\n onSave={() => void handleSave()}\n onClose={() => setDraft(null)}\n />\n </CardDisplay>\n )\n}\nOrgAutomationsCard.displayName = 'OrgAutomationsCard'\n\nexport default OrgAutomationsCard\n"],"names":["checkEntitlement","HOST_ACTION_STEP_LABELS","hostEventLabel","pluginDocsHelp","hostIdsFromScope","isOrgWideScope","CardDisplay","useConfirmationContext","ListPagination","TABLE_PAGE_SIZE_DEFAULT","useSnackbar","useFirestore","useFirestoreCollection","Alert","Button","Chip","Menu","MenuItem","Stack","Switch","Typography","collection","documentId","limit","orderBy","query","where","useCallback","useMemo","useState","ORG_AUTOMATIONS_COLLECTION","ORG_AUTOMATIONS_MAX","orgAutomationPausedHostIds","readOrgAutomation","newOrgAutomationDraft","OrgAutomationEditor","orgAutomationBody","orgAutomationDraft","useOrgAutomationsApi","orgSiteName","placedSiteIds","row","mount","visibleTo","hosts","map","host","id","placementLine","names","length","join","OrgAutomationsCard","props","org","canEdit","firestore","api","enqueueSnackbar","confirm","data","rows","orgId","idField","automations","slice","sort","a","b","String","name","localeCompare","page","setPage","pageSize","setPageSize","shown","draft","setDraft","editorOpened","setEditorOpened","saving","setSaving","pauseMenu","setPauseMenu","entitled","fail","error","message","variant","persist","handleAdd","handleSave","body","read","ok","problem","action","automationId","automation","handleToggle","event","$id","enabled","target","checked","handleDelete","confirmed","title","description","confirmationText","confirmationButtonProps","color","then","catch","setPaused","hostId","paused","header","help","anchor","contentGutterX","contentGutterY","spacing","placed","pausable","filter","includes","direction","sx","alignItems","size","disabled","onChange","slotProps","input","flex","minWidth","noWrap","trigger","steps","step","type","flexWrap","gap","label","onDelete","onClick","aria-haspopup","currentTarget","rowCount","count","onPageChange","onPageSizeChange","severity","alignSelf","anchorEl","open","Boolean","onClose","onDraft","update","previous","opened","onSave","displayName"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/plugins/workflows/src/lib/components/org-automations-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 type AglynOrgBilling,\n checkEntitlement,\n hostEventLabel,\n pluginDocsHelp,\n} from '@aglyn/aglyn'\nimport {\n hostIdsFromScope,\n isOrgWideScope,\n} from '@aglyn/aglyn/app-utils/scope-tokens'\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 {\n useFirestore,\n useFirestoreCollection,\n} from '@aglyn/tenant-feature-instance'\nimport {\n Alert,\n Button,\n Chip,\n Menu,\n MenuItem,\n Stack,\n Switch,\n Typography,\n} from '@mui/material'\nimport {\n collection,\n documentId,\n limit,\n orderBy,\n query,\n where,\n} from 'firebase/firestore'\nimport { useCallback, useMemo, useState } from 'react'\nimport {\n ORG_AUTOMATIONS_COLLECTION,\n ORG_AUTOMATIONS_MAX,\n orgAutomationPausedHostIds,\n type OrgAutomationRow,\n readOrgAutomation,\n} from '../model/org-automations'\nimport {\n newOrgAutomationDraft,\n OrgAutomationEditor,\n orgAutomationBody,\n type OrgAutomationDraft,\n orgAutomationDraft,\n} from './org-automation-editor.component'\nimport { useOrgAutomationsApi } from './use-org-automations-api'\nimport { orgSiteName, type WorkflowsOrgMount } from './workflows-org-mount'\nimport { HOST_ACTION_STEP_LABELS, type HostActionStepType } from '../model/host-actions'\n\nexport interface OrgAutomationsCardProps {\n mount: WorkflowsOrgMount\n org?: Partial<AglynOrgBilling>\n /**\n * Whether the reader may write the organization's automations — an owner,\n * admin or editor. The route decides; this keeps a viewer from being\n * offered controls that are about to refuse them.\n */\n canEdit: boolean\n}\n\n/** The sites an automation runs on, by id: every org site for `['org']`. */\nfunction placedSiteIds(\n row: Pick<OrgAutomationRow, 'visibleTo'>,\n mount: WorkflowsOrgMount,\n): string[] {\n return isOrgWideScope(row.visibleTo)\n ? mount.hosts.map((host) => host.id)\n : hostIdsFromScope(row.visibleTo)\n}\n\n/** \"Runs on every site\" or \"Runs on Shop, Blog\". */\nfunction placementLine(\n row: Pick<OrgAutomationRow, 'visibleTo'>,\n mount: WorkflowsOrgMount,\n): string {\n if (isOrgWideScope(row.visibleTo)) return 'Runs on every site'\n const names = hostIdsFromScope(row.visibleTo).map((id) => orgSiteName(mount, id))\n return names.length ? `Runs on ${names.join(', ')}` : 'Runs on no site'\n}\n\n/**\n * THE ORGANIZATION'S AUTOMATIONS (AGL-3302): what the organization runs on\n * the sites it chooses.\n *\n * One ceilinged read of the live automations — the org hub admits only\n * org-wide members, who read every one — and every write through\n * `automations/manage` or `automations/pause`, because the collection is\n * closed to client writes. Each row says where it runs and where it is\n * paused; a paused site is resumed from its chip, and any placed site can be\n * paused from the row, which is the same control the site's own hub offers.\n */\nexport function OrgAutomationsCard(props: OrgAutomationsCardProps) {\n const { mount, org, canEdit } = props\n const firestore = useFirestore()\n const api = useOrgAutomationsApi()\n const { enqueueSnackbar } = useSnackbar()\n const { confirm } = useConfirmationContext()\n\n /*\n * Every LIVE automation, ceilinged at the organization's cap plus the probe\n * row. `deletedAt` is always written — `null` while live — so equality asks\n * for exactly the live ones and deleted documents never take a place in the\n * window. Ordered by document id, which the automatic single-field index\n * carries behind the equality, so the window is named rather than whatever\n * order Firestore returns; the list is sorted by name once it is in hand.\n */\n const { data: rows } = useFirestoreCollection<OrgAutomationRow>(\n () =>\n query(\n collection(firestore, 'orgs', mount.orgId, ORG_AUTOMATIONS_COLLECTION),\n where('deletedAt', '==', null),\n orderBy(documentId()),\n limit(ORG_AUTOMATIONS_MAX + 1),\n ),\n [firestore, mount.orgId],\n { idField: '$id' },\n )\n const automations = useMemo(\n () =>\n [...(rows ?? [])]\n .slice(0, ORG_AUTOMATIONS_MAX)\n .sort((a, b) => String(a.name ?? '').localeCompare(String(b.name ?? ''))),\n [rows],\n )\n const [page, setPage] = useState(0)\n const [pageSize, setPageSize] = useState(TABLE_PAGE_SIZE_DEFAULT)\n const shown = useMemo(\n () => automations.slice(page * pageSize, page * pageSize + pageSize),\n [automations, page, pageSize],\n )\n\n const [draft, setDraft] = useState<OrgAutomationDraft | null>(null)\n /**\n * The editor has been opened at least once — the latch the pickers key on,\n * so Cancel and the next Edit do not buy the option lists twice.\n */\n const [editorOpened, setEditorOpened] = useState(false)\n if (draft && !editorOpened) setEditorOpened(true)\n const [saving, setSaving] = useState(false)\n const [pauseMenu, setPauseMenu] = useState<{\n anchor: HTMLElement\n row: OrgAutomationRow\n } | null>(null)\n\n const entitled = checkEntitlement(org, 'actions')\n const fail = useCallback(\n (error: unknown) =>\n enqueueSnackbar((error as Error)?.message || 'The request could not be completed', {\n variant: 'warning',\n persist: false,\n }),\n [enqueueSnackbar],\n )\n\n const handleAdd = useCallback(() => {\n if (!entitled) {\n enqueueSnackbar(\n 'Org automations are built from the actions builder, which requires a Pro plan — see Billing to upgrade',\n { variant: 'warning', persist: false },\n )\n return\n }\n setDraft(newOrgAutomationDraft())\n }, [entitled, enqueueSnackbar])\n\n const handleSave = useCallback(async () => {\n if (!draft) return\n const body = orgAutomationBody(draft)\n // The route's own reader, asked first so a mistake reads the same here as\n // it would coming back from the server — and costs no round trip.\n const read = readOrgAutomation(body)\n if (read.ok === false) {\n return void enqueueSnackbar(read.problem, { variant: 'warning', persist: false })\n }\n setSaving(true)\n try {\n await api('manage', {\n orgId: mount.orgId,\n action: draft.id ? 'update' : 'create',\n ...(draft.id ? { automationId: draft.id } : {}),\n automation: body,\n })\n setDraft(null)\n enqueueSnackbar('Org automation saved', { variant: 'success', persist: false })\n } catch (error) {\n fail(error)\n } finally {\n setSaving(false)\n }\n }, [draft, api, mount.orgId, enqueueSnackbar, fail])\n\n const handleToggle = useCallback(\n (row: OrgAutomationRow) => async (event: { target: { checked: boolean } }) => {\n try {\n await api('manage', {\n orgId: mount.orgId,\n action: 'setEnabled',\n automationId: row.$id,\n enabled: event.target.checked,\n })\n } catch (error) {\n fail(error)\n }\n },\n [api, mount.orgId, fail],\n )\n\n const handleDelete = useCallback(\n (row: OrgAutomationRow) => async () => {\n const confirmed = await confirm({\n title: 'Delete this org automation?',\n description:\n `\"${row.name}\" stops running on every site it is placed on, and ` +\n 'anyone waiting inside it stops too.',\n confirmationText: 'Delete',\n confirmationButtonProps: { color: 'error' },\n })\n .then(() => true)\n .catch(() => false)\n if (!confirmed) return\n try {\n await api('manage', {\n orgId: mount.orgId,\n action: 'delete',\n automationId: row.$id,\n })\n } catch (error) {\n fail(error)\n }\n },\n [confirm, api, mount.orgId, fail],\n )\n\n const setPaused = useCallback(\n async (row: OrgAutomationRow, hostId: string, paused: boolean) => {\n setPauseMenu(null)\n try {\n await api('pause', { hostId, automationId: row.$id, paused })\n } catch (error) {\n fail(error)\n }\n },\n [api, fail],\n )\n\n return (\n <CardDisplay\n header={'Org automations'}\n help={pluginDocsHelp('orgAutomations', { anchor: '#what-an-org-automation-is' })}\n contentGutterX\n contentGutterY\n >\n <Stack spacing={1}>\n <Typography variant=\"body2\" color=\"text.secondary\">\n {'Write an automation once and run it on every site you choose. ' +\n 'Each run is that site’s own: its email goes from that site, it ' +\n 'counts on that site’s action runs, and the site can pause it ' +\n 'for itself. Pro plans and up.'}\n </Typography>\n {shown.map((row) => {\n const paused = orgAutomationPausedHostIds(row)\n const placed = placedSiteIds(row, mount)\n const pausable = placed.filter((hostId) => !paused.includes(hostId))\n return (\n <Stack\n key={row.$id}\n direction=\"row\"\n spacing={1}\n sx={{ alignItems: 'center' }}\n >\n <Switch\n size=\"small\"\n checked={row.enabled !== false}\n disabled={!canEdit}\n onChange={handleToggle(row)}\n slotProps={{ input: { 'aria-label': `Switch ${row.name} on or off` } }}\n />\n <Stack sx={{ flex: 1, minWidth: 0 }} spacing={0.25}>\n <Typography variant=\"body2\" noWrap>\n {row.name}\n </Typography>\n <Typography variant=\"caption\" color=\"text.secondary\" noWrap>\n {`on ${hostEventLabel(row.trigger?.event)} · ${(row.steps ?? [])\n .map(\n (step) =>\n HOST_ACTION_STEP_LABELS[step.type as HostActionStepType] ??\n step.type,\n )\n .join(' → ')}`}\n </Typography>\n <Typography variant=\"caption\" color=\"text.secondary\" noWrap>\n {placementLine(row, mount)}\n </Typography>\n {paused.length ? (\n <Stack direction=\"row\" spacing={0.5} sx={{ flexWrap: 'wrap', gap: 0.5 }}>\n {paused.map((hostId) => (\n <Chip\n key={hostId}\n size=\"small\"\n variant=\"outlined\"\n color=\"warning\"\n label={`Paused on ${orgSiteName(mount, hostId)}`}\n {...(canEdit\n ? { onDelete: () => void setPaused(row, hostId, false) }\n : {})}\n />\n ))}\n </Stack>\n ) : null}\n </Stack>\n {canEdit ? (\n <>\n <Button size=\"small\" onClick={() => setDraft(orgAutomationDraft(row))}>\n {'Edit'}\n </Button>\n <Button\n size=\"small\"\n disabled={!pausable.length}\n aria-haspopup=\"menu\"\n onClick={(event) =>\n setPauseMenu({ anchor: event.currentTarget, row })\n }\n >\n {'Pause on…'}\n </Button>\n <Button size=\"small\" color=\"error\" onClick={handleDelete(row)}>\n {'Delete'}\n </Button>\n </>\n ) : null}\n </Stack>\n )\n })}\n {automations.length === 0 ? (\n <Typography variant=\"body2\" color=\"text.secondary\">\n {'No org automations yet.'}\n </Typography>\n ) : (\n <ListPagination\n page={page}\n pageSize={pageSize}\n rowCount={shown.length}\n count={automations.length}\n onPageChange={setPage}\n onPageSizeChange={setPageSize}\n />\n )}\n {(rows?.length ?? 0) > ORG_AUTOMATIONS_MAX ? (\n <Alert severity=\"info\">\n {`Showing ${ORG_AUTOMATIONS_MAX} org automations, the most an ` +\n 'organization holds.'}\n </Alert>\n ) : null}\n {canEdit ? (\n <Button\n size=\"small\"\n color=\"primary\"\n sx={{ alignSelf: 'flex-start' }}\n onClick={handleAdd}\n >\n {'Add org automation'}\n </Button>\n ) : null}\n </Stack>\n <Menu\n anchorEl={pauseMenu?.anchor ?? null}\n open={Boolean(pauseMenu)}\n onClose={() => setPauseMenu(null)}\n >\n {pauseMenu\n ? placedSiteIds(pauseMenu.row, mount)\n .filter(\n (hostId) =>\n !orgAutomationPausedHostIds(pauseMenu.row).includes(hostId),\n )\n .map((hostId) => (\n <MenuItem\n key={hostId}\n onClick={() => void setPaused(pauseMenu.row, hostId, true)}\n >\n {`Pause on ${orgSiteName(mount, hostId)}`}\n </MenuItem>\n ))\n : null}\n </Menu>\n <OrgAutomationEditor\n mount={mount}\n draft={draft}\n onDraft={(update) =>\n setDraft((previous) => (previous ? update(previous) : previous))\n }\n opened={editorOpened}\n saving={saving}\n onSave={() => void handleSave()}\n onClose={() => setDraft(null)}\n />\n </CardDisplay>\n )\n}\nOrgAutomationsCard.displayName = 'OrgAutomationsCard'\n\nexport default OrgAutomationsCard\n"],"names":["checkEntitlement","hostEventLabel","pluginDocsHelp","hostIdsFromScope","isOrgWideScope","CardDisplay","useConfirmationContext","ListPagination","TABLE_PAGE_SIZE_DEFAULT","useSnackbar","useFirestore","useFirestoreCollection","Alert","Button","Chip","Menu","MenuItem","Stack","Switch","Typography","collection","documentId","limit","orderBy","query","where","useCallback","useMemo","useState","ORG_AUTOMATIONS_COLLECTION","ORG_AUTOMATIONS_MAX","orgAutomationPausedHostIds","readOrgAutomation","newOrgAutomationDraft","OrgAutomationEditor","orgAutomationBody","orgAutomationDraft","useOrgAutomationsApi","orgSiteName","HOST_ACTION_STEP_LABELS","placedSiteIds","row","mount","visibleTo","hosts","map","host","id","placementLine","names","length","join","OrgAutomationsCard","props","org","canEdit","firestore","api","enqueueSnackbar","confirm","data","rows","orgId","idField","automations","slice","sort","a","b","String","name","localeCompare","page","setPage","pageSize","setPageSize","shown","draft","setDraft","editorOpened","setEditorOpened","saving","setSaving","pauseMenu","setPauseMenu","entitled","fail","error","message","variant","persist","handleAdd","handleSave","body","read","ok","problem","action","automationId","automation","handleToggle","event","$id","enabled","target","checked","handleDelete","confirmed","title","description","confirmationText","confirmationButtonProps","color","then","catch","setPaused","hostId","paused","header","help","anchor","contentGutterX","contentGutterY","spacing","placed","pausable","filter","includes","direction","sx","alignItems","size","disabled","onChange","slotProps","input","flex","minWidth","noWrap","trigger","steps","step","type","flexWrap","gap","label","onDelete","onClick","aria-haspopup","currentTarget","rowCount","count","onPageChange","onPageSizeChange","severity","alignSelf","anchorEl","open","Boolean","onClose","onDraft","update","previous","opened","onSave","displayName"],"mappings":"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"}
|
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
export interface RunQuotaLineProps {
|
|
2
|
-
|
|
2
|
+
/**
|
|
3
|
+
* The site the line sits on, or `null` on the organization's hub. Its own
|
|
4
|
+
* counter is read only when there is no workspace id to read the
|
|
5
|
+
* workspace's by.
|
|
6
|
+
*/
|
|
7
|
+
hostId: string | null;
|
|
8
|
+
/** The workspace whose runs are reported; defaults to the org doc's `$id`. */
|
|
9
|
+
orgId?: string | null;
|
|
3
10
|
/** The resolved org doc, from the plugin shell. */
|
|
4
11
|
org: unknown;
|
|
5
12
|
/** Which counter to report. */
|
|
@@ -16,9 +23,15 @@ export interface RunQuotaLineProps {
|
|
|
16
23
|
* returns early once `used + actions.length > limit`) was invisible on the
|
|
17
24
|
* page where a person is looking at their automations.
|
|
18
25
|
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
26
|
+
* The figure is the WORKSPACE's (AGL-3472): the band is the organization's,
|
|
27
|
+
* and the run gates hold it to every site's runs, counted at
|
|
28
|
+
* `orgs/{orgId}/counters/{counter}`. One site's own count against the whole
|
|
29
|
+
* band would read as headroom the gate has already spent elsewhere. Only a
|
|
30
|
+
* line with no workspace id falls back to the site's counter.
|
|
31
|
+
*
|
|
32
|
+
* Renders NOTHING while the counter or the plan is unresolved, or when the
|
|
33
|
+
* counter cannot be read. `0 runs this month` is what an unread counter looks
|
|
34
|
+
* like, and it is the one reading that makes a customer stop debugging.
|
|
22
35
|
*/
|
|
23
36
|
export declare function RunQuotaLine(props: RunQuotaLineProps): import("react").JSX.Element;
|
|
24
37
|
export declare namespace RunQuotaLine {
|
|
@@ -38,23 +38,32 @@ const COUNTER_LIMIT = {
|
|
|
38
38
|
* returns early once `used + actions.length > limit`) was invisible on the
|
|
39
39
|
* page where a person is looking at their automations.
|
|
40
40
|
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
*
|
|
41
|
+
* The figure is the WORKSPACE's (AGL-3472): the band is the organization's,
|
|
42
|
+
* and the run gates hold it to every site's runs, counted at
|
|
43
|
+
* `orgs/{orgId}/counters/{counter}`. One site's own count against the whole
|
|
44
|
+
* band would read as headroom the gate has already spent elsewhere. Only a
|
|
45
|
+
* line with no workspace id falls back to the site's counter.
|
|
46
|
+
*
|
|
47
|
+
* Renders NOTHING while the counter or the plan is unresolved, or when the
|
|
48
|
+
* counter cannot be read. `0 runs this month` is what an unread counter looks
|
|
49
|
+
* like, and it is the one reading that makes a customer stop debugging.
|
|
44
50
|
*/ export function RunQuotaLine(props) {
|
|
45
|
-
var _ref;
|
|
51
|
+
var _props_orgId, _ref;
|
|
46
52
|
var _resolveOrgEntitlements;
|
|
47
53
|
const { hostId, org, counter } = props;
|
|
48
54
|
const firestore = useFirestore();
|
|
49
55
|
const monthKey = new Date().toISOString().slice(0, 7);
|
|
50
|
-
const
|
|
56
|
+
const orgId = (_props_orgId = props.orgId) != null ? _props_orgId : org == null ? void 0 : org.$id;
|
|
57
|
+
const workspaceId = typeof orgId === 'string' && orgId ? orgId : null;
|
|
58
|
+
const { data: counterDoc, status } = useFirestoreDoc(()=>workspaceId ? doc(firestore, 'orgs', workspaceId, 'counters', counter) : hostId ? doc(firestore, 'hosts', hostId, 'counters', counter) : null, [
|
|
51
59
|
firestore,
|
|
60
|
+
workspaceId,
|
|
52
61
|
hostId,
|
|
53
62
|
counter
|
|
54
63
|
]);
|
|
55
|
-
// A
|
|
64
|
+
// A workspace that has never run one has no counter document; that is a
|
|
56
65
|
// settled zero, not a pending read.
|
|
57
|
-
if (status
|
|
66
|
+
if (status !== 'success') return null;
|
|
58
67
|
const limit = (_resolveOrgEntitlements = resolveOrgEntitlements(org)) == null ? void 0 : _resolveOrgEntitlements[COUNTER_LIMIT[counter]];
|
|
59
68
|
if (typeof limit !== 'number') return null;
|
|
60
69
|
const used = Number((_ref = counterDoc == null ? void 0 : counterDoc[monthKey]) != null ? _ref : 0);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../../libs/plugins/workflows/src/lib/components/run-quota-line.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 { isUnlimitedQuota, resolveOrgEntitlements } from '@aglyn/aglyn'\nimport { Typography } from '@mui/material'\nimport { doc } from 'firebase/firestore'\nimport {\n useFirestore,\n useFirestoreDoc,\n} from '@aglyn/tenant-feature-instance'\n\nexport interface RunQuotaLineProps {\n hostId: string\n /** The resolved org doc, from the plugin shell. */\n org: unknown\n /** Which counter to report. */\n counter: 'workflowRuns' | 'actionRuns'\n}\n\nconst COUNTER_LABEL = {\n workflowRuns: 'workflow runs',\n actionRuns: 'action runs',\n} as const\n\nconst COUNTER_LIMIT = {\n workflowRuns: 'workflowRunsPerMonth',\n actionRuns: 'actionRunsPerMonth',\n} as const\n\n/**\n * `1,284 runs this month · 500,000 included` (AGL-2171).\n *\n * `/product/workflows`'s run-history mockup puts this line opposite the\n * heading. The only place the product reported it was the Billing page, as\n * `1284 / 500000` — and `actionRunsPerMonth` had **no customer-facing\n * surface at all**, only the staff panel and the usage-alerts route. So\n * the quota that silently stops an automation from running (`runEventActions`\n * returns early once `used + actions.length > limit`) was invisible on the\n * page where a person is looking at their automations.\n *\n * Renders NOTHING while the counter or the plan is unresolved. `0 runs
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/plugins/workflows/src/lib/components/run-quota-line.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 { isUnlimitedQuota, resolveOrgEntitlements } from '@aglyn/aglyn'\nimport { Typography } from '@mui/material'\nimport { doc } from 'firebase/firestore'\nimport {\n useFirestore,\n useFirestoreDoc,\n} from '@aglyn/tenant-feature-instance'\n\nexport interface RunQuotaLineProps {\n /**\n * The site the line sits on, or `null` on the organization's hub. Its own\n * counter is read only when there is no workspace id to read the\n * workspace's by.\n */\n hostId: string | null\n /** The workspace whose runs are reported; defaults to the org doc's `$id`. */\n orgId?: string | null\n /** The resolved org doc, from the plugin shell. */\n org: unknown\n /** Which counter to report. */\n counter: 'workflowRuns' | 'actionRuns'\n}\n\nconst COUNTER_LABEL = {\n workflowRuns: 'workflow runs',\n actionRuns: 'action runs',\n} as const\n\nconst COUNTER_LIMIT = {\n workflowRuns: 'workflowRunsPerMonth',\n actionRuns: 'actionRunsPerMonth',\n} as const\n\n/**\n * `1,284 runs this month · 500,000 included` (AGL-2171).\n *\n * `/product/workflows`'s run-history mockup puts this line opposite the\n * heading. The only place the product reported it was the Billing page, as\n * `1284 / 500000` — and `actionRunsPerMonth` had **no customer-facing\n * surface at all**, only the staff panel and the usage-alerts route. So\n * the quota that silently stops an automation from running (`runEventActions`\n * returns early once `used + actions.length > limit`) was invisible on the\n * page where a person is looking at their automations.\n *\n * The figure is the WORKSPACE's (AGL-3472): the band is the organization's,\n * and the run gates hold it to every site's runs, counted at\n * `orgs/{orgId}/counters/{counter}`. One site's own count against the whole\n * band would read as headroom the gate has already spent elsewhere. Only a\n * line with no workspace id falls back to the site's counter.\n *\n * Renders NOTHING while the counter or the plan is unresolved, or when the\n * counter cannot be read. `0 runs this month` is what an unread counter looks\n * like, and it is the one reading that makes a customer stop debugging.\n */\nexport function RunQuotaLine(props: RunQuotaLineProps) {\n const { hostId, org, counter } = props\n const firestore = useFirestore()\n const monthKey = new Date().toISOString().slice(0, 7)\n const orgId =\n props.orgId ?? (org as { $id?: unknown } | null | undefined)?.$id\n const workspaceId = typeof orgId === 'string' && orgId ? orgId : null\n const { data: counterDoc, status } = useFirestoreDoc<Record<string, unknown>>(\n () =>\n workspaceId\n ? doc(firestore, 'orgs', workspaceId, 'counters', counter)\n : hostId\n ? doc(firestore, 'hosts', hostId, 'counters', counter)\n : null,\n [firestore, workspaceId, hostId, counter],\n )\n // A workspace that has never run one has no counter document; that is a\n // settled zero, not a pending read.\n if (status !== 'success') return null\n const limit = (\n resolveOrgEntitlements(org as never) as Record<string, unknown>\n )?.[COUNTER_LIMIT[counter]]\n if (typeof limit !== 'number') return null\n const used = Number(counterDoc?.[monthKey] ?? 0)\n // An unlimited band (an uncapped staff comp, AGL-3049) has no figure to\n // include: `Infinity.toLocaleString()` would print \"∞ included\".\n return (\n <Typography variant=\"caption\" color=\"text.secondary\">\n {`${used.toLocaleString()} ${COUNTER_LABEL[counter]} this month · ` +\n (isUnlimitedQuota(limit)\n ? 'no monthly limit'\n : `${limit.toLocaleString()} included`)}\n </Typography>\n )\n}\nRunQuotaLine.displayName = 'RunQuotaLine'\n\nexport default RunQuotaLine\n"],"names":["isUnlimitedQuota","resolveOrgEntitlements","Typography","doc","useFirestore","useFirestoreDoc","COUNTER_LABEL","workflowRuns","actionRuns","COUNTER_LIMIT","RunQuotaLine","props","hostId","org","counter","firestore","monthKey","Date","toISOString","slice","orgId","$id","workspaceId","data","counterDoc","status","limit","used","Number","variant","color","toLocaleString","displayName"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GACD;;AAEA,SAASA,gBAAgB,EAAEC,sBAAsB,QAAQ,eAAc;AACvE,SAASC,UAAU,QAAQ,gBAAe;AAC1C,SAASC,GAAG,QAAQ,qBAAoB;AACxC,SACEC,YAAY,EACZC,eAAe,QACV,iCAAgC;AAiBvC,MAAMC,gBAAgB;IACpBC,cAAc;IACdC,YAAY;AACd;AAEA,MAAMC,gBAAgB;IACpBF,cAAc;IACdC,YAAY;AACd;AAEA;;;;;;;;;;;;;;;;;;;;CAoBC,GACD,OAAO,SAASE,aAAaC,KAAwB;QAKjDA;QAeAV;IAnBF,MAAM,EAAEW,MAAM,EAAEC,GAAG,EAAEC,OAAO,EAAE,GAAGH;IACjC,MAAMI,YAAYX;IAClB,MAAMY,WAAW,IAAIC,OAAOC,WAAW,GAAGC,KAAK,CAAC,GAAG;IACnD,MAAMC,SACJT,eAAAA,MAAMS,KAAK,YAAXT,eAAgBE,uBAAD,AAACA,IAA8CQ,GAAG;IACnE,MAAMC,cAAc,OAAOF,UAAU,YAAYA,QAAQA,QAAQ;IACjE,MAAM,EAAEG,MAAMC,UAAU,EAAEC,MAAM,EAAE,GAAGpB,gBACnC,IACEiB,cACInB,IAAIY,WAAW,QAAQO,aAAa,YAAYR,WAChDF,SACET,IAAIY,WAAW,SAASH,QAAQ,YAAYE,WAC5C,MACR;QAACC;QAAWO;QAAaV;QAAQE;KAAQ;IAE3C,wEAAwE;IACxE,oCAAoC;IACpC,IAAIW,WAAW,WAAW,OAAO;IACjC,MAAMC,SACJzB,0BAAAA,uBAAuBY,yBADX,AACZZ,uBACC,CAACQ,aAAa,CAACK,QAAQ,CAAC;IAC3B,IAAI,OAAOY,UAAU,UAAU,OAAO;IACtC,MAAMC,OAAOC,eAAOJ,8BAAAA,UAAY,CAACR,SAAS,mBAAI;IAC9C,wEAAwE;IACxE,iEAAiE;IACjE,qBACE,KAACd;QAAW2B,SAAQ;QAAUC,OAAM;kBACjC,GAAGH,KAAKI,cAAc,GAAG,CAAC,EAAEzB,aAAa,CAACQ,QAAQ,CAAC,cAAc,CAAC,GAChEd,CAAAA,iBAAiB0B,SACd,qBACA,GAAGA,MAAMK,cAAc,GAAG,SAAS,CAAC,AAAD;;AAG/C;AACArB,aAAasB,WAAW,GAAG;AAE3B,eAAetB,aAAY"}
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
* limitations under the License.
|
|
16
16
|
*/ 'use client';
|
|
17
17
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
18
|
-
import {
|
|
18
|
+
import { hostEventLabel, pluginDocsHelp, scopeTokensForHost } from "@aglyn/aglyn";
|
|
19
19
|
import { CardDisplay } from "@aglyn/shared-ui-jsx";
|
|
20
20
|
import { useSnackbar } from "@aglyn/shared-ui-snackstack";
|
|
21
21
|
import { useFirestore, useFirestoreCollection, useOrgDataScope } from "@aglyn/tenant-feature-instance";
|
|
@@ -25,6 +25,7 @@ import { useCallback, useMemo, useState } from "react";
|
|
|
25
25
|
import { ORG_AUTOMATIONS_COLLECTION, ORG_AUTOMATIONS_MAX, orgAutomationPausedHostIds } from "../model/org-automations.js";
|
|
26
26
|
import HostRunHistoryCard from "./host-run-history-card.component.js";
|
|
27
27
|
import { useOrgAutomationsApi } from "./use-org-automations-api.js";
|
|
28
|
+
import { HOST_ACTION_STEP_LABELS } from "../model/host-actions.js";
|
|
28
29
|
/**
|
|
29
30
|
* THE ORGANIZATION'S AUTOMATIONS THAT RUN ON THIS SITE (AGL-3302), on the
|
|
30
31
|
* site's own Actions section: read-only, with the one control that belongs
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../../libs/plugins/workflows/src/lib/components/site-org-automations-panel.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 HOST_ACTION_STEP_LABELS,\n type HostActionStepType,\n hostEventLabel,\n pluginDocsHelp,\n scopeTokensForHost,\n} from '@aglyn/aglyn'\nimport { CardDisplay } from '@aglyn/shared-ui-jsx'\nimport { useSnackbar } from '@aglyn/shared-ui-snackstack'\nimport {\n useFirestore,\n useFirestoreCollection,\n useOrgDataScope,\n} from '@aglyn/tenant-feature-instance'\nimport {\n Button,\n Chip,\n Dialog,\n DialogActions,\n DialogContent,\n DialogTitle,\n Stack,\n Typography,\n} from '@mui/material'\nimport { collection, limit, query, where } from 'firebase/firestore'\nimport { useCallback, useMemo, useState } from 'react'\nimport {\n ORG_AUTOMATIONS_COLLECTION,\n ORG_AUTOMATIONS_MAX,\n orgAutomationPausedHostIds,\n type OrgAutomationRow,\n} from '../model/org-automations'\nimport HostRunHistoryCard from './host-run-history-card.component'\nimport { useOrgAutomationsApi } from './use-org-automations-api'\n\n/**\n * THE ORGANIZATION'S AUTOMATIONS THAT RUN ON THIS SITE (AGL-3302), on the\n * site's own Actions section: read-only, with the one control that belongs\n * to the site — pausing an automation here, and resuming it.\n *\n * Read with the site's own scope tokens, so the listener is provable for a\n * collaborator scoped to this site as well as for an org-wide member, and\n * only the live ones placed here come back. Editing is the organization's,\n * on its own hub; a pause is the site's, through `automations/pause`, which\n * admits the site's admins and editors and refuses anyone else with its own\n * words.\n *\n * Renders nothing while there is nothing: a site the organization runs no\n * automation on has no panel to explain.\n */\nexport function SiteOrgAutomationsPanel(props: { hostId: string }) {\n const { hostId } = props\n const firestore = useFirestore()\n const api = useOrgAutomationsApi()\n const { enqueueSnackbar } = useSnackbar()\n const { scope } = useOrgDataScope({ hostId })\n const tokens = useMemo(() => scopeTokensForHost(hostId), [hostId])\n const { data: rows } = useFirestoreCollection<OrgAutomationRow>(\n () =>\n scope\n ? query(\n collection(firestore, scope[0], scope[1], ORG_AUTOMATIONS_COLLECTION),\n where('deletedAt', '==', null),\n where('visibleTo', 'array-contains-any', tokens),\n limit(ORG_AUTOMATIONS_MAX + 1),\n )\n : null,\n [firestore, scope, tokens],\n { idField: '$id' },\n )\n const automations = useMemo(\n () =>\n [...(rows ?? [])].sort((a, b) =>\n String(a.name ?? '').localeCompare(String(b.name ?? '')),\n ),\n [rows],\n )\n const [busy, setBusy] = useState<string | null>(null)\n const [runsFor, setRunsFor] = useState<OrgAutomationRow | null>(null)\n\n const setPaused = useCallback(\n async (row: OrgAutomationRow, paused: boolean) => {\n setBusy(row.$id)\n try {\n await api('pause', { hostId, automationId: row.$id, paused })\n enqueueSnackbar(\n paused\n ? `“${row.name}” is paused on this site`\n : `“${row.name}” runs on this site again`,\n { variant: 'success', persist: false },\n )\n } catch (error) {\n enqueueSnackbar(\n (error as Error)?.message || 'The request could not be completed',\n { variant: 'warning', persist: false },\n )\n } finally {\n setBusy(null)\n }\n },\n [api, hostId, enqueueSnackbar],\n )\n\n if (!automations.length) return null\n return (\n <CardDisplay\n header={'Org automations on this site'}\n help={pluginDocsHelp('orgAutomations', { anchor: '#pause-it-on-one-site' })}\n contentGutterX\n contentGutterY\n >\n <Stack spacing={1}>\n <Typography variant=\"body2\" color=\"text.secondary\">\n {'Your organization runs these on this site beside the site’s own ' +\n 'actions. Each run sends from this site and counts on its action ' +\n 'runs. Pausing one stops it here — and anyone waiting inside it ' +\n 'here — and leaves every other site alone.'}\n </Typography>\n {automations.map((row) => {\n const paused = orgAutomationPausedHostIds(row).includes(hostId)\n const off = row.enabled === false\n return (\n <Stack\n key={row.$id}\n direction=\"row\"\n spacing={1}\n sx={{ alignItems: 'center' }}\n >\n <Stack sx={{ flex: 1, minWidth: 0 }}>\n <Typography variant=\"body2\" noWrap>\n {row.name}\n </Typography>\n <Typography variant=\"caption\" color=\"text.secondary\" noWrap>\n {`on ${hostEventLabel(row.trigger?.event)} · ${(row.steps ?? [])\n .map(\n (step) =>\n HOST_ACTION_STEP_LABELS[step.type as HostActionStepType] ??\n step.type,\n )\n .join(' → ')}`}\n </Typography>\n </Stack>\n <Chip\n size=\"small\"\n variant=\"outlined\"\n color={off ? 'default' : paused ? 'warning' : 'success'}\n label={off ? 'Switched off' : paused ? 'Paused here' : 'Runs here'}\n />\n <Button\n size=\"small\"\n disabled={busy === row.$id}\n onClick={() => void setPaused(row, !paused)}\n >\n {paused ? 'Resume here' : 'Pause here'}\n </Button>\n <Button size=\"small\" onClick={() => setRunsFor(row)}>\n {'Runs'}\n </Button>\n </Stack>\n )\n })}\n </Stack>\n <Dialog\n open={Boolean(runsFor)}\n onClose={() => setRunsFor(null)}\n // md: the history's four columns fit without the table scrolling.\n maxWidth=\"md\"\n fullWidth\n >\n <DialogTitle>{`Runs — ${runsFor?.name ?? ''}`}</DialogTitle>\n <DialogContent>\n {runsFor ? (\n <HostRunHistoryCard\n hostId={hostId}\n targetId={runsFor.$id}\n targetName={runsFor.name ?? ''}\n header=\"Recent runs on this site\"\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}\nSiteOrgAutomationsPanel.displayName = 'SiteOrgAutomationsPanel'\n\nexport default SiteOrgAutomationsPanel\n"],"names":["HOST_ACTION_STEP_LABELS","hostEventLabel","pluginDocsHelp","scopeTokensForHost","CardDisplay","useSnackbar","useFirestore","useFirestoreCollection","useOrgDataScope","Button","Chip","Dialog","DialogActions","DialogContent","DialogTitle","Stack","Typography","collection","limit","query","where","useCallback","useMemo","useState","ORG_AUTOMATIONS_COLLECTION","ORG_AUTOMATIONS_MAX","orgAutomationPausedHostIds","HostRunHistoryCard","useOrgAutomationsApi","SiteOrgAutomationsPanel","props","runsFor","hostId","firestore","api","enqueueSnackbar","scope","tokens","data","rows","idField","automations","sort","a","b","String","name","localeCompare","busy","setBusy","setRunsFor","setPaused","row","paused","$id","automationId","variant","persist","error","message","length","header","help","anchor","contentGutterX","contentGutterY","spacing","color","map","includes","off","enabled","direction","sx","alignItems","flex","minWidth","noWrap","trigger","event","steps","step","type","join","size","label","disabled","onClick","open","Boolean","onClose","maxWidth","fullWidth","targetId","targetName","displayName"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/plugins/workflows/src/lib/components/site-org-automations-panel.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 { hostEventLabel, pluginDocsHelp, scopeTokensForHost } from '@aglyn/aglyn'\nimport { CardDisplay } from '@aglyn/shared-ui-jsx'\nimport { useSnackbar } from '@aglyn/shared-ui-snackstack'\nimport {\n useFirestore,\n useFirestoreCollection,\n useOrgDataScope,\n} from '@aglyn/tenant-feature-instance'\nimport {\n Button,\n Chip,\n Dialog,\n DialogActions,\n DialogContent,\n DialogTitle,\n Stack,\n Typography,\n} from '@mui/material'\nimport { collection, limit, query, where } from 'firebase/firestore'\nimport { useCallback, useMemo, useState } from 'react'\nimport {\n ORG_AUTOMATIONS_COLLECTION,\n ORG_AUTOMATIONS_MAX,\n orgAutomationPausedHostIds,\n type OrgAutomationRow,\n} from '../model/org-automations'\nimport HostRunHistoryCard from './host-run-history-card.component'\nimport { useOrgAutomationsApi } from './use-org-automations-api'\nimport { HOST_ACTION_STEP_LABELS, type HostActionStepType } from '../model/host-actions'\n\n/**\n * THE ORGANIZATION'S AUTOMATIONS THAT RUN ON THIS SITE (AGL-3302), on the\n * site's own Actions section: read-only, with the one control that belongs\n * to the site — pausing an automation here, and resuming it.\n *\n * Read with the site's own scope tokens, so the listener is provable for a\n * collaborator scoped to this site as well as for an org-wide member, and\n * only the live ones placed here come back. Editing is the organization's,\n * on its own hub; a pause is the site's, through `automations/pause`, which\n * admits the site's admins and editors and refuses anyone else with its own\n * words.\n *\n * Renders nothing while there is nothing: a site the organization runs no\n * automation on has no panel to explain.\n */\nexport function SiteOrgAutomationsPanel(props: { hostId: string }) {\n const { hostId } = props\n const firestore = useFirestore()\n const api = useOrgAutomationsApi()\n const { enqueueSnackbar } = useSnackbar()\n const { scope } = useOrgDataScope({ hostId })\n const tokens = useMemo(() => scopeTokensForHost(hostId), [hostId])\n const { data: rows } = useFirestoreCollection<OrgAutomationRow>(\n () =>\n scope\n ? query(\n collection(firestore, scope[0], scope[1], ORG_AUTOMATIONS_COLLECTION),\n where('deletedAt', '==', null),\n where('visibleTo', 'array-contains-any', tokens),\n limit(ORG_AUTOMATIONS_MAX + 1),\n )\n : null,\n [firestore, scope, tokens],\n { idField: '$id' },\n )\n const automations = useMemo(\n () =>\n [...(rows ?? [])].sort((a, b) =>\n String(a.name ?? '').localeCompare(String(b.name ?? '')),\n ),\n [rows],\n )\n const [busy, setBusy] = useState<string | null>(null)\n const [runsFor, setRunsFor] = useState<OrgAutomationRow | null>(null)\n\n const setPaused = useCallback(\n async (row: OrgAutomationRow, paused: boolean) => {\n setBusy(row.$id)\n try {\n await api('pause', { hostId, automationId: row.$id, paused })\n enqueueSnackbar(\n paused\n ? `“${row.name}” is paused on this site`\n : `“${row.name}” runs on this site again`,\n { variant: 'success', persist: false },\n )\n } catch (error) {\n enqueueSnackbar(\n (error as Error)?.message || 'The request could not be completed',\n { variant: 'warning', persist: false },\n )\n } finally {\n setBusy(null)\n }\n },\n [api, hostId, enqueueSnackbar],\n )\n\n if (!automations.length) return null\n return (\n <CardDisplay\n header={'Org automations on this site'}\n help={pluginDocsHelp('orgAutomations', { anchor: '#pause-it-on-one-site' })}\n contentGutterX\n contentGutterY\n >\n <Stack spacing={1}>\n <Typography variant=\"body2\" color=\"text.secondary\">\n {'Your organization runs these on this site beside the site’s own ' +\n 'actions. Each run sends from this site and counts on its action ' +\n 'runs. Pausing one stops it here — and anyone waiting inside it ' +\n 'here — and leaves every other site alone.'}\n </Typography>\n {automations.map((row) => {\n const paused = orgAutomationPausedHostIds(row).includes(hostId)\n const off = row.enabled === false\n return (\n <Stack\n key={row.$id}\n direction=\"row\"\n spacing={1}\n sx={{ alignItems: 'center' }}\n >\n <Stack sx={{ flex: 1, minWidth: 0 }}>\n <Typography variant=\"body2\" noWrap>\n {row.name}\n </Typography>\n <Typography variant=\"caption\" color=\"text.secondary\" noWrap>\n {`on ${hostEventLabel(row.trigger?.event)} · ${(row.steps ?? [])\n .map(\n (step) =>\n HOST_ACTION_STEP_LABELS[step.type as HostActionStepType] ??\n step.type,\n )\n .join(' → ')}`}\n </Typography>\n </Stack>\n <Chip\n size=\"small\"\n variant=\"outlined\"\n color={off ? 'default' : paused ? 'warning' : 'success'}\n label={off ? 'Switched off' : paused ? 'Paused here' : 'Runs here'}\n />\n <Button\n size=\"small\"\n disabled={busy === row.$id}\n onClick={() => void setPaused(row, !paused)}\n >\n {paused ? 'Resume here' : 'Pause here'}\n </Button>\n <Button size=\"small\" onClick={() => setRunsFor(row)}>\n {'Runs'}\n </Button>\n </Stack>\n )\n })}\n </Stack>\n <Dialog\n open={Boolean(runsFor)}\n onClose={() => setRunsFor(null)}\n // md: the history's four columns fit without the table scrolling.\n maxWidth=\"md\"\n fullWidth\n >\n <DialogTitle>{`Runs — ${runsFor?.name ?? ''}`}</DialogTitle>\n <DialogContent>\n {runsFor ? (\n <HostRunHistoryCard\n hostId={hostId}\n targetId={runsFor.$id}\n targetName={runsFor.name ?? ''}\n header=\"Recent runs on this site\"\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}\nSiteOrgAutomationsPanel.displayName = 'SiteOrgAutomationsPanel'\n\nexport default SiteOrgAutomationsPanel\n"],"names":["hostEventLabel","pluginDocsHelp","scopeTokensForHost","CardDisplay","useSnackbar","useFirestore","useFirestoreCollection","useOrgDataScope","Button","Chip","Dialog","DialogActions","DialogContent","DialogTitle","Stack","Typography","collection","limit","query","where","useCallback","useMemo","useState","ORG_AUTOMATIONS_COLLECTION","ORG_AUTOMATIONS_MAX","orgAutomationPausedHostIds","HostRunHistoryCard","useOrgAutomationsApi","HOST_ACTION_STEP_LABELS","SiteOrgAutomationsPanel","props","runsFor","hostId","firestore","api","enqueueSnackbar","scope","tokens","data","rows","idField","automations","sort","a","b","String","name","localeCompare","busy","setBusy","setRunsFor","setPaused","row","paused","$id","automationId","variant","persist","error","message","length","header","help","anchor","contentGutterX","contentGutterY","spacing","color","map","includes","off","enabled","direction","sx","alignItems","flex","minWidth","noWrap","trigger","event","steps","step","type","join","size","label","disabled","onClick","open","Boolean","onClose","maxWidth","fullWidth","targetId","targetName","displayName"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GACD;;AAEA,SAASA,cAAc,EAAEC,cAAc,EAAEC,kBAAkB,QAAQ,eAAc;AACjF,SAASC,WAAW,QAAQ,uBAAsB;AAClD,SAASC,WAAW,QAAQ,8BAA6B;AACzD,SACEC,YAAY,EACZC,sBAAsB,EACtBC,eAAe,QACV,iCAAgC;AACvC,SACEC,MAAM,EACNC,IAAI,EACJC,MAAM,EACNC,aAAa,EACbC,aAAa,EACbC,WAAW,EACXC,KAAK,EACLC,UAAU,QACL,gBAAe;AACtB,SAASC,UAAU,EAAEC,KAAK,EAAEC,KAAK,EAAEC,KAAK,QAAQ,qBAAoB;AACpE,SAASC,WAAW,EAAEC,OAAO,EAAEC,QAAQ,QAAQ,QAAO;AACtD,SACEC,0BAA0B,EAC1BC,mBAAmB,EACnBC,0BAA0B,QAErB,8BAA0B;AACjC,OAAOC,wBAAwB,uCAAmC;AAClE,SAASC,oBAAoB,QAAQ,+BAA2B;AAChE,SAASC,uBAAuB,QAAiC,2BAAuB;AAExF;;;;;;;;;;;;;;CAcC,GACD,OAAO,SAASC,wBAAwBC,KAAyB;cA6HvCC;IA5HxB,MAAM,EAAEC,MAAM,EAAE,GAAGF;IACnB,MAAMG,YAAY5B;IAClB,MAAM6B,MAAMP;IACZ,MAAM,EAAEQ,eAAe,EAAE,GAAG/B;IAC5B,MAAM,EAAEgC,KAAK,EAAE,GAAG7B,gBAAgB;QAAEyB;IAAO;IAC3C,MAAMK,SAAShB,QAAQ,IAAMnB,mBAAmB8B,SAAS;QAACA;KAAO;IACjE,MAAM,EAAEM,MAAMC,IAAI,EAAE,GAAGjC,uBACrB,IACE8B,QACIlB,MACEF,WAAWiB,WAAWG,KAAK,CAAC,EAAE,EAAEA,KAAK,CAAC,EAAE,EAAEb,6BAC1CJ,MAAM,aAAa,MAAM,OACzBA,MAAM,aAAa,sBAAsBkB,SACzCpB,MAAMO,sBAAsB,MAE9B,MACN;QAACS;QAAWG;QAAOC;KAAO,EAC1B;QAAEG,SAAS;IAAM;IAEnB,MAAMC,cAAcpB,QAClB,IACE;eAAKkB,eAAAA,OAAQ,EAAE;SAAE,CAACG,IAAI,CAAC,CAACC,GAAGC;gBAClBD,SAAmCC;mBAA1CC,QAAOF,UAAAA,EAAEG,IAAI,YAANH,UAAU,IAAII,aAAa,CAACF,QAAOD,UAAAA,EAAEE,IAAI,YAANF,UAAU;YAExD;QAACL;KAAK;IAER,MAAM,CAACS,MAAMC,QAAQ,GAAG3B,SAAwB;IAChD,MAAM,CAACS,SAASmB,WAAW,GAAG5B,SAAkC;IAEhE,MAAM6B,YAAY/B,YAChB,OAAOgC,KAAuBC;QAC5BJ,QAAQG,IAAIE,GAAG;QACf,IAAI;YACF,MAAMpB,IAAI,SAAS;gBAAEF;gBAAQuB,cAAcH,IAAIE,GAAG;gBAAED;YAAO;YAC3DlB,gBACEkB,SACI,CAAC,CAAC,EAAED,IAAIN,IAAI,CAAC,wBAAwB,CAAC,GACtC,CAAC,CAAC,EAAEM,IAAIN,IAAI,CAAC,yBAAyB,CAAC,EAC3C;gBAAEU,SAAS;gBAAWC,SAAS;YAAM;QAEzC,EAAE,OAAOC,OAAO;YACdvB,gBACE,CAACuB,yBAAD,AAACA,MAAiBC,OAAO,KAAI,sCAC7B;gBAAEH,SAAS;gBAAWC,SAAS;YAAM;QAEzC,SAAU;YACRR,QAAQ;QACV;IACF,GACA;QAACf;QAAKF;QAAQG;KAAgB;IAGhC,IAAI,CAACM,YAAYmB,MAAM,EAAE,OAAO;IAChC,qBACE,MAACzD;QACC0D,QAAQ;QACRC,MAAM7D,eAAe,kBAAkB;YAAE8D,QAAQ;QAAwB;QACzEC,cAAc;QACdC,cAAc;;0BAEd,MAACnD;gBAAMoD,SAAS;;kCACd,KAACnD;wBAAWyC,SAAQ;wBAAQW,OAAM;kCAC/B,qEACC,qEACA,oEACA;;oBAEH1B,YAAY2B,GAAG,CAAC,CAAChB;4BAewCA;4BAA1BA;wBAd9B,MAAMC,SAAS5B,2BAA2B2B,KAAKiB,QAAQ,CAACrC;wBACxD,MAAMsC,MAAMlB,IAAImB,OAAO,KAAK;wBAC5B,qBACE,MAACzD;4BAEC0D,WAAU;4BACVN,SAAS;4BACTO,IAAI;gCAAEC,YAAY;4BAAS;;8CAE3B,MAAC5D;oCAAM2D,IAAI;wCAAEE,MAAM;wCAAGC,UAAU;oCAAE;;sDAChC,KAAC7D;4CAAWyC,SAAQ;4CAAQqB,MAAM;sDAC/BzB,IAAIN,IAAI;;sDAEX,KAAC/B;4CAAWyC,SAAQ;4CAAUW,OAAM;4CAAiBU,MAAM;sDACxD,CAAC,GAAG,EAAE7E,gBAAeoD,eAAAA,IAAI0B,OAAO,qBAAX1B,aAAa2B,KAAK,EAAE,GAAG,EAAE,EAAC3B,aAAAA,IAAI4B,KAAK,YAAT5B,aAAa,EAAE,EAC5DgB,GAAG,CACF,CAACa;oDACCrD;wDAAAA,qCAAAA,uBAAuB,CAACqD,KAAKC,IAAI,CAAuB,YAAxDtD,qCACAqD,KAAKC,IAAI;+CAEZC,IAAI,CAAC,QAAQ;;;;8CAGpB,KAAC1E;oCACC2E,MAAK;oCACL5B,SAAQ;oCACRW,OAAOG,MAAM,YAAYjB,SAAS,YAAY;oCAC9CgC,OAAOf,MAAM,iBAAiBjB,SAAS,gBAAgB;;8CAEzD,KAAC7C;oCACC4E,MAAK;oCACLE,UAAUtC,SAASI,IAAIE,GAAG;oCAC1BiC,SAAS,IAAM,KAAKpC,UAAUC,KAAK,CAACC;8CAEnCA,SAAS,gBAAgB;;8CAE5B,KAAC7C;oCAAO4E,MAAK;oCAAQG,SAAS,IAAMrC,WAAWE;8CAC5C;;;2BAjCEA,IAAIE,GAAG;oBAqClB;;;0BAEF,MAAC5C;gBACC8E,MAAMC,QAAQ1D;gBACd2D,SAAS,IAAMxC,WAAW;gBAC1B,kEAAkE;gBAClEyC,UAAS;gBACTC,SAAS;;kCAET,KAAC/E;kCAAa,CAAC,OAAO,UAAEkB,2BAAAA,QAASe,IAAI,mBAAI,IAAI;;kCAC7C,KAAClC;kCACEmB,wBACC,KAACL;4BACCM,QAAQA;4BACR6D,UAAU9D,QAAQuB,GAAG;4BACrBwC,UAAU,GAAE/D,gBAAAA,QAAQe,IAAI,YAAZf,gBAAgB;4BAC5B8B,QAAO;6BAEP;;kCAEN,KAAClD;kCACC,cAAA,KAACH;4BAAO2D,OAAM;4BAAUoB,SAAS,IAAMrC,WAAW;sCAC/C;;;;;;;AAMb;AACArB,wBAAwBkE,WAAW,GAAG;AAEtC,eAAelE,wBAAuB"}
|
|
@@ -88,9 +88,9 @@ import { workflowsOrgMount } from "./workflows-org-mount.js";
|
|
|
88
88
|
* and every site's own workflows, actions and webhooks listed with the site
|
|
89
89
|
* each belongs to.
|
|
90
90
|
*
|
|
91
|
-
*
|
|
92
|
-
*
|
|
93
|
-
*
|
|
91
|
+
* The run allowance line heads the workflows and actions lists here too: the
|
|
92
|
+
* allowance is the workspace's (AGL-3472), every site's runs spend it, and
|
|
93
|
+
* this is the page that lists them all.
|
|
94
94
|
*/ function orgSectionBody(section, mount, org, canEdit) {
|
|
95
95
|
switch(section){
|
|
96
96
|
case 'automations':
|
|
@@ -101,10 +101,21 @@ import { workflowsOrgMount } from "./workflows-org-mount.js";
|
|
|
101
101
|
});
|
|
102
102
|
case 'workflows':
|
|
103
103
|
case 'actions':
|
|
104
|
-
return /*#__PURE__*/
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
104
|
+
return /*#__PURE__*/ _jsxs(Stack, {
|
|
105
|
+
spacing: 1,
|
|
106
|
+
children: [
|
|
107
|
+
/*#__PURE__*/ _jsx(RunQuotaLine, {
|
|
108
|
+
hostId: null,
|
|
109
|
+
orgId: mount.orgId,
|
|
110
|
+
org: org,
|
|
111
|
+
counter: section === 'workflows' ? 'workflowRuns' : 'actionRuns'
|
|
112
|
+
}),
|
|
113
|
+
/*#__PURE__*/ _jsx(OrgSiteAutomationList, {
|
|
114
|
+
mount: mount,
|
|
115
|
+
kind: section,
|
|
116
|
+
canRead: true
|
|
117
|
+
})
|
|
118
|
+
]
|
|
108
119
|
});
|
|
109
120
|
case 'webhooks':
|
|
110
121
|
// A webhook holds its site's secret: the rules admit a site's admins
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../../libs/plugins/workflows/src/lib/components/workflows-console-page.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 type { AglynOrgBilling, ConsolePluginPageProps } from '@aglyn/aglyn'\nimport { HubSections } from '@aglyn/shared-ui-next'\nimport { Stack } from '@mui/material'\nimport { useMemo, type ReactNode } from 'react'\nimport HostActionsCard from './host-actions-card.component'\nimport HostWebhooksCard from './host-webhooks-card.component'\nimport HostWorkflowsCard from './host-workflows-card.component'\nimport OrgAutomationsCard from './org-automations-card.component'\nimport OrgSiteAutomationList from './org-site-automation-list.component'\nimport RunQuotaLine from './run-quota-line.component'\nimport SiteOrgAutomationsPanel from './site-org-automations-panel.component'\nimport type { WorkflowsConsoleSectionId } from './workflows-console-sections'\nimport {\n workflowsOrgMount,\n type WorkflowsOrgMount,\n} from './workflows-org-mount'\n\n/**\n * The body of one workflows section, built only when that section is the one\n * being read (AGL-2501).\n *\n * A function rather than a map of nodes on purpose: a `Record<id, ReactNode>`\n * would CONSTRUCT all three every render, and each card opens its Firestore\n * listens on mount — which is the entire cost this page exists to stop paying.\n * Only the returned branch is ever built.\n */\nfunction sectionBody(\n section: WorkflowsConsoleSectionId,\n hostId: string,\n org: Partial<AglynOrgBilling> | undefined,\n): ReactNode {\n switch (section) {\n case 'workflows':\n return (\n /*\n * `N runs this month · M included` (AGL-2171), which the run-history\n * mockup puts opposite the heading. The quota silently stops\n * automations running once it is reached, and the only place it was\n * reported was the Billing page.\n */\n <Stack spacing={1}>\n <RunQuotaLine hostId={hostId} org={org} counter=\"workflowRuns\" />\n <HostWorkflowsCard hostId={hostId} org={org} />\n </Stack>\n )\n case 'actions':\n return (\n <Stack spacing={1}>\n {/* `actionRunsPerMonth` had NO customer-facing surface at all\n before this — staff panel and usage-alerts only. */}\n <RunQuotaLine hostId={hostId} org={org} counter=\"actionRuns\" />\n <HostActionsCard hostId={hostId} org={org} />\n {/* What the organization runs on this site beside the site's own\n actions, and the site's pause for each (AGL-3302). */}\n <SiteOrgAutomationsPanel hostId={hostId} />\n </Stack>\n )\n case 'webhooks':\n return <HostWebhooksCard hostId={hostId} org={org} />\n default:\n return null\n }\n}\n\n/**\n * The body of one ORGANIZATION-level section (AGL-3302): the org automations,\n * and every site's own workflows, actions and webhooks listed with the site\n * each belongs to.\n *\n * No run allowance line: the allowance is each site's, and an org\n * automation's runs count on the site they run on — each site's own\n * Automation reports its meter.\n */\nfunction orgSectionBody(\n section: WorkflowsConsoleSectionId,\n mount: WorkflowsOrgMount,\n org: Partial<AglynOrgBilling> | undefined,\n canEdit: boolean,\n): ReactNode {\n switch (section) {\n case 'automations':\n return <OrgAutomationsCard mount={mount} org={org} canEdit={canEdit} />\n case 'workflows':\n case 'actions':\n return <OrgSiteAutomationList mount={mount} kind={section} canRead />\n case 'webhooks':\n // A webhook holds its site's secret: the rules admit a site's admins\n // and editors, which every org-wide member but a viewer is.\n return (\n <OrgSiteAutomationList mount={mount} kind=\"webhooks\" canRead={canEdit} />\n )\n default:\n return null\n }\n}\n\n/**\n * Automation page (AGL-101/148/149 → AGL-395): the automation surface —\n * workflow builder, event-triggered actions, and webhooks — owned by the\n * workflows plugin and rendered by the shell's generic plugin route. Each card\n * runs its own entitlement check (workflows / actions / webhooks are distinct\n * plan flags), so the shell's resolved `org` doc flows into all three.\n *\n * Sections are ROUTES (AGL-2501). `HubTabs lazy` already mounted one panel, so\n * this is not a read saving — `workflows-console-read-cost.spec.tsx` was\n * written BEFORE the conversion precisely to hold that line, and reports the\n * same counts after. What routing adds is that the URL names the section: it is\n * linkable, the back button walks sections, the breadcrumb says where you are,\n * and \"mount only what is open\" is structural rather than a `lazy` flag.\n *\n * The section ids are unchanged by the Automation rename: they are the\n * addresses people bookmark and the docs link to. A workflow belongs to the\n * site and an ACTION belongs to the site too; an interaction belongs to the\n * document that holds it and is edited on the element, not here.\n */\nexport function WorkflowsConsolePage(props: ConsolePluginPageProps) {\n const { hostId, orgMount, org, permissions, section, sections, basePath } =\n props\n /*\n * Mounted with no site: the organization's hub (AGL-3302). Memoised so the\n * cards below, which key their listeners on the mount's org, see one object.\n */\n const mount = useMemo(\n () => (hostId == null ? workflowsOrgMount(orgMount, basePath) : null),\n [hostId, orgMount, basePath],\n )\n\n /*\n * Nothing until the URL names a section. The shell redirects a bare hub URL\n * to the landing section and holds a spinner while it does, so this state is\n * transient — and rendering a default section here instead would pay for its\n * listens on a URL that is already being replaced.\n */\n if (!section || !sections?.length || !basePath) return null\n\n if (hostId == null) {\n // No site and no org to stand in for it: nothing this page can scope.\n if (!mount) return null\n return (\n <HubSections sections={sections}>\n {orgSectionBody(\n section as WorkflowsConsoleSectionId,\n mount,\n org,\n // An org viewer's `editHosts` is false; every other org role's is\n // true. The server routes decide — this keeps a viewer from being\n // offered controls that are about to refuse them.\n permissions?.editHosts !== false,\n )}\n </HubSections>\n )\n }\n\n return (\n <HubSections sections={sections}>\n {sectionBody(section as WorkflowsConsoleSectionId, hostId, org)}\n </HubSections>\n )\n}\nWorkflowsConsolePage.displayName = 'WorkflowsConsolePage'\n\nexport default WorkflowsConsolePage\n"],"names":["HubSections","Stack","useMemo","HostActionsCard","HostWebhooksCard","HostWorkflowsCard","OrgAutomationsCard","OrgSiteAutomationList","RunQuotaLine","SiteOrgAutomationsPanel","workflowsOrgMount","sectionBody","section","hostId","org","spacing","counter","orgSectionBody","mount","canEdit","kind","canRead","WorkflowsConsolePage","props","orgMount","permissions","sections","basePath","length","editHosts","displayName"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GACD;;AAGA,SAASA,WAAW,QAAQ,wBAAuB;AACnD,SAASC,KAAK,QAAQ,gBAAe;AACrC,SAASC,OAAO,QAAwB,QAAO;AAC/C,OAAOC,qBAAqB,mCAA+B;AAC3D,OAAOC,sBAAsB,oCAAgC;AAC7D,OAAOC,uBAAuB,qCAAiC;AAC/D,OAAOC,wBAAwB,sCAAkC;AACjE,OAAOC,2BAA2B,0CAAsC;AACxE,OAAOC,kBAAkB,gCAA4B;AACrD,OAAOC,6BAA6B,4CAAwC;AAE5E,SACEC,iBAAiB,QAEZ,2BAAuB;AAE9B;;;;;;;;CAQC,GACD,SAASC,YACPC,OAAkC,EAClCC,MAAc,EACdC,GAAyC;IAEzC,OAAQF;QACN,KAAK;YACH,OACE;;;;;SAKC,iBACD,MAACX;gBAAMc,SAAS;;kCACd,KAACP;wBAAaK,QAAQA;wBAAQC,KAAKA;wBAAKE,SAAQ;;kCAChD,KAACX;wBAAkBQ,QAAQA;wBAAQC,KAAKA;;;;QAG9C,KAAK;YACH,qBACE,MAACb;gBAAMc,SAAS;;kCAGd,KAACP;wBAAaK,QAAQA;wBAAQC,KAAKA;wBAAKE,SAAQ;;kCAChD,KAACb;wBAAgBU,QAAQA;wBAAQC,KAAKA;;kCAGtC,KAACL;wBAAwBI,QAAQA;;;;QAGvC,KAAK;YACH,qBAAO,KAACT;gBAAiBS,QAAQA;gBAAQC,KAAKA;;QAChD;YACE,OAAO;IACX;AACF;AAEA;;;;;;;;CAQC,GACD,SAASG,eACPL,OAAkC,EAClCM,KAAwB,EACxBJ,GAAyC,EACzCK,OAAgB;IAEhB,OAAQP;QACN,KAAK;YACH,qBAAO,KAACN;gBAAmBY,OAAOA;gBAAOJ,KAAKA;gBAAKK,SAASA;;QAC9D,KAAK;QACL,KAAK;YACH,qBAAO,KAACZ;gBAAsBW,OAAOA;gBAAOE,MAAMR;gBAASS,OAAO;;QACpE,KAAK;YACH,qEAAqE;YACrE,4DAA4D;YAC5D,qBACE,KAACd;gBAAsBW,OAAOA;gBAAOE,MAAK;gBAAWC,SAASF;;QAElE;YACE,OAAO;IACX;AACF;AAEA;;;;;;;;;;;;;;;;;;CAkBC,GACD,OAAO,SAASG,qBAAqBC,KAA6B;IAChE,MAAM,EAAEV,MAAM,EAAEW,QAAQ,EAAEV,GAAG,EAAEW,WAAW,EAAEb,OAAO,EAAEc,QAAQ,EAAEC,QAAQ,EAAE,GACvEJ;IACF;;;GAGC,GACD,MAAML,QAAQhB,QACZ,IAAOW,UAAU,OAAOH,kBAAkBc,UAAUG,YAAY,MAChE;QAACd;QAAQW;QAAUG;KAAS;IAG9B;;;;;GAKC,GACD,IAAI,CAACf,WAAW,EAACc,4BAAAA,SAAUE,MAAM,KAAI,CAACD,UAAU,OAAO;IAEvD,IAAId,UAAU,MAAM;QAClB,sEAAsE;QACtE,IAAI,CAACK,OAAO,OAAO;QACnB,qBACE,KAAClB;YAAY0B,UAAUA;sBACpBT,eACCL,SACAM,OACAJ,KACA,kEAAkE;YAClE,kEAAkE;YAClE,kDAAkD;YAClDW,CAAAA,+BAAAA,YAAaI,SAAS,MAAK;;IAInC;IAEA,qBACE,KAAC7B;QAAY0B,UAAUA;kBACpBf,YAAYC,SAAsCC,QAAQC;;AAGjE;AACAQ,qBAAqBQ,WAAW,GAAG;AAEnC,eAAeR,qBAAoB"}
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/plugins/workflows/src/lib/components/workflows-console-page.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 type { AglynOrgBilling, ConsolePluginPageProps } from '@aglyn/aglyn'\nimport { HubSections } from '@aglyn/shared-ui-next'\nimport { Stack } from '@mui/material'\nimport { useMemo, type ReactNode } from 'react'\nimport HostActionsCard from './host-actions-card.component'\nimport HostWebhooksCard from './host-webhooks-card.component'\nimport HostWorkflowsCard from './host-workflows-card.component'\nimport OrgAutomationsCard from './org-automations-card.component'\nimport OrgSiteAutomationList from './org-site-automation-list.component'\nimport RunQuotaLine from './run-quota-line.component'\nimport SiteOrgAutomationsPanel from './site-org-automations-panel.component'\nimport type { WorkflowsConsoleSectionId } from './workflows-console-sections'\nimport {\n workflowsOrgMount,\n type WorkflowsOrgMount,\n} from './workflows-org-mount'\n\n/**\n * The body of one workflows section, built only when that section is the one\n * being read (AGL-2501).\n *\n * A function rather than a map of nodes on purpose: a `Record<id, ReactNode>`\n * would CONSTRUCT all three every render, and each card opens its Firestore\n * listens on mount — which is the entire cost this page exists to stop paying.\n * Only the returned branch is ever built.\n */\nfunction sectionBody(\n section: WorkflowsConsoleSectionId,\n hostId: string,\n org: Partial<AglynOrgBilling> | undefined,\n): ReactNode {\n switch (section) {\n case 'workflows':\n return (\n /*\n * `N runs this month · M included` (AGL-2171), which the run-history\n * mockup puts opposite the heading. The quota silently stops\n * automations running once it is reached, and the only place it was\n * reported was the Billing page.\n */\n <Stack spacing={1}>\n <RunQuotaLine hostId={hostId} org={org} counter=\"workflowRuns\" />\n <HostWorkflowsCard hostId={hostId} org={org} />\n </Stack>\n )\n case 'actions':\n return (\n <Stack spacing={1}>\n {/* `actionRunsPerMonth` had NO customer-facing surface at all\n before this — staff panel and usage-alerts only. */}\n <RunQuotaLine hostId={hostId} org={org} counter=\"actionRuns\" />\n <HostActionsCard hostId={hostId} org={org} />\n {/* What the organization runs on this site beside the site's own\n actions, and the site's pause for each (AGL-3302). */}\n <SiteOrgAutomationsPanel hostId={hostId} />\n </Stack>\n )\n case 'webhooks':\n return <HostWebhooksCard hostId={hostId} org={org} />\n default:\n return null\n }\n}\n\n/**\n * The body of one ORGANIZATION-level section (AGL-3302): the org automations,\n * and every site's own workflows, actions and webhooks listed with the site\n * each belongs to.\n *\n * The run allowance line heads the workflows and actions lists here too: the\n * allowance is the workspace's (AGL-3472), every site's runs spend it, and\n * this is the page that lists them all.\n */\nfunction orgSectionBody(\n section: WorkflowsConsoleSectionId,\n mount: WorkflowsOrgMount,\n org: Partial<AglynOrgBilling> | undefined,\n canEdit: boolean,\n): ReactNode {\n switch (section) {\n case 'automations':\n return <OrgAutomationsCard mount={mount} org={org} canEdit={canEdit} />\n case 'workflows':\n case 'actions':\n return (\n <Stack spacing={1}>\n <RunQuotaLine\n hostId={null}\n orgId={mount.orgId}\n org={org}\n counter={section === 'workflows' ? 'workflowRuns' : 'actionRuns'}\n />\n <OrgSiteAutomationList mount={mount} kind={section} canRead />\n </Stack>\n )\n case 'webhooks':\n // A webhook holds its site's secret: the rules admit a site's admins\n // and editors, which every org-wide member but a viewer is.\n return (\n <OrgSiteAutomationList mount={mount} kind=\"webhooks\" canRead={canEdit} />\n )\n default:\n return null\n }\n}\n\n/**\n * Automation page (AGL-101/148/149 → AGL-395): the automation surface —\n * workflow builder, event-triggered actions, and webhooks — owned by the\n * workflows plugin and rendered by the shell's generic plugin route. Each card\n * runs its own entitlement check (workflows / actions / webhooks are distinct\n * plan flags), so the shell's resolved `org` doc flows into all three.\n *\n * Sections are ROUTES (AGL-2501). `HubTabs lazy` already mounted one panel, so\n * this is not a read saving — `workflows-console-read-cost.spec.tsx` was\n * written BEFORE the conversion precisely to hold that line, and reports the\n * same counts after. What routing adds is that the URL names the section: it is\n * linkable, the back button walks sections, the breadcrumb says where you are,\n * and \"mount only what is open\" is structural rather than a `lazy` flag.\n *\n * The section ids are unchanged by the Automation rename: they are the\n * addresses people bookmark and the docs link to. A workflow belongs to the\n * site and an ACTION belongs to the site too; an interaction belongs to the\n * document that holds it and is edited on the element, not here.\n */\nexport function WorkflowsConsolePage(props: ConsolePluginPageProps) {\n const { hostId, orgMount, org, permissions, section, sections, basePath } =\n props\n /*\n * Mounted with no site: the organization's hub (AGL-3302). Memoised so the\n * cards below, which key their listeners on the mount's org, see one object.\n */\n const mount = useMemo(\n () => (hostId == null ? workflowsOrgMount(orgMount, basePath) : null),\n [hostId, orgMount, basePath],\n )\n\n /*\n * Nothing until the URL names a section. The shell redirects a bare hub URL\n * to the landing section and holds a spinner while it does, so this state is\n * transient — and rendering a default section here instead would pay for its\n * listens on a URL that is already being replaced.\n */\n if (!section || !sections?.length || !basePath) return null\n\n if (hostId == null) {\n // No site and no org to stand in for it: nothing this page can scope.\n if (!mount) return null\n return (\n <HubSections sections={sections}>\n {orgSectionBody(\n section as WorkflowsConsoleSectionId,\n mount,\n org,\n // An org viewer's `editHosts` is false; every other org role's is\n // true. The server routes decide — this keeps a viewer from being\n // offered controls that are about to refuse them.\n permissions?.editHosts !== false,\n )}\n </HubSections>\n )\n }\n\n return (\n <HubSections sections={sections}>\n {sectionBody(section as WorkflowsConsoleSectionId, hostId, org)}\n </HubSections>\n )\n}\nWorkflowsConsolePage.displayName = 'WorkflowsConsolePage'\n\nexport default WorkflowsConsolePage\n"],"names":["HubSections","Stack","useMemo","HostActionsCard","HostWebhooksCard","HostWorkflowsCard","OrgAutomationsCard","OrgSiteAutomationList","RunQuotaLine","SiteOrgAutomationsPanel","workflowsOrgMount","sectionBody","section","hostId","org","spacing","counter","orgSectionBody","mount","canEdit","orgId","kind","canRead","WorkflowsConsolePage","props","orgMount","permissions","sections","basePath","length","editHosts","displayName"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GACD;;AAGA,SAASA,WAAW,QAAQ,wBAAuB;AACnD,SAASC,KAAK,QAAQ,gBAAe;AACrC,SAASC,OAAO,QAAwB,QAAO;AAC/C,OAAOC,qBAAqB,mCAA+B;AAC3D,OAAOC,sBAAsB,oCAAgC;AAC7D,OAAOC,uBAAuB,qCAAiC;AAC/D,OAAOC,wBAAwB,sCAAkC;AACjE,OAAOC,2BAA2B,0CAAsC;AACxE,OAAOC,kBAAkB,gCAA4B;AACrD,OAAOC,6BAA6B,4CAAwC;AAE5E,SACEC,iBAAiB,QAEZ,2BAAuB;AAE9B;;;;;;;;CAQC,GACD,SAASC,YACPC,OAAkC,EAClCC,MAAc,EACdC,GAAyC;IAEzC,OAAQF;QACN,KAAK;YACH,OACE;;;;;SAKC,iBACD,MAACX;gBAAMc,SAAS;;kCACd,KAACP;wBAAaK,QAAQA;wBAAQC,KAAKA;wBAAKE,SAAQ;;kCAChD,KAACX;wBAAkBQ,QAAQA;wBAAQC,KAAKA;;;;QAG9C,KAAK;YACH,qBACE,MAACb;gBAAMc,SAAS;;kCAGd,KAACP;wBAAaK,QAAQA;wBAAQC,KAAKA;wBAAKE,SAAQ;;kCAChD,KAACb;wBAAgBU,QAAQA;wBAAQC,KAAKA;;kCAGtC,KAACL;wBAAwBI,QAAQA;;;;QAGvC,KAAK;YACH,qBAAO,KAACT;gBAAiBS,QAAQA;gBAAQC,KAAKA;;QAChD;YACE,OAAO;IACX;AACF;AAEA;;;;;;;;CAQC,GACD,SAASG,eACPL,OAAkC,EAClCM,KAAwB,EACxBJ,GAAyC,EACzCK,OAAgB;IAEhB,OAAQP;QACN,KAAK;YACH,qBAAO,KAACN;gBAAmBY,OAAOA;gBAAOJ,KAAKA;gBAAKK,SAASA;;QAC9D,KAAK;QACL,KAAK;YACH,qBACE,MAAClB;gBAAMc,SAAS;;kCACd,KAACP;wBACCK,QAAQ;wBACRO,OAAOF,MAAME,KAAK;wBAClBN,KAAKA;wBACLE,SAASJ,YAAY,cAAc,iBAAiB;;kCAEtD,KAACL;wBAAsBW,OAAOA;wBAAOG,MAAMT;wBAASU,OAAO;;;;QAGjE,KAAK;YACH,qEAAqE;YACrE,4DAA4D;YAC5D,qBACE,KAACf;gBAAsBW,OAAOA;gBAAOG,MAAK;gBAAWC,SAASH;;QAElE;YACE,OAAO;IACX;AACF;AAEA;;;;;;;;;;;;;;;;;;CAkBC,GACD,OAAO,SAASI,qBAAqBC,KAA6B;IAChE,MAAM,EAAEX,MAAM,EAAEY,QAAQ,EAAEX,GAAG,EAAEY,WAAW,EAAEd,OAAO,EAAEe,QAAQ,EAAEC,QAAQ,EAAE,GACvEJ;IACF;;;GAGC,GACD,MAAMN,QAAQhB,QACZ,IAAOW,UAAU,OAAOH,kBAAkBe,UAAUG,YAAY,MAChE;QAACf;QAAQY;QAAUG;KAAS;IAG9B;;;;;GAKC,GACD,IAAI,CAAChB,WAAW,EAACe,4BAAAA,SAAUE,MAAM,KAAI,CAACD,UAAU,OAAO;IAEvD,IAAIf,UAAU,MAAM;QAClB,sEAAsE;QACtE,IAAI,CAACK,OAAO,OAAO;QACnB,qBACE,KAAClB;YAAY2B,UAAUA;sBACpBV,eACCL,SACAM,OACAJ,KACA,kEAAkE;YAClE,kEAAkE;YAClE,kDAAkD;YAClDY,CAAAA,+BAAAA,YAAaI,SAAS,MAAK;;IAInC;IAEA,qBACE,KAAC9B;QAAY2B,UAAUA;kBACpBhB,YAAYC,SAAsCC,QAAQC;;AAGjE;AACAS,qBAAqBQ,WAAW,GAAG;AAEnC,eAAeR,qBAAoB"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Aglyn LLC
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
16
|
+
*/
|
|
17
|
+
/**
|
|
18
|
+
* The automation editor's DECLARATIONS: what another surface reads of this
|
|
19
|
+
* plugin before any of its own surfaces load, in both apps and in the
|
|
20
|
+
* console's browser.
|
|
21
|
+
*
|
|
22
|
+
* The checks of the server steps an automation holds (AGL-3080), so a plugin
|
|
23
|
+
* that writes an automation it does not edit — a recipe installed into a
|
|
24
|
+
* site, a drafted automation graded before it is handed over — refuses what
|
|
25
|
+
* this editor would (`validateStoredInteraction`). Light by construction: the
|
|
26
|
+
* checks are pure, and nothing here reaches Firestore or React.
|
|
27
|
+
*/
|
|
28
|
+
export declare function registerWorkflowsDeclarations(): void;
|