@revenexx/studio-integrations 0.1.3 → 0.2.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.
- package/dist/module.json +1 -1
- package/dist/runtime/components/Integrations/CredentialCreateDialog.d.vue.ts +13 -0
- package/dist/runtime/components/Integrations/CredentialCreateDialog.vue +279 -0
- package/dist/runtime/components/Integrations/CredentialCreateDialog.vue.d.ts +13 -0
- package/dist/runtime/components/Integrations/CredentialDetailDialog.d.vue.ts +20 -0
- package/dist/runtime/components/Integrations/CredentialDetailDialog.vue +342 -0
- package/dist/runtime/components/Integrations/CredentialDetailDialog.vue.d.ts +20 -0
- package/dist/runtime/components/Integrations/CredentialLogo.d.vue.ts +14 -0
- package/dist/runtime/components/Integrations/CredentialLogo.vue +37 -0
- package/dist/runtime/components/Integrations/CredentialLogo.vue.d.ts +14 -0
- package/dist/runtime/components/Integrations/CredentialRevenexxSource.d.vue.ts +12 -0
- package/dist/runtime/components/Integrations/CredentialRevenexxSource.vue +364 -0
- package/dist/runtime/components/Integrations/CredentialRevenexxSource.vue.d.ts +12 -0
- package/dist/runtime/components/Integrations/CredentialTypePicker.d.vue.ts +15 -0
- package/dist/runtime/components/Integrations/CredentialTypePicker.vue +71 -0
- package/dist/runtime/components/Integrations/CredentialTypePicker.vue.d.ts +15 -0
- package/dist/runtime/components/Integrations/DeadLettersPanel.d.vue.ts +5 -0
- package/dist/runtime/components/Integrations/DeadLettersPanel.vue +151 -0
- package/dist/runtime/components/Integrations/DeadLettersPanel.vue.d.ts +5 -0
- package/dist/runtime/components/Integrations/EditorTip.d.vue.ts +17 -0
- package/dist/runtime/components/Integrations/EditorTip.vue +46 -0
- package/dist/runtime/components/Integrations/EditorTip.vue.d.ts +17 -0
- package/dist/runtime/components/Integrations/EventTypeCombobox.d.vue.ts +9 -0
- package/dist/runtime/components/Integrations/EventTypeCombobox.vue +64 -0
- package/dist/runtime/components/Integrations/EventTypeCombobox.vue.d.ts +9 -0
- package/dist/runtime/components/Integrations/ExpressionInput.d.vue.ts +19 -0
- package/dist/runtime/components/Integrations/ExpressionInput.vue +236 -0
- package/dist/runtime/components/Integrations/ExpressionInput.vue.d.ts +19 -0
- package/dist/runtime/components/Integrations/GroupFrameView.d.vue.ts +28 -0
- package/dist/runtime/components/Integrations/GroupFrameView.vue +222 -0
- package/dist/runtime/components/Integrations/GroupFrameView.vue.d.ts +28 -0
- package/dist/runtime/components/Integrations/NodeConfigDynamicField.d.vue.ts +14 -0
- package/dist/runtime/components/Integrations/NodeConfigDynamicField.vue +184 -0
- package/dist/runtime/components/Integrations/NodeConfigDynamicField.vue.d.ts +14 -0
- package/dist/runtime/components/Integrations/NodeConfigDynamicSchema.d.vue.ts +16 -0
- package/dist/runtime/components/Integrations/NodeConfigDynamicSchema.vue +102 -0
- package/dist/runtime/components/Integrations/NodeConfigDynamicSchema.vue.d.ts +16 -0
- package/dist/runtime/components/Integrations/NodeConfigField.d.vue.ts +23 -0
- package/dist/runtime/components/Integrations/NodeConfigField.vue +587 -0
- package/dist/runtime/components/Integrations/NodeConfigField.vue.d.ts +23 -0
- package/dist/runtime/components/Integrations/NodeDynamicOutputsResolver.d.vue.ts +14 -0
- package/dist/runtime/components/Integrations/NodeDynamicOutputsResolver.vue +80 -0
- package/dist/runtime/components/Integrations/NodeDynamicOutputsResolver.vue.d.ts +14 -0
- package/dist/runtime/components/Integrations/NodeInspector.d.vue.ts +22 -3
- package/dist/runtime/components/Integrations/NodeInspector.vue +1074 -294
- package/dist/runtime/components/Integrations/NodeInspector.vue.d.ts +22 -3
- package/dist/runtime/components/Integrations/NodeLogo.d.vue.ts +9 -0
- package/dist/runtime/components/Integrations/NodeLogo.vue +38 -0
- package/dist/runtime/components/Integrations/NodeLogo.vue.d.ts +9 -0
- package/dist/runtime/components/Integrations/NodePalette.d.vue.ts +22 -1
- package/dist/runtime/components/Integrations/NodePalette.vue +411 -90
- package/dist/runtime/components/Integrations/NodePalette.vue.d.ts +22 -1
- package/dist/runtime/components/Integrations/QueryBuilder.d.vue.ts +9 -0
- package/dist/runtime/components/Integrations/QueryBuilder.vue +239 -0
- package/dist/runtime/components/Integrations/QueryBuilder.vue.d.ts +9 -0
- package/dist/runtime/components/Integrations/{RunDetailDialog.d.vue.ts → RunActionsMenu.d.vue.ts} +3 -4
- package/dist/runtime/components/Integrations/RunActionsMenu.vue +86 -0
- package/dist/runtime/components/Integrations/{RunDetailDialog.vue.d.ts → RunActionsMenu.vue.d.ts} +3 -4
- package/dist/runtime/components/Integrations/RunDetailPanel.d.vue.ts +14 -0
- package/dist/runtime/components/Integrations/RunDetailPanel.vue +777 -0
- package/dist/runtime/components/Integrations/RunDetailPanel.vue.d.ts +14 -0
- package/dist/runtime/components/Integrations/RunPayloadInput.d.vue.ts +13 -0
- package/dist/runtime/components/Integrations/RunPayloadInput.vue +175 -0
- package/dist/runtime/components/Integrations/RunPayloadInput.vue.d.ts +13 -0
- package/dist/runtime/components/Integrations/RunResponseModal.d.vue.ts +27 -0
- package/dist/runtime/components/Integrations/RunResponseModal.vue +84 -0
- package/dist/runtime/components/Integrations/RunResponseModal.vue.d.ts +27 -0
- package/dist/runtime/components/Integrations/RunsTable.d.vue.ts +21 -0
- package/dist/runtime/components/Integrations/RunsTable.vue +114 -0
- package/dist/runtime/components/Integrations/RunsTable.vue.d.ts +21 -0
- package/dist/runtime/components/Integrations/SftpAccountImportDialog.d.vue.ts +11 -0
- package/dist/runtime/components/Integrations/SftpAccountImportDialog.vue +91 -0
- package/dist/runtime/components/Integrations/SftpAccountImportDialog.vue.d.ts +11 -0
- package/dist/runtime/components/Integrations/Sidebar.vue +1 -0
- package/dist/runtime/components/Integrations/StickyNoteView.d.vue.ts +28 -0
- package/dist/runtime/components/Integrations/StickyNoteView.vue +208 -0
- package/dist/runtime/components/Integrations/StickyNoteView.vue.d.ts +28 -0
- package/dist/runtime/components/Integrations/TemplateFlowPreview.d.vue.ts +29 -0
- package/dist/runtime/components/Integrations/TemplateFlowPreview.vue +201 -0
- package/dist/runtime/components/Integrations/TemplateFlowPreview.vue.d.ts +29 -0
- package/dist/runtime/components/Integrations/WorkflowContextMenu.d.vue.ts +32 -0
- package/dist/runtime/components/Integrations/WorkflowContextMenu.vue +138 -0
- package/dist/runtime/components/Integrations/WorkflowContextMenu.vue.d.ts +32 -0
- package/dist/runtime/components/Integrations/WorkflowCreateDialog.d.vue.ts +9 -0
- package/dist/runtime/components/Integrations/WorkflowCreateDialog.vue +322 -0
- package/dist/runtime/components/Integrations/WorkflowCreateDialog.vue.d.ts +9 -0
- package/dist/runtime/components/Integrations/WorkflowDuplicateDialog.d.vue.ts +18 -0
- package/dist/runtime/components/Integrations/WorkflowDuplicateDialog.vue +63 -0
- package/dist/runtime/components/Integrations/WorkflowDuplicateDialog.vue.d.ts +18 -0
- package/dist/runtime/components/Integrations/WorkflowEdgeView.d.vue.ts +12 -1
- package/dist/runtime/components/Integrations/WorkflowEdgeView.vue +68 -6
- package/dist/runtime/components/Integrations/WorkflowEdgeView.vue.d.ts +12 -1
- package/dist/runtime/components/Integrations/WorkflowEditor.d.vue.ts +8 -1
- package/dist/runtime/components/Integrations/WorkflowEditor.vue +1424 -144
- package/dist/runtime/components/Integrations/WorkflowEditor.vue.d.ts +8 -1
- package/dist/runtime/components/Integrations/WorkflowHistoryPanel.d.vue.ts +12 -0
- package/dist/runtime/components/Integrations/WorkflowHistoryPanel.vue +417 -0
- package/dist/runtime/components/Integrations/WorkflowHistoryPanel.vue.d.ts +12 -0
- package/dist/runtime/components/Integrations/WorkflowIconPicker.d.vue.ts +10 -0
- package/dist/runtime/components/Integrations/WorkflowIconPicker.vue +89 -0
- package/dist/runtime/components/Integrations/WorkflowIconPicker.vue.d.ts +10 -0
- package/dist/runtime/components/Integrations/WorkflowIconView.d.vue.ts +10 -0
- package/dist/runtime/components/Integrations/WorkflowIconView.vue +35 -0
- package/dist/runtime/components/Integrations/WorkflowIconView.vue.d.ts +10 -0
- package/dist/runtime/components/Integrations/WorkflowNodeView.d.vue.ts +5 -1
- package/dist/runtime/components/Integrations/WorkflowNodeView.vue +114 -84
- package/dist/runtime/components/Integrations/WorkflowNodeView.vue.d.ts +5 -1
- package/dist/runtime/components/Integrations/WorkflowRunReplayPanel.d.vue.ts +12 -0
- package/dist/runtime/components/Integrations/WorkflowRunReplayPanel.vue +654 -0
- package/dist/runtime/components/Integrations/WorkflowRunReplayPanel.vue.d.ts +12 -0
- package/dist/runtime/components/Integrations/WorkflowSettingsDialog.d.vue.ts +36 -0
- package/dist/runtime/components/Integrations/WorkflowSettingsDialog.vue +136 -0
- package/dist/runtime/components/Integrations/WorkflowSettingsDialog.vue.d.ts +36 -0
- package/dist/runtime/components/Integrations/WorkflowTagsInput.d.vue.ts +14 -0
- package/dist/runtime/components/Integrations/WorkflowTagsInput.vue +63 -0
- package/dist/runtime/components/Integrations/WorkflowTagsInput.vue.d.ts +14 -0
- package/dist/runtime/components/Integrations/WorkflowTriggerView.vue +35 -15
- package/dist/runtime/components/Integrations/WorkflowVariablesDialog.d.vue.ts +13 -0
- package/dist/runtime/components/Integrations/WorkflowVariablesDialog.vue +265 -0
- package/dist/runtime/components/Integrations/WorkflowVariablesDialog.vue.d.ts +13 -0
- package/dist/runtime/components/Integrations/WorkflowsTable.d.vue.ts +4 -1
- package/dist/runtime/components/Integrations/WorkflowsTable.vue +122 -39
- package/dist/runtime/components/Integrations/WorkflowsTable.vue.d.ts +4 -1
- package/dist/runtime/components/Integrations/workflowLayout.d.ts +5 -0
- package/dist/runtime/components/Integrations/workflowLayout.js +5 -3
- package/dist/runtime/composables/integrationsApi.d.ts +6 -2
- package/dist/runtime/composables/integrationsApi.js +5 -4
- package/dist/runtime/composables/useCanvasShortcuts.d.ts +37 -0
- package/dist/runtime/composables/useCanvasShortcuts.js +62 -0
- package/dist/runtime/composables/useIntegrationsDeadLetters.d.ts +22 -0
- package/dist/runtime/composables/useIntegrationsDeadLetters.js +50 -0
- package/dist/runtime/composables/useIntegrationsNodes.d.ts +4 -0
- package/dist/runtime/composables/useIntegrationsNodes.js +6 -3
- package/dist/runtime/composables/useIntegrationsRevisions.d.ts +40 -0
- package/dist/runtime/composables/useIntegrationsRevisions.js +51 -0
- package/dist/runtime/composables/useIntegrationsRuns.d.ts +21 -1
- package/dist/runtime/composables/useIntegrationsRuns.js +92 -4
- package/dist/runtime/composables/useIntegrationsTemplates.d.ts +1 -0
- package/dist/runtime/composables/useIntegrationsTemplates.js +32 -4
- package/dist/runtime/composables/useIntegrationsWorkflows.d.ts +1 -0
- package/dist/runtime/composables/useIntegrationsWorkflows.js +57 -1
- package/dist/runtime/composables/useMiniMapLayout.d.ts +34 -0
- package/dist/runtime/composables/useMiniMapLayout.js +119 -0
- package/dist/runtime/composables/useNodeConfigResolve.d.ts +43 -0
- package/dist/runtime/composables/useNodeConfigResolve.js +123 -0
- package/dist/runtime/composables/useNodeDrag.d.ts +22 -0
- package/dist/runtime/composables/useNodeDrag.js +10 -0
- package/dist/runtime/composables/usePaletteLayout.d.ts +41 -0
- package/dist/runtime/composables/usePaletteLayout.js +113 -0
- package/dist/runtime/data/expressionEditor.d.ts +22 -0
- package/dist/runtime/data/expressionEditor.js +40 -0
- package/dist/runtime/data/integrationNodeCatalog.js +8 -8
- package/dist/runtime/data/nodeInputData.d.ts +37 -0
- package/dist/runtime/data/nodeInputData.js +62 -0
- package/dist/runtime/data/nodeRunData.d.ts +56 -0
- package/dist/runtime/data/nodeRunData.js +91 -0
- package/dist/runtime/data/payloadForm.d.ts +44 -0
- package/dist/runtime/data/payloadForm.js +126 -0
- package/dist/runtime/data/workflowIconCatalog.d.ts +34 -0
- package/dist/runtime/data/workflowIconCatalog.js +116 -0
- package/dist/runtime/pages/integrations/audit.vue +25 -35
- package/dist/runtime/pages/integrations/credentials.vue +117 -122
- package/dist/runtime/pages/integrations/index.vue +133 -36
- package/dist/runtime/pages/integrations/runs.vue +125 -75
- package/dist/runtime/pages/integrations/schedules.vue +5 -16
- package/dist/runtime/pages/integrations/secrets.vue +1 -3
- package/dist/runtime/pages/integrations/workflows/[id].vue +599 -194
- package/dist/runtime/pages/integrations/workflows/index.vue +10 -8
- package/dist/runtime/types/integrations.d.ts +190 -4
- package/dist/runtime/utils/credentialState.d.ts +28 -0
- package/dist/runtime/utils/credentialState.js +29 -0
- package/dist/runtime/utils/localize.d.ts +3 -1
- package/dist/runtime/utils/localize.js +1 -2
- package/dist/runtime/utils/statusStyle.d.ts +6 -0
- package/dist/runtime/utils/statusStyle.js +15 -0
- package/package.json +12 -2
- package/dist/runtime/components/Integrations/RunDetailDialog.vue +0 -169
- package/dist/runtime/pages/integrations/workflows/new.d.vue.ts +0 -2
- package/dist/runtime/pages/integrations/workflows/new.vue +0 -153
- package/dist/runtime/pages/integrations/workflows/new.vue.d.ts +0 -2
|
@@ -25,8 +25,8 @@ export const TRIGGER_TEMPLATES = [
|
|
|
25
25
|
type: "manual",
|
|
26
26
|
name: { en: "Manual", de: "Manuell" },
|
|
27
27
|
description: {
|
|
28
|
-
en: "
|
|
29
|
-
de: "
|
|
28
|
+
en: "Start the workflow yourself with the Run button or an API call.",
|
|
29
|
+
de: "Starte den Workflow selbst \xFCber den Run-Button oder einen API-Aufruf."
|
|
30
30
|
},
|
|
31
31
|
icon: "Play",
|
|
32
32
|
defaultConfig: {}
|
|
@@ -36,8 +36,8 @@ export const TRIGGER_TEMPLATES = [
|
|
|
36
36
|
type: "schedule",
|
|
37
37
|
name: { en: "Schedule", de: "Zeitplan" },
|
|
38
38
|
description: {
|
|
39
|
-
en: "
|
|
40
|
-
de: "
|
|
39
|
+
en: "Runs automatically on a schedule you define, for example every night.",
|
|
40
|
+
de: "L\xE4uft automatisch nach deinem Zeitplan, zum Beispiel jede Nacht."
|
|
41
41
|
},
|
|
42
42
|
icon: "Clock",
|
|
43
43
|
defaultConfig: { cron: "0 * * * *", timezone: "Europe/Berlin" }
|
|
@@ -47,8 +47,8 @@ export const TRIGGER_TEMPLATES = [
|
|
|
47
47
|
type: "webhook",
|
|
48
48
|
name: { en: "Webhook", de: "Webhook" },
|
|
49
49
|
description: {
|
|
50
|
-
en: "
|
|
51
|
-
de: "
|
|
50
|
+
en: "Starts when an external system calls this workflow's URL.",
|
|
51
|
+
de: "Startet, wenn ein externes System die URL dieses Workflows aufruft."
|
|
52
52
|
},
|
|
53
53
|
icon: "Webhook",
|
|
54
54
|
defaultConfig: { path: "/incoming", method: "POST" }
|
|
@@ -58,8 +58,8 @@ export const TRIGGER_TEMPLATES = [
|
|
|
58
58
|
type: "event",
|
|
59
59
|
name: { en: "Event", de: "Event" },
|
|
60
60
|
description: {
|
|
61
|
-
en: "
|
|
62
|
-
de: "
|
|
61
|
+
en: "Starts when something happens on the platform, for example a new customer.",
|
|
62
|
+
de: "Startet, wenn auf der Plattform etwas passiert, zum Beispiel ein neuer Kunde."
|
|
63
63
|
},
|
|
64
64
|
icon: "Zap",
|
|
65
65
|
defaultConfig: { event_type: "" }
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { NodeManifest, NodeManifestOutput, OutputKind, WorkflowEdge, WorkflowNode } from '../types/integrations.js';
|
|
2
|
+
/** `${{ nodes.<id>.outputs.<port> }}`, optionally narrowed to one field. */
|
|
3
|
+
export declare function nodeOutputExpr(nodeId: string, port: string, field?: string): string;
|
|
4
|
+
/** `${{ trigger.payload }}`, optionally narrowed to a path inside it. */
|
|
5
|
+
export declare function triggerPayloadExpr(path?: string): string;
|
|
6
|
+
/** `${{ vars.<name> }}` */
|
|
7
|
+
export declare function variableExpr(name: string): string;
|
|
8
|
+
export interface UpstreamNodeRef {
|
|
9
|
+
node: WorkflowNode;
|
|
10
|
+
/** True when an edge feeds the selected node directly from this one. */
|
|
11
|
+
direct: boolean;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* All nodes the selected node can reference, found by walking the edges
|
|
15
|
+
* backwards from it (breadth-first, nearest first, deduped, cycle-safe).
|
|
16
|
+
* Trigger sources are skipped — only workflow nodes are listed.
|
|
17
|
+
*/
|
|
18
|
+
export declare function collectUpstreamNodes(selectedId: string, nodes: WorkflowNode[], edges: WorkflowEdge[]): UpstreamNodeRef[];
|
|
19
|
+
export interface FieldEntry {
|
|
20
|
+
name: string;
|
|
21
|
+
/** Declared data type (`string`, `number`, `boolean`, …) when the manifest carries one. */
|
|
22
|
+
dataType: string | null;
|
|
23
|
+
}
|
|
24
|
+
export interface PortEntry {
|
|
25
|
+
name: string;
|
|
26
|
+
kind: OutputKind;
|
|
27
|
+
/** Declared payload fields of this port (schema; may be empty). */
|
|
28
|
+
fields: FieldEntry[];
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* 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.
|
|
36
|
+
*/
|
|
37
|
+
export declare function portsForNode(node: WorkflowNode, manifest: NodeManifest | null, resolvedOutputs?: NodeManifestOutput[]): PortEntry[];
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
const OPEN = "${{ ";
|
|
2
|
+
const CLOSE = " }}";
|
|
3
|
+
function wrap(inner) {
|
|
4
|
+
return OPEN + inner + CLOSE;
|
|
5
|
+
}
|
|
6
|
+
export function nodeOutputExpr(nodeId, port, field) {
|
|
7
|
+
return wrap("nodes." + nodeId + ".outputs." + port + (field ? "." + field : ""));
|
|
8
|
+
}
|
|
9
|
+
export function triggerPayloadExpr(path) {
|
|
10
|
+
return wrap("trigger.payload" + (path ? "." + path : ""));
|
|
11
|
+
}
|
|
12
|
+
export function variableExpr(name) {
|
|
13
|
+
return wrap("vars." + name);
|
|
14
|
+
}
|
|
15
|
+
export function collectUpstreamNodes(selectedId, nodes, edges) {
|
|
16
|
+
const byId = new Map(nodes.map((n) => [n.id, n]));
|
|
17
|
+
const seen = /* @__PURE__ */ new Set([selectedId]);
|
|
18
|
+
const out = [];
|
|
19
|
+
let frontier = [selectedId];
|
|
20
|
+
let direct = true;
|
|
21
|
+
while (frontier.length > 0) {
|
|
22
|
+
const next = [];
|
|
23
|
+
for (const id of frontier) {
|
|
24
|
+
for (const e of edges) {
|
|
25
|
+
if (e.to.nodeId !== id || seen.has(e.from.nodeId)) continue;
|
|
26
|
+
seen.add(e.from.nodeId);
|
|
27
|
+
next.push(e.from.nodeId);
|
|
28
|
+
const node = byId.get(e.from.nodeId);
|
|
29
|
+
if (node && node.id !== selectedId) out.push({ node, direct });
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
frontier = next;
|
|
33
|
+
direct = false;
|
|
34
|
+
}
|
|
35
|
+
return out;
|
|
36
|
+
}
|
|
37
|
+
function fieldEntries(raw) {
|
|
38
|
+
if (Array.isArray(raw)) return raw.map((v) => ({ name: String(v), dataType: null }));
|
|
39
|
+
if (raw && typeof raw === "object") {
|
|
40
|
+
return Object.entries(raw).map(([name, spec]) => ({
|
|
41
|
+
name,
|
|
42
|
+
dataType: spec && typeof spec === "object" && typeof spec.dataType === "string" ? spec.dataType : null
|
|
43
|
+
}));
|
|
44
|
+
}
|
|
45
|
+
return [];
|
|
46
|
+
}
|
|
47
|
+
export function portsForNode(node, manifest, resolvedOutputs) {
|
|
48
|
+
const list = resolvedOutputs?.length ? resolvedOutputs : manifest?.outputs ?? [];
|
|
49
|
+
const ports = [];
|
|
50
|
+
for (const o of list) {
|
|
51
|
+
if (o.name) {
|
|
52
|
+
ports.push({ name: o.name, kind: o.kind, fields: fieldEntries(o.fields) });
|
|
53
|
+
} else if (o.sourceFromConfig) {
|
|
54
|
+
const raw = node.config?.[o.sourceFromConfig];
|
|
55
|
+
const values = Array.isArray(raw) ? raw : [];
|
|
56
|
+
for (const v of values) ports.push({ name: String(v), kind: o.kind, fields: fieldEntries(o.fields) });
|
|
57
|
+
if (o.fallback) ports.push({ name: o.fallback.name, kind: o.kind, fields: fieldEntries(o.fields) });
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
if (!ports.length) ports.push({ name: "default", kind: "default", fields: [] });
|
|
61
|
+
return ports;
|
|
62
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure helpers behind the workbench's sample-data layer: turning run-step
|
|
3
|
+
* outputs into per-port value maps, walking value paths, and resolving
|
|
4
|
+
* `${{ … }}` expressions against sampled data for the inline previews.
|
|
5
|
+
* Sample data is author-time sugar only — the engine never sees any of it.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* A run step's `output` payload is the node activity result — usually
|
|
9
|
+
* `{ outputs: { <port>: value }, branch? }`. Older/odd payloads may be the
|
|
10
|
+
* bare value; those count as the `default` port.
|
|
11
|
+
*/
|
|
12
|
+
export declare function portValuesFromStepOutput(output: unknown): Record<string, unknown>;
|
|
13
|
+
/**
|
|
14
|
+
* Walk `root` along dot-path segments; `undefined` on any miss. Mirrors the
|
|
15
|
+
* ENGINE's resolver semantics exactly: an array auto-maps the remaining path
|
|
16
|
+
* over its elements (`items.sku` → array of skus) and numeric segments are
|
|
17
|
+
* NOT indices — the preview must predict what a run would produce.
|
|
18
|
+
*/
|
|
19
|
+
export declare function valueAtPath(root: unknown, path: string[]): unknown;
|
|
20
|
+
/** Compact single-line preview of a sampled value, capped for chip display. */
|
|
21
|
+
export declare function previewValue(v: unknown, max?: number): string;
|
|
22
|
+
/** Map a sampled value onto the manifest dataType vocabulary (for glyphs). */
|
|
23
|
+
export declare function dataTypeOf(v: unknown): string | null;
|
|
24
|
+
export interface SampleContext {
|
|
25
|
+
/** nodeId → port → sampled payload (pinned sample or last-run output). */
|
|
26
|
+
nodeOutputs: Record<string, Record<string, unknown>>;
|
|
27
|
+
triggerPayload?: unknown;
|
|
28
|
+
variables?: Record<string, unknown>;
|
|
29
|
+
}
|
|
30
|
+
export interface ResolvedPreview {
|
|
31
|
+
/** The text with every resolvable token replaced by its sampled value. */
|
|
32
|
+
resolved: string;
|
|
33
|
+
/** Tokens that resolved against the sample context. */
|
|
34
|
+
hits: number;
|
|
35
|
+
/** Tokens the context has no data for (left in place). */
|
|
36
|
+
misses: number;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Resolve the `${{ … }}` tokens inside `text` against sampled data. Returns
|
|
40
|
+
* null when the text contains no tokens (nothing to preview). Unresolvable
|
|
41
|
+
* tokens stay verbatim and are counted as misses — the preview renders either
|
|
42
|
+
* way so the operator sees which part is still unknown.
|
|
43
|
+
*/
|
|
44
|
+
export declare function resolveExpressionText(text: string, ctx: SampleContext): ResolvedPreview | null;
|
|
45
|
+
export interface ExpressionToken {
|
|
46
|
+
/** The full `${{ … }}` token as it appears in the text. */
|
|
47
|
+
token: string;
|
|
48
|
+
/** The trimmed inner expression. */
|
|
49
|
+
expr: string;
|
|
50
|
+
start: number;
|
|
51
|
+
end: number;
|
|
52
|
+
}
|
|
53
|
+
/** Every expression token inside `text`, with positions for splicing. */
|
|
54
|
+
export declare function listExpressionTokens(text: string): ExpressionToken[];
|
|
55
|
+
/** Resolve one bare expression (no braces) against the sample context. */
|
|
56
|
+
export declare function resolveExpression(expr: string, ctx: SampleContext): unknown;
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
const TOKEN_RE = new RegExp("\\$\\{\\{\\s*([^}]+?)\\s*\\}\\}", "g");
|
|
2
|
+
export function portValuesFromStepOutput(output) {
|
|
3
|
+
if (output && typeof output === "object" && !Array.isArray(output)) {
|
|
4
|
+
const outputs = output.outputs;
|
|
5
|
+
if (outputs && typeof outputs === "object" && !Array.isArray(outputs)) {
|
|
6
|
+
return outputs;
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
if (output === void 0 || output === null) return {};
|
|
10
|
+
return { default: output };
|
|
11
|
+
}
|
|
12
|
+
export function valueAtPath(root, path) {
|
|
13
|
+
let cur = root;
|
|
14
|
+
for (let i = 0; i < path.length; i++) {
|
|
15
|
+
const seg = path[i];
|
|
16
|
+
if (seg === "") return void 0;
|
|
17
|
+
if (Array.isArray(cur)) {
|
|
18
|
+
const rest = path.slice(i);
|
|
19
|
+
return cur.map((el) => valueAtPath(el, rest));
|
|
20
|
+
}
|
|
21
|
+
if (!cur || typeof cur !== "object") return void 0;
|
|
22
|
+
cur = cur[seg];
|
|
23
|
+
}
|
|
24
|
+
return cur;
|
|
25
|
+
}
|
|
26
|
+
export function previewValue(v, max = 42) {
|
|
27
|
+
let s;
|
|
28
|
+
if (typeof v === "string") s = v;
|
|
29
|
+
else {
|
|
30
|
+
try {
|
|
31
|
+
s = JSON.stringify(v) ?? String(v);
|
|
32
|
+
} catch {
|
|
33
|
+
s = String(v);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
s = s.replace(/\s+/g, " ");
|
|
37
|
+
return s.length > max ? s.slice(0, max - 1) + "\u2026" : s;
|
|
38
|
+
}
|
|
39
|
+
export function dataTypeOf(v) {
|
|
40
|
+
if (v === null || v === void 0) return null;
|
|
41
|
+
if (Array.isArray(v)) return "array";
|
|
42
|
+
const t = typeof v;
|
|
43
|
+
if (t === "object") return "object";
|
|
44
|
+
if (t === "string" || t === "number" || t === "boolean") return t;
|
|
45
|
+
return null;
|
|
46
|
+
}
|
|
47
|
+
export function resolveExpressionText(text, ctx) {
|
|
48
|
+
let hits = 0;
|
|
49
|
+
let misses = 0;
|
|
50
|
+
let sawToken = false;
|
|
51
|
+
const resolved = text.replace(TOKEN_RE, (token, inner) => {
|
|
52
|
+
sawToken = true;
|
|
53
|
+
const value = resolveExpression(inner, ctx);
|
|
54
|
+
if (value === void 0) {
|
|
55
|
+
misses++;
|
|
56
|
+
return token;
|
|
57
|
+
}
|
|
58
|
+
hits++;
|
|
59
|
+
return typeof value === "string" ? value : previewValue(value, 200);
|
|
60
|
+
});
|
|
61
|
+
if (!sawToken) return null;
|
|
62
|
+
return { resolved, hits, misses };
|
|
63
|
+
}
|
|
64
|
+
export function listExpressionTokens(text) {
|
|
65
|
+
const re = new RegExp(TOKEN_RE.source, "g");
|
|
66
|
+
const out = [];
|
|
67
|
+
for (let m = re.exec(text); m !== null; m = re.exec(text)) {
|
|
68
|
+
out.push({ token: m[0], expr: (m[1] ?? "").trim(), start: m.index, end: m.index + m[0].length });
|
|
69
|
+
}
|
|
70
|
+
return out;
|
|
71
|
+
}
|
|
72
|
+
export function resolveExpression(expr, ctx) {
|
|
73
|
+
const path = expr.trim().split(".");
|
|
74
|
+
if (path[0] === "nodes" && path.length >= 4 && path[2] === "outputs") {
|
|
75
|
+
const ports = ctx.nodeOutputs[path[1]];
|
|
76
|
+
if (!ports) return void 0;
|
|
77
|
+
const port = path[3];
|
|
78
|
+
if (!(port in ports)) return void 0;
|
|
79
|
+
return valueAtPath(ports[port], path.slice(4));
|
|
80
|
+
}
|
|
81
|
+
if (path[0] === "trigger" && path[1] === "payload") {
|
|
82
|
+
if (ctx.triggerPayload === void 0) return void 0;
|
|
83
|
+
return valueAtPath(ctx.triggerPayload, path.slice(2));
|
|
84
|
+
}
|
|
85
|
+
if (path[0] === "vars" && path.length >= 2) {
|
|
86
|
+
const vars = ctx.variables ?? {};
|
|
87
|
+
if (!(path[1] in vars)) return void 0;
|
|
88
|
+
return valueAtPath(vars[path[1]], path.slice(2));
|
|
89
|
+
}
|
|
90
|
+
return void 0;
|
|
91
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import type { WorkflowBlob } from '../types/integrations.js';
|
|
2
|
+
/**
|
|
3
|
+
* Derives an input form for a manual run from the workflow blob itself: every
|
|
4
|
+
* `${{ trigger.payload.<path> }}` reference a node config carries becomes one
|
|
5
|
+
* form field — the workflow declares implicitly what it consumes, so no extra
|
|
6
|
+
* schema is needed and every existing template gets a form for free.
|
|
7
|
+
*
|
|
8
|
+
* File convention: a path group whose members include `data` (optionally
|
|
9
|
+
* `filename` / `contentType` / `size`) is rendered as ONE file field — picking
|
|
10
|
+
* a file fills the whole group (base64 + metadata), matching the workflow
|
|
11
|
+
* file-object shape the io/storage nodes consume.
|
|
12
|
+
*/
|
|
13
|
+
export interface PayloadField {
|
|
14
|
+
kind: 'text' | 'file';
|
|
15
|
+
/** Dot-path below `trigger.payload` ('' = the payload root, file groups only). */
|
|
16
|
+
path: string;
|
|
17
|
+
label: string;
|
|
18
|
+
}
|
|
19
|
+
/** Scan the blob's node configs and derive the payload form fields. */
|
|
20
|
+
export declare function payloadFieldsFromBlob(blob: Pick<WorkflowBlob, 'nodes'>): PayloadField[];
|
|
21
|
+
export declare function setPath(target: Record<string, unknown>, path: string, value: unknown): void;
|
|
22
|
+
export declare function getPath(source: Record<string, unknown>, path: string): unknown;
|
|
23
|
+
export interface AttachedFile {
|
|
24
|
+
data: string;
|
|
25
|
+
filename: string;
|
|
26
|
+
contentType: string;
|
|
27
|
+
size: number;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Build the run payload: expert-only extras first (preserved), then the form
|
|
31
|
+
* values on top. Text values that parse as JSON scalars/objects are passed
|
|
32
|
+
* typed (numbers stay numbers, `{"a":1}` becomes an object); everything else
|
|
33
|
+
* stays a string.
|
|
34
|
+
*/
|
|
35
|
+
export declare function buildPayload(fields: PayloadField[], textValues: Record<string, string>, files: Record<string, AttachedFile | null>, extras: Record<string, unknown>): Record<string, unknown>;
|
|
36
|
+
/**
|
|
37
|
+
* Split a payload object into form values + expert extras: known field paths
|
|
38
|
+
* feed the form, everything else is preserved verbatim for the expert view.
|
|
39
|
+
*/
|
|
40
|
+
export declare function splitPayload(fields: PayloadField[], payload: Record<string, unknown>): {
|
|
41
|
+
textValues: Record<string, string>;
|
|
42
|
+
files: Record<string, AttachedFile | null>;
|
|
43
|
+
extras: Record<string, unknown>;
|
|
44
|
+
};
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
const PAYLOAD_REF_RE = /\$\{\{\s*trigger\.payload\.([a-zA-Z0-9_.-]+)/g;
|
|
2
|
+
const FILE_KEYS = /* @__PURE__ */ new Set(["data", "filename", "contentType", "size"]);
|
|
3
|
+
function collectRefs(value, out) {
|
|
4
|
+
if (typeof value === "string") {
|
|
5
|
+
for (const m of value.matchAll(PAYLOAD_REF_RE)) out.add(m[1]);
|
|
6
|
+
} else if (Array.isArray(value)) {
|
|
7
|
+
for (const v of value) collectRefs(v, out);
|
|
8
|
+
} else if (value !== null && typeof value === "object") {
|
|
9
|
+
for (const v of Object.values(value)) collectRefs(v, out);
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
function labelFor(path) {
|
|
13
|
+
const last = path.split(".").pop() ?? path;
|
|
14
|
+
return last.replace(/[_-]/g, " ").replace(/([a-z])([A-Z])/g, "$1 $2").replace(/^./, (c) => c.toUpperCase());
|
|
15
|
+
}
|
|
16
|
+
export function payloadFieldsFromBlob(blob) {
|
|
17
|
+
const refs = /* @__PURE__ */ new Set();
|
|
18
|
+
for (const node of blob.nodes ?? []) collectRefs(node.config, refs);
|
|
19
|
+
if (refs.size === 0) return [];
|
|
20
|
+
const byPrefix = /* @__PURE__ */ new Map();
|
|
21
|
+
for (const ref of refs) {
|
|
22
|
+
const idx = ref.lastIndexOf(".");
|
|
23
|
+
const prefix = idx === -1 ? "" : ref.slice(0, idx);
|
|
24
|
+
const leaf = idx === -1 ? ref : ref.slice(idx + 1);
|
|
25
|
+
if (!byPrefix.has(prefix)) byPrefix.set(prefix, /* @__PURE__ */ new Set());
|
|
26
|
+
byPrefix.get(prefix).add(leaf);
|
|
27
|
+
}
|
|
28
|
+
const fields = [];
|
|
29
|
+
const consumed = /* @__PURE__ */ new Set();
|
|
30
|
+
for (const [prefix, leaves] of byPrefix) {
|
|
31
|
+
if (leaves.has("data")) {
|
|
32
|
+
fields.push({ kind: "file", path: prefix, label: prefix === "" ? "File" : labelFor(prefix) });
|
|
33
|
+
for (const leaf of leaves) {
|
|
34
|
+
if (FILE_KEYS.has(leaf)) consumed.add(prefix === "" ? leaf : `${prefix}.${leaf}`);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
for (const ref of [...refs].sort()) {
|
|
39
|
+
if (consumed.has(ref)) continue;
|
|
40
|
+
fields.push({ kind: "text", path: ref, label: labelFor(ref) });
|
|
41
|
+
}
|
|
42
|
+
return fields.sort((a, b) => a.kind === b.kind ? a.path.localeCompare(b.path) : a.kind === "file" ? -1 : 1);
|
|
43
|
+
}
|
|
44
|
+
export function setPath(target, path, value) {
|
|
45
|
+
if (path === "") {
|
|
46
|
+
if (value !== null && typeof value === "object") Object.assign(target, value);
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
const parts = path.split(".");
|
|
50
|
+
let cursor = target;
|
|
51
|
+
for (let i = 0; i < parts.length - 1; i++) {
|
|
52
|
+
const key = parts[i];
|
|
53
|
+
const next = cursor[key];
|
|
54
|
+
if (next === null || typeof next !== "object" || Array.isArray(next)) cursor[key] = {};
|
|
55
|
+
cursor = cursor[key];
|
|
56
|
+
}
|
|
57
|
+
cursor[parts[parts.length - 1]] = value;
|
|
58
|
+
}
|
|
59
|
+
export function getPath(source, path) {
|
|
60
|
+
if (path === "") return source;
|
|
61
|
+
let cursor = source;
|
|
62
|
+
for (const part of path.split(".")) {
|
|
63
|
+
if (cursor === null || typeof cursor !== "object") return void 0;
|
|
64
|
+
cursor = cursor[part];
|
|
65
|
+
}
|
|
66
|
+
return cursor;
|
|
67
|
+
}
|
|
68
|
+
export function buildPayload(fields, textValues, files, extras) {
|
|
69
|
+
const payload = JSON.parse(JSON.stringify(extras ?? {}));
|
|
70
|
+
for (const field of fields) {
|
|
71
|
+
if (field.kind === "file") {
|
|
72
|
+
const file = files[field.path];
|
|
73
|
+
if (file) setPath(payload, field.path, { ...file });
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
76
|
+
const raw = textValues[field.path];
|
|
77
|
+
if (raw === void 0 || raw === "") continue;
|
|
78
|
+
let value = raw;
|
|
79
|
+
try {
|
|
80
|
+
const parsed = JSON.parse(raw);
|
|
81
|
+
if (typeof parsed !== "string") value = parsed;
|
|
82
|
+
} catch {
|
|
83
|
+
}
|
|
84
|
+
setPath(payload, field.path, value);
|
|
85
|
+
}
|
|
86
|
+
return payload;
|
|
87
|
+
}
|
|
88
|
+
export function splitPayload(fields, payload) {
|
|
89
|
+
const extras = JSON.parse(JSON.stringify(payload ?? {}));
|
|
90
|
+
const textValues = {};
|
|
91
|
+
const files = {};
|
|
92
|
+
const deleteAt = (path) => {
|
|
93
|
+
if (path === "") return;
|
|
94
|
+
const parts = path.split(".");
|
|
95
|
+
let cursor = extras;
|
|
96
|
+
for (let i = 0; i < parts.length - 1; i++) {
|
|
97
|
+
if (cursor === null || typeof cursor !== "object") return;
|
|
98
|
+
cursor = cursor[parts[i]];
|
|
99
|
+
}
|
|
100
|
+
if (cursor !== null && typeof cursor === "object") delete cursor[parts[parts.length - 1]];
|
|
101
|
+
};
|
|
102
|
+
for (const field of fields) {
|
|
103
|
+
const value = getPath(payload, field.path);
|
|
104
|
+
if (field.kind === "file") {
|
|
105
|
+
const data = value !== null && typeof value === "object" ? value.data : void 0;
|
|
106
|
+
if (typeof data === "string" && data !== "") {
|
|
107
|
+
const v = value;
|
|
108
|
+
files[field.path] = {
|
|
109
|
+
data,
|
|
110
|
+
filename: typeof v.filename === "string" ? v.filename : "file",
|
|
111
|
+
contentType: typeof v.contentType === "string" ? v.contentType : "application/octet-stream",
|
|
112
|
+
size: typeof v.size === "number" ? v.size : Math.floor(data.length * 3 / 4)
|
|
113
|
+
};
|
|
114
|
+
} else {
|
|
115
|
+
files[field.path] = null;
|
|
116
|
+
}
|
|
117
|
+
for (const key of FILE_KEYS) deleteAt(field.path === "" ? key : `${field.path}.${key}`);
|
|
118
|
+
continue;
|
|
119
|
+
}
|
|
120
|
+
if (value !== void 0) {
|
|
121
|
+
textValues[field.path] = typeof value === "string" ? value : JSON.stringify(value);
|
|
122
|
+
deleteAt(field.path);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
return { textValues, files, extras };
|
|
126
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { Component } from 'vue';
|
|
2
|
+
/**
|
|
3
|
+
* Curated icon set a workflow can carry (`blob.icon`, kind `solar`). Only
|
|
4
|
+
* names from this map are stored — the picker offers them, `solarIconFor`
|
|
5
|
+
* resolves them, unknown/legacy names fall back to the workflow glyph.
|
|
6
|
+
* Every name here MUST already be a valid `#solar-icons` export.
|
|
7
|
+
*/
|
|
8
|
+
export declare const WORKFLOW_SOLAR_ICONS: Record<string, Component>;
|
|
9
|
+
/** Resolve a stored solar icon name; unknown names fall back to the workflow glyph. */
|
|
10
|
+
export declare function solarIconFor(name: string | undefined): Component;
|
|
11
|
+
/**
|
|
12
|
+
* Stable identity of a node-package image: the image UUID. Accepts both the
|
|
13
|
+
* bare UUID (what new blobs store) and a full signed image URL (what the
|
|
14
|
+
* registry serves and what legacy blobs stored — those URLs expire, which is
|
|
15
|
+
* exactly why only the UUID is persisted).
|
|
16
|
+
*/
|
|
17
|
+
export declare function imageIdFromSrc(src: string | undefined | null): string | null;
|
|
18
|
+
/**
|
|
19
|
+
* Resolve a stored image reference (UUID or legacy signed URL) to a FRESH
|
|
20
|
+
* signed URL from the live node catalog — manifests are re-signed on every
|
|
21
|
+
* fetch, so this never serves an expired signature. Reactive via the catalog.
|
|
22
|
+
*/
|
|
23
|
+
export declare function freshImageSrc(stored: string | undefined | null): string | null;
|
|
24
|
+
/**
|
|
25
|
+
* Unique node-package logos usable as workflow images (`blob.icon`, kind
|
|
26
|
+
* `image`) — so a Business Central workflow can wear the Business Central
|
|
27
|
+
* logo. Deduped by stable image id; `id` is what gets persisted (stable),
|
|
28
|
+
* `src` is the current fresh signed URL for previewing.
|
|
29
|
+
*/
|
|
30
|
+
export declare function nodeLogoOptions(): Array<{
|
|
31
|
+
label: string;
|
|
32
|
+
id: string;
|
|
33
|
+
src: string;
|
|
34
|
+
}>;
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Bag,
|
|
3
|
+
Bell,
|
|
4
|
+
Bolt,
|
|
5
|
+
Box,
|
|
6
|
+
Buildings,
|
|
7
|
+
CalendarMinimalistic,
|
|
8
|
+
Card,
|
|
9
|
+
Cart,
|
|
10
|
+
ChartSquare,
|
|
11
|
+
ClockCircle,
|
|
12
|
+
Database,
|
|
13
|
+
Download,
|
|
14
|
+
Earth,
|
|
15
|
+
FileText,
|
|
16
|
+
Folder,
|
|
17
|
+
Global,
|
|
18
|
+
GraphDown,
|
|
19
|
+
GraphUp,
|
|
20
|
+
Key,
|
|
21
|
+
Layers,
|
|
22
|
+
Letter,
|
|
23
|
+
LinkRound,
|
|
24
|
+
MagicStick,
|
|
25
|
+
Programming,
|
|
26
|
+
Pulse,
|
|
27
|
+
Radio,
|
|
28
|
+
Server,
|
|
29
|
+
ShieldCheck,
|
|
30
|
+
Shop,
|
|
31
|
+
Star,
|
|
32
|
+
TagPrice,
|
|
33
|
+
TestTube,
|
|
34
|
+
Upload,
|
|
35
|
+
User,
|
|
36
|
+
UsersGroupRounded,
|
|
37
|
+
WalletMoney
|
|
38
|
+
} from "#solar-icons";
|
|
39
|
+
import { INTEGRATION_NODE_CATALOG } from "./integrationNodeCatalog.js";
|
|
40
|
+
export const WORKFLOW_SOLAR_ICONS = {
|
|
41
|
+
Programming,
|
|
42
|
+
Bolt,
|
|
43
|
+
ClockCircle,
|
|
44
|
+
LinkRound,
|
|
45
|
+
Radio,
|
|
46
|
+
Database,
|
|
47
|
+
Server,
|
|
48
|
+
Box,
|
|
49
|
+
Layers,
|
|
50
|
+
Folder,
|
|
51
|
+
FileText,
|
|
52
|
+
Letter,
|
|
53
|
+
Upload,
|
|
54
|
+
Download,
|
|
55
|
+
Pulse,
|
|
56
|
+
GraphUp,
|
|
57
|
+
GraphDown,
|
|
58
|
+
ChartSquare,
|
|
59
|
+
MagicStick,
|
|
60
|
+
ShieldCheck,
|
|
61
|
+
Key,
|
|
62
|
+
Cart,
|
|
63
|
+
Bag,
|
|
64
|
+
Shop,
|
|
65
|
+
Card,
|
|
66
|
+
WalletMoney,
|
|
67
|
+
TagPrice,
|
|
68
|
+
Buildings,
|
|
69
|
+
Global,
|
|
70
|
+
Earth,
|
|
71
|
+
User,
|
|
72
|
+
UsersGroupRounded,
|
|
73
|
+
Bell,
|
|
74
|
+
CalendarMinimalistic,
|
|
75
|
+
Star,
|
|
76
|
+
TestTube
|
|
77
|
+
};
|
|
78
|
+
export function solarIconFor(name) {
|
|
79
|
+
return (name ? WORKFLOW_SOLAR_ICONS[name] : void 0) ?? Programming;
|
|
80
|
+
}
|
|
81
|
+
function loc(v) {
|
|
82
|
+
if (!v) return "";
|
|
83
|
+
return typeof v === "string" ? v : v.en ?? Object.values(v)[0] ?? "";
|
|
84
|
+
}
|
|
85
|
+
const UUID = "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}";
|
|
86
|
+
const IMAGE_URL_ID_RE = new RegExp(`node-packages/images/(${UUID})`, "i");
|
|
87
|
+
const BARE_UUID_RE = new RegExp(`^${UUID}$`, "i");
|
|
88
|
+
export function imageIdFromSrc(src) {
|
|
89
|
+
if (!src) return null;
|
|
90
|
+
if (BARE_UUID_RE.test(src)) return src.toLowerCase();
|
|
91
|
+
const m = IMAGE_URL_ID_RE.exec(src);
|
|
92
|
+
return m?.[1]?.toLowerCase() ?? null;
|
|
93
|
+
}
|
|
94
|
+
export function freshImageSrc(stored) {
|
|
95
|
+
const id = imageIdFromSrc(stored);
|
|
96
|
+
if (!id) return null;
|
|
97
|
+
for (const m of INTEGRATION_NODE_CATALOG) {
|
|
98
|
+
for (const img of m.images ?? []) {
|
|
99
|
+
if (img.src && img.src.toLowerCase().includes(`/images/${id}`)) return img.src;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
return null;
|
|
103
|
+
}
|
|
104
|
+
export function nodeLogoOptions() {
|
|
105
|
+
const byId = /* @__PURE__ */ new Map();
|
|
106
|
+
for (const m of INTEGRATION_NODE_CATALOG) {
|
|
107
|
+
const imgs = m.images ?? [];
|
|
108
|
+
const logo = imgs.find((i) => i.category === "logo") ?? imgs[0];
|
|
109
|
+
if (!logo?.src) continue;
|
|
110
|
+
const id = imageIdFromSrc(logo.src) ?? logo.src;
|
|
111
|
+
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 });
|
|
114
|
+
}
|
|
115
|
+
return [...byId.entries()].map(([id, v]) => ({ id, src: v.src, label: v.label })).sort((a, b) => a.label.localeCompare(b.label));
|
|
116
|
+
}
|