@aglyn/plugins-workflows 1.0.0-beta.228 → 1.0.0-beta.230
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/package.json +12 -12
- package/src/lib/components/host-actions-card.component.js +20 -3
- package/src/lib/components/host-actions-card.component.js.map +1 -1
- package/src/lib/components/host-workflows-card.component.d.ts +7 -0
- package/src/lib/components/host-workflows-card.component.js +35 -5
- package/src/lib/components/host-workflows-card.component.js.map +1 -1
- package/src/lib/components/org-automation-editor.component.d.ts +9 -0
- package/src/lib/components/org-automation-editor.component.js +32 -1
- package/src/lib/components/org-automation-editor.component.js.map +1 -1
- package/src/lib/components/org-automations-card.component.js +41 -9
- package/src/lib/components/org-automations-card.component.js.map +1 -1
- package/src/lib/components/workflow-zones.d.ts +53 -1
- package/src/lib/components/workflow-zones.js +14 -0
- package/src/lib/components/workflow-zones.js.map +1 -1
- package/src/lib/components/workflows-console-page.js +5 -3
- package/src/lib/components/workflows-console-page.js.map +1 -1
- package/src/lib/engine/run-event-actions.js +21 -5
- package/src/lib/engine/run-event-actions.js.map +1 -1
- package/src/lib/engine/webhook-delivery.d.ts +24 -0
- package/src/lib/engine/webhook-delivery.js +24 -0
- package/src/lib/engine/webhook-delivery.js.map +1 -0
- package/src/lib/model/webhooks.d.ts +8 -2
- package/src/lib/model/webhooks.js +7 -1
- package/src/lib/model/webhooks.js.map +1 -1
- package/src/lib/plugin.js +12 -3
- package/src/lib/plugin.js.map +1 -1
- package/src/lib/server/automation-run-figures.d.ts +38 -0
- package/src/lib/server/automation-run-figures.js +182 -0
- package/src/lib/server/automation-run-figures.js.map +1 -0
- package/src/lib/server-console.js +5 -0
- package/src/lib/server-console.js.map +1 -1
|
@@ -0,0 +1,24 @@
|
|
|
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 `webhookPost` step's transport (AGL-3628), behind its own module so
|
|
19
|
+
* the engine can load it lazily: it brings `undici`, which only that step
|
|
20
|
+
* needs and which cannot load under jsdom. The engine imports
|
|
21
|
+
* `@aglyn/tenant-data-admin` statically elsewhere, so it must lazy-load a
|
|
22
|
+
* module of its own rather than that library directly.
|
|
23
|
+
*/
|
|
24
|
+
export { describeConfiguredUrlRefusal, fetchConfiguredPublicUrl, } from '@aglyn/tenant-data-admin/server/configured-url-fetch';
|
|
@@ -0,0 +1,24 @@
|
|
|
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
|
+
* The `webhookPost` step's transport (AGL-3628), behind its own module so
|
|
18
|
+
* the engine can load it lazily: it brings `undici`, which only that step
|
|
19
|
+
* needs and which cannot load under jsdom. The engine imports
|
|
20
|
+
* `@aglyn/tenant-data-admin` statically elsewhere, so it must lazy-load a
|
|
21
|
+
* module of its own rather than that library directly.
|
|
22
|
+
*/ export { describeConfiguredUrlRefusal, fetchConfiguredPublicUrl } from "@aglyn/tenant-data-admin/server/configured-url-fetch";
|
|
23
|
+
|
|
24
|
+
//# sourceMappingURL=webhook-delivery.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/plugins/workflows/src/lib/engine/webhook-delivery.ts"],"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\n/**\n * The `webhookPost` step's transport (AGL-3628), behind its own module so\n * the engine can load it lazily: it brings `undici`, which only that step\n * needs and which cannot load under jsdom. The engine imports\n * `@aglyn/tenant-data-admin` statically elsewhere, so it must lazy-load a\n * module of its own rather than that library directly.\n */\nexport {\n describeConfiguredUrlRefusal,\n fetchConfiguredPublicUrl,\n} from '@aglyn/tenant-data-admin/server/configured-url-fetch'\n"],"names":["describeConfiguredUrlRefusal","fetchConfiguredPublicUrl"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GAED;;;;;;CAMC,GACD,SACEA,4BAA4B,EAC5BC,wBAAwB,QACnB,uDAAsD"}
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
export interface HostWebhook {
|
|
25
25
|
name: string;
|
|
26
26
|
direction: 'outbound' | 'inbound';
|
|
27
|
-
/** Outbound delivery URL (https only; checked
|
|
27
|
+
/** Outbound delivery URL (https only; resolved and checked at send time). */
|
|
28
28
|
url?: string;
|
|
29
29
|
/** Shared secret: signs outbound bodies, verifies inbound callers. */
|
|
30
30
|
secret?: string;
|
|
@@ -32,5 +32,11 @@ export interface HostWebhook {
|
|
|
32
32
|
workflowName?: string;
|
|
33
33
|
enabled?: boolean;
|
|
34
34
|
}
|
|
35
|
-
/**
|
|
35
|
+
/**
|
|
36
|
+
* A hint for the webhooks card's URL field: https, and not an obvious private
|
|
37
|
+
* IPv4 literal. It is NOT the SSRF guard — it reads only the URL's text, so
|
|
38
|
+
* an IPv6 literal, a decimal IPv4 or a name that resolves inward all pass it.
|
|
39
|
+
* Delivery goes through `fetchConfiguredPublicUrl` (`@aglyn/tenant-data-admin`),
|
|
40
|
+
* which resolves, pins and refuses redirects.
|
|
41
|
+
*/
|
|
36
42
|
export declare const WEBHOOK_URL_PATTERN: RegExp;
|
|
@@ -19,6 +19,12 @@
|
|
|
19
19
|
* inbound entries mint `/api/hooks/{hostId}/{hookId}` endpoints that run
|
|
20
20
|
* a workflow with the posted JSON in scope. Business tier (`webhooks`
|
|
21
21
|
* flag); Pro can be enabled per-tenant via entitlement overrides.
|
|
22
|
-
*/ /**
|
|
22
|
+
*/ /**
|
|
23
|
+
* A hint for the webhooks card's URL field: https, and not an obvious private
|
|
24
|
+
* IPv4 literal. It is NOT the SSRF guard — it reads only the URL's text, so
|
|
25
|
+
* an IPv6 literal, a decimal IPv4 or a name that resolves inward all pass it.
|
|
26
|
+
* Delivery goes through `fetchConfiguredPublicUrl` (`@aglyn/tenant-data-admin`),
|
|
27
|
+
* which resolves, pins and refuses redirects.
|
|
28
|
+
*/ export const WEBHOOK_URL_PATTERN = /^https:\/\/(?!localhost)(?!127\.)(?!0\.)(?!10\.)(?!172\.(1[6-9]|2\d|3[01])\.)(?!192\.168\.)(?!169\.254\.)[^\s]+$/i;
|
|
23
29
|
|
|
24
30
|
//# sourceMappingURL=webhooks.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../../libs/plugins/workflows/src/lib/model/webhooks.ts"],"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\n/**\n * Webhooks (AGL-149) at `hosts/{hostId}/webhooks/{id}`. Outbound entries\n * are targets a `webhookPost` action step delivers to (HMAC-signed);\n * inbound entries mint `/api/hooks/{hostId}/{hookId}` endpoints that run\n * a workflow with the posted JSON in scope. Business tier (`webhooks`\n * flag); Pro can be enabled per-tenant via entitlement overrides.\n */\nexport interface HostWebhook {\n name: string\n direction: 'outbound' | 'inbound'\n /** Outbound delivery URL (https only; checked
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/plugins/workflows/src/lib/model/webhooks.ts"],"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\n/**\n * Webhooks (AGL-149) at `hosts/{hostId}/webhooks/{id}`. Outbound entries\n * are targets a `webhookPost` action step delivers to (HMAC-signed);\n * inbound entries mint `/api/hooks/{hostId}/{hookId}` endpoints that run\n * a workflow with the posted JSON in scope. Business tier (`webhooks`\n * flag); Pro can be enabled per-tenant via entitlement overrides.\n */\nexport interface HostWebhook {\n name: string\n direction: 'outbound' | 'inbound'\n /** Outbound delivery URL (https only; resolved and checked at send time). */\n url?: string\n /** Shared secret: signs outbound bodies, verifies inbound callers. */\n secret?: string\n /** Inbound: workflow (by name) enrolled with the payload in scope. */\n workflowName?: string\n enabled?: boolean\n}\n\n/**\n * A hint for the webhooks card's URL field: https, and not an obvious private\n * IPv4 literal. It is NOT the SSRF guard — it reads only the URL's text, so\n * an IPv6 literal, a decimal IPv4 or a name that resolves inward all pass it.\n * Delivery goes through `fetchConfiguredPublicUrl` (`@aglyn/tenant-data-admin`),\n * which resolves, pins and refuses redirects.\n */\nexport const WEBHOOK_URL_PATTERN =\n /^https:\\/\\/(?!localhost)(?!127\\.)(?!0\\.)(?!10\\.)(?!172\\.(1[6-9]|2\\d|3[01])\\.)(?!192\\.168\\.)(?!169\\.254\\.)[^\\s]+$/i\n"],"names":["WEBHOOK_URL_PATTERN"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GAED;;;;;;CAMC,GAaD;;;;;;CAMC,GACD,OAAO,MAAMA,sBACX,oHAAmH"}
|
package/src/lib/plugin.js
CHANGED
|
@@ -21,7 +21,7 @@ import { StaffOrgAutomationsCard, StaffSiteAutomationsCard } from "./components/
|
|
|
21
21
|
import { WORKFLOWS_CONSOLE_SECTIONS, WORKFLOWS_ORG_CONSOLE_SECTIONS } from "./components/workflows-console-sections.js";
|
|
22
22
|
import { registerPluginZone } from "@aglyn/aglyn/plugin-manager/plugin-zones";
|
|
23
23
|
import { registerPluginTransferResourceUi } from "@aglyn/aglyn/plugin-manager/plugin-transfer-resources";
|
|
24
|
-
import { AUTOMATION_EDITOR_ZONE, AUTOMATION_RUN_ZONE, HOST_AUTOMATIONS_ZONE, WORKFLOW_USAGE_ZONE } from "./components/workflow-zones.js";
|
|
24
|
+
import { AUTOMATION_EDITOR_ZONE, AUTOMATION_RUN_ZONE, HOST_AUTOMATIONS_ZONE, ORG_AUTOMATIONS_ZONE, WORKFLOW_USAGE_ZONE } from "./components/workflow-zones.js";
|
|
25
25
|
import { BUNDLE_ID } from "./constants/bundle-common.js";
|
|
26
26
|
import { registerWorkflowsRecordLists } from "./model/workflows-record-lists.js";
|
|
27
27
|
import { registerWorkflowsRecordRoutes } from "./model/workflows-record-routes.js";
|
|
@@ -68,7 +68,16 @@ import { WORKFLOWS_SEARCH_SOURCES } from "./model/workflows-search-sources.js";
|
|
|
68
68
|
label: 'Automation page actions',
|
|
69
69
|
surface: 'console',
|
|
70
70
|
layout: 'bare',
|
|
71
|
-
description: 'On the Automation page, beside Add action and Recipes: another way to start an automation. `openAction` opens a listed action in the Actions editor; a widget here writes nothing through the page.'
|
|
71
|
+
description: 'On the Automation page, beside Add action and Recipes, and in the Workflows card’s header or empty state: another way to start an automation. `openAction` opens a listed action in the Actions editor; a widget here writes nothing through the page.'
|
|
72
|
+
}, {
|
|
73
|
+
pluginId: BUNDLE_ID
|
|
74
|
+
});
|
|
75
|
+
registerPluginZone({
|
|
76
|
+
zone: ORG_AUTOMATIONS_ZONE,
|
|
77
|
+
label: 'Org automations actions',
|
|
78
|
+
surface: 'console',
|
|
79
|
+
layout: 'bare',
|
|
80
|
+
description: 'In the header of the workspace’s Org automations card, for a member who may write them: another way to start an org automation. `triggers` and `steps` are what one may start on and hold; `propose` opens an automation in the section’s editor, unsaved and switched off. A widget here writes nothing.'
|
|
72
81
|
}, {
|
|
73
82
|
pluginId: BUNDLE_ID
|
|
74
83
|
});
|
|
@@ -77,7 +86,7 @@ import { WORKFLOWS_SEARCH_SOURCES } from "./model/workflows-search-sources.js";
|
|
|
77
86
|
label: 'An automation’s editor',
|
|
78
87
|
surface: 'console',
|
|
79
88
|
layout: 'bare',
|
|
80
|
-
description: 'Inside the editor of one saved automation, an action or a workflow. A widget here reads the automation as it is stored and changes nothing in the editor.'
|
|
89
|
+
description: 'Inside the editor of one saved automation, an action or a workflow. A widget here reads the automation as it is stored and changes nothing in the editor; in an action’s editor, `openAction` opens another listed action, such as a copy the widget drafted, in its place.'
|
|
81
90
|
}, {
|
|
82
91
|
pluginId: BUNDLE_ID
|
|
83
92
|
});
|
package/src/lib/plugin.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../libs/plugins/workflows/src/lib/plugin.ts"],"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\nimport * as Aglyn from '@aglyn/aglyn'\nimport { mdiSitemap } from '@aglyn/shared-data-mdi'\nimport { lazy } from 'react'\nimport { HostActivityCard } from './components/host-activity-card.component'\nimport {\n StaffOrgAutomationsCard,\n StaffSiteAutomationsCard,\n} from './components/staff-automations-card.component'\nimport {\n WORKFLOWS_CONSOLE_SECTIONS,\n WORKFLOWS_ORG_CONSOLE_SECTIONS,\n} from './components/workflows-console-sections'\nimport { registerPluginZone } from '@aglyn/aglyn/plugin-manager/plugin-zones'\nimport { registerPluginTransferResourceUi } from '@aglyn/aglyn/plugin-manager/plugin-transfer-resources'\nimport {\n AUTOMATION_EDITOR_ZONE,\n AUTOMATION_RUN_ZONE,\n HOST_AUTOMATIONS_ZONE,\n WORKFLOW_USAGE_ZONE,\n} from './components/workflow-zones'\nimport { BUNDLE_ID } from './constants/bundle-common'\nimport { registerWorkflowsRecordLists } from './model/workflows-record-lists'\nimport { registerWorkflowsRecordRoutes } from './model/workflows-record-routes'\nimport { WORKFLOWS_SEARCH_SOURCES } from './model/workflows-search-sources'\n\n/** Code-split: the Automation console page only loads when opened. */\nconst WorkflowsConsolePage = lazy(\n () => import('./components/workflows-console-page'),\n)\n\n/**\n * Workflows feature plugin (AGL-395). Console-only — workflows, actions,\n * and webhooks run server-side (event pipelines, `/api/hooks`), not through\n * a canvas element, so there is no UI bundle. The console half declares the\n * Automation nav + page through the ConsoleExtension registry, gated by the\n * `workflows` entitlement (the Actions/Webhooks tabs run their own per-plan\n * checks off the passed `org`). Where a workflow is used is asked of the\n * platform's scan and drawn in a zone this plugin hosts.\n *\n * `pluginId`, `featureFlag` and `navTabId` all still read `workflows`: they\n * are stored — an org's enabled-plugin ids, the plan's entitlement flags, the\n * Remote Config release flag — and a section's name is not a reason to orphan\n * them. Only what a reader sees carries the new name.\n */\nexport function registerWorkflowsConsole(): void {\n // How the Import & export hub names org automations in a workspace package (AGL-3535).\n registerPluginTransferResourceUi(\n 'workflows.org-automations',\n { label: 'Org automations', icon: { path: mdiSitemap.path } },\n { pluginId: BUNDLE_ID },\n )\n registerWorkflowsRecordRoutes()\n registerWorkflowsRecordLists()\n registerPluginZone(\n {\n zone: WORKFLOW_USAGE_ZONE,\n label: 'Where a workflow is used',\n surface: 'console',\n description:\n 'On the Automation page, after a reader asks where a workflow is used. A widget here lays out the scan the page already ran; it is handed the site, the answer and a way to close, and it writes nothing.',\n },\n // Named, because a spec calls this registrar without the loader.\n { pluginId: BUNDLE_ID },\n )\n // The zones the Automation page draws in its own layouts (AGL-2919): one\n // item in the Actions row, inside an open editor, on a failed run's row.\n registerPluginZone(\n {\n zone: HOST_AUTOMATIONS_ZONE,\n label: 'Automation page actions',\n surface: 'console',\n layout: 'bare',\n description:\n 'On the Automation page, beside Add action and Recipes: another way to start an automation. `openAction` opens a listed action in the Actions editor; a widget here writes nothing through the page.',\n },\n { pluginId: BUNDLE_ID },\n )\n registerPluginZone(\n {\n zone: AUTOMATION_EDITOR_ZONE,\n label: 'An automation’s editor',\n surface: 'console',\n layout: 'bare',\n description:\n 'Inside the editor of one saved automation, an action or a workflow. A widget here reads the automation as it is stored and changes nothing in the editor.',\n },\n { pluginId: BUNDLE_ID },\n )\n registerPluginZone(\n {\n zone: AUTOMATION_RUN_ZONE,\n label: 'A failed automation run',\n surface: 'console',\n layout: 'bare',\n description:\n 'On each failed run in an automation’s run history. A widget here reads the run as it was recorded and changes nothing.',\n },\n { pluginId: BUNDLE_ID },\n )\n Aglyn.registerConsoleExtension({\n // Host activity feed (AGL-419): rendered by the shell's\n // 'hostActivity' widget slot (dashboard + editor view page).\n widgets: [\n {\n slot: 'hostActivity',\n widgetId: 'workflows-host-activity',\n title: 'Recent Activity',\n Component: HostActivityCard,\n },\n // The staff site and organization pages' automations (AGL-3379), read\n // only: staff see what runs on a site without joining it.\n {\n slot: Aglyn.CONSOLE_WIDGET_SLOTS.staffSite,\n widgetId: 'workflows-staff-site-automations',\n title: 'Automations',\n Component: StaffSiteAutomationsCard,\n },\n {\n slot: Aglyn.CONSOLE_WIDGET_SLOTS.adminOrgDetail,\n widgetId: 'workflows-staff-org-automations',\n title: 'Organization automations',\n Component: StaffOrgAutomationsCard,\n },\n ],\n pluginId: BUNDLE_ID,\n displayName: 'Automation',\n featureFlag: 'workflows',\n searchSources: WORKFLOWS_SEARCH_SOURCES,\n navItems: [\n {\n label: 'Automation',\n // Workflows, Actions and Webhooks are the tabs INSIDE this section, so\n // the section is named for what they have in common. `/workflows` —\n // the address before the section had its own name — is redirected here\n // by this plugin's `consoleRedirects`.\n href: '/automation',\n // Sections as ROUTES (AGL-2501): each is a real URL the shell\n // resolves and gates, so the page mounts the one being read.\n sections: WORKFLOWS_CONSOLE_SECTIONS,\n // Reuse the existing release-flag nav-tab so staff-preview gating is\n // unchanged now that the tab comes from the plugin (AGL-395).\n navTabId: 'nav-tab-workflows',\n icon: { path: mdiSitemap.path },\n header: {\n title: 'Automation',\n icon: { path: mdiSitemap.path },\n docsTopic: 'workflows',\n },\n Component: WorkflowsConsolePage,\n },\n ],\n /*\n * The ORGANIZATION's Automation hub (AGL-3302), at `/[orgSlug]/automation`:\n * the org automations placed across the organization's sites, and every\n * site's own workflows, actions and webhooks side by side. The same page\n * component, mounted with no site; the site tab's release flag gates both\n * levels, so one flag rolls the surface out at once.\n */\n orgNavItems: [\n {\n label: 'Automation',\n href: '/automation',\n sections: WORKFLOWS_ORG_CONSOLE_SECTIONS,\n navTabId: 'nav-tab-workflows',\n icon: { path: mdiSitemap.path },\n header: {\n title: 'Automation',\n icon: { path: mdiSitemap.path },\n docsTopic: 'workflows',\n },\n Component: WorkflowsConsolePage,\n },\n ],\n })\n}\n\n// Activity feed consumed directly by the app (dashboard + screen view).\nexport { default as HostActivityCard } from './components/host-activity-card.component'\nexport type { HostActivityCardProps } from './components/host-activity-card.component'\n"],"names":["Aglyn","mdiSitemap","lazy","HostActivityCard","StaffOrgAutomationsCard","StaffSiteAutomationsCard","WORKFLOWS_CONSOLE_SECTIONS","WORKFLOWS_ORG_CONSOLE_SECTIONS","registerPluginZone","registerPluginTransferResourceUi","AUTOMATION_EDITOR_ZONE","AUTOMATION_RUN_ZONE","HOST_AUTOMATIONS_ZONE","WORKFLOW_USAGE_ZONE","BUNDLE_ID","registerWorkflowsRecordLists","registerWorkflowsRecordRoutes","WORKFLOWS_SEARCH_SOURCES","WorkflowsConsolePage","registerWorkflowsConsole","label","icon","path","pluginId","zone","surface","description","layout","registerConsoleExtension","widgets","slot","widgetId","title","Component","CONSOLE_WIDGET_SLOTS","staffSite","adminOrgDetail","displayName","featureFlag","searchSources","navItems","href","sections","navTabId","header","docsTopic","orgNavItems","default"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../../../../libs/plugins/workflows/src/lib/plugin.ts"],"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\nimport * as Aglyn from '@aglyn/aglyn'\nimport { mdiSitemap } from '@aglyn/shared-data-mdi'\nimport { lazy } from 'react'\nimport { HostActivityCard } from './components/host-activity-card.component'\nimport {\n StaffOrgAutomationsCard,\n StaffSiteAutomationsCard,\n} from './components/staff-automations-card.component'\nimport {\n WORKFLOWS_CONSOLE_SECTIONS,\n WORKFLOWS_ORG_CONSOLE_SECTIONS,\n} from './components/workflows-console-sections'\nimport { registerPluginZone } from '@aglyn/aglyn/plugin-manager/plugin-zones'\nimport { registerPluginTransferResourceUi } from '@aglyn/aglyn/plugin-manager/plugin-transfer-resources'\nimport {\n AUTOMATION_EDITOR_ZONE,\n AUTOMATION_RUN_ZONE,\n HOST_AUTOMATIONS_ZONE,\n ORG_AUTOMATIONS_ZONE,\n WORKFLOW_USAGE_ZONE,\n} from './components/workflow-zones'\nimport { BUNDLE_ID } from './constants/bundle-common'\nimport { registerWorkflowsRecordLists } from './model/workflows-record-lists'\nimport { registerWorkflowsRecordRoutes } from './model/workflows-record-routes'\nimport { WORKFLOWS_SEARCH_SOURCES } from './model/workflows-search-sources'\n\n/** Code-split: the Automation console page only loads when opened. */\nconst WorkflowsConsolePage = lazy(\n () => import('./components/workflows-console-page'),\n)\n\n/**\n * Workflows feature plugin (AGL-395). Console-only — workflows, actions,\n * and webhooks run server-side (event pipelines, `/api/hooks`), not through\n * a canvas element, so there is no UI bundle. The console half declares the\n * Automation nav + page through the ConsoleExtension registry, gated by the\n * `workflows` entitlement (the Actions/Webhooks tabs run their own per-plan\n * checks off the passed `org`). Where a workflow is used is asked of the\n * platform's scan and drawn in a zone this plugin hosts.\n *\n * `pluginId`, `featureFlag` and `navTabId` all still read `workflows`: they\n * are stored — an org's enabled-plugin ids, the plan's entitlement flags, the\n * Remote Config release flag — and a section's name is not a reason to orphan\n * them. Only what a reader sees carries the new name.\n */\nexport function registerWorkflowsConsole(): void {\n // How the Import & export hub names org automations in a workspace package (AGL-3535).\n registerPluginTransferResourceUi(\n 'workflows.org-automations',\n { label: 'Org automations', icon: { path: mdiSitemap.path } },\n { pluginId: BUNDLE_ID },\n )\n registerWorkflowsRecordRoutes()\n registerWorkflowsRecordLists()\n registerPluginZone(\n {\n zone: WORKFLOW_USAGE_ZONE,\n label: 'Where a workflow is used',\n surface: 'console',\n description:\n 'On the Automation page, after a reader asks where a workflow is used. A widget here lays out the scan the page already ran; it is handed the site, the answer and a way to close, and it writes nothing.',\n },\n // Named, because a spec calls this registrar without the loader.\n { pluginId: BUNDLE_ID },\n )\n // The zones the Automation page draws in its own layouts (AGL-2919): one\n // item in the Actions row, inside an open editor, on a failed run's row.\n registerPluginZone(\n {\n zone: HOST_AUTOMATIONS_ZONE,\n label: 'Automation page actions',\n surface: 'console',\n layout: 'bare',\n description:\n 'On the Automation page, beside Add action and Recipes, and in the Workflows card’s header or empty state: another way to start an automation. `openAction` opens a listed action in the Actions editor; a widget here writes nothing through the page.',\n },\n { pluginId: BUNDLE_ID },\n )\n registerPluginZone(\n {\n zone: ORG_AUTOMATIONS_ZONE,\n label: 'Org automations actions',\n surface: 'console',\n layout: 'bare',\n description:\n 'In the header of the workspace’s Org automations card, for a member who may write them: another way to start an org automation. `triggers` and `steps` are what one may start on and hold; `propose` opens an automation in the section’s editor, unsaved and switched off. A widget here writes nothing.',\n },\n { pluginId: BUNDLE_ID },\n )\n registerPluginZone(\n {\n zone: AUTOMATION_EDITOR_ZONE,\n label: 'An automation’s editor',\n surface: 'console',\n layout: 'bare',\n description:\n 'Inside the editor of one saved automation, an action or a workflow. A widget here reads the automation as it is stored and changes nothing in the editor; in an action’s editor, `openAction` opens another listed action, such as a copy the widget drafted, in its place.',\n },\n { pluginId: BUNDLE_ID },\n )\n registerPluginZone(\n {\n zone: AUTOMATION_RUN_ZONE,\n label: 'A failed automation run',\n surface: 'console',\n layout: 'bare',\n description:\n 'On each failed run in an automation’s run history. A widget here reads the run as it was recorded and changes nothing.',\n },\n { pluginId: BUNDLE_ID },\n )\n Aglyn.registerConsoleExtension({\n // Host activity feed (AGL-419): rendered by the shell's\n // 'hostActivity' widget slot (dashboard + editor view page).\n widgets: [\n {\n slot: 'hostActivity',\n widgetId: 'workflows-host-activity',\n title: 'Recent Activity',\n Component: HostActivityCard,\n },\n // The staff site and organization pages' automations (AGL-3379), read\n // only: staff see what runs on a site without joining it.\n {\n slot: Aglyn.CONSOLE_WIDGET_SLOTS.staffSite,\n widgetId: 'workflows-staff-site-automations',\n title: 'Automations',\n Component: StaffSiteAutomationsCard,\n },\n {\n slot: Aglyn.CONSOLE_WIDGET_SLOTS.adminOrgDetail,\n widgetId: 'workflows-staff-org-automations',\n title: 'Organization automations',\n Component: StaffOrgAutomationsCard,\n },\n ],\n pluginId: BUNDLE_ID,\n displayName: 'Automation',\n featureFlag: 'workflows',\n searchSources: WORKFLOWS_SEARCH_SOURCES,\n navItems: [\n {\n label: 'Automation',\n // Workflows, Actions and Webhooks are the tabs INSIDE this section, so\n // the section is named for what they have in common. `/workflows` —\n // the address before the section had its own name — is redirected here\n // by this plugin's `consoleRedirects`.\n href: '/automation',\n // Sections as ROUTES (AGL-2501): each is a real URL the shell\n // resolves and gates, so the page mounts the one being read.\n sections: WORKFLOWS_CONSOLE_SECTIONS,\n // Reuse the existing release-flag nav-tab so staff-preview gating is\n // unchanged now that the tab comes from the plugin (AGL-395).\n navTabId: 'nav-tab-workflows',\n icon: { path: mdiSitemap.path },\n header: {\n title: 'Automation',\n icon: { path: mdiSitemap.path },\n docsTopic: 'workflows',\n },\n Component: WorkflowsConsolePage,\n },\n ],\n /*\n * The ORGANIZATION's Automation hub (AGL-3302), at `/[orgSlug]/automation`:\n * the org automations placed across the organization's sites, and every\n * site's own workflows, actions and webhooks side by side. The same page\n * component, mounted with no site; the site tab's release flag gates both\n * levels, so one flag rolls the surface out at once.\n */\n orgNavItems: [\n {\n label: 'Automation',\n href: '/automation',\n sections: WORKFLOWS_ORG_CONSOLE_SECTIONS,\n navTabId: 'nav-tab-workflows',\n icon: { path: mdiSitemap.path },\n header: {\n title: 'Automation',\n icon: { path: mdiSitemap.path },\n docsTopic: 'workflows',\n },\n Component: WorkflowsConsolePage,\n },\n ],\n })\n}\n\n// Activity feed consumed directly by the app (dashboard + screen view).\nexport { default as HostActivityCard } from './components/host-activity-card.component'\nexport type { HostActivityCardProps } from './components/host-activity-card.component'\n"],"names":["Aglyn","mdiSitemap","lazy","HostActivityCard","StaffOrgAutomationsCard","StaffSiteAutomationsCard","WORKFLOWS_CONSOLE_SECTIONS","WORKFLOWS_ORG_CONSOLE_SECTIONS","registerPluginZone","registerPluginTransferResourceUi","AUTOMATION_EDITOR_ZONE","AUTOMATION_RUN_ZONE","HOST_AUTOMATIONS_ZONE","ORG_AUTOMATIONS_ZONE","WORKFLOW_USAGE_ZONE","BUNDLE_ID","registerWorkflowsRecordLists","registerWorkflowsRecordRoutes","WORKFLOWS_SEARCH_SOURCES","WorkflowsConsolePage","registerWorkflowsConsole","label","icon","path","pluginId","zone","surface","description","layout","registerConsoleExtension","widgets","slot","widgetId","title","Component","CONSOLE_WIDGET_SLOTS","staffSite","adminOrgDetail","displayName","featureFlag","searchSources","navItems","href","sections","navTabId","header","docsTopic","orgNavItems","default"],"mappings":"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"}
|
|
@@ -0,0 +1,38 @@
|
|
|
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
|
+
import { type PluginFigureReader } from '@aglyn/aglyn/plugin-manager/plugin-figures';
|
|
18
|
+
/**
|
|
19
|
+
* A site's automation runs as a figure table another plugin reads by id
|
|
20
|
+
* (AGL-3603) — the AI plugin's insights answer "which automations failed?"
|
|
21
|
+
* from it.
|
|
22
|
+
*
|
|
23
|
+
* Every run an action, a workflow or an organization automation makes is a
|
|
24
|
+
* row in the site's activity log carrying `result` (`succeeded` or `failed`)
|
|
25
|
+
* and `target` — the same rows the run history lists. The totals are COUNT
|
|
26
|
+
* aggregates over `result` in the window (the `activity` composite on
|
|
27
|
+
* `result` + `createdAt`), so they are exact however busy the site is; the
|
|
28
|
+
* per-automation split reads at most `AUTOMATION_RUN_FIGURES_WINDOW_CEILING`
|
|
29
|
+
* runs of each result, projected to `target`, and says so when that read
|
|
30
|
+
* low. A run's event payload names a person and is never read.
|
|
31
|
+
*/
|
|
32
|
+
type Firestore = FirebaseFirestore.Firestore;
|
|
33
|
+
/** Runs of one result one window reads for the per-automation split. */
|
|
34
|
+
export declare const AUTOMATION_RUN_FIGURES_WINDOW_CEILING = 500;
|
|
35
|
+
export declare function automationRunFigureReader(firestore: () => Firestore): PluginFigureReader;
|
|
36
|
+
/** Registers the automation runs reader from the console surface, where insight jobs run. */
|
|
37
|
+
export declare function registerAutomationRunFigureReader(firestore: () => Firestore): void;
|
|
38
|
+
export {};
|
|
@@ -0,0 +1,182 @@
|
|
|
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
|
+
*/ import { PLUGIN_FIGURE_MAX_ROWS, pluginFigureChange, pluginFigureWindows, registerPluginFigureReader } from "@aglyn/aglyn/plugin-manager/plugin-figures";
|
|
17
|
+
import { BUNDLE_ID } from "../constants/bundle-common.js";
|
|
18
|
+
/** Runs of one result one window reads for the per-automation split. */ export const AUTOMATION_RUN_FIGURES_WINDOW_CEILING = 500;
|
|
19
|
+
const WINDOWS = [
|
|
20
|
+
7,
|
|
21
|
+
14,
|
|
22
|
+
30,
|
|
23
|
+
90
|
|
24
|
+
];
|
|
25
|
+
function runsOf(firestore, hostId, result, startMs, endMs) {
|
|
26
|
+
return firestore.collection('hosts').doc(hostId).collection('activity').where('result', '==', result).where('createdAt', '>=', new Date(startMs)).where('createdAt', '<', new Date(endMs));
|
|
27
|
+
}
|
|
28
|
+
async function countOf(query) {
|
|
29
|
+
const snapshot = await query.count().get();
|
|
30
|
+
return Number(snapshot.data().count) || 0;
|
|
31
|
+
}
|
|
32
|
+
/** Runs of one result in the window, by the automation they belong to, read to the ceiling. */ async function byAutomation(query) {
|
|
33
|
+
const snapshot = await query.orderBy('createdAt', 'desc').select('target').limit(AUTOMATION_RUN_FIGURES_WINDOW_CEILING + 1).get();
|
|
34
|
+
const names = new Map();
|
|
35
|
+
for (const doc of snapshot.docs.slice(0, AUTOMATION_RUN_FIGURES_WINDOW_CEILING)){
|
|
36
|
+
var _doc_get, _names_get;
|
|
37
|
+
const target = (_doc_get = doc.get('target')) != null ? _doc_get : {};
|
|
38
|
+
const name = typeof target.name === 'string' && target.name.trim() || 'An automation with no name';
|
|
39
|
+
names.set(name, ((_names_get = names.get(name)) != null ? _names_get : 0) + 1);
|
|
40
|
+
}
|
|
41
|
+
return {
|
|
42
|
+
names,
|
|
43
|
+
truncated: snapshot.docs.length > AUTOMATION_RUN_FIGURES_WINDOW_CEILING
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
const failureRate = (counts)=>{
|
|
47
|
+
const total = counts.succeeded + counts.failed;
|
|
48
|
+
return total > 0 ? Math.round(counts.failed / total * 1000) / 10 : null;
|
|
49
|
+
};
|
|
50
|
+
export function automationRunFigureReader(firestore) {
|
|
51
|
+
return {
|
|
52
|
+
id: 'automations.runs',
|
|
53
|
+
label: 'Automation runs',
|
|
54
|
+
description: 'Runs of the site’s automations — actions, workflows and organization automations — over the window: how many succeeded and failed, the failure rate, and the change in runs from the window before, in total and by automation.',
|
|
55
|
+
scope: 'site',
|
|
56
|
+
windows: WINDOWS,
|
|
57
|
+
read: async (request)=>{
|
|
58
|
+
if (!request.hostId) return {
|
|
59
|
+
ok: false,
|
|
60
|
+
status: 400,
|
|
61
|
+
error: 'Open a site to read its automation runs'
|
|
62
|
+
};
|
|
63
|
+
if (!WINDOWS.includes(request.days)) {
|
|
64
|
+
return {
|
|
65
|
+
ok: false,
|
|
66
|
+
status: 400,
|
|
67
|
+
error: 'That window is not one automation runs are read over'
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
const db = firestore();
|
|
71
|
+
const hostId = request.hostId;
|
|
72
|
+
const { current, previous } = pluginFigureWindows(request.now, request.days);
|
|
73
|
+
const [succeeded, failed, before, okRuns, failedRuns] = await Promise.all([
|
|
74
|
+
countOf(runsOf(db, hostId, 'succeeded', current.startMs, current.endMs)),
|
|
75
|
+
countOf(runsOf(db, hostId, 'failed', current.startMs, current.endMs)),
|
|
76
|
+
Promise.all([
|
|
77
|
+
countOf(runsOf(db, hostId, 'succeeded', previous.startMs, previous.endMs)),
|
|
78
|
+
countOf(runsOf(db, hostId, 'failed', previous.startMs, previous.endMs))
|
|
79
|
+
]).then(([a, b])=>a + b),
|
|
80
|
+
byAutomation(runsOf(db, hostId, 'succeeded', current.startMs, current.endMs)),
|
|
81
|
+
byAutomation(runsOf(db, hostId, 'failed', current.startMs, current.endMs))
|
|
82
|
+
]);
|
|
83
|
+
const automations = new Map();
|
|
84
|
+
for (const [name, count] of okRuns.names){
|
|
85
|
+
var _ref;
|
|
86
|
+
var _automations_get;
|
|
87
|
+
automations.set(name, {
|
|
88
|
+
succeeded: count,
|
|
89
|
+
failed: (_ref = (_automations_get = automations.get(name)) == null ? void 0 : _automations_get.failed) != null ? _ref : 0
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
for (const [name, count] of failedRuns.names){
|
|
93
|
+
var _ref1;
|
|
94
|
+
var _automations_get1;
|
|
95
|
+
automations.set(name, {
|
|
96
|
+
succeeded: (_ref1 = (_automations_get1 = automations.get(name)) == null ? void 0 : _automations_get1.succeeded) != null ? _ref1 : 0,
|
|
97
|
+
failed: count
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
// The most failures first: that is the question a person asks of runs.
|
|
101
|
+
const ranked = [
|
|
102
|
+
...automations.entries()
|
|
103
|
+
].sort((a, b)=>b[1].failed - a[1].failed || b[1].succeeded - a[1].succeeded || a[0].localeCompare(b[0]));
|
|
104
|
+
const totals = {
|
|
105
|
+
succeeded,
|
|
106
|
+
failed
|
|
107
|
+
};
|
|
108
|
+
return {
|
|
109
|
+
ok: true,
|
|
110
|
+
table: {
|
|
111
|
+
title: 'Automation runs',
|
|
112
|
+
source: {
|
|
113
|
+
label: 'Automation',
|
|
114
|
+
path: 'automation'
|
|
115
|
+
},
|
|
116
|
+
period: {
|
|
117
|
+
from: current.from,
|
|
118
|
+
to: current.to,
|
|
119
|
+
days: request.days
|
|
120
|
+
},
|
|
121
|
+
columns: [
|
|
122
|
+
{
|
|
123
|
+
key: 'automation',
|
|
124
|
+
label: 'Automation',
|
|
125
|
+
kind: 'text'
|
|
126
|
+
},
|
|
127
|
+
{
|
|
128
|
+
key: 'succeeded',
|
|
129
|
+
label: 'Succeeded',
|
|
130
|
+
kind: 'count'
|
|
131
|
+
},
|
|
132
|
+
{
|
|
133
|
+
key: 'failed',
|
|
134
|
+
label: 'Failed',
|
|
135
|
+
kind: 'count'
|
|
136
|
+
},
|
|
137
|
+
{
|
|
138
|
+
key: 'failureRate',
|
|
139
|
+
label: 'Failure rate',
|
|
140
|
+
kind: 'percent'
|
|
141
|
+
},
|
|
142
|
+
{
|
|
143
|
+
key: 'change',
|
|
144
|
+
label: 'Change in runs',
|
|
145
|
+
kind: 'change'
|
|
146
|
+
}
|
|
147
|
+
],
|
|
148
|
+
rows: [
|
|
149
|
+
{
|
|
150
|
+
automation: 'All automations',
|
|
151
|
+
succeeded,
|
|
152
|
+
failed,
|
|
153
|
+
failureRate: failureRate(totals),
|
|
154
|
+
change: pluginFigureChange(succeeded + failed, before)
|
|
155
|
+
},
|
|
156
|
+
...ranked.slice(0, PLUGIN_FIGURE_MAX_ROWS - 1).map(([automation, counts])=>({
|
|
157
|
+
automation,
|
|
158
|
+
succeeded: counts.succeeded,
|
|
159
|
+
failed: counts.failed,
|
|
160
|
+
failureRate: failureRate(counts),
|
|
161
|
+
change: null
|
|
162
|
+
}))
|
|
163
|
+
],
|
|
164
|
+
omitted: Math.max(0, ranked.length - (PLUGIN_FIGURE_MAX_ROWS - 1)),
|
|
165
|
+
notes: [
|
|
166
|
+
'A run is counted on the day it ran. A run waiting on a later step counts as succeeded so far.',
|
|
167
|
+
...okRuns.truncated || failedRuns.truncated ? [
|
|
168
|
+
`The split by automation counts the most recent ${AUTOMATION_RUN_FIGURES_WINDOW_CEILING.toLocaleString('en-US')} runs of each result; the All automations row counts every run.`
|
|
169
|
+
] : []
|
|
170
|
+
]
|
|
171
|
+
}
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
/** Registers the automation runs reader from the console surface, where insight jobs run. */ export function registerAutomationRunFigureReader(firestore) {
|
|
177
|
+
registerPluginFigureReader(automationRunFigureReader(firestore), {
|
|
178
|
+
pluginId: BUNDLE_ID
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
//# sourceMappingURL=automation-run-figures.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/plugins/workflows/src/lib/server/automation-run-figures.ts"],"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\nimport {\n PLUGIN_FIGURE_MAX_ROWS,\n pluginFigureChange,\n pluginFigureWindows,\n registerPluginFigureReader,\n type PluginFigureReader,\n} from '@aglyn/aglyn/plugin-manager/plugin-figures'\nimport { BUNDLE_ID } from '../constants/bundle-common'\n\n/**\n * A site's automation runs as a figure table another plugin reads by id\n * (AGL-3603) — the AI plugin's insights answer \"which automations failed?\"\n * from it.\n *\n * Every run an action, a workflow or an organization automation makes is a\n * row in the site's activity log carrying `result` (`succeeded` or `failed`)\n * and `target` — the same rows the run history lists. The totals are COUNT\n * aggregates over `result` in the window (the `activity` composite on\n * `result` + `createdAt`), so they are exact however busy the site is; the\n * per-automation split reads at most `AUTOMATION_RUN_FIGURES_WINDOW_CEILING`\n * runs of each result, projected to `target`, and says so when that read\n * low. A run's event payload names a person and is never read.\n */\n\ntype Firestore = FirebaseFirestore.Firestore\n\n/** Runs of one result one window reads for the per-automation split. */\nexport const AUTOMATION_RUN_FIGURES_WINDOW_CEILING = 500\n\nconst WINDOWS: readonly number[] = [7, 14, 30, 90]\n\ninterface AutomationCounts {\n succeeded: number\n failed: number\n}\n\nfunction runsOf(\n firestore: Firestore,\n hostId: string,\n result: 'succeeded' | 'failed',\n startMs: number,\n endMs: number,\n): FirebaseFirestore.Query {\n return firestore\n .collection('hosts')\n .doc(hostId)\n .collection('activity')\n .where('result', '==', result)\n .where('createdAt', '>=', new Date(startMs))\n .where('createdAt', '<', new Date(endMs))\n}\n\nasync function countOf(query: FirebaseFirestore.Query): Promise<number> {\n const snapshot = await query.count().get()\n return Number(snapshot.data().count) || 0\n}\n\n/** Runs of one result in the window, by the automation they belong to, read to the ceiling. */\nasync function byAutomation(\n query: FirebaseFirestore.Query,\n): Promise<{ names: Map<string, number>; truncated: boolean }> {\n const snapshot = await query\n .orderBy('createdAt', 'desc')\n .select('target')\n .limit(AUTOMATION_RUN_FIGURES_WINDOW_CEILING + 1)\n .get()\n const names = new Map<string, number>()\n for (const doc of snapshot.docs.slice(0, AUTOMATION_RUN_FIGURES_WINDOW_CEILING)) {\n const target = (doc.get('target') ?? {}) as { name?: unknown; id?: unknown }\n const name =\n (typeof target.name === 'string' && target.name.trim()) || 'An automation with no name'\n names.set(name, (names.get(name) ?? 0) + 1)\n }\n return { names, truncated: snapshot.docs.length > AUTOMATION_RUN_FIGURES_WINDOW_CEILING }\n}\n\nconst failureRate = (counts: AutomationCounts): number | null => {\n const total = counts.succeeded + counts.failed\n return total > 0 ? Math.round((counts.failed / total) * 1_000) / 10 : null\n}\n\nexport function automationRunFigureReader(firestore: () => Firestore): PluginFigureReader {\n return {\n id: 'automations.runs',\n label: 'Automation runs',\n description:\n 'Runs of the site’s automations — actions, workflows and organization automations — over the window: how many succeeded and failed, the failure rate, and the change in runs from the window before, in total and by automation.',\n scope: 'site',\n windows: WINDOWS,\n read: async (request) => {\n if (!request.hostId) return { ok: false, status: 400, error: 'Open a site to read its automation runs' }\n if (!WINDOWS.includes(request.days)) {\n return { ok: false, status: 400, error: 'That window is not one automation runs are read over' }\n }\n const db = firestore()\n const hostId = request.hostId\n const { current, previous } = pluginFigureWindows(request.now, request.days)\n const [succeeded, failed, before, okRuns, failedRuns] = await Promise.all([\n countOf(runsOf(db, hostId, 'succeeded', current.startMs, current.endMs)),\n countOf(runsOf(db, hostId, 'failed', current.startMs, current.endMs)),\n Promise.all([\n countOf(runsOf(db, hostId, 'succeeded', previous.startMs, previous.endMs)),\n countOf(runsOf(db, hostId, 'failed', previous.startMs, previous.endMs)),\n ]).then(([a, b]) => a + b),\n byAutomation(runsOf(db, hostId, 'succeeded', current.startMs, current.endMs)),\n byAutomation(runsOf(db, hostId, 'failed', current.startMs, current.endMs)),\n ])\n const automations = new Map<string, AutomationCounts>()\n for (const [name, count] of okRuns.names) {\n automations.set(name, { succeeded: count, failed: automations.get(name)?.failed ?? 0 })\n }\n for (const [name, count] of failedRuns.names) {\n automations.set(name, { succeeded: automations.get(name)?.succeeded ?? 0, failed: count })\n }\n // The most failures first: that is the question a person asks of runs.\n const ranked = [...automations.entries()].sort(\n (a, b) => b[1].failed - a[1].failed || b[1].succeeded - a[1].succeeded || a[0].localeCompare(b[0]),\n )\n const totals = { succeeded, failed }\n return {\n ok: true,\n table: {\n title: 'Automation runs',\n source: { label: 'Automation', path: 'automation' },\n period: { from: current.from, to: current.to, days: request.days },\n columns: [\n { key: 'automation', label: 'Automation', kind: 'text' },\n { key: 'succeeded', label: 'Succeeded', kind: 'count' },\n { key: 'failed', label: 'Failed', kind: 'count' },\n { key: 'failureRate', label: 'Failure rate', kind: 'percent' },\n { key: 'change', label: 'Change in runs', kind: 'change' },\n ],\n rows: [\n {\n automation: 'All automations',\n succeeded,\n failed,\n failureRate: failureRate(totals),\n change: pluginFigureChange(succeeded + failed, before),\n },\n ...ranked.slice(0, PLUGIN_FIGURE_MAX_ROWS - 1).map(([automation, counts]) => ({\n automation,\n succeeded: counts.succeeded,\n failed: counts.failed,\n failureRate: failureRate(counts),\n change: null,\n })),\n ],\n omitted: Math.max(0, ranked.length - (PLUGIN_FIGURE_MAX_ROWS - 1)),\n notes: [\n 'A run is counted on the day it ran. A run waiting on a later step counts as succeeded so far.',\n ...(okRuns.truncated || failedRuns.truncated\n ? [\n `The split by automation counts the most recent ${AUTOMATION_RUN_FIGURES_WINDOW_CEILING.toLocaleString('en-US')} runs of each result; the All automations row counts every run.`,\n ]\n : []),\n ],\n },\n }\n },\n }\n}\n\n/** Registers the automation runs reader from the console surface, where insight jobs run. */\nexport function registerAutomationRunFigureReader(firestore: () => Firestore): void {\n registerPluginFigureReader(automationRunFigureReader(firestore), { pluginId: BUNDLE_ID })\n}\n"],"names":["PLUGIN_FIGURE_MAX_ROWS","pluginFigureChange","pluginFigureWindows","registerPluginFigureReader","BUNDLE_ID","AUTOMATION_RUN_FIGURES_WINDOW_CEILING","WINDOWS","runsOf","firestore","hostId","result","startMs","endMs","collection","doc","where","Date","countOf","query","snapshot","count","get","Number","data","byAutomation","orderBy","select","limit","names","Map","docs","slice","target","name","trim","set","truncated","length","failureRate","counts","total","succeeded","failed","Math","round","automationRunFigureReader","id","label","description","scope","windows","read","request","ok","status","error","includes","days","db","current","previous","now","before","okRuns","failedRuns","Promise","all","then","a","b","automations","ranked","entries","sort","localeCompare","totals","table","title","source","path","period","from","to","columns","key","kind","rows","automation","change","map","omitted","max","notes","toLocaleString","registerAutomationRunFigureReader","pluginId"],"mappings":"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"}
|
|
@@ -14,10 +14,12 @@
|
|
|
14
14
|
* See the License for the specific language governing permissions and
|
|
15
15
|
* limitations under the License.
|
|
16
16
|
*/ import { registerPluginApiRoute } from "@aglyn/aglyn/server";
|
|
17
|
+
import { firebaseAdmin } from "@aglyn/tenant-data-admin/server/firebase-admin";
|
|
17
18
|
import { registerWorkflowsServerDeclarations } from "./declarations.server.js";
|
|
18
19
|
import { registerAutomationDraftWriter } from "./server-automation-drafts.js";
|
|
19
20
|
import { ACTION_TEST_RUN_API_ROUTE, actionTestRunHandler } from "./server/action-test-run-route.js";
|
|
20
21
|
import { ORG_AUTOMATION_API_ROUTES, orgAutomationPauseHandler, orgAutomationsManageHandler, orgAutomationsManageSubject } from "./server/org-automations-routes.js";
|
|
22
|
+
import { registerAutomationRunFigureReader } from "./server/automation-run-figures.js";
|
|
21
23
|
/**
|
|
22
24
|
* The workflows plugin's console server surface (AGL-2919).
|
|
23
25
|
*
|
|
@@ -43,6 +45,9 @@ import { ORG_AUTOMATION_API_ROUTES, orgAutomationPauseHandler, orgAutomationsMan
|
|
|
43
45
|
registerPluginApiRoute(ORG_AUTOMATION_API_ROUTES.pause, orgAutomationPauseHandler);
|
|
44
46
|
// So does a test run: a site with Automation switched off has no such door.
|
|
45
47
|
registerPluginApiRoute(ACTION_TEST_RUN_API_ROUTE, actionTestRunHandler);
|
|
48
|
+
// Automation runs as a figure table (AGL-3603), for the AI plugin's
|
|
49
|
+
// insights to read by id; the console runs insight jobs.
|
|
50
|
+
registerAutomationRunFigureReader(()=>firebaseAdmin.app().firestore());
|
|
46
51
|
}
|
|
47
52
|
|
|
48
53
|
//# sourceMappingURL=server-console.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../libs/plugins/workflows/src/lib/server-console.ts"],"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\nimport { registerPluginApiRoute } from '@aglyn/aglyn/server'\nimport { registerWorkflowsServerDeclarations } from './declarations.server'\nimport { registerAutomationDraftWriter } from './server-automation-drafts'\nimport {\n ACTION_TEST_RUN_API_ROUTE,\n actionTestRunHandler,\n} from './server/action-test-run-route'\nimport {\n ORG_AUTOMATION_API_ROUTES,\n orgAutomationPauseHandler,\n orgAutomationsManageHandler,\n orgAutomationsManageSubject,\n} from './server/org-automations-routes'\n\n/**\n * The workflows plugin's console server surface (AGL-2919).\n *\n * The tenant surface (`registerWorkflowsApi`) serves the inbound webhook a\n * visitor-facing integration calls. This one serves what only the console\n * does: the automation draft writer another plugin reaches through the core's\n * resource-drafts seam, which the AI jobs that write through it — inline at a\n * door and on the beat — find registered in the console process alone\n * (AGL-3026); the doors that write the organization's automations\n * (AGL-3302); and the Actions card's test run (AGL-3309).\n */\nexport function registerWorkflowsConsoleApi(): void {\n // The console raises host events too — a CRM stage moved, a deal won, a\n // task completed — so the engine's listener is registered here as well as\n // at boot (see `declarations.server.ts`).\n registerWorkflowsServerDeclarations()\n registerAutomationDraftWriter()\n // The organization hub names its org and no site, so the route names that\n // org as its subject for the release gate.\n registerPluginApiRoute(\n ORG_AUTOMATION_API_ROUTES.manage,\n orgAutomationsManageHandler,\n { subject: orgAutomationsManageSubject },\n )\n // A site's own pause names the site, and is gated by that site's switch.\n registerPluginApiRoute(ORG_AUTOMATION_API_ROUTES.pause, orgAutomationPauseHandler)\n // So does a test run: a site with Automation switched off has no such door.\n registerPluginApiRoute(ACTION_TEST_RUN_API_ROUTE, actionTestRunHandler)\n}\n"],"names":["registerPluginApiRoute","registerWorkflowsServerDeclarations","registerAutomationDraftWriter","ACTION_TEST_RUN_API_ROUTE","actionTestRunHandler","ORG_AUTOMATION_API_ROUTES","orgAutomationPauseHandler","orgAutomationsManageHandler","orgAutomationsManageSubject","registerWorkflowsConsoleApi","manage","subject","pause"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GAED,SAASA,sBAAsB,QAAQ,sBAAqB;AAC5D,SAASC,mCAAmC,QAAQ,2BAAuB;AAC3E,SAASC,6BAA6B,QAAQ,gCAA4B;AAC1E,SACEC,yBAAyB,EACzBC,oBAAoB,QACf,oCAAgC;AACvC,SACEC,yBAAyB,EACzBC,yBAAyB,EACzBC,2BAA2B,EAC3BC,2BAA2B,QACtB,qCAAiC;
|
|
1
|
+
{"version":3,"sources":["../../../../../../libs/plugins/workflows/src/lib/server-console.ts"],"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\nimport { registerPluginApiRoute } from '@aglyn/aglyn/server'\nimport { firebaseAdmin } from '@aglyn/tenant-data-admin/server/firebase-admin'\nimport { registerWorkflowsServerDeclarations } from './declarations.server'\nimport { registerAutomationDraftWriter } from './server-automation-drafts'\nimport {\n ACTION_TEST_RUN_API_ROUTE,\n actionTestRunHandler,\n} from './server/action-test-run-route'\nimport {\n ORG_AUTOMATION_API_ROUTES,\n orgAutomationPauseHandler,\n orgAutomationsManageHandler,\n orgAutomationsManageSubject,\n} from './server/org-automations-routes'\nimport { registerAutomationRunFigureReader } from './server/automation-run-figures'\n\n/**\n * The workflows plugin's console server surface (AGL-2919).\n *\n * The tenant surface (`registerWorkflowsApi`) serves the inbound webhook a\n * visitor-facing integration calls. This one serves what only the console\n * does: the automation draft writer another plugin reaches through the core's\n * resource-drafts seam, which the AI jobs that write through it — inline at a\n * door and on the beat — find registered in the console process alone\n * (AGL-3026); the doors that write the organization's automations\n * (AGL-3302); and the Actions card's test run (AGL-3309).\n */\nexport function registerWorkflowsConsoleApi(): void {\n // The console raises host events too — a CRM stage moved, a deal won, a\n // task completed — so the engine's listener is registered here as well as\n // at boot (see `declarations.server.ts`).\n registerWorkflowsServerDeclarations()\n registerAutomationDraftWriter()\n // The organization hub names its org and no site, so the route names that\n // org as its subject for the release gate.\n registerPluginApiRoute(\n ORG_AUTOMATION_API_ROUTES.manage,\n orgAutomationsManageHandler,\n { subject: orgAutomationsManageSubject },\n )\n // A site's own pause names the site, and is gated by that site's switch.\n registerPluginApiRoute(ORG_AUTOMATION_API_ROUTES.pause, orgAutomationPauseHandler)\n // So does a test run: a site with Automation switched off has no such door.\n registerPluginApiRoute(ACTION_TEST_RUN_API_ROUTE, actionTestRunHandler)\n // Automation runs as a figure table (AGL-3603), for the AI plugin's\n // insights to read by id; the console runs insight jobs.\n registerAutomationRunFigureReader(() => firebaseAdmin.app().firestore())\n}\n"],"names":["registerPluginApiRoute","firebaseAdmin","registerWorkflowsServerDeclarations","registerAutomationDraftWriter","ACTION_TEST_RUN_API_ROUTE","actionTestRunHandler","ORG_AUTOMATION_API_ROUTES","orgAutomationPauseHandler","orgAutomationsManageHandler","orgAutomationsManageSubject","registerAutomationRunFigureReader","registerWorkflowsConsoleApi","manage","subject","pause","app","firestore"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GAED,SAASA,sBAAsB,QAAQ,sBAAqB;AAC5D,SAASC,aAAa,QAAQ,iDAAgD;AAC9E,SAASC,mCAAmC,QAAQ,2BAAuB;AAC3E,SAASC,6BAA6B,QAAQ,gCAA4B;AAC1E,SACEC,yBAAyB,EACzBC,oBAAoB,QACf,oCAAgC;AACvC,SACEC,yBAAyB,EACzBC,yBAAyB,EACzBC,2BAA2B,EAC3BC,2BAA2B,QACtB,qCAAiC;AACxC,SAASC,iCAAiC,QAAQ,qCAAiC;AAEnF;;;;;;;;;;CAUC,GACD,OAAO,SAASC;IACd,wEAAwE;IACxE,0EAA0E;IAC1E,0CAA0C;IAC1CT;IACAC;IACA,0EAA0E;IAC1E,2CAA2C;IAC3CH,uBACEM,0BAA0BM,MAAM,EAChCJ,6BACA;QAAEK,SAASJ;IAA4B;IAEzC,yEAAyE;IACzET,uBAAuBM,0BAA0BQ,KAAK,EAAEP;IACxD,4EAA4E;IAC5EP,uBAAuBI,2BAA2BC;IAClD,oEAAoE;IACpE,yDAAyD;IACzDK,kCAAkC,IAAMT,cAAcc,GAAG,GAAGC,SAAS;AACvE"}
|