@revenexx/studio-integrations 1.2.0 → 1.4.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 +581 -0
- package/dist/module.json +1 -1
- package/dist/runtime/components/Integrations/CanvasShortcutsDialog.d.vue.ts +9 -0
- package/dist/runtime/components/Integrations/CanvasShortcutsDialog.vue +53 -0
- package/dist/runtime/components/Integrations/CanvasShortcutsDialog.vue.d.ts +9 -0
- package/dist/runtime/components/Integrations/EditorTip.vue +2 -15
- package/dist/runtime/components/Integrations/NodeConfigDynamicSchema.vue +10 -2
- package/dist/runtime/components/Integrations/NodeConfigField.d.vue.ts +15 -1
- package/dist/runtime/components/Integrations/NodeConfigField.vue +158 -49
- package/dist/runtime/components/Integrations/NodeConfigField.vue.d.ts +15 -1
- package/dist/runtime/components/Integrations/NodeInspector.d.vue.ts +5 -1
- package/dist/runtime/components/Integrations/NodeInspector.vue +136 -81
- package/dist/runtime/components/Integrations/NodeInspector.vue.d.ts +5 -1
- package/dist/runtime/components/Integrations/NodeVersionMoveDialog.d.vue.ts +21 -0
- package/dist/runtime/components/Integrations/NodeVersionMoveDialog.vue +133 -0
- package/dist/runtime/components/Integrations/NodeVersionMoveDialog.vue.d.ts +21 -0
- package/dist/runtime/components/Integrations/RunDetailPanel.vue +80 -33
- package/dist/runtime/components/Integrations/StateNamespaceCreateDialog.d.vue.ts +16 -0
- package/dist/runtime/components/Integrations/StateNamespaceCreateDialog.vue +111 -0
- package/dist/runtime/components/Integrations/StateNamespaceCreateDialog.vue.d.ts +16 -0
- package/dist/runtime/components/Integrations/TemplateCard.d.vue.ts +0 -4
- package/dist/runtime/components/Integrations/TemplateCard.vue +3 -6
- package/dist/runtime/components/Integrations/TemplateCard.vue.d.ts +0 -4
- package/dist/runtime/components/Integrations/TemplateInstallStep.d.vue.ts +25 -0
- package/dist/runtime/components/Integrations/TemplateInstallStep.vue +198 -0
- package/dist/runtime/components/Integrations/TemplateInstallStep.vue.d.ts +25 -0
- package/dist/runtime/components/Integrations/WorkflowContextMenu.d.vue.ts +2 -2
- package/dist/runtime/components/Integrations/WorkflowContextMenu.vue +22 -40
- package/dist/runtime/components/Integrations/WorkflowContextMenu.vue.d.ts +2 -2
- package/dist/runtime/components/Integrations/WorkflowCreateDialog.vue +94 -65
- package/dist/runtime/components/Integrations/WorkflowEditor.d.vue.ts +36 -2
- package/dist/runtime/components/Integrations/WorkflowEditor.vue +200 -54
- package/dist/runtime/components/Integrations/WorkflowEditor.vue.d.ts +36 -2
- package/dist/runtime/components/Integrations/WorkflowRunReplayPanel.d.vue.ts +6 -2
- package/dist/runtime/components/Integrations/WorkflowRunReplayPanel.vue +4 -106
- package/dist/runtime/components/Integrations/WorkflowRunReplayPanel.vue.d.ts +6 -2
- package/dist/runtime/components/Integrations/WorkflowStateNamespacesDialog.d.vue.ts +13 -0
- package/dist/runtime/components/Integrations/WorkflowStateNamespacesDialog.vue +216 -0
- package/dist/runtime/components/Integrations/WorkflowStateNamespacesDialog.vue.d.ts +13 -0
- package/dist/runtime/components/Integrations/WorkflowsTable.vue +22 -11
- package/dist/runtime/composables/useCanvasShortcuts.d.ts +34 -0
- package/dist/runtime/composables/useCanvasShortcuts.js +11 -8
- package/dist/runtime/composables/useCredentialTypes.js +3 -9
- package/dist/runtime/composables/useIntegrationsCredentials.js +6 -14
- package/dist/runtime/composables/useIntegrationsNodes.js +2 -2
- package/dist/runtime/composables/useIntegrationsRuns.js +8 -13
- package/dist/runtime/composables/useIntegrationsSecrets.js +5 -5
- package/dist/runtime/composables/useIntegrationsTemplates.js +10 -8
- package/dist/runtime/composables/useIntegrationsTriggers.js +1 -4
- package/dist/runtime/composables/useIntegrationsWorkflows.js +11 -7
- package/dist/runtime/data/canvasShortcuts.d.ts +208 -0
- package/dist/runtime/data/canvasShortcuts.js +68 -0
- package/dist/runtime/data/integrationNodeCatalog.d.ts +25 -0
- package/dist/runtime/data/integrationNodeCatalog.js +8 -0
- package/dist/runtime/data/nodeVersionMove.d.ts +72 -0
- package/dist/runtime/data/nodeVersionMove.js +65 -0
- package/dist/runtime/i18n/messages/de.json +83 -20
- package/dist/runtime/i18n/messages/en.json +83 -20
- package/dist/runtime/pages/integrations/templates/[slug].vue +22 -132
- package/dist/runtime/pages/integrations/workflows/[id].vue +158 -53
- package/dist/runtime/pages/integrations/workflows/index.vue +23 -4
- package/dist/runtime/types/integrations.d.ts +44 -1
- package/dist/runtime/utils/apiEnvelope.d.ts +27 -0
- package/dist/runtime/utils/apiEnvelope.js +20 -0
- package/dist/runtime/utils/buildSettle.d.ts +68 -0
- package/dist/runtime/utils/buildSettle.js +29 -0
- package/dist/runtime/utils/configDefaults.d.ts +18 -0
- package/dist/runtime/utils/configDefaults.js +7 -0
- package/dist/runtime/utils/errorPathAdvice.d.ts +60 -0
- package/dist/runtime/utils/errorPathAdvice.js +19 -0
- package/dist/runtime/utils/notify.d.ts +2 -2
- package/dist/runtime/utils/runEnvelope.d.ts +12 -0
- package/dist/runtime/utils/runEnvelope.js +2 -1
- package/dist/runtime/utils/selectOptions.d.ts +48 -0
- package/dist/runtime/utils/selectOptions.js +19 -0
- package/dist/runtime/utils/settingCondition.d.ts +48 -0
- package/dist/runtime/utils/settingCondition.js +84 -0
- package/dist/runtime/utils/shortcutLabel.d.ts +40 -0
- package/dist/runtime/utils/shortcutLabel.js +48 -0
- package/dist/runtime/utils/stateNamespaceName.d.ts +23 -0
- package/dist/runtime/utils/stateNamespaceName.js +8 -0
- package/package.json +1 -1
|
@@ -28,7 +28,7 @@ import {
|
|
|
28
28
|
DropdownMenuTrigger,
|
|
29
29
|
TooltipProvider
|
|
30
30
|
} from "@revenexx/studio";
|
|
31
|
-
import { Braces, EllipsisVertical, GripVertical, Group as GroupIcon, Hand, Map as MapIcon, Minus, MousePointer2, Plus, Settings2, StickyNote } from "lucide-vue-next";
|
|
31
|
+
import { Braces, Database, EllipsisVertical, GripVertical, Group as GroupIcon, Hand, Keyboard, Map as MapIcon, Minus, MousePointer2, Plus, Settings2, StickyNote } from "lucide-vue-next";
|
|
32
32
|
import "@vue-flow/core/dist/style.css";
|
|
33
33
|
import "@vue-flow/core/dist/theme-default.css";
|
|
34
34
|
import "@vue-flow/minimap/dist/style.css";
|
|
@@ -40,14 +40,19 @@ import WorkflowTriggerView from "./WorkflowTriggerView.vue";
|
|
|
40
40
|
import StickyNoteView from "./StickyNoteView.vue";
|
|
41
41
|
import GroupFrameView from "./GroupFrameView.vue";
|
|
42
42
|
import WorkflowContextMenu, {} from "./WorkflowContextMenu.vue";
|
|
43
|
+
import CanvasShortcutsDialog from "./CanvasShortcutsDialog.vue";
|
|
44
|
+
import WorkflowStateNamespacesDialog from "./WorkflowStateNamespacesDialog.vue";
|
|
43
45
|
import WorkflowVariablesDialog from "./WorkflowVariablesDialog.vue";
|
|
44
46
|
import { useCanvasShortcuts } from "../../composables/useCanvasShortcuts";
|
|
47
|
+
import { libraryKeyCodes, primaryShortcut, shortcutKeys } from "../../data/canvasShortcuts";
|
|
45
48
|
import { usePaletteLayout } from "../../composables/usePaletteLayout";
|
|
46
49
|
import { useMiniMapLayout } from "../../composables/useMiniMapLayout";
|
|
47
50
|
import { toast } from "vue-sonner";
|
|
48
51
|
import WorkflowEdgeView from "./WorkflowEdgeView.vue";
|
|
49
52
|
import { layoutWorkflowNodes } from "./workflowLayout";
|
|
50
|
-
import {
|
|
53
|
+
import { defaultsFor } from "../../utils/configDefaults";
|
|
54
|
+
import { nodeDisplayLabel } from "../../utils/validationFindings";
|
|
55
|
+
import { TRIGGER_TEMPLATES, findManifest, newestExecutableVersion } from "../../data/integrationNodeCatalog";
|
|
51
56
|
import { isTerminalManifest, portsForNode } from "../../data/nodeInputData";
|
|
52
57
|
import { computeLoopBodies, iteratorNodeIds, nodeLoopData } from "../../data/loopBody";
|
|
53
58
|
import { inputHandleId, outputHandleId, portFromHandleId } from "../../data/handleId";
|
|
@@ -382,8 +387,32 @@ function edgeColorByKind(kind) {
|
|
|
382
387
|
syncFromBlob();
|
|
383
388
|
const paneReady = ref(false);
|
|
384
389
|
const pendingReveal = ref(null);
|
|
385
|
-
|
|
386
|
-
|
|
390
|
+
function liftAboveControlPane() {
|
|
391
|
+
const bar = controlBar.value?.getBoundingClientRect();
|
|
392
|
+
const wrap = canvasWrapRef.value?.getBoundingClientRect();
|
|
393
|
+
const vp = flow.viewport.value;
|
|
394
|
+
if (!bar || !wrap || !vp) return;
|
|
395
|
+
let top = Number.POSITIVE_INFINITY;
|
|
396
|
+
let bottom = Number.NEGATIVE_INFINITY;
|
|
397
|
+
for (const n of vfNodes.value) {
|
|
398
|
+
const height = flow.findNode(n.id)?.dimensions?.height ?? 76;
|
|
399
|
+
top = Math.min(top, n.position.y);
|
|
400
|
+
bottom = Math.max(bottom, n.position.y + height);
|
|
401
|
+
}
|
|
402
|
+
if (!Number.isFinite(top) || !Number.isFinite(bottom)) return;
|
|
403
|
+
const CLEARANCE = 8;
|
|
404
|
+
const overlap = wrap.top + vp.y + bottom * vp.zoom - bar.top + CLEARANCE;
|
|
405
|
+
if (overlap <= 0) return;
|
|
406
|
+
const roomAtTop = wrap.top + vp.y + top * vp.zoom - wrap.top - CLEARANCE;
|
|
407
|
+
const lift = Math.min(overlap, Math.max(roomAtTop, 0));
|
|
408
|
+
if (lift <= 0) return;
|
|
409
|
+
flow.setViewport({ ...vp, y: vp.y - lift });
|
|
410
|
+
}
|
|
411
|
+
flow.onPaneReady(async () => {
|
|
412
|
+
await nextTick();
|
|
413
|
+
void canvasWrapRef.value?.getBoundingClientRect();
|
|
414
|
+
await flow.fitView({ padding: { x: 0.2, top: 0.2, bottom: "96px" }, maxZoom: 1 });
|
|
415
|
+
liftAboveControlPane();
|
|
387
416
|
paneReady.value = true;
|
|
388
417
|
if (pendingReveal.value) {
|
|
389
418
|
centerOnNode(pendingReveal.value);
|
|
@@ -570,6 +599,18 @@ function updateSticky(id, patch) {
|
|
|
570
599
|
push();
|
|
571
600
|
}
|
|
572
601
|
const variablesOpen = ref(false);
|
|
602
|
+
const stateOpen = ref(false);
|
|
603
|
+
const stateCount = computed(() => (blob.value.state ?? []).length);
|
|
604
|
+
function updateStateNamespaces(next) {
|
|
605
|
+
blob.value.state = next.length ? next : void 0;
|
|
606
|
+
push();
|
|
607
|
+
}
|
|
608
|
+
function declareStateNamespace(namespace, role, visibility) {
|
|
609
|
+
const declared = blob.value.state ?? [];
|
|
610
|
+
if (declared.some((n) => n.namespace === namespace)) return;
|
|
611
|
+
blob.value.state = [...declared, { namespace, role, visibility }];
|
|
612
|
+
push();
|
|
613
|
+
}
|
|
573
614
|
const variableCount = computed(() => Object.keys(blob.value.variables ?? {}).length);
|
|
574
615
|
function updateVariables(next) {
|
|
575
616
|
blob.value.variables = Object.keys(next).length ? next : void 0;
|
|
@@ -824,7 +865,17 @@ function revealNode(id) {
|
|
|
824
865
|
selectedId.value = id;
|
|
825
866
|
}
|
|
826
867
|
}
|
|
827
|
-
|
|
868
|
+
function showNodeOnCanvas(id) {
|
|
869
|
+
const folded = collapsedGroupOf().get(id);
|
|
870
|
+
if (folded) patchGroup(folded.id, { collapsed: false });
|
|
871
|
+
if (blob.value.nodes.some((n) => n.id === id)) {
|
|
872
|
+
markBorn(id);
|
|
873
|
+
syncFromBlob();
|
|
874
|
+
}
|
|
875
|
+
if (paneReady.value) centerOnNode(id);
|
|
876
|
+
else pendingReveal.value = id;
|
|
877
|
+
}
|
|
878
|
+
defineExpose({ revealNode, showNodeOnCanvas, attachErrorStop });
|
|
828
879
|
const selectedUpstreamOutputs = computed(() => {
|
|
829
880
|
const id = selectedId.value;
|
|
830
881
|
if (!id) return [];
|
|
@@ -947,7 +998,7 @@ function addFromPayload(payload, pos) {
|
|
|
947
998
|
id,
|
|
948
999
|
nodeSlug: manifest.slug,
|
|
949
1000
|
nodeVersion: manifest.version,
|
|
950
|
-
config:
|
|
1001
|
+
config: defaultsFor(manifest.config ?? []),
|
|
951
1002
|
position: at
|
|
952
1003
|
});
|
|
953
1004
|
adoptIntoGroupAt(id, at);
|
|
@@ -992,7 +1043,7 @@ function onPaletteInsert(payload) {
|
|
|
992
1043
|
id,
|
|
993
1044
|
nodeSlug: manifest.slug,
|
|
994
1045
|
nodeVersion: manifest.version,
|
|
995
|
-
config:
|
|
1046
|
+
config: defaultsFor(manifest.config ?? []),
|
|
996
1047
|
position: { x: pc.pos.x, y: pc.pos.y }
|
|
997
1048
|
});
|
|
998
1049
|
blob.value.edges.push({
|
|
@@ -1044,7 +1095,7 @@ function spliceIntoEdge(edgeId, payload) {
|
|
|
1044
1095
|
id,
|
|
1045
1096
|
nodeSlug: manifest.slug,
|
|
1046
1097
|
nodeVersion: manifest.version,
|
|
1047
|
-
config:
|
|
1098
|
+
config: defaultsFor(manifest.config ?? []),
|
|
1048
1099
|
position: { x: snap((a.x + b.x) / 2), y: snap((a.y + b.y) / 2) }
|
|
1049
1100
|
});
|
|
1050
1101
|
blob.value.edges = blob.value.edges.filter((e) => e.id !== edgeId);
|
|
@@ -1057,12 +1108,44 @@ function spliceIntoEdge(edgeId, payload) {
|
|
|
1057
1108
|
syncFromBlob();
|
|
1058
1109
|
push();
|
|
1059
1110
|
}
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
return
|
|
1111
|
+
const STOP_AND_ERROR_SLUG = "revenexx:stop-and-error";
|
|
1112
|
+
function attachErrorStop(sourceNodeId, port) {
|
|
1113
|
+
const source = blob.value.nodes.find((n) => n.id === sourceNodeId);
|
|
1114
|
+
const version = newestExecutableVersion(STOP_AND_ERROR_SLUG);
|
|
1115
|
+
const manifest = version ? findManifest(STOP_AND_ERROR_SLUG, version) : null;
|
|
1116
|
+
if (!source || !manifest) return;
|
|
1117
|
+
const at = nodePosition(sourceNodeId);
|
|
1118
|
+
const id = `n-${Date.now()}`;
|
|
1119
|
+
blob.value.nodes.push({
|
|
1120
|
+
id,
|
|
1121
|
+
nodeSlug: manifest.slug,
|
|
1122
|
+
nodeVersion: manifest.version,
|
|
1123
|
+
config: {
|
|
1124
|
+
...defaultsFor(manifest.config ?? []),
|
|
1125
|
+
// The template convention verbatim: name the step that failed, then quote
|
|
1126
|
+
// its own message, so the run record says what went wrong rather than only
|
|
1127
|
+
// that something did. `errorCode` keeps the node's own default.
|
|
1128
|
+
message: t("integration.editor.errorPath.message", {
|
|
1129
|
+
label: nodeDisplayLabel(source),
|
|
1130
|
+
nodeId: source.id,
|
|
1131
|
+
port
|
|
1132
|
+
})
|
|
1133
|
+
},
|
|
1134
|
+
// Below the source and on the grid, the way the templates place theirs.
|
|
1135
|
+
// `freeSpotNear` keeps two of them off each other.
|
|
1136
|
+
position: freeSpotNear({ x: at.x, y: at.y + 180 })
|
|
1137
|
+
});
|
|
1138
|
+
blob.value.edges.push({
|
|
1139
|
+
id: `e-${Date.now().toString(36)}${Math.random().toString(36).slice(2, 6)}`,
|
|
1140
|
+
from: { nodeId: sourceNodeId, output: port },
|
|
1141
|
+
to: { nodeId: id, input: void 0 }
|
|
1142
|
+
});
|
|
1143
|
+
markBorn(id);
|
|
1144
|
+
syncFromBlob();
|
|
1145
|
+
if (paneReady.value) centerOnNode(id);
|
|
1146
|
+
else pendingReveal.value = id;
|
|
1147
|
+
push();
|
|
1148
|
+
toast.info(t("integration.editor.errorPath.toast.added", { label: nodeDisplayLabel(source) }));
|
|
1066
1149
|
}
|
|
1067
1150
|
function nodeDims(id) {
|
|
1068
1151
|
const d = flow.findNode(id)?.dimensions;
|
|
@@ -1231,9 +1314,9 @@ function setPointerMode(mode) {
|
|
|
1231
1314
|
}
|
|
1232
1315
|
}
|
|
1233
1316
|
const zoomPct = computed(() => `${Math.round((flow.viewport.value?.zoom ?? 1) * 100)}%`);
|
|
1234
|
-
const ZOOM_PRESETS = [50, 75, 100, 150, 200
|
|
1317
|
+
const ZOOM_PRESETS = [25, 50, 75, 100, 150, 200];
|
|
1235
1318
|
const MIN_ZOOM_PCT = 25;
|
|
1236
|
-
const MAX_ZOOM_PCT =
|
|
1319
|
+
const MAX_ZOOM_PCT = 200;
|
|
1237
1320
|
const zoomMenuOpen = ref(false);
|
|
1238
1321
|
const zoomInputText = ref("");
|
|
1239
1322
|
function setZoomPct(pct) {
|
|
@@ -1282,6 +1365,7 @@ async function focusPalette() {
|
|
|
1282
1365
|
paletteRef.value?.focusSearch();
|
|
1283
1366
|
}
|
|
1284
1367
|
const lightboxOpen = computed(() => !!selection.value);
|
|
1368
|
+
const shortcutsOpen = ref(false);
|
|
1285
1369
|
watch(lightboxOpen, (open) => {
|
|
1286
1370
|
if (!open) renameIntent.value = false;
|
|
1287
1371
|
});
|
|
@@ -1290,64 +1374,71 @@ function onConfigOpenAutoFocus(event) {
|
|
|
1290
1374
|
event.preventDefault();
|
|
1291
1375
|
event.target?.focus();
|
|
1292
1376
|
}
|
|
1293
|
-
const canvasHasKeyboard = computed(() => !lightboxOpen.value && !variablesOpen.value && !props.overlayOpen);
|
|
1377
|
+
const canvasHasKeyboard = computed(() => !lightboxOpen.value && !variablesOpen.value && !stateOpen.value && !shortcutsOpen.value && !props.overlayOpen);
|
|
1378
|
+
const DELETE_KEY_CODES = libraryKeyCodes("delete");
|
|
1294
1379
|
const singleSelected = computed(() => flow.getSelectedNodes.value.length === 1 ? flow.getSelectedNodes.value[0] : null);
|
|
1295
1380
|
useCanvasShortcuts(() => ({
|
|
1296
|
-
"
|
|
1381
|
+
[shortcutKeys("open")]: {
|
|
1297
1382
|
disabled: () => !singleSelected.value,
|
|
1298
1383
|
run: () => {
|
|
1299
1384
|
selectedId.value = singleSelected.value.id;
|
|
1300
1385
|
}
|
|
1301
1386
|
},
|
|
1302
|
-
"
|
|
1387
|
+
[shortcutKeys("rename")]: {
|
|
1303
1388
|
disabled: () => !singleSelected.value,
|
|
1304
1389
|
run: () => {
|
|
1305
1390
|
renameIntent.value = true;
|
|
1306
1391
|
selectedId.value = singleSelected.value.id;
|
|
1307
1392
|
}
|
|
1308
1393
|
},
|
|
1309
|
-
"
|
|
1310
|
-
"
|
|
1394
|
+
[shortcutKeys("selectAll")]: () => flow.addSelectedNodes(flow.getNodes.value),
|
|
1395
|
+
[shortcutKeys("copy")]: {
|
|
1311
1396
|
disabled: () => !flow.getSelectedNodes.value.length,
|
|
1312
1397
|
run: () => {
|
|
1313
1398
|
void copyNodes(flow.getSelectedNodes.value.map((n) => n.id));
|
|
1314
1399
|
}
|
|
1315
1400
|
},
|
|
1316
|
-
"
|
|
1401
|
+
[shortcutKeys("paste")]: () => {
|
|
1317
1402
|
void pasteNodes();
|
|
1318
1403
|
},
|
|
1319
|
-
"
|
|
1404
|
+
[shortcutKeys("duplicate")]: {
|
|
1320
1405
|
disabled: () => !flow.getSelectedNodes.value.length,
|
|
1321
1406
|
run: () => duplicateBlobNodes(flow.getSelectedNodes.value.map((n) => n.id))
|
|
1322
1407
|
},
|
|
1323
|
-
"
|
|
1408
|
+
[shortcutKeys("group")]: {
|
|
1324
1409
|
disabled: () => !flow.getSelectedNodes.value.length,
|
|
1325
1410
|
run: () => createGroupFromSelection(flow.getSelectedNodes.value.map((n) => n.id))
|
|
1326
1411
|
},
|
|
1327
|
-
"
|
|
1328
|
-
"
|
|
1412
|
+
[shortcutKeys("run")]: { disabled: () => !!props.runBusy, run: () => emit("run") },
|
|
1413
|
+
[shortcutKeys("tidyUp")]: () => {
|
|
1329
1414
|
void tidyUp();
|
|
1330
1415
|
},
|
|
1331
|
-
"
|
|
1332
|
-
"
|
|
1333
|
-
"
|
|
1334
|
-
"
|
|
1335
|
-
"
|
|
1416
|
+
[shortcutKeys("addSticky")]: () => addSticky(),
|
|
1417
|
+
[shortcutKeys("pointerSelect")]: () => setPointerMode("select"),
|
|
1418
|
+
[shortcutKeys("pointerHand")]: () => setPointerMode("hand"),
|
|
1419
|
+
[shortcutKeys("toggleActive")]: () => emit("toggleActive"),
|
|
1420
|
+
[shortcutKeys("variables")]: () => {
|
|
1336
1421
|
variablesOpen.value = true;
|
|
1337
1422
|
},
|
|
1338
|
-
"
|
|
1339
|
-
|
|
1423
|
+
[shortcutKeys("state")]: () => {
|
|
1424
|
+
stateOpen.value = true;
|
|
1425
|
+
},
|
|
1426
|
+
[shortcutKeys("settings")]: () => emit("openSettings"),
|
|
1427
|
+
[shortcutKeys("zoomOut")]: () => {
|
|
1340
1428
|
void flow.zoomOut({ duration: 150 });
|
|
1341
1429
|
},
|
|
1342
|
-
"
|
|
1430
|
+
[shortcutKeys("zoomIn")]: () => {
|
|
1343
1431
|
void flow.zoomIn({ duration: 150 });
|
|
1344
1432
|
},
|
|
1345
|
-
"
|
|
1346
|
-
"
|
|
1347
|
-
"
|
|
1433
|
+
[shortcutKeys("zoomReset")]: () => setZoomPct(100),
|
|
1434
|
+
[shortcutKeys("fitView")]: () => flow.fitView({ padding: 0.2, duration: 400, maxZoom: 1 }),
|
|
1435
|
+
[shortcutKeys("addNode")]: () => {
|
|
1348
1436
|
void focusPalette();
|
|
1349
1437
|
},
|
|
1350
|
-
"
|
|
1438
|
+
[shortcutKeys("overview")]: () => {
|
|
1439
|
+
shortcutsOpen.value = true;
|
|
1440
|
+
},
|
|
1441
|
+
[shortcutKeys("clearSelection")]: () => {
|
|
1351
1442
|
pendingSpliceEdgeId.value = null;
|
|
1352
1443
|
pendingConnect.value = null;
|
|
1353
1444
|
flow.removeSelectedElements();
|
|
@@ -1382,6 +1473,19 @@ const edgeTypes = {
|
|
|
1382
1473
|
:run-busy="runBusy"
|
|
1383
1474
|
@action="onMenuAction"
|
|
1384
1475
|
>
|
|
1476
|
+
<!-- `pan-activation-key-code` is null rather than left at its default, which
|
|
1477
|
+
is Space. The canvas library binds that key on the document and calls
|
|
1478
|
+
preventDefault on it, and `useCanvasShortcuts` steps aside for a key
|
|
1479
|
+
somebody upstream has already claimed — so Space renaming a node, which
|
|
1480
|
+
the shortcuts overview offers, answered nothing at all (PO-472).
|
|
1481
|
+
Nothing is given up by switching it off, and the reason is not that the
|
|
1482
|
+
drag pans anyway: in select mode `pan-on-drag` below lists the middle
|
|
1483
|
+
button only, and the library's own filter refuses a left-drag for a pan
|
|
1484
|
+
on that ground before the activation key is consulted at all. Measured:
|
|
1485
|
+
with the key claimed, Space held over a left-drag did nothing — no pan,
|
|
1486
|
+
and no rubber band either, because holding it also switched selecting
|
|
1487
|
+
off; with it freed, that drag draws the rubber band. What does change is
|
|
1488
|
+
Space over the wheel, which zooms the way the wheel alone does. -->
|
|
1385
1489
|
<VueFlow
|
|
1386
1490
|
v-model:nodes="vfNodes"
|
|
1387
1491
|
v-model:edges="vfEdges"
|
|
@@ -1398,10 +1502,11 @@ const edgeTypes = {
|
|
|
1398
1502
|
:selection-key-code="pointerMode === 'select' ? true : 'Shift'"
|
|
1399
1503
|
:pan-on-drag="pointerMode === 'hand' ? true : [1]"
|
|
1400
1504
|
:zoom-on-double-click="false"
|
|
1401
|
-
:delete-key-code="canvasHasKeyboard ?
|
|
1505
|
+
:delete-key-code="canvasHasKeyboard ? DELETE_KEY_CODES : null"
|
|
1506
|
+
:pan-activation-key-code="null"
|
|
1402
1507
|
:edges-updatable="true"
|
|
1403
1508
|
:min-zoom="0.25"
|
|
1404
|
-
:max-zoom="
|
|
1509
|
+
:max-zoom="2"
|
|
1405
1510
|
>
|
|
1406
1511
|
<Background pattern-color="#cbd5e1" :gap="20" :size="1.2" />
|
|
1407
1512
|
</VueFlow>
|
|
@@ -1641,10 +1746,11 @@ const edgeTypes = {
|
|
|
1641
1746
|
<TooltipProvider :delay-duration="250">
|
|
1642
1747
|
<div class="rounded-lg border border-gray-400/10 outline-1 outline-white/30 backdrop-blur-sm">
|
|
1643
1748
|
<div class="flex items-center gap-0.5 whitespace-nowrap border border-white bg-white rounded-lg bg-gradient-to-br from-white via-violet-50/40 to-white px-2 py-1">
|
|
1644
|
-
<!-- Smart Run: the page decides what "run" means —
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1749
|
+
<!-- Smart Run: the page decides what "run" means — a workflow that
|
|
1750
|
+
consumes trigger.payload, or leaves the mode to the caller, opens
|
|
1751
|
+
the run dialog; one that asks neither fires immediately. One
|
|
1752
|
+
button either way. -->
|
|
1753
|
+
<IntegrationsEditorTip :label="runWaiting ? t('integration.editor.tool.run.tooltipWaiting') : t('integration.editor.tool.run.tooltip')" :shortcut="primaryShortcut('run')">
|
|
1648
1754
|
<button
|
|
1649
1755
|
type="button"
|
|
1650
1756
|
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"
|
|
@@ -1662,7 +1768,7 @@ const edgeTypes = {
|
|
|
1662
1768
|
<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)]">
|
|
1663
1769
|
<!-- Icon-only, and the tooltip is not an accessible name: each one
|
|
1664
1770
|
says what it does itself, and whether it is the active mode. -->
|
|
1665
|
-
<IntegrationsEditorTip :label="t('integration.editor.tool.select')" shortcut="
|
|
1771
|
+
<IntegrationsEditorTip :label="t('integration.editor.tool.select')" :shortcut="primaryShortcut('pointerSelect')">
|
|
1666
1772
|
<button
|
|
1667
1773
|
type="button"
|
|
1668
1774
|
:aria-label="t('integration.editor.tool.select')"
|
|
@@ -1674,7 +1780,7 @@ const edgeTypes = {
|
|
|
1674
1780
|
<MousePointer2 :size="14" />
|
|
1675
1781
|
</button>
|
|
1676
1782
|
</IntegrationsEditorTip>
|
|
1677
|
-
<IntegrationsEditorTip :label="t('integration.editor.tool.hand')" shortcut="
|
|
1783
|
+
<IntegrationsEditorTip :label="t('integration.editor.tool.hand')" :shortcut="primaryShortcut('pointerHand')">
|
|
1678
1784
|
<button
|
|
1679
1785
|
type="button"
|
|
1680
1786
|
:aria-label="t('integration.editor.tool.hand')"
|
|
@@ -1688,7 +1794,7 @@ const edgeTypes = {
|
|
|
1688
1794
|
</IntegrationsEditorTip>
|
|
1689
1795
|
</div>
|
|
1690
1796
|
|
|
1691
|
-
<IntegrationsEditorTip :label="t('integration.editor.tool.tidyUp')" shortcut="
|
|
1797
|
+
<IntegrationsEditorTip :label="t('integration.editor.tool.tidyUp')" :shortcut="primaryShortcut('tidyUp')">
|
|
1692
1798
|
<button
|
|
1693
1799
|
type="button"
|
|
1694
1800
|
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]"
|
|
@@ -1698,7 +1804,7 @@ const edgeTypes = {
|
|
|
1698
1804
|
{{ t("integration.editor.tool.tidyUp") }}
|
|
1699
1805
|
</button>
|
|
1700
1806
|
</IntegrationsEditorTip>
|
|
1701
|
-
<IntegrationsEditorTip :label="t('integration.editor.tool.fitView.tooltip')" shortcut="
|
|
1807
|
+
<IntegrationsEditorTip :label="t('integration.editor.tool.fitView.tooltip')" :shortcut="primaryShortcut('fitView')">
|
|
1702
1808
|
<button
|
|
1703
1809
|
type="button"
|
|
1704
1810
|
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]"
|
|
@@ -1708,7 +1814,7 @@ const edgeTypes = {
|
|
|
1708
1814
|
{{ t("integration.editor.tool.fitView.label") }}
|
|
1709
1815
|
</button>
|
|
1710
1816
|
</IntegrationsEditorTip>
|
|
1711
|
-
<IntegrationsEditorTip :label="t('integration.editor.tool.addSticky.tooltip')" shortcut="
|
|
1817
|
+
<IntegrationsEditorTip :label="t('integration.editor.tool.addSticky.tooltip')" :shortcut="primaryShortcut('addSticky')">
|
|
1712
1818
|
<button
|
|
1713
1819
|
type="button"
|
|
1714
1820
|
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]"
|
|
@@ -1728,7 +1834,7 @@ const edgeTypes = {
|
|
|
1728
1834
|
{{ t("integration.editor.tool.addGroup.label") }}
|
|
1729
1835
|
</button>
|
|
1730
1836
|
</IntegrationsEditorTip>
|
|
1731
|
-
<IntegrationsEditorTip :label="t('integration.editor.tool.variables.tooltip')" shortcut="
|
|
1837
|
+
<IntegrationsEditorTip :label="t('integration.editor.tool.variables.tooltip')" :shortcut="primaryShortcut('variables')">
|
|
1732
1838
|
<button
|
|
1733
1839
|
type="button"
|
|
1734
1840
|
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]"
|
|
@@ -1739,7 +1845,18 @@ const edgeTypes = {
|
|
|
1739
1845
|
<span v-if="variableCount" class="rounded-lg bg-muted px-1.5 text-xs tabular-nums text-muted-foreground">{{ variableCount }}</span>
|
|
1740
1846
|
</button>
|
|
1741
1847
|
</IntegrationsEditorTip>
|
|
1742
|
-
<IntegrationsEditorTip :label="t('integration.editor.tool.
|
|
1848
|
+
<IntegrationsEditorTip :label="t('integration.editor.tool.state.tooltip')" :shortcut="primaryShortcut('state')">
|
|
1849
|
+
<button
|
|
1850
|
+
type="button"
|
|
1851
|
+
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]"
|
|
1852
|
+
@click="stateOpen = true"
|
|
1853
|
+
>
|
|
1854
|
+
<Database :size="13" />
|
|
1855
|
+
{{ t("integration.editor.tool.state.label") }}
|
|
1856
|
+
<span v-if="stateCount" class="rounded-lg bg-muted px-1.5 text-xs tabular-nums text-muted-foreground">{{ stateCount }}</span>
|
|
1857
|
+
</button>
|
|
1858
|
+
</IntegrationsEditorTip>
|
|
1859
|
+
<IntegrationsEditorTip :label="t('integration.editor.tool.settings.tooltip')" :shortcut="primaryShortcut('settings')">
|
|
1743
1860
|
<button
|
|
1744
1861
|
type="button"
|
|
1745
1862
|
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]"
|
|
@@ -1749,10 +1866,25 @@ const edgeTypes = {
|
|
|
1749
1866
|
{{ t("integration.editor.tool.settings.label") }}
|
|
1750
1867
|
</button>
|
|
1751
1868
|
</IntegrationsEditorTip>
|
|
1869
|
+
<!-- The overview, and the one control that has to be reachable without
|
|
1870
|
+
already knowing a key: it is where the other keys are learnt. Its
|
|
1871
|
+
tooltip carries `?` for the same reason — the pane teaches the key
|
|
1872
|
+
that teaches the rest. Icon-only, so it carries a name of its own
|
|
1873
|
+
(`specs/accessibility.md` AC-2). -->
|
|
1874
|
+
<IntegrationsEditorTip :label="t('integration.canvas.shortcuts.dialog.title')" :shortcut="primaryShortcut('overview')">
|
|
1875
|
+
<button
|
|
1876
|
+
type="button"
|
|
1877
|
+
:aria-label="t('integration.canvas.shortcuts.dialog.title')"
|
|
1878
|
+
class="flex size-8 items-center justify-center rounded-lg text-foreground transition hover:bg-black/[0.04]"
|
|
1879
|
+
@click="shortcutsOpen = true"
|
|
1880
|
+
>
|
|
1881
|
+
<Keyboard :size="14" />
|
|
1882
|
+
</button>
|
|
1883
|
+
</IntegrationsEditorTip>
|
|
1752
1884
|
|
|
1753
1885
|
<div class="mx-1 h-5 w-px bg-black/10" />
|
|
1754
1886
|
|
|
1755
|
-
<IntegrationsEditorTip :label="t('integration.editor.tool.zoomOut')" shortcut="
|
|
1887
|
+
<IntegrationsEditorTip :label="t('integration.editor.tool.zoomOut')" :shortcut="primaryShortcut('zoomOut')">
|
|
1756
1888
|
<button
|
|
1757
1889
|
type="button"
|
|
1758
1890
|
:aria-label="t('integration.editor.tool.zoomOut')"
|
|
@@ -1765,7 +1897,7 @@ const edgeTypes = {
|
|
|
1765
1897
|
<!-- Tooltip sits on a wrapper span so its as-child merge never
|
|
1766
1898
|
touches the dropdown trigger (merging both onto one button
|
|
1767
1899
|
swallowed the trigger's pointerdown and the menu never opened). -->
|
|
1768
|
-
<IntegrationsEditorTip :label="t('integration.editor.tool.zoomLevel.tooltip')" shortcut="
|
|
1900
|
+
<IntegrationsEditorTip :label="t('integration.editor.tool.zoomLevel.tooltip')" :shortcut="primaryShortcut('zoomReset')">
|
|
1769
1901
|
<span class="inline-flex">
|
|
1770
1902
|
<DropdownMenu v-model:open="zoomMenuOpen">
|
|
1771
1903
|
<DropdownMenuTrigger as-child>
|
|
@@ -1807,7 +1939,7 @@ const edgeTypes = {
|
|
|
1807
1939
|
</DropdownMenu>
|
|
1808
1940
|
</span>
|
|
1809
1941
|
</IntegrationsEditorTip>
|
|
1810
|
-
<IntegrationsEditorTip :label="t('integration.editor.tool.zoomIn')" shortcut="
|
|
1942
|
+
<IntegrationsEditorTip :label="t('integration.editor.tool.zoomIn')" :shortcut="primaryShortcut('zoomIn')">
|
|
1811
1943
|
<button
|
|
1812
1944
|
type="button"
|
|
1813
1945
|
:aria-label="t('integration.editor.tool.zoomIn')"
|
|
@@ -1838,6 +1970,14 @@ const edgeTypes = {
|
|
|
1838
1970
|
</div>
|
|
1839
1971
|
</div>
|
|
1840
1972
|
|
|
1973
|
+
<!-- State namespaces lightbox (control-pane entry) — what this workflow may
|
|
1974
|
+
remember between runs. -->
|
|
1975
|
+
<WorkflowStateNamespacesDialog
|
|
1976
|
+
v-model:open="stateOpen"
|
|
1977
|
+
:state="blob.state ?? []"
|
|
1978
|
+
@update:state="updateStateNamespaces"
|
|
1979
|
+
/>
|
|
1980
|
+
|
|
1841
1981
|
<!-- Workflow variables lightbox (control-pane entry). -->
|
|
1842
1982
|
<WorkflowVariablesDialog
|
|
1843
1983
|
v-model:open="variablesOpen"
|
|
@@ -1845,6 +1985,10 @@ const edgeTypes = {
|
|
|
1845
1985
|
@update:variables="updateVariables"
|
|
1846
1986
|
/>
|
|
1847
1987
|
|
|
1988
|
+
<!-- Every key this canvas answers, opened with `?`. Rendered here rather
|
|
1989
|
+
than at the page: the keys are the canvas's, and so is the list. -->
|
|
1990
|
+
<CanvasShortcutsDialog v-model:open="shortcutsOpen" />
|
|
1991
|
+
|
|
1848
1992
|
<!-- Node/trigger configuration — a near-fullscreen workbench lightbox
|
|
1849
1993
|
(Input pane / Parameters+Settings tabs / Save+Cancel footer). The
|
|
1850
1994
|
inspector edits a draft; closing without Save discards it. -->
|
|
@@ -1876,6 +2020,7 @@ const edgeTypes = {
|
|
|
1876
2020
|
:selection="selection"
|
|
1877
2021
|
:secret-keys="secretKeys"
|
|
1878
2022
|
:variables="blob.variables"
|
|
2023
|
+
:state-namespaces="blob.state ?? []"
|
|
1879
2024
|
:upstream-outputs="selectedUpstreamOutputs"
|
|
1880
2025
|
:autofocus-name="renameIntent"
|
|
1881
2026
|
:nodes="blob.nodes"
|
|
@@ -1891,6 +2036,7 @@ const edgeTypes = {
|
|
|
1891
2036
|
selectedId = id;
|
|
1892
2037
|
renameIntent = false;
|
|
1893
2038
|
}"
|
|
2039
|
+
@declare-state="declareStateNamespace"
|
|
1894
2040
|
/>
|
|
1895
2041
|
</DialogContent>
|
|
1896
2042
|
</Dialog>
|
|
@@ -42,17 +42,51 @@ type __VLS_Props = {
|
|
|
42
42
|
* id that is on the canvas is in the blob by construction.
|
|
43
43
|
*/
|
|
44
44
|
declare function revealNode(id: string): void;
|
|
45
|
+
/**
|
|
46
|
+
* Point at a node without opening it — for a reader who has to look at the
|
|
47
|
+
* card's *surroundings* rather than at its settings.
|
|
48
|
+
*
|
|
49
|
+
* The deliberate difference from {@link revealNode} is the missing selection,
|
|
50
|
+
* and with it the missing settings lightbox. That is the whole reason there are
|
|
51
|
+
* two functions: the validation banner sends someone to a field at fault, and
|
|
52
|
+
* the dialog is where that field is. The error-path advice sends them to a port
|
|
53
|
+
* with nothing on it, and the question they have to answer — where should this
|
|
54
|
+
* failure go? — is answered by the graph around the card, which a dialog over
|
|
55
|
+
* the canvas covers up.
|
|
56
|
+
*
|
|
57
|
+
* Marked with the same pulse a newly created card gets, because the job is the
|
|
58
|
+
* same one: say which of thirty cards is the one meant.
|
|
59
|
+
*/
|
|
60
|
+
declare function showNodeOnCanvas(id: string): void;
|
|
61
|
+
/**
|
|
62
|
+
* Hang a Stop-and-Error step off a node's error output and wire it up
|
|
63
|
+
* (specs/workflow-advice.md AC-3).
|
|
64
|
+
*
|
|
65
|
+
* The advice strip can tell an author their error output leads nowhere; on its
|
|
66
|
+
* own that is a reprimand without a remedy, because the repair — drop a node,
|
|
67
|
+
* pick the right one, connect it, write an expression quoting the failing step's
|
|
68
|
+
* message — is four steps of tedium they have to already know. Every template we
|
|
69
|
+
* ship does exactly this, twenty-five times over, so the shape is settled and
|
|
70
|
+
* worth one click.
|
|
71
|
+
*
|
|
72
|
+
* Leaves the result unsaved and unopened, like every other insertion here: the
|
|
73
|
+
* new step is highlighted and the author decides whether to keep it. Deleting it
|
|
74
|
+
* is the undo, because this editor has no undo stack to hook into.
|
|
75
|
+
*/
|
|
76
|
+
declare function attachErrorStop(sourceNodeId: string, port: string): void;
|
|
45
77
|
declare const _default: import("vue").DefineComponent<__VLS_Props, {
|
|
46
78
|
revealNode: typeof revealNode;
|
|
79
|
+
showNodeOnCanvas: typeof showNodeOnCanvas;
|
|
80
|
+
attachErrorStop: typeof attachErrorStop;
|
|
47
81
|
}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
48
|
-
change: (blob: WorkflowBlob) => any;
|
|
49
82
|
run: () => any;
|
|
50
83
|
toggleActive: () => any;
|
|
84
|
+
change: (blob: WorkflowBlob) => any;
|
|
51
85
|
openSettings: () => any;
|
|
52
86
|
}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
53
|
-
onChange?: ((blob: WorkflowBlob) => any) | undefined;
|
|
54
87
|
onRun?: (() => any) | undefined;
|
|
55
88
|
onToggleActive?: (() => any) | undefined;
|
|
89
|
+
onChange?: ((blob: WorkflowBlob) => any) | undefined;
|
|
56
90
|
onOpenSettings?: (() => any) | undefined;
|
|
57
91
|
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
58
92
|
export default _default;
|
|
@@ -3,9 +3,13 @@ import '@vue-flow/core/dist/theme-default.css';
|
|
|
3
3
|
import type { Workflow } from '../../types/integrations.js';
|
|
4
4
|
type __VLS_Props = {
|
|
5
5
|
workflow: Workflow;
|
|
6
|
-
/**
|
|
6
|
+
/** The run to replay (deep-link from the Runs table). */
|
|
7
7
|
initialRunId?: string | null;
|
|
8
|
-
/**
|
|
8
|
+
/**
|
|
9
|
+
* @deprecated Accepted and ignored since PO-350 — the panel has no other mode
|
|
10
|
+
* to switch out of. Kept so a host passing it keeps working; drop it at the
|
|
11
|
+
* next major.
|
|
12
|
+
*/
|
|
9
13
|
single?: boolean;
|
|
10
14
|
};
|
|
11
15
|
declare const _default: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|