@revenexx/studio-integrations 0.1.4 → 0.3.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 (188) hide show
  1. package/README.md +31 -0
  2. package/dist/module.d.mts +2 -2
  3. package/dist/module.json +1 -1
  4. package/dist/runtime/components/Integrations/CredentialCreateDialog.d.vue.ts +13 -0
  5. package/dist/runtime/components/Integrations/CredentialCreateDialog.vue +279 -0
  6. package/dist/runtime/components/Integrations/CredentialCreateDialog.vue.d.ts +13 -0
  7. package/dist/runtime/components/Integrations/CredentialDetailDialog.d.vue.ts +20 -0
  8. package/dist/runtime/components/Integrations/CredentialDetailDialog.vue +342 -0
  9. package/dist/runtime/components/Integrations/CredentialDetailDialog.vue.d.ts +20 -0
  10. package/dist/runtime/components/Integrations/CredentialLogo.d.vue.ts +14 -0
  11. package/dist/runtime/components/Integrations/CredentialLogo.vue +37 -0
  12. package/dist/runtime/components/Integrations/CredentialLogo.vue.d.ts +14 -0
  13. package/dist/runtime/components/Integrations/CredentialRevenexxSource.d.vue.ts +12 -0
  14. package/dist/runtime/components/Integrations/CredentialRevenexxSource.vue +364 -0
  15. package/dist/runtime/components/Integrations/CredentialRevenexxSource.vue.d.ts +12 -0
  16. package/dist/runtime/components/Integrations/CredentialTypePicker.d.vue.ts +15 -0
  17. package/dist/runtime/components/Integrations/CredentialTypePicker.vue +71 -0
  18. package/dist/runtime/components/Integrations/CredentialTypePicker.vue.d.ts +15 -0
  19. package/dist/runtime/components/Integrations/DeadLettersPanel.d.vue.ts +5 -0
  20. package/dist/runtime/components/Integrations/DeadLettersPanel.vue +151 -0
  21. package/dist/runtime/components/Integrations/DeadLettersPanel.vue.d.ts +5 -0
  22. package/dist/runtime/components/Integrations/EditorTip.d.vue.ts +17 -0
  23. package/dist/runtime/components/Integrations/EditorTip.vue +46 -0
  24. package/dist/runtime/components/Integrations/EditorTip.vue.d.ts +17 -0
  25. package/dist/runtime/components/Integrations/EventTypeCombobox.d.vue.ts +9 -0
  26. package/dist/runtime/components/Integrations/EventTypeCombobox.vue +64 -0
  27. package/dist/runtime/components/Integrations/EventTypeCombobox.vue.d.ts +9 -0
  28. package/dist/runtime/components/Integrations/ExpressionInput.d.vue.ts +19 -0
  29. package/dist/runtime/components/Integrations/ExpressionInput.vue +236 -0
  30. package/dist/runtime/components/Integrations/ExpressionInput.vue.d.ts +19 -0
  31. package/dist/runtime/components/Integrations/GroupFrameView.d.vue.ts +28 -0
  32. package/dist/runtime/components/Integrations/GroupFrameView.vue +222 -0
  33. package/dist/runtime/components/Integrations/GroupFrameView.vue.d.ts +28 -0
  34. package/dist/runtime/components/Integrations/NodeConfigDynamicField.d.vue.ts +14 -0
  35. package/dist/runtime/components/Integrations/NodeConfigDynamicField.vue +184 -0
  36. package/dist/runtime/components/Integrations/NodeConfigDynamicField.vue.d.ts +14 -0
  37. package/dist/runtime/components/Integrations/NodeConfigDynamicSchema.d.vue.ts +16 -0
  38. package/dist/runtime/components/Integrations/NodeConfigDynamicSchema.vue +102 -0
  39. package/dist/runtime/components/Integrations/NodeConfigDynamicSchema.vue.d.ts +16 -0
  40. package/dist/runtime/components/Integrations/NodeConfigField.d.vue.ts +23 -0
  41. package/dist/runtime/components/Integrations/NodeConfigField.vue +587 -0
  42. package/dist/runtime/components/Integrations/NodeConfigField.vue.d.ts +23 -0
  43. package/dist/runtime/components/Integrations/NodeDynamicOutputsResolver.d.vue.ts +14 -0
  44. package/dist/runtime/components/Integrations/NodeDynamicOutputsResolver.vue +80 -0
  45. package/dist/runtime/components/Integrations/NodeDynamicOutputsResolver.vue.d.ts +14 -0
  46. package/dist/runtime/components/Integrations/NodeInspector.d.vue.ts +22 -3
  47. package/dist/runtime/components/Integrations/NodeInspector.vue +1074 -294
  48. package/dist/runtime/components/Integrations/NodeInspector.vue.d.ts +22 -3
  49. package/dist/runtime/components/Integrations/NodeLogo.d.vue.ts +9 -0
  50. package/dist/runtime/components/Integrations/NodeLogo.vue +38 -0
  51. package/dist/runtime/components/Integrations/NodeLogo.vue.d.ts +9 -0
  52. package/dist/runtime/components/Integrations/NodePalette.d.vue.ts +22 -1
  53. package/dist/runtime/components/Integrations/NodePalette.vue +411 -90
  54. package/dist/runtime/components/Integrations/NodePalette.vue.d.ts +22 -1
  55. package/dist/runtime/components/Integrations/QueryBuilder.d.vue.ts +9 -0
  56. package/dist/runtime/components/Integrations/QueryBuilder.vue +239 -0
  57. package/dist/runtime/components/Integrations/QueryBuilder.vue.d.ts +9 -0
  58. package/dist/runtime/components/Integrations/{RunDetailDialog.d.vue.ts → RunActionsMenu.d.vue.ts} +3 -4
  59. package/dist/runtime/components/Integrations/RunActionsMenu.vue +86 -0
  60. package/dist/runtime/components/Integrations/{RunDetailDialog.vue.d.ts → RunActionsMenu.vue.d.ts} +3 -4
  61. package/dist/runtime/components/Integrations/RunDetailPanel.d.vue.ts +14 -0
  62. package/dist/runtime/components/Integrations/RunDetailPanel.vue +777 -0
  63. package/dist/runtime/components/Integrations/RunDetailPanel.vue.d.ts +14 -0
  64. package/dist/runtime/components/Integrations/RunPayloadInput.d.vue.ts +13 -0
  65. package/dist/runtime/components/Integrations/RunPayloadInput.vue +175 -0
  66. package/dist/runtime/components/Integrations/RunPayloadInput.vue.d.ts +13 -0
  67. package/dist/runtime/components/Integrations/RunResponseModal.d.vue.ts +27 -0
  68. package/dist/runtime/components/Integrations/RunResponseModal.vue +84 -0
  69. package/dist/runtime/components/Integrations/RunResponseModal.vue.d.ts +27 -0
  70. package/dist/runtime/components/Integrations/RunsTable.d.vue.ts +21 -0
  71. package/dist/runtime/components/Integrations/RunsTable.vue +114 -0
  72. package/dist/runtime/components/Integrations/RunsTable.vue.d.ts +21 -0
  73. package/dist/runtime/components/Integrations/SftpAccountImportDialog.d.vue.ts +11 -0
  74. package/dist/runtime/components/Integrations/SftpAccountImportDialog.vue +91 -0
  75. package/dist/runtime/components/Integrations/SftpAccountImportDialog.vue.d.ts +11 -0
  76. package/dist/runtime/components/Integrations/StickyNoteView.d.vue.ts +28 -0
  77. package/dist/runtime/components/Integrations/StickyNoteView.vue +208 -0
  78. package/dist/runtime/components/Integrations/StickyNoteView.vue.d.ts +28 -0
  79. package/dist/runtime/components/Integrations/TemplateFlowPreview.d.vue.ts +29 -0
  80. package/dist/runtime/components/Integrations/TemplateFlowPreview.vue +201 -0
  81. package/dist/runtime/components/Integrations/TemplateFlowPreview.vue.d.ts +29 -0
  82. package/dist/runtime/components/Integrations/WorkflowContextMenu.d.vue.ts +32 -0
  83. package/dist/runtime/components/Integrations/WorkflowContextMenu.vue +138 -0
  84. package/dist/runtime/components/Integrations/WorkflowContextMenu.vue.d.ts +32 -0
  85. package/dist/runtime/components/Integrations/WorkflowCreateDialog.d.vue.ts +9 -0
  86. package/dist/runtime/components/Integrations/WorkflowCreateDialog.vue +322 -0
  87. package/dist/runtime/components/Integrations/WorkflowCreateDialog.vue.d.ts +9 -0
  88. package/dist/runtime/components/Integrations/WorkflowDuplicateDialog.d.vue.ts +18 -0
  89. package/dist/runtime/components/Integrations/WorkflowDuplicateDialog.vue +63 -0
  90. package/dist/runtime/components/Integrations/WorkflowDuplicateDialog.vue.d.ts +18 -0
  91. package/dist/runtime/components/Integrations/WorkflowEdgeView.d.vue.ts +12 -1
  92. package/dist/runtime/components/Integrations/WorkflowEdgeView.vue +68 -6
  93. package/dist/runtime/components/Integrations/WorkflowEdgeView.vue.d.ts +12 -1
  94. package/dist/runtime/components/Integrations/WorkflowEditor.d.vue.ts +8 -1
  95. package/dist/runtime/components/Integrations/WorkflowEditor.vue +1424 -144
  96. package/dist/runtime/components/Integrations/WorkflowEditor.vue.d.ts +8 -1
  97. package/dist/runtime/components/Integrations/WorkflowHistoryPanel.d.vue.ts +12 -0
  98. package/dist/runtime/components/Integrations/WorkflowHistoryPanel.vue +417 -0
  99. package/dist/runtime/components/Integrations/WorkflowHistoryPanel.vue.d.ts +12 -0
  100. package/dist/runtime/components/Integrations/WorkflowIconPicker.d.vue.ts +10 -0
  101. package/dist/runtime/components/Integrations/WorkflowIconPicker.vue +89 -0
  102. package/dist/runtime/components/Integrations/WorkflowIconPicker.vue.d.ts +10 -0
  103. package/dist/runtime/components/Integrations/WorkflowIconView.d.vue.ts +10 -0
  104. package/dist/runtime/components/Integrations/WorkflowIconView.vue +35 -0
  105. package/dist/runtime/components/Integrations/WorkflowIconView.vue.d.ts +10 -0
  106. package/dist/runtime/components/Integrations/WorkflowNodeView.d.vue.ts +5 -1
  107. package/dist/runtime/components/Integrations/WorkflowNodeView.vue +114 -84
  108. package/dist/runtime/components/Integrations/WorkflowNodeView.vue.d.ts +5 -1
  109. package/dist/runtime/components/Integrations/WorkflowRunReplayPanel.d.vue.ts +12 -0
  110. package/dist/runtime/components/Integrations/WorkflowRunReplayPanel.vue +654 -0
  111. package/dist/runtime/components/Integrations/WorkflowRunReplayPanel.vue.d.ts +12 -0
  112. package/dist/runtime/components/Integrations/WorkflowSettingsDialog.d.vue.ts +36 -0
  113. package/dist/runtime/components/Integrations/WorkflowSettingsDialog.vue +136 -0
  114. package/dist/runtime/components/Integrations/WorkflowSettingsDialog.vue.d.ts +36 -0
  115. package/dist/runtime/components/Integrations/WorkflowTagsInput.d.vue.ts +14 -0
  116. package/dist/runtime/components/Integrations/WorkflowTagsInput.vue +63 -0
  117. package/dist/runtime/components/Integrations/WorkflowTagsInput.vue.d.ts +14 -0
  118. package/dist/runtime/components/Integrations/WorkflowTriggerView.vue +35 -15
  119. package/dist/runtime/components/Integrations/WorkflowVariablesDialog.d.vue.ts +13 -0
  120. package/dist/runtime/components/Integrations/WorkflowVariablesDialog.vue +265 -0
  121. package/dist/runtime/components/Integrations/WorkflowVariablesDialog.vue.d.ts +13 -0
  122. package/dist/runtime/components/Integrations/WorkflowsTable.d.vue.ts +4 -1
  123. package/dist/runtime/components/Integrations/WorkflowsTable.vue +122 -39
  124. package/dist/runtime/components/Integrations/WorkflowsTable.vue.d.ts +4 -1
  125. package/dist/runtime/components/Integrations/workflowLayout.d.ts +5 -0
  126. package/dist/runtime/components/Integrations/workflowLayout.js +5 -3
  127. package/dist/runtime/composables/integrationsApi.d.ts +6 -7
  128. package/dist/runtime/composables/integrationsApi.js +6 -12
  129. package/dist/runtime/composables/useCanvasShortcuts.d.ts +37 -0
  130. package/dist/runtime/composables/useCanvasShortcuts.js +62 -0
  131. package/dist/runtime/composables/useCredentialTypes.js +2 -1
  132. package/dist/runtime/composables/useIntegrationsAudit.js +2 -1
  133. package/dist/runtime/composables/useIntegrationsCredentials.js +2 -1
  134. package/dist/runtime/composables/useIntegrationsDeadLetters.d.ts +22 -0
  135. package/dist/runtime/composables/useIntegrationsDeadLetters.js +50 -0
  136. package/dist/runtime/composables/useIntegrationsNodes.d.ts +4 -0
  137. package/dist/runtime/composables/useIntegrationsNodes.js +8 -4
  138. package/dist/runtime/composables/useIntegrationsRevisions.d.ts +40 -0
  139. package/dist/runtime/composables/useIntegrationsRevisions.js +52 -0
  140. package/dist/runtime/composables/useIntegrationsRuns.d.ts +21 -1
  141. package/dist/runtime/composables/useIntegrationsRuns.js +94 -5
  142. package/dist/runtime/composables/useIntegrationsSecrets.js +2 -1
  143. package/dist/runtime/composables/useIntegrationsTemplates.d.ts +1 -0
  144. package/dist/runtime/composables/useIntegrationsTemplates.js +34 -5
  145. package/dist/runtime/composables/useIntegrationsTriggers.js +2 -1
  146. package/dist/runtime/composables/useIntegrationsWorkflows.d.ts +1 -0
  147. package/dist/runtime/composables/useIntegrationsWorkflows.js +59 -2
  148. package/dist/runtime/composables/useMiniMapLayout.d.ts +34 -0
  149. package/dist/runtime/composables/useMiniMapLayout.js +119 -0
  150. package/dist/runtime/composables/useNodeConfigResolve.d.ts +43 -0
  151. package/dist/runtime/composables/useNodeConfigResolve.js +124 -0
  152. package/dist/runtime/composables/useNodeDrag.d.ts +22 -0
  153. package/dist/runtime/composables/useNodeDrag.js +10 -0
  154. package/dist/runtime/composables/usePaletteLayout.d.ts +41 -0
  155. package/dist/runtime/composables/usePaletteLayout.js +113 -0
  156. package/dist/runtime/data/expressionEditor.d.ts +22 -0
  157. package/dist/runtime/data/expressionEditor.js +40 -0
  158. package/dist/runtime/data/integrationNodeCatalog.js +8 -8
  159. package/dist/runtime/data/nodeInputData.d.ts +37 -0
  160. package/dist/runtime/data/nodeInputData.js +62 -0
  161. package/dist/runtime/data/nodeRunData.d.ts +56 -0
  162. package/dist/runtime/data/nodeRunData.js +91 -0
  163. package/dist/runtime/data/payloadForm.d.ts +44 -0
  164. package/dist/runtime/data/payloadForm.js +126 -0
  165. package/dist/runtime/data/workflowIconCatalog.d.ts +34 -0
  166. package/dist/runtime/data/workflowIconCatalog.js +116 -0
  167. package/dist/runtime/pages/integrations/audit.vue +25 -35
  168. package/dist/runtime/pages/integrations/credentials.vue +117 -122
  169. package/dist/runtime/pages/integrations/index.vue +133 -36
  170. package/dist/runtime/pages/integrations/runs.vue +125 -75
  171. package/dist/runtime/pages/integrations/schedules.vue +5 -16
  172. package/dist/runtime/pages/integrations/secrets.vue +1 -3
  173. package/dist/runtime/pages/integrations/workflows/[id].vue +599 -194
  174. package/dist/runtime/pages/integrations/workflows/index.vue +10 -8
  175. package/dist/runtime/types/integrations.d.ts +190 -4
  176. package/dist/runtime/utils/apiError.d.ts +17 -0
  177. package/dist/runtime/utils/apiError.js +8 -0
  178. package/dist/runtime/utils/credentialState.d.ts +28 -0
  179. package/dist/runtime/utils/credentialState.js +29 -0
  180. package/dist/runtime/utils/localize.d.ts +3 -1
  181. package/dist/runtime/utils/localize.js +1 -2
  182. package/dist/runtime/utils/statusStyle.d.ts +6 -0
  183. package/dist/runtime/utils/statusStyle.js +15 -0
  184. package/package.json +20 -3
  185. package/dist/runtime/components/Integrations/RunDetailDialog.vue +0 -169
  186. package/dist/runtime/pages/integrations/workflows/new.d.vue.ts +0 -2
  187. package/dist/runtime/pages/integrations/workflows/new.vue +0 -153
  188. package/dist/runtime/pages/integrations/workflows/new.vue.d.ts +0 -2
@@ -2,11 +2,13 @@
2
2
  import { AddCircle as Plus } from "#solar-icons";
3
3
  import { Button } from "@revenexx/studio";
4
4
  import WorkflowsTable from "../../../components/Integrations/WorkflowsTable.vue";
5
+ import WorkflowCreateDialog from "../../../components/Integrations/WorkflowCreateDialog.vue";
5
6
  useHead({ title: "Workflows \xB7 Revenexx Cockpit" });
6
- const { workflows, load } = useIntegrationsWorkflows();
7
+ const { workflows, loading, load } = useIntegrationsWorkflows();
7
8
  onMounted(() => {
8
9
  void load();
9
10
  });
11
+ const createOpen = ref(false);
10
12
  </script>
11
13
 
12
14
  <template>
@@ -15,17 +17,17 @@ onMounted(() => {
15
17
  title="Workflows"
16
18
  >
17
19
  <template #actions>
18
- <NuxtLink to="/integrations/workflows/new">
19
- <Button class="h-7 text-sm">
20
- <Plus :size="14" />
21
- New workflow
22
- </Button>
23
- </NuxtLink>
20
+ <Button class="h-7 text-sm" @click="createOpen = true">
21
+ <Plus :size="14" />
22
+ New workflow
23
+ </Button>
24
24
  </template>
25
25
  </PageHeader>
26
26
 
27
27
  <div class="p-4">
28
- <WorkflowsTable :workflows="workflows" />
28
+ <WorkflowsTable :workflows="workflows" :loading="loading" />
29
29
  </div>
30
+
31
+ <WorkflowCreateDialog v-model:open="createOpen" />
30
32
  </IntegrationsLayout>
31
33
  </template>
@@ -37,6 +37,12 @@ export interface WorkflowNodeRetry {
37
37
  backoffSeconds?: number;
38
38
  strategy?: RetryStrategy;
39
39
  }
40
+ /**
41
+ * What the engine does when a node still fails after its retries: `fail`
42
+ * (default) fails the run; `route` records the failure as the node's `error`
43
+ * output so a wired error edge handles it. Stop and Error always fails.
44
+ */
45
+ export type WorkflowNodeOnError = 'route' | 'fail';
40
46
  export interface WorkflowNodePosition {
41
47
  x: number;
42
48
  y: number;
@@ -48,10 +54,19 @@ export interface WorkflowNode {
48
54
  /** semver pin for the chosen manifest version. */
49
55
  nodeVersion: string;
50
56
  name?: LocalizedString;
57
+ /** Optional editor-only note/comment on this node instance (blob `nodes[].notes`). */
58
+ notes?: string;
51
59
  /** Free-form key→value config, validated against the node manifest. */
52
60
  config: Record<string, unknown>;
53
61
  position?: WorkflowNodePosition;
54
62
  retry?: WorkflowNodeRetry;
63
+ onError?: WorkflowNodeOnError;
64
+ /**
65
+ * Per-node execution timeout in seconds (engine start-to-close, 1..7200).
66
+ * Absent = engine default (10 minutes). For long-running orchestration
67
+ * nodes, e.g. waiting on a bulk import job.
68
+ */
69
+ timeoutSeconds?: number;
55
70
  }
56
71
  export interface WorkflowEdge {
57
72
  id: string;
@@ -64,6 +79,49 @@ export interface WorkflowEdge {
64
79
  input?: string;
65
80
  };
66
81
  }
82
+ /** Editor-only node group: a canvas frame owning member nodes (blob `groups[]`). */
83
+ export interface WorkflowGroup {
84
+ id: string;
85
+ label: LocalizedString;
86
+ /** Member node/trigger handles. */
87
+ nodeIds: string[];
88
+ /** Palette index 0..6 (shares the sticky palette). */
89
+ color?: number;
90
+ /** Collapsed groups render as one compact card; members hide. */
91
+ collapsed?: boolean;
92
+ /** Manually resized frame; absent = derived from the members' bounding box. */
93
+ rect?: {
94
+ x: number;
95
+ y: number;
96
+ width: number;
97
+ height: number;
98
+ };
99
+ }
100
+ /** Editor-only sticky note on the canvas (engine-irrelevant; blob `stickies[]`). */
101
+ export interface WorkflowSticky {
102
+ id: string;
103
+ /** Note text; markdown-lite (`#`/`##`/`###` headings, `**bold**`), line breaks kept. */
104
+ content: string;
105
+ position: {
106
+ x: number;
107
+ y: number;
108
+ };
109
+ /** Absent → the editor's 240x160 default. */
110
+ size?: {
111
+ width: number;
112
+ height: number;
113
+ };
114
+ /** Palette index 0..6 (0 = amber default). */
115
+ color?: number;
116
+ }
117
+ /** Editor-only workflow icon (BlobDef `icon`): a curated solar icon name or a node-package image URL. */
118
+ export interface WorkflowIcon {
119
+ kind: 'solar' | 'image';
120
+ /** Icon-library name (kind=solar). */
121
+ name?: string;
122
+ /** Image URL, e.g. a node-package logo (kind=image). */
123
+ src?: string;
124
+ }
67
125
  export interface WorkflowBlob {
68
126
  nodeManifestVersion: string;
69
127
  name: LocalizedString;
@@ -77,8 +135,22 @@ export interface WorkflowBlob {
77
135
  x: number;
78
136
  y: number;
79
137
  }>;
138
+ /** Canvas sticky notes (engine-irrelevant annotations, BlobDef `stickies`). */
139
+ stickies?: WorkflowSticky[];
140
+ /** Canvas node groups (engine-irrelevant frames, BlobDef `groups`). */
141
+ groups?: WorkflowGroup[];
142
+ /** Organisational tags for grouping/filtering (engine-irrelevant, BlobDef `tags`). */
143
+ tags?: string[];
144
+ /** Workflow icon shown in lists and headers (engine-irrelevant, BlobDef `icon`). */
145
+ icon?: WorkflowIcon;
80
146
  }
81
147
  export type WorkflowExecutionMode = 'async_only' | 'sync_only' | 'caller_decides';
148
+ /**
149
+ * Build state of a workflow's executable bundle (backend `build_status`). Source
150
+ * of truth for runnability — the worker pool only runs a workflow once its
151
+ * bundle is `ready`; the API rejects runs with 409 in any other state.
152
+ */
153
+ export type WorkflowBuildStatus = 'pending' | 'building' | 'ready' | 'failed';
82
154
  export interface Workflow {
83
155
  id: number;
84
156
  name: string;
@@ -88,6 +160,10 @@ export interface Workflow {
88
160
  active: boolean;
89
161
  revision: number;
90
162
  execution_mode?: WorkflowExecutionMode;
163
+ /** Bundle build state; `null` on legacy rows the builder never touched. */
164
+ buildStatus: WorkflowBuildStatus | null;
165
+ /** Human-readable build failure reason, present when `buildStatus === 'failed'`. */
166
+ buildError: string | null;
91
167
  created_at: string;
92
168
  updated_at: string;
93
169
  }
@@ -106,12 +182,18 @@ export interface NodeManifestOutput {
106
182
  dataType: NodeDataType;
107
183
  description?: LocalizedString;
108
184
  sourceFromConfig?: string;
185
+ /** When true, the node's outputs for this manifest are resolved dynamically
186
+ * via config:resolve with target 'outputs' (later phase; harmless now). */
187
+ resolveOutputs?: boolean;
109
188
  fallback?: {
110
189
  name: string;
111
190
  label?: LocalizedString;
112
191
  };
192
+ /** Declared field names of this output's payload, when the manifest
193
+ * publishes them. Author-time schema only, never live run data. */
194
+ fields?: string[] | Record<string, unknown>;
113
195
  }
114
- export type ConfigFieldType = 'string' | 'number' | 'boolean' | 'select' | 'multiselect' | 'object' | 'array' | 'expression' | 'secret-ref' | 'credentials-ref';
196
+ export type ConfigFieldType = 'string' | 'number' | 'boolean' | 'select' | 'multiselect' | 'object' | 'array' | 'expression' | 'secret-ref' | 'credentials-ref' | 'dynamic-schema';
115
197
  export interface ConfigFieldOption {
116
198
  value: string | number | boolean;
117
199
  label: LocalizedString;
@@ -126,12 +208,20 @@ export interface ConfigField {
126
208
  placeholder?: LocalizedString;
127
209
  expressionAllowed?: boolean;
128
210
  options?: ConfigFieldOption[];
211
+ /** When true, this field's `options` are resolved at author-time via
212
+ * config:resolve with target === this field's `key` (see useNodeConfigResolve). */
213
+ dynamic?: boolean;
129
214
  /** sub-fields when type === 'object' (one level deep) */
130
215
  properties?: ConfigField[];
131
216
  /** item type when type === 'array' */
132
217
  items?: ConfigField;
133
- /** credential type slug the field binds to when type === 'credentials-ref' (e.g. 'revenexx:business-central'). */
134
- credentialType?: string;
218
+ /** credential type slug(s) the field binds to when type === 'credentials-ref'
219
+ * (e.g. 'revenexx:business-central'). An array lets a node accept more than
220
+ * one credential type; the picker merges the tenant's credentials across all. */
221
+ credentialType?: string | string[];
222
+ /** keys of other config fields this field's options/schema depend on. The
223
+ * driving `select` fields also form the node's canvas subtitle. */
224
+ dependsOn?: string[];
135
225
  validation?: {
136
226
  pattern?: string;
137
227
  min?: number;
@@ -140,6 +230,20 @@ export interface ConfigField {
140
230
  maxLength?: number;
141
231
  };
142
232
  }
233
+ export interface ResolveOption {
234
+ value: string | number | boolean;
235
+ label?: LocalizedString;
236
+ }
237
+ export interface NodeConfigResolveResult {
238
+ options?: ResolveOption[];
239
+ fields?: ConfigField[];
240
+ outputs?: NodeManifestOutput[];
241
+ }
242
+ export type ResolveErrorKind = 'building' | 'runtime' | 'forbidden' | 'notfound' | 'generic';
243
+ export interface NodeConfigResolveError {
244
+ kind: ResolveErrorKind;
245
+ message: string;
246
+ }
143
247
  export interface NodeManifest {
144
248
  slug: string;
145
249
  version: string;
@@ -148,9 +252,27 @@ export interface NodeManifest {
148
252
  description?: LocalizedString;
149
253
  /** lucide-vue-next icon name OR mdi:icon-id. */
150
254
  icon?: string;
255
+ /**
256
+ * Curated palette group path (e.g. ["Business Central", "Sales Orders"]).
257
+ * Optional manifest field; when absent the palette derives a path from the
258
+ * source package + slug heuristics.
259
+ */
260
+ groups?: LocalizedString[];
261
+ /** Brand images (category `logo` drives palette/canvas rendering); src is a signed URL. */
262
+ images?: Array<{
263
+ src: string;
264
+ alt?: LocalizedString;
265
+ title?: LocalizedString;
266
+ category?: string;
267
+ }>;
151
268
  input: NodeManifestInput;
152
269
  outputs: NodeManifestOutput[];
153
270
  config?: ConfigField[];
271
+ /** Source package (editor-side enrichment from GET /nodes; not manifest data). */
272
+ __package?: {
273
+ name: string;
274
+ label: string | null;
275
+ };
154
276
  }
155
277
  export interface SecretRecord {
156
278
  key: string;
@@ -178,12 +300,21 @@ export interface CredentialTypeField {
178
300
  };
179
301
  }
180
302
  /** A globally-registered credential type — drives the dynamic credential form. */
303
+ /** A brand/logo image shipped with a credential type. `src` is a short-lived
304
+ * signed URL minted by the credential-types API (ManifestImageUrlSigner). */
305
+ export interface CredentialTypeImage {
306
+ src: string;
307
+ alt?: LocalizedString;
308
+ category?: 'logo' | 'icon' | 'banner' | 'screenshot' | 'other' | string;
309
+ }
181
310
  export interface CredentialType {
182
311
  slug: string;
183
312
  version: string;
184
313
  name: LocalizedString;
185
314
  description?: LocalizedString;
186
315
  icon?: string;
316
+ /** Signed logo/brand image URLs from the API (prefer `category: 'logo'`). */
317
+ images?: CredentialTypeImage[];
187
318
  auth_kind: AuthKind;
188
319
  fields: CredentialTypeField[];
189
320
  }
@@ -196,6 +327,10 @@ export interface Credential {
196
327
  status: CredentialStatus;
197
328
  /** non-secret field values only (whitelisted types). */
198
329
  public_config?: Record<string, unknown>;
330
+ /** Outcome of the last connection test (persisted by the API). Null when never tested. */
331
+ last_test_at?: string | null;
332
+ last_test_ok?: boolean | null;
333
+ last_test_message?: string | null;
199
334
  created_at: string;
200
335
  updated_at: string;
201
336
  }
@@ -250,12 +385,30 @@ export interface ScheduleEntry {
250
385
  nextRunAt: string | null;
251
386
  lastRunAt: string | null;
252
387
  }
253
- export type TemplateCategory = 'sync' | 'notification' | 'enrichment' | 'fulfilment' | 'reporting' | 'finance';
388
+ export type TemplateCategory = 'sync' | 'notification' | 'enrichment' | 'fulfilment' | 'reporting' | 'finance' | 'commerce' | 'sales';
254
389
  export interface WorkflowTemplate {
255
390
  /** kebab-case stable id. */
256
391
  slug: string;
257
392
  name: string;
393
+ /** Plain one-liner for cards and pickers (shortDescription, or a de-markdowned excerpt). */
258
394
  description: string;
395
+ /** The full registry description as Markdown; rendered on the detail page. */
396
+ descriptionMd: string;
397
+ /** Trigger types from the catalogue listing (schedule/webhook/manual/event). */
398
+ triggerTypes: TriggerType[];
399
+ /** Registry images (banner/screenshot categories, signed URLs). */
400
+ images: Array<{
401
+ src: string;
402
+ category?: string;
403
+ alt?: unknown;
404
+ }>;
405
+ /** True once the heavy definition blob has been merged via fetchDetail. */
406
+ detailLoaded?: boolean;
407
+ /** Source node package this template ships with (e.g. Business Central). */
408
+ package?: {
409
+ name: string;
410
+ label: string | null;
411
+ } | null;
259
412
  category: TemplateCategory;
260
413
  industries: Array<'mechanical-engineering' | 'chemicals' | 'wholesale' | 'manufacturing' | 'retail' | 'any'>;
261
414
  /** Vendor slugs this template wires together (used to compute prerequisites). */
@@ -325,11 +478,42 @@ export interface WorkflowRunNodeStep {
325
478
  attempt: number;
326
479
  durationMs: number | null;
327
480
  }
481
+ export interface RunStepRow {
482
+ node_id: string;
483
+ node_slug: string;
484
+ activity_type: string;
485
+ status: string;
486
+ attempt: number;
487
+ scheduled_event_id: number | null;
488
+ duration_ms: number | null;
489
+ branch?: string | null;
490
+ error?: string | null;
491
+ input?: unknown;
492
+ output?: unknown;
493
+ /** Resolved node config for this step (present with include_payloads). */
494
+ config?: unknown;
495
+ scheduled_at?: string | null;
496
+ started_at?: string | null;
497
+ completed_at?: string | null;
498
+ }
499
+ export interface DeadLetterRow {
500
+ id: number;
501
+ workflow_id: number;
502
+ trigger_id: string | null;
503
+ source: string | null;
504
+ trigger_handle: string | null;
505
+ reason: string | null;
506
+ status: 'pending' | 'replayed' | 'discarded' | string;
507
+ created_at: string | null;
508
+ updated_at: string | null;
509
+ }
328
510
  export interface WorkflowRun {
329
511
  id: string;
330
512
  workflowId: number;
331
513
  workflowName: string;
332
514
  status: RunStatus;
515
+ /** Temporal run id for this execution; null when the row predates Temporal. */
516
+ temporalRunId?: string | null;
333
517
  triggerId: string;
334
518
  triggerType: TriggerType;
335
519
  startedAt: string;
@@ -348,6 +532,8 @@ export interface OutpostEvent {
348
532
  id: string;
349
533
  /** Topic the event was published on, e.g. "order.created". */
350
534
  topic: string;
535
+ /** Tenant slug from the envelope (empty when the source omits it). */
536
+ tenantId?: string;
351
537
  /** ISO timestamp the event was received. */
352
538
  time: string;
353
539
  /** Whether delivery may be retried (eligible_for_retry). */
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Error thrown by the Integrations API client.
3
+ *
4
+ * It lives here rather than next to `useIntegrationsApi` on purpose: the
5
+ * module auto-imports everything the `composables/` directory exports, and a
6
+ * class exported from there gets registered as an auto-import too. Consumed
7
+ * from the built `dist/` (any host that installs the package from npm) the
8
+ * auto-import resolver then injects the identifier back into the very file
9
+ * that declares it — "Identifier 'IntegrationsApiError' has already been
10
+ * declared" at runtime. Keeping non-composable exports out of that directory
11
+ * avoids the whole class of problem; callers import it explicitly.
12
+ */
13
+ export declare class IntegrationsApiError extends Error {
14
+ status: number;
15
+ body: unknown;
16
+ constructor(status: number, body: unknown, message: string);
17
+ }
@@ -0,0 +1,8 @@
1
+ export class IntegrationsApiError extends Error {
2
+ constructor(status, body, message) {
3
+ super(message);
4
+ this.status = status;
5
+ this.body = body;
6
+ this.name = "IntegrationsApiError";
7
+ }
8
+ }
@@ -0,0 +1,28 @@
1
+ import type { Credential } from '../types/integrations.js';
2
+ /**
3
+ * The honest, operator-facing state of a credential — derived from the
4
+ * persisted connection-test result, NOT from `status` (which only tracks the
5
+ * OAuth refresh lifecycle and defaults to `active` on create, so it can't say
6
+ * whether the access data actually works).
7
+ *
8
+ * needs_reauth → an OAuth refresh failed; reconnect required
9
+ * connected → the last connection test passed
10
+ * failed → the last connection test failed (see `message`)
11
+ * untested → never tested — deliberately distinct from a passing test
12
+ */
13
+ export type CredentialConnState = 'connected' | 'failed' | 'needs_reauth' | 'untested';
14
+ export interface CredentialStateInfo {
15
+ key: CredentialConnState;
16
+ label: string;
17
+ /** Badge/pill classes for this state. */
18
+ toneClass: string;
19
+ /** Failure detail, when the state is `failed`. */
20
+ message?: string | null;
21
+ /** When the underlying result was recorded (ISO). */
22
+ at?: string | null;
23
+ }
24
+ type TestableCredential = Pick<Credential, 'status' | 'last_test_ok' | 'last_test_at' | 'last_test_message'>;
25
+ export declare function credentialState(c: TestableCredential): CredentialStateInfo;
26
+ /** "just now" / "3m ago" / "2h ago" / "5d ago" / a date. Empty for no timestamp. */
27
+ export declare function relativeTime(iso?: string | null): string;
28
+ export {};
@@ -0,0 +1,29 @@
1
+ const TONE = {
2
+ connected: "bg-emerald-500/10 border-emerald-500/20 text-emerald-700",
3
+ failed: "bg-rose-500/10 border-rose-500/20 text-rose-700",
4
+ needs_reauth: "bg-amber-500/10 border-amber-500/20 text-amber-700",
5
+ untested: "bg-slate-500/10 border-slate-500/20 text-slate-600"
6
+ };
7
+ export function credentialState(c) {
8
+ if (c.status === "needs_reauth") {
9
+ return { key: "needs_reauth", label: "Needs reconnect", toneClass: TONE.needs_reauth, at: c.last_test_at };
10
+ }
11
+ if (c.last_test_ok === true) {
12
+ return { key: "connected", label: "Connected", toneClass: TONE.connected, at: c.last_test_at };
13
+ }
14
+ if (c.last_test_ok === false) {
15
+ return { key: "failed", label: "Failed", toneClass: TONE.failed, message: c.last_test_message, at: c.last_test_at };
16
+ }
17
+ return { key: "untested", label: "Not Connected", toneClass: TONE.untested };
18
+ }
19
+ export function relativeTime(iso) {
20
+ if (!iso) return "";
21
+ const t = new Date(iso).getTime();
22
+ if (Number.isNaN(t)) return "";
23
+ const ms = Date.now() - t;
24
+ if (ms < 6e4) return "just now";
25
+ if (ms < 36e5) return `${Math.floor(ms / 6e4)}m ago`;
26
+ if (ms < 864e5) return `${Math.floor(ms / 36e5)}h ago`;
27
+ if (ms < 30 * 864e5) return `${Math.floor(ms / 864e5)}d ago`;
28
+ return new Date(iso).toLocaleDateString();
29
+ }
@@ -4,6 +4,8 @@
4
4
  * object `{de:"…", en:"…"}` (the HTTP client does JSON decoding automatically).
5
5
  * JSON-encoded strings like `'{"de":"…","en":"…"}'` are also handled.
6
6
  *
7
- * Priority: 1) current browser locale language, 2) "en", 3) first key found.
7
+ * Priority: 1) "en", 2) first key found. English is the cockpit default —
8
+ * there is no working language switcher yet; browser-locale preference
9
+ * returns together with the switcher.
8
10
  */
9
11
  export declare function resolveLocalized(value: unknown): string;
@@ -4,8 +4,7 @@ export function resolveLocalized(value) {
4
4
  const map = value;
5
5
  const keys = Object.keys(map);
6
6
  if (!keys.length) return "";
7
- const lang = typeof navigator !== "undefined" ? navigator.language?.split("-")[0]?.toLowerCase() ?? "en" : "en";
8
- const picked = map[lang] ?? map["en"] ?? map[keys[0]];
7
+ const picked = map["en"] ?? map[keys[0]];
9
8
  return typeof picked === "string" ? picked : "";
10
9
  }
11
10
  if (typeof value !== "string") return String(value);
@@ -13,3 +13,9 @@ export declare function statusTone(status: string | null | undefined): StatusTon
13
13
  export declare function statusClass(status: string | null | undefined): string;
14
14
  /** Tone classes directly (when you already have a tone). */
15
15
  export declare function toneClass(tone: StatusTone): string;
16
+ /**
17
+ * Raw API/Temporal run vocabulary → the cockpit's run-status labels, so a run
18
+ * never reads "completed" in one surface and "succeeded" in another. Unknown
19
+ * statuses pass through lowercased.
20
+ */
21
+ export declare function runStatusLabel(status: string | null | undefined): string;
@@ -76,3 +76,18 @@ export function statusClass(status) {
76
76
  export function toneClass(tone) {
77
77
  return TONE_CLASS[tone];
78
78
  }
79
+ export function runStatusLabel(status) {
80
+ if (!status) return "";
81
+ const s = String(status).toLowerCase().replace(/[\s-]+/g, "_");
82
+ switch (s) {
83
+ case "completed":
84
+ return "succeeded";
85
+ case "pending":
86
+ return "queued";
87
+ case "terminated":
88
+ case "timed_out":
89
+ return "failed";
90
+ default:
91
+ return s;
92
+ }
93
+ }
package/package.json CHANGED
@@ -1,8 +1,12 @@
1
1
  {
2
2
  "name": "@revenexx/studio-integrations",
3
- "version": "0.1.4",
3
+ "version": "0.3.0",
4
4
  "type": "module",
5
5
  "description": "Integration Studio (core: workflows, node editor, runs, schedules, credentials, secrets, audit) as a standalone, publishable Nuxt module.",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://github.com/revenexx/studio-integrations.git"
9
+ },
6
10
  "main": "./dist/module.mjs",
7
11
  "types": "./dist/types.d.mts",
8
12
  "exports": {
@@ -25,24 +29,37 @@
25
29
  "peerDependencies": {
26
30
  "@dagrejs/dagre": "^3.0.0",
27
31
  "@revenexx/studio": "*",
32
+ "@revenexx/studio-shared": "^0.1.2",
33
+ "@solar-icons/nuxt": "^1.2.0",
34
+ "@tiptap/core": "^3.28.0",
35
+ "@tiptap/extension-document": "^3.28.0",
36
+ "@tiptap/extension-history": "^3.28.0",
37
+ "@tiptap/extension-paragraph": "^3.28.0",
38
+ "@tiptap/extension-text": "^3.28.0",
39
+ "@tiptap/pm": "^3.28.0",
40
+ "@tiptap/vue-3": "^3.28.0",
28
41
  "@vue-flow/background": "^1.3.2",
29
42
  "@vue-flow/controls": "^1.1.3",
30
43
  "@vue-flow/core": "^1.48.2",
31
44
  "@vue-flow/minimap": "^1.5.4",
45
+ "@vue-flow/node-toolbar": "^1.1.1",
32
46
  "lucide-vue-next": "^1.0.0",
33
47
  "nuxt": "^4.0.0",
34
48
  "vue": "^3.5.0",
35
- "@revenexx/studio-shared": "0.1.2"
49
+ "vue-sonner": "^2.0.0"
36
50
  },
37
51
  "devDependencies": {
38
52
  "@nuxt/module-builder": "^1.0.2",
39
53
  "@nuxt/kit": "^4.0.0",
54
+ "@nuxt/schema": "^4.0.0",
40
55
  "nuxt": "^4.2.2",
56
+ "vitest": "^3.2.0",
41
57
  "vue": "^3.5.26",
42
58
  "vue-tsc": "^2.2.0"
43
59
  },
44
60
  "license": "SEE LICENSE IN LICENSE",
45
61
  "scripts": {
46
- "build": "nuxt-module-build build"
62
+ "build": "nuxt-module-build build",
63
+ "test": "vitest run"
47
64
  }
48
65
  }