@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
|
@@ -61,6 +61,7 @@ const props = defineProps({
|
|
|
61
61
|
overlayOpen: { type: Boolean, required: false }
|
|
62
62
|
});
|
|
63
63
|
const emit = defineEmits(["change", "run", "toggleActive", "openSettings"]);
|
|
64
|
+
const t = useIntegrationsT();
|
|
64
65
|
const { keys: secretKeys } = useIntegrationsSecrets();
|
|
65
66
|
const blob = ref(clone(props.workflow.blob));
|
|
66
67
|
watch(() => props.workflow.id, () => {
|
|
@@ -127,7 +128,7 @@ function triggerPosition(id, index) {
|
|
|
127
128
|
function nodePosition(id) {
|
|
128
129
|
const wn = blob.value.nodes.find((n) => n.id === id);
|
|
129
130
|
if (wn) return { x: wn.position?.x ?? 0, y: wn.position?.y ?? 0 };
|
|
130
|
-
const ti = blob.value.triggers.findIndex((
|
|
131
|
+
const ti = blob.value.triggers.findIndex((t2) => t2.id === id);
|
|
131
132
|
if (ti >= 0) return triggerPosition(id, ti);
|
|
132
133
|
return { x: 0, y: 0 };
|
|
133
134
|
}
|
|
@@ -197,7 +198,7 @@ function ungroup(id) {
|
|
|
197
198
|
push();
|
|
198
199
|
}
|
|
199
200
|
function createGroupFromSelection(ids) {
|
|
200
|
-
const valid = ids.filter((id2) => blob.value.nodes.some((n) => n.id === id2) || blob.value.triggers.some((
|
|
201
|
+
const valid = ids.filter((id2) => blob.value.nodes.some((n) => n.id === id2) || blob.value.triggers.some((t2) => t2.id === id2));
|
|
201
202
|
if (valid.length < 1) return;
|
|
202
203
|
for (const g of blob.value.groups ?? []) {
|
|
203
204
|
g.nodeIds = g.nodeIds.filter((x) => !valid.includes(x));
|
|
@@ -206,7 +207,7 @@ function createGroupFromSelection(ids) {
|
|
|
206
207
|
const id = `g-${Date.now().toString(36)}${Math.random().toString(36).slice(2, 6)}`;
|
|
207
208
|
blob.value.groups = [...blob.value.groups ?? [], {
|
|
208
209
|
id,
|
|
209
|
-
label:
|
|
210
|
+
label: t("integration.editor.group.defaultLabel", { n: (blob.value.groups?.length ?? 0) + 1 }),
|
|
210
211
|
nodeIds: valid
|
|
211
212
|
}];
|
|
212
213
|
syncFromBlob();
|
|
@@ -267,12 +268,12 @@ function syncFromBlob() {
|
|
|
267
268
|
onRemove: () => removeBlobNode(s.id)
|
|
268
269
|
}
|
|
269
270
|
})),
|
|
270
|
-
...blob.value.triggers.filter((
|
|
271
|
-
id:
|
|
271
|
+
...blob.value.triggers.filter((t2) => !collapsedBy.has(t2.id)).map((t2, i) => ({
|
|
272
|
+
id: t2.id,
|
|
272
273
|
type: "trigger",
|
|
273
|
-
position: triggerPosition(
|
|
274
|
-
class: bornClass(
|
|
275
|
-
data:
|
|
274
|
+
position: triggerPosition(t2.id, i),
|
|
275
|
+
class: bornClass(t2.id),
|
|
276
|
+
data: t2
|
|
276
277
|
})),
|
|
277
278
|
...blob.value.nodes.filter((n) => !collapsedBy.has(n.id)).map((n) => ({
|
|
278
279
|
id: n.id,
|
|
@@ -394,7 +395,7 @@ function persistDraggedNodes(evt) {
|
|
|
394
395
|
const dy = Math.round(n.position.y - origin.frame.y);
|
|
395
396
|
for (const [id, memberPos] of Object.entries(origin.members)) {
|
|
396
397
|
const target = { x: Math.round(memberPos.x + dx), y: Math.round(memberPos.y + dy) };
|
|
397
|
-
if (blob.value.triggers.some((
|
|
398
|
+
if (blob.value.triggers.some((t2) => t2.id === id)) {
|
|
398
399
|
blob.value.triggerPositions = { ...blob.value.triggerPositions ?? {}, [id]: target };
|
|
399
400
|
} else {
|
|
400
401
|
const wn = blob.value.nodes.find((b) => b.id === id);
|
|
@@ -407,7 +408,7 @@ function persistDraggedNodes(evt) {
|
|
|
407
408
|
}
|
|
408
409
|
continue;
|
|
409
410
|
}
|
|
410
|
-
if (blob.value.triggers.some((
|
|
411
|
+
if (blob.value.triggers.some((t2) => t2.id === n.id)) {
|
|
411
412
|
blob.value.triggerPositions = { ...blob.value.triggerPositions ?? {}, [n.id]: pos };
|
|
412
413
|
} else if (blob.value.stickies?.some((s) => s.id === n.id)) {
|
|
413
414
|
const st = blob.value.stickies.find((s) => s.id === n.id);
|
|
@@ -456,7 +457,7 @@ flow.onConnectEnd((event) => {
|
|
|
456
457
|
pendingConnect.value = { sourceId: start.sourceId, output: start.output, pos: { x: snap(pos.x), y: snap(pos.y) } };
|
|
457
458
|
pendingSpliceEdgeId.value = null;
|
|
458
459
|
void focusPalette();
|
|
459
|
-
toast.info("
|
|
460
|
+
toast.info(t("integration.editor.quickConnect.toast"));
|
|
460
461
|
});
|
|
461
462
|
flow.onEdgeUpdate(({ edge, connection }) => {
|
|
462
463
|
if (!connection.source || !connection.target) return;
|
|
@@ -479,9 +480,11 @@ flow.onEdgesChange((changes) => {
|
|
|
479
480
|
if (mutated) push();
|
|
480
481
|
});
|
|
481
482
|
flow.onNodesChange((changes) => {
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
483
|
+
const removed = changes.filter((c) => c.type === "remove").map((c) => c.id);
|
|
484
|
+
if (!removed.length) return;
|
|
485
|
+
void nextTick(() => {
|
|
486
|
+
for (const id of removed) removeBlobNode(id);
|
|
487
|
+
});
|
|
485
488
|
});
|
|
486
489
|
function stripFromGroups(drop) {
|
|
487
490
|
if (!blob.value.groups?.length) return;
|
|
@@ -496,7 +499,7 @@ function removeBlobNode(id) {
|
|
|
496
499
|
stripFromGroups(/* @__PURE__ */ new Set([id]));
|
|
497
500
|
blob.value.nodes = blob.value.nodes.filter((n) => n.id !== id);
|
|
498
501
|
if (blob.value.stickies?.length) blob.value.stickies = blob.value.stickies.filter((s) => s.id !== id);
|
|
499
|
-
blob.value.triggers = blob.value.triggers.filter((
|
|
502
|
+
blob.value.triggers = blob.value.triggers.filter((t2) => t2.id !== id);
|
|
500
503
|
blob.value.edges = blob.value.edges.filter((e) => e.from.nodeId !== id && e.to.nodeId !== id);
|
|
501
504
|
if (blob.value.triggerPositions?.[id]) delete blob.value.triggerPositions[id];
|
|
502
505
|
if (selectedId.value === id) selectedId.value = null;
|
|
@@ -527,7 +530,7 @@ function addSticky(at) {
|
|
|
527
530
|
id: `s-${Date.now().toString(36)}${Math.random().toString(36).slice(2, 6)}`,
|
|
528
531
|
// n8n-style starter content: teaches the edit gesture and the supported
|
|
529
532
|
// markdown by example.
|
|
530
|
-
content: "
|
|
533
|
+
content: t("integration.editor.sticky.starterContent"),
|
|
531
534
|
position: at ? { x: Math.round(at.x), y: Math.round(at.y) } : {
|
|
532
535
|
x: Math.round(center.x - STICKY_DEFAULT_SIZE.width / 2),
|
|
533
536
|
y: Math.round(center.y - STICKY_DEFAULT_SIZE.height / 2)
|
|
@@ -543,7 +546,7 @@ function removeBlobNodes(ids) {
|
|
|
543
546
|
const drop = new Set(ids);
|
|
544
547
|
stripFromGroups(drop);
|
|
545
548
|
blob.value.nodes = blob.value.nodes.filter((n) => !drop.has(n.id));
|
|
546
|
-
blob.value.triggers = blob.value.triggers.filter((
|
|
549
|
+
blob.value.triggers = blob.value.triggers.filter((t2) => !drop.has(t2.id));
|
|
547
550
|
blob.value.edges = blob.value.edges.filter((e) => !drop.has(e.from.nodeId) && !drop.has(e.to.nodeId));
|
|
548
551
|
if (blob.value.stickies?.length) blob.value.stickies = blob.value.stickies.filter((s) => !drop.has(s.id));
|
|
549
552
|
for (const id of ids) {
|
|
@@ -602,9 +605,9 @@ async function copyNodes(ids) {
|
|
|
602
605
|
const edges = blob.value.edges.filter((e) => inner.has(e.from.nodeId) && inner.has(e.to.nodeId));
|
|
603
606
|
try {
|
|
604
607
|
await navigator.clipboard.writeText(JSON.stringify({ kind: CLIP_KIND, version: 1, nodes, edges }, null, 2));
|
|
605
|
-
toast.success(
|
|
608
|
+
toast.success(t("integration.editor.clipboard.toast.copied", nodes.length));
|
|
606
609
|
} catch {
|
|
607
|
-
toast.error("
|
|
610
|
+
toast.error(t("integration.editor.clipboard.error.write"));
|
|
608
611
|
}
|
|
609
612
|
}
|
|
610
613
|
async function pasteNodes(at) {
|
|
@@ -612,18 +615,18 @@ async function pasteNodes(at) {
|
|
|
612
615
|
try {
|
|
613
616
|
text = await navigator.clipboard.readText();
|
|
614
617
|
} catch {
|
|
615
|
-
toast.error("
|
|
618
|
+
toast.error(t("integration.editor.clipboard.error.read"));
|
|
616
619
|
return;
|
|
617
620
|
}
|
|
618
621
|
let payload;
|
|
619
622
|
try {
|
|
620
623
|
payload = JSON.parse(text);
|
|
621
624
|
} catch {
|
|
622
|
-
toast.error("
|
|
625
|
+
toast.error(t("integration.editor.clipboard.error.empty"));
|
|
623
626
|
return;
|
|
624
627
|
}
|
|
625
628
|
if (payload?.kind !== CLIP_KIND || !Array.isArray(payload.nodes) || !payload.nodes.length) {
|
|
626
|
-
toast.error("
|
|
629
|
+
toast.error(t("integration.editor.clipboard.error.empty"));
|
|
627
630
|
return;
|
|
628
631
|
}
|
|
629
632
|
const idMap = /* @__PURE__ */ new Map();
|
|
@@ -739,9 +742,9 @@ function isValidConnection(conn) {
|
|
|
739
742
|
const selectedId = ref(null);
|
|
740
743
|
const selection = computed(() => {
|
|
741
744
|
if (!selectedId.value) return null;
|
|
742
|
-
return blob.value.nodes.find((n) => n.id === selectedId.value) ?? blob.value.triggers.find((
|
|
745
|
+
return blob.value.nodes.find((n) => n.id === selectedId.value) ?? blob.value.triggers.find((t2) => t2.id === selectedId.value) ?? null;
|
|
743
746
|
});
|
|
744
|
-
const selectionIsTrigger = computed(() => !!selectedId.value && blob.value.triggers.some((
|
|
747
|
+
const selectionIsTrigger = computed(() => !!selectedId.value && blob.value.triggers.some((t2) => t2.id === selectedId.value));
|
|
745
748
|
flow.onNodeDoubleClick((evt) => {
|
|
746
749
|
if (evt.node.type === "sticky" || evt.node.type === "group") return;
|
|
747
750
|
selectedId.value = evt.node.id;
|
|
@@ -762,7 +765,7 @@ function centerOnNode(id) {
|
|
|
762
765
|
function revealNode(id) {
|
|
763
766
|
if (paneReady.value) centerOnNode(id);
|
|
764
767
|
else pendingReveal.value = id;
|
|
765
|
-
if (blob.value.nodes.some((n) => n.id === id) || blob.value.triggers.some((
|
|
768
|
+
if (blob.value.nodes.some((n) => n.id === id) || blob.value.triggers.some((t2) => t2.id === id)) {
|
|
766
769
|
renameIntent.value = false;
|
|
767
770
|
selectedId.value = id;
|
|
768
771
|
}
|
|
@@ -789,7 +792,7 @@ const selectedUpstreamOutputs = computed(() => {
|
|
|
789
792
|
});
|
|
790
793
|
function applyInspectorUpdate(next) {
|
|
791
794
|
const id = next.id;
|
|
792
|
-
const triggerIdx = blob.value.triggers.findIndex((
|
|
795
|
+
const triggerIdx = blob.value.triggers.findIndex((t2) => t2.id === id);
|
|
793
796
|
if (triggerIdx >= 0) {
|
|
794
797
|
blob.value.triggers[triggerIdx] = next;
|
|
795
798
|
} else {
|
|
@@ -862,7 +865,7 @@ function addFromPayload(payload, pos) {
|
|
|
862
865
|
const id2 = `g-${Date.now().toString(36)}${Math.random().toString(36).slice(2, 6)}`;
|
|
863
866
|
blob.value.groups = [...blob.value.groups ?? [], {
|
|
864
867
|
id: id2,
|
|
865
|
-
label:
|
|
868
|
+
label: t("integration.editor.group.defaultLabel", { n: (blob.value.groups?.length ?? 0) + 1 }),
|
|
866
869
|
nodeIds: [],
|
|
867
870
|
rect: { x: at.x, y: at.y, ...EMPTY_GROUP_SIZE }
|
|
868
871
|
}];
|
|
@@ -872,7 +875,7 @@ function addFromPayload(payload, pos) {
|
|
|
872
875
|
return;
|
|
873
876
|
}
|
|
874
877
|
if (payload.kind === "trigger") {
|
|
875
|
-
const tpl = TRIGGER_TEMPLATES.find((
|
|
878
|
+
const tpl = TRIGGER_TEMPLATES.find((t2) => t2.type === payload.type);
|
|
876
879
|
if (!tpl) return;
|
|
877
880
|
const id2 = crypto.randomUUID();
|
|
878
881
|
blob.value.triggers.push({ id: id2, type: tpl.type, config: { ...tpl.defaultConfig } });
|
|
@@ -950,7 +953,7 @@ provide("workflow-edge-actions", {
|
|
|
950
953
|
if (!blob.value.edges.some((e) => e.id === edgeId)) return;
|
|
951
954
|
pendingSpliceEdgeId.value = edgeId;
|
|
952
955
|
void focusPalette();
|
|
953
|
-
toast.info("
|
|
956
|
+
toast.info(t("integration.editor.splice.toast"));
|
|
954
957
|
}
|
|
955
958
|
});
|
|
956
959
|
function primaryOutputName(slug, version) {
|
|
@@ -962,7 +965,7 @@ function spliceIntoEdge(edgeId, payload) {
|
|
|
962
965
|
const manifest = findManifest(payload.slug, payload.version);
|
|
963
966
|
if (!edge || !manifest) return;
|
|
964
967
|
if (isTerminalManifest(manifest)) {
|
|
965
|
-
toast.error(
|
|
968
|
+
toast.error(t("integration.editor.splice.error.terminal", { name: resolveLocalized(manifest.name) || manifest.slug }));
|
|
966
969
|
return;
|
|
967
970
|
}
|
|
968
971
|
const a = nodePosition(edge.from.nodeId);
|
|
@@ -1298,7 +1301,7 @@ const edgeTypes = {
|
|
|
1298
1301
|
:kind="menu.kind"
|
|
1299
1302
|
:selection-count="flow.getSelectedNodes.value.length"
|
|
1300
1303
|
:total-nodes="vfNodes.length"
|
|
1301
|
-
:target-is-trigger="!!menu.targetId && blob.triggers.some((
|
|
1304
|
+
:target-is-trigger="!!menu.targetId && blob.triggers.some((t2) => t2.id === menu.targetId)"
|
|
1302
1305
|
:run-busy="runBusy"
|
|
1303
1306
|
@action="onMenuAction"
|
|
1304
1307
|
>
|
|
@@ -1351,7 +1354,7 @@ const edgeTypes = {
|
|
|
1351
1354
|
class="absolute -top-0.5 left-1/2 -translate-x-1/2 -translate-y-full rounded-md px-1.5 py-0.5 text-xs font-medium text-white shadow-sm"
|
|
1352
1355
|
:class="nodeDrag.dragging.value?.kind === 'trigger' ? 'bg-emerald-500' : nodeDrag.dragging.value?.kind === 'group' ? 'bg-slate-500' : 'bg-violet-500'"
|
|
1353
1356
|
>
|
|
1354
|
-
|
|
1357
|
+
{{ t("integration.editor.dropGhost.label") }}
|
|
1355
1358
|
</span>
|
|
1356
1359
|
</div>
|
|
1357
1360
|
</Transition>
|
|
@@ -1404,11 +1407,11 @@ const edgeTypes = {
|
|
|
1404
1407
|
<button
|
|
1405
1408
|
type="button"
|
|
1406
1409
|
class="flex h-9 items-center gap-1.5 rounded-lg bg-white px-3 text-sm font-medium transition hover:bg-muted/75 hover:cursor-pointer"
|
|
1407
|
-
title="
|
|
1410
|
+
:title="t('integration.editor.palette.action.expand.title')"
|
|
1408
1411
|
@click="void focusPalette()"
|
|
1409
1412
|
>
|
|
1410
1413
|
<Plus :size="14" class="text-emerald-600" />
|
|
1411
|
-
|
|
1414
|
+
{{ t("integration.editor.palette.title") }}
|
|
1412
1415
|
</button>
|
|
1413
1416
|
</div>
|
|
1414
1417
|
</div>
|
|
@@ -1427,29 +1430,29 @@ const edgeTypes = {
|
|
|
1427
1430
|
@pointerdown="palette.startDrag($event, paletteShellRef)"
|
|
1428
1431
|
>
|
|
1429
1432
|
<GripVertical :size="14" class="shrink-0 text-muted-foreground/60" />
|
|
1430
|
-
<span class="min-w-0 flex-1 truncate text-sm font-medium">
|
|
1433
|
+
<span class="min-w-0 flex-1 truncate text-sm font-medium">{{ t("integration.editor.palette.title") }}</span>
|
|
1431
1434
|
<DropdownMenu>
|
|
1432
1435
|
<DropdownMenuTrigger as-child>
|
|
1433
1436
|
<button
|
|
1434
1437
|
type="button"
|
|
1435
1438
|
class="flex size-6 shrink-0 items-center justify-center rounded-md text-muted-foreground transition hover:bg-muted/50 hover:text-foreground"
|
|
1436
|
-
title="
|
|
1439
|
+
:title="t('integration.editor.palette.action.placement.title')"
|
|
1437
1440
|
>
|
|
1438
1441
|
<EllipsisVertical :size="14" />
|
|
1439
1442
|
</button>
|
|
1440
1443
|
</DropdownMenuTrigger>
|
|
1441
1444
|
<DropdownMenuContent align="end" class="w-36 rounded-lg border border-black/[0.06] bg-white p-1 shadow-lg">
|
|
1442
|
-
<DropdownMenuItem class="rounded-md text-sm" @select="palette.dock('left')">
|
|
1443
|
-
<DropdownMenuItem class="rounded-md text-sm" @select="palette.dock('right')">
|
|
1444
|
-
<DropdownMenuItem class="rounded-md text-sm" @select="palette.floatHere(paletteShellRef)">
|
|
1445
|
+
<DropdownMenuItem class="rounded-md text-sm" @select="palette.dock('left')">{{ t("integration.editor.palette.action.dockLeft") }}</DropdownMenuItem>
|
|
1446
|
+
<DropdownMenuItem class="rounded-md text-sm" @select="palette.dock('right')">{{ t("integration.editor.palette.action.dockRight") }}</DropdownMenuItem>
|
|
1447
|
+
<DropdownMenuItem class="rounded-md text-sm" @select="palette.floatHere(paletteShellRef)">{{ t("integration.editor.panel.action.floatHere") }}</DropdownMenuItem>
|
|
1445
1448
|
<DropdownMenuSeparator class="my-1 h-px bg-black/[0.06]" />
|
|
1446
|
-
<DropdownMenuItem class="rounded-md text-sm" @select="palette.setCollapsed(true)">
|
|
1449
|
+
<DropdownMenuItem class="rounded-md text-sm" @select="palette.setCollapsed(true)">{{ t("integration.editor.panel.action.collapse") }}</DropdownMenuItem>
|
|
1447
1450
|
</DropdownMenuContent>
|
|
1448
1451
|
</DropdownMenu>
|
|
1449
1452
|
<button
|
|
1450
1453
|
type="button"
|
|
1451
1454
|
class="flex size-6 shrink-0 items-center justify-center rounded-md text-muted-foreground transition hover:bg-muted/50 hover:text-foreground"
|
|
1452
|
-
title="
|
|
1455
|
+
:title="t('integration.editor.palette.action.collapse.title')"
|
|
1453
1456
|
@click="palette.setCollapsed(true)"
|
|
1454
1457
|
>
|
|
1455
1458
|
<Minus :size="14" />
|
|
@@ -1491,11 +1494,11 @@ const edgeTypes = {
|
|
|
1491
1494
|
<button
|
|
1492
1495
|
type="button"
|
|
1493
1496
|
class="flex h-9 items-center gap-1.5 rounded-lg bg-white px-3 text-sm font-medium transition hover:bg-muted/75 hover:cursor-pointer"
|
|
1494
|
-
title="
|
|
1497
|
+
:title="t('integration.editor.minimap.action.expand.title')"
|
|
1495
1498
|
@click="minimapLayout.setCollapsed(false)"
|
|
1496
1499
|
>
|
|
1497
1500
|
<MapIcon :size="14" class="text-emerald-600" />
|
|
1498
|
-
|
|
1501
|
+
{{ t("integration.editor.minimap.title") }}
|
|
1499
1502
|
</button>
|
|
1500
1503
|
</div>
|
|
1501
1504
|
</div>
|
|
@@ -1514,31 +1517,31 @@ const edgeTypes = {
|
|
|
1514
1517
|
@pointerdown="minimapLayout.startDrag($event, minimapShellRef)"
|
|
1515
1518
|
>
|
|
1516
1519
|
<GripVertical :size="14" class="shrink-0 text-muted-foreground/60" />
|
|
1517
|
-
<span class="min-w-0 flex-1 truncate text-sm font-medium">
|
|
1520
|
+
<span class="min-w-0 flex-1 truncate text-sm font-medium">{{ t("integration.editor.minimap.title") }}</span>
|
|
1518
1521
|
<DropdownMenu>
|
|
1519
1522
|
<DropdownMenuTrigger as-child>
|
|
1520
1523
|
<button
|
|
1521
1524
|
type="button"
|
|
1522
1525
|
class="flex size-6 shrink-0 items-center justify-center rounded-md text-muted-foreground transition hover:bg-muted/50 hover:text-foreground"
|
|
1523
|
-
title="
|
|
1526
|
+
:title="t('integration.editor.minimap.action.placement.title')"
|
|
1524
1527
|
>
|
|
1525
1528
|
<EllipsisVertical :size="14" />
|
|
1526
1529
|
</button>
|
|
1527
1530
|
</DropdownMenuTrigger>
|
|
1528
1531
|
<DropdownMenuContent align="end" class="w-40 rounded-lg border border-black/[0.06] bg-white p-1 shadow-lg">
|
|
1529
|
-
<DropdownMenuItem class="rounded-md text-sm" @select="minimapLayout.dock('top-left')">
|
|
1530
|
-
<DropdownMenuItem class="rounded-md text-sm" @select="minimapLayout.dock('top-right')">
|
|
1531
|
-
<DropdownMenuItem class="rounded-md text-sm" @select="minimapLayout.dock('bottom-left')">
|
|
1532
|
-
<DropdownMenuItem class="rounded-md text-sm" @select="minimapLayout.dock('bottom-right')">
|
|
1533
|
-
<DropdownMenuItem class="rounded-md text-sm" @select="minimapLayout.floatHere(minimapShellRef)">
|
|
1532
|
+
<DropdownMenuItem class="rounded-md text-sm" @select="minimapLayout.dock('top-left')">{{ t("integration.editor.minimap.action.topLeft") }}</DropdownMenuItem>
|
|
1533
|
+
<DropdownMenuItem class="rounded-md text-sm" @select="minimapLayout.dock('top-right')">{{ t("integration.editor.minimap.action.topRight") }}</DropdownMenuItem>
|
|
1534
|
+
<DropdownMenuItem class="rounded-md text-sm" @select="minimapLayout.dock('bottom-left')">{{ t("integration.editor.minimap.action.bottomLeft") }}</DropdownMenuItem>
|
|
1535
|
+
<DropdownMenuItem class="rounded-md text-sm" @select="minimapLayout.dock('bottom-right')">{{ t("integration.editor.minimap.action.bottomRight") }}</DropdownMenuItem>
|
|
1536
|
+
<DropdownMenuItem class="rounded-md text-sm" @select="minimapLayout.floatHere(minimapShellRef)">{{ t("integration.editor.panel.action.floatHere") }}</DropdownMenuItem>
|
|
1534
1537
|
<DropdownMenuSeparator class="my-1 h-px bg-black/[0.06]" />
|
|
1535
|
-
<DropdownMenuItem class="rounded-md text-sm" @select="minimapLayout.setCollapsed(true)">
|
|
1538
|
+
<DropdownMenuItem class="rounded-md text-sm" @select="minimapLayout.setCollapsed(true)">{{ t("integration.editor.panel.action.collapse") }}</DropdownMenuItem>
|
|
1536
1539
|
</DropdownMenuContent>
|
|
1537
1540
|
</DropdownMenu>
|
|
1538
1541
|
<button
|
|
1539
1542
|
type="button"
|
|
1540
1543
|
class="flex size-6 shrink-0 items-center justify-center rounded-md text-muted-foreground transition hover:bg-muted/50 hover:text-foreground"
|
|
1541
|
-
title="
|
|
1544
|
+
:title="t('integration.editor.minimap.action.collapse.title')"
|
|
1542
1545
|
@click="minimapLayout.setCollapsed(true)"
|
|
1543
1546
|
>
|
|
1544
1547
|
<Minus :size="14" />
|
|
@@ -1564,7 +1567,7 @@ const edgeTypes = {
|
|
|
1564
1567
|
<!-- Smart Run: the page decides what "run" means — workflows that
|
|
1565
1568
|
consume trigger.payload open the payload dialog, payload-free
|
|
1566
1569
|
ones fire immediately. One button either way. -->
|
|
1567
|
-
<IntegrationsEditorTip :label="runWaiting ? '
|
|
1570
|
+
<IntegrationsEditorTip :label="runWaiting ? t('integration.editor.tool.run.tooltipWaiting') : t('integration.editor.tool.run.tooltip')" shortcut="mod+enter">
|
|
1568
1571
|
<button
|
|
1569
1572
|
type="button"
|
|
1570
1573
|
class="relative flex h-8 items-center gap-1.5 rounded-lg bg-gradient-to-b from-emerald-500 to-emerald-600 px-3.5 text-sm font-medium text-white transition after:pointer-events-none after:absolute after:inset-0 after:rounded-[inherit] after:shadow-[inset_0_1px_0_rgba(255,255,255,0.3),inset_0_-2px_0_rgba(0,0,0,0.25)] hover:from-emerald-600 hover:to-emerald-600 active:translate-y-px disabled:opacity-60"
|
|
@@ -1573,7 +1576,7 @@ const edgeTypes = {
|
|
|
1573
1576
|
>
|
|
1574
1577
|
<Loader2 v-if="runBusy" :size="14" class="animate-spin" />
|
|
1575
1578
|
<Play v-else :size="14" />
|
|
1576
|
-
{{ runWaiting ? "
|
|
1579
|
+
{{ runWaiting ? t("integration.editor.run.waitingForBuild") : t("integration.editor.run.button") }}
|
|
1577
1580
|
</button>
|
|
1578
1581
|
</IntegrationsEditorTip>
|
|
1579
1582
|
|
|
@@ -1582,10 +1585,10 @@ const edgeTypes = {
|
|
|
1582
1585
|
<div class="flex items-center gap-0.5 rounded-lg bg-black/[0.05] p-0.5 shadow-[inset_0_1px_2px_rgba(15,23,42,0.12)]">
|
|
1583
1586
|
<!-- Icon-only, and the tooltip is not an accessible name: each one
|
|
1584
1587
|
says what it does itself, and whether it is the active mode. -->
|
|
1585
|
-
<IntegrationsEditorTip label="
|
|
1588
|
+
<IntegrationsEditorTip :label="t('integration.editor.tool.select')" shortcut="v">
|
|
1586
1589
|
<button
|
|
1587
1590
|
type="button"
|
|
1588
|
-
aria-label="
|
|
1591
|
+
:aria-label="t('integration.editor.tool.select')"
|
|
1589
1592
|
:aria-pressed="pointerMode === 'select'"
|
|
1590
1593
|
class="flex size-7 items-center justify-center rounded-lg transition"
|
|
1591
1594
|
:class="pointerMode === 'select' ? 'bg-gradient-to-b from-white to-gray-50 text-foreground shadow-[0_1px_2px_rgba(15,23,42,0.18),inset_0_1px_0_rgba(255,255,255,0.9)]' : 'text-muted-foreground hover:text-foreground'"
|
|
@@ -1594,10 +1597,10 @@ const edgeTypes = {
|
|
|
1594
1597
|
<MousePointer2 :size="14" />
|
|
1595
1598
|
</button>
|
|
1596
1599
|
</IntegrationsEditorTip>
|
|
1597
|
-
<IntegrationsEditorTip label="
|
|
1600
|
+
<IntegrationsEditorTip :label="t('integration.editor.tool.hand')" shortcut="h">
|
|
1598
1601
|
<button
|
|
1599
1602
|
type="button"
|
|
1600
|
-
aria-label="
|
|
1603
|
+
:aria-label="t('integration.editor.tool.hand')"
|
|
1601
1604
|
:aria-pressed="pointerMode === 'hand'"
|
|
1602
1605
|
class="flex size-7 items-center justify-center rounded-lg transition"
|
|
1603
1606
|
:class="pointerMode === 'hand' ? 'bg-gradient-to-b from-white to-gray-50 text-foreground shadow-[0_1px_2px_rgba(15,23,42,0.18),inset_0_1px_0_rgba(255,255,255,0.9)]' : 'text-muted-foreground hover:text-foreground'"
|
|
@@ -1608,74 +1611,74 @@ const edgeTypes = {
|
|
|
1608
1611
|
</IntegrationsEditorTip>
|
|
1609
1612
|
</div>
|
|
1610
1613
|
|
|
1611
|
-
<IntegrationsEditorTip label="
|
|
1614
|
+
<IntegrationsEditorTip :label="t('integration.editor.tool.tidyUp')" shortcut="shift+alt+t">
|
|
1612
1615
|
<button
|
|
1613
1616
|
type="button"
|
|
1614
1617
|
class="flex h-8 items-center gap-1.5 rounded-lg px-2.5 text-sm font-medium text-foreground transition hover:bg-black/[0.04]"
|
|
1615
1618
|
@click="tidyUp"
|
|
1616
1619
|
>
|
|
1617
1620
|
<LayoutGrid :size="13" />
|
|
1618
|
-
|
|
1621
|
+
{{ t("integration.editor.tool.tidyUp") }}
|
|
1619
1622
|
</button>
|
|
1620
1623
|
</IntegrationsEditorTip>
|
|
1621
|
-
<IntegrationsEditorTip label="
|
|
1624
|
+
<IntegrationsEditorTip :label="t('integration.editor.tool.fitView.tooltip')" shortcut="1">
|
|
1622
1625
|
<button
|
|
1623
1626
|
type="button"
|
|
1624
1627
|
class="flex h-8 items-center gap-1.5 rounded-lg px-2.5 text-sm font-medium text-foreground transition hover:bg-black/[0.04]"
|
|
1625
1628
|
@click="flow.fitView({ padding: 0.2, duration: 400, maxZoom: 1 })"
|
|
1626
1629
|
>
|
|
1627
1630
|
<Sparkles :size="13" />
|
|
1628
|
-
|
|
1631
|
+
{{ t("integration.editor.tool.fitView.label") }}
|
|
1629
1632
|
</button>
|
|
1630
1633
|
</IntegrationsEditorTip>
|
|
1631
|
-
<IntegrationsEditorTip label="
|
|
1634
|
+
<IntegrationsEditorTip :label="t('integration.editor.tool.addSticky.tooltip')" shortcut="shift+s">
|
|
1632
1635
|
<button
|
|
1633
1636
|
type="button"
|
|
1634
1637
|
class="flex h-8 items-center gap-1.5 rounded-lg px-2.5 text-sm font-medium text-foreground transition hover:bg-black/[0.04]"
|
|
1635
1638
|
@click="addSticky()"
|
|
1636
1639
|
>
|
|
1637
1640
|
<StickyNote :size="13" />
|
|
1638
|
-
|
|
1641
|
+
{{ t("integration.editor.tool.addSticky.label") }}
|
|
1639
1642
|
</button>
|
|
1640
1643
|
</IntegrationsEditorTip>
|
|
1641
|
-
<IntegrationsEditorTip label="
|
|
1644
|
+
<IntegrationsEditorTip :label="t('integration.editor.tool.addGroup.tooltip')">
|
|
1642
1645
|
<button
|
|
1643
1646
|
type="button"
|
|
1644
1647
|
class="flex h-8 items-center gap-1.5 rounded-lg px-2.5 text-sm font-medium text-foreground transition hover:bg-black/[0.04]"
|
|
1645
1648
|
@click="addGroupFrame"
|
|
1646
1649
|
>
|
|
1647
1650
|
<GroupIcon :size="13" />
|
|
1648
|
-
|
|
1651
|
+
{{ t("integration.editor.tool.addGroup.label") }}
|
|
1649
1652
|
</button>
|
|
1650
1653
|
</IntegrationsEditorTip>
|
|
1651
|
-
<IntegrationsEditorTip label="
|
|
1654
|
+
<IntegrationsEditorTip :label="t('integration.editor.tool.variables.tooltip')" shortcut="shift+v">
|
|
1652
1655
|
<button
|
|
1653
1656
|
type="button"
|
|
1654
1657
|
class="flex h-8 items-center gap-1.5 rounded-lg px-2.5 text-sm font-medium text-foreground transition hover:bg-black/[0.04]"
|
|
1655
1658
|
@click="variablesOpen = true"
|
|
1656
1659
|
>
|
|
1657
1660
|
<Braces :size="13" />
|
|
1658
|
-
|
|
1661
|
+
{{ t("integration.editor.tool.variables.label") }}
|
|
1659
1662
|
<span v-if="variableCount" class="rounded-lg bg-muted px-1.5 text-xs tabular-nums text-muted-foreground">{{ variableCount }}</span>
|
|
1660
1663
|
</button>
|
|
1661
1664
|
</IntegrationsEditorTip>
|
|
1662
|
-
<IntegrationsEditorTip label="
|
|
1665
|
+
<IntegrationsEditorTip :label="t('integration.editor.tool.settings.tooltip')" shortcut="shift+alt+s">
|
|
1663
1666
|
<button
|
|
1664
1667
|
type="button"
|
|
1665
1668
|
class="flex h-8 items-center gap-1.5 rounded-lg px-2.5 text-sm font-medium text-foreground transition hover:bg-black/[0.04]"
|
|
1666
1669
|
@click="emit('openSettings')"
|
|
1667
1670
|
>
|
|
1668
1671
|
<Settings2 :size="13" />
|
|
1669
|
-
|
|
1672
|
+
{{ t("integration.editor.tool.settings.label") }}
|
|
1670
1673
|
</button>
|
|
1671
1674
|
</IntegrationsEditorTip>
|
|
1672
1675
|
|
|
1673
1676
|
<div class="mx-1 h-5 w-px bg-black/10" />
|
|
1674
1677
|
|
|
1675
|
-
<IntegrationsEditorTip label="
|
|
1678
|
+
<IntegrationsEditorTip :label="t('integration.editor.tool.zoomOut')" shortcut="-">
|
|
1676
1679
|
<button
|
|
1677
1680
|
type="button"
|
|
1678
|
-
aria-label="
|
|
1681
|
+
:aria-label="t('integration.editor.tool.zoomOut')"
|
|
1679
1682
|
class="flex size-8 items-center justify-center rounded-lg text-foreground transition hover:bg-black/[0.04]"
|
|
1680
1683
|
@click="flow.zoomOut({ duration: 150 })"
|
|
1681
1684
|
>
|
|
@@ -1685,7 +1688,7 @@ const edgeTypes = {
|
|
|
1685
1688
|
<!-- Tooltip sits on a wrapper span so its as-child merge never
|
|
1686
1689
|
touches the dropdown trigger (merging both onto one button
|
|
1687
1690
|
swallowed the trigger's pointerdown and the menu never opened). -->
|
|
1688
|
-
<IntegrationsEditorTip label="
|
|
1691
|
+
<IntegrationsEditorTip :label="t('integration.editor.tool.zoomLevel.tooltip')" shortcut="0">
|
|
1689
1692
|
<span class="inline-flex">
|
|
1690
1693
|
<DropdownMenu v-model:open="zoomMenuOpen">
|
|
1691
1694
|
<DropdownMenuTrigger as-child>
|
|
@@ -1695,7 +1698,7 @@ const edgeTypes = {
|
|
|
1695
1698
|
users do not need told and without the value they do. -->
|
|
1696
1699
|
<button
|
|
1697
1700
|
type="button"
|
|
1698
|
-
:aria-label="
|
|
1701
|
+
:aria-label="t('integration.editor.tool.zoomLevel.aria', { pct: zoomPct })"
|
|
1699
1702
|
class="w-12 rounded-lg py-1 text-center text-sm tabular-nums text-muted-foreground transition hover:bg-black/[0.04] hover:text-foreground"
|
|
1700
1703
|
>
|
|
1701
1704
|
{{ zoomPct }}
|
|
@@ -1707,7 +1710,7 @@ const edgeTypes = {
|
|
|
1707
1710
|
v-model="zoomInputText"
|
|
1708
1711
|
type="text"
|
|
1709
1712
|
inputmode="numeric"
|
|
1710
|
-
aria-label="
|
|
1713
|
+
:aria-label="t('integration.editor.tool.zoomLevel.inputAria')"
|
|
1711
1714
|
class="h-6 w-full rounded-md border border-black/[0.08] bg-white px-1 text-center text-sm tabular-nums focus:outline-none focus:ring-2 focus:ring-primary/40"
|
|
1712
1715
|
placeholder="%"
|
|
1713
1716
|
@keydown.stop
|
|
@@ -1727,10 +1730,10 @@ const edgeTypes = {
|
|
|
1727
1730
|
</DropdownMenu>
|
|
1728
1731
|
</span>
|
|
1729
1732
|
</IntegrationsEditorTip>
|
|
1730
|
-
<IntegrationsEditorTip label="
|
|
1733
|
+
<IntegrationsEditorTip :label="t('integration.editor.tool.zoomIn')" shortcut="=">
|
|
1731
1734
|
<button
|
|
1732
1735
|
type="button"
|
|
1733
|
-
aria-label="
|
|
1736
|
+
:aria-label="t('integration.editor.tool.zoomIn')"
|
|
1734
1737
|
class="flex size-8 items-center justify-center rounded-lg text-foreground transition hover:bg-black/[0.04]"
|
|
1735
1738
|
@click="flow.zoomIn({ duration: 150 })"
|
|
1736
1739
|
>
|
|
@@ -1749,10 +1752,10 @@ const edgeTypes = {
|
|
|
1749
1752
|
>
|
|
1750
1753
|
<div class="rounded-lg border border-dashed border-black/[0.12] bg-white/80 px-5 py-4 text-center text-sm text-muted-foreground shadow-sm backdrop-blur-sm">
|
|
1751
1754
|
<div class="font-medium text-foreground mb-1">
|
|
1752
|
-
|
|
1755
|
+
{{ t("integration.editor.emptyState.title") }}
|
|
1753
1756
|
</div>
|
|
1754
1757
|
<p>
|
|
1755
|
-
|
|
1758
|
+
{{ t("integration.editor.emptyState.hint") }}
|
|
1756
1759
|
</p>
|
|
1757
1760
|
</div>
|
|
1758
1761
|
</div>
|