@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, nextTick, onMounted, onUnmounted, ref, watch } from "vue";
|
|
3
|
-
import { AltArrowLeft as ArrowLeft, AltArrowRight as Chevron, Copy as CopyIcon, Pause as PauseIcon, RefreshCircle as Loader2, Play, Refresh as RetryIcon, Diskette as Save } from "#solar-icons";
|
|
3
|
+
import { AltArrowLeft as ArrowLeft, AltArrowRight as Chevron, Copy as CopyIcon, Pause as PauseIcon, RefreshCircle as Loader2, Play, Refresh as RetryIcon, Diskette as Save, SidebarMinimalistic as RailIcon } from "#solar-icons";
|
|
4
4
|
import {
|
|
5
5
|
AlertDialog,
|
|
6
6
|
AlertDialogContent,
|
|
@@ -31,24 +31,24 @@ import RunsTable from "../../../components/Integrations/RunsTable.vue";
|
|
|
31
31
|
import RunDetailPanel from "../../../components/Integrations/RunDetailPanel.vue";
|
|
32
32
|
import { toast } from "vue-sonner";
|
|
33
33
|
import { IntegrationsApiError, apiValidationIssues } from "../../../utils/apiError";
|
|
34
|
+
import { createPollBudget, SAFETY_POLL_MS } from "../../../utils/pollBudget";
|
|
34
35
|
import { findingsSummary, groupFindingsByNode, nodeDisplayLabel } from "../../../utils/validationFindings";
|
|
35
36
|
import { payloadFieldsFromBlob } from "../../../data/payloadForm";
|
|
36
37
|
import WorkflowIconView from "../../../components/Integrations/WorkflowIconView.vue";
|
|
38
|
+
const t = useIntegrationsT();
|
|
37
39
|
const route = useRoute();
|
|
38
40
|
const router = useRouter();
|
|
39
41
|
const { workflows, get, update, toggleActive } = useIntegrationsWorkflows();
|
|
40
|
-
const { autoEnable } = useIntegrationsFocus();
|
|
41
|
-
autoEnable();
|
|
42
42
|
const id = computed(() => Number(route.params.id));
|
|
43
43
|
const workflow = computed(() => workflows.value.find((w) => w.id === id.value) ?? null);
|
|
44
|
-
useHead({ title: () =>
|
|
44
|
+
useHead({ title: () => t("integration.editor.head.title", { name: workflow.value?.name ?? t("integration.editor.head.untitled") }) });
|
|
45
45
|
const tab = ref("editor");
|
|
46
|
-
const tabs = [
|
|
47
|
-
{ key: "editor", label: "
|
|
48
|
-
{ key: "history", label: "
|
|
49
|
-
{ key: "runs", label: "
|
|
50
|
-
{ key: "dead-letters", label: "
|
|
51
|
-
];
|
|
46
|
+
const tabs = computed(() => [
|
|
47
|
+
{ key: "editor", label: t("integration.editor.tab.editor") },
|
|
48
|
+
{ key: "history", label: t("integration.editor.tab.history") },
|
|
49
|
+
{ key: "runs", label: t("integration.editor.tab.runs") },
|
|
50
|
+
{ key: "dead-letters", label: t("integration.editor.tab.deadLetters") }
|
|
51
|
+
]);
|
|
52
52
|
const dirtyBlob = ref(null);
|
|
53
53
|
const isDirty = computed(() => dirtyBlob.value !== null);
|
|
54
54
|
const saving = ref(false);
|
|
@@ -95,12 +95,12 @@ async function waitForBuildReady() {
|
|
|
95
95
|
const status = fresh?.buildStatus;
|
|
96
96
|
if (status === "pending" || status === "building") continue;
|
|
97
97
|
if (status === "failed") {
|
|
98
|
-
toast.error("
|
|
98
|
+
toast.error(t("integration.editor.build.toast.failed"));
|
|
99
99
|
return false;
|
|
100
100
|
}
|
|
101
101
|
return true;
|
|
102
102
|
}
|
|
103
|
-
toast.error("
|
|
103
|
+
toast.error(t("integration.editor.build.toast.timeout"));
|
|
104
104
|
return false;
|
|
105
105
|
} finally {
|
|
106
106
|
waitingForBuild.value = false;
|
|
@@ -109,13 +109,13 @@ async function waitForBuildReady() {
|
|
|
109
109
|
const buildNotice = computed(() => {
|
|
110
110
|
switch (workflow.value?.buildStatus) {
|
|
111
111
|
case "building":
|
|
112
|
-
return { tone: "info", text: "
|
|
112
|
+
return { tone: "info", text: t("integration.editor.build.notice.building") };
|
|
113
113
|
case "pending":
|
|
114
|
-
return { tone: "info", text: "
|
|
114
|
+
return { tone: "info", text: t("integration.editor.build.notice.pending") };
|
|
115
115
|
case "failed":
|
|
116
116
|
return {
|
|
117
117
|
tone: "error",
|
|
118
|
-
text:
|
|
118
|
+
text: workflow.value?.buildError ? t("integration.editor.build.notice.failedWithError", { error: workflow.value.buildError }) : t("integration.editor.build.notice.failed")
|
|
119
119
|
};
|
|
120
120
|
default:
|
|
121
121
|
return null;
|
|
@@ -139,7 +139,7 @@ function discardChanges() {
|
|
|
139
139
|
const duplicateOpen = ref(false);
|
|
140
140
|
const duplicateTarget = computed(() => workflow.value ? { id: workflow.value.id, name: workflow.value.name } : null);
|
|
141
141
|
async function onDuplicated(copy) {
|
|
142
|
-
toast.success(
|
|
142
|
+
toast.success(t("integration.editor.toast.duplicated", { name: copy.name }));
|
|
143
143
|
await router.push(`/integrations/workflows/${copy.id}`);
|
|
144
144
|
}
|
|
145
145
|
async function onRevisionRestored() {
|
|
@@ -172,11 +172,11 @@ function viewRunFromModal(id2) {
|
|
|
172
172
|
}
|
|
173
173
|
function syncErrorMessage(e) {
|
|
174
174
|
if (e instanceof IntegrationsApiError) {
|
|
175
|
-
if (e.status === 504) return "
|
|
176
|
-
if (e.status === 422 && e.body?.status === "failed") return "
|
|
177
|
-
return e.message || "
|
|
175
|
+
if (e.status === 504) return t("integration.editor.run.error.syncTimeout");
|
|
176
|
+
if (e.status === 422 && e.body?.status === "failed") return t("integration.editor.run.error.syncFailed");
|
|
177
|
+
return e.message || t("integration.editor.run.error.syncFailed");
|
|
178
178
|
}
|
|
179
|
-
return e?.message || "
|
|
179
|
+
return e?.message || t("integration.editor.run.error.syncFailed");
|
|
180
180
|
}
|
|
181
181
|
function refusedForSettings(e) {
|
|
182
182
|
const issues = apiValidationIssues(e);
|
|
@@ -189,7 +189,7 @@ function refusedForSettings(e) {
|
|
|
189
189
|
...groups.filter((g) => !g.nodeId).flatMap((g) => g.messages)
|
|
190
190
|
];
|
|
191
191
|
const where = parts.length ? ` \u2014 ${parts.join("; ")}` : "";
|
|
192
|
-
const line =
|
|
192
|
+
const line = t("integration.editor.run.error.refusedForSettings", { summary, where });
|
|
193
193
|
return /[.!?]$/.test(line) ? line : `${line}.`;
|
|
194
194
|
}
|
|
195
195
|
async function reportRunFailure(e, fallback) {
|
|
@@ -207,7 +207,7 @@ async function run(mode) {
|
|
|
207
207
|
try {
|
|
208
208
|
payload = JSON.parse(payloadText.value || "{}");
|
|
209
209
|
} catch {
|
|
210
|
-
payloadError.value = "
|
|
210
|
+
payloadError.value = t("integration.editor.payload.error.invalidJson");
|
|
211
211
|
return;
|
|
212
212
|
}
|
|
213
213
|
payloadError.value = null;
|
|
@@ -243,7 +243,7 @@ async function run(mode) {
|
|
|
243
243
|
const res = await triggerRun(workflow.value.id, payload, "async");
|
|
244
244
|
runModalRunId.value = extractRunId(res);
|
|
245
245
|
} catch (e) {
|
|
246
|
-
await reportRunFailure(e, (err) => err?.message || "
|
|
246
|
+
await reportRunFailure(e, (err) => err?.message || t("integration.editor.run.error.couldNotStart"));
|
|
247
247
|
} finally {
|
|
248
248
|
running.value = false;
|
|
249
249
|
syncLoading.value = false;
|
|
@@ -266,7 +266,7 @@ const eventLog = typeof useIntegrationsEvents === "function" ? useIntegrationsEv
|
|
|
266
266
|
} };
|
|
267
267
|
const prefillBusy = ref(null);
|
|
268
268
|
const eventTriggerTopic = computed(() => {
|
|
269
|
-
const trigger = (workflow.value?.blob.triggers ?? []).find((
|
|
269
|
+
const trigger = (workflow.value?.blob.triggers ?? []).find((t2) => t2.type === "event");
|
|
270
270
|
const topic = trigger?.config?.event_type;
|
|
271
271
|
return typeof topic === "string" && topic.trim() !== "" ? topic.trim() : null;
|
|
272
272
|
});
|
|
@@ -301,7 +301,7 @@ async function insertLatestEvent() {
|
|
|
301
301
|
await eventLog.loadEvents();
|
|
302
302
|
const match = eventLog.events.value.filter((e) => e.topic === topic).sort((a, b) => (b.time ?? "").localeCompare(a.time ?? ""))[0];
|
|
303
303
|
if (!match) {
|
|
304
|
-
toast.info(
|
|
304
|
+
toast.info(t("integration.editor.event.toast.noneReceived", { topic }));
|
|
305
305
|
return;
|
|
306
306
|
}
|
|
307
307
|
payloadText.value = envelope(topic, match.data, {
|
|
@@ -327,6 +327,9 @@ const runsError = ref(null);
|
|
|
327
327
|
const runsPage = ref(1);
|
|
328
328
|
const runsTotal = ref(0);
|
|
329
329
|
const runsLastPage = ref(1);
|
|
330
|
+
const RUNS_POLL_MS = 3e3;
|
|
331
|
+
const { delivering: realtimeDelivering, runTick, lastRunEvent, buildTick, lastBuildEvent } = useIntegrationsRealtime();
|
|
332
|
+
const runsBudget = createPollBudget({ intervalMs: RUNS_POLL_MS, liveIntervalMs: SAFETY_POLL_MS });
|
|
330
333
|
let runsPoll = null;
|
|
331
334
|
function stopRunsPoll() {
|
|
332
335
|
if (runsPoll) {
|
|
@@ -337,12 +340,25 @@ function stopRunsPoll() {
|
|
|
337
340
|
function startRunsPoll() {
|
|
338
341
|
stopRunsPoll();
|
|
339
342
|
runsPoll = setInterval(() => {
|
|
340
|
-
if (runsPage.value === 1) void loadRuns(1, { silent: true });
|
|
341
|
-
},
|
|
343
|
+
if (runsPage.value === 1 && runsBudget.due(realtimeDelivering.value)) void loadRuns(1, { silent: true });
|
|
344
|
+
}, RUNS_POLL_MS);
|
|
342
345
|
}
|
|
343
346
|
onUnmounted(stopRunsPoll);
|
|
347
|
+
watch(runTick, () => {
|
|
348
|
+
if (tab.value !== "runs" || runsPage.value !== 1) return;
|
|
349
|
+
const eventWorkflow = workflowIdOf(lastRunEvent.value);
|
|
350
|
+
if (eventWorkflow && eventWorkflow !== String(workflow.value?.id ?? "")) return;
|
|
351
|
+
void loadRuns(1, { silent: true });
|
|
352
|
+
});
|
|
353
|
+
watch(buildTick, () => {
|
|
354
|
+
if (!workflow.value) return;
|
|
355
|
+
const eventWorkflow = lastBuildEvent.value?.topicId ?? workflowIdOf(lastBuildEvent.value);
|
|
356
|
+
if (eventWorkflow && eventWorkflow !== String(workflow.value.id)) return;
|
|
357
|
+
void get(workflow.value.id);
|
|
358
|
+
});
|
|
344
359
|
async function loadRuns(page = runsPage.value, opts = {}) {
|
|
345
360
|
if (!workflow.value) return;
|
|
361
|
+
runsBudget.spend();
|
|
346
362
|
if (!opts.silent) runsLoading.value = true;
|
|
347
363
|
runsError.value = null;
|
|
348
364
|
try {
|
|
@@ -356,7 +372,7 @@ async function loadRuns(page = runsPage.value, opts = {}) {
|
|
|
356
372
|
runsLastPage.value = res.lastPage;
|
|
357
373
|
runsPage.value = res.page;
|
|
358
374
|
} catch (e) {
|
|
359
|
-
runsError.value = e.message || "
|
|
375
|
+
runsError.value = e.message || t("integration.editor.runs.error.load");
|
|
360
376
|
} finally {
|
|
361
377
|
if (!opts.silent) runsLoading.value = false;
|
|
362
378
|
}
|
|
@@ -365,20 +381,43 @@ function goRunsPage(p) {
|
|
|
365
381
|
const next = Math.min(Math.max(1, p), runsLastPage.value);
|
|
366
382
|
if (next !== runsPage.value) void loadRuns(next);
|
|
367
383
|
}
|
|
368
|
-
watch(tab, (
|
|
369
|
-
if (
|
|
384
|
+
watch(tab, (t2) => {
|
|
385
|
+
if (t2 === "runs") {
|
|
370
386
|
void loadRuns(1);
|
|
371
387
|
startRunsPoll();
|
|
372
388
|
} else stopRunsPoll();
|
|
373
389
|
});
|
|
374
390
|
const settingsOpen = ref(false);
|
|
375
391
|
const openRunId = computed(() => route.query.run != null ? String(route.query.run) : null);
|
|
392
|
+
const { focused: railFolded, enable, disable } = useIntegrationsFocus();
|
|
393
|
+
const WIDE_CANVAS_KEY = "integrations.editor.wideCanvas";
|
|
394
|
+
const wideCanvasWanted = ref(false);
|
|
395
|
+
try {
|
|
396
|
+
wideCanvasWanted.value = localStorage.getItem(WIDE_CANVAS_KEY) === "1";
|
|
397
|
+
} catch {
|
|
398
|
+
}
|
|
399
|
+
const canvasFillsPage = computed(() => tab.value === "editor" && !openRunId.value);
|
|
400
|
+
const railShouldFold = computed(() => wideCanvasWanted.value && canvasFillsPage.value);
|
|
401
|
+
function applyRail() {
|
|
402
|
+
if (railShouldFold.value) enable();
|
|
403
|
+
else disable();
|
|
404
|
+
}
|
|
405
|
+
onMounted(() => applyRail());
|
|
406
|
+
watch(railShouldFold, () => applyRail());
|
|
407
|
+
onUnmounted(() => disable());
|
|
408
|
+
function toggleRail() {
|
|
409
|
+
wideCanvasWanted.value = !wideCanvasWanted.value;
|
|
410
|
+
try {
|
|
411
|
+
localStorage.setItem(WIDE_CANVAS_KEY, wideCanvasWanted.value ? "1" : "0");
|
|
412
|
+
} catch {
|
|
413
|
+
}
|
|
414
|
+
}
|
|
376
415
|
const runView = ref("details");
|
|
377
|
-
const runViews = [
|
|
378
|
-
{ key: "details", label: "
|
|
379
|
-
{ key: "timeline", label: "
|
|
380
|
-
{ key: "replay", label: "
|
|
381
|
-
];
|
|
416
|
+
const runViews = computed(() => [
|
|
417
|
+
{ key: "details", label: t("integration.editor.runView.details") },
|
|
418
|
+
{ key: "timeline", label: t("integration.editor.runView.timeline") },
|
|
419
|
+
{ key: "replay", label: t("integration.editor.runView.replay") }
|
|
420
|
+
]);
|
|
382
421
|
const openRun = ref(null);
|
|
383
422
|
const openRunError = ref(null);
|
|
384
423
|
async function loadOpenRun() {
|
|
@@ -387,7 +426,7 @@ async function loadOpenRun() {
|
|
|
387
426
|
try {
|
|
388
427
|
openRun.value = await fetchRun(workflow.value.id, openRunId.value, workflow.value.name);
|
|
389
428
|
} catch (e) {
|
|
390
|
-
openRunError.value = e?.message ?? "
|
|
429
|
+
openRunError.value = e?.message ?? t("integration.editor.run.error.loadOpenRun");
|
|
391
430
|
}
|
|
392
431
|
}
|
|
393
432
|
watch(openRunId, () => {
|
|
@@ -410,26 +449,26 @@ async function retryOpenRun() {
|
|
|
410
449
|
try {
|
|
411
450
|
const res = await retryRun(openRun.value.workflowId, openRun.value.id);
|
|
412
451
|
const newId = res && typeof res === "object" && "id" in res ? String(res.id) : null;
|
|
413
|
-
toast.success(newId && newId !== openRun.value.id ?
|
|
452
|
+
toast.success(newId && newId !== openRun.value.id ? t("integration.editor.retry.toast.started", { id: newId }) : t("integration.editor.retry.toast.requested"));
|
|
414
453
|
void loadRuns(1, { silent: true });
|
|
415
454
|
} catch (e) {
|
|
416
|
-
toast.error(e?.message ?? "
|
|
455
|
+
toast.error(e?.message ?? t("integration.editor.retry.error.generic"));
|
|
417
456
|
} finally {
|
|
418
457
|
retryBusy.value = false;
|
|
419
458
|
}
|
|
420
459
|
}
|
|
421
|
-
const EXECUTION_MODES = [
|
|
422
|
-
{ value: "async_only", label: "
|
|
423
|
-
{ value: "sync_only", label: "
|
|
424
|
-
{ value: "caller_decides", label: "
|
|
425
|
-
];
|
|
460
|
+
const EXECUTION_MODES = computed(() => [
|
|
461
|
+
{ value: "async_only", label: t("integration.editor.executionMode.async.label"), hint: t("integration.editor.executionMode.async.hint") },
|
|
462
|
+
{ value: "sync_only", label: t("integration.editor.executionMode.sync.label"), hint: t("integration.editor.executionMode.sync.hint") },
|
|
463
|
+
{ value: "caller_decides", label: t("integration.editor.executionMode.callerDecides.label"), hint: t("integration.editor.executionMode.callerDecides.hint") }
|
|
464
|
+
]);
|
|
426
465
|
const executionModeDraft = ref("async_only");
|
|
427
466
|
watch(workflow, (w) => {
|
|
428
467
|
if (w) executionModeDraft.value = w.execution_mode ?? "async_only";
|
|
429
468
|
}, { immediate: true });
|
|
430
469
|
const savingMode = ref(false);
|
|
431
470
|
function modeLabel(m) {
|
|
432
|
-
return m === "sync_only" ? "
|
|
471
|
+
return m === "sync_only" ? t("integration.editor.executionMode.sync.short") : m === "caller_decides" ? t("integration.editor.executionMode.callerDecides.label") : t("integration.editor.executionMode.async.short");
|
|
433
472
|
}
|
|
434
473
|
async function saveExecutionMode(mode) {
|
|
435
474
|
if (!workflow.value || mode === workflow.value.execution_mode) return;
|
|
@@ -448,7 +487,7 @@ async function saveExecutionMode(mode) {
|
|
|
448
487
|
await get(workflow.value.id);
|
|
449
488
|
} catch (e) {
|
|
450
489
|
executionModeDraft.value = prev;
|
|
451
|
-
saveError.value = e.message || "
|
|
490
|
+
saveError.value = e.message || t("integration.editor.executionMode.error.generic");
|
|
452
491
|
} finally {
|
|
453
492
|
savingMode.value = false;
|
|
454
493
|
}
|
|
@@ -456,7 +495,7 @@ async function saveExecutionMode(mode) {
|
|
|
456
495
|
const savingMeta = ref(false);
|
|
457
496
|
const tagSuggestions = computed(() => {
|
|
458
497
|
const all = /* @__PURE__ */ new Set();
|
|
459
|
-
for (const wf of workflows.value) for (const
|
|
498
|
+
for (const wf of workflows.value) for (const t2 of wf.blob.tags ?? []) all.add(t2);
|
|
460
499
|
return [...all].sort();
|
|
461
500
|
});
|
|
462
501
|
async function saveWorkflowMeta(meta) {
|
|
@@ -481,9 +520,9 @@ async function saveWorkflowMeta(meta) {
|
|
|
481
520
|
});
|
|
482
521
|
await get(workflow.value.id);
|
|
483
522
|
dirtyBlob.value = null;
|
|
484
|
-
toast.success("
|
|
523
|
+
toast.success(t("integration.editor.appearance.toast.saved"));
|
|
485
524
|
} catch (e) {
|
|
486
|
-
const msg = e.message || "
|
|
525
|
+
const msg = e.message || t("integration.editor.appearance.error.generic");
|
|
487
526
|
saveError.value = msg;
|
|
488
527
|
toast.error(msg);
|
|
489
528
|
} finally {
|
|
@@ -494,7 +533,7 @@ async function onToggleActive() {
|
|
|
494
533
|
const wf = workflow.value;
|
|
495
534
|
if (!wf) return;
|
|
496
535
|
if (!wf.active && isInvalid.value) {
|
|
497
|
-
toast.error(
|
|
536
|
+
toast.error(t("integration.editor.activate.error.needsFixing", validationWarnings.value?.length ?? 0));
|
|
498
537
|
return;
|
|
499
538
|
}
|
|
500
539
|
try {
|
|
@@ -503,10 +542,10 @@ async function onToggleActive() {
|
|
|
503
542
|
const issues = apiValidationIssues(e);
|
|
504
543
|
if (issues.length) {
|
|
505
544
|
await get(wf.id);
|
|
506
|
-
toast.error(
|
|
545
|
+
toast.error(t("integration.editor.activate.error.validationIssues", issues.length));
|
|
507
546
|
return;
|
|
508
547
|
}
|
|
509
|
-
toast.error(e.message || "
|
|
548
|
+
toast.error(e.message || t("integration.editor.activate.error.generic"));
|
|
510
549
|
}
|
|
511
550
|
}
|
|
512
551
|
async function save() {
|
|
@@ -533,7 +572,7 @@ async function save() {
|
|
|
533
572
|
});
|
|
534
573
|
deactivationOpen.value = true;
|
|
535
574
|
} else {
|
|
536
|
-
saveError.value = e.message || "
|
|
575
|
+
saveError.value = e.message || t("integration.editor.save.error.generic");
|
|
537
576
|
}
|
|
538
577
|
} finally {
|
|
539
578
|
saving.value = false;
|
|
@@ -556,10 +595,10 @@ async function confirmDeactivate() {
|
|
|
556
595
|
await get(workflow.value.id);
|
|
557
596
|
dirtyBlob.value = null;
|
|
558
597
|
deactivationOpen.value = false;
|
|
559
|
-
toast.success("
|
|
598
|
+
toast.success(t("integration.editor.deactivate.toast.savedPaused"));
|
|
560
599
|
} catch (e) {
|
|
561
600
|
deactivationOpen.value = false;
|
|
562
|
-
saveError.value = e.message || "
|
|
601
|
+
saveError.value = e.message || t("integration.editor.save.error.generic");
|
|
563
602
|
} finally {
|
|
564
603
|
saving.value = false;
|
|
565
604
|
}
|
|
@@ -583,41 +622,67 @@ function formatDateTime(iso) {
|
|
|
583
622
|
<PageHeader :title="workflow.name">
|
|
584
623
|
<template #title>
|
|
585
624
|
<span class="inline-flex min-w-0 items-center gap-1.5">
|
|
586
|
-
<NuxtLink to="/integrations/workflows" class="font-normal text-muted-foreground/80 transition-colors hover:text-primary">
|
|
625
|
+
<NuxtLink to="/integrations/workflows" class="font-normal text-muted-foreground/80 transition-colors hover:text-primary">{{ t("integration.editor.breadcrumb.workflows") }}</NuxtLink>
|
|
587
626
|
<Chevron :size="15" weight="Outline" class="text-muted-foreground/50" />
|
|
588
627
|
<!-- Run open: the breadcrumb extends — name and Runs become crumbs
|
|
589
628
|
back into the workflow surface. -->
|
|
590
629
|
<template v-if="openRunId">
|
|
591
630
|
<button type="button" class="truncate font-normal text-muted-foreground/80 transition-colors hover:text-primary" @click="closeRun('editor')">{{ workflow.name }}</button>
|
|
592
631
|
<Chevron :size="15" weight="Outline" class="text-muted-foreground/50" />
|
|
593
|
-
<button type="button" class="font-normal text-muted-foreground/80 transition-colors hover:text-primary" @click="closeRun('runs')">
|
|
632
|
+
<button type="button" class="font-normal text-muted-foreground/80 transition-colors hover:text-primary" @click="closeRun('runs')">{{ t("integration.editor.breadcrumb.runs") }}</button>
|
|
594
633
|
<Chevron :size="15" weight="Outline" class="text-muted-foreground/50" />
|
|
595
634
|
<!-- The Temporal run id IS the run's identity; the internal
|
|
596
635
|
number only fills in until the run is handed off. -->
|
|
597
|
-
<span class="truncate font-mono">{{ openRun?.temporalRunId ??
|
|
636
|
+
<span class="truncate font-mono">{{ openRun?.temporalRunId ?? t("integration.editor.breadcrumb.runNumber", { id: openRunId }) }}</span>
|
|
598
637
|
</template>
|
|
599
638
|
<template v-else>
|
|
600
639
|
<span class="flex size-7 shrink-0 items-center justify-center rounded-md bg-slate-100 text-slate-500">
|
|
601
640
|
<WorkflowIconView :icon="workflow.blob.icon" :size="16" />
|
|
602
641
|
</span>
|
|
603
642
|
<span class="truncate">{{ workflow.name }}</span>
|
|
604
|
-
<Badge variant="outline" class="ml-1.5 border text-xs font-medium uppercase text-muted-foreground" :title="
|
|
643
|
+
<Badge variant="outline" class="ml-1.5 border text-xs font-medium uppercase text-muted-foreground" :title="t('integration.editor.header.executionMode.title', { mode: modeLabel(workflow.execution_mode) })">
|
|
605
644
|
{{ modeLabel(workflow.execution_mode) }}
|
|
606
645
|
</Badge>
|
|
607
646
|
</template>
|
|
608
647
|
</span>
|
|
609
648
|
</template>
|
|
610
649
|
<template #actions>
|
|
650
|
+
<!-- Folding the rail away, and getting it back (PO-273). It reads as
|
|
651
|
+
chrome rather than as an action on this workflow, so the natural
|
|
652
|
+
place was ahead of the breadcrumb — but the shell's `#title` slot
|
|
653
|
+
*is* the `<h1>`'s content, and a control inside the heading makes
|
|
654
|
+
the page announce itself as "Hide navigation Workflows › Order
|
|
655
|
+
sync". `accessibility.md` AC-4 promises one heading that names what
|
|
656
|
+
the operator is looking at, so this sits in `#actions`, which is
|
|
657
|
+
outside it. Leftmost there is as near the rail as the shared header
|
|
658
|
+
allows without a slot of its own.
|
|
659
|
+
|
|
660
|
+
It carries its words and not just a pictogram: an icon-only control
|
|
661
|
+
here is one nobody finds, and the way back out of a folded rail is
|
|
662
|
+
the one control that cannot afford to be learnt by chance. Rendered
|
|
663
|
+
only where the canvas fills the page, the one surface it acts on. -->
|
|
664
|
+
<Button
|
|
665
|
+
v-if="canvasFillsPage"
|
|
666
|
+
variant="ghost"
|
|
667
|
+
size="sm"
|
|
668
|
+
class="h-7 shrink-0 gap-1.5 px-2 text-sm font-normal text-muted-foreground hover:text-primary"
|
|
669
|
+
:title="railFolded ? t('integration.nav.action.show.title') : t('integration.nav.action.hide.title')"
|
|
670
|
+
@click="toggleRail"
|
|
671
|
+
>
|
|
672
|
+
<RailIcon :size="15" />
|
|
673
|
+
{{ railFolded ? t("integration.nav.action.show") : t("integration.nav.action.hide") }}
|
|
674
|
+
</Button>
|
|
675
|
+
|
|
611
676
|
<!-- Run open: run-scoped actions replace the workflow Save. -->
|
|
612
677
|
<template v-if="openRunId">
|
|
613
678
|
<Button v-if="canRetryOpenRun" variant="outline" class="h-7 text-sm" :disabled="retryBusy" @click="retryOpenRun">
|
|
614
679
|
<Loader2 v-if="retryBusy" :size="12" class="animate-spin" />
|
|
615
680
|
<RetryIcon v-else :size="12" />
|
|
616
|
-
|
|
681
|
+
{{ t("integration.editor.action.retry") }}
|
|
617
682
|
</Button>
|
|
618
683
|
<Button class="h-7 text-sm" @click="closeRun('editor')">
|
|
619
684
|
<ArrowLeft :size="12" />
|
|
620
|
-
|
|
685
|
+
{{ t("integration.editor.action.backToWorkflow") }}
|
|
621
686
|
</Button>
|
|
622
687
|
</template>
|
|
623
688
|
<template v-else>
|
|
@@ -627,31 +692,31 @@ function formatDateTime(iso) {
|
|
|
627
692
|
:title="buildNotice?.text"
|
|
628
693
|
>
|
|
629
694
|
<Loader2 :size="12" class="animate-spin" />
|
|
630
|
-
{{ workflow.buildStatus === "building" ? "
|
|
695
|
+
{{ workflow.buildStatus === "building" ? t("integration.editor.build.chip.building") : t("integration.editor.build.chip.queued") }}
|
|
631
696
|
</span>
|
|
632
|
-
<span v-if="isDirty" class="text-sm text-amber-600">
|
|
633
|
-
<Button variant="outline" class="h-7 text-sm" :disabled="saving" title="
|
|
697
|
+
<span v-if="isDirty" class="text-sm text-amber-600">{{ t("integration.editor.status.unsavedChanges") }}</span>
|
|
698
|
+
<Button variant="outline" class="h-7 text-sm" :disabled="saving" :title="t('integration.editor.action.duplicate.title')" @click="duplicateOpen = true">
|
|
634
699
|
<CopyIcon :size="12" />
|
|
635
|
-
|
|
700
|
+
{{ t("integration.editor.action.duplicate.label") }}
|
|
636
701
|
</Button>
|
|
637
|
-
<Button variant="outline" class="h-7 text-sm" :disabled="!isDirty || saving" title="
|
|
638
|
-
|
|
702
|
+
<Button variant="outline" class="h-7 text-sm" :disabled="!isDirty || saving" :title="t('integration.editor.action.discard.title')" @click="discardChanges">
|
|
703
|
+
{{ t("integration.editor.action.discard.label") }}
|
|
639
704
|
</Button>
|
|
640
705
|
<Button class="h-7 text-sm" :disabled="!isDirty || saving" @click="save">
|
|
641
706
|
<Loader2 v-if="saving" :size="12" class="animate-spin" />
|
|
642
707
|
<Save v-else :size="12" />
|
|
643
|
-
{{ saving ? "
|
|
708
|
+
{{ saving ? t("integration.editor.action.save.saving") : t("integration.editor.action.save.label") }}
|
|
644
709
|
</Button>
|
|
645
710
|
<Button
|
|
646
711
|
:variant="workflow.active ? 'outline' : 'default'"
|
|
647
712
|
class="h-7 text-sm"
|
|
648
713
|
:class="workflow.active ? 'text-amber-700 hover:text-amber-800' : 'bg-emerald-600 text-white hover:bg-emerald-700'"
|
|
649
714
|
:disabled="!workflow.active && isInvalid"
|
|
650
|
-
:title="workflow.active ? '
|
|
715
|
+
:title="workflow.active ? t('integration.editor.action.pause.title') : isInvalid ? t('integration.editor.action.activate.title.invalid', validationWarnings?.length ?? 0) : t('integration.editor.action.activate.title')"
|
|
651
716
|
@click="onToggleActive"
|
|
652
717
|
>
|
|
653
718
|
<component :is="workflow.active ? PauseIcon : Play" :size="12" />
|
|
654
|
-
{{ workflow.active ? "
|
|
719
|
+
{{ workflow.active ? t("integration.editor.action.pause.label") : t("integration.editor.action.activate.label") }}
|
|
655
720
|
</Button>
|
|
656
721
|
</template>
|
|
657
722
|
</template>
|
|
@@ -666,11 +731,10 @@ function formatDateTime(iso) {
|
|
|
666
731
|
</div>
|
|
667
732
|
|
|
668
733
|
<div v-if="reauthCredentials.length" class="border-b border-amber-500/20 bg-amber-500/5 px-4 py-2 text-sm text-amber-800">
|
|
669
|
-
{{
|
|
670
|
-
need{{ reauthCredentials.length === 1 ? "s" : "" }} reconnecting
|
|
734
|
+
{{ t("integration.editor.reauth.banner", reauthCredentials.length) }}
|
|
671
735
|
({{ reauthCredentials.map((c) => c.name).join(", ") }}) —
|
|
672
736
|
<NuxtLink to="/integrations/credentials" class="font-medium underline">
|
|
673
|
-
fix
|
|
737
|
+
{{ t("integration.editor.reauth.action.fix") }}
|
|
674
738
|
</NuxtLink>.
|
|
675
739
|
</div>
|
|
676
740
|
|
|
@@ -685,7 +749,7 @@ function formatDateTime(iso) {
|
|
|
685
749
|
class="border-b border-amber-500/20 bg-amber-500/5 px-4 py-2 text-sm text-amber-800"
|
|
686
750
|
>
|
|
687
751
|
<p class="font-medium">
|
|
688
|
-
|
|
752
|
+
{{ t("integration.editor.validation.banner.title", { summary: warningSummary }) }}
|
|
689
753
|
</p>
|
|
690
754
|
<ul
|
|
691
755
|
class="mt-1 space-y-0.5"
|
|
@@ -704,7 +768,7 @@ function formatDateTime(iso) {
|
|
|
704
768
|
type="button"
|
|
705
769
|
class="text-left underline decoration-amber-700/30 underline-offset-2 hover:decoration-amber-800"
|
|
706
770
|
:title="g.messages.join('\n')"
|
|
707
|
-
:aria-label="
|
|
771
|
+
:aria-label="t('integration.editor.validation.node.ariaFix', g.fields.length, { label: g.label })"
|
|
708
772
|
@click="revealNode(g.nodeId)"
|
|
709
773
|
>
|
|
710
774
|
<span class="font-medium">{{ g.label }}</span> — {{ g.fields.join(", ") }}
|
|
@@ -713,7 +777,7 @@ function formatDateTime(iso) {
|
|
|
713
777
|
</li>
|
|
714
778
|
<li v-if="!warningsExpanded && warningGroups.length > WARN_COLLAPSED" class="pl-3">
|
|
715
779
|
<button type="button" class="text-amber-700/90 underline underline-offset-2 hover:text-amber-900" @click="warningsExpanded = true">
|
|
716
|
-
|
|
780
|
+
{{ t("integration.editor.validation.banner.more", { n: warningGroups.length - WARN_COLLAPSED }) }}
|
|
717
781
|
</button>
|
|
718
782
|
</li>
|
|
719
783
|
</ul>
|
|
@@ -738,7 +802,7 @@ function formatDateTime(iso) {
|
|
|
738
802
|
{{ openRunError }}
|
|
739
803
|
</div>
|
|
740
804
|
<div v-else class="flex items-center gap-2 p-12 text-sm text-muted-foreground">
|
|
741
|
-
<Loader2 :size="16" class="animate-spin" />
|
|
805
|
+
<Loader2 :size="16" class="animate-spin" /> {{ t("integration.editor.run.loading") }}
|
|
742
806
|
</div>
|
|
743
807
|
</div>
|
|
744
808
|
</div>
|
|
@@ -781,19 +845,19 @@ function formatDateTime(iso) {
|
|
|
781
845
|
:loading="runsLoading"
|
|
782
846
|
:pagination="false"
|
|
783
847
|
:show-workflow="false"
|
|
784
|
-
empty-text="
|
|
848
|
+
:empty-text="t('integration.editor.runs.empty')"
|
|
785
849
|
@changed="() => loadRuns()"
|
|
786
850
|
/>
|
|
787
851
|
|
|
788
852
|
<!-- Server pagination — the endpoint pages, so the whole history is reachable. -->
|
|
789
853
|
<div v-if="runsLastPage > 1 || runsTotal > wfRuns.length" class="flex items-center justify-between text-sm text-muted-foreground">
|
|
790
|
-
<span class="tabular-nums">
|
|
854
|
+
<span class="tabular-nums">{{ t("integration.editor.runs.pagination.page", { page: runsPage, lastPage: runsLastPage }) }} · {{ t("integration.editor.runs.pagination.count", runsTotal) }}</span>
|
|
791
855
|
<div class="flex gap-2">
|
|
792
856
|
<Button variant="outline" size="sm" class="h-7 text-sm" :disabled="runsPage <= 1 || runsLoading" @click="goRunsPage(runsPage - 1)">
|
|
793
|
-
|
|
857
|
+
{{ t("integration.editor.runs.pagination.newer") }}
|
|
794
858
|
</Button>
|
|
795
859
|
<Button variant="outline" size="sm" class="h-7 text-sm" :disabled="runsPage >= runsLastPage || runsLoading" @click="goRunsPage(runsPage + 1)">
|
|
796
|
-
|
|
860
|
+
{{ t("integration.editor.runs.pagination.older") }}
|
|
797
861
|
</Button>
|
|
798
862
|
</div>
|
|
799
863
|
</div>
|
|
@@ -811,7 +875,7 @@ function formatDateTime(iso) {
|
|
|
811
875
|
</template>
|
|
812
876
|
|
|
813
877
|
<div v-else class="p-12 text-center text-sm text-muted-foreground">
|
|
814
|
-
|
|
878
|
+
{{ t("integration.editor.state.loading") }}
|
|
815
879
|
</div>
|
|
816
880
|
</div>
|
|
817
881
|
|
|
@@ -819,31 +883,31 @@ function formatDateTime(iso) {
|
|
|
819
883
|
<Dialog v-model:open="runPayloadOpen">
|
|
820
884
|
<DialogContent class="sm:max-w-lg">
|
|
821
885
|
<DialogHeader>
|
|
822
|
-
<DialogTitle>
|
|
886
|
+
<DialogTitle>{{ t("integration.editor.runPayload.dialog.title") }}</DialogTitle>
|
|
823
887
|
<DialogDescription class="text-sm">
|
|
824
|
-
|
|
888
|
+
{{ t("integration.editor.runPayload.dialog.description") }}
|
|
825
889
|
</DialogDescription>
|
|
826
890
|
</DialogHeader>
|
|
827
891
|
<div v-if="eventTriggerTopic" class="flex flex-wrap items-center gap-1.5">
|
|
828
|
-
<span class="text-xs text-muted-foreground">
|
|
892
|
+
<span class="text-xs text-muted-foreground">{{ t("integration.editor.runPayload.prefill.label") }} <code class="font-mono">{{ eventTriggerTopic }}</code>:</span>
|
|
829
893
|
<Button
|
|
830
894
|
variant="outline"
|
|
831
895
|
class="h-7 text-xs"
|
|
832
896
|
:disabled="!catalogSample"
|
|
833
|
-
:title="catalogSample ? '
|
|
897
|
+
:title="catalogSample ? t('integration.editor.runPayload.action.sampleEvent.titleAvailable') : t('integration.editor.runPayload.action.sampleEvent.titleUnavailable')"
|
|
834
898
|
@click="insertSampleEvent"
|
|
835
899
|
>
|
|
836
|
-
|
|
900
|
+
{{ t("integration.editor.runPayload.action.sampleEvent") }}
|
|
837
901
|
</Button>
|
|
838
902
|
<Button
|
|
839
903
|
variant="outline"
|
|
840
904
|
class="h-7 text-xs"
|
|
841
905
|
:disabled="prefillBusy !== null"
|
|
842
|
-
title="
|
|
906
|
+
:title="t('integration.editor.runPayload.action.latestEvent.title')"
|
|
843
907
|
@click="insertLatestEvent"
|
|
844
908
|
>
|
|
845
909
|
<Loader2 v-if="prefillBusy === 'latest'" :size="12" class="animate-spin" />
|
|
846
|
-
|
|
910
|
+
{{ t("integration.editor.runPayload.action.latestEvent") }}
|
|
847
911
|
</Button>
|
|
848
912
|
</div>
|
|
849
913
|
<div class="space-y-1">
|
|
@@ -857,35 +921,35 @@ function formatDateTime(iso) {
|
|
|
857
921
|
<Button
|
|
858
922
|
variant="outline"
|
|
859
923
|
:disabled="running || syncLoading || waitingForBuild || buildFailed"
|
|
860
|
-
:title="buildFailed ? '
|
|
924
|
+
:title="buildFailed ? t('integration.editor.build.tooltip.failed') : void 0"
|
|
861
925
|
class="h-8 text-sm"
|
|
862
926
|
@click="runFromPayloadDialog('sync')"
|
|
863
927
|
>
|
|
864
928
|
<Loader2 v-if="syncLoading || waitingMode === 'sync'" :size="14" class="animate-spin" />
|
|
865
929
|
<Play v-else :size="14" />
|
|
866
|
-
{{ waitingMode === "sync" ? "
|
|
930
|
+
{{ waitingMode === "sync" ? t("integration.editor.run.waitingForBuild") : t("integration.editor.runPayload.action.run", { mode: t("integration.editor.mode.word.sync") }) }}
|
|
867
931
|
</Button>
|
|
868
932
|
<Button
|
|
869
933
|
:disabled="running || syncLoading || waitingForBuild || buildFailed"
|
|
870
|
-
:title="buildFailed ? '
|
|
934
|
+
:title="buildFailed ? t('integration.editor.build.tooltip.failed') : void 0"
|
|
871
935
|
class="h-8 text-sm"
|
|
872
936
|
@click="runFromPayloadDialog('async')"
|
|
873
937
|
>
|
|
874
938
|
<Loader2 v-if="running || waitingMode === 'async'" :size="14" class="animate-spin" />
|
|
875
939
|
<Play v-else :size="14" />
|
|
876
|
-
{{ waitingMode === "async" ? "
|
|
940
|
+
{{ waitingMode === "async" ? t("integration.editor.run.waitingForBuild") : t("integration.editor.runPayload.action.run", { mode: t("integration.editor.mode.word.async") }) }}
|
|
877
941
|
</Button>
|
|
878
942
|
</template>
|
|
879
943
|
<Button
|
|
880
944
|
v-else
|
|
881
945
|
:disabled="running || syncLoading || waitingForBuild || buildFailed"
|
|
882
|
-
:title="buildFailed ? '
|
|
946
|
+
:title="buildFailed ? t('integration.editor.build.tooltip.failed') : void 0"
|
|
883
947
|
class="h-8 text-sm"
|
|
884
948
|
@click="runFromPayloadDialog(primaryMode)"
|
|
885
949
|
>
|
|
886
950
|
<Loader2 v-if="running || syncLoading || waitingForBuild" :size="14" class="animate-spin" />
|
|
887
951
|
<Play v-else :size="14" />
|
|
888
|
-
{{ waitingForBuild ? "
|
|
952
|
+
{{ waitingForBuild ? t("integration.editor.run.waitingForBuild") : t("integration.editor.runPayload.action.run", { mode: t(primaryMode === "sync" ? "integration.editor.mode.word.sync" : "integration.editor.mode.word.async") }) }}
|
|
889
953
|
</Button>
|
|
890
954
|
</div>
|
|
891
955
|
</DialogContent>
|
|
@@ -924,10 +988,11 @@ function formatDateTime(iso) {
|
|
|
924
988
|
}">
|
|
925
989
|
<AlertDialogContent>
|
|
926
990
|
<AlertDialogHeader>
|
|
927
|
-
<AlertDialogTitle>
|
|
991
|
+
<AlertDialogTitle>{{ t("integration.editor.deactivate.dialog.title") }}</AlertDialogTitle>
|
|
928
992
|
<AlertDialogDescription>
|
|
929
|
-
|
|
930
|
-
<span class="font-medium">paused</span>
|
|
993
|
+
{{ t("integration.editor.deactivate.dialog.description.pre") }}
|
|
994
|
+
<span class="font-medium">{{ t("integration.editor.deactivate.dialog.description.paused") }}</span>
|
|
995
|
+
{{ t("integration.editor.deactivate.dialog.description.post") }}
|
|
931
996
|
</AlertDialogDescription>
|
|
932
997
|
</AlertDialogHeader>
|
|
933
998
|
<ul class="max-h-48 space-y-0.5 overflow-y-auto rounded-md border border-amber-500/20 bg-amber-500/5 px-3 py-2 text-sm text-amber-800">
|
|
@@ -938,11 +1003,11 @@ function formatDateTime(iso) {
|
|
|
938
1003
|
</ul>
|
|
939
1004
|
<AlertDialogFooter>
|
|
940
1005
|
<Button variant="outline" :disabled="saving" @click="deactivationOpen = false">
|
|
941
|
-
|
|
1006
|
+
{{ t("integration.editor.deactivate.dialog.cancel") }}
|
|
942
1007
|
</Button>
|
|
943
1008
|
<Button class="bg-emerald-600 text-white hover:bg-emerald-700" :disabled="saving" @click="confirmDeactivate">
|
|
944
1009
|
<Loader2 v-if="saving" :size="12" class="animate-spin" />
|
|
945
|
-
|
|
1010
|
+
{{ t("integration.editor.deactivate.dialog.confirm") }}
|
|
946
1011
|
</Button>
|
|
947
1012
|
</AlertDialogFooter>
|
|
948
1013
|
</AlertDialogContent>
|