@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
@@ -1,12 +1,5 @@
1
1
  import { computed } from "vue";
2
- export class IntegrationsApiError extends Error {
3
- constructor(status, body, message) {
4
- super(message);
5
- this.status = status;
6
- this.body = body;
7
- this.name = "IntegrationsApiError";
8
- }
9
- }
2
+ import { IntegrationsApiError } from "../utils/apiError.js";
10
3
  export function useIntegrationsApi() {
11
4
  const config = useRuntimeConfig();
12
5
  const { getToken } = usePlatformAuth();
@@ -29,13 +22,14 @@ export function useIntegrationsApi() {
29
22
  function url(path) {
30
23
  return `${baseUrl.value.replace(/\/$/, "")}${path.startsWith("/") ? path : `/${path}`}`;
31
24
  }
32
- async function request(method, path, body) {
25
+ async function request(method, path, body, opts) {
33
26
  const headers = await buildHeaders(body !== void 0 ? { "Content-Type": "application/json" } : {});
34
27
  try {
35
28
  return await $fetch(url(path), {
36
29
  method,
37
30
  headers,
38
- body: body !== void 0 ? body : void 0
31
+ body: body !== void 0 ? body : void 0,
32
+ signal: opts?.signal
39
33
  });
40
34
  } catch (err) {
41
35
  const fe = err;
@@ -46,8 +40,8 @@ export function useIntegrationsApi() {
46
40
  }
47
41
  return {
48
42
  baseUrl,
49
- get: (path) => request("GET", path),
50
- post: (path, body) => request("POST", path, body ?? {}),
43
+ get: (path, opts) => request("GET", path, void 0, opts),
44
+ post: (path, body, opts) => request("POST", path, body ?? {}, opts),
51
45
  put: (path, body) => request("PUT", path, body ?? {}),
52
46
  patch: (path, body) => request("PATCH", path, body ?? {}),
53
47
  del: (path) => request("DELETE", path)
@@ -0,0 +1,37 @@
1
+ /**
2
+ * useCanvasShortcuts — document-level keyboard shortcuts for the workflow
3
+ * canvas, with editing-context scoping.
4
+ *
5
+ * Modeled on n8n's useKeybindings (editor-ui/src/app/composables/useKeybindings.ts)
6
+ * but dependency-free (no @vueuse) and with the platform-neutral `mod` token.
7
+ *
8
+ * Map keys:
9
+ * - tokens joined by '+': modifiers `mod` (⌘ on mac, Ctrl elsewhere), `shift`,
10
+ * `alt`, plus one key: a single character ('a', '1', '+'), or a named key
11
+ * ('enter', 'escape', 'tab', 'space', 'f2', 'delete', 'backspace',
12
+ * 'arrowup', ...). Case-insensitive.
13
+ * - alternatives via '|': 'f2|space' fires on either.
14
+ *
15
+ * Handlers are a function or `{ disabled: () => boolean, run: fn }` — a disabled
16
+ * handler lets the event fall through untouched (no preventDefault), so e.g.
17
+ * Enter still types a newline when nothing is selected.
18
+ *
19
+ * Scoping — a keydown is IGNORED entirely when:
20
+ * 1. `options.disabled` is truthy (the editor passes "config lightbox open").
21
+ * 2. The event target (or activeElement fallback) is INPUT / TEXTAREA / SELECT,
22
+ * is contenteditable, or sits inside a [contenteditable] ancestor.
23
+ * 3. The target or an ancestor carries `data-canvas-shortcuts-ignore`.
24
+ * 4. `event.defaultPrevented` — someone upstream already claimed the key.
25
+ *
26
+ * On a match: preventDefault() + stopPropagation(), then run. Non-matching
27
+ * combos are never touched, so browser shortcuts keep working.
28
+ */
29
+ import type { MaybeRefOrGetter } from 'vue';
30
+ export type ShortcutHandler = ((event: KeyboardEvent) => void) | {
31
+ disabled: () => boolean;
32
+ run: (event: KeyboardEvent) => void;
33
+ };
34
+ export type ShortcutMap = Record<string, ShortcutHandler>;
35
+ export declare function useCanvasShortcuts(keymap: MaybeRefOrGetter<ShortcutMap>, options?: {
36
+ disabled?: MaybeRefOrGetter<boolean>;
37
+ }): void;
@@ -0,0 +1,62 @@
1
+ import { computed, onBeforeUnmount, onMounted, toValue } from "vue";
2
+ const IS_MAC = typeof navigator !== "undefined" && /Mac|iPhone|iPad/.test(navigator.platform ?? "");
3
+ function canonical(parts) {
4
+ return parts.map((p) => p.toLowerCase()).sort((a, b) => a.localeCompare(b)).join("+");
5
+ }
6
+ function normalizeShortcut(shortcut) {
7
+ if (shortcut.length === 1) return shortcut.toLowerCase();
8
+ return canonical(shortcut.split("+"));
9
+ }
10
+ function codeToKey(code) {
11
+ if (code.startsWith("Key")) return code.slice(3).toLowerCase();
12
+ if (code.startsWith("Digit")) return code.slice(5);
13
+ return code.toLowerCase();
14
+ }
15
+ function eventShortcuts(event) {
16
+ const mods = [];
17
+ if (event.shiftKey) mods.push("shift");
18
+ if (event.altKey) mods.push("alt");
19
+ if (IS_MAC ? event.metaKey : event.ctrlKey) mods.push("mod");
20
+ const key = event.key === " " ? "space" : event.key.toLowerCase();
21
+ const code = codeToKey(event.code ?? "");
22
+ return {
23
+ byKey: canonical([...mods, key]),
24
+ byCode: canonical([...mods, code])
25
+ };
26
+ }
27
+ function isEditingContext(event) {
28
+ const el = event.target instanceof Element ? event.target : document.activeElement;
29
+ if (!el) return false;
30
+ const tag = el.tagName;
31
+ if (tag === "INPUT" || tag === "TEXTAREA" || tag === "SELECT") return true;
32
+ if (el.isContentEditable) return true;
33
+ if (el.closest('[contenteditable=""],[contenteditable="true"]')) return true;
34
+ if (el.closest("[data-canvas-shortcuts-ignore]")) return true;
35
+ return false;
36
+ }
37
+ export function useCanvasShortcuts(keymap, options) {
38
+ const normalized = computed(() => {
39
+ const out = {};
40
+ for (const [combo, handler] of Object.entries(toValue(keymap))) {
41
+ for (const alt of combo.split("|")) {
42
+ out[normalizeShortcut(alt.trim())] = handler;
43
+ }
44
+ }
45
+ return out;
46
+ });
47
+ function onKeyDown(event) {
48
+ if (toValue(options?.disabled)) return;
49
+ if (event.defaultPrevented) return;
50
+ if (isEditingContext(event)) return;
51
+ const { byKey, byCode } = eventShortcuts(event);
52
+ const handler = normalized.value[byKey] ?? normalized.value[byCode];
53
+ if (!handler) return;
54
+ const run = typeof handler === "function" ? handler : handler.disabled() ? void 0 : handler.run;
55
+ if (!run) return;
56
+ event.preventDefault();
57
+ event.stopPropagation();
58
+ run(event);
59
+ }
60
+ onMounted(() => document.addEventListener("keydown", onKeyDown));
61
+ onBeforeUnmount(() => document.removeEventListener("keydown", onKeyDown));
62
+ }
@@ -1,4 +1,5 @@
1
- import { IntegrationsApiError, useIntegrationsApi } from "./integrationsApi.js";
1
+ import { useIntegrationsApi } from "./integrationsApi.js";
2
+ import { IntegrationsApiError } from "../utils/apiError.js";
2
3
  export function useCredentialTypes() {
3
4
  const types = useState("integrations.credentialTypes", () => []);
4
5
  const loading = useState("integrations.credentialTypes.loading", () => false);
@@ -1,4 +1,5 @@
1
- import { IntegrationsApiError, useIntegrationsApi } from "./integrationsApi.js";
1
+ import { useIntegrationsApi } from "./integrationsApi.js";
2
+ import { IntegrationsApiError } from "../utils/apiError.js";
2
3
  export function useIntegrationsAudit() {
3
4
  const api = useIntegrationsApi();
4
5
  const entries = useState("int.audit.entries", () => []);
@@ -1,5 +1,6 @@
1
1
  import { computed } from "vue";
2
- import { IntegrationsApiError, useIntegrationsApi } from "./integrationsApi.js";
2
+ import { useIntegrationsApi } from "./integrationsApi.js";
3
+ import { IntegrationsApiError } from "../utils/apiError.js";
3
4
  export function useIntegrationsCredentials() {
4
5
  const credentials = useState("integrations.credentials", () => []);
5
6
  const loading = useState("integrations.credentials.loading", () => false);
@@ -0,0 +1,22 @@
1
+ import type { DeadLetterRow } from '../types/integrations.js';
2
+ /** A dead letter enriched with its workflow's name (global "Missed runs" view). */
3
+ export interface GlobalDeadLetterRow extends DeadLetterRow {
4
+ workflowName: string;
5
+ }
6
+ export declare function useIntegrationsDeadLetters(): {
7
+ list: (workflowId: number | string, opts?: {
8
+ page?: number;
9
+ perPage?: number;
10
+ }) => Promise<{
11
+ items: DeadLetterRow[];
12
+ total: number;
13
+ page: number;
14
+ lastPage: number;
15
+ }>;
16
+ replay: (id: number | string) => Promise<unknown>;
17
+ discard: (id: number | string) => Promise<unknown>;
18
+ loadGlobal: (force?: boolean) => Promise<GlobalDeadLetterRow[]>;
19
+ globalItems: any;
20
+ globalLoading: any;
21
+ pendingCount: import("vue").ComputedRef<any>;
22
+ };
@@ -0,0 +1,50 @@
1
+ import { computed } from "vue";
2
+ import { useIntegrationsApi } from "./integrationsApi.js";
3
+ export function useIntegrationsDeadLetters() {
4
+ const api = useIntegrationsApi();
5
+ async function list(workflowId, opts = {}) {
6
+ const page = opts.page ?? 1;
7
+ const perPage = opts.perPage ?? 25;
8
+ const res = await api.get(
9
+ `/workflows/${workflowId}/dead-letters?page=${page}&per_page=${perPage}`
10
+ );
11
+ return {
12
+ items: res?.data ?? [],
13
+ total: res?.meta?.total ?? (res?.data?.length ?? 0),
14
+ page: res?.meta?.current_page ?? page,
15
+ lastPage: res?.meta?.last_page ?? 1
16
+ };
17
+ }
18
+ const replay = (id) => api.post(`/dead-letters/${id}/replay`, {});
19
+ const discard = (id) => api.post(`/dead-letters/${id}/discard`, {});
20
+ const { workflows, load: loadWorkflows } = useIntegrationsWorkflows();
21
+ const globalItems = useState("integrations.deadletters.global", () => []);
22
+ const globalLoading = useState("integrations.deadletters.global.loading", () => false);
23
+ const globalLoaded = useState("integrations.deadletters.global.loaded", () => false);
24
+ const pendingCount = computed(() => globalItems.value.filter((i) => i.status === "pending").length);
25
+ async function loadGlobal(force = false) {
26
+ if (globalLoading.value) return globalItems.value;
27
+ if (globalLoaded.value && !force) return globalItems.value;
28
+ globalLoading.value = true;
29
+ try {
30
+ await loadWorkflows();
31
+ const MAX_PAGES = 20;
32
+ const per = await Promise.allSettled(workflows.value.map(async (wf) => {
33
+ const out = [];
34
+ let page = 1;
35
+ while (page <= MAX_PAGES) {
36
+ const res = await list(wf.id, { page, perPage: 100 });
37
+ out.push(...res.items.map((i) => ({ ...i, workflowName: wf.name })));
38
+ if (page >= res.lastPage) break;
39
+ page++;
40
+ }
41
+ return out;
42
+ }));
43
+ globalItems.value = per.flatMap((p) => p.status === "fulfilled" ? p.value : []).sort((a, b) => new Date(b.created_at ?? 0).getTime() - new Date(a.created_at ?? 0).getTime());
44
+ globalLoaded.value = true;
45
+ } finally {
46
+ globalLoading.value = false;
47
+ }
48
+ }
49
+ return { list, replay, discard, loadGlobal, globalItems, globalLoading, pendingCount };
50
+ }
@@ -1,6 +1,10 @@
1
+ import { findManifest } from '../data/integrationNodeCatalog.js';
2
+ import { resolveLocalized } from '../utils/localize.js';
1
3
  export declare function useIntegrationsNodes(): {
2
4
  loading: any;
3
5
  error: any;
4
6
  loaded: any;
5
7
  load: (force?: boolean) => Promise<void>;
8
+ findManifest: typeof findManifest;
9
+ resolveLocalized: typeof resolveLocalized;
6
10
  };
@@ -1,5 +1,7 @@
1
- import { applyNodeCatalog } from "../data/integrationNodeCatalog.js";
2
- import { IntegrationsApiError, useIntegrationsApi } from "./integrationsApi.js";
1
+ import { applyNodeCatalog, findManifest } from "../data/integrationNodeCatalog.js";
2
+ import { resolveLocalized } from "../utils/localize.js";
3
+ import { useIntegrationsApi } from "./integrationsApi.js";
4
+ import { IntegrationsApiError } from "../utils/apiError.js";
3
5
  export function useIntegrationsNodes() {
4
6
  const loading = useState("integrations.nodes.loading", () => false);
5
7
  const error = useState("integrations.nodes.error", () => null);
@@ -17,7 +19,9 @@ export function useIntegrationsNodes() {
17
19
  ...n.manifest,
18
20
  slug: n.manifest.slug ?? n.slug,
19
21
  version: n.manifest.version ?? n.version,
20
- name: n.manifest.name ?? n.name
22
+ name: n.manifest.name ?? n.name,
23
+ // Keep the source package — the palette groups app nodes by it.
24
+ __package: n.package ? { name: n.package.name, label: n.package.label ?? null } : void 0
21
25
  }));
22
26
  applyNodeCatalog(manifests);
23
27
  loaded.value = true;
@@ -28,5 +32,5 @@ export function useIntegrationsNodes() {
28
32
  loading.value = false;
29
33
  }
30
34
  }
31
- return { loading, error, loaded, load };
35
+ return { loading, error, loaded, load, findManifest, resolveLocalized };
32
36
  }
@@ -0,0 +1,40 @@
1
+ import type { WorkflowBlob } from '../types/integrations.js';
2
+ /**
3
+ * Workflow revision history (PO — `workflow_histories`): every blob-changing
4
+ * save snapshots the previous revision. These endpoints expose that history
5
+ * and restore an archived revision as a brand-new one.
6
+ *
7
+ * GET /workflows/{id}/revisions → metadata list (paginated, newest first)
8
+ * GET /workflows/{id}/revisions/{rev} → full snapshot incl. blob + triggers
9
+ * POST /workflows/{id}/revisions/{rev}/restore
10
+ */
11
+ export interface WorkflowRevisionMeta {
12
+ id: number;
13
+ revision: number;
14
+ name: string;
15
+ description: string | null;
16
+ active: boolean;
17
+ blob_definition_version: string;
18
+ created_at: string | null;
19
+ updated_at: string | null;
20
+ archived_at: string | null;
21
+ }
22
+ export interface WorkflowRevisionDetail extends WorkflowRevisionMeta {
23
+ /** Cockpit-shaped blob: triggers merged in, like useIntegrationsWorkflows.toCockpit. */
24
+ blob: WorkflowBlob;
25
+ }
26
+ export declare function useIntegrationsRevisions(): {
27
+ loading: import("vue").Ref<boolean, boolean>;
28
+ error: import("vue").Ref<string | null, string | null>;
29
+ list: (workflowId: number, page?: number, perPage?: number) => Promise<{
30
+ revisions: WorkflowRevisionMeta[];
31
+ meta: {
32
+ current_page: number;
33
+ per_page: number;
34
+ total: number;
35
+ last_page: number;
36
+ };
37
+ }>;
38
+ get: (workflowId: number, revision: number) => Promise<WorkflowRevisionDetail>;
39
+ restore: (workflowId: number, revision: number) => Promise<void>;
40
+ };
@@ -0,0 +1,52 @@
1
+ import { ref } from "vue";
2
+ import { useIntegrationsApi } from "./integrationsApi.js";
3
+ import { IntegrationsApiError } from "../utils/apiError.js";
4
+ export function useIntegrationsRevisions() {
5
+ const api = useIntegrationsApi();
6
+ const loading = ref(false);
7
+ const error = ref(null);
8
+ function captureError(e, fallback) {
9
+ if (e instanceof IntegrationsApiError) return e.message;
10
+ return e?.message ?? fallback;
11
+ }
12
+ async function list(workflowId, page = 1, perPage = 25) {
13
+ loading.value = true;
14
+ error.value = null;
15
+ try {
16
+ const res = await api.get(`/workflows/${workflowId}/revisions?page=${page}&per_page=${perPage}`);
17
+ return { revisions: res.data ?? [], meta: res.meta };
18
+ } catch (e) {
19
+ error.value = captureError(e, "Could not load the revision history.");
20
+ throw e;
21
+ } finally {
22
+ loading.value = false;
23
+ }
24
+ }
25
+ async function get(workflowId, revision) {
26
+ const res = await api.get(`/workflows/${workflowId}/revisions/${revision}`);
27
+ const apiBlob = res.blob ?? {};
28
+ const triggers = (res.triggers ?? []).map((t) => ({
29
+ id: t.handle ?? String(t.id ?? ""),
30
+ type: t.type,
31
+ name: typeof t.name === "string" ? t.name : t.name ?? void 0,
32
+ active: t.active,
33
+ config: t.config ?? {}
34
+ }));
35
+ return {
36
+ ...res,
37
+ blob: {
38
+ nodeManifestVersion: apiBlob.nodeManifestVersion ?? "v0-draft",
39
+ name: apiBlob.name ?? res.name,
40
+ nodes: apiBlob.nodes ?? [],
41
+ edges: apiBlob.edges ?? [],
42
+ triggerPositions: apiBlob.triggerPositions ?? {},
43
+ stickies: apiBlob.stickies ?? [],
44
+ triggers
45
+ }
46
+ };
47
+ }
48
+ async function restore(workflowId, revision) {
49
+ await api.post(`/workflows/${workflowId}/revisions/${revision}/restore`, {});
50
+ }
51
+ return { loading, error, list, get, restore };
52
+ }
@@ -1,4 +1,4 @@
1
- import type { RunStatus, WorkflowRun } from '../types/integrations.js';
1
+ import type { RunStatus, RunStepRow, WorkflowRun } from '../types/integrations.js';
2
2
  export declare function useIntegrationsRuns(): {
3
3
  runs: any;
4
4
  loading: any;
@@ -8,17 +8,37 @@ export declare function useIntegrationsRuns(): {
8
8
  failedCount: import("vue").ComputedRef<any>;
9
9
  runningCount: import("vue").ComputedRef<any>;
10
10
  load: (force?: boolean) => Promise<WorkflowRun[]>;
11
+ loadForWorkflow: (workflowId: number, workflowName: string, opts?: {
12
+ reconcile?: boolean;
13
+ page?: number;
14
+ perPage?: number;
15
+ }) => Promise<{
16
+ runs: WorkflowRun[];
17
+ total: number;
18
+ page: number;
19
+ lastPage: number;
20
+ }>;
11
21
  list: (filter?: {
12
22
  workflowId?: number;
13
23
  status?: RunStatus;
14
24
  }) => WorkflowRun[];
15
25
  get: (id: string) => WorkflowRun | null;
26
+ fetchRun: (workflowId: number | string, runId: number | string, workflowName: string) => Promise<WorkflowRun>;
16
27
  trigger: (workflowId: number | string, payload?: Record<string, unknown>, mode?: "sync" | "async") => Promise<unknown>;
28
+ cancelRun: (workflowId: number | string, runId: number | string, reason?: string) => Promise<unknown>;
29
+ terminateRun: (workflowId: number | string, runId: number | string, reason?: string) => Promise<unknown>;
30
+ retryRun: (workflowId: number | string, runId: number | string) => Promise<unknown>;
31
+ resumeRun: (workflowId: number | string, runId: number | string, reason?: string) => Promise<unknown>;
17
32
  getRun: (workflowId: number | string, runId: number | string) => Promise<unknown>;
18
33
  getDetails: (workflowId: number | string, runId: number | string) => Promise<{
19
34
  source: string;
20
35
  data: Record<string, unknown>;
21
36
  }>;
37
+ getSteps: (workflowId: number | string, runId: number | string, includePayloads?: boolean) => Promise<{
38
+ source: string;
39
+ run: Record<string, unknown>;
40
+ steps: RunStepRow[];
41
+ }>;
22
42
  getHistory: (workflowId: number | string, runId: number | string, params?: {
23
43
  page_token?: string;
24
44
  page_size?: number;
@@ -1,5 +1,6 @@
1
1
  import { computed } from "vue";
2
- import { IntegrationsApiError, useIntegrationsApi } from "./integrationsApi.js";
2
+ import { useIntegrationsApi } from "./integrationsApi.js";
3
+ import { IntegrationsApiError } from "../utils/apiError.js";
3
4
  function mapStatus(status) {
4
5
  switch (status) {
5
6
  case "completed":
@@ -8,14 +9,18 @@ function mapStatus(status) {
8
9
  return "queued";
9
10
  case "terminated":
10
11
  return "failed";
12
+ case "timed_out":
13
+ return "failed";
11
14
  case "running":
12
15
  return "running";
13
16
  case "failed":
14
17
  return "failed";
15
18
  case "cancelled":
16
19
  return "cancelled";
20
+ // An unknown/unexpected status must never surface as a stuck `running` —
21
+ // fail closed so a run the backend can't classify is visibly terminal.
17
22
  default:
18
- return "running";
23
+ return "failed";
19
24
  }
20
25
  }
21
26
  export function useIntegrationsRuns() {
@@ -23,19 +28,25 @@ export function useIntegrationsRuns() {
23
28
  const loading = useState("integrations.runs.loading", () => false);
24
29
  const error = useState("integrations.runs.error", () => null);
25
30
  const loaded = useState("integrations.runs.loaded", () => false);
31
+ const reconciling = useState("integrations.runs.reconciling", () => false);
32
+ const SYNC_LIMIT = 5;
26
33
  const api = useIntegrationsApi();
27
34
  const { workflows, load: loadWorkflows } = useIntegrationsWorkflows();
28
35
  function mapRun(r, workflowName) {
36
+ const startedMs = r.started_at ? new Date(r.started_at).getTime() : null;
37
+ const finishedMs = r.completed_at ? new Date(r.completed_at).getTime() : null;
29
38
  return {
30
39
  id: String(r.id),
31
40
  workflowId: r.workflow_id,
32
41
  workflowName,
33
42
  status: mapStatus(r.status),
43
+ temporalRunId: r.temporal_run_id ?? null,
34
44
  triggerId: "",
35
45
  triggerType: "manual",
36
46
  startedAt: r.started_at ?? "",
37
47
  finishedAt: r.completed_at ?? null,
38
- durationMs: null,
48
+ // Derived from the timestamps — the list payload carries no duration.
49
+ durationMs: startedMs != null && finishedMs != null && finishedMs >= startedMs ? finishedMs - startedMs : null,
39
50
  steps: []
40
51
  };
41
52
  }
@@ -46,13 +57,41 @@ export function useIntegrationsRuns() {
46
57
  error.value = null;
47
58
  try {
48
59
  await loadWorkflows();
60
+ const MAX_PAGES = 100;
49
61
  const perWorkflow = await Promise.allSettled(
50
62
  workflows.value.map(async (wf) => {
51
- const res = await api.get(`/workflows/${wf.id}/runs`);
52
- return (res?.data ?? []).map((r) => mapRun(r, wf.name));
63
+ const out = [];
64
+ let page = 1;
65
+ while (page <= MAX_PAGES) {
66
+ const res = await api.get(
67
+ `/workflows/${wf.id}/runs?page=${page}&per_page=100`
68
+ );
69
+ out.push(...(res?.data ?? []).map((r) => mapRun(r, wf.name)));
70
+ const last = res?.meta?.last_page ?? 1;
71
+ if (page >= last) break;
72
+ page++;
73
+ }
74
+ return out;
53
75
  })
54
76
  );
55
77
  runs.value = perWorkflow.flatMap((p) => p.status === "fulfilled" ? p.value : []).sort((a, b) => new Date(b.startedAt).getTime() - new Date(a.startedAt).getTime());
78
+ if (!reconciling.value) {
79
+ reconciling.value = true;
80
+ try {
81
+ const active = runs.value.filter((r) => r.status === "running" || r.status === "queued").sort((a, b) => Number(b.id) - Number(a.id)).slice(0, SYNC_LIMIT);
82
+ await Promise.allSettled(active.map(async (r) => {
83
+ try {
84
+ const raw = await api.get(`/workflows/${r.workflowId}/runs/${r.id}`);
85
+ const apiRun = raw?.data ?? raw;
86
+ const fresh = mapRun(apiRun, r.workflowName);
87
+ runs.value = runs.value.map((x) => x.id === fresh.id ? fresh : x);
88
+ } catch {
89
+ }
90
+ }));
91
+ } finally {
92
+ reconciling.value = false;
93
+ }
94
+ }
56
95
  loaded.value = true;
57
96
  } catch (e) {
58
97
  error.value = e instanceof IntegrationsApiError ? e.message : e?.message ?? "Could not load runs.";
@@ -61,6 +100,32 @@ export function useIntegrationsRuns() {
61
100
  }
62
101
  return runs.value;
63
102
  }
103
+ async function loadForWorkflow(workflowId, workflowName, opts = {}) {
104
+ const page = opts.page ?? 1;
105
+ const perPage = opts.perPage ?? 25;
106
+ const res = await api.get(
107
+ `/workflows/${workflowId}/runs?page=${page}&per_page=${perPage}`
108
+ );
109
+ let list2 = (res?.data ?? []).map((r) => mapRun(r, workflowName)).sort((a, b) => new Date(b.startedAt).getTime() - new Date(a.startedAt).getTime());
110
+ if (opts.reconcile) {
111
+ const active = list2.filter((r) => r.status === "running" || r.status === "queued").sort((a, b) => Number(b.id) - Number(a.id)).slice(0, SYNC_LIMIT);
112
+ await Promise.allSettled(active.map(async (r) => {
113
+ try {
114
+ const raw = await api.get(`/workflows/${workflowId}/runs/${r.id}`);
115
+ const apiRun = raw?.data ?? raw;
116
+ const fresh = mapRun(apiRun, workflowName);
117
+ list2 = list2.map((x) => x.id === fresh.id ? fresh : x);
118
+ } catch {
119
+ }
120
+ }));
121
+ }
122
+ return {
123
+ runs: list2,
124
+ total: res?.meta?.total ?? list2.length,
125
+ page: res?.meta?.current_page ?? page,
126
+ lastPage: res?.meta?.last_page ?? 1
127
+ };
128
+ }
64
129
  function list(filter) {
65
130
  let result = [...runs.value];
66
131
  if (filter?.workflowId !== void 0) result = result.filter((r) => r.workflowId === filter.workflowId);
@@ -76,8 +141,25 @@ export function useIntegrationsRuns() {
76
141
  const res = await api.post(`/workflows/${workflowId}/runs`, body);
77
142
  return res?.data ?? res;
78
143
  }
144
+ async function runAction(workflowId, runId, action, reason) {
145
+ const body = reason ? { reason } : {};
146
+ const res = await api.post(`/workflows/${workflowId}/runs/${runId}/${action}`, body);
147
+ return res?.data ?? res;
148
+ }
149
+ const cancelRun = (workflowId, runId, reason) => runAction(workflowId, runId, "cancel", reason);
150
+ const terminateRun = (workflowId, runId, reason) => runAction(workflowId, runId, "terminate", reason);
151
+ const retryRun = (workflowId, runId) => runAction(workflowId, runId, "retry");
152
+ const resumeRun = (workflowId, runId, reason) => runAction(workflowId, runId, "resume", reason);
79
153
  const getRun = (workflowId, runId) => api.get(`/workflows/${workflowId}/runs/${runId}`);
154
+ async function fetchRun(workflowId, runId, workflowName) {
155
+ const raw = await getRun(workflowId, runId);
156
+ const apiRun = raw?.data ?? raw;
157
+ return mapRun(apiRun, workflowName);
158
+ }
80
159
  const getDetails = (workflowId, runId) => api.get(`/workflows/${workflowId}/runs/${runId}/details`);
160
+ const getSteps = (workflowId, runId, includePayloads = false) => api.get(
161
+ `/workflows/${workflowId}/runs/${runId}/steps${includePayloads ? "?include_payloads=1" : ""}`
162
+ );
81
163
  const getHistory = (workflowId, runId, params = {}) => {
82
164
  const qs = new URLSearchParams();
83
165
  if (params.page_token) qs.set("page_token", params.page_token);
@@ -98,11 +180,18 @@ export function useIntegrationsRuns() {
98
180
  failedCount,
99
181
  runningCount,
100
182
  load,
183
+ loadForWorkflow,
101
184
  list,
102
185
  get,
186
+ fetchRun,
103
187
  trigger,
188
+ cancelRun,
189
+ terminateRun,
190
+ retryRun,
191
+ resumeRun,
104
192
  getRun,
105
193
  getDetails,
194
+ getSteps,
106
195
  getHistory,
107
196
  getStackTrace
108
197
  };
@@ -1,5 +1,6 @@
1
1
  import { computed } from "vue";
2
- import { IntegrationsApiError, useIntegrationsApi } from "./integrationsApi.js";
2
+ import { useIntegrationsApi } from "./integrationsApi.js";
3
+ import { IntegrationsApiError } from "../utils/apiError.js";
3
4
  const KEY_PATTERN = /^[A-Z0-9_]+$/;
4
5
  export function useIntegrationsSecrets() {
5
6
  const secrets = useState("integrations.secrets", () => []);
@@ -10,6 +10,7 @@ export declare function useIntegrationsTemplates(): {
10
10
  list: () => WorkflowTemplate[];
11
11
  get: (slug: string) => WorkflowTemplate | null;
12
12
  fetchDetail: (slug: string) => Promise<WorkflowTemplate | null>;
13
+ ensureDetails: (slugs: string[], concurrency?: number) => Promise<void>;
13
14
  requirements: (slug: string) => Promise<TemplateRequirements | null>;
14
15
  instantiate: (slug: string, opts?: {
15
16
  name?: string;