@revenexx/studio-integrations 0.5.1 → 0.6.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 +201 -0
- package/README.md +17 -4
- package/dist/module.json +1 -1
- package/dist/runtime/components/Integrations/CredentialCreateDialog.vue +15 -14
- package/dist/runtime/components/Integrations/CredentialDetailDialog.vue +91 -19
- package/dist/runtime/components/Integrations/CredentialRevenexxSource.vue +58 -21
- package/dist/runtime/components/Integrations/CredentialTypePicker.vue +4 -8
- package/dist/runtime/components/Integrations/EventTypeCombobox.d.vue.ts +1 -0
- package/dist/runtime/components/Integrations/EventTypeCombobox.vue +4 -2
- package/dist/runtime/components/Integrations/EventTypeCombobox.vue.d.ts +1 -0
- package/dist/runtime/components/Integrations/ExpressionInput.d.vue.ts +4 -0
- package/dist/runtime/components/Integrations/ExpressionInput.vue +54 -25
- package/dist/runtime/components/Integrations/ExpressionInput.vue.d.ts +4 -0
- package/dist/runtime/components/Integrations/GroupFrameView.vue +12 -12
- package/dist/runtime/components/Integrations/Layout.vue +21 -2
- package/dist/runtime/components/Integrations/NodeConfigDynamicField.vue +10 -11
- package/dist/runtime/components/Integrations/NodeConfigDynamicSchema.vue +2 -5
- package/dist/runtime/components/Integrations/NodeConfigField.d.vue.ts +2 -0
- package/dist/runtime/components/Integrations/NodeConfigField.vue +160 -67
- package/dist/runtime/components/Integrations/NodeConfigField.vue.d.ts +2 -0
- package/dist/runtime/components/Integrations/NodeInspector.d.vue.ts +6 -0
- package/dist/runtime/components/Integrations/NodeInspector.vue +1075 -303
- package/dist/runtime/components/Integrations/NodeInspector.vue.d.ts +6 -0
- package/dist/runtime/components/Integrations/NodeLogo.d.vue.ts +12 -0
- package/dist/runtime/components/Integrations/NodeLogo.vue +2 -30
- package/dist/runtime/components/Integrations/NodeLogo.vue.d.ts +12 -0
- package/dist/runtime/components/Integrations/NodeMark.d.vue.ts +15 -0
- package/dist/runtime/components/Integrations/NodeMark.vue +79 -0
- package/dist/runtime/components/Integrations/NodeMark.vue.d.ts +15 -0
- package/dist/runtime/components/Integrations/NodeOutputSchema.d.vue.ts +21 -0
- package/dist/runtime/components/Integrations/NodeOutputSchema.vue +42 -0
- package/dist/runtime/components/Integrations/NodeOutputSchema.vue.d.ts +21 -0
- package/dist/runtime/components/Integrations/NodePalette.vue +100 -34
- package/dist/runtime/components/Integrations/QueryBuilder.vue +8 -1
- package/dist/runtime/components/Integrations/RunActionsMenu.vue +3 -1
- package/dist/runtime/components/Integrations/RunPayloadInput.vue +17 -4
- package/dist/runtime/components/Integrations/StickyNoteView.vue +2 -1
- package/dist/runtime/components/Integrations/TemplateCard.d.vue.ts +18 -0
- package/dist/runtime/components/Integrations/TemplateCard.vue +109 -0
- package/dist/runtime/components/Integrations/TemplateCard.vue.d.ts +18 -0
- package/dist/runtime/components/Integrations/TemplateFlowPreview.d.vue.ts +2 -2
- package/dist/runtime/components/Integrations/TemplateFlowPreview.vue +7 -10
- package/dist/runtime/components/Integrations/TemplateFlowPreview.vue.d.ts +2 -2
- package/dist/runtime/components/Integrations/WorkflowCreateDialog.vue +21 -37
- package/dist/runtime/components/Integrations/WorkflowEdgeView.d.vue.ts +18 -4
- package/dist/runtime/components/Integrations/WorkflowEdgeView.vue +23 -7
- package/dist/runtime/components/Integrations/WorkflowEdgeView.vue.d.ts +18 -4
- package/dist/runtime/components/Integrations/WorkflowEditor.d.vue.ts +20 -1
- package/dist/runtime/components/Integrations/WorkflowEditor.vue +167 -46
- package/dist/runtime/components/Integrations/WorkflowEditor.vue.d.ts +20 -1
- package/dist/runtime/components/Integrations/WorkflowHistoryPanel.vue +4 -20
- package/dist/runtime/components/Integrations/WorkflowIconPicker.d.vue.ts +19 -1
- package/dist/runtime/components/Integrations/WorkflowIconPicker.vue +11 -2
- package/dist/runtime/components/Integrations/WorkflowIconPicker.vue.d.ts +19 -1
- package/dist/runtime/components/Integrations/WorkflowNodeView.d.vue.ts +4 -0
- package/dist/runtime/components/Integrations/WorkflowNodeView.vue +189 -46
- package/dist/runtime/components/Integrations/WorkflowNodeView.vue.d.ts +4 -0
- package/dist/runtime/components/Integrations/WorkflowRunReplayPanel.vue +4 -20
- package/dist/runtime/components/Integrations/WorkflowSettingsDialog.vue +15 -9
- package/dist/runtime/components/Integrations/WorkflowTagsInput.d.vue.ts +1 -0
- package/dist/runtime/components/Integrations/WorkflowTagsInput.vue +7 -2
- package/dist/runtime/components/Integrations/WorkflowTagsInput.vue.d.ts +1 -0
- package/dist/runtime/components/Integrations/WorkflowTriggerView.vue +4 -2
- package/dist/runtime/components/Integrations/WorkflowVariablesDialog.vue +30 -17
- package/dist/runtime/components/Integrations/WorkflowsTable.vue +47 -7
- package/dist/runtime/composables/useCredentialTypes.js +4 -4
- package/dist/runtime/composables/useIntegrationsAudit.js +4 -3
- package/dist/runtime/composables/useIntegrationsCredentials.js +4 -4
- package/dist/runtime/composables/useIntegrationsDeadLetters.js +7 -6
- package/dist/runtime/composables/useIntegrationsNodes.js +4 -4
- package/dist/runtime/composables/useIntegrationsRuns.js +11 -6
- package/dist/runtime/composables/useIntegrationsSchedules.d.ts +4 -0
- package/dist/runtime/composables/useIntegrationsSchedules.js +10 -3
- package/dist/runtime/composables/useIntegrationsSecrets.js +10 -7
- package/dist/runtime/composables/useIntegrationsTemplates.d.ts +1 -1
- package/dist/runtime/composables/useIntegrationsTemplates.js +12 -8
- package/dist/runtime/composables/useIntegrationsTriggers.js +6 -6
- package/dist/runtime/composables/useIntegrationsWorkflows.js +8 -4
- package/dist/runtime/composables/useLoadGate.d.ts +17 -0
- package/dist/runtime/composables/useLoadGate.js +8 -0
- package/dist/runtime/data/branchReorder.d.ts +37 -0
- package/dist/runtime/data/branchReorder.js +71 -0
- package/dist/runtime/data/handleId.d.ts +23 -0
- package/dist/runtime/data/handleId.js +6 -0
- package/dist/runtime/data/integrationTemplates.d.ts +39 -0
- package/dist/runtime/data/integrationTemplates.js +15 -0
- package/dist/runtime/data/integrationWorkflowSamples.js +1 -1
- package/dist/runtime/data/nodeIcons.d.ts +2 -0
- package/dist/runtime/data/nodeIcons.js +73 -0
- package/dist/runtime/data/nodeInputData.d.ts +16 -4
- package/dist/runtime/data/nodeInputData.js +4 -0
- package/dist/runtime/data/payloadForm.d.ts +9 -2
- package/dist/runtime/data/payloadForm.js +27 -3
- package/dist/runtime/data/portTone.d.ts +17 -0
- package/dist/runtime/data/portTone.js +7 -0
- package/dist/runtime/data/webhookAuth.d.ts +18 -0
- package/dist/runtime/data/webhookAuth.js +19 -0
- package/dist/runtime/data/workflowIconCatalog.js +2 -5
- package/dist/runtime/pages/integrations/audit.vue +91 -6
- package/dist/runtime/pages/integrations/credentials/oauth-complete.vue +6 -4
- package/dist/runtime/pages/integrations/credentials.vue +119 -21
- package/dist/runtime/pages/integrations/index.vue +49 -44
- package/dist/runtime/pages/integrations/runs.vue +1 -1
- package/dist/runtime/pages/integrations/schedules.vue +51 -7
- package/dist/runtime/pages/integrations/secrets.vue +29 -7
- package/dist/runtime/pages/integrations/templates/[slug].vue +52 -30
- package/dist/runtime/pages/integrations/templates/index.vue +57 -86
- package/dist/runtime/pages/integrations/workflows/[id].vue +196 -8
- package/dist/runtime/pages/integrations/workflows/index.vue +15 -2
- package/dist/runtime/types/integrations.d.ts +65 -6
- package/dist/runtime/utils/apiError.d.ts +47 -0
- package/dist/runtime/utils/apiError.js +32 -0
- package/dist/runtime/utils/cockpitSources.d.ts +153 -0
- package/dist/runtime/utils/cockpitSources.js +14 -0
- package/dist/runtime/utils/loadGate.d.ts +61 -0
- package/dist/runtime/utils/loadGate.js +22 -0
- package/dist/runtime/utils/localize.d.ts +29 -0
- package/dist/runtime/utils/localize.js +4 -0
- package/dist/runtime/utils/notify.d.ts +59 -0
- package/dist/runtime/utils/notify.js +21 -0
- package/dist/runtime/utils/revenexxCredentialSource.d.ts +26 -0
- package/dist/runtime/utils/revenexxCredentialSource.js +8 -0
- package/dist/runtime/utils/schedule.d.ts +141 -0
- package/dist/runtime/utils/schedule.js +207 -0
- package/dist/runtime/utils/validationFindings.d.ts +101 -0
- package/dist/runtime/utils/validationFindings.js +53 -0
- package/dist/runtime/utils/whenIdle.d.ts +42 -0
- package/dist/runtime/utils/whenIdle.js +12 -0
- package/package.json +8 -2
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<script setup>
|
|
2
|
-
import { computed, ref, watch } from "vue";
|
|
2
|
+
import { computed, ref, useId, watch } from "vue";
|
|
3
3
|
import { Paperclip, TrashBinMinimalistic as Trash2 } from "#solar-icons";
|
|
4
4
|
import { Input, Switch, Textarea } from "@revenexx/studio";
|
|
5
5
|
import { buildPayload, payloadFieldsFromBlob, splitPayload } from "../../data/payloadForm";
|
|
@@ -8,6 +8,8 @@ const props = defineProps({
|
|
|
8
8
|
});
|
|
9
9
|
const model = defineModel({ type: String, ...{ default: "{}" } });
|
|
10
10
|
const fields = computed(() => payloadFieldsFromBlob(props.blob));
|
|
11
|
+
const uid = useId();
|
|
12
|
+
const fieldId = (path) => `${uid}-${path}`;
|
|
11
13
|
const textValues = ref({});
|
|
12
14
|
const files = ref({});
|
|
13
15
|
const extras = ref({});
|
|
@@ -96,17 +98,24 @@ function prettyBytes(n) {
|
|
|
96
98
|
<span class="text-xs font-medium text-muted-foreground">
|
|
97
99
|
{{ expert ? "Trigger payload (JSON)" : "Trigger payload" }}
|
|
98
100
|
</span>
|
|
101
|
+
<!-- The Switch is a `button role="switch"`, and HTML-AAM does not name a
|
|
102
|
+
button from a wrapping <label> — Chromium does, other engines need
|
|
103
|
+
not. The explicit name is what the promise rests on. -->
|
|
99
104
|
<label class="flex items-center gap-1.5 text-xs text-muted-foreground">
|
|
100
|
-
<Switch :model-value="expert" @update:model-value="toggleExpert" />
|
|
105
|
+
<Switch aria-label="Expert (JSON)" :model-value="expert" @update:model-value="toggleExpert" />
|
|
101
106
|
Expert (JSON)
|
|
102
107
|
</label>
|
|
103
108
|
</div>
|
|
104
|
-
<
|
|
109
|
+
<span v-else class="text-xs font-medium text-muted-foreground">Trigger payload (JSON)</span>
|
|
105
110
|
|
|
106
111
|
<!-- ── Form mode: fields derived from the blob's payload references ──── -->
|
|
107
112
|
<div v-if="!expert && fields.length" class="space-y-3">
|
|
108
113
|
<div v-for="field in fields" :key="`${field.kind}:${field.path}`" class="space-y-1">
|
|
109
|
-
|
|
114
|
+
<!-- A file field has no control to point at once a file is attached —
|
|
115
|
+
the drop zone is replaced by the file's own row — so there the
|
|
116
|
+
caption stays a caption and the controls name themselves. -->
|
|
117
|
+
<label v-if="field.kind === 'file'" class="text-xs font-medium">{{ field.label }}</label>
|
|
118
|
+
<label v-else :for="fieldId(field.path)" class="text-xs font-medium">{{ field.label }}</label>
|
|
110
119
|
|
|
111
120
|
<template v-if="field.kind === 'file'">
|
|
112
121
|
<div
|
|
@@ -121,6 +130,7 @@ function prettyBytes(n) {
|
|
|
121
130
|
Drop a file here or click to choose
|
|
122
131
|
<input
|
|
123
132
|
type="file"
|
|
133
|
+
:aria-label="field.label"
|
|
124
134
|
class="absolute inset-0 cursor-pointer opacity-0"
|
|
125
135
|
@change="onPick(field.path, $event)"
|
|
126
136
|
>
|
|
@@ -133,6 +143,7 @@ function prettyBytes(n) {
|
|
|
133
143
|
type="button"
|
|
134
144
|
class="flex size-6 shrink-0 items-center justify-center rounded text-muted-foreground transition hover:bg-muted/60 hover:text-rose-600"
|
|
135
145
|
title="Remove file"
|
|
146
|
+
:aria-label="`Remove the file for ${field.label}`"
|
|
136
147
|
@click="detach(field.path)"
|
|
137
148
|
>
|
|
138
149
|
<Trash2 :size="13" />
|
|
@@ -145,6 +156,7 @@ function prettyBytes(n) {
|
|
|
145
156
|
|
|
146
157
|
<template v-else>
|
|
147
158
|
<Input
|
|
159
|
+
:id="fieldId(field.path)"
|
|
148
160
|
:model-value="textValues[field.path] ?? ''"
|
|
149
161
|
class="h-8 text-sm"
|
|
150
162
|
:placeholder="`\${{ trigger.payload.${field.path} }}`"
|
|
@@ -163,6 +175,7 @@ function prettyBytes(n) {
|
|
|
163
175
|
<template v-else>
|
|
164
176
|
<Textarea
|
|
165
177
|
v-model="model"
|
|
178
|
+
aria-label="Trigger payload (JSON)"
|
|
166
179
|
:rows="8"
|
|
167
180
|
spellcheck="false"
|
|
168
181
|
class="font-mono text-xs"
|
|
@@ -181,7 +181,8 @@ function onViewMouseDown(e) {
|
|
|
181
181
|
v-else
|
|
182
182
|
ref="textareaEl"
|
|
183
183
|
v-model="draft"
|
|
184
|
-
|
|
184
|
+
aria-label="Note text"
|
|
185
|
+
class="nodrag nowheel h-full w-full resize-none bg-transparent px-3 py-2 text-sm leading-snug text-stone-700 outline-none placeholder:text-stone-400 focus:ring-2 focus:ring-inset focus:ring-stone-500/40"
|
|
185
186
|
placeholder="Write a note… (# heading, **bold**, *italic*, `code`, [link](https://…), - list)"
|
|
186
187
|
spellcheck="false"
|
|
187
188
|
@blur="commitEdit"
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { WorkflowTemplate } from '../../types/integrations.js';
|
|
2
|
+
type __VLS_Props = {
|
|
3
|
+
template: WorkflowTemplate;
|
|
4
|
+
/** How much room the surface has. See the comment above; no default on purpose. */
|
|
5
|
+
density: 'full' | 'compact';
|
|
6
|
+
/** Given → the card is a link there. Omitted → a button that emits `select`. */
|
|
7
|
+
to?: string;
|
|
8
|
+
/** This card is the one being acted on: it says so and cannot be pressed again. */
|
|
9
|
+
busy?: boolean;
|
|
10
|
+
/** Another card on the surface is being acted on, so this one is out of reach. */
|
|
11
|
+
disabled?: boolean;
|
|
12
|
+
};
|
|
13
|
+
declare const _default: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
14
|
+
select: () => any;
|
|
15
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
16
|
+
onSelect?: (() => any) | undefined;
|
|
17
|
+
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
18
|
+
export default _default;
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import { computed, resolveComponent } from "vue";
|
|
3
|
+
import { RefreshCircle as Loader2, ClockCircle as Clock, Global as Webhook, Play, Bolt as Zap } from "#solar-icons";
|
|
4
|
+
import { templateCategoryLabel, templatePackageLabel } from "../../data/integrationTemplates";
|
|
5
|
+
import TemplateFlowPreview from "./TemplateFlowPreview.vue";
|
|
6
|
+
const props = defineProps({
|
|
7
|
+
template: { type: Object, required: true },
|
|
8
|
+
density: { type: String, required: true },
|
|
9
|
+
to: { type: String, required: false },
|
|
10
|
+
busy: { type: Boolean, required: false },
|
|
11
|
+
disabled: { type: Boolean, required: false }
|
|
12
|
+
});
|
|
13
|
+
const emit = defineEmits(["select"]);
|
|
14
|
+
const NuxtLink = resolveComponent("NuxtLink");
|
|
15
|
+
const full = computed(() => props.density === "full");
|
|
16
|
+
const banner = computed(
|
|
17
|
+
() => full.value ? props.template.images.find((i) => i.category === "banner")?.src ?? null : null
|
|
18
|
+
);
|
|
19
|
+
const TRIGGER_ICON = { schedule: Clock, webhook: Webhook, manual: Play, event: Zap };
|
|
20
|
+
const TRIGGER_LABEL = { schedule: "Scheduled", webhook: "Webhook", manual: "Run on demand", event: "Event-driven" };
|
|
21
|
+
function levelDot(level) {
|
|
22
|
+
return level === "beginner" ? "bg-emerald-500" : level === "intermediate" ? "bg-amber-500" : "bg-rose-500";
|
|
23
|
+
}
|
|
24
|
+
const packageLabel = computed(() => templatePackageLabel(props.template));
|
|
25
|
+
const categoryLabel = computed(() => templateCategoryLabel(props.template.category));
|
|
26
|
+
const CHIP = "inline-flex items-center whitespace-nowrap rounded-full uppercase font-medium";
|
|
27
|
+
const chipSize = computed(() => full.value ? "px-2 py-0.5 text-xs" : "px-1.5 py-px text-[11px]");
|
|
28
|
+
</script>
|
|
29
|
+
|
|
30
|
+
<template>
|
|
31
|
+
<component
|
|
32
|
+
:is="to ? NuxtLink : 'button'"
|
|
33
|
+
v-bind="to ? { to } : { type: 'button', disabled: disabled || busy }"
|
|
34
|
+
class="flex flex-col overflow-hidden rounded-lg border border-black/[0.06] bg-white text-left transition hover:border-black/20 hover:shadow-sm disabled:opacity-60"
|
|
35
|
+
@click="to ? void 0 : emit('select')"
|
|
36
|
+
>
|
|
37
|
+
<!-- The picture: the flow this template builds, drawn from its own
|
|
38
|
+
definition, or the publisher's banner where one ships. -->
|
|
39
|
+
<div
|
|
40
|
+
class="relative shrink-0 border-b border-black/[0.06] bg-slate-50/70 [background-image:radial-gradient(circle,rgba(15,23,42,0.07)_1px,transparent_1px)]"
|
|
41
|
+
:class="full ? 'h-36 [background-size:14px_14px]' : 'h-24 [background-size:12px_12px]'"
|
|
42
|
+
>
|
|
43
|
+
<img v-if="banner" :src="banner" alt="" class="h-full w-full object-cover">
|
|
44
|
+
<!-- `full` keeps its chips on the picture, so the drawing starts below
|
|
45
|
+
them: the graph is fitted to whichever axis binds, and a flow slightly
|
|
46
|
+
taller in proportion than this box reaches the top edge — where the
|
|
47
|
+
chip is. The 28px are the chip's own 20 plus its 8 of inset, so the
|
|
48
|
+
two can no longer meet (PO-243).
|
|
49
|
+
|
|
50
|
+
No horizontal padding, deliberately: all three surfaces used to pass
|
|
51
|
+
one (`px-2` in the gallery, `px-1` in the compact places) and none of
|
|
52
|
+
them insetted anything. The preview's `svg` is `absolute inset-0`, so
|
|
53
|
+
it is laid out against its parent's *padding box* and fills it whatever
|
|
54
|
+
the padding is — measured identical to the picture, 421.3px wide either
|
|
55
|
+
way. The graph's own inset is `TemplateFlowPreview`'s `padding` prop,
|
|
56
|
+
36 logical units, which is where it belongs. -->
|
|
57
|
+
<TemplateFlowPreview
|
|
58
|
+
v-else-if="template.detailLoaded"
|
|
59
|
+
:blob="template.blob"
|
|
60
|
+
:height="full ? 116 : 96"
|
|
61
|
+
:class="full ? 'mt-7' : ''"
|
|
62
|
+
/>
|
|
63
|
+
<!-- Named, because "still on its way" and "this template draws nothing"
|
|
64
|
+
are the same sight otherwise — and a spinner nobody can address is a
|
|
65
|
+
promise no test can hold to. -->
|
|
66
|
+
<div
|
|
67
|
+
v-else
|
|
68
|
+
role="status"
|
|
69
|
+
aria-label="Loading the flow"
|
|
70
|
+
class="flex h-full items-center justify-center"
|
|
71
|
+
>
|
|
72
|
+
<Loader2 :size="full ? 16 : 14" class="animate-spin text-muted-foreground/50" />
|
|
73
|
+
</div>
|
|
74
|
+
|
|
75
|
+
<div v-if="full" class="absolute left-2 top-2 flex items-center gap-1.5">
|
|
76
|
+
<span v-if="categoryLabel" :class="[CHIP, chipSize, 'bg-slate-100 text-slate-700']">{{ categoryLabel }}</span>
|
|
77
|
+
<span v-if="packageLabel" :class="[CHIP, chipSize, 'bg-violet-100 text-violet-700']">{{ packageLabel }}</span>
|
|
78
|
+
</div>
|
|
79
|
+
|
|
80
|
+
<Loader2 v-if="busy" :size="13" class="absolute right-1.5 top-1.5 animate-spin text-muted-foreground" />
|
|
81
|
+
</div>
|
|
82
|
+
|
|
83
|
+
<div class="flex min-h-0 flex-1 flex-col" :class="full ? 'p-4' : 'p-3'">
|
|
84
|
+
<div class="flex items-center gap-2">
|
|
85
|
+
<div class="min-w-0 flex-1 truncate text-sm font-semibold text-foreground">{{ template.name }}</div>
|
|
86
|
+
<!-- Compact has no room on the picture, so the category rides the name. -->
|
|
87
|
+
<span v-if="!full && categoryLabel" :class="[CHIP, chipSize, 'bg-slate-100 text-slate-700']">{{ categoryLabel }}</span>
|
|
88
|
+
</div>
|
|
89
|
+
<p class="mt-1 flex-1 text-sm text-muted-foreground line-clamp-2">{{ template.description }}</p>
|
|
90
|
+
|
|
91
|
+
<div v-if="full" class="mt-3 flex items-center gap-2 text-xs text-muted-foreground">
|
|
92
|
+
<span
|
|
93
|
+
v-for="t in template.triggerTypes"
|
|
94
|
+
:key="t"
|
|
95
|
+
class="inline-flex items-center gap-1 whitespace-nowrap rounded-full bg-slate-100 px-2 py-0.5 uppercase"
|
|
96
|
+
>
|
|
97
|
+
<component :is="TRIGGER_ICON[t] ?? Zap" :size="10" />
|
|
98
|
+
{{ TRIGGER_LABEL[t] ?? t }}
|
|
99
|
+
</span>
|
|
100
|
+
<span class="flex-1" />
|
|
101
|
+
<span class="inline-flex items-center gap-1 whitespace-nowrap rounded-full bg-slate-100 px-2 py-0.5 uppercase">
|
|
102
|
+
<span class="size-1.5 rounded-full" :class="levelDot(template.level)" />
|
|
103
|
+
{{ template.level }}
|
|
104
|
+
</span>
|
|
105
|
+
<span v-if="template.publisher.kind !== 'revenexx'" class="inline-flex items-center rounded-full bg-slate-100 px-2 py-0.5 uppercase">{{ template.publisher.name }}</span>
|
|
106
|
+
</div>
|
|
107
|
+
</div>
|
|
108
|
+
</component>
|
|
109
|
+
</template>
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { WorkflowTemplate } from '../../types/integrations.js';
|
|
2
|
+
type __VLS_Props = {
|
|
3
|
+
template: WorkflowTemplate;
|
|
4
|
+
/** How much room the surface has. See the comment above; no default on purpose. */
|
|
5
|
+
density: 'full' | 'compact';
|
|
6
|
+
/** Given → the card is a link there. Omitted → a button that emits `select`. */
|
|
7
|
+
to?: string;
|
|
8
|
+
/** This card is the one being acted on: it says so and cannot be pressed again. */
|
|
9
|
+
busy?: boolean;
|
|
10
|
+
/** Another card on the surface is being acted on, so this one is out of reach. */
|
|
11
|
+
disabled?: boolean;
|
|
12
|
+
};
|
|
13
|
+
declare const _default: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
14
|
+
select: () => any;
|
|
15
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
16
|
+
onSelect?: (() => any) | undefined;
|
|
17
|
+
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
18
|
+
export default _default;
|
|
@@ -11,9 +11,9 @@ type __VLS_Props = {
|
|
|
11
11
|
*/
|
|
12
12
|
showErrorBranches?: boolean;
|
|
13
13
|
};
|
|
14
|
-
declare var
|
|
14
|
+
declare var __VLS_8: {};
|
|
15
15
|
type __VLS_Slots = {} & {
|
|
16
|
-
empty?: (props: typeof
|
|
16
|
+
empty?: (props: typeof __VLS_8) => any;
|
|
17
17
|
};
|
|
18
18
|
declare const __VLS_component: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
|
|
19
19
|
height: number;
|
|
@@ -3,7 +3,8 @@ import { computed } from "vue";
|
|
|
3
3
|
import * as Lucide from "lucide-vue-next";
|
|
4
4
|
import { findManifest, NODE_CATEGORIES, TRIGGER_TEMPLATES } from "../../data/integrationNodeCatalog";
|
|
5
5
|
import { resolveLocalized } from "../../utils/localize";
|
|
6
|
-
import
|
|
6
|
+
import { describeCron } from "../../utils/schedule";
|
|
7
|
+
import IntegrationsNodeMark from "./NodeMark.vue";
|
|
7
8
|
const props = defineProps({
|
|
8
9
|
blob: { type: [Object, null], required: true },
|
|
9
10
|
height: { type: Number, required: false, default: 144 },
|
|
@@ -23,7 +24,7 @@ const boxes = computed(() => {
|
|
|
23
24
|
triggers.forEach((t, i) => {
|
|
24
25
|
const pos = blob.triggerPositions?.[t.id] ?? { x: 40, y: 40 + i * 160 };
|
|
25
26
|
const template = TRIGGER_TEMPLATES.find((tt) => tt.type === t.type);
|
|
26
|
-
const subtitle = t.type === "schedule" && t.config?.cron ? String(t.config.cron) : t.type === "webhook" && t.config?.path ? String(t.config.path) : resolveLocalized(template?.description ?? "");
|
|
27
|
+
const subtitle = t.type === "schedule" && t.config?.cron ? describeCron(String(t.config.cron)) ?? String(t.config.cron) : t.type === "webhook" && t.config?.path ? String(t.config.path) : resolveLocalized(template?.description ?? "");
|
|
27
28
|
out.push({
|
|
28
29
|
key: `t-${t.id}`,
|
|
29
30
|
kind: "trigger",
|
|
@@ -59,9 +60,6 @@ const boxes = computed(() => {
|
|
|
59
60
|
});
|
|
60
61
|
return out;
|
|
61
62
|
});
|
|
62
|
-
function hasLogo(m) {
|
|
63
|
-
return (m?.images ?? []).some((i) => i.category === "logo");
|
|
64
|
-
}
|
|
65
63
|
function prettify(slug) {
|
|
66
64
|
const tail = slug.includes(":") ? slug.split(":").pop() : slug;
|
|
67
65
|
return tail.split("-").map((s) => s.charAt(0).toUpperCase() + s.slice(1)).join(" ");
|
|
@@ -100,8 +98,8 @@ const edgePaths = computed(() => {
|
|
|
100
98
|
});
|
|
101
99
|
const EDGE_STROKE = {
|
|
102
100
|
default: "#94a3b8",
|
|
103
|
-
trigger: "#
|
|
104
|
-
error: "#
|
|
101
|
+
trigger: "#94a3b8",
|
|
102
|
+
error: "#cbd5e1"
|
|
105
103
|
};
|
|
106
104
|
const bounds = computed(() => {
|
|
107
105
|
if (!boxes.value.length) return { x: 0, y: 0, w: 1, h: 1 };
|
|
@@ -182,10 +180,9 @@ const bounds = computed(() => {
|
|
|
182
180
|
>
|
|
183
181
|
<span
|
|
184
182
|
class="flex size-8 shrink-0 items-center justify-center rounded-md"
|
|
185
|
-
:class="
|
|
183
|
+
:class="b.categoryColor"
|
|
186
184
|
>
|
|
187
|
-
<
|
|
188
|
-
<component :is="b.icon" v-else :size="15" :stroke-width="2.25" />
|
|
185
|
+
<IntegrationsNodeMark :manifest="b.manifest" :size="18" />
|
|
189
186
|
</span>
|
|
190
187
|
<div class="min-w-0 flex-1">
|
|
191
188
|
<div class="truncate text-sm font-semibold leading-tight text-foreground">{{ b.label }}</div>
|
|
@@ -11,9 +11,9 @@ type __VLS_Props = {
|
|
|
11
11
|
*/
|
|
12
12
|
showErrorBranches?: boolean;
|
|
13
13
|
};
|
|
14
|
-
declare var
|
|
14
|
+
declare var __VLS_8: {};
|
|
15
15
|
type __VLS_Slots = {} & {
|
|
16
|
-
empty?: (props: typeof
|
|
16
|
+
empty?: (props: typeof __VLS_8) => any;
|
|
17
17
|
};
|
|
18
18
|
declare const __VLS_component: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
|
|
19
19
|
height: number;
|
|
@@ -20,9 +20,10 @@ import {
|
|
|
20
20
|
} from "@revenexx/studio";
|
|
21
21
|
import { toast } from "vue-sonner";
|
|
22
22
|
import { TRIGGER_TEMPLATES } from "../../data/integrationNodeCatalog";
|
|
23
|
-
import
|
|
23
|
+
import TemplateCard from "./TemplateCard.vue";
|
|
24
24
|
import WorkflowIconPicker from "./WorkflowIconPicker.vue";
|
|
25
25
|
import WorkflowTagsInput from "./WorkflowTagsInput.vue";
|
|
26
|
+
import { resolveLocalized } from "../../utils/localize";
|
|
26
27
|
const open = defineModel("open", { type: Boolean, ...{ default: false } });
|
|
27
28
|
const router = useRouter();
|
|
28
29
|
const { create, workflows } = useIntegrationsWorkflows();
|
|
@@ -32,10 +33,6 @@ const modeTabs = [
|
|
|
32
33
|
{ key: "blank", label: "Start blank" },
|
|
33
34
|
{ key: "template", label: "Start from template" }
|
|
34
35
|
];
|
|
35
|
-
function loc(v) {
|
|
36
|
-
if (!v) return "";
|
|
37
|
-
return typeof v === "string" ? v : v.en ?? Object.values(v)[0] ?? "";
|
|
38
|
-
}
|
|
39
36
|
function iconFor(name2) {
|
|
40
37
|
if (!name2) return Lucide.Box;
|
|
41
38
|
return Lucide[name2] || Lucide.Box;
|
|
@@ -165,26 +162,26 @@ async function useTemplate(slug) {
|
|
|
165
162
|
</div>
|
|
166
163
|
|
|
167
164
|
<div class="grid grid-cols-[130px_1fr] items-center gap-x-4">
|
|
168
|
-
<Label>Tags</Label>
|
|
169
|
-
<WorkflowTagsInput v-model="tags" :suggestions="tagSuggestions" />
|
|
165
|
+
<Label for="wf-tags">Tags</Label>
|
|
166
|
+
<WorkflowTagsInput v-model="tags" input-id="wf-tags" :suggestions="tagSuggestions" />
|
|
170
167
|
</div>
|
|
171
168
|
|
|
172
169
|
<div class="grid grid-cols-[130px_1fr] items-center gap-x-4">
|
|
173
|
-
<Label>Icon</Label>
|
|
174
|
-
<WorkflowIconPicker v-model="icon" />
|
|
170
|
+
<Label id="wf-icon-label">Icon</Label>
|
|
171
|
+
<WorkflowIconPicker v-model="icon" trigger-labelledby="wf-icon-label" />
|
|
175
172
|
</div>
|
|
176
173
|
|
|
177
174
|
<div class="grid grid-cols-[130px_1fr] items-center gap-x-4">
|
|
178
|
-
<Label>Trigger</Label>
|
|
175
|
+
<Label for="wf-trigger">Trigger</Label>
|
|
179
176
|
<Select v-model="triggerType">
|
|
180
|
-
<SelectTrigger class="w-full bg-white">
|
|
177
|
+
<SelectTrigger id="wf-trigger" class="w-full bg-white">
|
|
181
178
|
<SelectValue>
|
|
182
179
|
<span class="flex min-w-0 items-center gap-2">
|
|
183
180
|
<span class="flex size-6 shrink-0 items-center justify-center rounded-md bg-emerald-100 text-emerald-600">
|
|
184
181
|
<component :is="iconFor(selectedTrigger?.icon)" :size="13" />
|
|
185
182
|
</span>
|
|
186
|
-
<span class="shrink-0 text-sm font-medium">{{
|
|
187
|
-
<span class="truncate text-sm text-muted-foreground">{{
|
|
183
|
+
<span class="shrink-0 text-sm font-medium">{{ resolveLocalized(selectedTrigger?.name) }}</span>
|
|
184
|
+
<span class="truncate text-sm text-muted-foreground">{{ resolveLocalized(selectedTrigger?.description) }}</span>
|
|
188
185
|
</span>
|
|
189
186
|
</SelectValue>
|
|
190
187
|
</SelectTrigger>
|
|
@@ -195,8 +192,8 @@ async function useTemplate(slug) {
|
|
|
195
192
|
<component :is="iconFor(t.icon)" :size="14" />
|
|
196
193
|
</span>
|
|
197
194
|
<span class="min-w-0">
|
|
198
|
-
<span class="block text-sm font-medium">{{
|
|
199
|
-
<span class="block text-sm text-muted-foreground">{{
|
|
195
|
+
<span class="block text-sm font-medium">{{ resolveLocalized(t.name) }}</span>
|
|
196
|
+
<span class="block text-sm text-muted-foreground">{{ resolveLocalized(t.description) }}</span>
|
|
200
197
|
</span>
|
|
201
198
|
</span>
|
|
202
199
|
</SelectItem>
|
|
@@ -205,9 +202,9 @@ async function useTemplate(slug) {
|
|
|
205
202
|
</div>
|
|
206
203
|
|
|
207
204
|
<div class="grid grid-cols-[130px_1fr] items-center gap-x-4">
|
|
208
|
-
<Label>Execution mode</Label>
|
|
205
|
+
<Label for="wf-exec-mode">Execution mode</Label>
|
|
209
206
|
<Select v-model="executionMode">
|
|
210
|
-
<SelectTrigger class="w-full bg-white">
|
|
207
|
+
<SelectTrigger id="wf-exec-mode" class="w-full bg-white">
|
|
211
208
|
<SelectValue>
|
|
212
209
|
<span class="flex min-w-0 items-center gap-2">
|
|
213
210
|
<span class="flex size-6 shrink-0 items-center justify-center rounded-md bg-slate-100 text-slate-500">
|
|
@@ -256,6 +253,7 @@ async function useTemplate(slug) {
|
|
|
256
253
|
<input
|
|
257
254
|
v-model="templateSearch"
|
|
258
255
|
type="text"
|
|
256
|
+
aria-label="Search templates"
|
|
259
257
|
placeholder="Search templates…"
|
|
260
258
|
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"
|
|
261
259
|
>
|
|
@@ -282,29 +280,15 @@ async function useTemplate(slug) {
|
|
|
282
280
|
</p>
|
|
283
281
|
|
|
284
282
|
<div v-else class="grid gap-2.5 sm:grid-cols-2 lg:grid-cols-3">
|
|
285
|
-
<
|
|
283
|
+
<TemplateCard
|
|
286
284
|
v-for="tpl in filteredTemplates"
|
|
287
285
|
:key="tpl.slug"
|
|
288
|
-
|
|
289
|
-
|
|
286
|
+
:template="tpl"
|
|
287
|
+
density="compact"
|
|
288
|
+
:busy="instantiatingSlug === tpl.slug"
|
|
290
289
|
:disabled="!!instantiatingSlug"
|
|
291
|
-
@
|
|
292
|
-
|
|
293
|
-
<div class="relative h-24 shrink-0 border-b border-black/[0.06] bg-slate-50/70 [background-image:radial-gradient(circle,rgba(15,23,42,0.07)_1px,transparent_1px)] [background-size:12px_12px]">
|
|
294
|
-
<TemplateFlowPreview v-if="tpl.detailLoaded" :blob="tpl.blob" :height="96" class="px-1" />
|
|
295
|
-
<div v-else class="flex h-full items-center justify-center">
|
|
296
|
-
<Loader2 :size="14" class="animate-spin text-muted-foreground/40" />
|
|
297
|
-
</div>
|
|
298
|
-
<span class="absolute left-1.5 top-1.5 inline-flex items-center rounded-full bg-slate-100 px-1.5 py-px uppercase text-[11px] font-medium text-slate-700">
|
|
299
|
-
{{ tpl.category.charAt(0).toUpperCase() + tpl.category.slice(1) }}
|
|
300
|
-
</span>
|
|
301
|
-
<Loader2 v-if="instantiatingSlug === tpl.slug" :size="13" class="absolute right-1.5 top-1.5 animate-spin text-muted-foreground" />
|
|
302
|
-
</div>
|
|
303
|
-
<div class="flex min-h-0 flex-1 flex-col p-3">
|
|
304
|
-
<div class="truncate text-sm font-medium">{{ tpl.name }}</div>
|
|
305
|
-
<p class="mt-0.5 line-clamp-2 text-sm text-muted-foreground">{{ tpl.description }}</p>
|
|
306
|
-
</div>
|
|
307
|
-
</button>
|
|
290
|
+
@select="useTemplate(tpl.slug)"
|
|
291
|
+
/>
|
|
308
292
|
</div>
|
|
309
293
|
|
|
310
294
|
<div class="flex items-center justify-between pt-1">
|
|
@@ -4,10 +4,14 @@ import { type EdgeProps } from '@vue-flow/core';
|
|
|
4
4
|
*
|
|
5
5
|
* - hard right-angle routing (`getSmoothStepPath`, radius 0)
|
|
6
6
|
* - arrow-head pointing into the target
|
|
7
|
-
* -
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
7
|
+
* - colour encodes IMPORTANCE, not meaning (PO-197): the main flow leads in
|
|
8
|
+
* slate, the error/exception path recedes in a paler slate. The semantic
|
|
9
|
+
* colour (green = normal/active output incl. branch & switch cases, rose =
|
|
10
|
+
* error) lives on the source PORT DOT — a small, localised legend — so the
|
|
11
|
+
* connective edges stay calm.
|
|
12
|
+
* - optional center label (used by the canvas to print branch names) — branch
|
|
13
|
+
* routes only, never the error route (promised: `specs/editor-output-paths.md`,
|
|
14
|
+
* reasoning: `docs/editor-path-colors.md`)
|
|
11
15
|
* - n8n-style midpoint tools on hover/selection: [+] splices a node into
|
|
12
16
|
* the connection (editor-provided action), [trash] deletes the edge
|
|
13
17
|
*
|
|
@@ -19,6 +23,16 @@ interface Data {
|
|
|
19
23
|
kind: EdgeKind;
|
|
20
24
|
/** Optional human label shown mid-edge (e.g. "true", "cases:paid"). */
|
|
21
25
|
label?: string;
|
|
26
|
+
/**
|
|
27
|
+
* Fan-out lane: this edge's rank among its source node's ACTUAL outgoing
|
|
28
|
+
* edges (ordered left-to-right by output handle) and how many there are.
|
|
29
|
+
* Siblings leaving a multi-output node (Switch, out/error) would otherwise
|
|
30
|
+
* bend on the same horizontal line and overlap — the renderer staggers the
|
|
31
|
+
* bend height by lane so the horizontal runs sit on distinct levels. A lone
|
|
32
|
+
* edge has `laneCount` 1 and gets no stagger.
|
|
33
|
+
*/
|
|
34
|
+
laneIndex?: number;
|
|
35
|
+
laneCount?: number;
|
|
22
36
|
/**
|
|
23
37
|
* Run-replay overlay (WorkflowRunReplayPanel): the edge is on the path the
|
|
24
38
|
* run actually took — drawn blue and thicker. `ahead` marks the part of the
|
|
@@ -41,6 +41,19 @@ const props = defineProps({
|
|
|
41
41
|
});
|
|
42
42
|
const flow = useVueFlow();
|
|
43
43
|
const edgeActions = inject("workflow-edge-actions", null);
|
|
44
|
+
const centerY = computed(() => {
|
|
45
|
+
const n = props.data?.laneCount ?? 1;
|
|
46
|
+
const i = props.data?.laneIndex ?? 0;
|
|
47
|
+
if (n <= 1) return void 0;
|
|
48
|
+
const mid = (props.sourceY + props.targetY) / 2;
|
|
49
|
+
const STEP = 11;
|
|
50
|
+
const span = Math.abs(props.targetY - props.sourceY);
|
|
51
|
+
const dist = Math.abs(i - (n - 1) / 2);
|
|
52
|
+
const tie = i / Math.max(1, n - 1) * (STEP / 3);
|
|
53
|
+
const lift = Math.min(dist * STEP + tie, Math.max(0, span / 2 - span / 6));
|
|
54
|
+
const towardSource = Math.sign(props.sourceY - props.targetY) || -1;
|
|
55
|
+
return mid + towardSource * lift;
|
|
56
|
+
});
|
|
44
57
|
const path = computed(() => getSmoothStepPath({
|
|
45
58
|
sourceX: props.sourceX,
|
|
46
59
|
sourceY: props.sourceY,
|
|
@@ -48,15 +61,18 @@ const path = computed(() => getSmoothStepPath({
|
|
|
48
61
|
targetX: props.targetX,
|
|
49
62
|
targetY: props.targetY,
|
|
50
63
|
targetPosition: props.targetPosition,
|
|
51
|
-
borderRadius: 0
|
|
64
|
+
borderRadius: 0,
|
|
65
|
+
centerY: centerY.value
|
|
52
66
|
}));
|
|
67
|
+
const NEUTRAL = { stroke: "#94a3b8", label: "#475569", bg: "#f1f5f9" };
|
|
68
|
+
const MUTED = { stroke: "#cbd5e1", label: "#94a3b8", bg: "#f8fafc" };
|
|
53
69
|
const palette = {
|
|
54
|
-
default:
|
|
55
|
-
success:
|
|
56
|
-
error:
|
|
57
|
-
"branch-true":
|
|
58
|
-
"branch-false":
|
|
59
|
-
branch:
|
|
70
|
+
default: NEUTRAL,
|
|
71
|
+
success: NEUTRAL,
|
|
72
|
+
error: MUTED,
|
|
73
|
+
"branch-true": NEUTRAL,
|
|
74
|
+
"branch-false": NEUTRAL,
|
|
75
|
+
branch: NEUTRAL
|
|
60
76
|
};
|
|
61
77
|
const color = computed(() => palette[props.data?.kind ?? "default"] ?? palette.default);
|
|
62
78
|
const isSelected = computed(() => props.selected);
|
|
@@ -4,10 +4,14 @@ import { type EdgeProps } from '@vue-flow/core';
|
|
|
4
4
|
*
|
|
5
5
|
* - hard right-angle routing (`getSmoothStepPath`, radius 0)
|
|
6
6
|
* - arrow-head pointing into the target
|
|
7
|
-
* -
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
7
|
+
* - colour encodes IMPORTANCE, not meaning (PO-197): the main flow leads in
|
|
8
|
+
* slate, the error/exception path recedes in a paler slate. The semantic
|
|
9
|
+
* colour (green = normal/active output incl. branch & switch cases, rose =
|
|
10
|
+
* error) lives on the source PORT DOT — a small, localised legend — so the
|
|
11
|
+
* connective edges stay calm.
|
|
12
|
+
* - optional center label (used by the canvas to print branch names) — branch
|
|
13
|
+
* routes only, never the error route (promised: `specs/editor-output-paths.md`,
|
|
14
|
+
* reasoning: `docs/editor-path-colors.md`)
|
|
11
15
|
* - n8n-style midpoint tools on hover/selection: [+] splices a node into
|
|
12
16
|
* the connection (editor-provided action), [trash] deletes the edge
|
|
13
17
|
*
|
|
@@ -19,6 +23,16 @@ interface Data {
|
|
|
19
23
|
kind: EdgeKind;
|
|
20
24
|
/** Optional human label shown mid-edge (e.g. "true", "cases:paid"). */
|
|
21
25
|
label?: string;
|
|
26
|
+
/**
|
|
27
|
+
* Fan-out lane: this edge's rank among its source node's ACTUAL outgoing
|
|
28
|
+
* edges (ordered left-to-right by output handle) and how many there are.
|
|
29
|
+
* Siblings leaving a multi-output node (Switch, out/error) would otherwise
|
|
30
|
+
* bend on the same horizontal line and overlap — the renderer staggers the
|
|
31
|
+
* bend height by lane so the horizontal runs sit on distinct levels. A lone
|
|
32
|
+
* edge has `laneCount` 1 and gets no stagger.
|
|
33
|
+
*/
|
|
34
|
+
laneIndex?: number;
|
|
35
|
+
laneCount?: number;
|
|
22
36
|
/**
|
|
23
37
|
* Run-replay overlay (WorkflowRunReplayPanel): the edge is on the path the
|
|
24
38
|
* run actually took — drawn blue and thicker. `ahead` marks the part of the
|
|
@@ -8,8 +8,27 @@ type __VLS_Props = {
|
|
|
8
8
|
runBusy?: boolean;
|
|
9
9
|
/** The run is queued behind a bundle build — busy, but worth saying why. */
|
|
10
10
|
runWaiting?: boolean;
|
|
11
|
+
/**
|
|
12
|
+
* One of the page's own lightboxes is open above the editor (settings,
|
|
13
|
+
* duplicate, run payload, the sync response, the deactivation prompt). The
|
|
14
|
+
* canvas stands its keyboard shortcuts down while one is up — see
|
|
15
|
+
* `canvasHasKeyboard` below. A new page-level dialog belongs in here too.
|
|
16
|
+
*/
|
|
17
|
+
overlayOpen?: boolean;
|
|
11
18
|
};
|
|
12
|
-
|
|
19
|
+
/**
|
|
20
|
+
* Show a node the user was sent to from outside the canvas — the validation
|
|
21
|
+
* banner's per-node line (PO-209). Centres the card and opens its settings,
|
|
22
|
+
* which is where the fields at fault are.
|
|
23
|
+
*
|
|
24
|
+
* A node inside a collapsed group has no card on the canvas: centring would pan
|
|
25
|
+
* to empty space, so it only opens the settings. The reverse can't happen — an
|
|
26
|
+
* id that is on the canvas is in the blob by construction.
|
|
27
|
+
*/
|
|
28
|
+
declare function revealNode(id: string): void;
|
|
29
|
+
declare const _default: import("vue").DefineComponent<__VLS_Props, {
|
|
30
|
+
revealNode: typeof revealNode;
|
|
31
|
+
}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
13
32
|
change: (blob: WorkflowBlob) => any;
|
|
14
33
|
run: () => any;
|
|
15
34
|
toggleActive: () => any;
|