@revenexx/studio-integrations 1.3.0 → 1.4.1
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 +457 -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/CredentialDetailDialog.vue +61 -29
- package/dist/runtime/components/Integrations/EditorTip.vue +2 -15
- package/dist/runtime/components/Integrations/NodeConfigField.d.vue.ts +10 -0
- package/dist/runtime/components/Integrations/NodeConfigField.vue +94 -49
- package/dist/runtime/components/Integrations/NodeConfigField.vue.d.ts +10 -0
- package/dist/runtime/components/Integrations/NodeInspector.vue +37 -60
- package/dist/runtime/components/Integrations/RunDetailPanel.vue +80 -33
- 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 +165 -56
- 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/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 +5 -8
- package/dist/runtime/composables/useIntegrationsTriggers.js +1 -4
- package/dist/runtime/composables/useIntegrationsWorkflows.js +5 -7
- package/dist/runtime/data/canvasShortcuts.d.ts +208 -0
- package/dist/runtime/data/canvasShortcuts.js +68 -0
- package/dist/runtime/i18n/messages/de.json +30 -16
- package/dist/runtime/i18n/messages/en.json +30 -16
- package/dist/runtime/pages/integrations/credentials.vue +40 -18
- package/dist/runtime/pages/integrations/templates/[slug].vue +22 -132
- package/dist/runtime/pages/integrations/workflows/[id].vue +128 -33
- package/dist/runtime/utils/apiEnvelope.d.ts +27 -0
- package/dist/runtime/utils/apiEnvelope.js +20 -0
- package/dist/runtime/utils/apiError.d.ts +35 -8
- package/dist/runtime/utils/apiError.js +12 -12
- 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/shortcutLabel.d.ts +40 -0
- package/dist/runtime/utils/shortcutLabel.js +48 -0
- package/package.json +1 -1
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
type __VLS_Props = {
|
|
2
|
+
slug: string;
|
|
3
|
+
};
|
|
4
|
+
declare var __VLS_69: {
|
|
5
|
+
installing: any;
|
|
6
|
+
};
|
|
7
|
+
type __VLS_Slots = {} & {
|
|
8
|
+
secondary?: (props: typeof __VLS_69) => any;
|
|
9
|
+
};
|
|
10
|
+
declare const __VLS_component: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
11
|
+
installed: (id: number) => any;
|
|
12
|
+
"update:loading": (loading: boolean) => any;
|
|
13
|
+
"update:installing": (installing: boolean) => any;
|
|
14
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
15
|
+
onInstalled?: ((id: number) => any) | undefined;
|
|
16
|
+
"onUpdate:loading"?: ((loading: boolean) => any) | undefined;
|
|
17
|
+
"onUpdate:installing"?: ((installing: boolean) => any) | undefined;
|
|
18
|
+
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
19
|
+
declare const _default: __VLS_WithSlots<typeof __VLS_component, __VLS_Slots>;
|
|
20
|
+
export default _default;
|
|
21
|
+
type __VLS_WithSlots<T, S> = T & {
|
|
22
|
+
new (): {
|
|
23
|
+
$slots: S;
|
|
24
|
+
};
|
|
25
|
+
};
|
|
@@ -17,11 +17,11 @@ type __VLS_Slots = {} & {
|
|
|
17
17
|
default?: (props: typeof __VLS_14) => any;
|
|
18
18
|
};
|
|
19
19
|
declare const __VLS_component: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
20
|
-
action: (id: MenuActionId) => any;
|
|
21
20
|
"update:open": (open: boolean) => any;
|
|
21
|
+
action: (id: MenuActionId) => any;
|
|
22
22
|
}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
23
|
-
onAction?: ((id: MenuActionId) => any) | undefined;
|
|
24
23
|
"onUpdate:open"?: ((open: boolean) => any) | undefined;
|
|
24
|
+
onAction?: ((id: MenuActionId) => any) | undefined;
|
|
25
25
|
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
26
26
|
declare const _default: __VLS_WithSlots<typeof __VLS_component, __VLS_Slots>;
|
|
27
27
|
export default _default;
|
|
@@ -9,6 +9,8 @@ import {
|
|
|
9
9
|
ContextMenuShortcut,
|
|
10
10
|
ContextMenuTrigger
|
|
11
11
|
} from "@revenexx/studio";
|
|
12
|
+
import { primaryShortcut } from "../../data/canvasShortcuts";
|
|
13
|
+
import { formatShortcut } from "../../utils/shortcutLabel";
|
|
12
14
|
const props = defineProps({
|
|
13
15
|
kind: { type: String, required: true },
|
|
14
16
|
selectionCount: { type: Number, required: true },
|
|
@@ -18,44 +20,24 @@ const props = defineProps({
|
|
|
18
20
|
});
|
|
19
21
|
const emit = defineEmits(["action", "update:open"]);
|
|
20
22
|
const t = useIntegrationsT();
|
|
21
|
-
const isMac = typeof navigator !== "undefined" && /Mac|iPhone|iPad/.test(navigator.platform ?? "");
|
|
22
|
-
function formatShortcut(tokens) {
|
|
23
|
-
const parts = tokens.split("+");
|
|
24
|
-
const out = [];
|
|
25
|
-
for (const raw of parts) {
|
|
26
|
-
const t2 = raw.toLowerCase();
|
|
27
|
-
if (t2 === "mod") out.push(isMac ? "\u2318" : "Ctrl");
|
|
28
|
-
else if (t2 === "shift") out.push("\u21E7");
|
|
29
|
-
else if (t2 === "alt") out.push(isMac ? "\u2325" : "Alt");
|
|
30
|
-
else if (t2 === "enter") out.push("\u21B5");
|
|
31
|
-
else if (t2 === "backspace") out.push("\u232B");
|
|
32
|
-
else if (t2 === "delete") out.push("Del");
|
|
33
|
-
else if (t2 === "escape") out.push("Esc");
|
|
34
|
-
else if (t2 === "tab") out.push("Tab");
|
|
35
|
-
else if (t2 === "space") out.push("Space");
|
|
36
|
-
else if (t2 === "f2") out.push("F2");
|
|
37
|
-
else out.push(t2.toUpperCase());
|
|
38
|
-
}
|
|
39
|
-
return isMac ? out.join("") : out.join("+");
|
|
40
|
-
}
|
|
41
23
|
const allSelected = computed(() => props.totalNodes > 0 && props.selectionCount >= props.totalNodes);
|
|
42
24
|
const sections = computed(() => {
|
|
43
25
|
if (props.kind === "node") {
|
|
44
26
|
return [
|
|
45
27
|
[
|
|
46
|
-
{ id: "open", label: t("integration.canvas.contextMenu.item.open"), shortcut: "
|
|
47
|
-
{ id: "rename", label: t("integration.canvas.contextMenu.item.rename"), shortcut: "
|
|
28
|
+
{ id: "open", label: t("integration.canvas.contextMenu.item.open"), shortcut: primaryShortcut("open") },
|
|
29
|
+
{ id: "rename", label: t("integration.canvas.contextMenu.item.rename"), shortcut: primaryShortcut("rename") }
|
|
48
30
|
],
|
|
49
31
|
[
|
|
50
|
-
{ id: "copy", label: t("integration.canvas.contextMenu.item.copy"), shortcut: "
|
|
51
|
-
{ id: "duplicate", label: t("integration.canvas.contextMenu.item.duplicate"), shortcut: "
|
|
32
|
+
{ id: "copy", label: t("integration.canvas.contextMenu.item.copy"), shortcut: primaryShortcut("copy"), disabled: props.targetIsTrigger },
|
|
33
|
+
{ id: "duplicate", label: t("integration.canvas.contextMenu.item.duplicate"), shortcut: primaryShortcut("duplicate"), disabled: props.targetIsTrigger }
|
|
52
34
|
],
|
|
53
35
|
[
|
|
54
|
-
{ id: "run", label: t("integration.canvas.contextMenu.item.runWorkflow"), shortcut: "
|
|
55
|
-
{ id: "tidy-up", label: t("integration.canvas.contextMenu.item.tidyUp"), shortcut: "
|
|
36
|
+
{ id: "run", label: t("integration.canvas.contextMenu.item.runWorkflow"), shortcut: primaryShortcut("run"), disabled: props.runBusy },
|
|
37
|
+
{ id: "tidy-up", label: t("integration.canvas.contextMenu.item.tidyUp"), shortcut: primaryShortcut("tidyUp") }
|
|
56
38
|
],
|
|
57
39
|
[
|
|
58
|
-
{ id: "delete", label: t("integration.common.action.delete"), shortcut: "
|
|
40
|
+
{ id: "delete", label: t("integration.common.action.delete"), shortcut: primaryShortcut("delete"), danger: true }
|
|
59
41
|
]
|
|
60
42
|
];
|
|
61
43
|
}
|
|
@@ -63,32 +45,32 @@ const sections = computed(() => {
|
|
|
63
45
|
const n = props.selectionCount;
|
|
64
46
|
return [
|
|
65
47
|
[
|
|
66
|
-
{ id: "copy", label: t("integration.canvas.contextMenu.item.copyNodes", n), shortcut: "
|
|
67
|
-
{ id: "duplicate", label: t("integration.canvas.contextMenu.item.duplicateNodes", n), shortcut: "
|
|
48
|
+
{ id: "copy", label: t("integration.canvas.contextMenu.item.copyNodes", n), shortcut: primaryShortcut("copy") },
|
|
49
|
+
{ id: "duplicate", label: t("integration.canvas.contextMenu.item.duplicateNodes", n), shortcut: primaryShortcut("duplicate") }
|
|
68
50
|
],
|
|
69
51
|
[
|
|
70
|
-
{ id: "group", label: t("integration.canvas.contextMenu.item.groupNodes", n), shortcut: "
|
|
71
|
-
{ id: "tidy-up", label: t("integration.canvas.contextMenu.item.tidyUp"), shortcut: "
|
|
72
|
-
{ id: "select-all", label: t("integration.canvas.contextMenu.item.selectAll"), shortcut: "
|
|
73
|
-
{ id: "clear-selection", label: t("integration.canvas.contextMenu.item.clearSelection"), shortcut: "
|
|
52
|
+
{ id: "group", label: t("integration.canvas.contextMenu.item.groupNodes", n), shortcut: primaryShortcut("group") },
|
|
53
|
+
{ id: "tidy-up", label: t("integration.canvas.contextMenu.item.tidyUp"), shortcut: primaryShortcut("tidyUp") },
|
|
54
|
+
{ id: "select-all", label: t("integration.canvas.contextMenu.item.selectAll"), shortcut: primaryShortcut("selectAll"), disabled: allSelected.value },
|
|
55
|
+
{ id: "clear-selection", label: t("integration.canvas.contextMenu.item.clearSelection"), shortcut: primaryShortcut("clearSelection") }
|
|
74
56
|
],
|
|
75
57
|
[
|
|
76
|
-
{ id: "delete", label: t("integration.canvas.contextMenu.item.deleteNodes", n), shortcut: "
|
|
58
|
+
{ id: "delete", label: t("integration.canvas.contextMenu.item.deleteNodes", n), shortcut: primaryShortcut("delete"), danger: true }
|
|
77
59
|
]
|
|
78
60
|
];
|
|
79
61
|
}
|
|
80
62
|
return [
|
|
81
63
|
[
|
|
82
|
-
{ id: "add-node", label: t("integration.canvas.contextMenu.item.addNode"), shortcut: "
|
|
83
|
-
{ id: "add-sticky", label: t("integration.canvas.contextMenu.item.addSticky"), shortcut: "
|
|
84
|
-
{ id: "paste", label: t("integration.canvas.contextMenu.item.paste"), shortcut: "
|
|
64
|
+
{ id: "add-node", label: t("integration.canvas.contextMenu.item.addNode"), shortcut: primaryShortcut("addNode") },
|
|
65
|
+
{ id: "add-sticky", label: t("integration.canvas.contextMenu.item.addSticky"), shortcut: primaryShortcut("addSticky") },
|
|
66
|
+
{ id: "paste", label: t("integration.canvas.contextMenu.item.paste"), shortcut: primaryShortcut("paste") }
|
|
85
67
|
],
|
|
86
68
|
[
|
|
87
|
-
{ id: "tidy-up", label: t("integration.canvas.contextMenu.item.tidyUp"), shortcut: "
|
|
88
|
-
{ id: "fit-view", label: t("integration.canvas.contextMenu.item.fitView"), shortcut: "
|
|
69
|
+
{ id: "tidy-up", label: t("integration.canvas.contextMenu.item.tidyUp"), shortcut: primaryShortcut("tidyUp") },
|
|
70
|
+
{ id: "fit-view", label: t("integration.canvas.contextMenu.item.fitView"), shortcut: primaryShortcut("fitView") }
|
|
89
71
|
],
|
|
90
72
|
[
|
|
91
|
-
{ id: "select-all", label: t("integration.canvas.contextMenu.item.selectAll"), shortcut: "
|
|
73
|
+
{ id: "select-all", label: t("integration.canvas.contextMenu.item.selectAll"), shortcut: primaryShortcut("selectAll"), disabled: allSelected.value || props.totalNodes === 0 }
|
|
92
74
|
]
|
|
93
75
|
];
|
|
94
76
|
});
|
|
@@ -17,11 +17,11 @@ type __VLS_Slots = {} & {
|
|
|
17
17
|
default?: (props: typeof __VLS_14) => any;
|
|
18
18
|
};
|
|
19
19
|
declare const __VLS_component: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
20
|
-
action: (id: MenuActionId) => any;
|
|
21
20
|
"update:open": (open: boolean) => any;
|
|
21
|
+
action: (id: MenuActionId) => any;
|
|
22
22
|
}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
23
|
-
onAction?: ((id: MenuActionId) => any) | undefined;
|
|
24
23
|
"onUpdate:open"?: ((open: boolean) => any) | undefined;
|
|
24
|
+
onAction?: ((id: MenuActionId) => any) | undefined;
|
|
25
25
|
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
26
26
|
declare const _default: __VLS_WithSlots<typeof __VLS_component, __VLS_Slots>;
|
|
27
27
|
export default _default;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<script setup>
|
|
2
2
|
import { computed, ref, watch } from "vue";
|
|
3
|
-
import { RefreshCircle as Loader2, Magnifier as Search, MagicStick as Sparkles } from "#solar-icons";
|
|
3
|
+
import { AltArrowLeft as ArrowLeft, RefreshCircle as Loader2, Magnifier as Search, MagicStick as Sparkles } from "#solar-icons";
|
|
4
4
|
import { triggerGlyph } from "../../data/triggerGlyphs";
|
|
5
5
|
import * as Lucide from "lucide-vue-next";
|
|
6
6
|
import {
|
|
@@ -19,10 +19,10 @@ import {
|
|
|
19
19
|
SelectValue,
|
|
20
20
|
Textarea
|
|
21
21
|
} from "@revenexx/studio";
|
|
22
|
-
import { toast } from "vue-sonner";
|
|
23
22
|
import { TRIGGER_TEMPLATES } from "../../data/integrationNodeCatalog";
|
|
24
23
|
import LoadingAnnouncement from "./LoadingAnnouncement.vue";
|
|
25
24
|
import TemplateCard from "./TemplateCard.vue";
|
|
25
|
+
import TemplateInstallStep from "./TemplateInstallStep.vue";
|
|
26
26
|
import WorkflowIconPicker from "./WorkflowIconPicker.vue";
|
|
27
27
|
import WorkflowTagsInput from "./WorkflowTagsInput.vue";
|
|
28
28
|
import { resolveLocalized } from "../../utils/localize";
|
|
@@ -31,7 +31,7 @@ const open = defineModel("open", { type: Boolean, ...{ default: false } });
|
|
|
31
31
|
const t = useIntegrationsT();
|
|
32
32
|
const router = useRouter();
|
|
33
33
|
const { create, workflows } = useIntegrationsWorkflows();
|
|
34
|
-
const { templates, loading: templatesLoading, error: templatesError, load: loadTemplates, ensureDetails
|
|
34
|
+
const { templates, loading: templatesLoading, error: templatesError, load: loadTemplates, ensureDetails } = useIntegrationsTemplates();
|
|
35
35
|
const mode = ref("blank");
|
|
36
36
|
const modeTabs = computed(() => [
|
|
37
37
|
{ key: "blank", label: t("integration.workflows.create.tab.blank") },
|
|
@@ -72,6 +72,7 @@ watch(open, (v) => {
|
|
|
72
72
|
icon.value = null;
|
|
73
73
|
error.value = null;
|
|
74
74
|
templateSearch.value = "";
|
|
75
|
+
pickedSlug.value = null;
|
|
75
76
|
void loadTemplates();
|
|
76
77
|
});
|
|
77
78
|
async function submit() {
|
|
@@ -109,8 +110,14 @@ async function submit() {
|
|
|
109
110
|
submitting.value = false;
|
|
110
111
|
}
|
|
111
112
|
}
|
|
112
|
-
const
|
|
113
|
+
const pickedSlug = ref(null);
|
|
113
114
|
const templateSearch = ref("");
|
|
115
|
+
const stepLoading = ref(false);
|
|
116
|
+
const stepInstalling = ref(false);
|
|
117
|
+
watch(mode, (m) => {
|
|
118
|
+
if (m !== "template") pickedSlug.value = null;
|
|
119
|
+
});
|
|
120
|
+
const pickedTemplate = computed(() => templates.value.find((tpl) => tpl.slug === pickedSlug.value) ?? null);
|
|
114
121
|
watch(() => templates.value.length, (n) => {
|
|
115
122
|
if (n) void ensureDetails(templates.value.map((tpl) => tpl.slug));
|
|
116
123
|
}, { immediate: true });
|
|
@@ -119,19 +126,9 @@ const filteredTemplates = computed(() => {
|
|
|
119
126
|
if (!q) return templates.value;
|
|
120
127
|
return templates.value.filter((tpl) => `${tpl.name} ${tpl.description} ${tpl.category}`.toLowerCase().includes(q));
|
|
121
128
|
});
|
|
122
|
-
async function
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
try {
|
|
126
|
-
const id = await instantiate(slug);
|
|
127
|
-
if (id == null) throw new Error("The template could not be instantiated.");
|
|
128
|
-
open.value = false;
|
|
129
|
-
await router.push(`/integrations/workflows/${id}`);
|
|
130
|
-
} catch (e) {
|
|
131
|
-
toast.error(errorReason(e, t("integration.workflows.create.toast.templateError")));
|
|
132
|
-
} finally {
|
|
133
|
-
instantiatingSlug.value = null;
|
|
134
|
-
}
|
|
129
|
+
async function installed(id) {
|
|
130
|
+
open.value = false;
|
|
131
|
+
await router.push(`/integrations/workflows/${id}`);
|
|
135
132
|
}
|
|
136
133
|
</script>
|
|
137
134
|
|
|
@@ -154,8 +151,8 @@ async function useTemplate(slug) {
|
|
|
154
151
|
there (PO-251). -->
|
|
155
152
|
<LoadingAnnouncement
|
|
156
153
|
:label="t('integration.workflows.create.tab.template')"
|
|
157
|
-
:loading="mode === 'template' && templatesLoading && !templates.length"
|
|
158
|
-
:text="t('integration.workflows.create.template.state.loading')"
|
|
154
|
+
:loading="mode === 'template' && (stepLoading || templatesLoading && !templates.length)"
|
|
155
|
+
:text="stepLoading ? t('integration.templates.detail.install.state.loading') : t('integration.workflows.create.template.state.loading')"
|
|
159
156
|
/>
|
|
160
157
|
|
|
161
158
|
<!-- ── Blank ─────────────────────────────────────────────────────────── -->
|
|
@@ -265,58 +262,90 @@ async function useTemplate(slug) {
|
|
|
265
262
|
|
|
266
263
|
<!-- ── From template ─────────────────────────────────────────────────── -->
|
|
267
264
|
<div v-else class="-m-1 max-h-[65vh] space-y-3 overflow-y-auto p-1">
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
265
|
+
<!-- The install step, once a template is picked: the same one the
|
|
266
|
+
template's own page opens, so both routes create the same workflow. -->
|
|
267
|
+
<template v-if="pickedSlug">
|
|
268
|
+
<div class="flex items-center gap-2">
|
|
269
|
+
<!-- Closed while the install is in flight: the step would unmount
|
|
270
|
+
under it, the request would land anyway, and the editor would
|
|
271
|
+
open on a workflow nobody was told was being created — twice
|
|
272
|
+
over if a second template were picked in that window. -->
|
|
273
|
+
<Button variant="outline" class="h-8 shrink-0 text-sm" :disabled="stepInstalling" @click="pickedSlug = null">
|
|
274
|
+
<ArrowLeft :size="13" />
|
|
275
|
+
{{ t("integration.workflows.create.template.backToPicker") }}
|
|
276
|
+
</Button>
|
|
277
|
+
<span class="truncate text-sm font-medium">{{ pickedTemplate?.name }}</span>
|
|
278
|
+
</div>
|
|
279
|
+
<p class="text-sm text-muted-foreground">
|
|
280
|
+
{{ t("integration.templates.detail.install.description") }}
|
|
281
|
+
</p>
|
|
282
|
+
|
|
283
|
+
<TemplateInstallStep
|
|
284
|
+
:slug="pickedSlug"
|
|
285
|
+
@installed="installed"
|
|
286
|
+
@update:loading="stepLoading = $event"
|
|
287
|
+
@update:installing="stepInstalling = $event"
|
|
276
288
|
>
|
|
277
|
-
|
|
289
|
+
<template #secondary="{ installing }">
|
|
290
|
+
<Button variant="outline" :disabled="installing" @click="open = false">
|
|
291
|
+
{{ t("integration.common.action.cancel") }}
|
|
292
|
+
</Button>
|
|
293
|
+
</template>
|
|
294
|
+
</TemplateInstallStep>
|
|
295
|
+
</template>
|
|
296
|
+
|
|
297
|
+
<template v-else>
|
|
298
|
+
<div class="relative">
|
|
299
|
+
<Search :size="12" class="absolute left-2 top-1/2 -translate-y-1/2 text-muted-foreground" />
|
|
300
|
+
<input
|
|
301
|
+
v-model="templateSearch"
|
|
302
|
+
type="text"
|
|
303
|
+
:aria-label="t('integration.workflows.create.template.search.aria')"
|
|
304
|
+
:placeholder="t('integration.workflows.create.template.search.placeholder')"
|
|
305
|
+
class="h-8 w-full rounded-md border border-black/[0.08] bg-white pl-7 pr-2 text-sm focus:outline-none focus:ring-2 focus:ring-emerald-500/40"
|
|
306
|
+
>
|
|
307
|
+
</div>
|
|
278
308
|
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
309
|
+
<div v-if="templatesLoading && !templates.length" aria-hidden="true" class="grid gap-2 p-1 sm:grid-cols-2">
|
|
310
|
+
<div v-for="n in 6" :key="`sk-tpl-${n}`" class="rounded-lg border border-black/[0.06] bg-white p-3 space-y-2">
|
|
311
|
+
<div class="flex items-center gap-2">
|
|
312
|
+
<div class="size-7 rounded-md bg-black/[0.07] animate-pulse" />
|
|
313
|
+
<div class="h-3 w-1/2 rounded bg-black/[0.07] animate-pulse" />
|
|
314
|
+
</div>
|
|
315
|
+
<div class="h-3 w-full rounded bg-black/[0.05] animate-pulse" />
|
|
316
|
+
<div class="h-3 w-2/3 rounded bg-black/[0.05] animate-pulse" />
|
|
284
317
|
</div>
|
|
285
|
-
<div class="h-3 w-full rounded bg-black/[0.05] animate-pulse" />
|
|
286
|
-
<div class="h-3 w-2/3 rounded bg-black/[0.05] animate-pulse" />
|
|
287
318
|
</div>
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
</p>
|
|
319
|
+
<div v-else-if="templatesError" class="rounded-md border border-rose-500/20 bg-rose-500/5 px-3 py-2 text-sm text-rose-700">
|
|
320
|
+
{{ templatesError }}
|
|
321
|
+
</div>
|
|
322
|
+
<p v-else-if="!templates.length" class="p-6 text-center text-sm text-muted-foreground">
|
|
323
|
+
{{ t("integration.workflows.create.template.empty") }}
|
|
324
|
+
</p>
|
|
325
|
+
<p v-else-if="!filteredTemplates.length" class="p-6 text-center text-sm text-muted-foreground">
|
|
326
|
+
{{ t("integration.workflows.create.template.noMatch", { query: templateSearch }) }}
|
|
327
|
+
</p>
|
|
298
328
|
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
/>
|
|
309
|
-
</div>
|
|
329
|
+
<div v-else class="grid gap-2.5 sm:grid-cols-2 lg:grid-cols-3">
|
|
330
|
+
<TemplateCard
|
|
331
|
+
v-for="tpl in filteredTemplates"
|
|
332
|
+
:key="tpl.slug"
|
|
333
|
+
:template="tpl"
|
|
334
|
+
density="compact"
|
|
335
|
+
@select="pickedSlug = tpl.slug"
|
|
336
|
+
/>
|
|
337
|
+
</div>
|
|
310
338
|
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
339
|
+
<div class="flex items-center justify-between pt-1">
|
|
340
|
+
<NuxtLink to="/integrations/templates" class="inline-flex items-center gap-1 text-sm text-muted-foreground transition-colors hover:text-primary" @click="open = false">
|
|
341
|
+
<Sparkles :size="13" />
|
|
342
|
+
{{ t("integration.workflows.create.template.browseAll") }}
|
|
343
|
+
</NuxtLink>
|
|
344
|
+
<Button type="button" variant="outline" class="h-8 text-sm" @click="open = false">
|
|
345
|
+
{{ t("integration.common.action.cancel") }}
|
|
346
|
+
</Button>
|
|
347
|
+
</div>
|
|
348
|
+
</template>
|
|
320
349
|
</div>
|
|
321
350
|
</DialogContent>
|
|
322
351
|
</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;
|