@revenexx/studio-integrations 0.6.0 → 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.
- package/CHANGELOG.md +227 -0
- package/README.md +31 -0
- package/dist/module.d.mts +17 -1
- package/dist/module.json +1 -1
- package/dist/module.mjs +10 -2
- package/dist/runtime/components/Integrations/CredentialCreateDialog.vue +29 -28
- package/dist/runtime/components/Integrations/CredentialDetailDialog.vue +38 -37
- package/dist/runtime/components/Integrations/CredentialRevenexxSource.vue +58 -58
- package/dist/runtime/components/Integrations/CredentialTypePicker.vue +10 -9
- package/dist/runtime/components/Integrations/DeadLettersPanel.vue +18 -17
- package/dist/runtime/components/Integrations/EventTypeCombobox.vue +4 -3
- package/dist/runtime/components/Integrations/ExpressionInput.vue +16 -15
- package/dist/runtime/components/Integrations/GroupFrameView.vue +29 -19
- package/dist/runtime/components/Integrations/Layout.vue +28 -3
- package/dist/runtime/components/Integrations/NodeConfigDynamicField.vue +15 -14
- package/dist/runtime/components/Integrations/NodeConfigDynamicSchema.vue +9 -8
- package/dist/runtime/components/Integrations/NodeConfigField.vue +43 -42
- package/dist/runtime/components/Integrations/NodeInspector.vue +225 -216
- package/dist/runtime/components/Integrations/NodeOutputSchema.d.vue.ts +1 -1
- package/dist/runtime/components/Integrations/NodeOutputSchema.vue +3 -2
- package/dist/runtime/components/Integrations/NodeOutputSchema.vue.d.ts +1 -1
- package/dist/runtime/components/Integrations/NodePalette.vue +30 -29
- package/dist/runtime/components/Integrations/QueryBuilder.vue +44 -43
- package/dist/runtime/components/Integrations/RunActionsMenu.vue +36 -12
- package/dist/runtime/components/Integrations/RunDetailPanel.vue +114 -62
- package/dist/runtime/components/Integrations/RunPayloadInput.vue +14 -13
- package/dist/runtime/components/Integrations/RunResponseModal.vue +11 -10
- package/dist/runtime/components/Integrations/RunsTable.d.vue.ts +0 -1
- package/dist/runtime/components/Integrations/RunsTable.vue +38 -16
- package/dist/runtime/components/Integrations/RunsTable.vue.d.ts +0 -1
- package/dist/runtime/components/Integrations/SftpAccountImportDialog.vue +8 -7
- package/dist/runtime/components/Integrations/Sidebar.vue +14 -10
- package/dist/runtime/components/Integrations/StickyNoteView.d.vue.ts +14 -4
- package/dist/runtime/components/Integrations/StickyNoteView.vue +37 -23
- package/dist/runtime/components/Integrations/StickyNoteView.vue.d.ts +14 -4
- package/dist/runtime/components/Integrations/TemplateCard.vue +16 -6
- package/dist/runtime/components/Integrations/TemplateFlowPreview.vue +10 -9
- package/dist/runtime/components/Integrations/WorkflowContextMenu.vue +34 -33
- package/dist/runtime/components/Integrations/WorkflowCreateDialog.vue +36 -35
- package/dist/runtime/components/Integrations/WorkflowDuplicateDialog.vue +8 -7
- package/dist/runtime/components/Integrations/WorkflowEdgeView.vue +6 -4
- package/dist/runtime/components/Integrations/WorkflowEditor.vue +82 -79
- package/dist/runtime/components/Integrations/WorkflowHistoryPanel.vue +24 -23
- package/dist/runtime/components/Integrations/WorkflowIconPicker.vue +7 -6
- package/dist/runtime/components/Integrations/WorkflowNodeView.vue +19 -20
- package/dist/runtime/components/Integrations/WorkflowRunReplayPanel.vue +52 -39
- package/dist/runtime/components/Integrations/WorkflowSettingsDialog.vue +20 -19
- package/dist/runtime/components/Integrations/WorkflowTagsInput.vue +9 -8
- package/dist/runtime/components/Integrations/WorkflowTriggerView.vue +12 -9
- package/dist/runtime/components/Integrations/WorkflowVariablesDialog.vue +27 -26
- package/dist/runtime/components/Integrations/WorkflowsTable.vue +83 -45
- package/dist/runtime/composables/integrationsApi.js +4 -2
- package/dist/runtime/composables/useCredentialTypes.js +4 -2
- package/dist/runtime/composables/useIntegrationsCredentials.js +6 -4
- package/dist/runtime/composables/useIntegrationsFocus.d.ts +12 -0
- package/dist/runtime/composables/useIntegrationsLocale.d.ts +26 -0
- package/dist/runtime/composables/useIntegrationsLocale.js +8 -0
- package/dist/runtime/composables/useIntegrationsNodes.js +3 -1
- package/dist/runtime/composables/useIntegrationsRealtime.d.ts +149 -0
- package/dist/runtime/composables/useIntegrationsRealtime.js +80 -0
- package/dist/runtime/composables/useIntegrationsRevisions.js +9 -7
- package/dist/runtime/composables/useIntegrationsRuns.d.ts +1 -1
- package/dist/runtime/composables/useIntegrationsRuns.js +3 -1
- package/dist/runtime/composables/useIntegrationsSecrets.js +4 -2
- package/dist/runtime/composables/useIntegrationsT.d.ts +35 -0
- package/dist/runtime/composables/useIntegrationsT.js +9 -0
- package/dist/runtime/composables/useIntegrationsTemplates.d.ts +3 -3
- package/dist/runtime/composables/useIntegrationsTemplates.js +16 -8
- package/dist/runtime/composables/useIntegrationsTriggers.js +4 -2
- package/dist/runtime/composables/useIntegrationsWorkflows.js +5 -3
- package/dist/runtime/composables/useNodeConfigResolve.js +2 -1
- package/dist/runtime/data/integrationNodeCatalog.d.ts +41 -0
- package/dist/runtime/data/integrationNodeCatalog.js +14 -0
- package/dist/runtime/data/integrationTemplates.d.ts +9 -0
- package/dist/runtime/data/integrationTemplates.js +7 -1
- package/dist/runtime/data/payloadForm.js +2 -1
- package/dist/runtime/data/workflowIconCatalog.js +2 -1
- package/dist/runtime/i18n/messages/de.json +1207 -0
- package/dist/runtime/i18n/messages/en.json +1207 -0
- package/dist/runtime/i18n/translate.d.ts +83 -0
- package/dist/runtime/i18n/translate.js +41 -0
- package/dist/runtime/pages/integrations/audit.vue +52 -34
- package/dist/runtime/pages/integrations/credentials/oauth-complete.vue +3 -2
- package/dist/runtime/pages/integrations/credentials.vue +70 -52
- package/dist/runtime/pages/integrations/index.vue +50 -56
- package/dist/runtime/pages/integrations/runs.vue +33 -21
- package/dist/runtime/pages/integrations/schedules.vue +49 -28
- package/dist/runtime/pages/integrations/secrets.vue +34 -34
- package/dist/runtime/pages/integrations/templates/[slug].vue +77 -68
- package/dist/runtime/pages/integrations/templates/index.vue +35 -27
- package/dist/runtime/pages/integrations/workflows/[id].vue +164 -99
- package/dist/runtime/pages/integrations/workflows/index.vue +10 -5
- package/dist/runtime/plugins/locale.d.ts +10 -0
- package/dist/runtime/plugins/locale.js +6 -0
- package/dist/runtime/plugins/realtime.client.d.ts +32 -0
- package/dist/runtime/plugins/realtime.client.js +4 -0
- package/dist/runtime/utils/credentialState.d.ts +24 -1
- package/dist/runtime/utils/credentialState.js +26 -11
- package/dist/runtime/utils/localize.d.ts +18 -5
- package/dist/runtime/utils/localize.js +32 -9
- package/dist/runtime/utils/pollBudget.d.ts +72 -0
- package/dist/runtime/utils/pollBudget.js +17 -0
- package/dist/runtime/utils/schedule.d.ts +0 -25
- package/dist/runtime/utils/schedule.js +37 -25
- package/dist/runtime/utils/statusStyle.d.ts +26 -2
- package/dist/runtime/utils/statusStyle.js +9 -1
- package/dist/runtime/utils/validationFindings.d.ts +2 -2
- package/dist/runtime/utils/validationFindings.js +4 -3
- package/dist/types.d.mts +2 -6
- package/package.json +3 -2
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<script setup>
|
|
2
2
|
import { computed, onMounted, ref, watch } from "vue";
|
|
3
|
-
import { AddCircle as Plus, TrashBinMinimalistic as
|
|
3
|
+
import { AddCircle as Plus, TrashBinMinimalistic as TrashBin } from "#solar-icons";
|
|
4
4
|
import {
|
|
5
5
|
Button,
|
|
6
6
|
Input,
|
|
@@ -29,6 +29,7 @@ const props = defineProps({
|
|
|
29
29
|
refused: { type: String, required: false }
|
|
30
30
|
});
|
|
31
31
|
const emit = defineEmits(["set"]);
|
|
32
|
+
const t = useIntegrationsT();
|
|
32
33
|
const value = computed(() => props.config[props.field.key]);
|
|
33
34
|
function write(v) {
|
|
34
35
|
emit("set", props.field.key, v);
|
|
@@ -44,18 +45,18 @@ const formatError = computed(() => {
|
|
|
44
45
|
const val = props.field.validation;
|
|
45
46
|
if (!val) return null;
|
|
46
47
|
if (typeof v === "string") {
|
|
47
|
-
if (val.minLength != null && v.length < val.minLength) return
|
|
48
|
-
if (val.maxLength != null && v.length > val.maxLength) return
|
|
48
|
+
if (val.minLength != null && v.length < val.minLength) return t("integration.nodeConfig.validation.minLength", { min: val.minLength });
|
|
49
|
+
if (val.maxLength != null && v.length > val.maxLength) return t("integration.nodeConfig.validation.maxLength", { max: val.maxLength });
|
|
49
50
|
if (val.pattern) {
|
|
50
51
|
try {
|
|
51
|
-
if (!new RegExp(val.pattern).test(v)) return "
|
|
52
|
+
if (!new RegExp(val.pattern).test(v)) return t("integration.nodeConfig.validation.pattern");
|
|
52
53
|
} catch {
|
|
53
54
|
}
|
|
54
55
|
}
|
|
55
56
|
}
|
|
56
57
|
if (typeof v === "number") {
|
|
57
|
-
if (val.min != null && v < val.min) return
|
|
58
|
-
if (val.max != null && v > val.max) return
|
|
58
|
+
if (val.min != null && v < val.min) return t("integration.nodeConfig.validation.min", { min: val.min });
|
|
59
|
+
if (val.max != null && v > val.max) return t("integration.nodeConfig.validation.max", { max: val.max });
|
|
59
60
|
}
|
|
60
61
|
return null;
|
|
61
62
|
});
|
|
@@ -69,9 +70,9 @@ const constraintHint = computed(() => {
|
|
|
69
70
|
if (val.min != null) return `\u2265 ${val.min}`;
|
|
70
71
|
if (val.max != null) return `\u2264 ${val.max}`;
|
|
71
72
|
} else {
|
|
72
|
-
if (val.minLength != null && val.maxLength != null) return
|
|
73
|
-
if (val.minLength != null) return
|
|
74
|
-
if (val.maxLength != null) return
|
|
73
|
+
if (val.minLength != null && val.maxLength != null) return t("integration.nodeConfig.hint.charRange", { min: val.minLength, max: val.maxLength });
|
|
74
|
+
if (val.minLength != null) return t("integration.nodeConfig.hint.charMin", { min: val.minLength });
|
|
75
|
+
if (val.maxLength != null) return t("integration.nodeConfig.hint.charMax", { max: val.maxLength });
|
|
75
76
|
}
|
|
76
77
|
return "";
|
|
77
78
|
});
|
|
@@ -103,11 +104,11 @@ const bound = computed(() => {
|
|
|
103
104
|
const credOptions = computed(
|
|
104
105
|
() => credsForField(props.field).map((c) => ({ credential: c, state: credentialState(c) }))
|
|
105
106
|
);
|
|
106
|
-
const UNKNOWN_CREDENTIAL =
|
|
107
|
+
const UNKNOWN_CREDENTIAL = computed(() => t("integration.nodeConfig.credential.unknown"));
|
|
107
108
|
function credTriggerLabel(field) {
|
|
108
109
|
const label = resolveLocalized(field.label);
|
|
109
|
-
if (bound.value) return
|
|
110
|
-
if (value.value && credentialsLoaded.value) return
|
|
110
|
+
if (bound.value) return t("integration.nodeConfig.credential.trigger.bound", { label, name: bound.value.credential.name, state: bound.value.state.label });
|
|
111
|
+
if (value.value && credentialsLoaded.value) return t("integration.nodeConfig.credential.trigger.unknown", { label, unknown: UNKNOWN_CREDENTIAL.value });
|
|
111
112
|
return label;
|
|
112
113
|
}
|
|
113
114
|
const credCreateOpen = ref(false);
|
|
@@ -126,8 +127,8 @@ function onCredentialSelect(v) {
|
|
|
126
127
|
write(v);
|
|
127
128
|
}
|
|
128
129
|
function acceptsSftp(field) {
|
|
129
|
-
const
|
|
130
|
-
return
|
|
130
|
+
const t2 = field.credentialType;
|
|
131
|
+
return t2 === "revenexx:sftp" || Array.isArray(t2) && t2.includes("revenexx:sftp");
|
|
131
132
|
}
|
|
132
133
|
const EXPR_TOKEN = "${{";
|
|
133
134
|
const canToggleExpression = computed(
|
|
@@ -231,7 +232,7 @@ function writeJson(text) {
|
|
|
231
232
|
jsonError.value = null;
|
|
232
233
|
emit("set", props.field.key, parsed);
|
|
233
234
|
} catch {
|
|
234
|
-
jsonError.value = "
|
|
235
|
+
jsonError.value = t("integration.nodeConfig.json.invalid");
|
|
235
236
|
}
|
|
236
237
|
}
|
|
237
238
|
function readArray() {
|
|
@@ -266,28 +267,28 @@ function setArrayItemField(index, fieldKey, v) {
|
|
|
266
267
|
without the required marker, which is a state and not part of a
|
|
267
268
|
name. -->
|
|
268
269
|
<Label class="text-mono" :class="invalid ? 'text-rose-600' : 'text-muted-foreground'">
|
|
269
|
-
{{ resolveLocalized(field.label) }}<span v-if="field.required" class="text-rose-500" title="
|
|
270
|
+
{{ resolveLocalized(field.label) }}<span v-if="field.required" class="text-rose-500" :title="t('integration.nodeConfig.field.requiredMark')"> *</span>
|
|
270
271
|
</Label>
|
|
271
272
|
<div class="flex shrink-0 items-center gap-1.5">
|
|
272
273
|
<div v-if="isObjectField && !showExpression" class="flex items-center rounded border border-black/[0.08] bg-white p-px">
|
|
273
274
|
<button
|
|
274
275
|
type="button"
|
|
275
276
|
:disabled="!flatCapable"
|
|
276
|
-
title="
|
|
277
|
+
:title="t('integration.nodeConfig.object.toggle.fieldsTitle')"
|
|
277
278
|
class="rounded px-1 py-px text-[10px] font-medium transition disabled:pointer-events-none disabled:opacity-40"
|
|
278
279
|
:class="objectMode === 'form' ? 'bg-slate-100 text-foreground' : 'text-muted-foreground hover:text-foreground'"
|
|
279
280
|
@click="objectMode = 'form'"
|
|
280
281
|
>
|
|
281
|
-
|
|
282
|
+
{{ t("integration.nodeConfig.object.toggle.fields") }}
|
|
282
283
|
</button>
|
|
283
284
|
<button
|
|
284
285
|
type="button"
|
|
285
|
-
title="
|
|
286
|
+
:title="t('integration.nodeConfig.object.toggle.jsonTitle')"
|
|
286
287
|
class="rounded px-1 py-px text-[10px] font-medium transition"
|
|
287
288
|
:class="objectMode === 'json' ? 'bg-slate-100 text-foreground' : 'text-muted-foreground hover:text-foreground'"
|
|
288
289
|
@click="objectMode = 'json'"
|
|
289
290
|
>
|
|
290
|
-
|
|
291
|
+
{{ t("integration.nodeConfig.object.toggle.json") }}
|
|
291
292
|
</button>
|
|
292
293
|
</div>
|
|
293
294
|
<button
|
|
@@ -295,7 +296,7 @@ function setArrayItemField(index, fieldKey, v) {
|
|
|
295
296
|
type="button"
|
|
296
297
|
class="rounded border px-1 py-0.5 font-mono text-[10px] transition"
|
|
297
298
|
:class="showExpression ? 'border-emerald-500/40 bg-emerald-500/15 text-emerald-700' : 'border-black/[0.08] bg-white text-muted-foreground hover:text-foreground'"
|
|
298
|
-
:title="showExpression ? '
|
|
299
|
+
:title="showExpression ? t('integration.nodeConfig.expression.toggle.off') : t('integration.nodeConfig.expression.toggle.on')"
|
|
299
300
|
@click="toggleExpression"
|
|
300
301
|
>
|
|
301
302
|
{{ exprHint }}
|
|
@@ -303,7 +304,7 @@ function setArrayItemField(index, fieldKey, v) {
|
|
|
303
304
|
<span
|
|
304
305
|
v-else-if="field.expressionAllowed"
|
|
305
306
|
class="rounded border border-emerald-500/25 bg-emerald-500/10 px-1 py-0.5 font-mono text-[10px] text-emerald-600"
|
|
306
|
-
title="
|
|
307
|
+
:title="t('integration.nodeConfig.expression.badge.title')"
|
|
307
308
|
>
|
|
308
309
|
{{ exprHint }}
|
|
309
310
|
</span>
|
|
@@ -338,26 +339,26 @@ function setArrayItemField(index, fieldKey, v) {
|
|
|
338
339
|
<!-- A repeating row has no room for visible labels, so each control
|
|
339
340
|
names itself and says which row of which field it belongs to. -->
|
|
340
341
|
<Input
|
|
341
|
-
:aria-label="
|
|
342
|
+
:aria-label="t('integration.nodeConfig.object.row.keyAria', { label: resolveLocalized(field.label), n: idx + 1 })"
|
|
342
343
|
:model-value="row.key"
|
|
343
|
-
placeholder="
|
|
344
|
+
:placeholder="t('integration.nodeConfig.object.row.keyPlaceholder')"
|
|
344
345
|
class="h-7 w-[38%] rounded-md border border-black/[0.08] ring-0 shadow-none bg-white text-sm"
|
|
345
346
|
@update:model-value="(v) => setKvRow(idx, { key: String(v) })"
|
|
346
347
|
/>
|
|
347
348
|
<Input
|
|
348
|
-
:aria-label="
|
|
349
|
+
:aria-label="t('integration.nodeConfig.object.row.valueAria', { label: resolveLocalized(field.label), n: idx + 1 })"
|
|
349
350
|
:model-value="row.value"
|
|
350
|
-
placeholder="
|
|
351
|
+
:placeholder="t('integration.nodeConfig.object.row.valuePlaceholder')"
|
|
351
352
|
class="h-7 min-w-0 flex-1 rounded-md border border-black/[0.08] ring-0 shadow-none bg-white text-sm"
|
|
352
353
|
@update:model-value="(v) => setKvRow(idx, { value: String(v) })"
|
|
353
354
|
/>
|
|
354
355
|
<button
|
|
355
356
|
type="button"
|
|
356
|
-
:aria-label="
|
|
357
|
+
:aria-label="t('integration.nodeConfig.object.row.removeAria', { label: resolveLocalized(field.label), n: idx + 1 })"
|
|
357
358
|
class="flex size-6 shrink-0 items-center justify-center rounded text-muted-foreground transition hover:text-rose-600"
|
|
358
359
|
@click="removeKvRow(idx)"
|
|
359
360
|
>
|
|
360
|
-
<
|
|
361
|
+
<TrashBin :size="11" />
|
|
361
362
|
</button>
|
|
362
363
|
</div>
|
|
363
364
|
<Button
|
|
@@ -368,7 +369,7 @@ function setArrayItemField(index, fieldKey, v) {
|
|
|
368
369
|
@click="addKvRow"
|
|
369
370
|
>
|
|
370
371
|
<Plus :size="11" />
|
|
371
|
-
|
|
372
|
+
{{ t("integration.nodeConfig.action.addRow") }}
|
|
372
373
|
</Button>
|
|
373
374
|
</div>
|
|
374
375
|
|
|
@@ -464,7 +465,7 @@ function setArrayItemField(index, fieldKey, v) {
|
|
|
464
465
|
@update:model-value="(v) => write(v)"
|
|
465
466
|
>
|
|
466
467
|
<SelectTrigger :aria-label="resolveLocalized(field.label)" size="sm" class="h-8 w-full rounded-md border border-black/[0.08] ring-0 shadow-none text-sm bg-white">
|
|
467
|
-
<SelectValue :placeholder="resolveLocalized(field.placeholder) || '
|
|
468
|
+
<SelectValue :placeholder="resolveLocalized(field.placeholder) || t('integration.nodeConfig.select.placeholder')" />
|
|
468
469
|
</SelectTrigger>
|
|
469
470
|
<SelectContent>
|
|
470
471
|
<SelectItem v-for="opt in field.options ?? []" :key="String(opt.value)" :value="String(opt.value)">
|
|
@@ -498,7 +499,7 @@ function setArrayItemField(index, fieldKey, v) {
|
|
|
498
499
|
@update:model-value="(v) => write(v)"
|
|
499
500
|
>
|
|
500
501
|
<SelectTrigger :aria-label="resolveLocalized(field.label)" size="sm" class="h-8 w-full rounded-md border border-black/[0.08] ring-0 shadow-none text-sm bg-white">
|
|
501
|
-
<SelectValue placeholder="
|
|
502
|
+
<SelectValue :placeholder="t('integration.nodeConfig.secretRef.placeholder')" />
|
|
502
503
|
</SelectTrigger>
|
|
503
504
|
<SelectContent>
|
|
504
505
|
<SelectItem v-for="k in secretKeys" :key="k" :value="k">{{ k }}</SelectItem>
|
|
@@ -520,7 +521,7 @@ function setArrayItemField(index, fieldKey, v) {
|
|
|
520
521
|
"Revenexx APIConnected". Rendering it here keeps the pill a pill, and
|
|
521
522
|
the placeholder has to be drawn by hand because a slot replaces the
|
|
522
523
|
fallback that would otherwise show it. -->
|
|
523
|
-
<SelectValue placeholder="
|
|
524
|
+
<SelectValue :placeholder="t('integration.nodeConfig.credential.placeholder')">
|
|
524
525
|
<span v-if="bound" class="flex min-w-0 items-center gap-1.5">
|
|
525
526
|
<span class="min-w-0 truncate">{{ bound.credential.name }}</span>
|
|
526
527
|
<!-- No `title` on this badge: `SelectValue` renders itself with
|
|
@@ -539,7 +540,7 @@ function setArrayItemField(index, fieldKey, v) {
|
|
|
539
540
|
while the workflow still runs into the dead reference. `loaded`
|
|
540
541
|
keeps the wait before the first response out of it. -->
|
|
541
542
|
<span v-else-if="value && credentialsLoaded" class="text-rose-600">{{ UNKNOWN_CREDENTIAL }}</span>
|
|
542
|
-
<span v-else class="text-muted-foreground">
|
|
543
|
+
<span v-else class="text-muted-foreground">{{ t("integration.nodeConfig.credential.placeholder") }}</span>
|
|
543
544
|
</SelectValue>
|
|
544
545
|
</SelectTrigger>
|
|
545
546
|
<SelectContent>
|
|
@@ -562,24 +563,24 @@ function setArrayItemField(index, fieldKey, v) {
|
|
|
562
563
|
</span>
|
|
563
564
|
</SelectItem>
|
|
564
565
|
<div v-if="!credOptions.length" class="px-2 py-1.5 text-sm text-muted-foreground">
|
|
565
|
-
|
|
566
|
+
{{ t("integration.nodeConfig.credential.empty") }}
|
|
566
567
|
</div>
|
|
567
568
|
<SelectSeparator />
|
|
568
569
|
<SelectItem :value="CRED_ACTION_NEW" class="font-medium text-violet-600 data-[highlighted]:text-violet-700">
|
|
569
|
-
|
|
570
|
+
{{ t("integration.nodeConfig.credential.action.new") }}
|
|
570
571
|
</SelectItem>
|
|
571
572
|
<SelectItem v-if="acceptsSftp(field)" :value="CRED_ACTION_SFTP" class="font-medium text-violet-600 data-[highlighted]:text-violet-700">
|
|
572
|
-
|
|
573
|
+
{{ t("integration.nodeConfig.credential.action.importSftp") }}
|
|
573
574
|
</SelectItem>
|
|
574
575
|
</SelectContent>
|
|
575
576
|
</Select>
|
|
576
577
|
<!-- What the state has to add, as text rather than as a tooltip — the shape
|
|
577
578
|
the detail dialog uses beneath its own badge. -->
|
|
578
579
|
<p v-if="bound?.state.key === 'needs_reauth'" class="text-sm text-amber-600">
|
|
579
|
-
|
|
580
|
+
{{ t("integration.nodeConfig.credential.state.needsReauth") }}
|
|
580
581
|
</p>
|
|
581
582
|
<p v-else-if="bound?.state.key === 'failed' && bound.state.message" class="text-sm break-words text-rose-600">
|
|
582
|
-
|
|
583
|
+
{{ t("integration.nodeConfig.credential.state.failed", { message: bound.state.message }) }}
|
|
583
584
|
</p>
|
|
584
585
|
<IntegrationsCredentialCreateDialog
|
|
585
586
|
v-model:open="credCreateOpen"
|
|
@@ -606,11 +607,11 @@ function setArrayItemField(index, fieldKey, v) {
|
|
|
606
607
|
</span>
|
|
607
608
|
<button
|
|
608
609
|
type="button"
|
|
609
|
-
:aria-label="
|
|
610
|
+
:aria-label="t('integration.nodeConfig.array.removeItemAria', { label: resolveLocalized(field.label), n: idx + 1 })"
|
|
610
611
|
class="flex size-5 items-center justify-center rounded text-muted-foreground hover:text-rose-600"
|
|
611
612
|
@click="removeArrayItem(idx)"
|
|
612
613
|
>
|
|
613
|
-
<
|
|
614
|
+
<TrashBin :size="11" />
|
|
614
615
|
</button>
|
|
615
616
|
</div>
|
|
616
617
|
<div
|
|
@@ -624,7 +625,7 @@ function setArrayItemField(index, fieldKey, v) {
|
|
|
624
625
|
<!-- The label above repeats per item, so it cannot own an id; the
|
|
625
626
|
input carries its own name including the item number. -->
|
|
626
627
|
<Input
|
|
627
|
-
:aria-label="
|
|
628
|
+
:aria-label="t('integration.nodeConfig.array.subFieldAria', { label: resolveLocalized(sub.label), n: idx + 1 })"
|
|
628
629
|
:model-value="item[sub.key] ?? ''"
|
|
629
630
|
:placeholder="resolveLocalized(sub.placeholder)"
|
|
630
631
|
class="h-7 text-sm bg-white"
|
|
@@ -641,7 +642,7 @@ function setArrayItemField(index, fieldKey, v) {
|
|
|
641
642
|
@click="pushArrayItem(Object.fromEntries((field.items?.properties ?? []).map((p) => [p.key, ''])))"
|
|
642
643
|
>
|
|
643
644
|
<Plus :size="11" />
|
|
644
|
-
|
|
645
|
+
{{ t("integration.nodeConfig.action.addRow") }}
|
|
645
646
|
</Button>
|
|
646
647
|
</div>
|
|
647
648
|
|