@revenexx/studio-integrations 0.5.1 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (171) hide show
  1. package/CHANGELOG.md +428 -0
  2. package/README.md +48 -4
  3. package/dist/module.d.mts +17 -1
  4. package/dist/module.json +1 -1
  5. package/dist/module.mjs +10 -2
  6. package/dist/runtime/components/Integrations/CredentialCreateDialog.vue +43 -41
  7. package/dist/runtime/components/Integrations/CredentialDetailDialog.vue +123 -50
  8. package/dist/runtime/components/Integrations/CredentialRevenexxSource.vue +108 -71
  9. package/dist/runtime/components/Integrations/CredentialTypePicker.vue +12 -15
  10. package/dist/runtime/components/Integrations/DeadLettersPanel.vue +18 -17
  11. package/dist/runtime/components/Integrations/EventTypeCombobox.d.vue.ts +1 -0
  12. package/dist/runtime/components/Integrations/EventTypeCombobox.vue +7 -4
  13. package/dist/runtime/components/Integrations/EventTypeCombobox.vue.d.ts +1 -0
  14. package/dist/runtime/components/Integrations/ExpressionInput.d.vue.ts +4 -0
  15. package/dist/runtime/components/Integrations/ExpressionInput.vue +67 -37
  16. package/dist/runtime/components/Integrations/ExpressionInput.vue.d.ts +4 -0
  17. package/dist/runtime/components/Integrations/GroupFrameView.vue +30 -20
  18. package/dist/runtime/components/Integrations/Layout.vue +48 -4
  19. package/dist/runtime/components/Integrations/NodeConfigDynamicField.vue +23 -23
  20. package/dist/runtime/components/Integrations/NodeConfigDynamicSchema.vue +11 -13
  21. package/dist/runtime/components/Integrations/NodeConfigField.d.vue.ts +2 -0
  22. package/dist/runtime/components/Integrations/NodeConfigField.vue +187 -93
  23. package/dist/runtime/components/Integrations/NodeConfigField.vue.d.ts +2 -0
  24. package/dist/runtime/components/Integrations/NodeInspector.d.vue.ts +6 -0
  25. package/dist/runtime/components/Integrations/NodeInspector.vue +1157 -376
  26. package/dist/runtime/components/Integrations/NodeInspector.vue.d.ts +6 -0
  27. package/dist/runtime/components/Integrations/NodeLogo.d.vue.ts +12 -0
  28. package/dist/runtime/components/Integrations/NodeLogo.vue +2 -30
  29. package/dist/runtime/components/Integrations/NodeLogo.vue.d.ts +12 -0
  30. package/dist/runtime/components/Integrations/NodeMark.d.vue.ts +15 -0
  31. package/dist/runtime/components/Integrations/NodeMark.vue +79 -0
  32. package/dist/runtime/components/Integrations/NodeMark.vue.d.ts +15 -0
  33. package/dist/runtime/components/Integrations/NodeOutputSchema.d.vue.ts +21 -0
  34. package/dist/runtime/components/Integrations/NodeOutputSchema.vue +43 -0
  35. package/dist/runtime/components/Integrations/NodeOutputSchema.vue.d.ts +21 -0
  36. package/dist/runtime/components/Integrations/NodePalette.vue +122 -55
  37. package/dist/runtime/components/Integrations/QueryBuilder.vue +46 -38
  38. package/dist/runtime/components/Integrations/RunActionsMenu.vue +38 -12
  39. package/dist/runtime/components/Integrations/RunDetailPanel.vue +114 -62
  40. package/dist/runtime/components/Integrations/RunPayloadInput.vue +27 -13
  41. package/dist/runtime/components/Integrations/RunResponseModal.vue +11 -10
  42. package/dist/runtime/components/Integrations/RunsTable.d.vue.ts +0 -1
  43. package/dist/runtime/components/Integrations/RunsTable.vue +38 -16
  44. package/dist/runtime/components/Integrations/RunsTable.vue.d.ts +0 -1
  45. package/dist/runtime/components/Integrations/SftpAccountImportDialog.vue +8 -7
  46. package/dist/runtime/components/Integrations/Sidebar.vue +14 -10
  47. package/dist/runtime/components/Integrations/StickyNoteView.d.vue.ts +14 -4
  48. package/dist/runtime/components/Integrations/StickyNoteView.vue +38 -23
  49. package/dist/runtime/components/Integrations/StickyNoteView.vue.d.ts +14 -4
  50. package/dist/runtime/components/Integrations/TemplateCard.d.vue.ts +18 -0
  51. package/dist/runtime/components/Integrations/TemplateCard.vue +119 -0
  52. package/dist/runtime/components/Integrations/TemplateCard.vue.d.ts +18 -0
  53. package/dist/runtime/components/Integrations/TemplateFlowPreview.d.vue.ts +2 -2
  54. package/dist/runtime/components/Integrations/TemplateFlowPreview.vue +16 -18
  55. package/dist/runtime/components/Integrations/TemplateFlowPreview.vue.d.ts +2 -2
  56. package/dist/runtime/components/Integrations/WorkflowContextMenu.vue +34 -33
  57. package/dist/runtime/components/Integrations/WorkflowCreateDialog.vue +52 -67
  58. package/dist/runtime/components/Integrations/WorkflowDuplicateDialog.vue +8 -7
  59. package/dist/runtime/components/Integrations/WorkflowEdgeView.d.vue.ts +18 -4
  60. package/dist/runtime/components/Integrations/WorkflowEdgeView.vue +29 -11
  61. package/dist/runtime/components/Integrations/WorkflowEdgeView.vue.d.ts +18 -4
  62. package/dist/runtime/components/Integrations/WorkflowEditor.d.vue.ts +20 -1
  63. package/dist/runtime/components/Integrations/WorkflowEditor.vue +240 -116
  64. package/dist/runtime/components/Integrations/WorkflowEditor.vue.d.ts +20 -1
  65. package/dist/runtime/components/Integrations/WorkflowHistoryPanel.vue +28 -43
  66. package/dist/runtime/components/Integrations/WorkflowIconPicker.d.vue.ts +19 -1
  67. package/dist/runtime/components/Integrations/WorkflowIconPicker.vue +17 -7
  68. package/dist/runtime/components/Integrations/WorkflowIconPicker.vue.d.ts +19 -1
  69. package/dist/runtime/components/Integrations/WorkflowNodeView.d.vue.ts +4 -0
  70. package/dist/runtime/components/Integrations/WorkflowNodeView.vue +198 -56
  71. package/dist/runtime/components/Integrations/WorkflowNodeView.vue.d.ts +4 -0
  72. package/dist/runtime/components/Integrations/WorkflowRunReplayPanel.vue +56 -59
  73. package/dist/runtime/components/Integrations/WorkflowSettingsDialog.vue +28 -21
  74. package/dist/runtime/components/Integrations/WorkflowTagsInput.d.vue.ts +1 -0
  75. package/dist/runtime/components/Integrations/WorkflowTagsInput.vue +15 -9
  76. package/dist/runtime/components/Integrations/WorkflowTagsInput.vue.d.ts +1 -0
  77. package/dist/runtime/components/Integrations/WorkflowTriggerView.vue +15 -10
  78. package/dist/runtime/components/Integrations/WorkflowVariablesDialog.vue +50 -36
  79. package/dist/runtime/components/Integrations/WorkflowsTable.vue +126 -48
  80. package/dist/runtime/composables/integrationsApi.js +4 -2
  81. package/dist/runtime/composables/useCredentialTypes.js +8 -6
  82. package/dist/runtime/composables/useIntegrationsAudit.js +4 -3
  83. package/dist/runtime/composables/useIntegrationsCredentials.js +10 -8
  84. package/dist/runtime/composables/useIntegrationsDeadLetters.js +7 -6
  85. package/dist/runtime/composables/useIntegrationsFocus.d.ts +12 -0
  86. package/dist/runtime/composables/useIntegrationsLocale.d.ts +26 -0
  87. package/dist/runtime/composables/useIntegrationsLocale.js +8 -0
  88. package/dist/runtime/composables/useIntegrationsNodes.js +7 -5
  89. package/dist/runtime/composables/useIntegrationsRealtime.d.ts +149 -0
  90. package/dist/runtime/composables/useIntegrationsRealtime.js +80 -0
  91. package/dist/runtime/composables/useIntegrationsRevisions.js +9 -7
  92. package/dist/runtime/composables/useIntegrationsRuns.d.ts +1 -1
  93. package/dist/runtime/composables/useIntegrationsRuns.js +14 -7
  94. package/dist/runtime/composables/useIntegrationsSchedules.d.ts +4 -0
  95. package/dist/runtime/composables/useIntegrationsSchedules.js +10 -3
  96. package/dist/runtime/composables/useIntegrationsSecrets.js +14 -9
  97. package/dist/runtime/composables/useIntegrationsT.d.ts +35 -0
  98. package/dist/runtime/composables/useIntegrationsT.js +9 -0
  99. package/dist/runtime/composables/useIntegrationsTemplates.d.ts +3 -3
  100. package/dist/runtime/composables/useIntegrationsTemplates.js +28 -16
  101. package/dist/runtime/composables/useIntegrationsTriggers.js +10 -8
  102. package/dist/runtime/composables/useIntegrationsWorkflows.js +13 -7
  103. package/dist/runtime/composables/useLoadGate.d.ts +17 -0
  104. package/dist/runtime/composables/useLoadGate.js +8 -0
  105. package/dist/runtime/composables/useNodeConfigResolve.js +2 -1
  106. package/dist/runtime/data/branchReorder.d.ts +37 -0
  107. package/dist/runtime/data/branchReorder.js +71 -0
  108. package/dist/runtime/data/handleId.d.ts +23 -0
  109. package/dist/runtime/data/handleId.js +6 -0
  110. package/dist/runtime/data/integrationNodeCatalog.d.ts +41 -0
  111. package/dist/runtime/data/integrationNodeCatalog.js +14 -0
  112. package/dist/runtime/data/integrationTemplates.d.ts +48 -0
  113. package/dist/runtime/data/integrationTemplates.js +21 -0
  114. package/dist/runtime/data/integrationWorkflowSamples.js +1 -1
  115. package/dist/runtime/data/nodeIcons.d.ts +2 -0
  116. package/dist/runtime/data/nodeIcons.js +73 -0
  117. package/dist/runtime/data/nodeInputData.d.ts +16 -4
  118. package/dist/runtime/data/nodeInputData.js +4 -0
  119. package/dist/runtime/data/payloadForm.d.ts +9 -2
  120. package/dist/runtime/data/payloadForm.js +29 -4
  121. package/dist/runtime/data/portTone.d.ts +17 -0
  122. package/dist/runtime/data/portTone.js +7 -0
  123. package/dist/runtime/data/webhookAuth.d.ts +18 -0
  124. package/dist/runtime/data/webhookAuth.js +19 -0
  125. package/dist/runtime/data/workflowIconCatalog.js +4 -6
  126. package/dist/runtime/i18n/messages/de.json +1207 -0
  127. package/dist/runtime/i18n/messages/en.json +1207 -0
  128. package/dist/runtime/i18n/translate.d.ts +83 -0
  129. package/dist/runtime/i18n/translate.js +41 -0
  130. package/dist/runtime/pages/integrations/audit.vue +140 -37
  131. package/dist/runtime/pages/integrations/credentials/oauth-complete.vue +9 -6
  132. package/dist/runtime/pages/integrations/credentials.vue +180 -64
  133. package/dist/runtime/pages/integrations/index.vue +91 -92
  134. package/dist/runtime/pages/integrations/runs.vue +33 -21
  135. package/dist/runtime/pages/integrations/schedules.vue +88 -23
  136. package/dist/runtime/pages/integrations/secrets.vue +57 -35
  137. package/dist/runtime/pages/integrations/templates/[slug].vue +119 -88
  138. package/dist/runtime/pages/integrations/templates/index.vue +82 -103
  139. package/dist/runtime/pages/integrations/workflows/[id].vue +344 -91
  140. package/dist/runtime/pages/integrations/workflows/index.vue +23 -5
  141. package/dist/runtime/plugins/locale.d.ts +10 -0
  142. package/dist/runtime/plugins/locale.js +6 -0
  143. package/dist/runtime/plugins/realtime.client.d.ts +32 -0
  144. package/dist/runtime/plugins/realtime.client.js +4 -0
  145. package/dist/runtime/types/integrations.d.ts +65 -6
  146. package/dist/runtime/utils/apiError.d.ts +47 -0
  147. package/dist/runtime/utils/apiError.js +32 -0
  148. package/dist/runtime/utils/cockpitSources.d.ts +153 -0
  149. package/dist/runtime/utils/cockpitSources.js +14 -0
  150. package/dist/runtime/utils/credentialState.d.ts +24 -1
  151. package/dist/runtime/utils/credentialState.js +26 -11
  152. package/dist/runtime/utils/loadGate.d.ts +61 -0
  153. package/dist/runtime/utils/loadGate.js +22 -0
  154. package/dist/runtime/utils/localize.d.ts +46 -4
  155. package/dist/runtime/utils/localize.js +34 -7
  156. package/dist/runtime/utils/notify.d.ts +59 -0
  157. package/dist/runtime/utils/notify.js +21 -0
  158. package/dist/runtime/utils/pollBudget.d.ts +72 -0
  159. package/dist/runtime/utils/pollBudget.js +17 -0
  160. package/dist/runtime/utils/revenexxCredentialSource.d.ts +26 -0
  161. package/dist/runtime/utils/revenexxCredentialSource.js +8 -0
  162. package/dist/runtime/utils/schedule.d.ts +116 -0
  163. package/dist/runtime/utils/schedule.js +219 -0
  164. package/dist/runtime/utils/statusStyle.d.ts +26 -2
  165. package/dist/runtime/utils/statusStyle.js +9 -1
  166. package/dist/runtime/utils/validationFindings.d.ts +101 -0
  167. package/dist/runtime/utils/validationFindings.js +54 -0
  168. package/dist/runtime/utils/whenIdle.d.ts +42 -0
  169. package/dist/runtime/utils/whenIdle.js +12 -0
  170. package/dist/types.d.mts +2 -6
  171. package/package.json +10 -3
@@ -3,9 +3,57 @@ import type { WorkflowTemplate } from '../types/integrations.js';
3
3
  * Category lens config for the Templates catalogue. The templates themselves
4
4
  * come live from the Integrations registry (`GET /templates`) — there is no
5
5
  * mock catalogue; an empty registry is an empty catalogue.
6
+ *
7
+ * The two categories that templates actually ship with today are `commerce` and
8
+ * `sales`: the eight templates in `@revenexx/integrations-nodes-core` are all
9
+ * `commerce`, the two in the Business Central package `sales`. Neither was named
10
+ * here, so both were shown by the fallback rather than by a label — the studio's
11
+ * one list of categories described none of the catalogue it had. The other six
12
+ * are named on spec and nothing publishes them yet.
6
13
  */
7
14
  export declare const TEMPLATE_CATEGORIES: Array<{
8
15
  key: WorkflowTemplate['category'];
9
16
  label: string;
10
17
  color: string;
11
18
  }>;
19
+ /**
20
+ * What a template's category is called, wherever the studio shows one.
21
+ *
22
+ * Four surfaces draw a category chip — the gallery, a template's own page, the
23
+ * dashboard's template panel and the start-from-a-template list in the dialog that
24
+ * creates a workflow — and each worked the name out for itself: a lookup with a
25
+ * capitalisation fallback, the raw registry key, and two separate capitalisations.
26
+ * They agreed only by coincidence, because every label in `TEMPLATE_CATEGORIES`
27
+ * above happens to be its key capitalised.
28
+ *
29
+ * That coincidence ends with the first category whose name is not a capitalisation
30
+ * — `crm`, `b2b`, `erp` — and categories arrive with node packages rather than with
31
+ * a release of the studio, so it is a matter of when. Every chip goes through here
32
+ * instead.
33
+ *
34
+ * The fallback is the catalogue's own promise (`specs/templates.md` AC-2): a
35
+ * category the studio has never been taught still gets a chip, named as well as it
36
+ * can be rather than dropped. That guarantee held on the gallery alone before; it
37
+ * now holds on all four.
38
+ *
39
+ * `specs/templates.md` AC-8 splits this in two: the first half — a category the
40
+ * studio *does* have a name for — is the studio's own word, and can follow the
41
+ * reader's language; the second half — the registry's own key, capitalised — never
42
+ * can, because a bare key carries no text to read in any language. Only the first
43
+ * half goes through `useIntegrationsT()`. A message missing from the catalogue
44
+ * (this key not merged into `messages/*.json` yet) falls back to the same English
45
+ * word `TEMPLATE_CATEGORIES` always carried, so the label degrades to "correct but
46
+ * unlocalised" rather than to the raw key.
47
+ */
48
+ export declare function templateCategoryLabel(key: string): string;
49
+ /**
50
+ * The integration a template ships with, as a card badges it — and as the
51
+ * gallery's search matches it. The core toolbox stays unbadged: every template
52
+ * would carry it, so it would say nothing.
53
+ *
54
+ * It lives here for the same reason `templateCategoryLabel` does. The gallery
55
+ * both shows this label and searches by it, so a copy inside the card component
56
+ * would be a second implementation of a name — the exact duplication PO-243
57
+ * removes.
58
+ */
59
+ export declare function templatePackageLabel(tpl: Pick<WorkflowTemplate, 'package'>): string | null;
@@ -1,5 +1,8 @@
1
+ import { useIntegrationsT } from "../composables/useIntegrationsT.js";
1
2
  export const TEMPLATE_CATEGORIES = [
2
3
  // Uniform muted pill — the label carries the meaning, no rainbow needed.
4
+ { key: "commerce", label: "Commerce", color: "bg-slate-100 text-slate-700" },
5
+ { key: "sales", label: "Sales", color: "bg-slate-100 text-slate-700" },
3
6
  { key: "sync", label: "Sync", color: "bg-slate-100 text-slate-700" },
4
7
  { key: "notification", label: "Notification", color: "bg-slate-100 text-slate-700" },
5
8
  { key: "fulfilment", label: "Fulfilment", color: "bg-slate-100 text-slate-700" },
@@ -7,3 +10,21 @@ export const TEMPLATE_CATEGORIES = [
7
10
  { key: "finance", label: "Finance", color: "bg-slate-100 text-slate-700" },
8
11
  { key: "reporting", label: "Reporting", color: "bg-slate-100 text-slate-700" }
9
12
  ];
13
+ export function templateCategoryLabel(key) {
14
+ if (!key) return "";
15
+ const known = TEMPLATE_CATEGORIES.find((c) => c.key === key);
16
+ if (known) {
17
+ const t = useIntegrationsT();
18
+ const messageKey = `integration.templates.category.${known.key}`;
19
+ const translated = t(messageKey);
20
+ return translated === messageKey ? known.label : translated;
21
+ }
22
+ return key.charAt(0).toUpperCase() + key.slice(1);
23
+ }
24
+ export function templatePackageLabel(tpl) {
25
+ const pkg = tpl.package;
26
+ if (!pkg) return null;
27
+ const tail = (pkg.name.split("/").pop() ?? pkg.name).replace(/^integrations-nodes-/, "");
28
+ if (tail === "core") return null;
29
+ return pkg.label ?? tail.split("-").map((s) => s.charAt(0).toUpperCase() + s.slice(1)).join(" ");
30
+ }
@@ -137,7 +137,7 @@ export const SAMPLE_WORKFLOWS = [
137
137
  }
138
138
  ],
139
139
  variables: {
140
- source: { type: "string", default: "primary", required: false }
140
+ source: { type: "string", default: "primary" }
141
141
  },
142
142
  nodes: [
143
143
  {
@@ -0,0 +1,2 @@
1
+ /** Resolve a manifest icon name to a Lucide component (Box as last resort). */
2
+ export declare function nodeIcon(name?: string | null): unknown;
@@ -0,0 +1,73 @@
1
+ import * as Lucide from "lucide-vue-next";
2
+ const MDI_TO_LUCIDE = {
3
+ "account-group-outline": "Users",
4
+ "account-outline": "User",
5
+ "account-plus-outline": "UserPlus",
6
+ "alert-octagon": "OctagonAlert",
7
+ "api": "Webhook",
8
+ "book-open-outline": "BookOpen",
9
+ "bullseye-arrow": "Target",
10
+ "calendar-check-outline": "CalendarCheck",
11
+ "card-account-details-outline": "IdCard",
12
+ "cart-outline": "ShoppingCart",
13
+ "cart-plus": "ShoppingBasket",
14
+ "circle-outline": "Circle",
15
+ "clock-outline": "Clock",
16
+ "cloud-download": "CloudDownload",
17
+ "cloud-upload": "CloudUpload",
18
+ "cloud-upload-outline": "CloudUpload",
19
+ "code-brackets": "Brackets",
20
+ "code-json": "Braces",
21
+ "code-tags": "Code",
22
+ "compare-horizontal": "ArrowLeftRight",
23
+ "currency-eur": "Euro",
24
+ "database-cog-outline": "Database",
25
+ "database-export-outline": "HardDriveUpload",
26
+ "database-import-outline": "HardDriveDownload",
27
+ "domain": "Building2",
28
+ "email-send": "Send",
29
+ "file-edit-outline": "FilePen",
30
+ "file-export-outline": "FileOutput",
31
+ "file-import-outline": "FileInput",
32
+ "file-move-outline": "FileSymlink",
33
+ "file-plus": "FilePlus",
34
+ "file-question-outline": "FileQuestion",
35
+ "file-remove-outline": "FileX",
36
+ "filter": "Filter",
37
+ "find-replace": "Replace",
38
+ "folder-download-outline": "FolderDown",
39
+ "folder-plus-outline": "FolderPlus",
40
+ "folder-search-outline": "FolderSearch",
41
+ "folder-upload-outline": "FolderUp",
42
+ "folder-zip-outline": "FolderArchive",
43
+ "format-list-bulleted-type": "List",
44
+ "handshake": "Handshake",
45
+ "handshake-outline": "Handshake",
46
+ "link-lock": "Link2",
47
+ "magnify": "Search",
48
+ "office-building-outline": "Building",
49
+ "pencil-box-outline": "SquarePen",
50
+ "pipe": "Workflow",
51
+ "receipt-outline": "Receipt",
52
+ "receipt-text-outline": "ReceiptText",
53
+ "regex": "Regex",
54
+ "repeat": "Repeat",
55
+ "ruler": "Ruler",
56
+ "source-branch": "GitBranch",
57
+ "tag-multiple-outline": "Tags",
58
+ "transfer": "ArrowRightLeft",
59
+ "translate": "Languages",
60
+ "truck-outline": "Truck",
61
+ "web": "Globe",
62
+ "xml": "CodeXml"
63
+ };
64
+ export function nodeIcon(name) {
65
+ if (!name) return Lucide.Box;
66
+ const bare = name.includes(":") ? name.split(":").pop() : name;
67
+ const mapped = MDI_TO_LUCIDE[bare];
68
+ if (mapped && Lucide[mapped]) {
69
+ return Lucide[mapped];
70
+ }
71
+ const pascal = bare.split("-").map((s) => s.charAt(0).toUpperCase() + s.slice(1)).join("");
72
+ return Lucide[pascal] || Lucide.Box;
73
+ }
@@ -27,11 +27,23 @@ export interface PortEntry {
27
27
  /** Declared payload fields of this port (schema; may be empty). */
28
28
  fields: FieldEntry[];
29
29
  }
30
+ /**
31
+ * A manifest declaring zero output ports describes a TERMINAL node (PO-201):
32
+ * the run ends there, so it gets no output handle and no edge may leave it.
33
+ *
34
+ * The distinction that matters is **declared empty vs. not known**. An absent
35
+ * manifest — a node that is not installed — is not terminal; we simply cannot
36
+ * work out its ports, and it has to stay wirable. Same for a `sourceFromConfig`
37
+ * or `resolveOutputs` set that expands to nothing: unresolved, not terminal.
38
+ * Only an explicit `[]` is the node making a statement about itself.
39
+ */
40
+ export declare function isTerminalManifest(manifest: NodeManifest | null | undefined): boolean;
30
41
  /**
31
42
  * The output ports one upstream node exposes, mirroring the canvas port
32
- * derivation: named ports map straight over, `sourceFromConfig` ports expand
33
- * from the node's config values (plus the optional fallback), and a node
34
- * without any resolvable port still gets its `default`. Server-resolved
35
- * dynamic outputs, when present, replace the manifest's static list.
43
+ * derivation in `WorkflowNodeView.vue`. Named ports map straight over,
44
+ * `sourceFromConfig` ports expand from the node's config values (plus the
45
+ * optional fallback), and a node whose ports could not be worked out still
46
+ * gets its `default`. Server-resolved dynamic outputs, when present, replace
47
+ * the manifest's static list.
36
48
  */
37
49
  export declare function portsForNode(node: WorkflowNode, manifest: NodeManifest | null, resolvedOutputs?: NodeManifestOutput[]): PortEntry[];
@@ -44,7 +44,11 @@ function fieldEntries(raw) {
44
44
  }
45
45
  return [];
46
46
  }
47
+ export function isTerminalManifest(manifest) {
48
+ return !!manifest && Array.isArray(manifest.outputs) && !manifest.outputs.length;
49
+ }
47
50
  export function portsForNode(node, manifest, resolvedOutputs) {
51
+ if (isTerminalManifest(manifest)) return [];
48
52
  const list = resolvedOutputs?.length ? resolvedOutputs : manifest?.outputs ?? [];
49
53
  const ports = [];
50
54
  for (const o of list) {
@@ -16,8 +16,15 @@ export interface PayloadField {
16
16
  path: string;
17
17
  label: string;
18
18
  }
19
- /** Scan the blob's node configs and derive the payload form fields. */
20
- export declare function payloadFieldsFromBlob(blob: Pick<WorkflowBlob, 'nodes'>): PayloadField[];
19
+ /**
20
+ * Payload form fields: fields DECLARED on a manual trigger come first (the
21
+ * author's explicit contract, e.g. a file field for a manual import), then
22
+ * every `${{ trigger.payload.* }}` reference found in node configs that the
23
+ * declarations don't already cover.
24
+ */
25
+ export declare function payloadFieldsFromBlob(blob: Pick<WorkflowBlob, 'nodes'> & {
26
+ triggers?: WorkflowBlob['triggers'];
27
+ }): PayloadField[];
21
28
  export declare function setPath(target: Record<string, unknown>, path: string, value: unknown): void;
22
29
  export declare function getPath(source: Record<string, unknown>, path: string): unknown;
23
30
  export interface AttachedFile {
@@ -1,3 +1,4 @@
1
+ import { useIntegrationsT } from "../composables/useIntegrationsT.js";
1
2
  const PAYLOAD_REF_RE = /\$\{\{\s*trigger\.payload\.([a-zA-Z0-9_.-]+)/g;
2
3
  const FILE_KEYS = /* @__PURE__ */ new Set(["data", "filename", "contentType", "size"]);
3
4
  function collectRefs(value, out) {
@@ -14,9 +15,23 @@ function labelFor(path) {
14
15
  return last.replace(/[_-]/g, " ").replace(/([a-z])([A-Z])/g, "$1 $2").replace(/^./, (c) => c.toUpperCase());
15
16
  }
16
17
  export function payloadFieldsFromBlob(blob) {
18
+ const declared = [];
19
+ for (const t of blob.triggers ?? []) {
20
+ if (t.type !== "manual") continue;
21
+ for (const d of t.config?.payloadFields ?? []) {
22
+ const path = d.path?.trim();
23
+ if (!path && d.kind !== "file") continue;
24
+ declared.push({
25
+ kind: d.kind === "file" ? "file" : "text",
26
+ path: path ?? "",
27
+ label: d.label?.trim() || labelFor(path || "file")
28
+ });
29
+ }
30
+ }
17
31
  const refs = /* @__PURE__ */ new Set();
18
32
  for (const node of blob.nodes ?? []) collectRefs(node.config, refs);
19
- if (refs.size === 0) return [];
33
+ if (refs.size === 0 && declared.length === 0) return [];
34
+ const declaredPaths = new Set(declared.map((f) => f.path));
20
35
  const byPrefix = /* @__PURE__ */ new Map();
21
36
  for (const ref of refs) {
22
37
  const idx = ref.lastIndexOf(".");
@@ -26,10 +41,16 @@ export function payloadFieldsFromBlob(blob) {
26
41
  byPrefix.get(prefix).add(leaf);
27
42
  }
28
43
  const fields = [];
29
- const consumed = /* @__PURE__ */ new Set();
44
+ const consumed = new Set(declaredPaths);
30
45
  for (const [prefix, leaves] of byPrefix) {
31
46
  if (leaves.has("data")) {
32
- fields.push({ kind: "file", path: prefix, label: prefix === "" ? "File" : labelFor(prefix) });
47
+ if (declaredPaths.has(prefix)) {
48
+ for (const leaf of leaves) {
49
+ if (FILE_KEYS.has(leaf)) consumed.add(prefix === "" ? leaf : `${prefix}.${leaf}`);
50
+ }
51
+ continue;
52
+ }
53
+ fields.push({ kind: "file", path: prefix, label: prefix === "" ? useIntegrationsT()("integration.common.label.file") : labelFor(prefix) });
33
54
  for (const leaf of leaves) {
34
55
  if (FILE_KEYS.has(leaf)) consumed.add(prefix === "" ? leaf : `${prefix}.${leaf}`);
35
56
  }
@@ -37,9 +58,13 @@ export function payloadFieldsFromBlob(blob) {
37
58
  }
38
59
  for (const ref of [...refs].sort()) {
39
60
  if (consumed.has(ref)) continue;
61
+ if (declared.some((d) => d.kind === "file" && (d.path === "" ? FILE_KEYS.has(ref) : ref.startsWith(d.path + ".")))) continue;
40
62
  fields.push({ kind: "text", path: ref, label: labelFor(ref) });
41
63
  }
42
- return fields.sort((a, b) => a.kind === b.kind ? a.path.localeCompare(b.path) : a.kind === "file" ? -1 : 1);
64
+ return [
65
+ ...declared,
66
+ ...fields.sort((a, b) => a.kind === b.kind ? a.path.localeCompare(b.path) : a.kind === "file" ? -1 : 1)
67
+ ];
43
68
  }
44
69
  export function setPath(target, path, value) {
45
70
  if (path === "") {
@@ -0,0 +1,17 @@
1
+ import type { OutputKind } from '../types/integrations.js';
2
+ /**
3
+ * The colour of the dot in front of a port name, wherever a port is listed
4
+ * rather than drawn on the canvas: the Input panel's upstream trees and the
5
+ * node's own output schema.
6
+ *
7
+ * The legend mirrors `portTone` on the canvas node (PO-197): green = a real,
8
+ * active output — the normal continuation, including switch cases, iterator
9
+ * `item` and If/Filter `true`; soft rose = the error output that only runs on
10
+ * failure; neutral slate for `false` and fallbacks. There is no separate branch
11
+ * colour — the labels already say "one of several".
12
+ *
13
+ * It lives here rather than in a component because two lists render it and they
14
+ * must never disagree. They did once: the schema list kept a private copy and
15
+ * silently held the pre-PO-197 palette while the Input panel moved on.
16
+ */
17
+ export declare function portDotClass(kind: OutputKind, name: string): string;
@@ -0,0 +1,7 @@
1
+ export function portDotClass(kind, name) {
2
+ if (name === "true") return "bg-emerald-500";
3
+ if (name === "false") return "bg-slate-500";
4
+ if (name === "error" || kind === "error") return "bg-rose-300";
5
+ if (name === "done") return "bg-emerald-500";
6
+ return "bg-emerald-500";
7
+ }
@@ -0,0 +1,18 @@
1
+ import type { WorkflowTrigger } from '../types/integrations.js';
2
+ /**
3
+ * Mapping between the webhook Protection select and the ingress verification
4
+ * profiles stored on the trigger (`authProfile`/`authConfig`). Bearer is the
5
+ * token profile with a fixed Authorization + "Bearer " prefix.
6
+ *
7
+ * An ABSENT authProfile reads as 'token': that is what the exposure defaults
8
+ * to server-side (and what every endpoint provisioned before this feature
9
+ * got), so the select shows the effective behavior. The UI persists the
10
+ * choice explicitly the moment the public toggle is enabled, so anything
11
+ * exposed from here on carries what it shows.
12
+ */
13
+ export type WebhookAuthChoice = 'none' | 'token' | 'bearer' | 'basic';
14
+ type TriggerConfig = WorkflowTrigger['config'];
15
+ export declare function authChoiceFromConfig(config: TriggerConfig | undefined): WebhookAuthChoice;
16
+ /** The config patch that makes a Protection choice stored state. */
17
+ export declare function configPatchForAuthChoice(choice: WebhookAuthChoice): Partial<TriggerConfig>;
18
+ export {};
@@ -0,0 +1,19 @@
1
+ export function authChoiceFromConfig(config) {
2
+ if (config?.authProfile === "none") return "none";
3
+ if (config?.authProfile === "basic") return "basic";
4
+ if (config?.authProfile === "token" && config?.authConfig?.prefix === "Bearer ") return "bearer";
5
+ return "token";
6
+ }
7
+ export function configPatchForAuthChoice(choice) {
8
+ switch (choice) {
9
+ case "none":
10
+ return { authProfile: "none", authConfig: void 0 };
11
+ case "bearer":
12
+ return { authProfile: "token", authConfig: { header: "Authorization", prefix: "Bearer " } };
13
+ case "basic":
14
+ return { authProfile: "basic", authConfig: void 0 };
15
+ case "token":
16
+ default:
17
+ return { authProfile: "token", authConfig: void 0 };
18
+ }
19
+ }
@@ -37,6 +37,7 @@ import {
37
37
  WalletMoney
38
38
  } from "#solar-icons";
39
39
  import { INTEGRATION_NODE_CATALOG } from "./integrationNodeCatalog.js";
40
+ import { resolveLocalized } from "../utils/localize.js";
40
41
  export const WORKFLOW_SOLAR_ICONS = {
41
42
  Programming,
42
43
  Bolt,
@@ -78,10 +79,6 @@ export const WORKFLOW_SOLAR_ICONS = {
78
79
  export function solarIconFor(name) {
79
80
  return (name ? WORKFLOW_SOLAR_ICONS[name] : void 0) ?? Programming;
80
81
  }
81
- function loc(v) {
82
- if (!v) return "";
83
- return typeof v === "string" ? v : v.en ?? Object.values(v)[0] ?? "";
84
- }
85
82
  const UUID = "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}";
86
83
  const IMAGE_URL_ID_RE = new RegExp(`node-packages/images/(${UUID})`, "i");
87
84
  const BARE_UUID_RE = new RegExp(`^${UUID}$`, "i");
@@ -102,6 +99,7 @@ export function freshImageSrc(stored) {
102
99
  return null;
103
100
  }
104
101
  export function nodeLogoOptions() {
102
+ const t = useIntegrationsT();
105
103
  const byId = /* @__PURE__ */ new Map();
106
104
  for (const m of INTEGRATION_NODE_CATALOG) {
107
105
  const imgs = m.images ?? [];
@@ -109,8 +107,8 @@ export function nodeLogoOptions() {
109
107
  if (!logo?.src) continue;
110
108
  const id = imageIdFromSrc(logo.src) ?? logo.src;
111
109
  if (byId.has(id)) continue;
112
- const label = m.__package?.label || (m.groups?.length ? loc(m.groups[0]) : "") || loc(m.name);
113
- byId.set(id, { label: label || "Integration", src: logo.src });
110
+ const label = m.__package?.label || (m.groups?.length ? resolveLocalized(m.groups[0]) : "") || resolveLocalized(m.name);
111
+ byId.set(id, { label: label || t("integration.workflows.iconCatalog.label.fallback"), src: logo.src });
114
112
  }
115
113
  return [...byId.entries()].map(([id, v]) => ({ id, src: v.src, label: v.label })).sort((a, b) => a.label.localeCompare(b.label));
116
114
  }