@revenexx/studio-integrations 0.1.3 → 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/Sidebar.vue +1 -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 +12 -2
- 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,151 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import { onMounted, ref, watch } from "vue";
|
|
3
|
+
import { RefreshCircle as Loader2, Refresh as ReplayIcon, TrashBinMinimalistic as Trash2 } from "#solar-icons";
|
|
4
|
+
import { Badge, Button } from "@revenexx/studio";
|
|
5
|
+
import { toast } from "vue-sonner";
|
|
6
|
+
const props = defineProps({
|
|
7
|
+
workflowId: { type: Number, required: true }
|
|
8
|
+
});
|
|
9
|
+
const { list, replay, discard } = useIntegrationsDeadLetters();
|
|
10
|
+
const PER_PAGE = 25;
|
|
11
|
+
const items = ref([]);
|
|
12
|
+
const loading = ref(false);
|
|
13
|
+
const error = ref(null);
|
|
14
|
+
const page = ref(1);
|
|
15
|
+
const total = ref(0);
|
|
16
|
+
const lastPage = ref(1);
|
|
17
|
+
const busyId = ref(null);
|
|
18
|
+
async function load(p = page.value) {
|
|
19
|
+
loading.value = true;
|
|
20
|
+
error.value = null;
|
|
21
|
+
try {
|
|
22
|
+
const res = await list(props.workflowId, { page: p, perPage: PER_PAGE });
|
|
23
|
+
items.value = res.items;
|
|
24
|
+
total.value = res.total;
|
|
25
|
+
lastPage.value = res.lastPage;
|
|
26
|
+
page.value = res.page;
|
|
27
|
+
} catch (e) {
|
|
28
|
+
error.value = e?.message ?? "Could not load dead letters.";
|
|
29
|
+
} finally {
|
|
30
|
+
loading.value = false;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
function goPage(p) {
|
|
34
|
+
const next = Math.min(Math.max(1, p), lastPage.value);
|
|
35
|
+
if (next !== page.value) void load(next);
|
|
36
|
+
}
|
|
37
|
+
onMounted(() => void load(1));
|
|
38
|
+
watch(() => props.workflowId, () => void load(1));
|
|
39
|
+
async function onReplay(dl) {
|
|
40
|
+
busyId.value = dl.id;
|
|
41
|
+
try {
|
|
42
|
+
const res = await replay(dl.id);
|
|
43
|
+
const newId = res && typeof res === "object" && "id" in res ? String(res.id) : null;
|
|
44
|
+
toast.success(newId ? `Replayed \u2014 started run #${newId}` : "Replayed");
|
|
45
|
+
await load();
|
|
46
|
+
} catch (e) {
|
|
47
|
+
toast.error(e?.message ?? "Could not replay.");
|
|
48
|
+
} finally {
|
|
49
|
+
busyId.value = null;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
async function onDiscard(dl) {
|
|
53
|
+
busyId.value = dl.id;
|
|
54
|
+
try {
|
|
55
|
+
await discard(dl.id);
|
|
56
|
+
toast.success("Discarded");
|
|
57
|
+
await load();
|
|
58
|
+
} catch (e) {
|
|
59
|
+
toast.error(e?.message ?? "Could not discard.");
|
|
60
|
+
} finally {
|
|
61
|
+
busyId.value = null;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
function statusClass(status) {
|
|
65
|
+
if (status === "pending") return "bg-amber-500/15 text-amber-700 border-amber-500/25";
|
|
66
|
+
if (status === "replayed") return "bg-emerald-500/15 text-emerald-700 border-emerald-500/25";
|
|
67
|
+
return "bg-slate-500/15 text-slate-600 border-slate-500/20";
|
|
68
|
+
}
|
|
69
|
+
function fmt(iso) {
|
|
70
|
+
if (!iso) return "\u2014";
|
|
71
|
+
try {
|
|
72
|
+
return new Date(iso).toLocaleString();
|
|
73
|
+
} catch {
|
|
74
|
+
return iso;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
</script>
|
|
78
|
+
|
|
79
|
+
<template>
|
|
80
|
+
<div class="space-y-3">
|
|
81
|
+
<div class="flex items-center justify-between">
|
|
82
|
+
<div>
|
|
83
|
+
<h3 class="text-sm font-semibold">Missed runs</h3>
|
|
84
|
+
<p class="mt-0.5 text-sm text-muted-foreground">
|
|
85
|
+
Triggers that fired while this workflow couldn't run (bundle building or failed). Replay starts a fresh run from the captured payload.
|
|
86
|
+
</p>
|
|
87
|
+
</div>
|
|
88
|
+
<Button variant="outline" size="sm" class="h-7 text-sm" :disabled="loading" @click="() => load()">
|
|
89
|
+
<Loader2 v-if="loading" :size="12" class="animate-spin" />
|
|
90
|
+
Refresh
|
|
91
|
+
</Button>
|
|
92
|
+
</div>
|
|
93
|
+
|
|
94
|
+
<div v-if="error" class="rounded-md border border-rose-500/20 bg-rose-500/5 px-3 py-2 text-sm text-rose-700">
|
|
95
|
+
{{ error }}
|
|
96
|
+
</div>
|
|
97
|
+
|
|
98
|
+
<div v-if="loading && !items.length">
|
|
99
|
+
<div class="rounded-lg border border-black/[0.06] bg-white divide-y divide-black/[0.04]">
|
|
100
|
+
<div v-for="n in 4" :key="`sk-${n}`" class="flex items-start gap-3 px-3 py-3">
|
|
101
|
+
<div class="h-5 w-16 shrink-0 rounded bg-black/[0.07] animate-pulse" />
|
|
102
|
+
<div class="min-w-0 flex-1 space-y-2">
|
|
103
|
+
<div class="h-3 w-1/3 rounded bg-black/[0.07] animate-pulse" />
|
|
104
|
+
<div class="h-3 w-2/3 rounded bg-black/[0.05] animate-pulse" />
|
|
105
|
+
</div>
|
|
106
|
+
</div>
|
|
107
|
+
</div>
|
|
108
|
+
</div>
|
|
109
|
+
<div v-else-if="!items.length" class="rounded-lg border border-black/[0.06] bg-white p-6 text-center text-sm text-muted-foreground">
|
|
110
|
+
No missed runs. Every trigger firing made it into a run.
|
|
111
|
+
</div>
|
|
112
|
+
|
|
113
|
+
<div v-else class="rounded-lg border border-black/[0.06] bg-white divide-y divide-black/[0.04]">
|
|
114
|
+
<div
|
|
115
|
+
v-for="dl in items"
|
|
116
|
+
:key="dl.id"
|
|
117
|
+
class="flex items-start gap-3 px-3 py-2.5"
|
|
118
|
+
>
|
|
119
|
+
<Badge variant="outline" :class="['border text-xs font-medium uppercase shrink-0 mt-0.5', statusClass(dl.status)]">{{ dl.status }}</Badge>
|
|
120
|
+
<div class="min-w-0 flex-1">
|
|
121
|
+
<div class="text-sm break-words">{{ dl.reason || "No reason recorded." }}</div>
|
|
122
|
+
<div class="mt-0.5 flex flex-wrap items-center gap-x-3 gap-y-0.5 text-xs text-muted-foreground font-mono">
|
|
123
|
+
<span>#{{ dl.id }}</span>
|
|
124
|
+
<span v-if="dl.source">{{ dl.source }}</span>
|
|
125
|
+
<span v-if="dl.trigger_handle">↳ {{ dl.trigger_handle }}</span>
|
|
126
|
+
<span>{{ fmt(dl.created_at) }}</span>
|
|
127
|
+
</div>
|
|
128
|
+
</div>
|
|
129
|
+
<div v-if="dl.status === 'pending'" class="flex shrink-0 items-center gap-1">
|
|
130
|
+
<Button variant="outline" size="sm" class="h-7 text-sm" :disabled="busyId === dl.id" @click="onReplay(dl)">
|
|
131
|
+
<Loader2 v-if="busyId === dl.id" :size="12" class="animate-spin" />
|
|
132
|
+
<ReplayIcon v-else :size="12" />
|
|
133
|
+
Replay
|
|
134
|
+
</Button>
|
|
135
|
+
<Button variant="ghost" size="sm" class="h-7 text-sm text-rose-600 hover:bg-rose-500/10" :disabled="busyId === dl.id" @click="onDiscard(dl)">
|
|
136
|
+
<Trash2 :size="12" />
|
|
137
|
+
Discard
|
|
138
|
+
</Button>
|
|
139
|
+
</div>
|
|
140
|
+
</div>
|
|
141
|
+
</div>
|
|
142
|
+
|
|
143
|
+
<div v-if="lastPage > 1" class="flex items-center justify-between text-sm text-muted-foreground">
|
|
144
|
+
<span class="tabular-nums">Page {{ page }} / {{ lastPage }} · {{ total }} total</span>
|
|
145
|
+
<div class="flex gap-2">
|
|
146
|
+
<Button variant="outline" size="sm" class="h-7 text-sm" :disabled="page <= 1 || loading" @click="goPage(page - 1)">← Newer</Button>
|
|
147
|
+
<Button variant="outline" size="sm" class="h-7 text-sm" :disabled="page >= lastPage || loading" @click="goPage(page + 1)">Older →</Button>
|
|
148
|
+
</div>
|
|
149
|
+
</div>
|
|
150
|
+
</div>
|
|
151
|
+
</template>
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
type __VLS_Props = {
|
|
2
|
+
workflowId: number;
|
|
3
|
+
};
|
|
4
|
+
declare const _default: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
5
|
+
export default _default;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
type __VLS_Props = {
|
|
2
|
+
label: string;
|
|
3
|
+
/** e.g. 'mod+enter', 'shift+alt+t', 'v', '1'. Omit for label-only tips. */
|
|
4
|
+
shortcut?: string;
|
|
5
|
+
};
|
|
6
|
+
declare var __VLS_10: {};
|
|
7
|
+
type __VLS_Slots = {} & {
|
|
8
|
+
default?: (props: typeof __VLS_10) => any;
|
|
9
|
+
};
|
|
10
|
+
declare const __VLS_component: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
11
|
+
declare const _default: __VLS_WithSlots<typeof __VLS_component, __VLS_Slots>;
|
|
12
|
+
export default _default;
|
|
13
|
+
type __VLS_WithSlots<T, S> = T & {
|
|
14
|
+
new (): {
|
|
15
|
+
$slots: S;
|
|
16
|
+
};
|
|
17
|
+
};
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import { computed } from "vue";
|
|
3
|
+
import { Tooltip, TooltipContent, TooltipTrigger } from "@revenexx/studio";
|
|
4
|
+
const props = defineProps({
|
|
5
|
+
label: { type: String, required: true },
|
|
6
|
+
shortcut: { type: String, required: false }
|
|
7
|
+
});
|
|
8
|
+
const isMac = typeof navigator !== "undefined" && /Mac|iPhone|iPad/.test(navigator.platform ?? "");
|
|
9
|
+
const keys = computed(() => {
|
|
10
|
+
if (!props.shortcut) return "";
|
|
11
|
+
const out = [];
|
|
12
|
+
for (const raw of props.shortcut.split("+")) {
|
|
13
|
+
const t = raw.toLowerCase();
|
|
14
|
+
if (t === "mod") out.push(isMac ? "\u2318" : "Ctrl");
|
|
15
|
+
else if (t === "shift") out.push("\u21E7");
|
|
16
|
+
else if (t === "alt") out.push(isMac ? "\u2325" : "Alt");
|
|
17
|
+
else if (t === "enter") out.push("\u21B5");
|
|
18
|
+
else if (t === "escape") out.push("Esc");
|
|
19
|
+
else out.push(t.toUpperCase());
|
|
20
|
+
}
|
|
21
|
+
return isMac ? out.join("") : out.join("+");
|
|
22
|
+
});
|
|
23
|
+
</script>
|
|
24
|
+
|
|
25
|
+
<template>
|
|
26
|
+
<Tooltip :delay-duration="250">
|
|
27
|
+
<TooltipTrigger as-child>
|
|
28
|
+
<slot />
|
|
29
|
+
</TooltipTrigger>
|
|
30
|
+
<TooltipContent
|
|
31
|
+
side="top"
|
|
32
|
+
:side-offset="8"
|
|
33
|
+
class="editor-tip flex items-center gap-1.5 rounded-md border border-black/[0.06] bg-white px-2 py-1 text-xs text-foreground shadow-md"
|
|
34
|
+
>
|
|
35
|
+
<span>{{ label }}</span>
|
|
36
|
+
<kbd
|
|
37
|
+
v-if="keys"
|
|
38
|
+
class="rounded border border-black/[0.08] bg-muted/60 px-1 py-px font-mono text-[10px] tabular-nums text-muted-foreground"
|
|
39
|
+
>{{ keys }}</kbd>
|
|
40
|
+
</TooltipContent>
|
|
41
|
+
</Tooltip>
|
|
42
|
+
</template>
|
|
43
|
+
|
|
44
|
+
<style>
|
|
45
|
+
.editor-tip svg{display:none!important}
|
|
46
|
+
</style>
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
type __VLS_Props = {
|
|
2
|
+
label: string;
|
|
3
|
+
/** e.g. 'mod+enter', 'shift+alt+t', 'v', '1'. Omit for label-only tips. */
|
|
4
|
+
shortcut?: string;
|
|
5
|
+
};
|
|
6
|
+
declare var __VLS_10: {};
|
|
7
|
+
type __VLS_Slots = {} & {
|
|
8
|
+
default?: (props: typeof __VLS_10) => any;
|
|
9
|
+
};
|
|
10
|
+
declare const __VLS_component: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
11
|
+
declare const _default: __VLS_WithSlots<typeof __VLS_component, __VLS_Slots>;
|
|
12
|
+
export default _default;
|
|
13
|
+
type __VLS_WithSlots<T, S> = T & {
|
|
14
|
+
new (): {
|
|
15
|
+
$slots: S;
|
|
16
|
+
};
|
|
17
|
+
};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
type __VLS_Props = {
|
|
2
|
+
modelValue: string;
|
|
3
|
+
};
|
|
4
|
+
declare const _default: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
5
|
+
"update:modelValue": (value: string) => any;
|
|
6
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
7
|
+
"onUpdate:modelValue"?: ((value: string) => any) | undefined;
|
|
8
|
+
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
9
|
+
export default _default;
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import { computed, onMounted, ref } from "vue";
|
|
3
|
+
import { Input } from "@revenexx/studio";
|
|
4
|
+
const props = defineProps({
|
|
5
|
+
modelValue: { type: String, required: true }
|
|
6
|
+
});
|
|
7
|
+
const emit = defineEmits(["update:modelValue"]);
|
|
8
|
+
const catalog = useDefinedEvents();
|
|
9
|
+
onMounted(() => {
|
|
10
|
+
void catalog.load();
|
|
11
|
+
});
|
|
12
|
+
const focused = ref(false);
|
|
13
|
+
const options = computed(() => {
|
|
14
|
+
const out = /* @__PURE__ */ new Map();
|
|
15
|
+
for (const e of catalog.emits.value) out.set(e.topic, { topic: e.topic, source: e.app });
|
|
16
|
+
for (const t of catalog.listens.value) {
|
|
17
|
+
if (!out.has(t)) out.set(t, { topic: t, source: null });
|
|
18
|
+
}
|
|
19
|
+
return [...out.values()].sort((a, b) => a.topic.localeCompare(b.topic));
|
|
20
|
+
});
|
|
21
|
+
const filtered = computed(() => {
|
|
22
|
+
const q = (props.modelValue ?? "").trim().toLowerCase();
|
|
23
|
+
const list = q ? options.value.filter((o) => o.topic.toLowerCase().includes(q)) : options.value;
|
|
24
|
+
return list.slice(0, 40);
|
|
25
|
+
});
|
|
26
|
+
const open = computed(() => focused.value && (filtered.value.length > 0 || catalog.loading.value));
|
|
27
|
+
function pick(topic) {
|
|
28
|
+
emit("update:modelValue", topic);
|
|
29
|
+
focused.value = false;
|
|
30
|
+
}
|
|
31
|
+
</script>
|
|
32
|
+
|
|
33
|
+
<template>
|
|
34
|
+
<div class="relative">
|
|
35
|
+
<Input
|
|
36
|
+
:model-value="modelValue"
|
|
37
|
+
placeholder="customer.created"
|
|
38
|
+
class="h-8 text-sm bg-white font-mono"
|
|
39
|
+
@update:model-value="(v) => emit('update:modelValue', String(v))"
|
|
40
|
+
@focus="focused = true"
|
|
41
|
+
@blur="focused = false"
|
|
42
|
+
/>
|
|
43
|
+
<div
|
|
44
|
+
v-if="open"
|
|
45
|
+
class="absolute left-0 right-0 top-full z-30 mt-1 max-h-56 overflow-y-auto rounded-md border border-black/[0.08] bg-white py-1 shadow-md"
|
|
46
|
+
>
|
|
47
|
+
<div v-if="catalog.loading.value && !filtered.length" class="px-2.5 py-1.5 text-sm text-muted-foreground">
|
|
48
|
+
Loading event catalog…
|
|
49
|
+
</div>
|
|
50
|
+
<button
|
|
51
|
+
v-for="o in filtered"
|
|
52
|
+
:key="o.topic"
|
|
53
|
+
type="button"
|
|
54
|
+
class="flex w-full items-center gap-2 px-2.5 py-1.5 text-left hover:bg-muted/50"
|
|
55
|
+
@mousedown.prevent="pick(o.topic)"
|
|
56
|
+
>
|
|
57
|
+
<code class="min-w-0 flex-1 truncate font-mono text-[13px]">{{ o.topic }}</code>
|
|
58
|
+
<span v-if="o.source" class="shrink-0 rounded-full bg-slate-100 px-1.5 py-px text-[11px] font-medium uppercase text-slate-700">
|
|
59
|
+
{{ o.source }}
|
|
60
|
+
</span>
|
|
61
|
+
</button>
|
|
62
|
+
</div>
|
|
63
|
+
</div>
|
|
64
|
+
</template>
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
type __VLS_Props = {
|
|
2
|
+
modelValue: string;
|
|
3
|
+
};
|
|
4
|
+
declare const _default: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
5
|
+
"update:modelValue": (value: string) => any;
|
|
6
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
7
|
+
"onUpdate:modelValue"?: ((value: string) => any) | undefined;
|
|
8
|
+
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
9
|
+
export default _default;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { WorkflowVariable } from '../../types/integrations.js';
|
|
2
|
+
type UpstreamOutput = {
|
|
3
|
+
nodeId: string;
|
|
4
|
+
nodeName?: string;
|
|
5
|
+
output: string;
|
|
6
|
+
fields?: string[];
|
|
7
|
+
};
|
|
8
|
+
type __VLS_Props = {
|
|
9
|
+
modelValue: unknown;
|
|
10
|
+
placeholder?: string;
|
|
11
|
+
variables?: Record<string, WorkflowVariable>;
|
|
12
|
+
upstreamOutputs?: UpstreamOutput[];
|
|
13
|
+
};
|
|
14
|
+
declare const _default: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
15
|
+
"update:modelValue": (value: string) => any;
|
|
16
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
17
|
+
"onUpdate:modelValue"?: ((value: string) => any) | undefined;
|
|
18
|
+
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
19
|
+
export default _default;
|
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import { computed, inject, onBeforeUnmount, onMounted, ref, watch } from "vue";
|
|
3
|
+
import { Editor, EditorContent } from "@tiptap/vue-3";
|
|
4
|
+
import { Node } from "@tiptap/core";
|
|
5
|
+
import Document from "@tiptap/extension-document";
|
|
6
|
+
import Paragraph from "@tiptap/extension-paragraph";
|
|
7
|
+
import Text from "@tiptap/extension-text";
|
|
8
|
+
import History from "@tiptap/extension-history";
|
|
9
|
+
import { resolveExpressionText } from "../../data/nodeRunData";
|
|
10
|
+
import { EXPR_TOKEN_NODE, docToText, hasRawTokenText, textToDoc } from "../../data/expressionEditor";
|
|
11
|
+
const props = defineProps({
|
|
12
|
+
modelValue: { type: null, required: true },
|
|
13
|
+
placeholder: { type: String, required: false },
|
|
14
|
+
variables: { type: Object, required: false },
|
|
15
|
+
upstreamOutputs: { type: Array, required: false }
|
|
16
|
+
});
|
|
17
|
+
const emit = defineEmits(["update:modelValue"]);
|
|
18
|
+
const text = computed(() => String(props.modelValue ?? ""));
|
|
19
|
+
const OPEN = "${{ ";
|
|
20
|
+
const CLOSE = " }}";
|
|
21
|
+
function tok(inner) {
|
|
22
|
+
return OPEN + inner + CLOSE;
|
|
23
|
+
}
|
|
24
|
+
const triggerLabel = "{ }";
|
|
25
|
+
const nodeNames = inject("integrationsNodeNames", null);
|
|
26
|
+
function pillLabel(expr) {
|
|
27
|
+
const path = expr.split(".");
|
|
28
|
+
if (path[0] === "nodes" && path[2] === "outputs") {
|
|
29
|
+
const name = nodeNames?.value[path[1] ?? ""] ?? path[1] ?? "";
|
|
30
|
+
const rest = path.slice(3).filter((seg, i) => !(i === 0 && seg === "default")).join(".");
|
|
31
|
+
return rest ? name + " \xB7 " + rest : name;
|
|
32
|
+
}
|
|
33
|
+
if (path[0] === "trigger" && path[1] === "payload") {
|
|
34
|
+
const rest = path.slice(2).join(".");
|
|
35
|
+
return rest ? "Trigger \xB7 " + rest : "Trigger payload";
|
|
36
|
+
}
|
|
37
|
+
if (path[0] === "vars") return "Variable \xB7 " + path.slice(1).join(".");
|
|
38
|
+
if (path[0] === "in") {
|
|
39
|
+
const rest = path.slice(1).join(".");
|
|
40
|
+
return rest ? "Input \xB7 " + rest : "Input payload";
|
|
41
|
+
}
|
|
42
|
+
return expr;
|
|
43
|
+
}
|
|
44
|
+
function tokenLabel(token) {
|
|
45
|
+
const inner = token.replace(/^\$\{\{\s*/, "").replace(/\s*\}\}$/, "");
|
|
46
|
+
return pillLabel(inner);
|
|
47
|
+
}
|
|
48
|
+
const ExprToken = Node.create({
|
|
49
|
+
name: EXPR_TOKEN_NODE,
|
|
50
|
+
group: "inline",
|
|
51
|
+
inline: true,
|
|
52
|
+
atom: true,
|
|
53
|
+
selectable: true,
|
|
54
|
+
addAttributes() {
|
|
55
|
+
return { token: { default: "" } };
|
|
56
|
+
},
|
|
57
|
+
parseHTML() {
|
|
58
|
+
return [{
|
|
59
|
+
tag: "span[data-expr-token]",
|
|
60
|
+
getAttrs: (el) => ({ token: el.getAttribute("data-expr-token") ?? "" })
|
|
61
|
+
}];
|
|
62
|
+
},
|
|
63
|
+
renderHTML({ node }) {
|
|
64
|
+
return ["span", { "data-expr-token": String(node.attrs.token) }, String(node.attrs.token)];
|
|
65
|
+
},
|
|
66
|
+
addNodeView() {
|
|
67
|
+
return ({ node }) => {
|
|
68
|
+
const dom = document.createElement("span");
|
|
69
|
+
dom.className = "expr-pill";
|
|
70
|
+
dom.textContent = tokenLabel(String(node.attrs.token));
|
|
71
|
+
dom.title = String(node.attrs.token);
|
|
72
|
+
return { dom };
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
const editor = new Editor({
|
|
77
|
+
extensions: [Document, Paragraph, Text, History, ExprToken],
|
|
78
|
+
content: textToDoc(text.value),
|
|
79
|
+
editorProps: {
|
|
80
|
+
// Single line: swallow Enter (paragraph splits would break the field).
|
|
81
|
+
handleKeyDown: (_view, event) => event.key === "Enter" && !event.isComposing
|
|
82
|
+
},
|
|
83
|
+
onUpdate({ editor: ed }) {
|
|
84
|
+
const json = ed.getJSON();
|
|
85
|
+
let raw = docToText(json);
|
|
86
|
+
if (hasRawTokenText(json)) {
|
|
87
|
+
ed.commands.setContent(textToDoc(raw));
|
|
88
|
+
raw = docToText(ed.getJSON());
|
|
89
|
+
}
|
|
90
|
+
if (raw !== text.value) emit("update:modelValue", raw);
|
|
91
|
+
},
|
|
92
|
+
onFocus() {
|
|
93
|
+
if (insertHandler) insertHandler.value = insertToken;
|
|
94
|
+
if (hasSuggestions.value) open.value = true;
|
|
95
|
+
}
|
|
96
|
+
});
|
|
97
|
+
onBeforeUnmount(() => {
|
|
98
|
+
if (insertHandler?.value === insertToken) insertHandler.value = null;
|
|
99
|
+
editor.destroy();
|
|
100
|
+
});
|
|
101
|
+
watch(text, (t) => {
|
|
102
|
+
if (docToText(editor.getJSON()) !== t) {
|
|
103
|
+
editor.commands.setContent(textToDoc(t));
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
function insertToken(expr) {
|
|
107
|
+
if (editor.isDestroyed) return;
|
|
108
|
+
editor.chain().focus().insertContent({ type: EXPR_TOKEN_NODE, attrs: { token: expr } }).run();
|
|
109
|
+
}
|
|
110
|
+
const insertHandler = inject("integrationsExpressionInsert", null);
|
|
111
|
+
const sampleContext = inject("integrationsSampleContext", null);
|
|
112
|
+
const preview = computed(() => {
|
|
113
|
+
if (!sampleContext) return null;
|
|
114
|
+
return resolveExpressionText(text.value, sampleContext.value);
|
|
115
|
+
});
|
|
116
|
+
const sections = computed(() => {
|
|
117
|
+
const out = [];
|
|
118
|
+
const vars = props.variables ?? {};
|
|
119
|
+
const varItems = Object.keys(vars).map((key) => ({
|
|
120
|
+
label: key,
|
|
121
|
+
expr: tok("vars." + key)
|
|
122
|
+
}));
|
|
123
|
+
if (varItems.length) out.push({ heading: "VARIABLES", items: varItems });
|
|
124
|
+
const upstream = props.upstreamOutputs ?? [];
|
|
125
|
+
const nodeItems = upstream.flatMap((u) => {
|
|
126
|
+
const base = "nodes." + u.nodeId + ".outputs." + u.output;
|
|
127
|
+
const rows = [{
|
|
128
|
+
label: (u.nodeName || u.nodeId) + " \u2192 " + u.output,
|
|
129
|
+
expr: tok(base)
|
|
130
|
+
}];
|
|
131
|
+
for (const f of u.fields ?? []) {
|
|
132
|
+
rows.push({ label: (u.nodeName || u.nodeId) + " \u2192 " + u.output + "." + f, expr: tok(base + "." + f) });
|
|
133
|
+
}
|
|
134
|
+
return rows;
|
|
135
|
+
});
|
|
136
|
+
if (nodeItems.length) out.push({ heading: "NODE OUTPUTS", items: nodeItems });
|
|
137
|
+
const primary = upstream[0];
|
|
138
|
+
const inItems = [{ label: "input payload", expr: tok("in") }];
|
|
139
|
+
for (const f of primary?.fields ?? []) {
|
|
140
|
+
inItems.push({ label: "input." + f, expr: tok("in." + f) });
|
|
141
|
+
}
|
|
142
|
+
out.push({ heading: "INPUT", items: inItems });
|
|
143
|
+
return out;
|
|
144
|
+
});
|
|
145
|
+
const hasSuggestions = computed(() => sections.value.some((s) => s.items.length > 0));
|
|
146
|
+
const open = ref(false);
|
|
147
|
+
const wrapRef = ref(null);
|
|
148
|
+
function toggle() {
|
|
149
|
+
if (!open.value && !hasSuggestions.value) return;
|
|
150
|
+
open.value = !open.value;
|
|
151
|
+
}
|
|
152
|
+
function onFocusOut(e) {
|
|
153
|
+
if (wrapRef.value && e.relatedTarget instanceof globalThis.Node && wrapRef.value.contains(e.relatedTarget)) return;
|
|
154
|
+
open.value = false;
|
|
155
|
+
}
|
|
156
|
+
function onKeydown(e) {
|
|
157
|
+
if (e.key === "Escape" && open.value) {
|
|
158
|
+
e.stopPropagation();
|
|
159
|
+
e.preventDefault();
|
|
160
|
+
open.value = false;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
function onDocMousedown(e) {
|
|
164
|
+
if (wrapRef.value && !wrapRef.value.contains(e.target)) open.value = false;
|
|
165
|
+
}
|
|
166
|
+
onMounted(() => document.addEventListener("mousedown", onDocMousedown));
|
|
167
|
+
onBeforeUnmount(() => document.removeEventListener("mousedown", onDocMousedown));
|
|
168
|
+
function insert(expr) {
|
|
169
|
+
insertToken(expr);
|
|
170
|
+
open.value = false;
|
|
171
|
+
}
|
|
172
|
+
</script>
|
|
173
|
+
|
|
174
|
+
<template>
|
|
175
|
+
<div ref="wrapRef" class="relative" @focusout="onFocusOut">
|
|
176
|
+
<div class="flex items-center gap-1">
|
|
177
|
+
<div class="expr-editor relative h-8 min-w-0 flex-1 overflow-hidden rounded-md border border-black/[0.08] bg-white px-2 font-mono text-sm transition focus-within:border-black/[0.16]">
|
|
178
|
+
<span
|
|
179
|
+
v-if="!text"
|
|
180
|
+
class="pointer-events-none absolute left-2 top-1/2 -translate-y-1/2 truncate text-muted-foreground/60"
|
|
181
|
+
>{{ placeholder }}</span>
|
|
182
|
+
<EditorContent :editor="editor" class="h-full" @keydown="onKeydown" />
|
|
183
|
+
</div>
|
|
184
|
+
<button
|
|
185
|
+
type="button"
|
|
186
|
+
title="Insert expression"
|
|
187
|
+
class="flex h-8 shrink-0 items-center rounded-md border border-black/[0.08] bg-white px-1.5 font-mono text-sm text-muted-foreground transition hover:text-foreground hover:bg-muted/30"
|
|
188
|
+
:class="open ? 'ring-2 ring-emerald-500/40' : ''"
|
|
189
|
+
@mousedown.prevent="toggle"
|
|
190
|
+
>
|
|
191
|
+
{{ triggerLabel }}
|
|
192
|
+
</button>
|
|
193
|
+
</div>
|
|
194
|
+
|
|
195
|
+
<p
|
|
196
|
+
v-if="preview"
|
|
197
|
+
class="mt-1 flex min-w-0 items-baseline gap-1 text-[11px]"
|
|
198
|
+
:title="preview.misses ? 'Parts of this expression have no sample data yet' : preview.resolved"
|
|
199
|
+
>
|
|
200
|
+
<span class="shrink-0 text-muted-foreground">→</span>
|
|
201
|
+
<span class="min-w-0 truncate font-mono" :class="preview.misses ? 'text-amber-600' : 'text-emerald-700'">{{ preview.resolved }}</span>
|
|
202
|
+
</p>
|
|
203
|
+
|
|
204
|
+
<div
|
|
205
|
+
v-if="open && hasSuggestions"
|
|
206
|
+
class="absolute right-0 top-full z-50 mt-1 max-h-64 w-72 overflow-y-auto rounded-md border border-black/[0.08] bg-white py-1 text-sm shadow-lg"
|
|
207
|
+
>
|
|
208
|
+
<template v-for="section in sections" :key="section.heading">
|
|
209
|
+
<div
|
|
210
|
+
v-if="section.items.length"
|
|
211
|
+
class="px-2 pb-0.5 pt-1.5 text-[10px] font-medium uppercase tracking-wider text-muted-foreground"
|
|
212
|
+
>
|
|
213
|
+
{{ section.heading }}
|
|
214
|
+
</div>
|
|
215
|
+
<button
|
|
216
|
+
v-for="item in section.items"
|
|
217
|
+
:key="item.expr"
|
|
218
|
+
type="button"
|
|
219
|
+
class="block w-full px-2 py-1 text-left transition hover:bg-muted/50"
|
|
220
|
+
@mousedown.prevent="insert(item.expr)"
|
|
221
|
+
>
|
|
222
|
+
<div class="truncate text-muted-foreground">
|
|
223
|
+
{{ item.label }}
|
|
224
|
+
</div>
|
|
225
|
+
<div class="truncate font-mono text-emerald-700">
|
|
226
|
+
{{ item.expr }}
|
|
227
|
+
</div>
|
|
228
|
+
</button>
|
|
229
|
+
</template>
|
|
230
|
+
</div>
|
|
231
|
+
</div>
|
|
232
|
+
</template>
|
|
233
|
+
|
|
234
|
+
<style>
|
|
235
|
+
.expr-editor .ProseMirror{align-items:center;display:flex;height:100%;outline:none;overflow-x:auto;scrollbar-width:none}.expr-editor .ProseMirror p{line-height:30px;margin:0;white-space:pre}.expr-pill{background:rgba(16,185,129,.1);border:1px solid rgba(16,185,129,.25);border-radius:6px;color:#047857;display:inline-block;font-family:ui-sans-serif,system-ui,sans-serif;font-size:11px;line-height:18px;margin:0 1px;padding:0 6px;-webkit-user-select:none;-moz-user-select:none;user-select:none;vertical-align:baseline;white-space:nowrap}.expr-pill.ProseMirror-selectednode{outline:2px solid rgba(16,185,129,.5)}
|
|
236
|
+
</style>
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { WorkflowVariable } from '../../types/integrations.js';
|
|
2
|
+
type UpstreamOutput = {
|
|
3
|
+
nodeId: string;
|
|
4
|
+
nodeName?: string;
|
|
5
|
+
output: string;
|
|
6
|
+
fields?: string[];
|
|
7
|
+
};
|
|
8
|
+
type __VLS_Props = {
|
|
9
|
+
modelValue: unknown;
|
|
10
|
+
placeholder?: string;
|
|
11
|
+
variables?: Record<string, WorkflowVariable>;
|
|
12
|
+
upstreamOutputs?: UpstreamOutput[];
|
|
13
|
+
};
|
|
14
|
+
declare const _default: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
15
|
+
"update:modelValue": (value: string) => any;
|
|
16
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
17
|
+
"onUpdate:modelValue"?: ((value: string) => any) | undefined;
|
|
18
|
+
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
19
|
+
export default _default;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { WorkflowGroup } from '../../types/integrations.js';
|
|
2
|
+
interface GroupNodeData {
|
|
3
|
+
group: WorkflowGroup;
|
|
4
|
+
/** Derived frame size (expanded mode). */
|
|
5
|
+
rect: {
|
|
6
|
+
width: number;
|
|
7
|
+
height: number;
|
|
8
|
+
};
|
|
9
|
+
memberCount: number;
|
|
10
|
+
/** Absent in read-only previews — no toolbar, no editing. */
|
|
11
|
+
actions?: {
|
|
12
|
+
rename: (label: string) => void;
|
|
13
|
+
setColor: (i: number) => void;
|
|
14
|
+
toggleCollapse: () => void;
|
|
15
|
+
ungroup: () => void;
|
|
16
|
+
resize: (size: {
|
|
17
|
+
width: number;
|
|
18
|
+
height: number;
|
|
19
|
+
}) => void;
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
type __VLS_Props = {
|
|
23
|
+
id: string;
|
|
24
|
+
data: GroupNodeData;
|
|
25
|
+
selected?: boolean;
|
|
26
|
+
};
|
|
27
|
+
declare const _default: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, any, string, import("vue").PublicProps, any, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
28
|
+
export default _default;
|