@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
@@ -0,0 +1,222 @@
1
+ <script setup>
2
+ import { computed, nextTick, ref } from "vue";
3
+ import { Handle, Position, useVueFlow } from "@vue-flow/core";
4
+ import { NodeToolbar } from "@vue-flow/node-toolbar";
5
+ import { ChevronsDownUp, ChevronsUpDown, Trash2, Ungroup } from "lucide-vue-next";
6
+ const props = defineProps({
7
+ id: { type: String, required: true },
8
+ data: { type: Object, required: true },
9
+ selected: { type: Boolean, required: false }
10
+ });
11
+ defineEmits(["updateNodeInternals"]);
12
+ const GROUP_COLORS = [
13
+ { bg: "rgba(254,243,199,0.45)", border: "#fcd34d", chip: "#f59e0b" },
14
+ { bg: "rgba(255,237,213,0.45)", border: "#fdba74", chip: "#f97316" },
15
+ { bg: "rgba(255,228,230,0.45)", border: "#fda4af", chip: "#f43f5e" },
16
+ { bg: "rgba(220,252,231,0.45)", border: "#86efac", chip: "#10b981" },
17
+ { bg: "rgba(219,234,254,0.45)", border: "#93c5fd", chip: "#3b82f6" },
18
+ { bg: "rgba(237,233,254,0.45)", border: "#c4b5fd", chip: "#8b5cf6" },
19
+ { bg: "rgba(245,245,244,0.6)", border: "#d6d3d1", chip: "#78716c" }
20
+ ];
21
+ const color = computed(() => GROUP_COLORS[props.data.group.color ?? 4] ?? GROUP_COLORS[4]);
22
+ function loc(v) {
23
+ if (!v) return "";
24
+ return typeof v === "string" ? v : v.en ?? Object.values(v)[0] ?? "";
25
+ }
26
+ const label = computed(() => loc(props.data.group.label) || "Group");
27
+ const collapsed = computed(() => props.data.group.collapsed === true);
28
+ const editable = computed(() => !!props.data.actions);
29
+ const editing = ref(false);
30
+ const draft = ref("");
31
+ const inputEl = ref(null);
32
+ function startRename() {
33
+ if (!editable.value) return;
34
+ draft.value = label.value;
35
+ editing.value = true;
36
+ void nextTick(() => inputEl.value?.focus());
37
+ }
38
+ function commitRename() {
39
+ if (!editing.value) return;
40
+ editing.value = false;
41
+ const next = draft.value.trim();
42
+ if (next && next !== label.value) props.data.actions?.rename(next);
43
+ }
44
+ const hovered = ref(false);
45
+ let hoverTimer = null;
46
+ function onHoverEnter() {
47
+ if (hoverTimer) clearTimeout(hoverTimer);
48
+ hovered.value = true;
49
+ }
50
+ function onHoverLeave() {
51
+ if (hoverTimer) clearTimeout(hoverTimer);
52
+ hoverTimer = setTimeout(() => {
53
+ hovered.value = false;
54
+ }, 250);
55
+ }
56
+ const toolbarVisible = computed(() => editable.value && !editing.value && (hovered.value || !!props.selected));
57
+ const memberCountText = computed(() => `${props.data.memberCount} node${props.data.memberCount === 1 ? "" : "s"}`);
58
+ const flow = useVueFlow();
59
+ const resizing = ref(false);
60
+ const liveW = ref(0);
61
+ const liveH = ref(0);
62
+ let resizeStart = { x: 0, y: 0, w: 0, h: 0 };
63
+ const frameW = computed(() => resizing.value ? liveW.value : props.data.rect.width);
64
+ const frameH = computed(() => resizing.value ? liveH.value : props.data.rect.height);
65
+ function onResizeStart(e) {
66
+ e.stopPropagation();
67
+ e.preventDefault();
68
+ resizing.value = true;
69
+ liveW.value = props.data.rect.width;
70
+ liveH.value = props.data.rect.height;
71
+ resizeStart = { x: e.clientX, y: e.clientY, w: liveW.value, h: liveH.value };
72
+ e.target.setPointerCapture(e.pointerId);
73
+ }
74
+ function onResizeMove(e) {
75
+ if (!resizing.value) return;
76
+ const zoom = flow.viewport.value.zoom || 1;
77
+ liveW.value = Math.max(150, Math.round(resizeStart.w + (e.clientX - resizeStart.x) / zoom));
78
+ liveH.value = Math.max(90, Math.round(resizeStart.h + (e.clientY - resizeStart.y) / zoom));
79
+ }
80
+ function onResizeEnd() {
81
+ if (!resizing.value) return;
82
+ resizing.value = false;
83
+ props.data.actions?.resize({ width: liveW.value, height: liveH.value });
84
+ }
85
+ </script>
86
+
87
+ <template>
88
+ <div class="relative">
89
+ <NodeToolbar :is-visible="toolbarVisible" :position="Position.Top" :offset="8">
90
+ <div
91
+ class="flex items-center gap-1 rounded-lg border border-black/[0.06] bg-white px-1.5 py-1 shadow-md"
92
+ @mouseenter="onHoverEnter"
93
+ @mouseleave="onHoverLeave"
94
+ >
95
+ <button
96
+ v-for="(c, i) in GROUP_COLORS"
97
+ :key="i"
98
+ type="button"
99
+ class="size-4.5 rounded-full border transition hover:scale-110"
100
+ :class="(data.group.color ?? 4) === i ? 'ring-2 ring-black/25 ring-offset-1' : ''"
101
+ :style="{ backgroundColor: c.chip, borderColor: c.border, width: '16px', height: '16px' }"
102
+ @click="data.actions?.setColor(i)"
103
+ />
104
+ <div class="mx-0.5 h-4 w-px bg-black/10" />
105
+ <button
106
+ type="button"
107
+ class="flex size-6 items-center justify-center rounded-md text-muted-foreground transition hover:bg-muted/50 hover:text-foreground"
108
+ :title="collapsed ? 'Expand group' : 'Collapse group'"
109
+ @click="data.actions?.toggleCollapse()"
110
+ >
111
+ <component :is="collapsed ? ChevronsUpDown : ChevronsDownUp" :size="13" />
112
+ </button>
113
+ <button
114
+ type="button"
115
+ class="flex size-6 items-center justify-center rounded-md text-muted-foreground transition hover:bg-muted/50 hover:text-foreground"
116
+ title="Ungroup (keep the nodes)"
117
+ @click="data.actions?.ungroup()"
118
+ >
119
+ <Ungroup :size="13" />
120
+ </button>
121
+ <button
122
+ type="button"
123
+ class="flex size-6 items-center justify-center rounded-md text-muted-foreground transition hover:bg-rose-50 hover:text-rose-600"
124
+ title="Remove group frame"
125
+ @click="data.actions?.ungroup()"
126
+ >
127
+ <Trash2 :size="13" />
128
+ </button>
129
+ </div>
130
+ </NodeToolbar>
131
+
132
+ <!-- Collapsed: compact stand-in card with generic edge handles. -->
133
+ <template v-if="collapsed">
134
+ <Handle
135
+ id="__in__top"
136
+ type="target"
137
+ :position="Position.Top"
138
+ class="!size-3 !rounded-full !border-2 !border-white !bg-slate-500 !shadow-sm"
139
+ />
140
+ <div
141
+ class="w-[220px] rounded-lg border-2 bg-white transition-all duration-150"
142
+ :style="{ borderColor: color.border }"
143
+ :class="selected ? 'shadow-[0_0_0_2px_rgba(59,130,246,0.2)]' : 'shadow-sm hover:shadow-md'"
144
+ @mouseenter="onHoverEnter"
145
+ @mouseleave="onHoverLeave"
146
+ @dblclick.stop="data.actions?.toggleCollapse()"
147
+ >
148
+ <div class="flex items-center gap-2.5 px-3 py-2.5">
149
+ <span class="flex size-8 shrink-0 items-center justify-center rounded-md text-white" :style="{ backgroundColor: color.chip }">
150
+ <ChevronsUpDown :size="15" />
151
+ </span>
152
+ <div class="min-w-0 flex-1">
153
+ <div class="truncate text-sm font-semibold leading-tight text-foreground">{{ label }}</div>
154
+ <div class="mt-0.5 text-sm text-muted-foreground">{{ memberCountText }}</div>
155
+ </div>
156
+ </div>
157
+ </div>
158
+ <Handle
159
+ id="default__bottom"
160
+ type="source"
161
+ :position="Position.Bottom"
162
+ class="!size-3 !rounded-full !border-2 !border-white !bg-slate-500 !shadow-sm"
163
+ />
164
+ </template>
165
+
166
+ <!-- Expanded: the frame behind the members. -->
167
+ <div
168
+ v-else
169
+ class="pointer-events-none relative rounded-xl border-2 border-dashed transition-colors"
170
+ :class="selected ? 'shadow-[0_0_0_2px_rgba(59,130,246,0.15)]' : ''"
171
+ :style="{
172
+ width: `${frameW}px`,
173
+ height: `${frameH}px`,
174
+ backgroundColor: color.bg,
175
+ borderColor: color.border
176
+ }"
177
+ >
178
+ <div
179
+ class="pointer-events-auto flex cursor-grab items-center gap-1.5 px-3 pt-1.5 active:cursor-grabbing"
180
+ @mouseenter="onHoverEnter"
181
+ @mouseleave="onHoverLeave"
182
+ >
183
+ <input
184
+ v-if="editing"
185
+ ref="inputEl"
186
+ v-model="draft"
187
+ class="nodrag w-40 rounded border border-black/[0.1] bg-white px-1 py-0.5 text-sm font-semibold focus:outline-none focus:ring-2 focus:ring-primary/40"
188
+ @blur="commitRename"
189
+ @keydown.enter.prevent="commitRename"
190
+ @keydown.stop
191
+ @mousedown.stop
192
+ >
193
+ <span
194
+ v-else
195
+ class="select-none text-sm font-semibold"
196
+ :style="{ color: color.chip }"
197
+ @dblclick.stop="startRename"
198
+ >
199
+ {{ label }}
200
+ </span>
201
+ <span class="select-none text-xs text-muted-foreground">· {{ memberCountText }}</span>
202
+ </div>
203
+
204
+ <!-- Bottom-right resize handle (editable frames only). -->
205
+ <div
206
+ v-if="editable"
207
+ class="nodrag pointer-events-auto absolute bottom-0 right-0 flex size-5 cursor-se-resize items-end justify-end p-1"
208
+ :style="{ color: color.chip }"
209
+ title="Resize group"
210
+ @pointerdown="onResizeStart"
211
+ @pointermove="onResizeMove"
212
+ @pointerup="onResizeEnd"
213
+ @pointercancel="onResizeEnd"
214
+ >
215
+ <svg viewBox="0 0 8 8" class="size-2.5" fill="none" stroke="currentColor" stroke-width="1.2" stroke-linecap="round">
216
+ <path d="M7 1 1 7" />
217
+ <path d="M7 4.5 4.5 7" />
218
+ </svg>
219
+ </div>
220
+ </div>
221
+ </div>
222
+ </template>
@@ -0,0 +1,28 @@
1
+ import type { WorkflowGroup } from '../../types/integrations.js';
2
+ interface GroupNodeData {
3
+ group: WorkflowGroup;
4
+ /** Derived frame size (expanded mode). */
5
+ rect: {
6
+ width: number;
7
+ height: number;
8
+ };
9
+ memberCount: number;
10
+ /** Absent in read-only previews — no toolbar, no editing. */
11
+ actions?: {
12
+ rename: (label: string) => void;
13
+ setColor: (i: number) => void;
14
+ toggleCollapse: () => void;
15
+ ungroup: () => void;
16
+ resize: (size: {
17
+ width: number;
18
+ height: number;
19
+ }) => void;
20
+ };
21
+ }
22
+ type __VLS_Props = {
23
+ id: string;
24
+ data: GroupNodeData;
25
+ selected?: boolean;
26
+ };
27
+ declare const _default: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, any, string, import("vue").PublicProps, any, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
28
+ export default _default;
@@ -0,0 +1,14 @@
1
+ import type { ConfigField } from '../../types/integrations.js';
2
+ type __VLS_Props = {
3
+ slug: string;
4
+ version: string;
5
+ field: ConfigField;
6
+ config: Record<string, unknown>;
7
+ modelValue: unknown;
8
+ };
9
+ declare const _default: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
10
+ "update:modelValue": (value: unknown) => any;
11
+ }, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
12
+ "onUpdate:modelValue"?: ((value: unknown) => any) | undefined;
13
+ }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
14
+ export default _default;
@@ -0,0 +1,184 @@
1
+ <script setup>
2
+ import { computed, ref } from "vue";
3
+ import { ChevronDown } from "lucide-vue-next";
4
+ import { Input } from "@revenexx/studio";
5
+ const props = defineProps({
6
+ slug: { type: String, required: true },
7
+ version: { type: String, required: true },
8
+ field: { type: Object, required: true },
9
+ config: { type: Object, required: true },
10
+ modelValue: { type: null, required: true }
11
+ });
12
+ const emit = defineEmits(["update:modelValue"]);
13
+ function labelText(v) {
14
+ if (!v) return "";
15
+ return typeof v === "string" ? v : v.en ?? Object.values(v)[0] ?? "";
16
+ }
17
+ const search = ref("");
18
+ const focused = ref(false);
19
+ const q = useNodeConfigResolve({
20
+ slug: () => props.slug,
21
+ version: () => props.version,
22
+ target: () => props.field.key,
23
+ config: () => props.config,
24
+ dependsOn: () => props.field.dependsOn,
25
+ search: () => focused.value ? search.value : ""
26
+ });
27
+ const options = computed(() => q.data.value?.options ?? []);
28
+ const isMulti = computed(() => props.field.type === "multiselect");
29
+ const disabledControlClass = "flex h-8 items-center rounded-md border border-black/[0.08] bg-white px-2 text-sm text-muted-foreground opacity-50";
30
+ const currentValue = computed(() => String(props.modelValue ?? ""));
31
+ const currentKnown = computed(
32
+ () => options.value.some((o) => String(o.value) === currentValue.value)
33
+ );
34
+ const currentLabel = computed(() => {
35
+ const hit = options.value.find((o) => String(o.value) === currentValue.value);
36
+ return hit ? labelText(hit.label) || String(hit.value) : currentValue.value;
37
+ });
38
+ const listOpen = computed(() => focused.value && !q.gated.value);
39
+ const visibleOptions = computed(() => {
40
+ const term = search.value.trim().toLowerCase();
41
+ if (!focused.value || !term) return options.value;
42
+ const hits = options.value.filter(
43
+ (o) => (labelText(o.label) || "").toLowerCase().includes(term) || String(o.value).toLowerCase().includes(term)
44
+ );
45
+ return hits.length ? hits : options.value;
46
+ });
47
+ function onComboFocus() {
48
+ search.value = "";
49
+ focused.value = true;
50
+ }
51
+ function onComboBlur() {
52
+ focused.value = false;
53
+ }
54
+ function pick(value) {
55
+ emit("update:modelValue", value);
56
+ search.value = "";
57
+ focused.value = false;
58
+ }
59
+ const selectedArray = computed(
60
+ () => Array.isArray(props.modelValue) ? props.modelValue.map(String) : []
61
+ );
62
+ const knownValues = computed(() => new Set(options.value.map((o) => String(o.value))));
63
+ const missingValues = computed(() => selectedArray.value.filter((v) => !knownValues.value.has(v)));
64
+ const multiFilter = ref("");
65
+ const visibleMultiOptions = computed(() => {
66
+ const f = multiFilter.value.trim().toLowerCase();
67
+ if (!f) return options.value;
68
+ return options.value.filter(
69
+ (o) => (labelText(o.label) || String(o.value)).toLowerCase().includes(f) || String(o.value).toLowerCase().includes(f)
70
+ );
71
+ });
72
+ function toggleMulti(optValue) {
73
+ const arr = selectedArray.value;
74
+ const has = arr.includes(optValue);
75
+ emit("update:modelValue", has ? arr.filter((v) => v !== optValue) : [...arr, optValue]);
76
+ }
77
+ </script>
78
+
79
+ <template>
80
+ <div>
81
+ <!-- gated: required dependencies still unset -->
82
+ <template v-if="q.gated.value">
83
+ <div :class="disabledControlClass">—</div>
84
+ <p class="mt-1 text-sm text-amber-600">Set {{ q.unsatisfied.value.join(", ") }} first</p>
85
+ </template>
86
+
87
+ <!-- first load: no data yet -->
88
+ <template v-else-if="q.isFetching.value && options.length === 0">
89
+ <div :class="disabledControlClass">resolving options…</div>
90
+ </template>
91
+
92
+ <!-- error: build/runtime/etc -->
93
+ <template v-else-if="q.error.value">
94
+ <div :class="disabledControlClass">—</div>
95
+ <div class="mt-1 flex items-center gap-2 text-sm text-amber-600">
96
+ <span>{{ q.error.value.kind === "building" ? "Node bundle still building." : q.error.value.message }}</span>
97
+ <button
98
+ type="button"
99
+ class="rounded border border-black/[0.08] px-1.5 py-0.5 text-mono text-muted-foreground transition hover:text-foreground"
100
+ @click="q.refetch()"
101
+ >
102
+ RETRY
103
+ </button>
104
+ </div>
105
+ </template>
106
+
107
+ <!-- multiselect — pill toggles with a client-side filter for long lists -->
108
+ <template v-else-if="isMulti">
109
+ <Input
110
+ v-if="options.length > 10"
111
+ v-model="multiFilter"
112
+ placeholder="Filter options"
113
+ class="mb-1.5 h-7 bg-white text-sm"
114
+ />
115
+ <div class="flex flex-wrap gap-1">
116
+ <span v-if="visibleMultiOptions.length === 0" class="text-sm text-muted-foreground">
117
+ {{ options.length === 0 ? "no options available" : "no options match the filter" }}
118
+ </span>
119
+ <button
120
+ v-for="opt in visibleMultiOptions"
121
+ :key="String(opt.value)"
122
+ type="button"
123
+ :disabled="q.isFetching.value"
124
+ class="rounded-md border border-black/[0.08] px-1.5 py-0.5 text-sm transition disabled:cursor-wait disabled:opacity-60"
125
+ :class="selectedArray.includes(String(opt.value)) ? 'bg-emerald-500/15 text-emerald-700 border-emerald-500/30' : 'bg-white text-muted-foreground hover:text-foreground'"
126
+ @click="toggleMulti(String(opt.value))"
127
+ >
128
+ {{ labelText(opt.label) || String(opt.value) }}
129
+ </button>
130
+ <!-- stored values no longer offered — shown read-only so they stay visible -->
131
+ <span
132
+ v-for="m in missingValues"
133
+ :key="m"
134
+ class="rounded-md border border-black/[0.08] bg-white px-1.5 py-0.5 text-sm text-muted-foreground opacity-60"
135
+ >
136
+ {{ m }} (not in list)
137
+ </span>
138
+ </div>
139
+ <p v-if="q.isFetching.value && q.hasData.value" class="mt-1 text-sm text-muted-foreground">reloading…</p>
140
+ </template>
141
+
142
+ <!-- single select: searchable combobox; typing re-resolves with the term -->
143
+ <template v-else>
144
+ <div class="relative">
145
+ <Input
146
+ :model-value="focused ? search : currentLabel"
147
+ :placeholder="labelText(field.placeholder) || 'Pick one'"
148
+ class="h-8 bg-white pr-7 text-sm"
149
+ @update:model-value="(v) => {
150
+ search = String(v);
151
+ }"
152
+ @focus="onComboFocus"
153
+ @blur="onComboBlur"
154
+ />
155
+ <ChevronDown :size="14" class="pointer-events-none absolute right-2 top-1/2 -translate-y-1/2 text-muted-foreground" />
156
+ <div
157
+ v-if="listOpen"
158
+ class="absolute left-0 right-0 top-full z-30 mt-1 max-h-56 overflow-y-auto rounded-md border border-black/[0.08] bg-white py-1 shadow-md"
159
+ >
160
+ <div v-if="q.isFetching.value" class="px-2.5 py-1.5 text-sm text-muted-foreground">
161
+ {{ search ? "searching\u2026" : "resolving options\u2026" }}
162
+ </div>
163
+ <button
164
+ v-for="opt in visibleOptions"
165
+ :key="String(opt.value)"
166
+ type="button"
167
+ class="flex w-full items-center px-2.5 py-1.5 text-left text-sm hover:bg-muted/50"
168
+ :class="String(opt.value) === currentValue ? 'bg-emerald-500/10 text-emerald-800' : ''"
169
+ @mousedown.prevent="pick(String(opt.value))"
170
+ >
171
+ <span class="min-w-0 truncate">{{ labelText(opt.label) || String(opt.value) }}</span>
172
+ </button>
173
+ <div v-if="!q.isFetching.value && visibleOptions.length === 0" class="px-2.5 py-1.5 text-sm text-muted-foreground">
174
+ {{ search ? 'nothing matches "' + search + '"' : "no options available" }}
175
+ </div>
176
+ </div>
177
+ </div>
178
+ <p v-if="currentValue !== '' && !currentKnown" class="mt-1 text-sm text-amber-600">
179
+ current value not in resolved options
180
+ </p>
181
+ <p v-if="q.isFetching.value && q.hasData.value && !focused" class="mt-1 text-sm text-muted-foreground">reloading…</p>
182
+ </template>
183
+ </div>
184
+ </template>
@@ -0,0 +1,14 @@
1
+ import type { ConfigField } from '../../types/integrations.js';
2
+ type __VLS_Props = {
3
+ slug: string;
4
+ version: string;
5
+ field: ConfigField;
6
+ config: Record<string, unknown>;
7
+ modelValue: unknown;
8
+ };
9
+ declare const _default: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
10
+ "update:modelValue": (value: unknown) => any;
11
+ }, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
12
+ "onUpdate:modelValue"?: ((value: unknown) => any) | undefined;
13
+ }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
14
+ export default _default;
@@ -0,0 +1,16 @@
1
+ import type { ConfigField } from '../../types/integrations.js';
2
+ type __VLS_Props = {
3
+ slug: string;
4
+ version: string;
5
+ field: ConfigField;
6
+ config: Record<string, unknown>;
7
+ staticKeys: string[];
8
+ secretKeys: string[];
9
+ depth?: number;
10
+ };
11
+ declare const _default: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
12
+ set: (key: string, value: unknown) => any;
13
+ }, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
14
+ onSet?: ((key: string, value: unknown) => any) | undefined;
15
+ }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
16
+ export default _default;
@@ -0,0 +1,102 @@
1
+ <script setup>
2
+ import { computed } from "vue";
3
+ import { Button } from "@revenexx/studio";
4
+ import { IntegrationsApiError } from "../../composables/integrationsApi";
5
+ const props = defineProps({
6
+ slug: { type: String, required: true },
7
+ version: { type: String, required: true },
8
+ field: { type: Object, required: true },
9
+ config: { type: Object, required: true },
10
+ staticKeys: { type: Array, required: true },
11
+ secretKeys: { type: Array, required: true },
12
+ depth: { type: Number, required: false }
13
+ });
14
+ const emit = defineEmits(["set"]);
15
+ void IntegrationsApiError;
16
+ const MAX_DEPTH = 5;
17
+ const q = useNodeConfigResolve({
18
+ slug: () => props.slug,
19
+ version: () => props.version,
20
+ target: () => "*",
21
+ config: () => props.config,
22
+ dependsOn: () => props.field.dependsOn
23
+ });
24
+ const resolvedFields = computed(() => q.data.value?.fields ?? []);
25
+ function labelText(v) {
26
+ if (!v) return "";
27
+ return typeof v === "string" ? v : v.en ?? Object.values(v)[0] ?? "";
28
+ }
29
+ </script>
30
+
31
+ <template>
32
+ <div>
33
+ <!-- gated: required dependencies still unset -->
34
+ <p v-if="q.gated.value" class="text-sm text-amber-600">
35
+ Set {{ q.unsatisfied.value.join(", ") }} first
36
+ </p>
37
+
38
+ <!-- first load: no fields yet -->
39
+ <p v-else-if="q.isFetching.value && !resolvedFields.length" class="text-sm text-muted-foreground">
40
+ Resolving fields…
41
+ </p>
42
+
43
+ <!-- error: build/runtime/etc -->
44
+ <div v-else-if="q.error.value" class="flex items-center gap-2 text-sm text-amber-600">
45
+ <span>{{ q.error.value.kind === "building" ? "Node bundle still building." : q.error.value.message }}</span>
46
+ <Button
47
+ type="button"
48
+ variant="outline"
49
+ size="sm"
50
+ class="h-6 px-1.5 text-mono text-muted-foreground"
51
+ @click="q.refetch()"
52
+ >
53
+ RETRY
54
+ </Button>
55
+ </div>
56
+
57
+ <!-- empty: resolved but no fields -->
58
+ <p v-else-if="!resolvedFields.length" class="text-sm text-muted-foreground">
59
+ No fields resolved.
60
+ </p>
61
+
62
+ <!-- fieldset: the resolved child fields, rendered into the flat node config -->
63
+ <fieldset
64
+ v-else
65
+ :disabled="q.isFetching.value"
66
+ :class="{ 'opacity-60': q.isFetching.value }"
67
+ class="space-y-3 rounded-md border border-black/[0.08] bg-muted/10 p-3 m-0"
68
+ >
69
+ <legend class="px-1 text-mono text-muted-foreground">
70
+ {{ labelText(field.label) }}
71
+ </legend>
72
+ <template v-for="f in resolvedFields" :key="f.key">
73
+ <!-- collision guard: a resolved key that shadows a static config field is skipped -->
74
+ <p v-if="staticKeys.includes(f.key)" class="text-sm text-amber-600">
75
+ resolved field '{{ f.key }}' collides with a static config field — skipped
76
+ </p>
77
+
78
+ <!-- depth cap: don't expand nested dynamic-schema past MAX_DEPTH -->
79
+ <p v-else-if="f.type === 'dynamic-schema' && (depth ?? 0) >= MAX_DEPTH" class="text-sm text-muted-foreground">
80
+ nested dynamic-schema is not expanded further
81
+ </p>
82
+
83
+ <!-- a resolved field, rendered exactly like a static node config field -->
84
+ <IntegrationsNodeConfigField
85
+ v-else
86
+ :field="f"
87
+ :config="config"
88
+ :slug="slug"
89
+ :version="version"
90
+ :secret-keys="secretKeys"
91
+ :static-keys="staticKeys"
92
+ :depth="(depth ?? 0) + 1"
93
+ @set="(k, v) => emit('set', k, v)"
94
+ />
95
+ </template>
96
+
97
+ <p v-if="q.isFetching.value && q.hasData.value" class="text-sm text-muted-foreground">
98
+ reloading fields…
99
+ </p>
100
+ </fieldset>
101
+ </div>
102
+ </template>
@@ -0,0 +1,16 @@
1
+ import type { ConfigField } from '../../types/integrations.js';
2
+ type __VLS_Props = {
3
+ slug: string;
4
+ version: string;
5
+ field: ConfigField;
6
+ config: Record<string, unknown>;
7
+ staticKeys: string[];
8
+ secretKeys: string[];
9
+ depth?: number;
10
+ };
11
+ declare const _default: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
12
+ set: (key: string, value: unknown) => any;
13
+ }, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
14
+ onSet?: ((key: string, value: unknown) => any) | undefined;
15
+ }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
16
+ export default _default;
@@ -0,0 +1,23 @@
1
+ import type { ConfigField, WorkflowVariable } from '../../types/integrations.js';
2
+ type __VLS_Props = {
3
+ field: ConfigField;
4
+ config: Record<string, unknown>;
5
+ slug: string;
6
+ version: string;
7
+ secretKeys: string[];
8
+ staticKeys?: string[];
9
+ depth?: number;
10
+ variables?: Record<string, WorkflowVariable>;
11
+ upstreamOutputs?: Array<{
12
+ nodeId: string;
13
+ nodeName?: string;
14
+ output: string;
15
+ fields?: string[];
16
+ }>;
17
+ };
18
+ declare const _default: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
19
+ set: (key: string, value: unknown) => any;
20
+ }, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
21
+ onSet?: ((key: string, value: unknown) => any) | undefined;
22
+ }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
23
+ export default _default;