@revenexx/studio-integrations 0.1.4 → 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.
Files changed (179) hide show
  1. package/dist/module.json +1 -1
  2. package/dist/runtime/components/Integrations/CredentialCreateDialog.d.vue.ts +13 -0
  3. package/dist/runtime/components/Integrations/CredentialCreateDialog.vue +279 -0
  4. package/dist/runtime/components/Integrations/CredentialCreateDialog.vue.d.ts +13 -0
  5. package/dist/runtime/components/Integrations/CredentialDetailDialog.d.vue.ts +20 -0
  6. package/dist/runtime/components/Integrations/CredentialDetailDialog.vue +342 -0
  7. package/dist/runtime/components/Integrations/CredentialDetailDialog.vue.d.ts +20 -0
  8. package/dist/runtime/components/Integrations/CredentialLogo.d.vue.ts +14 -0
  9. package/dist/runtime/components/Integrations/CredentialLogo.vue +37 -0
  10. package/dist/runtime/components/Integrations/CredentialLogo.vue.d.ts +14 -0
  11. package/dist/runtime/components/Integrations/CredentialRevenexxSource.d.vue.ts +12 -0
  12. package/dist/runtime/components/Integrations/CredentialRevenexxSource.vue +364 -0
  13. package/dist/runtime/components/Integrations/CredentialRevenexxSource.vue.d.ts +12 -0
  14. package/dist/runtime/components/Integrations/CredentialTypePicker.d.vue.ts +15 -0
  15. package/dist/runtime/components/Integrations/CredentialTypePicker.vue +71 -0
  16. package/dist/runtime/components/Integrations/CredentialTypePicker.vue.d.ts +15 -0
  17. package/dist/runtime/components/Integrations/DeadLettersPanel.d.vue.ts +5 -0
  18. package/dist/runtime/components/Integrations/DeadLettersPanel.vue +151 -0
  19. package/dist/runtime/components/Integrations/DeadLettersPanel.vue.d.ts +5 -0
  20. package/dist/runtime/components/Integrations/EditorTip.d.vue.ts +17 -0
  21. package/dist/runtime/components/Integrations/EditorTip.vue +46 -0
  22. package/dist/runtime/components/Integrations/EditorTip.vue.d.ts +17 -0
  23. package/dist/runtime/components/Integrations/EventTypeCombobox.d.vue.ts +9 -0
  24. package/dist/runtime/components/Integrations/EventTypeCombobox.vue +64 -0
  25. package/dist/runtime/components/Integrations/EventTypeCombobox.vue.d.ts +9 -0
  26. package/dist/runtime/components/Integrations/ExpressionInput.d.vue.ts +19 -0
  27. package/dist/runtime/components/Integrations/ExpressionInput.vue +236 -0
  28. package/dist/runtime/components/Integrations/ExpressionInput.vue.d.ts +19 -0
  29. package/dist/runtime/components/Integrations/GroupFrameView.d.vue.ts +28 -0
  30. package/dist/runtime/components/Integrations/GroupFrameView.vue +222 -0
  31. package/dist/runtime/components/Integrations/GroupFrameView.vue.d.ts +28 -0
  32. package/dist/runtime/components/Integrations/NodeConfigDynamicField.d.vue.ts +14 -0
  33. package/dist/runtime/components/Integrations/NodeConfigDynamicField.vue +184 -0
  34. package/dist/runtime/components/Integrations/NodeConfigDynamicField.vue.d.ts +14 -0
  35. package/dist/runtime/components/Integrations/NodeConfigDynamicSchema.d.vue.ts +16 -0
  36. package/dist/runtime/components/Integrations/NodeConfigDynamicSchema.vue +102 -0
  37. package/dist/runtime/components/Integrations/NodeConfigDynamicSchema.vue.d.ts +16 -0
  38. package/dist/runtime/components/Integrations/NodeConfigField.d.vue.ts +23 -0
  39. package/dist/runtime/components/Integrations/NodeConfigField.vue +587 -0
  40. package/dist/runtime/components/Integrations/NodeConfigField.vue.d.ts +23 -0
  41. package/dist/runtime/components/Integrations/NodeDynamicOutputsResolver.d.vue.ts +14 -0
  42. package/dist/runtime/components/Integrations/NodeDynamicOutputsResolver.vue +80 -0
  43. package/dist/runtime/components/Integrations/NodeDynamicOutputsResolver.vue.d.ts +14 -0
  44. package/dist/runtime/components/Integrations/NodeInspector.d.vue.ts +22 -3
  45. package/dist/runtime/components/Integrations/NodeInspector.vue +1074 -294
  46. package/dist/runtime/components/Integrations/NodeInspector.vue.d.ts +22 -3
  47. package/dist/runtime/components/Integrations/NodeLogo.d.vue.ts +9 -0
  48. package/dist/runtime/components/Integrations/NodeLogo.vue +38 -0
  49. package/dist/runtime/components/Integrations/NodeLogo.vue.d.ts +9 -0
  50. package/dist/runtime/components/Integrations/NodePalette.d.vue.ts +22 -1
  51. package/dist/runtime/components/Integrations/NodePalette.vue +411 -90
  52. package/dist/runtime/components/Integrations/NodePalette.vue.d.ts +22 -1
  53. package/dist/runtime/components/Integrations/QueryBuilder.d.vue.ts +9 -0
  54. package/dist/runtime/components/Integrations/QueryBuilder.vue +239 -0
  55. package/dist/runtime/components/Integrations/QueryBuilder.vue.d.ts +9 -0
  56. package/dist/runtime/components/Integrations/{RunDetailDialog.d.vue.ts → RunActionsMenu.d.vue.ts} +3 -4
  57. package/dist/runtime/components/Integrations/RunActionsMenu.vue +86 -0
  58. package/dist/runtime/components/Integrations/{RunDetailDialog.vue.d.ts → RunActionsMenu.vue.d.ts} +3 -4
  59. package/dist/runtime/components/Integrations/RunDetailPanel.d.vue.ts +14 -0
  60. package/dist/runtime/components/Integrations/RunDetailPanel.vue +777 -0
  61. package/dist/runtime/components/Integrations/RunDetailPanel.vue.d.ts +14 -0
  62. package/dist/runtime/components/Integrations/RunPayloadInput.d.vue.ts +13 -0
  63. package/dist/runtime/components/Integrations/RunPayloadInput.vue +175 -0
  64. package/dist/runtime/components/Integrations/RunPayloadInput.vue.d.ts +13 -0
  65. package/dist/runtime/components/Integrations/RunResponseModal.d.vue.ts +27 -0
  66. package/dist/runtime/components/Integrations/RunResponseModal.vue +84 -0
  67. package/dist/runtime/components/Integrations/RunResponseModal.vue.d.ts +27 -0
  68. package/dist/runtime/components/Integrations/RunsTable.d.vue.ts +21 -0
  69. package/dist/runtime/components/Integrations/RunsTable.vue +114 -0
  70. package/dist/runtime/components/Integrations/RunsTable.vue.d.ts +21 -0
  71. package/dist/runtime/components/Integrations/SftpAccountImportDialog.d.vue.ts +11 -0
  72. package/dist/runtime/components/Integrations/SftpAccountImportDialog.vue +91 -0
  73. package/dist/runtime/components/Integrations/SftpAccountImportDialog.vue.d.ts +11 -0
  74. package/dist/runtime/components/Integrations/StickyNoteView.d.vue.ts +28 -0
  75. package/dist/runtime/components/Integrations/StickyNoteView.vue +208 -0
  76. package/dist/runtime/components/Integrations/StickyNoteView.vue.d.ts +28 -0
  77. package/dist/runtime/components/Integrations/TemplateFlowPreview.d.vue.ts +29 -0
  78. package/dist/runtime/components/Integrations/TemplateFlowPreview.vue +201 -0
  79. package/dist/runtime/components/Integrations/TemplateFlowPreview.vue.d.ts +29 -0
  80. package/dist/runtime/components/Integrations/WorkflowContextMenu.d.vue.ts +32 -0
  81. package/dist/runtime/components/Integrations/WorkflowContextMenu.vue +138 -0
  82. package/dist/runtime/components/Integrations/WorkflowContextMenu.vue.d.ts +32 -0
  83. package/dist/runtime/components/Integrations/WorkflowCreateDialog.d.vue.ts +9 -0
  84. package/dist/runtime/components/Integrations/WorkflowCreateDialog.vue +322 -0
  85. package/dist/runtime/components/Integrations/WorkflowCreateDialog.vue.d.ts +9 -0
  86. package/dist/runtime/components/Integrations/WorkflowDuplicateDialog.d.vue.ts +18 -0
  87. package/dist/runtime/components/Integrations/WorkflowDuplicateDialog.vue +63 -0
  88. package/dist/runtime/components/Integrations/WorkflowDuplicateDialog.vue.d.ts +18 -0
  89. package/dist/runtime/components/Integrations/WorkflowEdgeView.d.vue.ts +12 -1
  90. package/dist/runtime/components/Integrations/WorkflowEdgeView.vue +68 -6
  91. package/dist/runtime/components/Integrations/WorkflowEdgeView.vue.d.ts +12 -1
  92. package/dist/runtime/components/Integrations/WorkflowEditor.d.vue.ts +8 -1
  93. package/dist/runtime/components/Integrations/WorkflowEditor.vue +1424 -144
  94. package/dist/runtime/components/Integrations/WorkflowEditor.vue.d.ts +8 -1
  95. package/dist/runtime/components/Integrations/WorkflowHistoryPanel.d.vue.ts +12 -0
  96. package/dist/runtime/components/Integrations/WorkflowHistoryPanel.vue +417 -0
  97. package/dist/runtime/components/Integrations/WorkflowHistoryPanel.vue.d.ts +12 -0
  98. package/dist/runtime/components/Integrations/WorkflowIconPicker.d.vue.ts +10 -0
  99. package/dist/runtime/components/Integrations/WorkflowIconPicker.vue +89 -0
  100. package/dist/runtime/components/Integrations/WorkflowIconPicker.vue.d.ts +10 -0
  101. package/dist/runtime/components/Integrations/WorkflowIconView.d.vue.ts +10 -0
  102. package/dist/runtime/components/Integrations/WorkflowIconView.vue +35 -0
  103. package/dist/runtime/components/Integrations/WorkflowIconView.vue.d.ts +10 -0
  104. package/dist/runtime/components/Integrations/WorkflowNodeView.d.vue.ts +5 -1
  105. package/dist/runtime/components/Integrations/WorkflowNodeView.vue +114 -84
  106. package/dist/runtime/components/Integrations/WorkflowNodeView.vue.d.ts +5 -1
  107. package/dist/runtime/components/Integrations/WorkflowRunReplayPanel.d.vue.ts +12 -0
  108. package/dist/runtime/components/Integrations/WorkflowRunReplayPanel.vue +654 -0
  109. package/dist/runtime/components/Integrations/WorkflowRunReplayPanel.vue.d.ts +12 -0
  110. package/dist/runtime/components/Integrations/WorkflowSettingsDialog.d.vue.ts +36 -0
  111. package/dist/runtime/components/Integrations/WorkflowSettingsDialog.vue +136 -0
  112. package/dist/runtime/components/Integrations/WorkflowSettingsDialog.vue.d.ts +36 -0
  113. package/dist/runtime/components/Integrations/WorkflowTagsInput.d.vue.ts +14 -0
  114. package/dist/runtime/components/Integrations/WorkflowTagsInput.vue +63 -0
  115. package/dist/runtime/components/Integrations/WorkflowTagsInput.vue.d.ts +14 -0
  116. package/dist/runtime/components/Integrations/WorkflowTriggerView.vue +35 -15
  117. package/dist/runtime/components/Integrations/WorkflowVariablesDialog.d.vue.ts +13 -0
  118. package/dist/runtime/components/Integrations/WorkflowVariablesDialog.vue +265 -0
  119. package/dist/runtime/components/Integrations/WorkflowVariablesDialog.vue.d.ts +13 -0
  120. package/dist/runtime/components/Integrations/WorkflowsTable.d.vue.ts +4 -1
  121. package/dist/runtime/components/Integrations/WorkflowsTable.vue +122 -39
  122. package/dist/runtime/components/Integrations/WorkflowsTable.vue.d.ts +4 -1
  123. package/dist/runtime/components/Integrations/workflowLayout.d.ts +5 -0
  124. package/dist/runtime/components/Integrations/workflowLayout.js +5 -3
  125. package/dist/runtime/composables/integrationsApi.d.ts +6 -2
  126. package/dist/runtime/composables/integrationsApi.js +5 -4
  127. package/dist/runtime/composables/useCanvasShortcuts.d.ts +37 -0
  128. package/dist/runtime/composables/useCanvasShortcuts.js +62 -0
  129. package/dist/runtime/composables/useIntegrationsDeadLetters.d.ts +22 -0
  130. package/dist/runtime/composables/useIntegrationsDeadLetters.js +50 -0
  131. package/dist/runtime/composables/useIntegrationsNodes.d.ts +4 -0
  132. package/dist/runtime/composables/useIntegrationsNodes.js +6 -3
  133. package/dist/runtime/composables/useIntegrationsRevisions.d.ts +40 -0
  134. package/dist/runtime/composables/useIntegrationsRevisions.js +51 -0
  135. package/dist/runtime/composables/useIntegrationsRuns.d.ts +21 -1
  136. package/dist/runtime/composables/useIntegrationsRuns.js +92 -4
  137. package/dist/runtime/composables/useIntegrationsTemplates.d.ts +1 -0
  138. package/dist/runtime/composables/useIntegrationsTemplates.js +32 -4
  139. package/dist/runtime/composables/useIntegrationsWorkflows.d.ts +1 -0
  140. package/dist/runtime/composables/useIntegrationsWorkflows.js +57 -1
  141. package/dist/runtime/composables/useMiniMapLayout.d.ts +34 -0
  142. package/dist/runtime/composables/useMiniMapLayout.js +119 -0
  143. package/dist/runtime/composables/useNodeConfigResolve.d.ts +43 -0
  144. package/dist/runtime/composables/useNodeConfigResolve.js +123 -0
  145. package/dist/runtime/composables/useNodeDrag.d.ts +22 -0
  146. package/dist/runtime/composables/useNodeDrag.js +10 -0
  147. package/dist/runtime/composables/usePaletteLayout.d.ts +41 -0
  148. package/dist/runtime/composables/usePaletteLayout.js +113 -0
  149. package/dist/runtime/data/expressionEditor.d.ts +22 -0
  150. package/dist/runtime/data/expressionEditor.js +40 -0
  151. package/dist/runtime/data/integrationNodeCatalog.js +8 -8
  152. package/dist/runtime/data/nodeInputData.d.ts +37 -0
  153. package/dist/runtime/data/nodeInputData.js +62 -0
  154. package/dist/runtime/data/nodeRunData.d.ts +56 -0
  155. package/dist/runtime/data/nodeRunData.js +91 -0
  156. package/dist/runtime/data/payloadForm.d.ts +44 -0
  157. package/dist/runtime/data/payloadForm.js +126 -0
  158. package/dist/runtime/data/workflowIconCatalog.d.ts +34 -0
  159. package/dist/runtime/data/workflowIconCatalog.js +116 -0
  160. package/dist/runtime/pages/integrations/audit.vue +25 -35
  161. package/dist/runtime/pages/integrations/credentials.vue +117 -122
  162. package/dist/runtime/pages/integrations/index.vue +133 -36
  163. package/dist/runtime/pages/integrations/runs.vue +125 -75
  164. package/dist/runtime/pages/integrations/schedules.vue +5 -16
  165. package/dist/runtime/pages/integrations/secrets.vue +1 -3
  166. package/dist/runtime/pages/integrations/workflows/[id].vue +599 -194
  167. package/dist/runtime/pages/integrations/workflows/index.vue +10 -8
  168. package/dist/runtime/types/integrations.d.ts +190 -4
  169. package/dist/runtime/utils/credentialState.d.ts +28 -0
  170. package/dist/runtime/utils/credentialState.js +29 -0
  171. package/dist/runtime/utils/localize.d.ts +3 -1
  172. package/dist/runtime/utils/localize.js +1 -2
  173. package/dist/runtime/utils/statusStyle.d.ts +6 -0
  174. package/dist/runtime/utils/statusStyle.js +15 -0
  175. package/package.json +11 -1
  176. package/dist/runtime/components/Integrations/RunDetailDialog.vue +0 -169
  177. package/dist/runtime/pages/integrations/workflows/new.d.vue.ts +0 -2
  178. package/dist/runtime/pages/integrations/workflows/new.vue +0 -153
  179. package/dist/runtime/pages/integrations/workflows/new.vue.d.ts +0 -2
@@ -1,5 +1,5 @@
1
1
  <script setup>
2
- import { computed } from "vue";
2
+ import { computed, inject, ref, watch } from "vue";
3
3
  import { Handle, Position, useVueFlow } from "@vue-flow/core";
4
4
  import { NodeToolbar } from "@vue-flow/node-toolbar";
5
5
  import * as Lucide from "lucide-vue-next";
@@ -13,6 +13,7 @@ defineOptions({ inheritAttrs: false });
13
13
  defineEmits(["updateNodeInternals"]);
14
14
  const manifest = computed(() => findManifest(props.data.nodeSlug, props.data.nodeVersion));
15
15
  const category = computed(() => NODE_CATEGORIES.find((c) => c.key === manifest.value?.category));
16
+ const hasLogo = computed(() => (manifest.value?.images ?? []).some((i) => i.category === "logo"));
16
17
  function iconFor(name) {
17
18
  if (!name) return Lucide.Box;
18
19
  const cleaned = (name.includes(":") ? name.split(":").pop() : name).split("-").map((s) => s.charAt(0).toUpperCase() + s.slice(1)).join("");
@@ -20,18 +21,32 @@ function iconFor(name) {
20
21
  }
21
22
  function labelText(value) {
22
23
  if (!value) return "";
23
- return typeof value === "string" ? value : Object.values(value)[0] ?? "";
24
+ return typeof value === "string" ? value : value.en ?? Object.values(value)[0] ?? "";
24
25
  }
25
26
  const title = computed(
26
27
  () => labelText(props.data.name) || labelText(manifest.value?.name) || props.data.nodeSlug
27
28
  );
28
- const description = computed(() => labelText(manifest.value?.description));
29
29
  const inputRequired = computed(() => manifest.value?.input?.required !== false);
30
- const outputs = computed(() => {
31
- const m = manifest.value;
32
- if (!m) return [{ name: "default", kind: "default", label: "out" }];
30
+ const subtitleKeys = computed(() => {
31
+ const fields = manifest.value?.config ?? [];
32
+ const driving = /* @__PURE__ */ new Set();
33
+ for (const f of fields) for (const dep of f.dependsOn ?? []) driving.add(dep);
34
+ const drivingSelects = fields.filter((f) => f.type === "select" && driving.has(f.key)).map((f) => f.key);
35
+ if (drivingSelects.length) return drivingSelects;
36
+ return fields.filter((f) => f.type === "select" || f.type === "multiselect").slice(0, 2).map((f) => f.key);
37
+ });
38
+ function scalarText(v) {
39
+ if (Array.isArray(v)) {
40
+ return v.filter((x) => ["string", "number", "boolean"].includes(typeof x)).map((x) => String(x).trim()).filter(Boolean).join(", ");
41
+ }
42
+ return ["string", "number", "boolean"].includes(typeof v) ? String(v).trim() : "";
43
+ }
44
+ const subtitle = computed(
45
+ () => subtitleKeys.value.map((k) => scalarText(props.data.config?.[k])).filter((s) => s !== "").join(" \xB7 ")
46
+ );
47
+ function portsFromOutputs(list) {
33
48
  const ports = [];
34
- for (const o of m.outputs ?? []) {
49
+ for (const o of list) {
35
50
  if (o.name) {
36
51
  ports.push({ name: o.name, kind: o.kind, label: labelText(o.label) || o.name });
37
52
  } else if (o.sourceFromConfig) {
@@ -50,20 +65,32 @@ const outputs = computed(() => {
50
65
  }
51
66
  }
52
67
  }
68
+ return ports;
69
+ }
70
+ const resolvePending = computed(() => (manifest.value?.outputs ?? []).some((o) => o.resolveOutputs === true) && !Array.isArray(props.data.__resolvedOutputs));
71
+ const outputs = computed(() => {
72
+ const resolved = props.data.__resolvedOutputs;
73
+ if (Array.isArray(resolved) && resolved.length) {
74
+ const ports2 = portsFromOutputs(resolved);
75
+ if (!ports2.length) ports2.push({ name: "default", kind: "default", label: "out" });
76
+ return ports2;
77
+ }
78
+ const m = manifest.value;
79
+ if (!m) return [{ name: "default", kind: "default", label: "out" }];
80
+ const ports = portsFromOutputs(m.outputs ?? []);
53
81
  if (!ports.length) ports.push({ name: "default", kind: "default", label: "out" });
54
82
  return ports;
55
83
  });
56
- function handleColorClass(kind) {
57
- if (kind === "error") return "!bg-rose-400";
58
- if (kind === "branch") return "!bg-violet-400";
59
- return "!bg-slate-400";
84
+ function portTone(p) {
85
+ if (p.name === "true") return { handle: "!bg-emerald-500", label: "text-emerald-600" };
86
+ if (p.name === "false") return { handle: "!bg-amber-400", label: "text-amber-600" };
87
+ if (p.kind === "error") return { handle: "!bg-rose-500", label: "text-rose-600" };
88
+ if (p.kind === "branch") return { handle: "!bg-violet-500", label: "text-violet-600" };
89
+ return { handle: "!bg-slate-500", label: "text-slate-500" };
60
90
  }
61
- function legendDotClass(kind) {
62
- if (kind === "error") return "bg-rose-400";
63
- if (kind === "branch") return "bg-violet-400";
64
- return "bg-slate-400";
65
- }
66
- const SIDES = ["top", "right", "bottom", "left"];
91
+ const showPortLabels = computed(() => resolvePending.value || outputs.value.length > 1 || outputs.value.some((p) => p.kind !== "default"));
92
+ const IN_SIDES = ["top"];
93
+ const OUT_SIDES = ["bottom"];
67
94
  function sideToPosition(s) {
68
95
  return s === "top" ? Position.Top : s === "right" ? Position.Right : s === "bottom" ? Position.Bottom : Position.Left;
69
96
  }
@@ -73,33 +100,31 @@ function distributedStyle(side, i, total) {
73
100
  return { top: pct };
74
101
  }
75
102
  const flow = useVueFlow();
103
+ const hovered = ref(false);
104
+ let hoverTimer = null;
105
+ function onHoverEnter() {
106
+ if (hoverTimer) clearTimeout(hoverTimer);
107
+ hovered.value = true;
108
+ }
109
+ function onHoverLeave() {
110
+ if (hoverTimer) clearTimeout(hoverTimer);
111
+ hoverTimer = setTimeout(() => {
112
+ hovered.value = false;
113
+ }, 200);
114
+ }
115
+ watch(subtitle, () => flow.updateNodeInternals([props.id]));
116
+ const nodeActions = inject("workflow-node-actions", null);
76
117
  function duplicate() {
77
- const offset = 80;
78
- const newId = `n-${Date.now()}`;
79
- flow.addNodes([{
80
- id: newId,
81
- type: "workflow",
82
- position: {
83
- x: (props.data.position?.x ?? 0) + offset,
84
- y: (props.data.position?.y ?? 0) + offset
85
- },
86
- data: {
87
- ...props.data,
88
- id: newId,
89
- position: {
90
- x: (props.data.position?.x ?? 0) + offset,
91
- y: (props.data.position?.y ?? 0) + offset
92
- }
93
- }
94
- }]);
118
+ nodeActions?.duplicate(props.id);
95
119
  }
96
120
  function remove() {
97
- flow.removeNodes([props.id]);
121
+ if (nodeActions) nodeActions.remove(props.id);
122
+ else flow.removeNodes([props.id]);
98
123
  }
99
124
  </script>
100
125
 
101
126
  <template>
102
- <NodeToolbar :position="Position.Top" :offset="36" class="flex items-center gap-1 rounded-md border border-black/[0.08] bg-white px-1 py-1 shadow-md">
127
+ <NodeToolbar :is-visible="hovered || selected" :position="Position.Top" :offset="8" class="flex items-center gap-1 rounded-md border border-black/[0.08] bg-white px-1 py-1 shadow-md" @mouseenter="onHoverEnter" @mouseleave="onHoverLeave">
103
128
  <button
104
129
  type="button"
105
130
  class="flex h-6 items-center gap-1 rounded px-1.5 text-sm text-foreground/80 hover:bg-muted/50"
@@ -119,22 +144,23 @@ function remove() {
119
144
  </button>
120
145
  </NodeToolbar>
121
146
 
122
- <!-- Input handles: one per side, centered on each edge. -->
147
+ <!-- Input: ONE logical input, attachable from the left or the top — both
148
+ dots feed the same `__in` port. Clearly visible, ring + shadow. -->
123
149
  <template v-if="inputRequired">
124
150
  <Handle
125
- v-for="side in SIDES"
151
+ v-for="side in IN_SIDES"
126
152
  :id="`__in__${side}`"
127
153
  :key="`in-${side}`"
128
154
  type="target"
129
155
  :position="sideToPosition(side)"
130
- class="!size-2 !rounded-full !border-2 !border-white !bg-slate-400 opacity-70 transition-all hover:!size-2.5 hover:!bg-slate-600 hover:opacity-100"
156
+ title="Input"
157
+ class="!size-3 !rounded-full !border-2 !border-white !bg-slate-500 !shadow-sm transition-all hover:!size-3.5 hover:!bg-slate-700"
131
158
  />
132
159
  </template>
133
160
 
134
- <!-- Output handles: each port exposed on all 4 sides, distributed evenly
135
- per side so multi-output nodes (success/error, switch cases) don't
136
- overlap. -->
137
- <template v-for="side in SIDES" :key="`side-${side}`">
161
+ <!-- Output handles: right + bottom, distributed per side. Color encodes the
162
+ port semantics (true/false/error/branch/default), matching the edges. -->
163
+ <template v-for="side in OUT_SIDES" :key="`side-${side}`">
138
164
  <Handle
139
165
  v-for="(p, i) in outputs"
140
166
  :id="`${p.name}__${side}`"
@@ -143,58 +169,62 @@ function remove() {
143
169
  :position="sideToPosition(side)"
144
170
  :title="p.label"
145
171
  :style="distributedStyle(side, i, outputs.length)"
146
- class="!size-2 !rounded-full !border-2 !border-white opacity-70 transition-all hover:!size-2.5 hover:opacity-100"
147
- :class="handleColorClass(p.kind)"
172
+ class="!size-3 !rounded-full !border-2 !border-white !shadow-sm transition-all hover:!size-3.5"
173
+ :class="portTone(p).handle"
148
174
  />
149
175
  </template>
150
176
 
177
+ <!-- The card itself — deliberately minimal: icon, name, what it's set to.
178
+ Everything else lives in the config lightbox. -->
151
179
  <div
152
- class="w-[240px] rounded-lg border bg-white transition-all duration-150"
153
- :class="selected ? 'border-emerald-500/50 shadow-[0_0_0_2px_rgba(16,185,129,0.18)]' : 'border-black/[0.08] shadow-sm hover:shadow-md hover:border-black/[0.16]'"
180
+ class="relative w-[220px] rounded-lg border bg-white transition-all duration-150"
181
+ @mouseenter="onHoverEnter"
182
+ @mouseleave="onHoverLeave"
183
+ :class="[
184
+ selected ? 'border-emerald-500/50 shadow-[0_0_0_2px_rgba(16,185,129,0.18)]' : 'border-black/[0.08] shadow-sm hover:shadow-md hover:border-black/[0.16]',
185
+ showPortLabels ? 'pb-3.5' : ''
186
+ ]"
154
187
  >
155
- <div class="flex items-center gap-2 px-3 pt-2.5 pb-1.5">
156
- <span class="flex size-7 shrink-0 items-center justify-center rounded-md" :class="category?.color ?? 'bg-muted text-foreground'">
157
- <component :is="iconFor(manifest?.icon)" :size="14" :stroke-width="2.25" />
188
+ <!-- Port labels sit ABOVE their bottom dots, inside the card's label
189
+ strip, whenever ports are distinguishable (true/false, error, cases). -->
190
+ <template v-if="showPortLabels">
191
+ <!-- Dynamic ports resolving (server round-trip, slower for external
192
+ nodes) — a spinner instead of the incomplete static set. -->
193
+ <span
194
+ v-if="resolvePending"
195
+ class="pointer-events-none absolute bottom-1 left-1/2 flex -translate-x-1/2 select-none items-center gap-1 whitespace-nowrap text-[9px] font-semibold uppercase tracking-wide text-muted-foreground"
196
+ >
197
+ <Lucide.LoaderCircle :size="9" class="animate-spin" />
198
+ Ports
199
+ </span>
200
+ <template v-else>
201
+ <span
202
+ v-for="(p, i) in outputs"
203
+ :key="`plabel-${p.name}`"
204
+ class="pointer-events-none absolute bottom-1 select-none whitespace-nowrap text-[9px] font-semibold uppercase tracking-wide"
205
+ :class="portTone(p).label"
206
+ :style="{ left: `${(i + 1) / (outputs.length + 1) * 100}%`, transform: 'translateX(-50%)' }"
207
+ >
208
+ {{ p.label }}
209
+ </span>
210
+ </template>
211
+ </template>
212
+ <div class="flex items-center gap-2.5 px-3 py-2.5">
213
+ <span
214
+ class="flex size-8 shrink-0 items-center justify-center rounded-md"
215
+ :class="hasLogo ? 'bg-white ring-1 ring-black/[0.06]' : category?.color ?? 'bg-muted text-foreground'"
216
+ >
217
+ <IntegrationsNodeLogo v-if="hasLogo" :manifest="manifest" :size="18" />
218
+ <component :is="iconFor(manifest?.icon)" v-else :size="15" :stroke-width="2.25" />
158
219
  </span>
159
220
  <div class="min-w-0 flex-1">
160
221
  <div class="text-sm font-semibold leading-tight text-foreground truncate">
161
222
  {{ title }}
162
223
  </div>
163
- <div class="text-sm text-muted-foreground truncate font-mono">
164
- {{ data.nodeSlug }}<span class="opacity-60">@{{ data.nodeVersion }}</span>
224
+ <div v-if="subtitle" class="mt-0.5 text-sm text-muted-foreground truncate" :title="subtitle">
225
+ {{ subtitle }}
165
226
  </div>
166
227
  </div>
167
228
  </div>
168
-
169
- <p v-if="description" class="px-3 pb-2 text-sm text-muted-foreground line-clamp-2">
170
- {{ description }}
171
- </p>
172
-
173
- <div
174
- v-if="outputs.length"
175
- class="border-t border-black/[0.04] bg-muted/20 px-3 py-1.5 rounded-b-lg"
176
- >
177
- <div
178
- v-for="p in outputs"
179
- :key="p.name"
180
- class="flex items-center gap-1.5 py-0.5 text-sm"
181
- >
182
- <span class="size-1.5 rounded-full shrink-0" :class="legendDotClass(p.kind)" />
183
- <span
184
- class="font-mono truncate"
185
- :class="p.kind === 'error' ? 'text-rose-600' : p.kind === 'branch' ? 'text-violet-600' : 'text-foreground/70'"
186
- >
187
- {{ p.label }}
188
- </span>
189
- </div>
190
- </div>
191
-
192
- <div
193
- v-if="data.retry"
194
- class="flex items-center gap-1.5 border-t border-black/[0.04] px-3 py-1 text-sm text-muted-foreground"
195
- >
196
- <Lucide.RotateCcw :size="10" />
197
- <span>Retry × {{ data.retry.maxAttempts }} · {{ data.retry.strategy ?? "linear" }}</span>
198
- </div>
199
229
  </div>
200
230
  </template>
@@ -1,6 +1,10 @@
1
- import type { WorkflowNode } from '../../types/integrations.js';
1
+ import type { NodeManifestOutput, WorkflowNode } from '../../types/integrations.js';
2
2
  interface NodeData extends WorkflowNode {
3
3
  __selected?: boolean;
4
+ /** Server-resolved + merged output ports (PO-143 Phase 3), injected by the
5
+ * editor without persisting to the blob. When present and non-empty, these
6
+ * drive the rendered handles instead of the static manifest computation. */
7
+ __resolvedOutputs?: NodeManifestOutput[];
4
8
  }
5
9
  type __VLS_Props = {
6
10
  id: string;
@@ -0,0 +1,12 @@
1
+ import '@vue-flow/core/dist/style.css';
2
+ import '@vue-flow/core/dist/theme-default.css';
3
+ import type { Workflow } from '../../types/integrations.js';
4
+ type __VLS_Props = {
5
+ workflow: Workflow;
6
+ /** Preselect a run (deep-link from the Runs table). */
7
+ initialRunId?: string | null;
8
+ /** Replay ONLY the initial run: no run list, no browsing (run detail view). */
9
+ single?: boolean;
10
+ };
11
+ declare const _default: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
12
+ export default _default;