@revenexx/studio-integrations 0.1.3 → 0.2.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 (180) hide show
  1. package/dist/module.json +1 -1
  2. package/dist/runtime/components/Integrations/CredentialCreateDialog.d.vue.ts +13 -0
  3. package/dist/runtime/components/Integrations/CredentialCreateDialog.vue +279 -0
  4. package/dist/runtime/components/Integrations/CredentialCreateDialog.vue.d.ts +13 -0
  5. package/dist/runtime/components/Integrations/CredentialDetailDialog.d.vue.ts +20 -0
  6. package/dist/runtime/components/Integrations/CredentialDetailDialog.vue +342 -0
  7. package/dist/runtime/components/Integrations/CredentialDetailDialog.vue.d.ts +20 -0
  8. package/dist/runtime/components/Integrations/CredentialLogo.d.vue.ts +14 -0
  9. package/dist/runtime/components/Integrations/CredentialLogo.vue +37 -0
  10. package/dist/runtime/components/Integrations/CredentialLogo.vue.d.ts +14 -0
  11. package/dist/runtime/components/Integrations/CredentialRevenexxSource.d.vue.ts +12 -0
  12. package/dist/runtime/components/Integrations/CredentialRevenexxSource.vue +364 -0
  13. package/dist/runtime/components/Integrations/CredentialRevenexxSource.vue.d.ts +12 -0
  14. package/dist/runtime/components/Integrations/CredentialTypePicker.d.vue.ts +15 -0
  15. package/dist/runtime/components/Integrations/CredentialTypePicker.vue +71 -0
  16. package/dist/runtime/components/Integrations/CredentialTypePicker.vue.d.ts +15 -0
  17. package/dist/runtime/components/Integrations/DeadLettersPanel.d.vue.ts +5 -0
  18. package/dist/runtime/components/Integrations/DeadLettersPanel.vue +151 -0
  19. package/dist/runtime/components/Integrations/DeadLettersPanel.vue.d.ts +5 -0
  20. package/dist/runtime/components/Integrations/EditorTip.d.vue.ts +17 -0
  21. package/dist/runtime/components/Integrations/EditorTip.vue +46 -0
  22. package/dist/runtime/components/Integrations/EditorTip.vue.d.ts +17 -0
  23. package/dist/runtime/components/Integrations/EventTypeCombobox.d.vue.ts +9 -0
  24. package/dist/runtime/components/Integrations/EventTypeCombobox.vue +64 -0
  25. package/dist/runtime/components/Integrations/EventTypeCombobox.vue.d.ts +9 -0
  26. package/dist/runtime/components/Integrations/ExpressionInput.d.vue.ts +19 -0
  27. package/dist/runtime/components/Integrations/ExpressionInput.vue +236 -0
  28. package/dist/runtime/components/Integrations/ExpressionInput.vue.d.ts +19 -0
  29. package/dist/runtime/components/Integrations/GroupFrameView.d.vue.ts +28 -0
  30. package/dist/runtime/components/Integrations/GroupFrameView.vue +222 -0
  31. package/dist/runtime/components/Integrations/GroupFrameView.vue.d.ts +28 -0
  32. package/dist/runtime/components/Integrations/NodeConfigDynamicField.d.vue.ts +14 -0
  33. package/dist/runtime/components/Integrations/NodeConfigDynamicField.vue +184 -0
  34. package/dist/runtime/components/Integrations/NodeConfigDynamicField.vue.d.ts +14 -0
  35. package/dist/runtime/components/Integrations/NodeConfigDynamicSchema.d.vue.ts +16 -0
  36. package/dist/runtime/components/Integrations/NodeConfigDynamicSchema.vue +102 -0
  37. package/dist/runtime/components/Integrations/NodeConfigDynamicSchema.vue.d.ts +16 -0
  38. package/dist/runtime/components/Integrations/NodeConfigField.d.vue.ts +23 -0
  39. package/dist/runtime/components/Integrations/NodeConfigField.vue +587 -0
  40. package/dist/runtime/components/Integrations/NodeConfigField.vue.d.ts +23 -0
  41. package/dist/runtime/components/Integrations/NodeDynamicOutputsResolver.d.vue.ts +14 -0
  42. package/dist/runtime/components/Integrations/NodeDynamicOutputsResolver.vue +80 -0
  43. package/dist/runtime/components/Integrations/NodeDynamicOutputsResolver.vue.d.ts +14 -0
  44. package/dist/runtime/components/Integrations/NodeInspector.d.vue.ts +22 -3
  45. package/dist/runtime/components/Integrations/NodeInspector.vue +1074 -294
  46. package/dist/runtime/components/Integrations/NodeInspector.vue.d.ts +22 -3
  47. package/dist/runtime/components/Integrations/NodeLogo.d.vue.ts +9 -0
  48. package/dist/runtime/components/Integrations/NodeLogo.vue +38 -0
  49. package/dist/runtime/components/Integrations/NodeLogo.vue.d.ts +9 -0
  50. package/dist/runtime/components/Integrations/NodePalette.d.vue.ts +22 -1
  51. package/dist/runtime/components/Integrations/NodePalette.vue +411 -90
  52. package/dist/runtime/components/Integrations/NodePalette.vue.d.ts +22 -1
  53. package/dist/runtime/components/Integrations/QueryBuilder.d.vue.ts +9 -0
  54. package/dist/runtime/components/Integrations/QueryBuilder.vue +239 -0
  55. package/dist/runtime/components/Integrations/QueryBuilder.vue.d.ts +9 -0
  56. package/dist/runtime/components/Integrations/{RunDetailDialog.d.vue.ts → RunActionsMenu.d.vue.ts} +3 -4
  57. package/dist/runtime/components/Integrations/RunActionsMenu.vue +86 -0
  58. package/dist/runtime/components/Integrations/{RunDetailDialog.vue.d.ts → RunActionsMenu.vue.d.ts} +3 -4
  59. package/dist/runtime/components/Integrations/RunDetailPanel.d.vue.ts +14 -0
  60. package/dist/runtime/components/Integrations/RunDetailPanel.vue +777 -0
  61. package/dist/runtime/components/Integrations/RunDetailPanel.vue.d.ts +14 -0
  62. package/dist/runtime/components/Integrations/RunPayloadInput.d.vue.ts +13 -0
  63. package/dist/runtime/components/Integrations/RunPayloadInput.vue +175 -0
  64. package/dist/runtime/components/Integrations/RunPayloadInput.vue.d.ts +13 -0
  65. package/dist/runtime/components/Integrations/RunResponseModal.d.vue.ts +27 -0
  66. package/dist/runtime/components/Integrations/RunResponseModal.vue +84 -0
  67. package/dist/runtime/components/Integrations/RunResponseModal.vue.d.ts +27 -0
  68. package/dist/runtime/components/Integrations/RunsTable.d.vue.ts +21 -0
  69. package/dist/runtime/components/Integrations/RunsTable.vue +114 -0
  70. package/dist/runtime/components/Integrations/RunsTable.vue.d.ts +21 -0
  71. package/dist/runtime/components/Integrations/SftpAccountImportDialog.d.vue.ts +11 -0
  72. package/dist/runtime/components/Integrations/SftpAccountImportDialog.vue +91 -0
  73. package/dist/runtime/components/Integrations/SftpAccountImportDialog.vue.d.ts +11 -0
  74. package/dist/runtime/components/Integrations/Sidebar.vue +1 -0
  75. package/dist/runtime/components/Integrations/StickyNoteView.d.vue.ts +28 -0
  76. package/dist/runtime/components/Integrations/StickyNoteView.vue +208 -0
  77. package/dist/runtime/components/Integrations/StickyNoteView.vue.d.ts +28 -0
  78. package/dist/runtime/components/Integrations/TemplateFlowPreview.d.vue.ts +29 -0
  79. package/dist/runtime/components/Integrations/TemplateFlowPreview.vue +201 -0
  80. package/dist/runtime/components/Integrations/TemplateFlowPreview.vue.d.ts +29 -0
  81. package/dist/runtime/components/Integrations/WorkflowContextMenu.d.vue.ts +32 -0
  82. package/dist/runtime/components/Integrations/WorkflowContextMenu.vue +138 -0
  83. package/dist/runtime/components/Integrations/WorkflowContextMenu.vue.d.ts +32 -0
  84. package/dist/runtime/components/Integrations/WorkflowCreateDialog.d.vue.ts +9 -0
  85. package/dist/runtime/components/Integrations/WorkflowCreateDialog.vue +322 -0
  86. package/dist/runtime/components/Integrations/WorkflowCreateDialog.vue.d.ts +9 -0
  87. package/dist/runtime/components/Integrations/WorkflowDuplicateDialog.d.vue.ts +18 -0
  88. package/dist/runtime/components/Integrations/WorkflowDuplicateDialog.vue +63 -0
  89. package/dist/runtime/components/Integrations/WorkflowDuplicateDialog.vue.d.ts +18 -0
  90. package/dist/runtime/components/Integrations/WorkflowEdgeView.d.vue.ts +12 -1
  91. package/dist/runtime/components/Integrations/WorkflowEdgeView.vue +68 -6
  92. package/dist/runtime/components/Integrations/WorkflowEdgeView.vue.d.ts +12 -1
  93. package/dist/runtime/components/Integrations/WorkflowEditor.d.vue.ts +8 -1
  94. package/dist/runtime/components/Integrations/WorkflowEditor.vue +1424 -144
  95. package/dist/runtime/components/Integrations/WorkflowEditor.vue.d.ts +8 -1
  96. package/dist/runtime/components/Integrations/WorkflowHistoryPanel.d.vue.ts +12 -0
  97. package/dist/runtime/components/Integrations/WorkflowHistoryPanel.vue +417 -0
  98. package/dist/runtime/components/Integrations/WorkflowHistoryPanel.vue.d.ts +12 -0
  99. package/dist/runtime/components/Integrations/WorkflowIconPicker.d.vue.ts +10 -0
  100. package/dist/runtime/components/Integrations/WorkflowIconPicker.vue +89 -0
  101. package/dist/runtime/components/Integrations/WorkflowIconPicker.vue.d.ts +10 -0
  102. package/dist/runtime/components/Integrations/WorkflowIconView.d.vue.ts +10 -0
  103. package/dist/runtime/components/Integrations/WorkflowIconView.vue +35 -0
  104. package/dist/runtime/components/Integrations/WorkflowIconView.vue.d.ts +10 -0
  105. package/dist/runtime/components/Integrations/WorkflowNodeView.d.vue.ts +5 -1
  106. package/dist/runtime/components/Integrations/WorkflowNodeView.vue +114 -84
  107. package/dist/runtime/components/Integrations/WorkflowNodeView.vue.d.ts +5 -1
  108. package/dist/runtime/components/Integrations/WorkflowRunReplayPanel.d.vue.ts +12 -0
  109. package/dist/runtime/components/Integrations/WorkflowRunReplayPanel.vue +654 -0
  110. package/dist/runtime/components/Integrations/WorkflowRunReplayPanel.vue.d.ts +12 -0
  111. package/dist/runtime/components/Integrations/WorkflowSettingsDialog.d.vue.ts +36 -0
  112. package/dist/runtime/components/Integrations/WorkflowSettingsDialog.vue +136 -0
  113. package/dist/runtime/components/Integrations/WorkflowSettingsDialog.vue.d.ts +36 -0
  114. package/dist/runtime/components/Integrations/WorkflowTagsInput.d.vue.ts +14 -0
  115. package/dist/runtime/components/Integrations/WorkflowTagsInput.vue +63 -0
  116. package/dist/runtime/components/Integrations/WorkflowTagsInput.vue.d.ts +14 -0
  117. package/dist/runtime/components/Integrations/WorkflowTriggerView.vue +35 -15
  118. package/dist/runtime/components/Integrations/WorkflowVariablesDialog.d.vue.ts +13 -0
  119. package/dist/runtime/components/Integrations/WorkflowVariablesDialog.vue +265 -0
  120. package/dist/runtime/components/Integrations/WorkflowVariablesDialog.vue.d.ts +13 -0
  121. package/dist/runtime/components/Integrations/WorkflowsTable.d.vue.ts +4 -1
  122. package/dist/runtime/components/Integrations/WorkflowsTable.vue +122 -39
  123. package/dist/runtime/components/Integrations/WorkflowsTable.vue.d.ts +4 -1
  124. package/dist/runtime/components/Integrations/workflowLayout.d.ts +5 -0
  125. package/dist/runtime/components/Integrations/workflowLayout.js +5 -3
  126. package/dist/runtime/composables/integrationsApi.d.ts +6 -2
  127. package/dist/runtime/composables/integrationsApi.js +5 -4
  128. package/dist/runtime/composables/useCanvasShortcuts.d.ts +37 -0
  129. package/dist/runtime/composables/useCanvasShortcuts.js +62 -0
  130. package/dist/runtime/composables/useIntegrationsDeadLetters.d.ts +22 -0
  131. package/dist/runtime/composables/useIntegrationsDeadLetters.js +50 -0
  132. package/dist/runtime/composables/useIntegrationsNodes.d.ts +4 -0
  133. package/dist/runtime/composables/useIntegrationsNodes.js +6 -3
  134. package/dist/runtime/composables/useIntegrationsRevisions.d.ts +40 -0
  135. package/dist/runtime/composables/useIntegrationsRevisions.js +51 -0
  136. package/dist/runtime/composables/useIntegrationsRuns.d.ts +21 -1
  137. package/dist/runtime/composables/useIntegrationsRuns.js +92 -4
  138. package/dist/runtime/composables/useIntegrationsTemplates.d.ts +1 -0
  139. package/dist/runtime/composables/useIntegrationsTemplates.js +32 -4
  140. package/dist/runtime/composables/useIntegrationsWorkflows.d.ts +1 -0
  141. package/dist/runtime/composables/useIntegrationsWorkflows.js +57 -1
  142. package/dist/runtime/composables/useMiniMapLayout.d.ts +34 -0
  143. package/dist/runtime/composables/useMiniMapLayout.js +119 -0
  144. package/dist/runtime/composables/useNodeConfigResolve.d.ts +43 -0
  145. package/dist/runtime/composables/useNodeConfigResolve.js +123 -0
  146. package/dist/runtime/composables/useNodeDrag.d.ts +22 -0
  147. package/dist/runtime/composables/useNodeDrag.js +10 -0
  148. package/dist/runtime/composables/usePaletteLayout.d.ts +41 -0
  149. package/dist/runtime/composables/usePaletteLayout.js +113 -0
  150. package/dist/runtime/data/expressionEditor.d.ts +22 -0
  151. package/dist/runtime/data/expressionEditor.js +40 -0
  152. package/dist/runtime/data/integrationNodeCatalog.js +8 -8
  153. package/dist/runtime/data/nodeInputData.d.ts +37 -0
  154. package/dist/runtime/data/nodeInputData.js +62 -0
  155. package/dist/runtime/data/nodeRunData.d.ts +56 -0
  156. package/dist/runtime/data/nodeRunData.js +91 -0
  157. package/dist/runtime/data/payloadForm.d.ts +44 -0
  158. package/dist/runtime/data/payloadForm.js +126 -0
  159. package/dist/runtime/data/workflowIconCatalog.d.ts +34 -0
  160. package/dist/runtime/data/workflowIconCatalog.js +116 -0
  161. package/dist/runtime/pages/integrations/audit.vue +25 -35
  162. package/dist/runtime/pages/integrations/credentials.vue +117 -122
  163. package/dist/runtime/pages/integrations/index.vue +133 -36
  164. package/dist/runtime/pages/integrations/runs.vue +125 -75
  165. package/dist/runtime/pages/integrations/schedules.vue +5 -16
  166. package/dist/runtime/pages/integrations/secrets.vue +1 -3
  167. package/dist/runtime/pages/integrations/workflows/[id].vue +599 -194
  168. package/dist/runtime/pages/integrations/workflows/index.vue +10 -8
  169. package/dist/runtime/types/integrations.d.ts +190 -4
  170. package/dist/runtime/utils/credentialState.d.ts +28 -0
  171. package/dist/runtime/utils/credentialState.js +29 -0
  172. package/dist/runtime/utils/localize.d.ts +3 -1
  173. package/dist/runtime/utils/localize.js +1 -2
  174. package/dist/runtime/utils/statusStyle.d.ts +6 -0
  175. package/dist/runtime/utils/statusStyle.js +15 -0
  176. package/package.json +12 -2
  177. package/dist/runtime/components/Integrations/RunDetailDialog.vue +0 -169
  178. package/dist/runtime/pages/integrations/workflows/new.d.vue.ts +0 -2
  179. package/dist/runtime/pages/integrations/workflows/new.vue +0 -153
  180. package/dist/runtime/pages/integrations/workflows/new.vue.d.ts +0 -2
@@ -0,0 +1,20 @@
1
+ import type { Credential, CredentialType } from '../../types/integrations.js';
2
+ /**
3
+ * Credential detail / edit view — a single scrolling page (no tabs): the
4
+ * connection state up top, the editable fields, then read-only metadata.
5
+ * Self-contained — owns update / delete / test / OAuth reconnect against the
6
+ * Integrations service via the shared composable.
7
+ */
8
+ type __VLS_Props = {
9
+ open: boolean;
10
+ credential: Credential | null;
11
+ type: CredentialType | null;
12
+ };
13
+ declare const _default: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
14
+ "update:open": (args_0: boolean) => any;
15
+ changed: () => any;
16
+ }, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
17
+ "onUpdate:open"?: ((args_0: boolean) => any) | undefined;
18
+ onChanged?: (() => any) | undefined;
19
+ }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
20
+ export default _default;
@@ -0,0 +1,14 @@
1
+ import type { CredentialType } from '../../types/integrations.js';
2
+ /**
3
+ * A credential type's brand logo. Renders the `logo` image from the type's
4
+ * `images[]` (a short-lived signed URL from the credential-types API), falling
5
+ * back to a generic key glyph when no image is present or the image fails to
6
+ * load (expired signature / 404). This is the single place that knows how a
7
+ * credential type renders its icon.
8
+ */
9
+ type __VLS_Props = {
10
+ type?: CredentialType | null;
11
+ size?: number;
12
+ };
13
+ declare const _default: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
14
+ export default _default;
@@ -0,0 +1,37 @@
1
+ <script setup>
2
+ import { computed, ref, watch } from "vue";
3
+ import { ShieldKeyhole as KeyIcon } from "#solar-icons";
4
+ const props = defineProps({
5
+ type: { type: [Object, null], required: false },
6
+ size: { type: Number, required: false }
7
+ });
8
+ const box = computed(() => (props.size ?? 16) + 16);
9
+ const glyph = computed(() => props.size ?? 16);
10
+ const logoSrc = computed(() => {
11
+ const imgs = props.type?.images;
12
+ if (!imgs?.length) return null;
13
+ const pick = imgs.find((i) => i.category === "logo") ?? imgs[0];
14
+ return typeof pick?.src === "string" && pick.src ? pick.src : null;
15
+ });
16
+ const failed = ref(false);
17
+ watch(logoSrc, () => {
18
+ failed.value = false;
19
+ });
20
+ const showImg = computed(() => !!logoSrc.value && !failed.value);
21
+ </script>
22
+
23
+ <template>
24
+ <span
25
+ class="flex items-center justify-center overflow-hidden rounded-md bg-slate-100 text-slate-500 shrink-0"
26
+ :style="{ width: `${box}px`, height: `${box}px` }"
27
+ >
28
+ <img
29
+ v-if="showImg"
30
+ :src="logoSrc"
31
+ alt=""
32
+ class="h-full w-full object-contain p-0.5"
33
+ @error="failed = true"
34
+ >
35
+ <KeyIcon v-else :size="glyph" />
36
+ </span>
37
+ </template>
@@ -0,0 +1,14 @@
1
+ import type { CredentialType } from '../../types/integrations.js';
2
+ /**
3
+ * A credential type's brand logo. Renders the `logo` image from the type's
4
+ * `images[]` (a short-lived signed URL from the credential-types API), falling
5
+ * back to a generic key glyph when no image is present or the image fails to
6
+ * load (expired signature / 404). This is the single place that knows how a
7
+ * credential type renders its icon.
8
+ */
9
+ type __VLS_Props = {
10
+ type?: CredentialType | null;
11
+ size?: number;
12
+ };
13
+ declare const _default: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
14
+ export default _default;
@@ -0,0 +1,12 @@
1
+ import type { CredentialType } from '../../types/integrations.js';
2
+ type __VLS_Props = {
3
+ type: CredentialType | null;
4
+ };
5
+ declare const _default: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
6
+ "update:active": (args_0: boolean) => any;
7
+ apply: (args_0: Record<string, unknown>) => any;
8
+ }, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
9
+ "onUpdate:active"?: ((args_0: boolean) => any) | undefined;
10
+ onApply?: ((args_0: Record<string, unknown>) => any) | undefined;
11
+ }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
12
+ export default _default;
@@ -0,0 +1,364 @@
1
+ <script setup>
2
+ import { computed, reactive, ref, watch } from "vue";
3
+ import {
4
+ AddCircle as Plus,
5
+ CheckCircle as Check,
6
+ RefreshCircle as Loader2
7
+ } from "#solar-icons";
8
+ import {
9
+ Button,
10
+ Dialog,
11
+ DialogContent,
12
+ DialogDescription,
13
+ DialogFooter,
14
+ DialogHeader,
15
+ DialogTitle,
16
+ Input,
17
+ Label,
18
+ Switch,
19
+ Select,
20
+ SelectContent,
21
+ SelectItem,
22
+ SelectTrigger,
23
+ SelectValue
24
+ } from "@revenexx/studio";
25
+ import { toast } from "vue-sonner";
26
+ const props = defineProps({
27
+ type: { type: [Object, null], required: true }
28
+ });
29
+ const emit = defineEmits(["update:active", "apply"]);
30
+ const KIND_BY_SLUG = {
31
+ "revenexx:sftp": "sftp",
32
+ "revenexx:smtp": "smtp",
33
+ "revenexx:api": "api"
34
+ };
35
+ const kind = computed(() => props.type ? KIND_BY_SLUG[props.type.slug] ?? null : null);
36
+ const SWITCH_LABEL = {
37
+ sftp: "Use revenexx SFTP Servers",
38
+ smtp: "Use revenexx Mail Servers",
39
+ api: "Use revenexx API Keys"
40
+ };
41
+ const NEW_LABEL = {
42
+ sftp: "New SFTP account",
43
+ smtp: "New mail credential",
44
+ api: "New API key"
45
+ };
46
+ const { tenants, onlyTenantSlug, load: loadTenants } = useConsoleTenants();
47
+ const { markets, activeCode, isGlobal, GLOBAL_MARKET_CODE, fetchMarkets } = useActiveMarket();
48
+ const sftp = useConsoleSftp();
49
+ const mail = useMailAdmin();
50
+ const consoleKeys = useConsoleApiKeys();
51
+ const config = useRuntimeConfig();
52
+ const sftpHost = config.public.sftpHost ?? "share.revenexx.com";
53
+ const sftpPort = Number(config.public.sftpPort ?? 42);
54
+ const mailSmtpHost = config.public.mailSmtpHost ?? "mail.rvnxx.com";
55
+ const mailSmtpPort = Number(config.public.mailSmtpPort ?? 587);
56
+ const active = ref(false);
57
+ const tenant = ref(null);
58
+ const marketCode = ref(GLOBAL_MARKET_CODE);
59
+ const selectedId = ref("");
60
+ const loadingList = ref(false);
61
+ const applying = ref(false);
62
+ const applied = ref(null);
63
+ const smtpCreds = ref([]);
64
+ watch(active, (v) => emit("update:active", v));
65
+ watch(kind, () => {
66
+ active.value = false;
67
+ selectedId.value = "";
68
+ applied.value = null;
69
+ });
70
+ const sftpOptions = computed(() => sftp.accounts.value.filter((a) => (a.is_active || a.status === "active") && a.login_username).map((a) => ({ value: String(a.id), label: a.login_username })));
71
+ const marketOptions = computed(() => [
72
+ { code: GLOBAL_MARKET_CODE, label: "Global (tenant baseline)" },
73
+ ...markets.value.map((m) => ({ code: m.code, label: `${m.name} (${m.code})` }))
74
+ ]);
75
+ async function ensureLists() {
76
+ loadingList.value = true;
77
+ try {
78
+ await loadTenants();
79
+ if (!tenant.value) tenant.value = onlyTenantSlug.value ?? tenants.value[0]?.slug ?? null;
80
+ if (kind.value === "sftp") await sftp.load(tenant.value);
81
+ else if (kind.value === "smtp") {
82
+ const list = await mail.listCredentials();
83
+ smtpCreds.value = (list ?? []).filter((c) => c.type === "SMTP").map((c) => ({ uuid: c.uuid, name: c.name }));
84
+ } else if (kind.value === "api") {
85
+ marketCode.value = activeCode.value;
86
+ await fetchMarkets();
87
+ }
88
+ } catch (e) {
89
+ toast.error(e?.message ?? "Could not load revenexx resources.");
90
+ } finally {
91
+ loadingList.value = false;
92
+ }
93
+ }
94
+ watch(active, (on) => {
95
+ if (on) void ensureLists();
96
+ });
97
+ function marketSlug() {
98
+ return marketCode.value === GLOBAL_MARKET_CODE ? "" : marketCode.value;
99
+ }
100
+ async function applySftp() {
101
+ const t = tenant.value;
102
+ const acc = sftp.accounts.value.find((a) => String(a.id) === selectedId.value);
103
+ if (!t || !acc) return;
104
+ applying.value = true;
105
+ try {
106
+ const creds = await sftp.revealPassword(t, acc.id);
107
+ if (!creds) {
108
+ toast.error("Account still provisioning \u2014 try again in a moment.");
109
+ return;
110
+ }
111
+ emit("apply", {
112
+ host: sftpHost,
113
+ port: sftpPort,
114
+ username: acc.login_username ?? creds.username,
115
+ password: creds.password
116
+ });
117
+ applied.value = `${acc.login_username}@${sftpHost}:${sftpPort}`;
118
+ } catch (e) {
119
+ toast.error(e?.message ?? "Could not read the SFTP password.");
120
+ } finally {
121
+ applying.value = false;
122
+ }
123
+ }
124
+ async function applySmtp() {
125
+ applying.value = true;
126
+ try {
127
+ const cred = await mail.getCredential(selectedId.value);
128
+ emit("apply", {
129
+ host: mailSmtpHost,
130
+ port: mailSmtpPort,
131
+ user: cred.smtp_username ?? "",
132
+ password: cred.smtp_password ?? "",
133
+ secure: mailSmtpPort === 465
134
+ });
135
+ applied.value = `${cred.smtp_username}@${mailSmtpHost}:${mailSmtpPort}`;
136
+ } catch (e) {
137
+ toast.error(e?.message ?? "Could not read the mail credential.");
138
+ } finally {
139
+ applying.value = false;
140
+ }
141
+ }
142
+ function onSelect(id) {
143
+ selectedId.value = id;
144
+ if (!id) {
145
+ applied.value = null;
146
+ return;
147
+ }
148
+ if (kind.value === "sftp") void applySftp();
149
+ else if (kind.value === "smtp") void applySmtp();
150
+ }
151
+ watch([tenant, marketCode], () => {
152
+ if (active.value && kind.value === "api" && apiKeyReady.value) {
153
+ emit("apply", { tenant: tenant.value ?? "", market: marketSlug() });
154
+ }
155
+ });
156
+ const createOpen = ref(false);
157
+ const creating = ref(false);
158
+ const createName = ref("");
159
+ const provisioningNote = ref("");
160
+ const apiKeyReady = ref(false);
161
+ function openCreate() {
162
+ createName.value = "";
163
+ provisioningNote.value = "";
164
+ createOpen.value = true;
165
+ }
166
+ const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
167
+ async function createSftp() {
168
+ const t = tenant.value;
169
+ if (!t) {
170
+ toast.error("No tenant selected.");
171
+ return;
172
+ }
173
+ creating.value = true;
174
+ try {
175
+ let acc = await sftp.create(t, createName.value.trim() || void 0);
176
+ for (let i = 0; i < 24 && !(acc.is_active || acc.status === "active"); i++) {
177
+ provisioningNote.value = "Provisioning the account\u2026";
178
+ await sleep(2500);
179
+ acc = await sftp.refresh(t, acc.id);
180
+ if (acc.status === "failed") throw new Error(acc.error_message || "Provisioning failed.");
181
+ }
182
+ if (!(acc.is_active || acc.status === "active")) {
183
+ throw new Error("Still provisioning \u2014 pick it from the list once it turns active.");
184
+ }
185
+ await sftp.load(t);
186
+ selectedId.value = String(acc.id);
187
+ await applySftp();
188
+ createOpen.value = false;
189
+ toast.success("SFTP account created");
190
+ } catch (e) {
191
+ toast.error(e?.message ?? "Could not create the SFTP account.");
192
+ } finally {
193
+ creating.value = false;
194
+ provisioningNote.value = "";
195
+ }
196
+ }
197
+ async function createSmtp() {
198
+ creating.value = true;
199
+ try {
200
+ const cred = await mail.createCredential({ name: createName.value.trim() || "SMTP", type: "SMTP" });
201
+ emit("apply", {
202
+ host: mailSmtpHost,
203
+ port: mailSmtpPort,
204
+ user: cred.smtp_username ?? "",
205
+ password: cred.smtp_password ?? "",
206
+ secure: mailSmtpPort === 465
207
+ });
208
+ applied.value = `${cred.smtp_username}@${mailSmtpHost}:${mailSmtpPort}`;
209
+ smtpCreds.value = [{ uuid: cred.uuid, name: cred.name }, ...smtpCreds.value];
210
+ selectedId.value = cred.uuid;
211
+ createOpen.value = false;
212
+ toast.success("Mail credential created");
213
+ } catch (e) {
214
+ toast.error(e?.message ?? "Could not create the mail credential.");
215
+ } finally {
216
+ creating.value = false;
217
+ }
218
+ }
219
+ async function createApiKey() {
220
+ creating.value = true;
221
+ try {
222
+ const { secret } = await consoleKeys.create(createName.value.trim() || "Integrations key", ["*"]);
223
+ emit("apply", { apiKey: secret, tenant: tenant.value ?? "", market: marketSlug() });
224
+ apiKeyReady.value = true;
225
+ applied.value = `Key for ${tenant.value}${marketSlug() ? ` \xB7 ${marketSlug()}` : " \xB7 global"}`;
226
+ createOpen.value = false;
227
+ toast.success("API key created");
228
+ } catch (e) {
229
+ toast.error(e?.message ?? "Could not create the API key.");
230
+ } finally {
231
+ creating.value = false;
232
+ }
233
+ }
234
+ function submitCreate() {
235
+ if (kind.value === "sftp") void createSftp();
236
+ else if (kind.value === "smtp") void createSmtp();
237
+ else if (kind.value === "api") void createApiKey();
238
+ }
239
+ </script>
240
+
241
+ <template>
242
+ <div v-if="kind" class="rounded-lg border border-black/[0.08] bg-muted/20 p-3">
243
+ <!-- Switch header -->
244
+ <div class="flex items-center justify-between gap-3">
245
+ <div class="min-w-0">
246
+ <div class="text-sm font-medium">{{ SWITCH_LABEL[kind] }}</div>
247
+ <p class="text-xs text-muted-foreground">
248
+ Reuse an existing revenexx resource instead of typing access data by hand.
249
+ </p>
250
+ </div>
251
+ <Switch :model-value="active" @update:model-value="(v) => active = v" />
252
+ </div>
253
+
254
+ <div v-if="active" class="mt-3 space-y-3">
255
+ <!-- Tenant (preselected) -->
256
+ <div class="space-y-1.5">
257
+ <Label>Tenant</Label>
258
+ <Select :model-value="tenant ?? ''" @update:model-value="(v) => tenant = v">
259
+ <SelectTrigger class="bg-white">
260
+ <SelectValue placeholder="Select tenant" />
261
+ </SelectTrigger>
262
+ <SelectContent>
263
+ <SelectItem v-for="t in tenants" :key="t.slug" :value="t.slug">
264
+ {{ t.name }} ({{ t.slug }})
265
+ </SelectItem>
266
+ </SelectContent>
267
+ </Select>
268
+ </div>
269
+
270
+ <!-- Market scope — only the Revenexx API credential is market-scoped -->
271
+ <div v-if="kind === 'api'" class="space-y-1.5">
272
+ <Label>Market</Label>
273
+ <Select :model-value="marketCode" @update:model-value="(v) => marketCode = v">
274
+ <SelectTrigger class="bg-white">
275
+ <SelectValue placeholder="Select market" />
276
+ </SelectTrigger>
277
+ <SelectContent>
278
+ <SelectItem v-for="m in marketOptions" :key="m.code" :value="m.code">
279
+ {{ m.label }}
280
+ </SelectItem>
281
+ </SelectContent>
282
+ </Select>
283
+ </div>
284
+
285
+ <!-- Resource select (SFTP / Mail) -->
286
+ <div v-if="kind === 'sftp' || kind === 'smtp'" class="space-y-1.5">
287
+ <Label>{{ kind === "sftp" ? "SFTP account" : "Mail credential" }}</Label>
288
+ <div class="flex items-center gap-2">
289
+ <Select :model-value="selectedId" class="flex-1" @update:model-value="(v) => onSelect(v)">
290
+ <SelectTrigger class="bg-white">
291
+ <SelectValue :placeholder="loadingList ? 'Loading\u2026' : 'Select one'" />
292
+ </SelectTrigger>
293
+ <SelectContent>
294
+ <template v-if="kind === 'sftp'">
295
+ <SelectItem v-for="o in sftpOptions" :key="o.value" :value="o.value">{{ o.label }}</SelectItem>
296
+ </template>
297
+ <template v-else>
298
+ <SelectItem v-for="c in smtpCreds" :key="c.uuid" :value="c.uuid">{{ c.name }}</SelectItem>
299
+ </template>
300
+ </SelectContent>
301
+ </Select>
302
+ <Button variant="outline" size="sm" class="shrink-0 bg-white" :disabled="!tenant" @click="openCreate">
303
+ <Plus :size="14" class="mr-1" />
304
+ New
305
+ </Button>
306
+ </div>
307
+ </div>
308
+
309
+ <!-- API key: no existing selection (secret can't be read back) -->
310
+ <div v-else-if="kind === 'api'">
311
+ <Button variant="outline" size="sm" class="bg-white" :disabled="!tenant" @click="openCreate">
312
+ <Plus :size="14" class="mr-1" />
313
+ Create new API key
314
+ </Button>
315
+ </div>
316
+
317
+ <!-- Applied summary -->
318
+ <div v-if="applied || applying" class="flex items-center gap-2 rounded-md bg-emerald-500/10 px-3 py-2 text-sm text-emerald-700">
319
+ <Loader2 v-if="applying" :size="14" class="animate-spin" />
320
+ <Check v-else :size="14" />
321
+ <span class="truncate">{{ applying ? "Copying access data\u2026" : `Using ${applied}` }}</span>
322
+ </div>
323
+ </div>
324
+
325
+ <!-- Stacked "New …" lightbox -->
326
+ <Dialog v-model:open="createOpen">
327
+ <DialogContent class="sm:max-w-md">
328
+ <DialogHeader>
329
+ <DialogTitle>{{ kind ? NEW_LABEL[kind] : "New" }}</DialogTitle>
330
+ <DialogDescription class="text-sm">
331
+ <template v-if="kind === 'api'">
332
+ A full-access key is minted for <b>{{ tenant }}</b> and copied straight into this credential.
333
+ </template>
334
+ <template v-else-if="kind === 'sftp'">
335
+ Reserves a new SFTP account for <b>{{ tenant }}</b> and fills its login here.
336
+ </template>
337
+ <template v-else>
338
+ Creates a new SMTP credential and fills its login here.
339
+ </template>
340
+ </DialogDescription>
341
+ </DialogHeader>
342
+
343
+ <div class="space-y-1.5 py-1">
344
+ <Label for="rvnxx-new-name">{{ kind === "sftp" ? "Label" : "Name" }}</Label>
345
+ <Input
346
+ id="rvnxx-new-name"
347
+ v-model="createName"
348
+ class="bg-white"
349
+ :placeholder="kind === 'sftp' ? 'e.g. imports' : 'e.g. Production'"
350
+ />
351
+ <p v-if="provisioningNote" class="text-xs text-muted-foreground">{{ provisioningNote }}</p>
352
+ </div>
353
+
354
+ <DialogFooter>
355
+ <Button variant="ghost" :disabled="creating" @click="createOpen = false">Cancel</Button>
356
+ <Button :disabled="creating" @click="submitCreate">
357
+ <Loader2 v-if="creating" :size="14" class="mr-1 animate-spin" />
358
+ Create
359
+ </Button>
360
+ </DialogFooter>
361
+ </DialogContent>
362
+ </Dialog>
363
+ </div>
364
+ </template>
@@ -0,0 +1,12 @@
1
+ import type { CredentialType } from '../../types/integrations.js';
2
+ type __VLS_Props = {
3
+ type: CredentialType | null;
4
+ };
5
+ declare const _default: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
6
+ "update:active": (args_0: boolean) => any;
7
+ apply: (args_0: Record<string, unknown>) => any;
8
+ }, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
9
+ "onUpdate:active"?: ((args_0: boolean) => any) | undefined;
10
+ onApply?: ((args_0: Record<string, unknown>) => any) | undefined;
11
+ }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
12
+ export default _default;
@@ -0,0 +1,15 @@
1
+ import type { CredentialType } from '../../types/integrations.js';
2
+ /**
3
+ * Scalable credential-type picker — a searchable list ("Search for app…") that
4
+ * scales to ~1000 types where a card grid would not. Client-side filter over the
5
+ * already-loaded catalogue; no debounce needed.
6
+ */
7
+ type __VLS_Props = {
8
+ types: CredentialType[];
9
+ };
10
+ declare const _default: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
11
+ pick: (args_0: CredentialType) => any;
12
+ }, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
13
+ onPick?: ((args_0: CredentialType) => any) | undefined;
14
+ }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
15
+ export default _default;
@@ -0,0 +1,71 @@
1
+ <script setup>
2
+ import { computed, ref } from "vue";
3
+ import { Magnifier as Search } from "#solar-icons";
4
+ import { Input } from "@revenexx/studio";
5
+ const props = defineProps({
6
+ types: { type: Array, required: true }
7
+ });
8
+ const emit = defineEmits(["pick"]);
9
+ const query = ref("");
10
+ function loc(v) {
11
+ if (!v) return "";
12
+ if (typeof v === "string") return v;
13
+ const o = v;
14
+ return o.en ?? o.de ?? Object.values(o)[0] ?? "";
15
+ }
16
+ function authKindLabel(k) {
17
+ switch (k) {
18
+ case "api-key":
19
+ return "API Key";
20
+ case "oauth2-authcode":
21
+ case "oauth2-client-credentials":
22
+ return "OAuth2";
23
+ case "basic-auth":
24
+ return "Basic Auth";
25
+ case "static":
26
+ return "Static";
27
+ case "secret":
28
+ return "Secret";
29
+ default:
30
+ return k ?? "";
31
+ }
32
+ }
33
+ const filtered = computed(() => {
34
+ const q = query.value.trim().toLowerCase();
35
+ if (!q) return props.types;
36
+ return props.types.filter((t) => loc(t.name).toLowerCase().includes(q));
37
+ });
38
+ </script>
39
+
40
+ <template>
41
+ <div class="py-1">
42
+ <div class="relative">
43
+ <Search :size="15" class="absolute left-3 top-1/2 -translate-y-1/2 text-muted-foreground" />
44
+ <Input
45
+ v-model="query"
46
+ class="bg-white pl-9"
47
+ placeholder="Search for an app…"
48
+ autofocus
49
+ />
50
+ </div>
51
+
52
+ <div class="mt-2 max-h-80 overflow-y-auto -mx-1 px-1">
53
+ <p v-if="!filtered.length" class="px-2 py-6 text-center text-sm text-muted-foreground">
54
+ No credential type matches “{{ query }}”.
55
+ </p>
56
+ <button
57
+ v-for="t in filtered"
58
+ :key="t.slug"
59
+ type="button"
60
+ class="flex w-full items-center gap-2.5 rounded-md px-2 py-2 text-left transition hover:bg-muted/50"
61
+ @click="emit('pick', t)"
62
+ >
63
+ <IntegrationsCredentialLogo :type="t" :size="16" />
64
+ <div class="min-w-0 flex-1 truncate text-sm">
65
+ <span class="font-medium">{{ loc(t.name) || t.slug }}</span>
66
+ <span class="ml-1.5 text-muted-foreground">({{ authKindLabel(t.auth_kind) }})</span>
67
+ </div>
68
+ </button>
69
+ </div>
70
+ </div>
71
+ </template>
@@ -0,0 +1,15 @@
1
+ import type { CredentialType } from '../../types/integrations.js';
2
+ /**
3
+ * Scalable credential-type picker — a searchable list ("Search for app…") that
4
+ * scales to ~1000 types where a card grid would not. Client-side filter over the
5
+ * already-loaded catalogue; no debounce needed.
6
+ */
7
+ type __VLS_Props = {
8
+ types: CredentialType[];
9
+ };
10
+ declare const _default: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
11
+ pick: (args_0: CredentialType) => any;
12
+ }, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
13
+ onPick?: ((args_0: CredentialType) => any) | undefined;
14
+ }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
15
+ export default _default;
@@ -0,0 +1,5 @@
1
+ type __VLS_Props = {
2
+ workflowId: number;
3
+ };
4
+ declare const _default: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
5
+ export default _default;