@revenexx/studio-integrations 0.5.1 → 0.7.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 (171) hide show
  1. package/CHANGELOG.md +428 -0
  2. package/README.md +48 -4
  3. package/dist/module.d.mts +17 -1
  4. package/dist/module.json +1 -1
  5. package/dist/module.mjs +10 -2
  6. package/dist/runtime/components/Integrations/CredentialCreateDialog.vue +43 -41
  7. package/dist/runtime/components/Integrations/CredentialDetailDialog.vue +123 -50
  8. package/dist/runtime/components/Integrations/CredentialRevenexxSource.vue +108 -71
  9. package/dist/runtime/components/Integrations/CredentialTypePicker.vue +12 -15
  10. package/dist/runtime/components/Integrations/DeadLettersPanel.vue +18 -17
  11. package/dist/runtime/components/Integrations/EventTypeCombobox.d.vue.ts +1 -0
  12. package/dist/runtime/components/Integrations/EventTypeCombobox.vue +7 -4
  13. package/dist/runtime/components/Integrations/EventTypeCombobox.vue.d.ts +1 -0
  14. package/dist/runtime/components/Integrations/ExpressionInput.d.vue.ts +4 -0
  15. package/dist/runtime/components/Integrations/ExpressionInput.vue +67 -37
  16. package/dist/runtime/components/Integrations/ExpressionInput.vue.d.ts +4 -0
  17. package/dist/runtime/components/Integrations/GroupFrameView.vue +30 -20
  18. package/dist/runtime/components/Integrations/Layout.vue +48 -4
  19. package/dist/runtime/components/Integrations/NodeConfigDynamicField.vue +23 -23
  20. package/dist/runtime/components/Integrations/NodeConfigDynamicSchema.vue +11 -13
  21. package/dist/runtime/components/Integrations/NodeConfigField.d.vue.ts +2 -0
  22. package/dist/runtime/components/Integrations/NodeConfigField.vue +187 -93
  23. package/dist/runtime/components/Integrations/NodeConfigField.vue.d.ts +2 -0
  24. package/dist/runtime/components/Integrations/NodeInspector.d.vue.ts +6 -0
  25. package/dist/runtime/components/Integrations/NodeInspector.vue +1157 -376
  26. package/dist/runtime/components/Integrations/NodeInspector.vue.d.ts +6 -0
  27. package/dist/runtime/components/Integrations/NodeLogo.d.vue.ts +12 -0
  28. package/dist/runtime/components/Integrations/NodeLogo.vue +2 -30
  29. package/dist/runtime/components/Integrations/NodeLogo.vue.d.ts +12 -0
  30. package/dist/runtime/components/Integrations/NodeMark.d.vue.ts +15 -0
  31. package/dist/runtime/components/Integrations/NodeMark.vue +79 -0
  32. package/dist/runtime/components/Integrations/NodeMark.vue.d.ts +15 -0
  33. package/dist/runtime/components/Integrations/NodeOutputSchema.d.vue.ts +21 -0
  34. package/dist/runtime/components/Integrations/NodeOutputSchema.vue +43 -0
  35. package/dist/runtime/components/Integrations/NodeOutputSchema.vue.d.ts +21 -0
  36. package/dist/runtime/components/Integrations/NodePalette.vue +122 -55
  37. package/dist/runtime/components/Integrations/QueryBuilder.vue +46 -38
  38. package/dist/runtime/components/Integrations/RunActionsMenu.vue +38 -12
  39. package/dist/runtime/components/Integrations/RunDetailPanel.vue +114 -62
  40. package/dist/runtime/components/Integrations/RunPayloadInput.vue +27 -13
  41. package/dist/runtime/components/Integrations/RunResponseModal.vue +11 -10
  42. package/dist/runtime/components/Integrations/RunsTable.d.vue.ts +0 -1
  43. package/dist/runtime/components/Integrations/RunsTable.vue +38 -16
  44. package/dist/runtime/components/Integrations/RunsTable.vue.d.ts +0 -1
  45. package/dist/runtime/components/Integrations/SftpAccountImportDialog.vue +8 -7
  46. package/dist/runtime/components/Integrations/Sidebar.vue +14 -10
  47. package/dist/runtime/components/Integrations/StickyNoteView.d.vue.ts +14 -4
  48. package/dist/runtime/components/Integrations/StickyNoteView.vue +38 -23
  49. package/dist/runtime/components/Integrations/StickyNoteView.vue.d.ts +14 -4
  50. package/dist/runtime/components/Integrations/TemplateCard.d.vue.ts +18 -0
  51. package/dist/runtime/components/Integrations/TemplateCard.vue +119 -0
  52. package/dist/runtime/components/Integrations/TemplateCard.vue.d.ts +18 -0
  53. package/dist/runtime/components/Integrations/TemplateFlowPreview.d.vue.ts +2 -2
  54. package/dist/runtime/components/Integrations/TemplateFlowPreview.vue +16 -18
  55. package/dist/runtime/components/Integrations/TemplateFlowPreview.vue.d.ts +2 -2
  56. package/dist/runtime/components/Integrations/WorkflowContextMenu.vue +34 -33
  57. package/dist/runtime/components/Integrations/WorkflowCreateDialog.vue +52 -67
  58. package/dist/runtime/components/Integrations/WorkflowDuplicateDialog.vue +8 -7
  59. package/dist/runtime/components/Integrations/WorkflowEdgeView.d.vue.ts +18 -4
  60. package/dist/runtime/components/Integrations/WorkflowEdgeView.vue +29 -11
  61. package/dist/runtime/components/Integrations/WorkflowEdgeView.vue.d.ts +18 -4
  62. package/dist/runtime/components/Integrations/WorkflowEditor.d.vue.ts +20 -1
  63. package/dist/runtime/components/Integrations/WorkflowEditor.vue +240 -116
  64. package/dist/runtime/components/Integrations/WorkflowEditor.vue.d.ts +20 -1
  65. package/dist/runtime/components/Integrations/WorkflowHistoryPanel.vue +28 -43
  66. package/dist/runtime/components/Integrations/WorkflowIconPicker.d.vue.ts +19 -1
  67. package/dist/runtime/components/Integrations/WorkflowIconPicker.vue +17 -7
  68. package/dist/runtime/components/Integrations/WorkflowIconPicker.vue.d.ts +19 -1
  69. package/dist/runtime/components/Integrations/WorkflowNodeView.d.vue.ts +4 -0
  70. package/dist/runtime/components/Integrations/WorkflowNodeView.vue +198 -56
  71. package/dist/runtime/components/Integrations/WorkflowNodeView.vue.d.ts +4 -0
  72. package/dist/runtime/components/Integrations/WorkflowRunReplayPanel.vue +56 -59
  73. package/dist/runtime/components/Integrations/WorkflowSettingsDialog.vue +28 -21
  74. package/dist/runtime/components/Integrations/WorkflowTagsInput.d.vue.ts +1 -0
  75. package/dist/runtime/components/Integrations/WorkflowTagsInput.vue +15 -9
  76. package/dist/runtime/components/Integrations/WorkflowTagsInput.vue.d.ts +1 -0
  77. package/dist/runtime/components/Integrations/WorkflowTriggerView.vue +15 -10
  78. package/dist/runtime/components/Integrations/WorkflowVariablesDialog.vue +50 -36
  79. package/dist/runtime/components/Integrations/WorkflowsTable.vue +126 -48
  80. package/dist/runtime/composables/integrationsApi.js +4 -2
  81. package/dist/runtime/composables/useCredentialTypes.js +8 -6
  82. package/dist/runtime/composables/useIntegrationsAudit.js +4 -3
  83. package/dist/runtime/composables/useIntegrationsCredentials.js +10 -8
  84. package/dist/runtime/composables/useIntegrationsDeadLetters.js +7 -6
  85. package/dist/runtime/composables/useIntegrationsFocus.d.ts +12 -0
  86. package/dist/runtime/composables/useIntegrationsLocale.d.ts +26 -0
  87. package/dist/runtime/composables/useIntegrationsLocale.js +8 -0
  88. package/dist/runtime/composables/useIntegrationsNodes.js +7 -5
  89. package/dist/runtime/composables/useIntegrationsRealtime.d.ts +149 -0
  90. package/dist/runtime/composables/useIntegrationsRealtime.js +80 -0
  91. package/dist/runtime/composables/useIntegrationsRevisions.js +9 -7
  92. package/dist/runtime/composables/useIntegrationsRuns.d.ts +1 -1
  93. package/dist/runtime/composables/useIntegrationsRuns.js +14 -7
  94. package/dist/runtime/composables/useIntegrationsSchedules.d.ts +4 -0
  95. package/dist/runtime/composables/useIntegrationsSchedules.js +10 -3
  96. package/dist/runtime/composables/useIntegrationsSecrets.js +14 -9
  97. package/dist/runtime/composables/useIntegrationsT.d.ts +35 -0
  98. package/dist/runtime/composables/useIntegrationsT.js +9 -0
  99. package/dist/runtime/composables/useIntegrationsTemplates.d.ts +3 -3
  100. package/dist/runtime/composables/useIntegrationsTemplates.js +28 -16
  101. package/dist/runtime/composables/useIntegrationsTriggers.js +10 -8
  102. package/dist/runtime/composables/useIntegrationsWorkflows.js +13 -7
  103. package/dist/runtime/composables/useLoadGate.d.ts +17 -0
  104. package/dist/runtime/composables/useLoadGate.js +8 -0
  105. package/dist/runtime/composables/useNodeConfigResolve.js +2 -1
  106. package/dist/runtime/data/branchReorder.d.ts +37 -0
  107. package/dist/runtime/data/branchReorder.js +71 -0
  108. package/dist/runtime/data/handleId.d.ts +23 -0
  109. package/dist/runtime/data/handleId.js +6 -0
  110. package/dist/runtime/data/integrationNodeCatalog.d.ts +41 -0
  111. package/dist/runtime/data/integrationNodeCatalog.js +14 -0
  112. package/dist/runtime/data/integrationTemplates.d.ts +48 -0
  113. package/dist/runtime/data/integrationTemplates.js +21 -0
  114. package/dist/runtime/data/integrationWorkflowSamples.js +1 -1
  115. package/dist/runtime/data/nodeIcons.d.ts +2 -0
  116. package/dist/runtime/data/nodeIcons.js +73 -0
  117. package/dist/runtime/data/nodeInputData.d.ts +16 -4
  118. package/dist/runtime/data/nodeInputData.js +4 -0
  119. package/dist/runtime/data/payloadForm.d.ts +9 -2
  120. package/dist/runtime/data/payloadForm.js +29 -4
  121. package/dist/runtime/data/portTone.d.ts +17 -0
  122. package/dist/runtime/data/portTone.js +7 -0
  123. package/dist/runtime/data/webhookAuth.d.ts +18 -0
  124. package/dist/runtime/data/webhookAuth.js +19 -0
  125. package/dist/runtime/data/workflowIconCatalog.js +4 -6
  126. package/dist/runtime/i18n/messages/de.json +1207 -0
  127. package/dist/runtime/i18n/messages/en.json +1207 -0
  128. package/dist/runtime/i18n/translate.d.ts +83 -0
  129. package/dist/runtime/i18n/translate.js +41 -0
  130. package/dist/runtime/pages/integrations/audit.vue +140 -37
  131. package/dist/runtime/pages/integrations/credentials/oauth-complete.vue +9 -6
  132. package/dist/runtime/pages/integrations/credentials.vue +180 -64
  133. package/dist/runtime/pages/integrations/index.vue +91 -92
  134. package/dist/runtime/pages/integrations/runs.vue +33 -21
  135. package/dist/runtime/pages/integrations/schedules.vue +88 -23
  136. package/dist/runtime/pages/integrations/secrets.vue +57 -35
  137. package/dist/runtime/pages/integrations/templates/[slug].vue +119 -88
  138. package/dist/runtime/pages/integrations/templates/index.vue +82 -103
  139. package/dist/runtime/pages/integrations/workflows/[id].vue +344 -91
  140. package/dist/runtime/pages/integrations/workflows/index.vue +23 -5
  141. package/dist/runtime/plugins/locale.d.ts +10 -0
  142. package/dist/runtime/plugins/locale.js +6 -0
  143. package/dist/runtime/plugins/realtime.client.d.ts +32 -0
  144. package/dist/runtime/plugins/realtime.client.js +4 -0
  145. package/dist/runtime/types/integrations.d.ts +65 -6
  146. package/dist/runtime/utils/apiError.d.ts +47 -0
  147. package/dist/runtime/utils/apiError.js +32 -0
  148. package/dist/runtime/utils/cockpitSources.d.ts +153 -0
  149. package/dist/runtime/utils/cockpitSources.js +14 -0
  150. package/dist/runtime/utils/credentialState.d.ts +24 -1
  151. package/dist/runtime/utils/credentialState.js +26 -11
  152. package/dist/runtime/utils/loadGate.d.ts +61 -0
  153. package/dist/runtime/utils/loadGate.js +22 -0
  154. package/dist/runtime/utils/localize.d.ts +46 -4
  155. package/dist/runtime/utils/localize.js +34 -7
  156. package/dist/runtime/utils/notify.d.ts +59 -0
  157. package/dist/runtime/utils/notify.js +21 -0
  158. package/dist/runtime/utils/pollBudget.d.ts +72 -0
  159. package/dist/runtime/utils/pollBudget.js +17 -0
  160. package/dist/runtime/utils/revenexxCredentialSource.d.ts +26 -0
  161. package/dist/runtime/utils/revenexxCredentialSource.js +8 -0
  162. package/dist/runtime/utils/schedule.d.ts +116 -0
  163. package/dist/runtime/utils/schedule.js +219 -0
  164. package/dist/runtime/utils/statusStyle.d.ts +26 -2
  165. package/dist/runtime/utils/statusStyle.js +9 -1
  166. package/dist/runtime/utils/validationFindings.d.ts +101 -0
  167. package/dist/runtime/utils/validationFindings.js +54 -0
  168. package/dist/runtime/utils/whenIdle.d.ts +42 -0
  169. package/dist/runtime/utils/whenIdle.js +12 -0
  170. package/dist/types.d.mts +2 -6
  171. package/package.json +10 -3
@@ -0,0 +1,22 @@
1
+ import { whenIdle } from "./whenIdle.js";
2
+ export function createLoadGate(state) {
3
+ const { loading, loaded, started, finished } = state;
4
+ return {
5
+ async claim(force = false) {
6
+ const askedAt = started.value;
7
+ while (loading.value) {
8
+ await whenIdle(loading);
9
+ if (!force) return false;
10
+ if (finished.value > askedAt) return false;
11
+ }
12
+ if (loaded?.value && !force) return false;
13
+ started.value++;
14
+ loading.value = true;
15
+ return true;
16
+ },
17
+ release() {
18
+ loading.value = false;
19
+ finished.value++;
20
+ }
21
+ };
22
+ }
@@ -1,11 +1,53 @@
1
+ /**
2
+ * Tell the studio which language to render in. **This is the host's job**, and
3
+ * it is the whole contract: the module is published, so it must not go looking
4
+ * for the cockpit's storage keys or import the cockpit's i18n. A host with a
5
+ * language switcher calls this whenever the choice changes; a host with a fixed
6
+ * language sets `studioIntegrations.locale` in its Nuxt config instead and
7
+ * never calls this at all.
8
+ *
9
+ * A BCP-47 tag (`de`, `en`, `de-CH`). Empty or absent means English.
10
+ */
11
+ export declare function setStudioLocale(locale: string | null | undefined): void;
12
+ /** The language the studio is currently rendering in. Reactive when read in an effect. */
13
+ export declare function studioLocale(): string;
1
14
  /**
2
15
  * Resolve a multilingual value from the Integrations API. The API returns
3
16
  * names and descriptions either as a plain string or as an already-parsed
4
17
  * object `{de:"…", en:"…"}` (the HTTP client does JSON decoding automatically).
5
18
  * JSON-encoded strings like `'{"de":"…","en":"…"}'` are also handled.
6
19
  *
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.
20
+ * The language is the studio's ({@link setStudioLocale}) unless the caller
21
+ * names one. English is the fallback, and the map's own first entry the
22
+ * fallback after that.
23
+ *
24
+ * **This is the studio's only resolver, and that is the point.** The same three
25
+ * lines used to sit in seventeen components under six names (`labelText`, `loc`,
26
+ * `locText`, `localLabel`, `title`, `descriptionText`), all agreeing with this
27
+ * function by coincidence. A language switcher wired into this one place would
28
+ * have translated a fraction of the surface with nothing going red — so PO-229
29
+ * collapsed them here before building one. Anything that renders a name, a
30
+ * label, a description or a placeholder from the API calls this; nothing
31
+ * re-derives the rule.
32
+ *
33
+ * Two of the seventeen were named for their call site rather than for the rule
34
+ * (`WorkflowTriggerView`'s `title`, `WorkflowVariablesDialog`'s
35
+ * `descriptionText`), so no grep for the rule's shape found them. Both resolve
36
+ * text a person typed and went to `resolveDisplayName` below, not here.
37
+ */
38
+ export declare function resolveLocalized(value: unknown, locale?: string): string;
39
+ /**
40
+ * The same resolution, for a value that may be **text a person wrote** — a
41
+ * node's own name, a group frame's label.
42
+ *
43
+ * `resolveLocalized` normalises: it trims, and it reads a leading `{` as JSON.
44
+ * That is right for a manifest string and wrong for a user's own, and it has
45
+ * already cost once (PO-204): run through the trimming resolver, the node-name
46
+ * field ate the space the user had just typed, so "Fetch open orders" came back
47
+ * as "Fetchopenorders". A name like `{"a":"b"}` would render as `b`.
48
+ *
49
+ * So a string is passed through untouched and only the localised-object form is
50
+ * resolved. Use this wherever the value can be something a person typed; use
51
+ * `resolveLocalized` for anything that can only have come from a manifest.
10
52
  */
11
- export declare function resolveLocalized(value: unknown): string;
53
+ export declare function resolveDisplayName(value: string | Record<string, string> | undefined | null, locale?: string): string;
@@ -1,11 +1,34 @@
1
- export function resolveLocalized(value) {
1
+ import { shallowRef } from "vue";
2
+ const uiLocale = shallowRef("en");
3
+ export function setStudioLocale(locale) {
4
+ const next = typeof locale === "string" ? locale.trim() : "";
5
+ uiLocale.value = next || "en";
6
+ }
7
+ export function studioLocale() {
8
+ return uiLocale.value;
9
+ }
10
+ function pickLanguage(map, locale) {
11
+ const keys = Object.keys(map);
12
+ if (!keys.length) return "";
13
+ const wanted = locale.toLowerCase();
14
+ const base = wanted.split("-")[0];
15
+ const candidates = [
16
+ keys.find((k) => k.toLowerCase() === wanted),
17
+ keys.find((k) => k.toLowerCase().split("-")[0] === base),
18
+ keys.find((k) => k.toLowerCase().split("-")[0] === "en"),
19
+ keys[0]
20
+ ];
21
+ for (const key of candidates) {
22
+ if (key === void 0) continue;
23
+ const picked = map[key];
24
+ if (typeof picked === "string") return picked;
25
+ }
26
+ return "";
27
+ }
28
+ export function resolveLocalized(value, locale = uiLocale.value) {
2
29
  if (value === null || value === void 0) return "";
3
30
  if (typeof value === "object" && !Array.isArray(value)) {
4
- const map = value;
5
- const keys = Object.keys(map);
6
- if (!keys.length) return "";
7
- const picked = map["en"] ?? map[keys[0]];
8
- return typeof picked === "string" ? picked : "";
31
+ return pickLanguage(value, locale);
9
32
  }
10
33
  if (typeof value !== "string") return String(value);
11
34
  const trimmed = value.trim();
@@ -13,8 +36,12 @@ export function resolveLocalized(value) {
13
36
  try {
14
37
  const parsed = JSON.parse(trimmed);
15
38
  if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) return trimmed;
16
- return resolveLocalized(parsed);
39
+ return resolveLocalized(parsed, locale);
17
40
  } catch {
18
41
  return trimmed;
19
42
  }
20
43
  }
44
+ export function resolveDisplayName(value, locale = uiLocale.value) {
45
+ if (typeof value === "string") return value;
46
+ return resolveLocalized(value, locale);
47
+ }
@@ -0,0 +1,59 @@
1
+ /**
2
+ * A proxy rather than a hand-written object, so the whole library stays reachable:
3
+ * `toast.dismiss`, `toast.promise`, `toast.custom` and whatever it gains next are
4
+ * forwarded and guarded on access. Listing the methods by hand would have turned the
5
+ * first call to an unlisted one into "undefined is not a function" — a second defect
6
+ * of the same shape as the one this file exists for.
7
+ */
8
+ export declare const toast: ((message: string | (() => string | import("vue").Component) | import("vue").Component, data?: import("vue-sonner").ExternalToast) => string | number) & {
9
+ success: (message: string | (() => string | import("vue").Component) | import("vue").Component, data?: import("vue-sonner").ExternalToast) => string | number;
10
+ info: (message: string | (() => string | import("vue").Component) | import("vue").Component, data?: import("vue-sonner").ExternalToast) => string | number;
11
+ warning: (message: string | (() => string | import("vue").Component) | import("vue").Component, data?: import("vue-sonner").ExternalToast) => string | number;
12
+ error: (message: string | (() => string | import("vue").Component) | import("vue").Component, data?: import("vue-sonner").ExternalToast) => string | number;
13
+ custom: (component: import("vue").Component, data?: import("vue-sonner").ExternalToast) => string | number;
14
+ message: (message: string | (() => string | import("vue").Component) | import("vue").Component, data?: import("vue-sonner").ExternalToast) => string | number;
15
+ promise: <ToastData>(promise: Promise<ToastData> | (() => Promise<ToastData>), data?: ({
16
+ action?: (import("vue-sonner").Action | import("vue").Component) | undefined;
17
+ icon?: import("vue").Component | undefined;
18
+ class?: string | undefined;
19
+ id?: number | string | undefined;
20
+ position?: ("top-left" | "top-right" | "bottom-left" | "bottom-right" | "top-center" | "bottom-center") | undefined;
21
+ cancel?: (import("vue-sonner").Action | import("vue").Component) | undefined;
22
+ toasterId?: string | undefined;
23
+ component?: import("vue").Component | undefined;
24
+ componentProps?: any;
25
+ richColors?: boolean | undefined;
26
+ invert?: boolean | undefined;
27
+ closeButton?: boolean | undefined;
28
+ dismissible?: boolean | undefined;
29
+ duration?: number | undefined;
30
+ important?: boolean | undefined;
31
+ onDismiss?: ((toast: import("vue-sonner").ToastT) => void) | undefined;
32
+ onAutoClose?: ((toast: import("vue-sonner").ToastT) => void) | undefined;
33
+ cancelButtonStyle?: import("vue").CSSProperties | undefined;
34
+ actionButtonStyle?: import("vue").CSSProperties | undefined;
35
+ style?: import("vue").CSSProperties | undefined;
36
+ unstyled?: boolean | undefined;
37
+ classes?: import("vue-sonner").ToastClasses | undefined;
38
+ descriptionClass?: string | undefined;
39
+ closeButtonPosition?: ("top-left" | "top-right" | "bottom-left" | "bottom-right") | undefined;
40
+ testId?: string | undefined;
41
+ } & {
42
+ loading?: string | import("vue").Component;
43
+ success?: (string | import("vue").Component | ((data: ToastData) => import("vue").Component | string | Promise<import("vue").Component | string>)) | (import("vue-sonner").PromiseIExtendedResult | ((data: ToastData) => import("vue-sonner").PromiseIExtendedResult | Promise<import("vue-sonner").PromiseIExtendedResult>)) | undefined;
44
+ error?: (string | import("vue").Component | ((data: any) => import("vue").Component | string | Promise<import("vue").Component | string>)) | (import("vue-sonner").PromiseIExtendedResult | ((data: any) => import("vue-sonner").PromiseIExtendedResult | Promise<import("vue-sonner").PromiseIExtendedResult>));
45
+ description?: string | import("vue").Component | ((data: any) => import("vue").Component | string | Promise<import("vue").Component | string>);
46
+ finally?: () => void | Promise<void>;
47
+ }) | undefined) => (string & {
48
+ unwrap: () => Promise<ToastData>;
49
+ }) | (number & {
50
+ unwrap: () => Promise<ToastData>;
51
+ }) | {
52
+ unwrap: () => Promise<ToastData>;
53
+ } | undefined;
54
+ dismiss: (id?: number | string) => string | number | undefined;
55
+ loading: (message: string | (() => string | import("vue").Component) | import("vue").Component, data?: import("vue-sonner").ExternalToast) => string | number;
56
+ } & {
57
+ getHistory: () => (import("vue-sonner").ToastT<import("vue").Component> | import("vue-sonner").ToastToDismiss)[];
58
+ getToasts: () => (import("vue-sonner").ToastT<import("vue").Component> | import("vue-sonner").ToastToDismiss)[];
59
+ };
@@ -0,0 +1,21 @@
1
+ import { toast as sonner } from "vue-sonner";
2
+ function guarded(kind, fn) {
3
+ return (...args) => {
4
+ try {
5
+ return fn(...args);
6
+ } catch (e) {
7
+ console.warn(`[studio-integrations] notification dropped (${kind}): ${String(args[0])}`, e);
8
+ return void 0;
9
+ }
10
+ };
11
+ }
12
+ export const toast = new Proxy(sonner, {
13
+ apply(target, thisArg, args) {
14
+ return guarded("message", (...a) => Reflect.apply(target, thisArg, a))(...args);
15
+ },
16
+ get(target, prop) {
17
+ const value = Reflect.get(target, prop);
18
+ if (typeof value !== "function") return value;
19
+ return guarded(String(prop), (...args) => value.apply(target, args));
20
+ }
21
+ });
@@ -0,0 +1,72 @@
1
+ /**
2
+ * How often a poll is still allowed to fetch once realtime is carrying the same
3
+ * updates.
4
+ *
5
+ * Every run surface polls: the runs list every three seconds, the detail panel
6
+ * every three and its timeline every ten, the replay canvas every four. That is the
7
+ * only thing that made a `running → completed` transition appear at all, and it is
8
+ * expensive — `runs.vue`'s pass fans out one request per workflow and then
9
+ * reconciles up to five active runs, so the list can cost dozens of requests every
10
+ * three seconds while anything is in flight.
11
+ *
12
+ * Talkback replaces the *latency* argument for polling, not the safety argument. So
13
+ * the intervals stay exactly where they are and this decides, per tick, whether the
14
+ * tick may spend a request: at the ordinary cadence while nothing is being reported,
15
+ * and at a slow safety cadence once something is.
16
+ *
17
+ * COUNTING TICKS, NOT READING A CLOCK, and that is deliberate twice over. The tick
18
+ * is the only thing that has actually happened — a wall-clock reading would make
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
21
+ * it; a `Date.now()` in here would read the fake time, which is the kind of
22
+ * coupling that makes a test pass for the wrong reason.
23
+ *
24
+ * WHAT `delivering` HAS TO MEAN, and this is the argument the parameter's name is
25
+ * carrying. Being subscribed is no evidence: a channel resolves from the local
26
+ * subscription, so a tenant whose event catalogue never publishes these topics holds
27
+ * open channels that stay silent for the life of the tab — and thinning on that state
28
+ * would make such a tenant ten times slower than before any of this existed, with
29
+ * nothing anywhere saying so. `useIntegrationsRealtime` therefore counts deliveries,
30
+ * and this is only ever thinned once something has really arrived.
31
+ *
32
+ * WHY A SLOW POLL RATHER THAN NONE. What is still unavailable is whether delivery is
33
+ * CONTINUING: a socket that dies quietly after one event keeps reading as delivering,
34
+ * because the per-channel confirmation that would settle it is not passed through the
35
+ * packages between Centrifugo and here. A budget that stopped fetching entirely would
36
+ * then show a stale list for as long as the tab stayed open, with nothing anywhere
37
+ * saying so. Backing off from three seconds to thirty gives up latency we now get
38
+ * from events and keeps the property that mattered: the view converges without the
39
+ * operator doing anything.
40
+ *
41
+ * The caller keeps its own tick-shedding (`!loading.value`) in front of this, so a
42
+ * tick that finds a load still out neither fetches nor spends budget — see
43
+ * `loadGate.ts` for why that flag is trustworthy.
44
+ */
45
+ export interface PollBudgetOptions {
46
+ /** The caller's own interval, i.e. how much time one `due()` call stands for. */
47
+ intervalMs: number;
48
+ /** The gap between fetches while reports are arriving. */
49
+ liveIntervalMs: number;
50
+ }
51
+ export interface PollBudget {
52
+ /**
53
+ * Whether this tick may fetch. Advances the budget, so call it once per tick and
54
+ * last in the condition — `hasActive && !loading && budget.due(delivering)`.
55
+ */
56
+ due: (delivering: boolean) => boolean;
57
+ /**
58
+ * Counts a fetch this budget did not authorise: a report's refetch, a manual
59
+ * refresh, a row action, an opening surface's first read. Without it the next due
60
+ * tick would send a second request for a state that was just read.
61
+ *
62
+ * CALL IT IN THE LOADER, not at each call site, wherever the surface has a loader
63
+ * of its own to put it in — `[id].vue`'s `loadRuns`, `RunDetailPanel`'s
64
+ * `loadSummary` and `loadTimelineEvents`, `runs.vue`'s `reload`. A contract that
65
+ * asks every future caller to remember is one that ends up wider than the wiring,
66
+ * which is how this note came to be written.
67
+ */
68
+ spend: () => void;
69
+ }
70
+ /** The safety cadence every run surface backs off to while reports are arriving. */
71
+ export declare const SAFETY_POLL_MS = 30000;
72
+ export declare function createPollBudget(options: PollBudgetOptions): PollBudget;
@@ -0,0 +1,17 @@
1
+ export const SAFETY_POLL_MS = 3e4;
2
+ export function createPollBudget(options) {
3
+ let elapsed = 0;
4
+ return {
5
+ due(delivering) {
6
+ elapsed += options.intervalMs;
7
+ if (!delivering || elapsed >= options.liveIntervalMs) {
8
+ elapsed = 0;
9
+ return true;
10
+ }
11
+ return false;
12
+ },
13
+ spend() {
14
+ elapsed = 0;
15
+ }
16
+ };
17
+ }
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Which credential types offer the "Use revenexx …" source alternative, and
3
+ * under which kind.
4
+ *
5
+ * This lives apart from the component that renders it because its *parents* need
6
+ * it too: the detail dialog mounts that component only for the types it actually
7
+ * serves, since for every other type it renders nothing anyway.
8
+ *
9
+ * It was once load-bearing for a different reason — the component resolved
10
+ * cockpit-only composables at setup time, so mounting it outside the cockpit
11
+ * threw and took the surrounding form down. That is fixed (PO-222): the component
12
+ * asks whether those sources exist. So this guard is now tidiness rather than
13
+ * protection, which is also why the create dialog never having one stopped
14
+ * mattering.
15
+ */
16
+ export type RevenexxSourceKind = 'sftp' | 'smtp' | 'api';
17
+ export declare const REVENEXX_SOURCE_KIND_BY_SLUG: Record<string, RevenexxSourceKind>;
18
+ /**
19
+ * Whether this credential type has a managed revenexx counterpart to copy from.
20
+ *
21
+ * Own properties only: `in` would answer yes for everything on the prototype
22
+ * chain, so a type slugged `toString` or `constructor` would pass the guard and
23
+ * then resolve to a function instead of a kind — and this guard is what decides
24
+ * whether the cockpit-coupled component mounts at all.
25
+ */
26
+ export declare function hasRevenexxSource(slug: string | null | undefined): boolean;
@@ -0,0 +1,8 @@
1
+ export const REVENEXX_SOURCE_KIND_BY_SLUG = {
2
+ "revenexx:sftp": "sftp",
3
+ "revenexx:smtp": "smtp",
4
+ "revenexx:api": "api"
5
+ };
6
+ export function hasRevenexxSource(slug) {
7
+ return !!slug && Object.hasOwn(REVENEXX_SOURCE_KIND_BY_SLUG, slug);
8
+ }
@@ -0,0 +1,116 @@
1
+ /** A rhythm the picker can build, and `describeRecurrence` can always say. */
2
+ export type Recurrence =
3
+ /** `interval` minutes apart, all day, every day. `1` means every minute. */
4
+ {
5
+ kind: 'minutes';
6
+ interval: number;
7
+ }
8
+ /** Once an hour, at `minute` past. */
9
+ | {
10
+ kind: 'hourly';
11
+ minute: number;
12
+ }
13
+ /** Every `interval` hours (2 or more), at `minute` past. */
14
+ | {
15
+ kind: 'hours';
16
+ interval: number;
17
+ minute: number;
18
+ }
19
+ /** Once a day, at a fixed time. */
20
+ | {
21
+ kind: 'daily';
22
+ hour: number;
23
+ minute: number;
24
+ }
25
+ /**
26
+ * Several times a day, at the same minute past each of `hours` — two or more —
27
+ * and on `days`, or every day when that is `null`.
28
+ *
29
+ * A list of hours and a run of them are the same rhythm written two ways
30
+ * (`9,10,11` fires exactly when `9-11` does), so both read back into this one
31
+ * form and `toCron` picks the canonical spelling. Times with *different*
32
+ * minutes are not one rhythm and cron cannot express them in one expression:
33
+ * 07:30 and 09:15 is two schedules.
34
+ */
35
+ | {
36
+ kind: 'times';
37
+ minute: number;
38
+ hours: number[];
39
+ days: number[] | null;
40
+ }
41
+ /** On the given weekdays (0 = Sunday), at a fixed time. Never empty. */
42
+ | {
43
+ kind: 'weekly';
44
+ days: number[];
45
+ hour: number;
46
+ minute: number;
47
+ }
48
+ /** On one day of the month, at a fixed time. */
49
+ | {
50
+ kind: 'monthly';
51
+ day: number;
52
+ hour: number;
53
+ minute: number;
54
+ };
55
+ /**
56
+ * The zone a schedule without one of its own runs in: the platform's default,
57
+ * which is UTC (`config('app.timezone')`, which nothing overrides).
58
+ *
59
+ * Not the zone the studio *writes*. A schedule set up here carries
60
+ * `Europe/Berlin` from the trigger's own default config, and this is only what a
61
+ * schedule that arrived without a zone actually runs in.
62
+ */
63
+ export declare const PLATFORM_TIMEZONE = "UTC";
64
+ /**
65
+ * The zone a schedule's numbers are read in — its own where it has one, the
66
+ * platform's default where it does not.
67
+ *
68
+ * One function because two surfaces show it: the trigger settings under the
69
+ * controls, and the Schedules page in its own column. A surface that answered this
70
+ * for itself is how one schedule ends up with two zones, and a zone is half of
71
+ * what a time means.
72
+ */
73
+ export declare function scheduleTimezone(timezone: unknown): string;
74
+ /**
75
+ * The rhythm an expression describes, or `null` when it is not one of them.
76
+ *
77
+ * @param cron A five-field expression: minute hour day-of-month month day-of-week.
78
+ */
79
+ export declare function parseCron(cron: string | null | undefined): Recurrence | null;
80
+ /**
81
+ * The five-field expression for a rhythm. Always valid, always five fields, and
82
+ * **never both a day of the month and a weekday** — cron reads that pair as
83
+ * "either", so a picker that produced it would mean something other than what it
84
+ * showed.
85
+ *
86
+ * Three rhythms are written in their canonical form rather than literally, so one
87
+ * rhythm has one expression: an hourly interval of 1 is `hourly`, a weekly
88
+ * schedule on all seven days is `daily`, and every day of the week under `times`
89
+ * is written as an open field. Reading any of them back therefore gives the
90
+ * canonical form, not the one passed in.
91
+ */
92
+ export declare function toCron(r: Recurrence): string;
93
+ /**
94
+ * A sentence for a rhythm. Total: every `Recurrence` has one, which is what lets
95
+ * a surface show the sentence in place of the expression.
96
+ */
97
+ export declare function describeRecurrence(r: Recurrence): string;
98
+ /**
99
+ * A sentence for the expression, or `null` when it cannot be said plainly.
100
+ *
101
+ * Nothing at all is the point where it happens. A wrong aid is worse than none,
102
+ * because a schedule that reads "Daily at 03:00" and fires hourly is a fault
103
+ * nobody goes looking for — so the shapes this cannot read produce no sentence,
104
+ * and the surface shows the expression instead.
105
+ *
106
+ * Times are read as written: the expression's own numbers, in the schedule's own
107
+ * timezone. Nothing here converts anything, which is why the timezone is the
108
+ * caller's to show.
109
+ */
110
+ export declare function describeCron(cron: string | null | undefined): string | null;
111
+ /**
112
+ * How long a rhythm waits between firings, in minutes — the order a "when does
113
+ * this run" column sorts in. An expression that cannot be read sorts last, since
114
+ * the alternative is ordering rows by a string the reader cannot see.
115
+ */
116
+ export declare function cadenceRank(cron: string | null | undefined): number;