@revenexx/studio-integrations 0.1.4 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/module.json +1 -1
- package/dist/runtime/components/Integrations/CredentialCreateDialog.d.vue.ts +13 -0
- package/dist/runtime/components/Integrations/CredentialCreateDialog.vue +279 -0
- package/dist/runtime/components/Integrations/CredentialCreateDialog.vue.d.ts +13 -0
- package/dist/runtime/components/Integrations/CredentialDetailDialog.d.vue.ts +20 -0
- package/dist/runtime/components/Integrations/CredentialDetailDialog.vue +342 -0
- package/dist/runtime/components/Integrations/CredentialDetailDialog.vue.d.ts +20 -0
- package/dist/runtime/components/Integrations/CredentialLogo.d.vue.ts +14 -0
- package/dist/runtime/components/Integrations/CredentialLogo.vue +37 -0
- package/dist/runtime/components/Integrations/CredentialLogo.vue.d.ts +14 -0
- package/dist/runtime/components/Integrations/CredentialRevenexxSource.d.vue.ts +12 -0
- package/dist/runtime/components/Integrations/CredentialRevenexxSource.vue +364 -0
- package/dist/runtime/components/Integrations/CredentialRevenexxSource.vue.d.ts +12 -0
- package/dist/runtime/components/Integrations/CredentialTypePicker.d.vue.ts +15 -0
- package/dist/runtime/components/Integrations/CredentialTypePicker.vue +71 -0
- package/dist/runtime/components/Integrations/CredentialTypePicker.vue.d.ts +15 -0
- package/dist/runtime/components/Integrations/DeadLettersPanel.d.vue.ts +5 -0
- package/dist/runtime/components/Integrations/DeadLettersPanel.vue +151 -0
- package/dist/runtime/components/Integrations/DeadLettersPanel.vue.d.ts +5 -0
- package/dist/runtime/components/Integrations/EditorTip.d.vue.ts +17 -0
- package/dist/runtime/components/Integrations/EditorTip.vue +46 -0
- package/dist/runtime/components/Integrations/EditorTip.vue.d.ts +17 -0
- package/dist/runtime/components/Integrations/EventTypeCombobox.d.vue.ts +9 -0
- package/dist/runtime/components/Integrations/EventTypeCombobox.vue +64 -0
- package/dist/runtime/components/Integrations/EventTypeCombobox.vue.d.ts +9 -0
- package/dist/runtime/components/Integrations/ExpressionInput.d.vue.ts +19 -0
- package/dist/runtime/components/Integrations/ExpressionInput.vue +236 -0
- package/dist/runtime/components/Integrations/ExpressionInput.vue.d.ts +19 -0
- package/dist/runtime/components/Integrations/GroupFrameView.d.vue.ts +28 -0
- package/dist/runtime/components/Integrations/GroupFrameView.vue +222 -0
- package/dist/runtime/components/Integrations/GroupFrameView.vue.d.ts +28 -0
- package/dist/runtime/components/Integrations/NodeConfigDynamicField.d.vue.ts +14 -0
- package/dist/runtime/components/Integrations/NodeConfigDynamicField.vue +184 -0
- package/dist/runtime/components/Integrations/NodeConfigDynamicField.vue.d.ts +14 -0
- package/dist/runtime/components/Integrations/NodeConfigDynamicSchema.d.vue.ts +16 -0
- package/dist/runtime/components/Integrations/NodeConfigDynamicSchema.vue +102 -0
- package/dist/runtime/components/Integrations/NodeConfigDynamicSchema.vue.d.ts +16 -0
- package/dist/runtime/components/Integrations/NodeConfigField.d.vue.ts +23 -0
- package/dist/runtime/components/Integrations/NodeConfigField.vue +587 -0
- package/dist/runtime/components/Integrations/NodeConfigField.vue.d.ts +23 -0
- package/dist/runtime/components/Integrations/NodeDynamicOutputsResolver.d.vue.ts +14 -0
- package/dist/runtime/components/Integrations/NodeDynamicOutputsResolver.vue +80 -0
- package/dist/runtime/components/Integrations/NodeDynamicOutputsResolver.vue.d.ts +14 -0
- package/dist/runtime/components/Integrations/NodeInspector.d.vue.ts +22 -3
- package/dist/runtime/components/Integrations/NodeInspector.vue +1074 -294
- package/dist/runtime/components/Integrations/NodeInspector.vue.d.ts +22 -3
- package/dist/runtime/components/Integrations/NodeLogo.d.vue.ts +9 -0
- package/dist/runtime/components/Integrations/NodeLogo.vue +38 -0
- package/dist/runtime/components/Integrations/NodeLogo.vue.d.ts +9 -0
- package/dist/runtime/components/Integrations/NodePalette.d.vue.ts +22 -1
- package/dist/runtime/components/Integrations/NodePalette.vue +411 -90
- package/dist/runtime/components/Integrations/NodePalette.vue.d.ts +22 -1
- package/dist/runtime/components/Integrations/QueryBuilder.d.vue.ts +9 -0
- package/dist/runtime/components/Integrations/QueryBuilder.vue +239 -0
- package/dist/runtime/components/Integrations/QueryBuilder.vue.d.ts +9 -0
- package/dist/runtime/components/Integrations/{RunDetailDialog.d.vue.ts → RunActionsMenu.d.vue.ts} +3 -4
- package/dist/runtime/components/Integrations/RunActionsMenu.vue +86 -0
- package/dist/runtime/components/Integrations/{RunDetailDialog.vue.d.ts → RunActionsMenu.vue.d.ts} +3 -4
- package/dist/runtime/components/Integrations/RunDetailPanel.d.vue.ts +14 -0
- package/dist/runtime/components/Integrations/RunDetailPanel.vue +777 -0
- package/dist/runtime/components/Integrations/RunDetailPanel.vue.d.ts +14 -0
- package/dist/runtime/components/Integrations/RunPayloadInput.d.vue.ts +13 -0
- package/dist/runtime/components/Integrations/RunPayloadInput.vue +175 -0
- package/dist/runtime/components/Integrations/RunPayloadInput.vue.d.ts +13 -0
- package/dist/runtime/components/Integrations/RunResponseModal.d.vue.ts +27 -0
- package/dist/runtime/components/Integrations/RunResponseModal.vue +84 -0
- package/dist/runtime/components/Integrations/RunResponseModal.vue.d.ts +27 -0
- package/dist/runtime/components/Integrations/RunsTable.d.vue.ts +21 -0
- package/dist/runtime/components/Integrations/RunsTable.vue +114 -0
- package/dist/runtime/components/Integrations/RunsTable.vue.d.ts +21 -0
- package/dist/runtime/components/Integrations/SftpAccountImportDialog.d.vue.ts +11 -0
- package/dist/runtime/components/Integrations/SftpAccountImportDialog.vue +91 -0
- package/dist/runtime/components/Integrations/SftpAccountImportDialog.vue.d.ts +11 -0
- package/dist/runtime/components/Integrations/StickyNoteView.d.vue.ts +28 -0
- package/dist/runtime/components/Integrations/StickyNoteView.vue +208 -0
- package/dist/runtime/components/Integrations/StickyNoteView.vue.d.ts +28 -0
- package/dist/runtime/components/Integrations/TemplateFlowPreview.d.vue.ts +29 -0
- package/dist/runtime/components/Integrations/TemplateFlowPreview.vue +201 -0
- package/dist/runtime/components/Integrations/TemplateFlowPreview.vue.d.ts +29 -0
- package/dist/runtime/components/Integrations/WorkflowContextMenu.d.vue.ts +32 -0
- package/dist/runtime/components/Integrations/WorkflowContextMenu.vue +138 -0
- package/dist/runtime/components/Integrations/WorkflowContextMenu.vue.d.ts +32 -0
- package/dist/runtime/components/Integrations/WorkflowCreateDialog.d.vue.ts +9 -0
- package/dist/runtime/components/Integrations/WorkflowCreateDialog.vue +322 -0
- package/dist/runtime/components/Integrations/WorkflowCreateDialog.vue.d.ts +9 -0
- package/dist/runtime/components/Integrations/WorkflowDuplicateDialog.d.vue.ts +18 -0
- package/dist/runtime/components/Integrations/WorkflowDuplicateDialog.vue +63 -0
- package/dist/runtime/components/Integrations/WorkflowDuplicateDialog.vue.d.ts +18 -0
- package/dist/runtime/components/Integrations/WorkflowEdgeView.d.vue.ts +12 -1
- package/dist/runtime/components/Integrations/WorkflowEdgeView.vue +68 -6
- package/dist/runtime/components/Integrations/WorkflowEdgeView.vue.d.ts +12 -1
- package/dist/runtime/components/Integrations/WorkflowEditor.d.vue.ts +8 -1
- package/dist/runtime/components/Integrations/WorkflowEditor.vue +1424 -144
- package/dist/runtime/components/Integrations/WorkflowEditor.vue.d.ts +8 -1
- package/dist/runtime/components/Integrations/WorkflowHistoryPanel.d.vue.ts +12 -0
- package/dist/runtime/components/Integrations/WorkflowHistoryPanel.vue +417 -0
- package/dist/runtime/components/Integrations/WorkflowHistoryPanel.vue.d.ts +12 -0
- package/dist/runtime/components/Integrations/WorkflowIconPicker.d.vue.ts +10 -0
- package/dist/runtime/components/Integrations/WorkflowIconPicker.vue +89 -0
- package/dist/runtime/components/Integrations/WorkflowIconPicker.vue.d.ts +10 -0
- package/dist/runtime/components/Integrations/WorkflowIconView.d.vue.ts +10 -0
- package/dist/runtime/components/Integrations/WorkflowIconView.vue +35 -0
- package/dist/runtime/components/Integrations/WorkflowIconView.vue.d.ts +10 -0
- package/dist/runtime/components/Integrations/WorkflowNodeView.d.vue.ts +5 -1
- package/dist/runtime/components/Integrations/WorkflowNodeView.vue +114 -84
- package/dist/runtime/components/Integrations/WorkflowNodeView.vue.d.ts +5 -1
- package/dist/runtime/components/Integrations/WorkflowRunReplayPanel.d.vue.ts +12 -0
- package/dist/runtime/components/Integrations/WorkflowRunReplayPanel.vue +654 -0
- package/dist/runtime/components/Integrations/WorkflowRunReplayPanel.vue.d.ts +12 -0
- package/dist/runtime/components/Integrations/WorkflowSettingsDialog.d.vue.ts +36 -0
- package/dist/runtime/components/Integrations/WorkflowSettingsDialog.vue +136 -0
- package/dist/runtime/components/Integrations/WorkflowSettingsDialog.vue.d.ts +36 -0
- package/dist/runtime/components/Integrations/WorkflowTagsInput.d.vue.ts +14 -0
- package/dist/runtime/components/Integrations/WorkflowTagsInput.vue +63 -0
- package/dist/runtime/components/Integrations/WorkflowTagsInput.vue.d.ts +14 -0
- package/dist/runtime/components/Integrations/WorkflowTriggerView.vue +35 -15
- package/dist/runtime/components/Integrations/WorkflowVariablesDialog.d.vue.ts +13 -0
- package/dist/runtime/components/Integrations/WorkflowVariablesDialog.vue +265 -0
- package/dist/runtime/components/Integrations/WorkflowVariablesDialog.vue.d.ts +13 -0
- package/dist/runtime/components/Integrations/WorkflowsTable.d.vue.ts +4 -1
- package/dist/runtime/components/Integrations/WorkflowsTable.vue +122 -39
- package/dist/runtime/components/Integrations/WorkflowsTable.vue.d.ts +4 -1
- package/dist/runtime/components/Integrations/workflowLayout.d.ts +5 -0
- package/dist/runtime/components/Integrations/workflowLayout.js +5 -3
- package/dist/runtime/composables/integrationsApi.d.ts +6 -2
- package/dist/runtime/composables/integrationsApi.js +5 -4
- package/dist/runtime/composables/useCanvasShortcuts.d.ts +37 -0
- package/dist/runtime/composables/useCanvasShortcuts.js +62 -0
- package/dist/runtime/composables/useIntegrationsDeadLetters.d.ts +22 -0
- package/dist/runtime/composables/useIntegrationsDeadLetters.js +50 -0
- package/dist/runtime/composables/useIntegrationsNodes.d.ts +4 -0
- package/dist/runtime/composables/useIntegrationsNodes.js +6 -3
- package/dist/runtime/composables/useIntegrationsRevisions.d.ts +40 -0
- package/dist/runtime/composables/useIntegrationsRevisions.js +51 -0
- package/dist/runtime/composables/useIntegrationsRuns.d.ts +21 -1
- package/dist/runtime/composables/useIntegrationsRuns.js +92 -4
- package/dist/runtime/composables/useIntegrationsTemplates.d.ts +1 -0
- package/dist/runtime/composables/useIntegrationsTemplates.js +32 -4
- package/dist/runtime/composables/useIntegrationsWorkflows.d.ts +1 -0
- package/dist/runtime/composables/useIntegrationsWorkflows.js +57 -1
- package/dist/runtime/composables/useMiniMapLayout.d.ts +34 -0
- package/dist/runtime/composables/useMiniMapLayout.js +119 -0
- package/dist/runtime/composables/useNodeConfigResolve.d.ts +43 -0
- package/dist/runtime/composables/useNodeConfigResolve.js +123 -0
- package/dist/runtime/composables/useNodeDrag.d.ts +22 -0
- package/dist/runtime/composables/useNodeDrag.js +10 -0
- package/dist/runtime/composables/usePaletteLayout.d.ts +41 -0
- package/dist/runtime/composables/usePaletteLayout.js +113 -0
- package/dist/runtime/data/expressionEditor.d.ts +22 -0
- package/dist/runtime/data/expressionEditor.js +40 -0
- package/dist/runtime/data/integrationNodeCatalog.js +8 -8
- package/dist/runtime/data/nodeInputData.d.ts +37 -0
- package/dist/runtime/data/nodeInputData.js +62 -0
- package/dist/runtime/data/nodeRunData.d.ts +56 -0
- package/dist/runtime/data/nodeRunData.js +91 -0
- package/dist/runtime/data/payloadForm.d.ts +44 -0
- package/dist/runtime/data/payloadForm.js +126 -0
- package/dist/runtime/data/workflowIconCatalog.d.ts +34 -0
- package/dist/runtime/data/workflowIconCatalog.js +116 -0
- package/dist/runtime/pages/integrations/audit.vue +25 -35
- package/dist/runtime/pages/integrations/credentials.vue +117 -122
- package/dist/runtime/pages/integrations/index.vue +133 -36
- package/dist/runtime/pages/integrations/runs.vue +125 -75
- package/dist/runtime/pages/integrations/schedules.vue +5 -16
- package/dist/runtime/pages/integrations/secrets.vue +1 -3
- package/dist/runtime/pages/integrations/workflows/[id].vue +599 -194
- package/dist/runtime/pages/integrations/workflows/index.vue +10 -8
- package/dist/runtime/types/integrations.d.ts +190 -4
- package/dist/runtime/utils/credentialState.d.ts +28 -0
- package/dist/runtime/utils/credentialState.js +29 -0
- package/dist/runtime/utils/localize.d.ts +3 -1
- package/dist/runtime/utils/localize.js +1 -2
- package/dist/runtime/utils/statusStyle.d.ts +6 -0
- package/dist/runtime/utils/statusStyle.js +15 -0
- package/package.json +11 -1
- package/dist/runtime/components/Integrations/RunDetailDialog.vue +0 -169
- package/dist/runtime/pages/integrations/workflows/new.d.vue.ts +0 -2
- package/dist/runtime/pages/integrations/workflows/new.vue +0 -153
- package/dist/runtime/pages/integrations/workflows/new.vue.d.ts +0 -2
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import { computed, reactive, ref, watch } from "vue";
|
|
3
|
+
import { AddCircle as Plus, Copy, TrashBinMinimalistic as Trash2 } from "#solar-icons";
|
|
4
|
+
import {
|
|
5
|
+
Button,
|
|
6
|
+
Dialog,
|
|
7
|
+
DialogContent,
|
|
8
|
+
DialogDescription,
|
|
9
|
+
DialogHeader,
|
|
10
|
+
DialogTitle,
|
|
11
|
+
Input,
|
|
12
|
+
Label,
|
|
13
|
+
Switch,
|
|
14
|
+
Select,
|
|
15
|
+
SelectContent,
|
|
16
|
+
SelectItem,
|
|
17
|
+
SelectTrigger,
|
|
18
|
+
SelectValue
|
|
19
|
+
} from "@revenexx/studio";
|
|
20
|
+
import { toast } from "vue-sonner";
|
|
21
|
+
const props = defineProps({
|
|
22
|
+
open: { type: Boolean, required: true },
|
|
23
|
+
variables: { type: Object, required: true }
|
|
24
|
+
});
|
|
25
|
+
const emit = defineEmits(["update:open", "update:variables"]);
|
|
26
|
+
const KEY_PATTERN = /^[a-z_][a-z0-9_]*$/i;
|
|
27
|
+
const TYPES = ["string", "number", "boolean", "object", "array"];
|
|
28
|
+
const jsonDrafts = reactive({});
|
|
29
|
+
const jsonErrors = reactive({});
|
|
30
|
+
watch(() => props.open, (o) => {
|
|
31
|
+
if (!o) return;
|
|
32
|
+
for (const k of Object.keys(jsonDrafts)) delete jsonDrafts[k];
|
|
33
|
+
for (const k of Object.keys(jsonErrors)) delete jsonErrors[k];
|
|
34
|
+
for (const [key, v] of Object.entries(props.variables)) {
|
|
35
|
+
if (v.type === "object" || v.type === "array") {
|
|
36
|
+
jsonDrafts[key] = v.default === void 0 ? "" : JSON.stringify(v.default, null, 2);
|
|
37
|
+
jsonErrors[key] = null;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
const entries = computed(() => Object.entries(props.variables));
|
|
42
|
+
function commit(next) {
|
|
43
|
+
emit("update:variables", next);
|
|
44
|
+
}
|
|
45
|
+
function patchVar(key, patch) {
|
|
46
|
+
const cur = props.variables[key];
|
|
47
|
+
if (!cur) return;
|
|
48
|
+
commit({ ...props.variables, [key]: { ...cur, ...patch } });
|
|
49
|
+
}
|
|
50
|
+
function removeVar(key) {
|
|
51
|
+
const next = { ...props.variables };
|
|
52
|
+
delete next[key];
|
|
53
|
+
delete jsonDrafts[key];
|
|
54
|
+
delete jsonErrors[key];
|
|
55
|
+
commit(next);
|
|
56
|
+
}
|
|
57
|
+
function changeType(key, type) {
|
|
58
|
+
const blank = {
|
|
59
|
+
string: "",
|
|
60
|
+
number: 0,
|
|
61
|
+
boolean: false,
|
|
62
|
+
object: void 0,
|
|
63
|
+
array: void 0
|
|
64
|
+
};
|
|
65
|
+
patchVar(key, { type, default: blank[type] });
|
|
66
|
+
if (type === "object" || type === "array") {
|
|
67
|
+
jsonDrafts[key] = "";
|
|
68
|
+
jsonErrors[key] = null;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
function applyJsonDraft(key, type) {
|
|
72
|
+
const raw = (jsonDrafts[key] ?? "").trim();
|
|
73
|
+
if (!raw) {
|
|
74
|
+
jsonErrors[key] = null;
|
|
75
|
+
patchVar(key, { default: void 0 });
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
try {
|
|
79
|
+
const parsed = JSON.parse(raw);
|
|
80
|
+
const ok = type === "array" ? Array.isArray(parsed) : parsed !== null && typeof parsed === "object" && !Array.isArray(parsed);
|
|
81
|
+
if (!ok) {
|
|
82
|
+
jsonErrors[key] = type === "array" ? "Must be a JSON array." : "Must be a JSON object.";
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
jsonErrors[key] = null;
|
|
86
|
+
patchVar(key, { default: parsed });
|
|
87
|
+
} catch {
|
|
88
|
+
jsonErrors[key] = "Not valid JSON.";
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
function descriptionText(v) {
|
|
92
|
+
const d = v.description;
|
|
93
|
+
if (!d) return "";
|
|
94
|
+
return typeof d === "string" ? d : d.en ?? Object.values(d)[0] ?? "";
|
|
95
|
+
}
|
|
96
|
+
function writeDescription(key, text) {
|
|
97
|
+
const cur = props.variables[key];
|
|
98
|
+
if (!cur) return;
|
|
99
|
+
if (!text.trim()) {
|
|
100
|
+
const { description: _drop, ...rest } = cur;
|
|
101
|
+
commit({ ...props.variables, [key]: rest });
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
const existing = typeof cur.description === "object" && cur.description !== null ? cur.description : {};
|
|
105
|
+
patchVar(key, { description: { ...existing, en: text } });
|
|
106
|
+
}
|
|
107
|
+
const newKey = ref("");
|
|
108
|
+
const newKeyError = computed(() => {
|
|
109
|
+
const k = newKey.value.trim();
|
|
110
|
+
if (!k) return null;
|
|
111
|
+
if (!KEY_PATTERN.test(k)) return "Letters, digits and _ only; must not start with a digit.";
|
|
112
|
+
if (props.variables[k]) return "Key already exists.";
|
|
113
|
+
return null;
|
|
114
|
+
});
|
|
115
|
+
function addVariable() {
|
|
116
|
+
const k = newKey.value.trim();
|
|
117
|
+
if (!k || newKeyError.value) return;
|
|
118
|
+
commit({ ...props.variables, [k]: { type: "string", default: "" } });
|
|
119
|
+
newKey.value = "";
|
|
120
|
+
}
|
|
121
|
+
async function copyUsage(key) {
|
|
122
|
+
try {
|
|
123
|
+
await navigator.clipboard.writeText(`\${{ vars.${key} }}`);
|
|
124
|
+
toast.success("Expression copied");
|
|
125
|
+
} catch {
|
|
126
|
+
toast.error("Could not copy");
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
</script>
|
|
130
|
+
|
|
131
|
+
<template>
|
|
132
|
+
<Dialog :open="open" @update:open="(v2) => emit('update:open', v2)">
|
|
133
|
+
<DialogContent class="max-w-[94vw] sm:max-w-3xl">
|
|
134
|
+
<DialogHeader>
|
|
135
|
+
<DialogTitle>Workflow variables</DialogTitle>
|
|
136
|
+
<DialogDescription class="text-sm">
|
|
137
|
+
Reusable values for this workflow — reference them in any config field as
|
|
138
|
+
<code v-pre class="rounded bg-black/[0.05] px-1 py-0.5 font-mono text-xs">${{ vars.key }}</code>.
|
|
139
|
+
Changes persist with the workflow Save.
|
|
140
|
+
</DialogDescription>
|
|
141
|
+
</DialogHeader>
|
|
142
|
+
|
|
143
|
+
<div class="max-h-[62vh] space-y-3 overflow-y-auto pr-1">
|
|
144
|
+
<p v-if="!entries.length" class="rounded-lg border border-dashed border-black/[0.12] px-4 py-6 text-center text-sm text-muted-foreground">
|
|
145
|
+
No variables yet — add the first one below.
|
|
146
|
+
</p>
|
|
147
|
+
|
|
148
|
+
<div
|
|
149
|
+
v-for="[key, v] in entries"
|
|
150
|
+
:key="key"
|
|
151
|
+
class="rounded-lg border border-black/[0.06] bg-white p-3"
|
|
152
|
+
>
|
|
153
|
+
<div class="flex items-center gap-2">
|
|
154
|
+
<code class="min-w-0 truncate font-mono text-sm font-semibold">{{ key }}</code>
|
|
155
|
+
<button
|
|
156
|
+
type="button"
|
|
157
|
+
class="flex size-6 shrink-0 items-center justify-center rounded-md text-muted-foreground transition hover:bg-muted/50 hover:text-foreground"
|
|
158
|
+
:title="`Copy \${{ vars.${key} }}`"
|
|
159
|
+
@click="copyUsage(key)"
|
|
160
|
+
>
|
|
161
|
+
<Copy :size="12" />
|
|
162
|
+
</button>
|
|
163
|
+
<div class="flex-1" />
|
|
164
|
+
<label class="flex items-center gap-1.5 text-sm text-muted-foreground">
|
|
165
|
+
Required
|
|
166
|
+
<Switch
|
|
167
|
+
:model-value="v.required === true"
|
|
168
|
+
@update:model-value="(val) => patchVar(key, { required: val || void 0 })"
|
|
169
|
+
/>
|
|
170
|
+
</label>
|
|
171
|
+
<button
|
|
172
|
+
type="button"
|
|
173
|
+
class="flex size-6 shrink-0 items-center justify-center rounded-md text-muted-foreground transition hover:bg-rose-50 hover:text-rose-600"
|
|
174
|
+
title="Delete variable"
|
|
175
|
+
@click="removeVar(key)"
|
|
176
|
+
>
|
|
177
|
+
<Trash2 :size="13" />
|
|
178
|
+
</button>
|
|
179
|
+
</div>
|
|
180
|
+
|
|
181
|
+
<div class="mt-2 grid gap-2 sm:grid-cols-[8rem_1fr]">
|
|
182
|
+
<div class="space-y-1">
|
|
183
|
+
<Label class="text-mono text-muted-foreground">Type</Label>
|
|
184
|
+
<Select :model-value="v.type" @update:model-value="(t) => changeType(key, t)">
|
|
185
|
+
<SelectTrigger class="h-8 bg-white text-sm">
|
|
186
|
+
<SelectValue />
|
|
187
|
+
</SelectTrigger>
|
|
188
|
+
<SelectContent>
|
|
189
|
+
<SelectItem v-for="t in TYPES" :key="t" :value="t">{{ t }}</SelectItem>
|
|
190
|
+
</SelectContent>
|
|
191
|
+
</Select>
|
|
192
|
+
</div>
|
|
193
|
+
|
|
194
|
+
<div class="space-y-1">
|
|
195
|
+
<Label class="text-mono text-muted-foreground">
|
|
196
|
+
Default{{ v.required ? " (ignored while required)" : "" }}
|
|
197
|
+
</Label>
|
|
198
|
+
|
|
199
|
+
<Input
|
|
200
|
+
v-if="v.type === 'string'"
|
|
201
|
+
:model-value="typeof v.default === 'string' ? v.default : ''"
|
|
202
|
+
class="h-8 bg-white text-sm"
|
|
203
|
+
@update:model-value="(val) => patchVar(key, { default: String(val) })"
|
|
204
|
+
/>
|
|
205
|
+
<Input
|
|
206
|
+
v-else-if="v.type === 'number'"
|
|
207
|
+
type="number"
|
|
208
|
+
:model-value="typeof v.default === 'number' ? v.default : ''"
|
|
209
|
+
class="h-8 bg-white text-sm"
|
|
210
|
+
@update:model-value="(val) => patchVar(key, { default: val === '' ? void 0 : Number(val) })"
|
|
211
|
+
/>
|
|
212
|
+
<div v-else-if="v.type === 'boolean'" class="flex h-8 items-center">
|
|
213
|
+
<Switch
|
|
214
|
+
:model-value="v.default === true"
|
|
215
|
+
@update:model-value="(val) => patchVar(key, { default: val })"
|
|
216
|
+
/>
|
|
217
|
+
</div>
|
|
218
|
+
<div v-else>
|
|
219
|
+
<textarea
|
|
220
|
+
:value="jsonDrafts[key] ?? ''"
|
|
221
|
+
rows="3"
|
|
222
|
+
spellcheck="false"
|
|
223
|
+
class="w-full rounded-md border bg-white p-2 font-mono text-xs focus:outline-none focus:ring-2 focus:ring-primary/40"
|
|
224
|
+
:class="jsonErrors[key] ? 'border-rose-400' : 'border-black/[0.08]'"
|
|
225
|
+
:placeholder="v.type === 'array' ? 'JSON array, e.g. [1, 2]' : 'JSON object, e.g. { \u2026 }'"
|
|
226
|
+
@input="(e) => jsonDrafts[key] = e.target.value"
|
|
227
|
+
@blur="applyJsonDraft(key, v.type)"
|
|
228
|
+
/>
|
|
229
|
+
<p v-if="jsonErrors[key]" class="text-xs text-rose-600">{{ jsonErrors[key] }}</p>
|
|
230
|
+
</div>
|
|
231
|
+
</div>
|
|
232
|
+
</div>
|
|
233
|
+
|
|
234
|
+
<div class="mt-2 space-y-1">
|
|
235
|
+
<Label class="text-mono text-muted-foreground">Description</Label>
|
|
236
|
+
<Input
|
|
237
|
+
:model-value="descriptionText(v)"
|
|
238
|
+
class="h-8 bg-white text-sm"
|
|
239
|
+
placeholder="What this variable is for"
|
|
240
|
+
@update:model-value="(val) => writeDescription(key, String(val))"
|
|
241
|
+
/>
|
|
242
|
+
</div>
|
|
243
|
+
</div>
|
|
244
|
+
|
|
245
|
+
<!-- Add row -->
|
|
246
|
+
<div class="rounded-lg border border-dashed border-black/[0.12] p-3">
|
|
247
|
+
<Label class="text-mono text-muted-foreground">New variable</Label>
|
|
248
|
+
<div class="mt-1 flex items-center gap-2">
|
|
249
|
+
<Input
|
|
250
|
+
v-model="newKey"
|
|
251
|
+
class="h-8 flex-1 bg-white font-mono text-sm"
|
|
252
|
+
placeholder="e.g. base_url"
|
|
253
|
+
@keydown.enter.prevent="addVariable"
|
|
254
|
+
/>
|
|
255
|
+
<Button size="sm" class="h-8" :disabled="!newKey.trim() || !!newKeyError" @click="addVariable">
|
|
256
|
+
<Plus :size="14" class="mr-1" />
|
|
257
|
+
Add
|
|
258
|
+
</Button>
|
|
259
|
+
</div>
|
|
260
|
+
<p v-if="newKeyError" class="mt-1 text-xs text-rose-600">{{ newKeyError }}</p>
|
|
261
|
+
</div>
|
|
262
|
+
</div>
|
|
263
|
+
</DialogContent>
|
|
264
|
+
</Dialog>
|
|
265
|
+
</template>
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { WorkflowVariable } from '../../types/integrations.js';
|
|
2
|
+
type __VLS_Props = {
|
|
3
|
+
open: boolean;
|
|
4
|
+
variables: Record<string, WorkflowVariable>;
|
|
5
|
+
};
|
|
6
|
+
declare const _default: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
7
|
+
"update:open": (args_0: boolean) => any;
|
|
8
|
+
"update:variables": (next: Record<string, WorkflowVariable>) => any;
|
|
9
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
10
|
+
"onUpdate:open"?: ((args_0: boolean) => any) | undefined;
|
|
11
|
+
"onUpdate:variables"?: ((next: Record<string, WorkflowVariable>) => any) | undefined;
|
|
12
|
+
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
13
|
+
export default _default;
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import type { Workflow as WorkflowResource } from '../../types/integrations.js';
|
|
2
2
|
type __VLS_Props = {
|
|
3
3
|
workflows: WorkflowResource[];
|
|
4
|
+
loading?: boolean;
|
|
4
5
|
};
|
|
5
|
-
declare const _default: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
|
|
6
|
+
declare const _default: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
|
|
7
|
+
loading: boolean;
|
|
8
|
+
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
6
9
|
export default _default;
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
<script setup>
|
|
2
|
-
import {
|
|
2
|
+
import { RefreshCircle as Loader2, MenuDots as MoreHorizontal } from "#solar-icons";
|
|
3
|
+
import { toast } from "vue-sonner";
|
|
4
|
+
import WorkflowDuplicateDialog from "./WorkflowDuplicateDialog.vue";
|
|
5
|
+
import WorkflowIconView from "./WorkflowIconView.vue";
|
|
6
|
+
import { Layers } from "#solar-icons";
|
|
3
7
|
import {
|
|
4
8
|
AlertDialog,
|
|
5
9
|
AlertDialogContent,
|
|
@@ -17,10 +21,33 @@ import {
|
|
|
17
21
|
DropdownMenuTrigger
|
|
18
22
|
} from "@revenexx/studio";
|
|
19
23
|
defineProps({
|
|
20
|
-
workflows: { type: Array, required: true }
|
|
24
|
+
workflows: { type: Array, required: true },
|
|
25
|
+
loading: { type: Boolean, required: false, default: false }
|
|
21
26
|
});
|
|
22
27
|
const router = useRouter();
|
|
23
28
|
const { remove, toggleActive } = useIntegrationsWorkflows();
|
|
29
|
+
const duplicateTarget = ref(null);
|
|
30
|
+
const duplicateOpen = ref(false);
|
|
31
|
+
function askDuplicate(wf) {
|
|
32
|
+
duplicateTarget.value = { id: wf.id, name: wf.name };
|
|
33
|
+
duplicateOpen.value = true;
|
|
34
|
+
}
|
|
35
|
+
async function onDuplicated(copy) {
|
|
36
|
+
toast.success(`Duplicated as \u201C${copy.name}\u201D`);
|
|
37
|
+
await router.push(`/integrations/workflows/${copy.id}`);
|
|
38
|
+
}
|
|
39
|
+
const GROUP_BY_TAGS_KEY = "integrations.workflows.groupByTags";
|
|
40
|
+
const groupByTags = ref(false);
|
|
41
|
+
try {
|
|
42
|
+
groupByTags.value = localStorage.getItem(GROUP_BY_TAGS_KEY) === "1";
|
|
43
|
+
} catch {
|
|
44
|
+
}
|
|
45
|
+
watch(groupByTags, (on) => {
|
|
46
|
+
try {
|
|
47
|
+
localStorage.setItem(GROUP_BY_TAGS_KEY, on ? "1" : "0");
|
|
48
|
+
} catch {
|
|
49
|
+
}
|
|
50
|
+
});
|
|
24
51
|
const { runs, load: loadRuns, list: listRuns } = useIntegrationsRuns();
|
|
25
52
|
onMounted(() => {
|
|
26
53
|
void loadRuns();
|
|
@@ -59,14 +86,37 @@ async function confirmDelete() {
|
|
|
59
86
|
deleting.value = false;
|
|
60
87
|
}
|
|
61
88
|
}
|
|
62
|
-
function triggerIcon(type) {
|
|
63
|
-
return type === "schedule" ? Clock : type === "webhook" ? Webhook : type === "event" ? Bolt : Play;
|
|
64
|
-
}
|
|
65
89
|
function statusBadge(wf) {
|
|
66
90
|
if (!wf.active) return { label: "Paused", class: "bg-slate-100 text-slate-700 border-slate-200" };
|
|
67
91
|
if (wf.revision === 0) return { label: "Draft", class: "bg-amber-500/10 text-amber-700 border-amber-500/20" };
|
|
68
92
|
return { label: "Active", class: "bg-emerald-500/10 text-emerald-700 border-emerald-500/20" };
|
|
69
93
|
}
|
|
94
|
+
function buildState(wf) {
|
|
95
|
+
switch (wf.buildStatus) {
|
|
96
|
+
case "building":
|
|
97
|
+
return { label: "Building\u2026", class: "bg-sky-500/15 text-sky-700 border-sky-500/20" };
|
|
98
|
+
case "pending":
|
|
99
|
+
return { label: "Pending", class: "bg-amber-500/10 text-amber-700 border-amber-500/20" };
|
|
100
|
+
case "failed":
|
|
101
|
+
return { label: "Failed", class: "bg-rose-500/15 text-rose-700 border-rose-500/20" };
|
|
102
|
+
case "ready":
|
|
103
|
+
return { label: "Ready", class: "bg-emerald-500/10 text-emerald-700 border-emerald-500/20" };
|
|
104
|
+
default:
|
|
105
|
+
return { label: "\u2014", class: "bg-slate-100 text-slate-700 border-slate-200" };
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
function modeLabel(m) {
|
|
109
|
+
switch (m) {
|
|
110
|
+
case "sync_only":
|
|
111
|
+
return "sync";
|
|
112
|
+
case "caller_decides":
|
|
113
|
+
return "caller";
|
|
114
|
+
case "async_only":
|
|
115
|
+
return "async";
|
|
116
|
+
default:
|
|
117
|
+
return "\u2014";
|
|
118
|
+
}
|
|
119
|
+
}
|
|
70
120
|
function formatDateTime(iso) {
|
|
71
121
|
if (!iso) return "\u2014";
|
|
72
122
|
try {
|
|
@@ -86,7 +136,7 @@ const columns = [
|
|
|
86
136
|
label: "Name",
|
|
87
137
|
sortable: true,
|
|
88
138
|
sortGetter: (w) => w.name.toLowerCase(),
|
|
89
|
-
searchGetter: (w) => `${w.name} ${w.description ?? ""}`
|
|
139
|
+
searchGetter: (w) => `${w.name} ${w.description ?? ""} ${(w.blob.tags ?? []).join(" ")}`
|
|
90
140
|
},
|
|
91
141
|
{
|
|
92
142
|
key: "status",
|
|
@@ -96,30 +146,32 @@ const columns = [
|
|
|
96
146
|
sortGetter: (w) => w.active ? w.revision === 0 ? "draft" : "active" : "paused"
|
|
97
147
|
},
|
|
98
148
|
{
|
|
99
|
-
key: "
|
|
100
|
-
label: "
|
|
101
|
-
width: "
|
|
149
|
+
key: "build",
|
|
150
|
+
label: "Build",
|
|
151
|
+
width: "120px",
|
|
102
152
|
sortable: true,
|
|
103
|
-
sortGetter: (w) => w.
|
|
153
|
+
sortGetter: (w) => w.buildStatus ?? ""
|
|
104
154
|
},
|
|
105
155
|
{
|
|
106
|
-
key: "
|
|
107
|
-
label: "
|
|
108
|
-
width: "
|
|
156
|
+
key: "mode",
|
|
157
|
+
label: "Mode",
|
|
158
|
+
width: "120px",
|
|
109
159
|
sortable: true,
|
|
110
|
-
sortGetter: (w) => w.
|
|
160
|
+
sortGetter: (w) => w.execution_mode ?? ""
|
|
111
161
|
},
|
|
112
162
|
{
|
|
113
|
-
key: "
|
|
114
|
-
label: "
|
|
115
|
-
width: "
|
|
163
|
+
key: "triggers",
|
|
164
|
+
label: "Triggers",
|
|
165
|
+
width: "140px",
|
|
116
166
|
sortable: true,
|
|
117
|
-
sortGetter: (w) => w.
|
|
167
|
+
sortGetter: (w) => w.blob.triggers.map((t) => t.type).join(",")
|
|
118
168
|
},
|
|
119
169
|
{
|
|
120
170
|
key: "lastRun",
|
|
121
171
|
label: "Last run",
|
|
122
|
-
|
|
172
|
+
// Wide enough for badge + full timestamp — the flexible Name column has
|
|
173
|
+
// the slack to give; a truncated "18. Juli, 1…" helps nobody.
|
|
174
|
+
width: "210px",
|
|
123
175
|
sortable: true,
|
|
124
176
|
sortGetter: (w) => lastRunFor(w.id)?.startedAt ?? ""
|
|
125
177
|
},
|
|
@@ -142,59 +194,86 @@ const columns = [
|
|
|
142
194
|
<template>
|
|
143
195
|
<DataTable
|
|
144
196
|
:data="workflows"
|
|
197
|
+
:group-by="groupByTags ? (w) => w.blob.tags ?? [] : null"
|
|
198
|
+
group-empty-label="No tags"
|
|
145
199
|
:columns="columns"
|
|
146
200
|
:row-key="(wf2) => wf2.id"
|
|
147
201
|
:default-sort="{ column: 'updated', direction: 'desc' }"
|
|
148
202
|
:search="{ placeholder: 'Search workflows\u2026' }"
|
|
149
203
|
:filter="true"
|
|
204
|
+
:loading="loading"
|
|
150
205
|
empty-text="No workflows yet."
|
|
151
206
|
@row-click="(wf2) => router.push(`/integrations/workflows/${wf2.id}`)"
|
|
152
207
|
>
|
|
208
|
+
<template #toolbar-left>
|
|
209
|
+
<Button
|
|
210
|
+
variant="outline"
|
|
211
|
+
size="sm"
|
|
212
|
+
class="h-7 gap-1.5 text-sm"
|
|
213
|
+
:class="groupByTags ? 'border-primary/30 text-primary' : ''"
|
|
214
|
+
@click="groupByTags = !groupByTags"
|
|
215
|
+
>
|
|
216
|
+
<Layers :size="13" />
|
|
217
|
+
Group by tags
|
|
218
|
+
</Button>
|
|
219
|
+
</template>
|
|
220
|
+
|
|
153
221
|
<!-- Name (icon + title + description) -->
|
|
154
222
|
<template #cell-name="{ row: wf }">
|
|
155
223
|
<div class="flex items-center gap-2 min-w-0">
|
|
156
|
-
<div class="flex size-
|
|
157
|
-
<
|
|
224
|
+
<div class="flex size-8 shrink-0 items-center justify-center rounded-md bg-slate-100 text-slate-500">
|
|
225
|
+
<WorkflowIconView :icon="wf.blob.icon" :size="18" />
|
|
158
226
|
</div>
|
|
159
227
|
<div class="flex flex-col min-w-0">
|
|
160
228
|
<span class="font-medium text-sm truncate">{{ wf.name }}</span>
|
|
161
229
|
<span v-if="wf.description" class="text-sm text-muted-foreground truncate">{{ wf.description }}</span>
|
|
230
|
+
<div v-if="wf.blob.tags?.length" class="mt-0.5 flex flex-wrap gap-1">
|
|
231
|
+
<span
|
|
232
|
+
v-for="t in wf.blob.tags"
|
|
233
|
+
:key="t"
|
|
234
|
+
class="rounded border border-black/[0.06] bg-muted/50 px-1 text-[10px] leading-4 text-muted-foreground"
|
|
235
|
+
>{{ t }}</span>
|
|
236
|
+
</div>
|
|
162
237
|
</div>
|
|
163
238
|
</div>
|
|
164
239
|
</template>
|
|
165
240
|
|
|
166
241
|
<template #cell-status="{ row: wf }">
|
|
167
|
-
<Badge variant="outline" :class="['text-
|
|
242
|
+
<Badge variant="outline" :class="['border text-xs font-medium uppercase', statusBadge(wf).class]">
|
|
168
243
|
{{ statusBadge(wf).label }}
|
|
169
244
|
</Badge>
|
|
170
245
|
</template>
|
|
171
246
|
|
|
247
|
+
<template #cell-build="{ row: wf }">
|
|
248
|
+
<Badge variant="outline" :class="['border text-xs font-medium uppercase', buildState(wf).class]">
|
|
249
|
+
{{ buildState(wf).label }}
|
|
250
|
+
</Badge>
|
|
251
|
+
</template>
|
|
252
|
+
|
|
253
|
+
<template #cell-mode="{ row: wf }">
|
|
254
|
+
<Badge v-if="wf.execution_mode" variant="outline" class="border text-xs font-medium uppercase text-muted-foreground">
|
|
255
|
+
{{ modeLabel(wf.execution_mode) }}
|
|
256
|
+
</Badge>
|
|
257
|
+
<span v-else class="text-sm text-muted-foreground">—</span>
|
|
258
|
+
</template>
|
|
259
|
+
|
|
260
|
+
<!-- Small badges, stacked vertically — several triggers must never
|
|
261
|
+
overflow the column into their neighbors. -->
|
|
172
262
|
<template #cell-triggers="{ row: wf }">
|
|
173
|
-
<div class="flex
|
|
263
|
+
<div class="flex min-w-0 flex-col items-start gap-1">
|
|
174
264
|
<span
|
|
175
265
|
v-for="t in wf.blob.triggers"
|
|
176
266
|
:key="t.id"
|
|
177
|
-
class="inline-flex items-center
|
|
267
|
+
class="inline-flex items-center whitespace-nowrap rounded-md border border-black/[0.06] bg-muted/50 px-1.5 py-0.5 text-xs font-medium uppercase text-muted-foreground"
|
|
178
268
|
>
|
|
179
|
-
<component :is="triggerIcon(t.type)" :size="11" />
|
|
180
269
|
{{ t.type }}
|
|
181
270
|
</span>
|
|
182
271
|
</div>
|
|
183
272
|
</template>
|
|
184
273
|
|
|
185
|
-
<template #cell-nodes="{ row: wf }">
|
|
186
|
-
<span class="text-sm text-muted-foreground tabular-nums">
|
|
187
|
-
{{ wf.blob.nodes.length }} node<span v-if="wf.blob.nodes.length !== 1">s</span>
|
|
188
|
-
</span>
|
|
189
|
-
</template>
|
|
190
|
-
|
|
191
|
-
<template #cell-revision="{ row: wf }">
|
|
192
|
-
<span class="text-sm text-muted-foreground tabular-nums">r{{ wf.revision }}</span>
|
|
193
|
-
</template>
|
|
194
|
-
|
|
195
274
|
<template #cell-lastRun="{ row: wf }">
|
|
196
275
|
<div v-if="lastRunFor(wf.id)" class="flex items-center gap-2 min-w-0">
|
|
197
|
-
<Badge variant="outline" :class="['text-
|
|
276
|
+
<Badge variant="outline" :class="['border text-xs font-medium uppercase shrink-0', runBadge(lastRunFor(wf.id).status).class]">
|
|
198
277
|
{{ runBadge(lastRunFor(wf.id).status).label }}
|
|
199
278
|
</Badge>
|
|
200
279
|
<span class="text-sm tabular-nums text-muted-foreground truncate">
|
|
@@ -222,10 +301,12 @@ const columns = [
|
|
|
222
301
|
<DropdownMenuLabel>Actions</DropdownMenuLabel>
|
|
223
302
|
<DropdownMenuSeparator />
|
|
224
303
|
<DropdownMenuItem @select="router.push(`/integrations/workflows/${wf.id}`)">
|
|
225
|
-
|
|
304
|
+
Open editor
|
|
305
|
+
</DropdownMenuItem>
|
|
306
|
+
<DropdownMenuItem @select="askDuplicate(wf)">
|
|
307
|
+
Duplicate
|
|
226
308
|
</DropdownMenuItem>
|
|
227
309
|
<DropdownMenuItem @select="toggleActive(wf.id)">
|
|
228
|
-
<component :is="wf.active ? Pause : Play" :size="14" />
|
|
229
310
|
{{ wf.active ? "Pause" : "Activate" }}
|
|
230
311
|
</DropdownMenuItem>
|
|
231
312
|
<DropdownMenuSeparator />
|
|
@@ -233,7 +314,7 @@ const columns = [
|
|
|
233
314
|
class="text-destructive focus:text-destructive"
|
|
234
315
|
@select="askDelete(wf)"
|
|
235
316
|
>
|
|
236
|
-
|
|
317
|
+
Delete
|
|
237
318
|
</DropdownMenuItem>
|
|
238
319
|
</DropdownMenuContent>
|
|
239
320
|
</DropdownMenu>
|
|
@@ -265,4 +346,6 @@ const columns = [
|
|
|
265
346
|
</AlertDialogFooter>
|
|
266
347
|
</AlertDialogContent>
|
|
267
348
|
</AlertDialog>
|
|
349
|
+
|
|
350
|
+
<WorkflowDuplicateDialog v-model:open="duplicateOpen" :workflow="duplicateTarget" @duplicated="onDuplicated" />
|
|
268
351
|
</template>
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import type { Workflow as WorkflowResource } from '../../types/integrations.js';
|
|
2
2
|
type __VLS_Props = {
|
|
3
3
|
workflows: WorkflowResource[];
|
|
4
|
+
loading?: boolean;
|
|
4
5
|
};
|
|
5
|
-
declare const _default: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
|
|
6
|
+
declare const _default: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
|
|
7
|
+
loading: boolean;
|
|
8
|
+
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
6
9
|
export default _default;
|
|
@@ -14,4 +14,9 @@ export declare function layoutWorkflowNodes(nodes: VFNode[], edges: VFEdge[], op
|
|
|
14
14
|
nodeHeight?: number;
|
|
15
15
|
rankSeparation?: number;
|
|
16
16
|
nodeSeparation?: number;
|
|
17
|
+
/** Per-node size overrides (e.g. group clusters laid out as one unit). */
|
|
18
|
+
sizes?: Record<string, {
|
|
19
|
+
width: number;
|
|
20
|
+
height: number;
|
|
21
|
+
}>;
|
|
17
22
|
}): VFNode[];
|
|
@@ -8,8 +8,9 @@ export function layoutWorkflowNodes(nodes, edges, options = {}) {
|
|
|
8
8
|
const g = new dagre.graphlib.Graph();
|
|
9
9
|
g.setDefaultEdgeLabel(() => ({}));
|
|
10
10
|
g.setGraph({ rankdir: dir, ranksep, nodesep, marginx: 20, marginy: 20 });
|
|
11
|
+
const sizeOf = (id) => options.sizes?.[id] ?? { width: nodeWidth, height: nodeHeight };
|
|
11
12
|
for (const n of nodes) {
|
|
12
|
-
g.setNode(n.id,
|
|
13
|
+
g.setNode(n.id, sizeOf(n.id));
|
|
13
14
|
}
|
|
14
15
|
for (const e of edges) {
|
|
15
16
|
g.setEdge(e.source, e.target);
|
|
@@ -18,11 +19,12 @@ export function layoutWorkflowNodes(nodes, edges, options = {}) {
|
|
|
18
19
|
return nodes.map((n) => {
|
|
19
20
|
const laid = g.node(n.id);
|
|
20
21
|
if (!laid) return n;
|
|
22
|
+
const size = sizeOf(n.id);
|
|
21
23
|
return {
|
|
22
24
|
...n,
|
|
23
25
|
position: {
|
|
24
|
-
x: laid.x -
|
|
25
|
-
y: laid.y -
|
|
26
|
+
x: laid.x - size.width / 2,
|
|
27
|
+
y: laid.y - size.height / 2
|
|
26
28
|
}
|
|
27
29
|
};
|
|
28
30
|
});
|
|
@@ -5,8 +5,12 @@ export declare class IntegrationsApiError extends Error {
|
|
|
5
5
|
}
|
|
6
6
|
export declare function useIntegrationsApi(): {
|
|
7
7
|
baseUrl: import("vue").ComputedRef<string>;
|
|
8
|
-
get: <T>(path: string
|
|
9
|
-
|
|
8
|
+
get: <T>(path: string, opts?: {
|
|
9
|
+
signal?: AbortSignal;
|
|
10
|
+
}) => Promise<T>;
|
|
11
|
+
post: <T>(path: string, body?: unknown, opts?: {
|
|
12
|
+
signal?: AbortSignal;
|
|
13
|
+
}) => Promise<T>;
|
|
10
14
|
put: <T>(path: string, body?: unknown) => Promise<T>;
|
|
11
15
|
patch: <T>(path: string, body?: unknown) => Promise<T>;
|
|
12
16
|
del: <T>(path: string) => Promise<T>;
|
|
@@ -29,13 +29,14 @@ export function useIntegrationsApi() {
|
|
|
29
29
|
function url(path) {
|
|
30
30
|
return `${baseUrl.value.replace(/\/$/, "")}${path.startsWith("/") ? path : `/${path}`}`;
|
|
31
31
|
}
|
|
32
|
-
async function request(method, path, body) {
|
|
32
|
+
async function request(method, path, body, opts) {
|
|
33
33
|
const headers = await buildHeaders(body !== void 0 ? { "Content-Type": "application/json" } : {});
|
|
34
34
|
try {
|
|
35
35
|
return await $fetch(url(path), {
|
|
36
36
|
method,
|
|
37
37
|
headers,
|
|
38
|
-
body: body !== void 0 ? body : void 0
|
|
38
|
+
body: body !== void 0 ? body : void 0,
|
|
39
|
+
signal: opts?.signal
|
|
39
40
|
});
|
|
40
41
|
} catch (err) {
|
|
41
42
|
const fe = err;
|
|
@@ -46,8 +47,8 @@ export function useIntegrationsApi() {
|
|
|
46
47
|
}
|
|
47
48
|
return {
|
|
48
49
|
baseUrl,
|
|
49
|
-
get: (path) => request("GET", path),
|
|
50
|
-
post: (path, body) => request("POST", path, body ?? {}),
|
|
50
|
+
get: (path, opts) => request("GET", path, void 0, opts),
|
|
51
|
+
post: (path, body, opts) => request("POST", path, body ?? {}, opts),
|
|
51
52
|
put: (path, body) => request("PUT", path, body ?? {}),
|
|
52
53
|
patch: (path, body) => request("PATCH", path, body ?? {}),
|
|
53
54
|
del: (path) => request("DELETE", path)
|