@revenexx/studio-integrations 3.7.1 → 3.8.1

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 (41) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/dist/module.json +1 -1
  3. package/dist/runtime/components/Integrations/CredentialCreateDialog.vue +3 -1
  4. package/dist/runtime/components/Integrations/DeadLettersPanel.vue +2 -1
  5. package/dist/runtime/components/Integrations/GroupFrameView.vue +17 -6
  6. package/dist/runtime/components/Integrations/NodeConfigDynamicField.vue +37 -17
  7. package/dist/runtime/components/Integrations/NodeConfigDynamicSchema.d.vue.ts +2 -0
  8. package/dist/runtime/components/Integrations/NodeConfigDynamicSchema.vue +5 -2
  9. package/dist/runtime/components/Integrations/NodeConfigDynamicSchema.vue.d.ts +2 -0
  10. package/dist/runtime/components/Integrations/NodeConfigField.vue +1 -0
  11. package/dist/runtime/components/Integrations/RunResponseModal.d.vue.ts +6 -0
  12. package/dist/runtime/components/Integrations/RunResponseModal.vue +36 -5
  13. package/dist/runtime/components/Integrations/RunResponseModal.vue.d.ts +6 -0
  14. package/dist/runtime/components/Integrations/Sidebar.vue +22 -5
  15. package/dist/runtime/components/Integrations/StickyNoteView.vue +22 -9
  16. package/dist/runtime/components/Integrations/TemplateFlowPreview.vue +3 -3
  17. package/dist/runtime/components/Integrations/WorkflowEdgeView.vue +3 -2
  18. package/dist/runtime/components/Integrations/WorkflowEditor.vue +32 -27
  19. package/dist/runtime/components/Integrations/WorkflowTriggerView.vue +1 -1
  20. package/dist/runtime/components/Integrations/WorkflowsTable.vue +9 -14
  21. package/dist/runtime/composables/useCanvasTarget.d.ts +15 -0
  22. package/dist/runtime/composables/useCanvasTarget.js +10 -0
  23. package/dist/runtime/composables/useIntegrationsSummary.d.ts +29 -0
  24. package/dist/runtime/composables/useIntegrationsSummary.js +37 -0
  25. package/dist/runtime/composables/useNodeConfigResolve.d.ts +25 -2
  26. package/dist/runtime/composables/useNodeConfigResolve.js +11 -2
  27. package/dist/runtime/composables/useOAuthConnect.d.ts +5 -0
  28. package/dist/runtime/composables/useOAuthConnect.js +3 -1
  29. package/dist/runtime/i18n/messages/de.json +4 -3
  30. package/dist/runtime/i18n/messages/en.json +4 -3
  31. package/dist/runtime/pages/integrations/runs.vue +2 -1
  32. package/dist/runtime/pages/integrations/workflows/[id].vue +39 -2
  33. package/dist/runtime/utils/canvasFit.d.ts +59 -0
  34. package/dist/runtime/utils/canvasFit.js +78 -0
  35. package/dist/runtime/utils/executionMode.d.ts +18 -0
  36. package/dist/runtime/utils/executionMode.js +17 -0
  37. package/dist/runtime/utils/optionSearch.d.ts +24 -0
  38. package/dist/runtime/utils/optionSearch.js +31 -0
  39. package/dist/runtime/utils/runFailure.d.ts +37 -0
  40. package/dist/runtime/utils/runFailure.js +16 -0
  41. package/package.json +1 -1
@@ -0,0 +1,78 @@
1
+ const PADDING = 0.2;
2
+ const MIN_SIDE = 160;
3
+ function width(b) {
4
+ return b.right - b.left;
5
+ }
6
+ function height(b) {
7
+ return b.bottom - b.top;
8
+ }
9
+ function overlaps(a, b) {
10
+ return a.left < b.right && b.left < a.right && a.top < b.bottom && b.top < a.bottom;
11
+ }
12
+ function contains(outer, inner) {
13
+ return outer.left <= inner.left && outer.top <= inner.top && outer.right >= inner.right && outer.bottom >= inner.bottom;
14
+ }
15
+ function sidePadding(length) {
16
+ return Math.floor((length - length / (1 + PADDING)) * 0.5);
17
+ }
18
+ export function freeRectangles(canvas, panels) {
19
+ let free = [canvas];
20
+ for (const raw of panels) {
21
+ const panel = {
22
+ left: Math.max(raw.left, canvas.left),
23
+ top: Math.max(raw.top, canvas.top),
24
+ right: Math.min(raw.right, canvas.right),
25
+ bottom: Math.min(raw.bottom, canvas.bottom)
26
+ };
27
+ if (width(panel) <= 0 || height(panel) <= 0) continue;
28
+ const next = [];
29
+ for (const r of free) {
30
+ if (!overlaps(r, panel)) {
31
+ next.push(r);
32
+ continue;
33
+ }
34
+ if (panel.left > r.left) next.push({ ...r, right: panel.left });
35
+ if (panel.right < r.right) next.push({ ...r, left: panel.right });
36
+ if (panel.top > r.top) next.push({ ...r, bottom: panel.top });
37
+ if (panel.bottom < r.bottom) next.push({ ...r, top: panel.bottom });
38
+ }
39
+ free = next.filter((r, i) => !next.some((o, j) => j !== i && contains(o, r) && (!contains(r, o) || j < i)));
40
+ }
41
+ return free;
42
+ }
43
+ function zoomInto(area, drawing, minZoom, maxZoom) {
44
+ const w = width(area) - 2 * sidePadding(width(area));
45
+ const h = height(area) - 2 * sidePadding(height(area));
46
+ const zoom = Math.min(w / Math.max(drawing.width, 1), h / Math.max(drawing.height, 1));
47
+ return Math.min(maxZoom, Math.max(minZoom, zoom));
48
+ }
49
+ const CENTRAL_SHARE = 0.75;
50
+ export function fitArea(canvas, panels, drawing, minZoom, maxZoom) {
51
+ const free = freeRectangles(canvas, panels).filter((r) => width(r) > 0 && height(r) > 0);
52
+ const roomy = free.filter((r) => width(r) >= MIN_SIDE && height(r) >= MIN_SIDE);
53
+ const usable = roomy.length ? roomy : free;
54
+ if (!usable.length) return canvas;
55
+ const zooms = usable.map((r) => zoomInto(r, drawing, minZoom, maxZoom));
56
+ const floor = Math.max(...zooms) * CENTRAL_SHARE - 1e-6;
57
+ const cx = (canvas.left + canvas.right) / 2;
58
+ const cy = (canvas.top + canvas.bottom) / 2;
59
+ const offCentre = (r) => Math.hypot((r.left + r.right) / 2 - cx, (r.top + r.bottom) / 2 - cy);
60
+ let best = null;
61
+ for (const [i, r] of usable.entries()) {
62
+ if (zooms[i] < floor) continue;
63
+ if (best === null || offCentre(r) < offCentre(best) - 1e-6 || Math.abs(offCentre(r) - offCentre(best)) <= 1e-6 && width(r) * height(r) > width(best) * height(best)) {
64
+ best = r;
65
+ }
66
+ }
67
+ return best ?? canvas;
68
+ }
69
+ export function paddingFor(canvas, area) {
70
+ const padX = sidePadding(width(area));
71
+ const padY = sidePadding(height(area));
72
+ return {
73
+ top: `${area.top - canvas.top + padY}px`,
74
+ right: `${canvas.right - area.right + padX}px`,
75
+ bottom: `${canvas.bottom - area.bottom + padY}px`,
76
+ left: `${area.left - canvas.left + padX}px`
77
+ };
78
+ }
@@ -0,0 +1,18 @@
1
+ import type { WorkflowExecutionMode } from '../types/integrations.js';
2
+ /**
3
+ * The message key that names an execution mode in a compact badge (PO-615).
4
+ *
5
+ * Two surfaces say it: the Mode column of the workflows list and the badge beside
6
+ * the name in a workflow's header. They used to read two sets of keys, and so the
7
+ * list wrote "ASYNC" where the header wrote "Asynchron" for the same workflow. One
8
+ * function keeps the word in one place — the lesson `triggerTypeLabel` was written
9
+ * on. Caller decides has no shorter form than its choice label, so both surfaces
10
+ * use that.
11
+ *
12
+ * A mode the studio does not know yet — or none at all — has no key: the caller
13
+ * decides what an unknown mode reads as, because the list shows a dash where the
14
+ * header falls back to the default mode.
15
+ */
16
+ export declare function executionModeLabelKey(mode: WorkflowExecutionMode | string | null | undefined): string | null;
17
+ /** The short word for an execution mode in the reader's language, or `fallback` for one without a key. */
18
+ export declare function executionModeLabel(mode: WorkflowExecutionMode | string | null | undefined, fallback?: string): string;
@@ -0,0 +1,17 @@
1
+ import { useIntegrationsT } from "../composables/useIntegrationsT.js";
2
+ export function executionModeLabelKey(mode) {
3
+ switch (mode) {
4
+ case "async_only":
5
+ return "integration.editor.executionMode.async.short";
6
+ case "sync_only":
7
+ return "integration.editor.executionMode.sync.short";
8
+ case "caller_decides":
9
+ return "integration.editor.executionMode.callerDecides.label";
10
+ default:
11
+ return null;
12
+ }
13
+ }
14
+ export function executionModeLabel(mode, fallback = "\u2014") {
15
+ const key = executionModeLabelKey(mode);
16
+ return key ? useIntegrationsT()(key) : fallback;
17
+ }
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Narrowing a list of options to what an operator typed, and ordering what is
3
+ * left by how well it matches (PO-650).
4
+ *
5
+ * An option has a label the operator reads and a value the platform stores —
6
+ * often a code (`EN-US`, `DE`). A term is first a guess at the start of one of
7
+ * them, and only after that something the label merely contains: "EN" is meant
8
+ * as English, not as the middle of "Armenisch". So the order is
9
+ *
10
+ * 1. the value starts with the term,
11
+ * 2. the label starts with it,
12
+ * 3. a word of the label starts with it,
13
+ * 4. the label or the value contains it,
14
+ * 5. every word of it is in the label, in any order ("Roth Carl"),
15
+ *
16
+ * and an option that matches none of them is not offered. Within a rank the
17
+ * options keep the order they came in, which is the order the platform chose.
18
+ */
19
+ /**
20
+ * The options that match `term`, best match first. An empty term (or one of
21
+ * blanks) leaves the list as it is; a term nothing matches leaves it empty —
22
+ * never the whole list, which is what an operator would read as "matches".
23
+ */
24
+ export declare function narrowOptions<T>(options: readonly T[], term: string, labelOf: (option: T) => string, valueOf: (option: T) => string): T[];
@@ -0,0 +1,31 @@
1
+ var Rank = /* @__PURE__ */ ((Rank2) => {
2
+ Rank2[Rank2["ValuePrefix"] = 0] = "ValuePrefix";
3
+ Rank2[Rank2["LabelPrefix"] = 1] = "LabelPrefix";
4
+ Rank2[Rank2["WordPrefix"] = 2] = "WordPrefix";
5
+ Rank2[Rank2["Contains"] = 3] = "Contains";
6
+ Rank2[Rank2["AllWords"] = 4] = "AllWords";
7
+ return Rank2;
8
+ })(Rank || {});
9
+ function words(label) {
10
+ return label.split(/[^\p{L}\p{N}]+/u).filter(Boolean);
11
+ }
12
+ function rankOf(label, value, term) {
13
+ if (value.startsWith(term)) return 0 /* ValuePrefix */;
14
+ if (label.startsWith(term)) return 1 /* LabelPrefix */;
15
+ if (words(label).some((word) => word.startsWith(term))) return 2 /* WordPrefix */;
16
+ if (label.includes(term) || value.includes(term)) return 3 /* Contains */;
17
+ const termWords = words(term);
18
+ if (termWords.length > 1 && termWords.every((word) => label.includes(word))) return 4 /* AllWords */;
19
+ return void 0;
20
+ }
21
+ export function narrowOptions(options, term, labelOf, valueOf) {
22
+ const needle = term.trim().toLocaleLowerCase();
23
+ if (!needle) return [...options];
24
+ const ranked = [];
25
+ options.forEach((option, index) => {
26
+ const rank = rankOf(labelOf(option).toLocaleLowerCase(), valueOf(option).toLocaleLowerCase(), needle);
27
+ if (rank !== void 0) ranked.push({ option, rank, index });
28
+ });
29
+ ranked.sort((a, b) => a.rank - b.rank || a.index - b.index);
30
+ return ranked.map((r) => r.option);
31
+ }
@@ -0,0 +1,37 @@
1
+ import type { RunStepRow } from '../types/integrations.js';
2
+ /**
3
+ * Why a run failed, in the two parts an author reads it by (PO-690): the step
4
+ * it failed at, named the way the canvas names it, and the cause in the step's
5
+ * own words.
6
+ *
7
+ * Either may be missing. The step is unknown until the run's steps have been read,
8
+ * and stays unknown where they cannot be; the cause then falls back to what the run
9
+ * itself recorded, which is less precise but is still the platform's reason.
10
+ */
11
+ export interface RunFailure {
12
+ step: string | null;
13
+ cause: string | null;
14
+ }
15
+ /** A node as the blob carries it, enough to look a step's node up by id and name it. */
16
+ export interface FailureNode {
17
+ id: string;
18
+ name?: unknown;
19
+ nodeSlug: string;
20
+ nodeVersion?: string;
21
+ }
22
+ /** Whether a run, as the platform reports it, ended in failure. */
23
+ export declare function isFailedRun(run: {
24
+ status?: unknown;
25
+ } | null | undefined): boolean;
26
+ /** A reason that is text with something in it, or nothing. */
27
+ export declare function reasonText(value: unknown): string | null;
28
+ /**
29
+ * The failure read off a run's steps, with `fallbackCause` where no step says why.
30
+ *
31
+ * The LAST failed row is the one taken: a step retried by the engine leaves a row
32
+ * per attempt, and the final one is the failure that ended the run. A failed step
33
+ * is named after its node on the canvas; a node no longer on the canvas — the run
34
+ * is of a saved version since edited — is named the way the catalogue names its
35
+ * kind, never by the generated id.
36
+ */
37
+ export declare function runFailureFromSteps(steps: readonly RunStepRow[] | null | undefined, nodes: readonly FailureNode[], fallbackCause: string | null): RunFailure;
@@ -0,0 +1,16 @@
1
+ import { nodeDisplayName } from "./nodeDisplayName.js";
2
+ import { stepError } from "./stepError.js";
3
+ const FAILED_RUN = /* @__PURE__ */ new Set(["failed", "terminated", "timed_out"]);
4
+ export function isFailedRun(run) {
5
+ return FAILED_RUN.has(String(run?.status ?? "").toLowerCase());
6
+ }
7
+ export function reasonText(value) {
8
+ return typeof value === "string" && value.trim() !== "" ? value.trim() : null;
9
+ }
10
+ export function runFailureFromSteps(steps, nodes, fallbackCause) {
11
+ const failed = [...steps ?? []].reverse().find((s) => String(s.status).toLowerCase() === "failed");
12
+ if (!failed) return { step: null, cause: fallbackCause };
13
+ const node = nodes.find((n) => n.id === failed.node_id);
14
+ const step = node ? nodeDisplayName(node) : nodeDisplayName({ nodeSlug: failed.node_slug });
15
+ return { step, cause: stepError(failed.error)?.message ?? fallbackCause };
16
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@revenexx/studio-integrations",
3
- "version": "3.7.1",
3
+ "version": "3.8.1",
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
6
  "repository": {