@revenexx/studio-integrations 0.7.0 → 1.1.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 (88) hide show
  1. package/CHANGELOG.md +633 -0
  2. package/dist/module.json +1 -1
  3. package/dist/module.mjs +2 -1
  4. package/dist/runtime/components/Integrations/CredentialCreateDialog.vue +4 -1
  5. package/dist/runtime/components/Integrations/CredentialDetailDialog.vue +8 -2
  6. package/dist/runtime/components/Integrations/DeadLettersPanel.vue +2 -6
  7. package/dist/runtime/components/Integrations/ExpressionInput.vue +5 -0
  8. package/dist/runtime/components/Integrations/NodeConfigDynamicField.d.vue.ts +3 -0
  9. package/dist/runtime/components/Integrations/NodeConfigDynamicField.vue +16 -3
  10. package/dist/runtime/components/Integrations/NodeConfigDynamicField.vue.d.ts +3 -0
  11. package/dist/runtime/components/Integrations/NodeConfigDynamicSchema.vue +1 -0
  12. package/dist/runtime/components/Integrations/NodeConfigField.d.vue.ts +3 -0
  13. package/dist/runtime/components/Integrations/NodeConfigField.vue +2 -0
  14. package/dist/runtime/components/Integrations/NodeConfigField.vue.d.ts +3 -0
  15. package/dist/runtime/components/Integrations/NodeInspector.d.vue.ts +2 -2
  16. package/dist/runtime/components/Integrations/NodeInspector.vue +135 -10
  17. package/dist/runtime/components/Integrations/NodeInspector.vue.d.ts +2 -2
  18. package/dist/runtime/components/Integrations/NodeOutputSchema.d.vue.ts +2 -1
  19. package/dist/runtime/components/Integrations/NodeOutputSchema.vue +34 -8
  20. package/dist/runtime/components/Integrations/NodeOutputSchema.vue.d.ts +2 -1
  21. package/dist/runtime/components/Integrations/NodePalette.vue +12 -8
  22. package/dist/runtime/components/Integrations/RunDetailPanel.vue +9 -6
  23. package/dist/runtime/components/Integrations/RunsTable.vue +2 -2
  24. package/dist/runtime/components/Integrations/StickyNoteView.vue +45 -11
  25. package/dist/runtime/components/Integrations/SurfaceCard.d.vue.ts +50 -0
  26. package/dist/runtime/components/Integrations/SurfaceCard.vue +55 -0
  27. package/dist/runtime/components/Integrations/SurfaceCard.vue.d.ts +50 -0
  28. package/dist/runtime/components/Integrations/TemplateCard.vue +3 -3
  29. package/dist/runtime/components/Integrations/TemplateFlowPreview.vue +12 -3
  30. package/dist/runtime/components/Integrations/WorkflowCreateDialog.vue +5 -4
  31. package/dist/runtime/components/Integrations/WorkflowEditor.d.vue.ts +16 -0
  32. package/dist/runtime/components/Integrations/WorkflowEditor.vue +79 -12
  33. package/dist/runtime/components/Integrations/WorkflowEditor.vue.d.ts +16 -0
  34. package/dist/runtime/components/Integrations/WorkflowHistoryPanel.d.vue.ts +6 -0
  35. package/dist/runtime/components/Integrations/WorkflowHistoryPanel.vue +13 -3
  36. package/dist/runtime/components/Integrations/WorkflowHistoryPanel.vue.d.ts +6 -0
  37. package/dist/runtime/components/Integrations/WorkflowNodeView.d.vue.ts +13 -0
  38. package/dist/runtime/components/Integrations/WorkflowNodeView.vue +95 -29
  39. package/dist/runtime/components/Integrations/WorkflowNodeView.vue.d.ts +13 -0
  40. package/dist/runtime/components/Integrations/WorkflowRunReplayPanel.vue +11 -10
  41. package/dist/runtime/components/Integrations/WorkflowSettingsDialog.d.vue.ts +16 -17
  42. package/dist/runtime/components/Integrations/WorkflowSettingsDialog.vue +37 -26
  43. package/dist/runtime/components/Integrations/WorkflowSettingsDialog.vue.d.ts +16 -17
  44. package/dist/runtime/components/Integrations/WorkflowTriggerView.vue +4 -5
  45. package/dist/runtime/components/Integrations/WorkflowVariablesDialog.vue +53 -14
  46. package/dist/runtime/components/Integrations/WorkflowsTable.vue +9 -4
  47. package/dist/runtime/composables/useIntegrationsCredentials.d.ts +11 -0
  48. package/dist/runtime/composables/useIntegrationsCredentials.js +2 -2
  49. package/dist/runtime/composables/useIntegrationsDeadLetters.d.ts +9 -2
  50. package/dist/runtime/composables/useIntegrationsDeadLetters.js +27 -18
  51. package/dist/runtime/composables/useIntegrationsNodes.js +11 -1
  52. package/dist/runtime/composables/useIntegrationsRuns.d.ts +30 -1
  53. package/dist/runtime/composables/useIntegrationsRuns.js +70 -29
  54. package/dist/runtime/composables/useIntegrationsSchedules.d.ts +7 -14
  55. package/dist/runtime/composables/useIntegrationsSchedules.js +80 -35
  56. package/dist/runtime/composables/useIntegrationsTriggers.d.ts +30 -3
  57. package/dist/runtime/composables/useIntegrationsTriggers.js +18 -7
  58. package/dist/runtime/composables/useIntegrationsWorkflows.d.ts +10 -1
  59. package/dist/runtime/composables/useIntegrationsWorkflows.js +25 -4
  60. package/dist/runtime/composables/useNodeConfigResolve.js +2 -1
  61. package/dist/runtime/data/integrationNodeCatalog.d.ts +22 -1
  62. package/dist/runtime/data/integrationNodeCatalog.js +8 -4
  63. package/dist/runtime/data/loopBody.d.ts +129 -0
  64. package/dist/runtime/data/loopBody.js +76 -0
  65. package/dist/runtime/data/nodeInputData.d.ts +58 -1
  66. package/dist/runtime/data/nodeInputData.js +30 -5
  67. package/dist/runtime/data/triggerGlyphs.d.ts +47 -0
  68. package/dist/runtime/data/triggerGlyphs.js +11 -0
  69. package/dist/runtime/i18n/messages/de.json +62 -33
  70. package/dist/runtime/i18n/messages/en.json +32 -3
  71. package/dist/runtime/pages/integrations/credentials.vue +4 -1
  72. package/dist/runtime/pages/integrations/index.vue +32 -34
  73. package/dist/runtime/pages/integrations/runs.vue +22 -10
  74. package/dist/runtime/pages/integrations/schedules.vue +64 -7
  75. package/dist/runtime/pages/integrations/templates/[slug].vue +13 -5
  76. package/dist/runtime/pages/integrations/workflows/[id].vue +193 -104
  77. package/dist/runtime/types/integrations.d.ts +64 -1
  78. package/dist/runtime/utils/cockpitSources.d.ts +22 -3
  79. package/dist/runtime/utils/credentialState.d.ts +6 -1
  80. package/dist/runtime/utils/credentialState.js +1 -1
  81. package/dist/runtime/utils/localize.d.ts +34 -0
  82. package/dist/runtime/utils/localize.js +22 -7
  83. package/dist/runtime/utils/pollBudget.d.ts +1 -1
  84. package/dist/runtime/utils/servedPaths.d.ts +22 -0
  85. package/dist/runtime/utils/servedPaths.js +3 -0
  86. package/dist/runtime/utils/statusStyle.d.ts +52 -0
  87. package/dist/runtime/utils/statusStyle.js +26 -0
  88. package/package.json +1 -1
@@ -11,6 +11,40 @@
11
11
  export declare function setStudioLocale(locale: string | null | undefined): void;
12
12
  /** The language the studio is currently rendering in. Reactive when read in an effect. */
13
13
  export declare function studioLocale(): string;
14
+ /**
15
+ * The key a read answers from — which is the key a *deletion* has to remove, since
16
+ * what the user is clearing is the text in front of them.
17
+ *
18
+ * All four steps, in the order `resolveLocalized` reads them: the exact tag, the same
19
+ * language in another region, English, and the map's own first entry. `''` when the
20
+ * map holds no string at all.
21
+ */
22
+ export declare function languageKeyRead(map: unknown, locale?: string): string;
23
+ /**
24
+ * The key an edit is written to.
25
+ *
26
+ * The first two steps of {@link languageKeyRead} and deliberately not its last two:
27
+ * falling back to English or to the first entry answers "what can I show you", and
28
+ * writing there would put the author's text into a language they are not reading —
29
+ * the silent loss this exists to prevent (PO-259). A language the map does not hold
30
+ * yet is written under its base subtag, never the tag the host set, so that reading
31
+ * it back finds it: a `de-CH` studio reading a `de` text through the region step
32
+ * would otherwise write a new `de-CH` key and leave every plain-`de` reader on the
33
+ * old wording.
34
+ *
35
+ * **That guarantee is about the keys this function invents.** The first two steps
36
+ * return a key the map already holds, verbatim — so a map carrying `DE-ch` is written
37
+ * back into `DE-ch`, which the API's `^[a-z]{2,3}(-[A-Z]{2})?$` rejects. Not a case
38
+ * that can arise: such a map could not have been saved in the first place, and the
39
+ * only writer of these keys is this function. Returning an existing key as it stands
40
+ * is what makes the write land where the read came from, which is worth more here than
41
+ * normalising a shape nothing can produce — but it is why the sentence above says
42
+ * *invents* rather than *writes*.
43
+ *
44
+ * Deleting is the other question and has the other answer — see
45
+ * {@link languageKeyRead}.
46
+ */
47
+ export declare function languageKeyToWrite(map: unknown, locale?: string): string;
14
48
  /**
15
49
  * Resolve a multilingual value from the Integrations API. The API returns
16
50
  * names and descriptions either as a plain string or as an already-parsed
@@ -7,24 +7,39 @@ export function setStudioLocale(locale) {
7
7
  export function studioLocale() {
8
8
  return uiLocale.value;
9
9
  }
10
- function pickLanguage(map, locale) {
11
- const keys = Object.keys(map);
10
+ function baseLanguage(locale) {
11
+ const base = locale.toLowerCase().split(/[-_]/)[0] ?? "";
12
+ return /^[a-z]{2,3}$/.test(base) ? base : "en";
13
+ }
14
+ export function languageKeyRead(map, locale = studioLocale()) {
15
+ const obj = map && typeof map === "object" ? map : {};
16
+ const keys = Object.keys(obj);
12
17
  if (!keys.length) return "";
13
18
  const wanted = locale.toLowerCase();
14
- const base = wanted.split("-")[0];
19
+ const base = baseLanguage(locale);
15
20
  const candidates = [
16
21
  keys.find((k) => k.toLowerCase() === wanted),
17
- keys.find((k) => k.toLowerCase().split("-")[0] === base),
18
- keys.find((k) => k.toLowerCase().split("-")[0] === "en"),
22
+ keys.find((k) => baseLanguage(k) === base),
23
+ keys.find((k) => baseLanguage(k) === "en"),
19
24
  keys[0]
20
25
  ];
21
26
  for (const key of candidates) {
22
27
  if (key === void 0) continue;
23
- const picked = map[key];
24
- if (typeof picked === "string") return picked;
28
+ if (typeof obj[key] === "string") return key;
25
29
  }
26
30
  return "";
27
31
  }
32
+ export function languageKeyToWrite(map, locale = studioLocale()) {
33
+ const keys = map && typeof map === "object" ? Object.keys(map) : [];
34
+ const wanted = locale.toLowerCase();
35
+ const base = baseLanguage(locale);
36
+ return keys.find((k) => k.toLowerCase() === wanted) ?? keys.find((k) => baseLanguage(k) === base) ?? base;
37
+ }
38
+ function pickLanguage(map, locale) {
39
+ const key = languageKeyRead(map, locale);
40
+ const picked = key ? map[key] : void 0;
41
+ return typeof picked === "string" ? picked : "";
42
+ }
28
43
  export function resolveLocalized(value, locale = uiLocale.value) {
29
44
  if (value === null || value === void 0) return "";
30
45
  if (typeof value === "object" && !Array.isArray(value)) {
@@ -17,7 +17,7 @@
17
17
  * COUNTING TICKS, NOT READING A CLOCK, and that is deliberate twice over. The tick
18
18
  * is the only thing that has actually happened — a wall-clock reading would make
19
19
  * this disagree with a `setInterval` the browser throttled in a background tab. And
20
- * `specs/runs.md` AC-12's test installs Playwright's fake clock and fast-forwards
20
+ * `specs/runs.md` AC-8's test installs Playwright's fake clock and fast-forwards
21
21
  * it; a `Date.now()` in here would read the fake time, which is the kind of
22
22
  * coupling that makes a test pass for the wrong reason.
23
23
  *
@@ -0,0 +1,22 @@
1
+ /**
2
+ * The `/integrations/…` paths a host actually serves, out of the route records its
3
+ * router hands back.
4
+ *
5
+ * The dashboard's four shortcuts into Import & Export, the SFTP server, the event
6
+ * stream and inbound webhooks point at pages this module does not have — they are
7
+ * the host's (PO-223, [`docs/host-surfaces.md`](../../../docs/host-surfaces.md)) —
8
+ * so each card is offered as a way in only where the host has the path.
9
+ *
10
+ * It lives here rather than in the page for the same reason `scanRoutes` lives in
11
+ * `src/pageRoutes.ts`: the trailing-slash strip and the decision to compare exactly
12
+ * are what the doc names as the *misinforming* failure mode, and prose does not
13
+ * fail. `servedPaths.test.ts` pins the three cases that matter.
14
+ *
15
+ * **Exact strings, deliberately.** A parametrised page registers
16
+ * `/integrations/:surface`, and a route-prefixing i18n strategy registers
17
+ * `/en/integrations/io`; neither is one of the four literals, so a host built that
18
+ * way is told its own surfaces live elsewhere. That is the documented limit of the
19
+ * question — narrower than resolving through the matcher, which a host with a
20
+ * catch-all page answers "yes" to everywhere.
21
+ */
22
+ export declare function servedPaths(routePaths: string[]): Set<string>;
@@ -0,0 +1,3 @@
1
+ export function servedPaths(routePaths) {
2
+ return new Set(routePaths.map((path) => path.replace(/\/$/, "")));
3
+ }
@@ -42,4 +42,56 @@ export declare const RUN_STATUS_WORDS: readonly ["running", "succeeded", "failed
42
42
  * never disagree about which status they mean.
43
43
  */
44
44
  export declare function normalisedRunStatus(status: string | null | undefined): string;
45
+ /**
46
+ * The classes a run's status badge is drawn with — the colour half of
47
+ * {@link runStatusLabel}, and it reads the same word.
48
+ *
49
+ * `statusClass` on its own is handed whatever the platform wrote, and the map it
50
+ * looks in knows the studio's vocabulary rather than Temporal's: `terminated` and
51
+ * `timed_out` are in no branch of it, so a run the operator terminated was drawn
52
+ * neutral — the colour a *cancelled* run wears — while its badge said "failed".
53
+ * Two runs reading the same, in two colours, because the word went through
54
+ * {@link normalisedRunStatus} and the colour did not.
55
+ *
56
+ * So this normalises first. Every surface drawing a run's state calls it rather
57
+ * than `statusClass`, which stays what it is: one map from a status *word* to a
58
+ * tone, for the many vocabularies across the cockpit that already speak it.
59
+ */
60
+ export declare function runStatusClass(status: string | null | undefined): string;
45
61
  export declare function runStatusLabel(status: string | null | undefined): string;
62
+ /**
63
+ * A missed run's state, as a word written for the operator.
64
+ *
65
+ * The counterpart to {@link runStatusLabel} for the entry a trigger firing leaves
66
+ * when its workflow could not run. A state the catalogue does not know is named as
67
+ * unknown and carries the platform's own value inside that frame, so an operator
68
+ * can still quote what arrived without the studio claiming the word as one of its
69
+ * own. Nothing in, nothing out — the same answer `runStatusLabel` gives, for a
70
+ * column that is never actually empty.
71
+ *
72
+ * **The match is exact, unlike `runStatusLabel`'s**, and that is the point rather
73
+ * than an omission. Everything else that reads this field compares it strictly —
74
+ * whether an entry offers replay and discard, and whether it counts towards the
75
+ * firings still waiting — so a value differing by case or a stray space is one the
76
+ * studio does not act on. Saying "waiting" for it would promise an action that is
77
+ * not offered; saying it is unknown is what the rest of the studio already
78
+ * believes.
79
+ *
80
+ * The frame carries the value with its surrounding whitespace off and nothing else
81
+ * touched. Not verbatim, twice over, and neither is worth chasing: the badge is
82
+ * HTML, which collapses whitespace, and it draws its text uppercased — so an
83
+ * operator reads the letters that arrived rather than the casing, exactly as they
84
+ * do for the three states the studio does have words for.
85
+ */
86
+ export declare function deadLetterStatusLabel(status: string | null | undefined): string;
87
+ /**
88
+ * The classes a missed run's state badge is drawn with, on every surface that lists
89
+ * one.
90
+ *
91
+ * The colour half of {@link deadLetterStatusLabel}, reading the same map by the same
92
+ * exact match, so the two cannot disagree about which states the studio knows: a
93
+ * state named as unknown is drawn as unknown. Tones come from the shared palette,
94
+ * so this is one more vocabulary mapped into the studio's colours rather than a
95
+ * second set of colours.
96
+ */
97
+ export declare function deadLetterStatusClass(status: string | null | undefined): string;
@@ -89,13 +89,39 @@ export function normalisedRunStatus(status) {
89
89
  case "terminated":
90
90
  case "timed_out":
91
91
  return "failed";
92
+ // Temporal spells a cancellation the American way and the studio does not, so
93
+ // without this the *word* half of the promise fails on the surfaces that read
94
+ // the platform's answer directly: the row said `cancelled`, the record
95
+ // `canceled`, and in German the record said it in English.
96
+ case "canceled":
97
+ return "cancelled";
92
98
  default:
93
99
  return s;
94
100
  }
95
101
  }
102
+ export function runStatusClass(status) {
103
+ return statusClass(normalisedRunStatus(status));
104
+ }
96
105
  export function runStatusLabel(status) {
97
106
  const normalized = normalisedRunStatus(status);
98
107
  if (!normalized) return "";
99
108
  if (!RUN_STATUS_WORD_SET.has(normalized)) return normalized;
100
109
  return useIntegrationsT()(`integration.runs.status.${normalized}`);
101
110
  }
111
+ const MISSED_RUN_STATUS_TONE = /* @__PURE__ */ new Map([
112
+ ["pending", "warning"],
113
+ ["replayed", "success"],
114
+ ["discarded", "neutral"]
115
+ ]);
116
+ export function deadLetterStatusLabel(status) {
117
+ if (!status) return "";
118
+ const raw = String(status);
119
+ if (!MISSED_RUN_STATUS_TONE.has(raw)) {
120
+ return useIntegrationsT()("integration.deadLetters.status.unknown", { status: raw.trim() || raw });
121
+ }
122
+ return useIntegrationsT()(`integration.deadLetters.status.${raw}`);
123
+ }
124
+ export function deadLetterStatusClass(status) {
125
+ const tone = status ? MISSED_RUN_STATUS_TONE.get(String(status)) : void 0;
126
+ return toneClass(tone ?? "neutral");
127
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@revenexx/studio-integrations",
3
- "version": "0.7.0",
3
+ "version": "1.1.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
6
  "repository": {