@revenexx/studio-integrations 0.1.4 → 0.3.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/README.md +31 -0
- package/dist/module.d.mts +2 -2
- package/dist/module.json +1 -1
- package/dist/runtime/components/Integrations/CredentialCreateDialog.d.vue.ts +13 -0
- package/dist/runtime/components/Integrations/CredentialCreateDialog.vue +279 -0
- package/dist/runtime/components/Integrations/CredentialCreateDialog.vue.d.ts +13 -0
- package/dist/runtime/components/Integrations/CredentialDetailDialog.d.vue.ts +20 -0
- package/dist/runtime/components/Integrations/CredentialDetailDialog.vue +342 -0
- package/dist/runtime/components/Integrations/CredentialDetailDialog.vue.d.ts +20 -0
- package/dist/runtime/components/Integrations/CredentialLogo.d.vue.ts +14 -0
- package/dist/runtime/components/Integrations/CredentialLogo.vue +37 -0
- package/dist/runtime/components/Integrations/CredentialLogo.vue.d.ts +14 -0
- package/dist/runtime/components/Integrations/CredentialRevenexxSource.d.vue.ts +12 -0
- package/dist/runtime/components/Integrations/CredentialRevenexxSource.vue +364 -0
- package/dist/runtime/components/Integrations/CredentialRevenexxSource.vue.d.ts +12 -0
- package/dist/runtime/components/Integrations/CredentialTypePicker.d.vue.ts +15 -0
- package/dist/runtime/components/Integrations/CredentialTypePicker.vue +71 -0
- package/dist/runtime/components/Integrations/CredentialTypePicker.vue.d.ts +15 -0
- package/dist/runtime/components/Integrations/DeadLettersPanel.d.vue.ts +5 -0
- package/dist/runtime/components/Integrations/DeadLettersPanel.vue +151 -0
- package/dist/runtime/components/Integrations/DeadLettersPanel.vue.d.ts +5 -0
- package/dist/runtime/components/Integrations/EditorTip.d.vue.ts +17 -0
- package/dist/runtime/components/Integrations/EditorTip.vue +46 -0
- package/dist/runtime/components/Integrations/EditorTip.vue.d.ts +17 -0
- package/dist/runtime/components/Integrations/EventTypeCombobox.d.vue.ts +9 -0
- package/dist/runtime/components/Integrations/EventTypeCombobox.vue +64 -0
- package/dist/runtime/components/Integrations/EventTypeCombobox.vue.d.ts +9 -0
- package/dist/runtime/components/Integrations/ExpressionInput.d.vue.ts +19 -0
- package/dist/runtime/components/Integrations/ExpressionInput.vue +236 -0
- package/dist/runtime/components/Integrations/ExpressionInput.vue.d.ts +19 -0
- package/dist/runtime/components/Integrations/GroupFrameView.d.vue.ts +28 -0
- package/dist/runtime/components/Integrations/GroupFrameView.vue +222 -0
- package/dist/runtime/components/Integrations/GroupFrameView.vue.d.ts +28 -0
- package/dist/runtime/components/Integrations/NodeConfigDynamicField.d.vue.ts +14 -0
- package/dist/runtime/components/Integrations/NodeConfigDynamicField.vue +184 -0
- package/dist/runtime/components/Integrations/NodeConfigDynamicField.vue.d.ts +14 -0
- package/dist/runtime/components/Integrations/NodeConfigDynamicSchema.d.vue.ts +16 -0
- package/dist/runtime/components/Integrations/NodeConfigDynamicSchema.vue +102 -0
- package/dist/runtime/components/Integrations/NodeConfigDynamicSchema.vue.d.ts +16 -0
- package/dist/runtime/components/Integrations/NodeConfigField.d.vue.ts +23 -0
- package/dist/runtime/components/Integrations/NodeConfigField.vue +587 -0
- package/dist/runtime/components/Integrations/NodeConfigField.vue.d.ts +23 -0
- package/dist/runtime/components/Integrations/NodeDynamicOutputsResolver.d.vue.ts +14 -0
- package/dist/runtime/components/Integrations/NodeDynamicOutputsResolver.vue +80 -0
- package/dist/runtime/components/Integrations/NodeDynamicOutputsResolver.vue.d.ts +14 -0
- package/dist/runtime/components/Integrations/NodeInspector.d.vue.ts +22 -3
- package/dist/runtime/components/Integrations/NodeInspector.vue +1074 -294
- package/dist/runtime/components/Integrations/NodeInspector.vue.d.ts +22 -3
- package/dist/runtime/components/Integrations/NodeLogo.d.vue.ts +9 -0
- package/dist/runtime/components/Integrations/NodeLogo.vue +38 -0
- package/dist/runtime/components/Integrations/NodeLogo.vue.d.ts +9 -0
- package/dist/runtime/components/Integrations/NodePalette.d.vue.ts +22 -1
- package/dist/runtime/components/Integrations/NodePalette.vue +411 -90
- package/dist/runtime/components/Integrations/NodePalette.vue.d.ts +22 -1
- package/dist/runtime/components/Integrations/QueryBuilder.d.vue.ts +9 -0
- package/dist/runtime/components/Integrations/QueryBuilder.vue +239 -0
- package/dist/runtime/components/Integrations/QueryBuilder.vue.d.ts +9 -0
- package/dist/runtime/components/Integrations/{RunDetailDialog.d.vue.ts → RunActionsMenu.d.vue.ts} +3 -4
- package/dist/runtime/components/Integrations/RunActionsMenu.vue +86 -0
- package/dist/runtime/components/Integrations/{RunDetailDialog.vue.d.ts → RunActionsMenu.vue.d.ts} +3 -4
- package/dist/runtime/components/Integrations/RunDetailPanel.d.vue.ts +14 -0
- package/dist/runtime/components/Integrations/RunDetailPanel.vue +777 -0
- package/dist/runtime/components/Integrations/RunDetailPanel.vue.d.ts +14 -0
- package/dist/runtime/components/Integrations/RunPayloadInput.d.vue.ts +13 -0
- package/dist/runtime/components/Integrations/RunPayloadInput.vue +175 -0
- package/dist/runtime/components/Integrations/RunPayloadInput.vue.d.ts +13 -0
- package/dist/runtime/components/Integrations/RunResponseModal.d.vue.ts +27 -0
- package/dist/runtime/components/Integrations/RunResponseModal.vue +84 -0
- package/dist/runtime/components/Integrations/RunResponseModal.vue.d.ts +27 -0
- package/dist/runtime/components/Integrations/RunsTable.d.vue.ts +21 -0
- package/dist/runtime/components/Integrations/RunsTable.vue +114 -0
- package/dist/runtime/components/Integrations/RunsTable.vue.d.ts +21 -0
- package/dist/runtime/components/Integrations/SftpAccountImportDialog.d.vue.ts +11 -0
- package/dist/runtime/components/Integrations/SftpAccountImportDialog.vue +91 -0
- package/dist/runtime/components/Integrations/SftpAccountImportDialog.vue.d.ts +11 -0
- package/dist/runtime/components/Integrations/StickyNoteView.d.vue.ts +28 -0
- package/dist/runtime/components/Integrations/StickyNoteView.vue +208 -0
- package/dist/runtime/components/Integrations/StickyNoteView.vue.d.ts +28 -0
- package/dist/runtime/components/Integrations/TemplateFlowPreview.d.vue.ts +29 -0
- package/dist/runtime/components/Integrations/TemplateFlowPreview.vue +201 -0
- package/dist/runtime/components/Integrations/TemplateFlowPreview.vue.d.ts +29 -0
- package/dist/runtime/components/Integrations/WorkflowContextMenu.d.vue.ts +32 -0
- package/dist/runtime/components/Integrations/WorkflowContextMenu.vue +138 -0
- package/dist/runtime/components/Integrations/WorkflowContextMenu.vue.d.ts +32 -0
- package/dist/runtime/components/Integrations/WorkflowCreateDialog.d.vue.ts +9 -0
- package/dist/runtime/components/Integrations/WorkflowCreateDialog.vue +322 -0
- package/dist/runtime/components/Integrations/WorkflowCreateDialog.vue.d.ts +9 -0
- package/dist/runtime/components/Integrations/WorkflowDuplicateDialog.d.vue.ts +18 -0
- package/dist/runtime/components/Integrations/WorkflowDuplicateDialog.vue +63 -0
- package/dist/runtime/components/Integrations/WorkflowDuplicateDialog.vue.d.ts +18 -0
- package/dist/runtime/components/Integrations/WorkflowEdgeView.d.vue.ts +12 -1
- package/dist/runtime/components/Integrations/WorkflowEdgeView.vue +68 -6
- package/dist/runtime/components/Integrations/WorkflowEdgeView.vue.d.ts +12 -1
- package/dist/runtime/components/Integrations/WorkflowEditor.d.vue.ts +8 -1
- package/dist/runtime/components/Integrations/WorkflowEditor.vue +1424 -144
- package/dist/runtime/components/Integrations/WorkflowEditor.vue.d.ts +8 -1
- package/dist/runtime/components/Integrations/WorkflowHistoryPanel.d.vue.ts +12 -0
- package/dist/runtime/components/Integrations/WorkflowHistoryPanel.vue +417 -0
- package/dist/runtime/components/Integrations/WorkflowHistoryPanel.vue.d.ts +12 -0
- package/dist/runtime/components/Integrations/WorkflowIconPicker.d.vue.ts +10 -0
- package/dist/runtime/components/Integrations/WorkflowIconPicker.vue +89 -0
- package/dist/runtime/components/Integrations/WorkflowIconPicker.vue.d.ts +10 -0
- package/dist/runtime/components/Integrations/WorkflowIconView.d.vue.ts +10 -0
- package/dist/runtime/components/Integrations/WorkflowIconView.vue +35 -0
- package/dist/runtime/components/Integrations/WorkflowIconView.vue.d.ts +10 -0
- package/dist/runtime/components/Integrations/WorkflowNodeView.d.vue.ts +5 -1
- package/dist/runtime/components/Integrations/WorkflowNodeView.vue +114 -84
- package/dist/runtime/components/Integrations/WorkflowNodeView.vue.d.ts +5 -1
- package/dist/runtime/components/Integrations/WorkflowRunReplayPanel.d.vue.ts +12 -0
- package/dist/runtime/components/Integrations/WorkflowRunReplayPanel.vue +654 -0
- package/dist/runtime/components/Integrations/WorkflowRunReplayPanel.vue.d.ts +12 -0
- package/dist/runtime/components/Integrations/WorkflowSettingsDialog.d.vue.ts +36 -0
- package/dist/runtime/components/Integrations/WorkflowSettingsDialog.vue +136 -0
- package/dist/runtime/components/Integrations/WorkflowSettingsDialog.vue.d.ts +36 -0
- package/dist/runtime/components/Integrations/WorkflowTagsInput.d.vue.ts +14 -0
- package/dist/runtime/components/Integrations/WorkflowTagsInput.vue +63 -0
- package/dist/runtime/components/Integrations/WorkflowTagsInput.vue.d.ts +14 -0
- package/dist/runtime/components/Integrations/WorkflowTriggerView.vue +35 -15
- package/dist/runtime/components/Integrations/WorkflowVariablesDialog.d.vue.ts +13 -0
- package/dist/runtime/components/Integrations/WorkflowVariablesDialog.vue +265 -0
- package/dist/runtime/components/Integrations/WorkflowVariablesDialog.vue.d.ts +13 -0
- package/dist/runtime/components/Integrations/WorkflowsTable.d.vue.ts +4 -1
- package/dist/runtime/components/Integrations/WorkflowsTable.vue +122 -39
- package/dist/runtime/components/Integrations/WorkflowsTable.vue.d.ts +4 -1
- package/dist/runtime/components/Integrations/workflowLayout.d.ts +5 -0
- package/dist/runtime/components/Integrations/workflowLayout.js +5 -3
- package/dist/runtime/composables/integrationsApi.d.ts +6 -7
- package/dist/runtime/composables/integrationsApi.js +6 -12
- package/dist/runtime/composables/useCanvasShortcuts.d.ts +37 -0
- package/dist/runtime/composables/useCanvasShortcuts.js +62 -0
- package/dist/runtime/composables/useCredentialTypes.js +2 -1
- package/dist/runtime/composables/useIntegrationsAudit.js +2 -1
- package/dist/runtime/composables/useIntegrationsCredentials.js +2 -1
- 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 +8 -4
- package/dist/runtime/composables/useIntegrationsRevisions.d.ts +40 -0
- package/dist/runtime/composables/useIntegrationsRevisions.js +52 -0
- package/dist/runtime/composables/useIntegrationsRuns.d.ts +21 -1
- package/dist/runtime/composables/useIntegrationsRuns.js +94 -5
- package/dist/runtime/composables/useIntegrationsSecrets.js +2 -1
- package/dist/runtime/composables/useIntegrationsTemplates.d.ts +1 -0
- package/dist/runtime/composables/useIntegrationsTemplates.js +34 -5
- package/dist/runtime/composables/useIntegrationsTriggers.js +2 -1
- package/dist/runtime/composables/useIntegrationsWorkflows.d.ts +1 -0
- package/dist/runtime/composables/useIntegrationsWorkflows.js +59 -2
- 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 +124 -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/apiError.d.ts +17 -0
- package/dist/runtime/utils/apiError.js +8 -0
- 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 +20 -3
- 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
|
@@ -1,140 +1,461 @@
|
|
|
1
1
|
<script setup>
|
|
2
|
-
import { computed, ref } from "vue";
|
|
2
|
+
import { computed, ref, watch } from "vue";
|
|
3
3
|
import * as Lucide from "lucide-vue-next";
|
|
4
4
|
import { INTEGRATION_NODE_CATALOG, NODE_CATEGORIES, TRIGGER_TEMPLATES } from "../../data/integrationNodeCatalog";
|
|
5
5
|
const { load: loadNodes } = useIntegrationsNodes();
|
|
6
6
|
onMounted(() => {
|
|
7
7
|
void loadNodes();
|
|
8
8
|
});
|
|
9
|
+
const emit = defineEmits(["insert"]);
|
|
9
10
|
const search = ref("");
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
}
|
|
14
|
-
function descOf(value) {
|
|
11
|
+
const searchInput = ref(null);
|
|
12
|
+
defineExpose({ focusSearch: () => searchInput.value?.focus() });
|
|
13
|
+
function loc(value) {
|
|
15
14
|
if (!value) return "";
|
|
16
15
|
return typeof value === "string" ? value : value.en ?? Object.values(value)[0] ?? "";
|
|
17
16
|
}
|
|
18
|
-
|
|
17
|
+
function iconFor(name) {
|
|
18
|
+
if (!name) return Lucide.Box;
|
|
19
|
+
const cleaned = (name.includes(":") ? name.split(":").pop() : name).split("-").map((s) => s.charAt(0).toUpperCase() + s.slice(1)).join("");
|
|
20
|
+
return Lucide[cleaned] || Lucide.Box;
|
|
21
|
+
}
|
|
22
|
+
const CORE_GROUP_BY_CATEGORY = {
|
|
23
|
+
control: "Flow",
|
|
24
|
+
transform: "Data",
|
|
25
|
+
io: "Data",
|
|
26
|
+
action: "Actions",
|
|
27
|
+
trigger: "Triggers"
|
|
28
|
+
};
|
|
29
|
+
const CORE_LABEL_ALIAS = {
|
|
30
|
+
"Flow control": "Flow",
|
|
31
|
+
"Files": "Data",
|
|
32
|
+
"Files & I/O": "Data",
|
|
33
|
+
"Network": "Messaging"
|
|
34
|
+
};
|
|
35
|
+
const CORE_GROUP_META = {
|
|
36
|
+
"Data": { icon: "Database", color: "bg-slate-100 text-amber-700/80" },
|
|
37
|
+
"Flow": { icon: "Split", color: "bg-slate-100 text-rose-600/80" },
|
|
38
|
+
"Messaging": { icon: "MessageCircle", color: "bg-slate-100 text-violet-600/80" },
|
|
39
|
+
"Actions": { icon: "Wand2", color: "bg-slate-100 text-sky-600/80" }
|
|
40
|
+
};
|
|
41
|
+
function coreGroupIcon(label) {
|
|
42
|
+
const meta = CORE_GROUP_META[label];
|
|
43
|
+
return meta && Lucide[meta.icon] || Lucide.FolderOpen;
|
|
44
|
+
}
|
|
45
|
+
const VERB_PREFIX = /^(create|get|list|update|delete|search|send|sync|upsert|cancel)-(.+)$/;
|
|
46
|
+
function titleize(kebab) {
|
|
47
|
+
return kebab.split("-").map((s) => s.charAt(0).toUpperCase() + s.slice(1)).join(" ");
|
|
48
|
+
}
|
|
49
|
+
function packageAppLabel(pkg) {
|
|
50
|
+
if (pkg.label) return pkg.label;
|
|
51
|
+
const tail = pkg.name.split("/").pop() ?? pkg.name;
|
|
52
|
+
return titleize(tail.replace(/^integrations-nodes-/, ""));
|
|
53
|
+
}
|
|
54
|
+
function isAppPackage(pkg) {
|
|
55
|
+
if (!pkg) return false;
|
|
56
|
+
const tail = pkg.name.split("/").pop() ?? pkg.name;
|
|
57
|
+
return tail.startsWith("integrations-nodes-") && tail !== "integrations-nodes-core";
|
|
58
|
+
}
|
|
59
|
+
function hasLogo(m) {
|
|
60
|
+
return (m.images ?? []).some((i) => i.category === "logo");
|
|
61
|
+
}
|
|
62
|
+
function groupPath(m) {
|
|
63
|
+
if (m.groups?.length) {
|
|
64
|
+
const path = m.groups.map((g) => loc(g)).filter(Boolean);
|
|
65
|
+
if (isIntegration(m) || !path.length) return path;
|
|
66
|
+
return [CORE_LABEL_ALIAS[path[0]] ?? path[0], ...path.slice(1)];
|
|
67
|
+
}
|
|
68
|
+
if (isAppPackage(m.__package)) {
|
|
69
|
+
const app = packageAppLabel(m.__package);
|
|
70
|
+
const local = m.slug.split(":").pop() ?? m.slug;
|
|
71
|
+
const pkgKey = (m.__package.name.split("/").pop() ?? "").replace(/^integrations-nodes-/, "");
|
|
72
|
+
const rest = local.startsWith(`${pkgKey}-`) ? local.slice(pkgKey.length + 1) : local;
|
|
73
|
+
const verb = VERB_PREFIX.exec(rest);
|
|
74
|
+
return verb ? [app, titleize(verb[2])] : [app];
|
|
75
|
+
}
|
|
76
|
+
return [CORE_GROUP_BY_CATEGORY[m.category] ?? "Other"];
|
|
77
|
+
}
|
|
78
|
+
function isIntegration(m) {
|
|
79
|
+
return isAppPackage(m.__package) || (m.groups?.length ?? 0) > 1 || hasLogo(m);
|
|
80
|
+
}
|
|
81
|
+
function makeGroup(label) {
|
|
82
|
+
return { label, children: /* @__PURE__ */ new Map(), leaves: [], count: 0 };
|
|
83
|
+
}
|
|
84
|
+
const latestManifests = computed(() => {
|
|
85
|
+
const seen = /* @__PURE__ */ new Set();
|
|
86
|
+
const out = [];
|
|
87
|
+
for (const m of INTEGRATION_NODE_CATALOG) {
|
|
88
|
+
if (seen.has(m.slug)) continue;
|
|
89
|
+
seen.add(m.slug);
|
|
90
|
+
out.push(m);
|
|
91
|
+
}
|
|
92
|
+
return out;
|
|
93
|
+
});
|
|
94
|
+
const tree = computed(() => {
|
|
95
|
+
const apps = makeGroup("Integrations");
|
|
96
|
+
const core = makeGroup("Core");
|
|
97
|
+
for (const m of latestManifests.value) {
|
|
98
|
+
if (m.category === "trigger") continue;
|
|
99
|
+
const path = groupPath(m);
|
|
100
|
+
const root = isIntegration(m) ? apps : core;
|
|
101
|
+
let cursor = root;
|
|
102
|
+
cursor.count++;
|
|
103
|
+
for (const label of path) {
|
|
104
|
+
if (!cursor.children.has(label)) cursor.children.set(label, makeGroup(label));
|
|
105
|
+
cursor = cursor.children.get(label);
|
|
106
|
+
cursor.count++;
|
|
107
|
+
}
|
|
108
|
+
cursor.leaves.push(m);
|
|
109
|
+
}
|
|
110
|
+
return { apps, core };
|
|
111
|
+
});
|
|
112
|
+
const appRows = computed(() => {
|
|
113
|
+
const rows = Array.from(tree.value.apps.children.entries());
|
|
114
|
+
const sftpIdx = rows.findIndex(([label]) => label === "SFTP");
|
|
115
|
+
const ftpIdx = rows.findIndex(([label]) => label === "FTP");
|
|
116
|
+
if (ftpIdx !== -1 && sftpIdx !== -1 && sftpIdx !== ftpIdx + 1) {
|
|
117
|
+
const [sftp] = rows.splice(sftpIdx, 1);
|
|
118
|
+
rows.splice(rows.findIndex(([label]) => label === "FTP") + 1, 0, sftp);
|
|
119
|
+
}
|
|
120
|
+
return rows;
|
|
121
|
+
});
|
|
122
|
+
function subtreeManifests(g) {
|
|
123
|
+
const out = [...g.leaves];
|
|
124
|
+
for (const child of g.children.values()) out.push(...subtreeManifests(child));
|
|
125
|
+
return out;
|
|
126
|
+
}
|
|
127
|
+
function groupLogoManifest(g) {
|
|
128
|
+
return subtreeManifests(g).find(hasLogo) ?? null;
|
|
129
|
+
}
|
|
130
|
+
const stack = ref([]);
|
|
131
|
+
const direction = ref("push");
|
|
132
|
+
const triggersLevel = computed(() => stack.value.length > 0 && stack.value[stack.value.length - 1][0] === "__triggers");
|
|
133
|
+
const currentGroup = computed(() => {
|
|
134
|
+
if (!stack.value.length || triggersLevel.value) return null;
|
|
135
|
+
const path = stack.value[stack.value.length - 1];
|
|
136
|
+
let cursor = path[0] === "__apps" ? tree.value.apps : tree.value.core;
|
|
137
|
+
for (const label of path.slice(1)) {
|
|
138
|
+
cursor = cursor?.children.get(label);
|
|
139
|
+
if (!cursor) return null;
|
|
140
|
+
}
|
|
141
|
+
return cursor ?? null;
|
|
142
|
+
});
|
|
143
|
+
const levelTitle = computed(() => {
|
|
144
|
+
if (triggersLevel.value) return "Triggers";
|
|
145
|
+
return currentGroup.value?.label ?? "Add node";
|
|
146
|
+
});
|
|
147
|
+
function pushPath(path) {
|
|
148
|
+
direction.value = "push";
|
|
149
|
+
stack.value = [...stack.value, path];
|
|
150
|
+
search.value = "";
|
|
151
|
+
}
|
|
152
|
+
function pushChild(label) {
|
|
153
|
+
const base = stack.value[stack.value.length - 1];
|
|
154
|
+
if (!base) return;
|
|
155
|
+
pushPath([...base, label]);
|
|
156
|
+
}
|
|
157
|
+
function popLevel() {
|
|
158
|
+
direction.value = "pop";
|
|
159
|
+
stack.value = stack.value.slice(0, -1);
|
|
160
|
+
search.value = "";
|
|
161
|
+
}
|
|
162
|
+
const levelKey = computed(() => stack.value.length);
|
|
163
|
+
const searchHits = computed(() => {
|
|
19
164
|
const q = search.value.trim().toLowerCase();
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
if (
|
|
26
|
-
|
|
27
|
-
};
|
|
28
|
-
const knownKeys = new Set(NODE_CATEGORIES.map((c) => String(c.key)));
|
|
29
|
-
const groups = NODE_CATEGORIES.map((cat) => {
|
|
30
|
-
const manifests = INTEGRATION_NODE_CATALOG.filter((m) => m.category === cat.key && matchesManifest(m));
|
|
31
|
-
const triggers = cat.key === "trigger" ? TRIGGER_TEMPLATES.filter(matchesTrigger) : [];
|
|
32
|
-
return { ...cat, manifests, triggers };
|
|
33
|
-
});
|
|
34
|
-
const other = INTEGRATION_NODE_CATALOG.filter((m) => !knownKeys.has(String(m.category ?? "")) && matchesManifest(m));
|
|
35
|
-
if (other.length) {
|
|
36
|
-
groups.push({ key: "other", label: "Nodes", color: "bg-slate-100 text-slate-500", manifests: other, triggers: [] });
|
|
165
|
+
if (!q || triggersLevel.value) return [];
|
|
166
|
+
const scope = currentGroup.value ? subtreeManifests(currentGroup.value) : latestManifests.value.filter((m) => m.category !== "trigger");
|
|
167
|
+
const hits = [];
|
|
168
|
+
for (const m of scope) {
|
|
169
|
+
const hay = `${loc(m.name)} ${m.slug} ${loc(m.description)}`.toLowerCase();
|
|
170
|
+
if (hay.includes(q)) hits.push({ manifest: m, path: groupPath(m) });
|
|
171
|
+
if (hits.length >= 50) break;
|
|
37
172
|
}
|
|
38
|
-
return
|
|
173
|
+
return hits;
|
|
39
174
|
});
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
const
|
|
44
|
-
|
|
45
|
-
|
|
175
|
+
const matchedTriggers = computed(() => {
|
|
176
|
+
const q = search.value.trim().toLowerCase();
|
|
177
|
+
if (!q || currentGroup.value) return [];
|
|
178
|
+
const matches = (t) => loc(t.name).toLowerCase().includes(q) || t.type.includes(q) || loc(t.description).toLowerCase().includes(q);
|
|
179
|
+
return TRIGGER_TEMPLATES.filter(matches);
|
|
180
|
+
});
|
|
181
|
+
const nodeDrag = useNodeDrag();
|
|
182
|
+
function setCustomDragImage(ev, label, logoSrc, accent = "#10b981") {
|
|
183
|
+
if (!ev.dataTransfer) return;
|
|
184
|
+
const el = document.createElement("div");
|
|
185
|
+
el.style.cssText = "position:fixed;top:-1000px;left:-1000px;pointer-events:none;display:flex;align-items:center;gap:8px;padding:8px 14px 8px 10px;background:#fff;border:1px solid rgba(0,0,0,.1);border-radius:10px;box-shadow:0 8px 24px rgba(15,23,42,.18);font:600 13px ui-sans-serif,system-ui;color:#0f172a;max-width:240px;";
|
|
186
|
+
if (logoSrc) {
|
|
187
|
+
const img = document.createElement("img");
|
|
188
|
+
img.src = logoSrc;
|
|
189
|
+
img.style.cssText = "width:18px;height:18px;object-fit:contain;border-radius:3px;flex:none;";
|
|
190
|
+
el.appendChild(img);
|
|
191
|
+
} else {
|
|
192
|
+
const dot = document.createElement("span");
|
|
193
|
+
dot.style.cssText = `width:10px;height:10px;border-radius:9999px;background:${accent};flex:none;`;
|
|
194
|
+
el.appendChild(dot);
|
|
195
|
+
}
|
|
196
|
+
const text = document.createElement("span");
|
|
197
|
+
text.textContent = label;
|
|
198
|
+
text.style.cssText = "white-space:nowrap;overflow:hidden;text-overflow:ellipsis;";
|
|
199
|
+
el.appendChild(text);
|
|
200
|
+
document.body.appendChild(el);
|
|
201
|
+
ev.dataTransfer.setDragImage(el, 22, 20);
|
|
202
|
+
window.setTimeout(() => el.remove(), 0);
|
|
203
|
+
}
|
|
204
|
+
function logoSrcOf(m) {
|
|
205
|
+
const imgs = m.images ?? [];
|
|
206
|
+
return (imgs.find((i) => i.category === "logo") ?? imgs[0])?.src ?? null;
|
|
46
207
|
}
|
|
47
|
-
function onManifestDragStart(
|
|
208
|
+
function onManifestDragStart(m, ev) {
|
|
48
209
|
if (!ev.dataTransfer) return;
|
|
49
|
-
ev.dataTransfer.setData("application/integration-node", JSON.stringify({
|
|
50
|
-
kind: "manifest",
|
|
51
|
-
slug: manifest.slug,
|
|
52
|
-
version: manifest.version
|
|
53
|
-
}));
|
|
210
|
+
ev.dataTransfer.setData("application/integration-node", JSON.stringify({ kind: "manifest", slug: m.slug, version: m.version }));
|
|
54
211
|
ev.dataTransfer.effectAllowed = "move";
|
|
212
|
+
setCustomDragImage(ev, loc(m.name), logoSrcOf(m), "#8b5cf6");
|
|
213
|
+
nodeDrag.start({ kind: "manifest", manifest: m });
|
|
55
214
|
}
|
|
56
215
|
function onTriggerDragStart(tpl, ev) {
|
|
57
216
|
if (!ev.dataTransfer) return;
|
|
58
|
-
ev.dataTransfer.setData("application/integration-node", JSON.stringify({
|
|
59
|
-
kind: "trigger",
|
|
60
|
-
type: tpl.type
|
|
61
|
-
}));
|
|
217
|
+
ev.dataTransfer.setData("application/integration-node", JSON.stringify({ kind: "trigger", type: tpl.type }));
|
|
62
218
|
ev.dataTransfer.effectAllowed = "move";
|
|
219
|
+
setCustomDragImage(ev, loc(tpl.name), null, "#10b981");
|
|
220
|
+
nodeDrag.start({ kind: "trigger", tpl });
|
|
221
|
+
}
|
|
222
|
+
function onDragEnd() {
|
|
223
|
+
nodeDrag.end();
|
|
224
|
+
}
|
|
225
|
+
function insertManifest(m) {
|
|
226
|
+
emit("insert", { kind: "manifest", slug: m.slug, version: m.version });
|
|
63
227
|
}
|
|
228
|
+
function insertTrigger(tpl) {
|
|
229
|
+
emit("insert", { kind: "trigger", type: tpl.type });
|
|
230
|
+
}
|
|
231
|
+
function categoryColor(label) {
|
|
232
|
+
const meta = CORE_GROUP_META[label];
|
|
233
|
+
if (meta) return meta.color;
|
|
234
|
+
const cat = NODE_CATEGORIES.find((c) => c.label === label || CORE_GROUP_BY_CATEGORY[String(c.key)] === label);
|
|
235
|
+
return cat?.color ?? "bg-slate-100 text-slate-500";
|
|
236
|
+
}
|
|
237
|
+
watch(tree, () => {
|
|
238
|
+
if (stack.value.length && !triggersLevel.value && !currentGroup.value) stack.value = [];
|
|
239
|
+
});
|
|
240
|
+
const searching = computed(() => search.value.trim().length > 0);
|
|
64
241
|
</script>
|
|
65
242
|
|
|
66
243
|
<template>
|
|
67
|
-
<aside class="flex h-full w-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
244
|
+
<aside class="flex h-full w-full flex-col bg-white">
|
|
245
|
+
<!-- Header: search + (when inside a group) the back affordance. The root
|
|
246
|
+
title lives in the editor's palette shell header, not here. -->
|
|
247
|
+
<div class="border-b border-black/[0.06] p-3">
|
|
248
|
+
<div v-if="stack.length" class="mb-2 flex min-w-0 items-center gap-1.5">
|
|
249
|
+
<button
|
|
250
|
+
type="button"
|
|
251
|
+
class="flex size-6 shrink-0 items-center justify-center rounded-md text-muted-foreground transition hover:bg-muted/50 hover:text-foreground"
|
|
252
|
+
title="Back"
|
|
253
|
+
@click="popLevel"
|
|
254
|
+
>
|
|
255
|
+
<Lucide.ArrowLeft :size="14" />
|
|
256
|
+
</button>
|
|
257
|
+
<div class="min-w-0 flex-1 truncate text-mono text-muted-foreground">
|
|
258
|
+
{{ levelTitle }}
|
|
259
|
+
</div>
|
|
71
260
|
</div>
|
|
72
261
|
<div class="relative">
|
|
73
262
|
<Lucide.Search :size="12" class="absolute left-2 top-1/2 -translate-y-1/2 text-muted-foreground" />
|
|
74
263
|
<input
|
|
264
|
+
ref="searchInput"
|
|
75
265
|
v-model="search"
|
|
76
266
|
type="text"
|
|
77
|
-
placeholder="Search
|
|
267
|
+
:placeholder="stack.length ? `Search in ${levelTitle}\u2026` : 'Search all nodes\u2026'"
|
|
78
268
|
class="h-7 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"
|
|
269
|
+
@keydown.esc="search ? search = '' : stack.length && popLevel()"
|
|
79
270
|
>
|
|
80
271
|
</div>
|
|
81
272
|
</div>
|
|
82
273
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
274
|
+
<!-- Levels slide horizontally; search results replace the level flat.
|
|
275
|
+
The transition-active classes must NOT repeat tokens from the level's
|
|
276
|
+
static class (absolute/inset-0): Vue removes active-class tokens when
|
|
277
|
+
the transition ends and would strip them from the static class too,
|
|
278
|
+
leaving the level statically positioned and unscrollable. -->
|
|
279
|
+
<div class="relative min-h-0 flex-1 overflow-hidden">
|
|
280
|
+
<Transition
|
|
281
|
+
:enter-active-class="'transition-transform duration-200 ease-out'"
|
|
282
|
+
:enter-from-class="direction === 'push' ? 'translate-x-full' : '-translate-x-full'"
|
|
283
|
+
enter-to-class="translate-x-0"
|
|
284
|
+
:leave-active-class="'transition-transform duration-200 ease-in'"
|
|
285
|
+
leave-from-class="translate-x-0"
|
|
286
|
+
:leave-to-class="direction === 'push' ? '-translate-x-full' : 'translate-x-full'"
|
|
287
|
+
>
|
|
288
|
+
<!-- scrollbar-width/color opt out of macOS overlay scrollbars, so the
|
|
289
|
+
thin scrollbar stays visible whenever the level overflows. -->
|
|
290
|
+
<div :key="`${levelKey}-${searching}`" class="absolute inset-0 overflow-y-auto overscroll-contain p-2 [scrollbar-color:rgb(0_0_0/0.22)_transparent] [scrollbar-width:thin]">
|
|
291
|
+
<!-- ── Search results (flat, path as subtitle) ─────────────────── -->
|
|
292
|
+
<template v-if="searching">
|
|
293
|
+
<div v-if="matchedTriggers.length" class="mb-1">
|
|
294
|
+
<div class="px-2 py-1 text-mono text-muted-foreground">Triggers</div>
|
|
295
|
+
<div
|
|
296
|
+
v-for="t in matchedTriggers"
|
|
297
|
+
:key="t.id"
|
|
298
|
+
class="group flex cursor-grab items-center gap-2 rounded-md border border-transparent px-2 py-1.5 transition hover:border-black/[0.08] hover:bg-muted/40 active:cursor-grabbing"
|
|
299
|
+
draggable="true"
|
|
300
|
+
@dragstart="onTriggerDragStart(t, $event)"
|
|
301
|
+
@dragend="onDragEnd"
|
|
302
|
+
@click="insertTrigger(t)"
|
|
303
|
+
>
|
|
304
|
+
<span class="flex size-6 shrink-0 items-center justify-center rounded-md bg-emerald-100 text-emerald-600">
|
|
305
|
+
<component :is="iconFor(t.icon)" :size="13" />
|
|
306
|
+
</span>
|
|
307
|
+
<div class="min-w-0">
|
|
308
|
+
<div class="truncate text-sm font-medium">{{ loc(t.name) }}</div>
|
|
309
|
+
<div class="text-xs leading-snug text-muted-foreground">Trigger</div>
|
|
310
|
+
</div>
|
|
104
311
|
</div>
|
|
105
|
-
|
|
106
|
-
|
|
312
|
+
</div>
|
|
313
|
+
|
|
314
|
+
<p v-if="!searchHits.length && !matchedTriggers.length" class="px-2 py-6 text-center text-sm text-muted-foreground">
|
|
315
|
+
Nothing matches “{{ search }}”.
|
|
316
|
+
</p>
|
|
317
|
+
<div
|
|
318
|
+
v-for="hit in searchHits"
|
|
319
|
+
:key="`${hit.manifest.slug}@${hit.manifest.version}`"
|
|
320
|
+
class="group flex cursor-grab items-start gap-2 rounded-md border border-transparent px-2 py-1.5 transition hover:border-black/[0.08] hover:bg-muted/40 active:cursor-grabbing"
|
|
321
|
+
draggable="true"
|
|
322
|
+
:title="loc(hit.manifest.name)"
|
|
323
|
+
@dragstart="onManifestDragStart(hit.manifest, $event)"
|
|
324
|
+
@dragend="onDragEnd"
|
|
325
|
+
@click="insertManifest(hit.manifest)"
|
|
326
|
+
>
|
|
327
|
+
<span class="flex size-6 shrink-0 items-center justify-center rounded-md" :class="categoryColor(hit.path[0] ?? '')">
|
|
328
|
+
<IntegrationsNodeLogo :manifest="hit.manifest" :size="13" />
|
|
329
|
+
</span>
|
|
330
|
+
<div class="min-w-0 flex-1">
|
|
331
|
+
<div class="truncate text-sm font-medium">{{ loc(hit.manifest.name) }}</div>
|
|
332
|
+
<div class="text-xs leading-snug text-muted-foreground">{{ loc(hit.manifest.description) }}</div>
|
|
333
|
+
<div class="truncate text-xs text-muted-foreground/70">{{ hit.path.join(" \u203A ") }}</div>
|
|
107
334
|
</div>
|
|
108
335
|
</div>
|
|
109
|
-
</
|
|
336
|
+
</template>
|
|
110
337
|
|
|
111
|
-
<!--
|
|
112
|
-
<
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
338
|
+
<!-- ── Triggers level ──────────────────────────────────────────── -->
|
|
339
|
+
<template v-else-if="triggersLevel">
|
|
340
|
+
<div
|
|
341
|
+
v-for="t in TRIGGER_TEMPLATES"
|
|
342
|
+
:key="t.id"
|
|
343
|
+
class="group flex cursor-grab items-center gap-2 rounded-md border border-transparent px-2 py-1.5 transition hover:border-black/[0.08] hover:bg-muted/40 active:cursor-grabbing"
|
|
344
|
+
draggable="true"
|
|
345
|
+
:title="loc(t.name)"
|
|
346
|
+
@dragstart="onTriggerDragStart(t, $event)"
|
|
347
|
+
@dragend="onDragEnd"
|
|
348
|
+
@click="insertTrigger(t)"
|
|
349
|
+
>
|
|
350
|
+
<span class="flex size-6 shrink-0 items-center justify-center rounded-md bg-emerald-100 text-emerald-600">
|
|
351
|
+
<component :is="iconFor(t.icon)" :size="13" />
|
|
352
|
+
</span>
|
|
353
|
+
<div class="min-w-0">
|
|
354
|
+
<div class="truncate text-sm font-medium">{{ loc(t.name) }}</div>
|
|
355
|
+
<div class="text-xs leading-snug text-muted-foreground">{{ loc(t.description) }}</div>
|
|
126
356
|
</div>
|
|
127
|
-
|
|
128
|
-
|
|
357
|
+
</div>
|
|
358
|
+
</template>
|
|
359
|
+
|
|
360
|
+
<!-- ── Root level ──────────────────────────────────────────────── -->
|
|
361
|
+
<template v-else-if="!currentGroup">
|
|
362
|
+
<!-- Triggers group on top -->
|
|
363
|
+
<div v-if="tree.core.children.size">
|
|
364
|
+
<div class="px-2 py-1 text-mono text-muted-foreground">Core</div>
|
|
365
|
+
<button
|
|
366
|
+
type="button"
|
|
367
|
+
class="flex w-full items-center gap-2 rounded-md border border-transparent px-2 py-1.5 text-left transition hover:border-black/[0.08] hover:bg-muted/40"
|
|
368
|
+
@click="pushPath(['__triggers'])"
|
|
369
|
+
>
|
|
370
|
+
<span class="flex size-6 shrink-0 items-center justify-center rounded-md bg-slate-100 text-emerald-600/80">
|
|
371
|
+
<Lucide.Zap :size="13" />
|
|
372
|
+
</span>
|
|
373
|
+
<span class="min-w-0 flex-1 truncate text-sm font-medium">Triggers</span>
|
|
374
|
+
<span class="text-sm tabular-nums text-muted-foreground">{{ TRIGGER_TEMPLATES.length }}</span>
|
|
375
|
+
<Lucide.ChevronRight :size="13" class="text-muted-foreground" />
|
|
376
|
+
</button>
|
|
377
|
+
<button
|
|
378
|
+
v-for="[label, group] in tree.core.children"
|
|
379
|
+
:key="`core-${label}`"
|
|
380
|
+
type="button"
|
|
381
|
+
class="flex w-full items-center gap-2 rounded-md border border-transparent px-2 py-1.5 text-left transition hover:border-black/[0.08] hover:bg-muted/40"
|
|
382
|
+
@click="pushPath(['__core', label])"
|
|
383
|
+
>
|
|
384
|
+
<span class="flex size-6 shrink-0 items-center justify-center rounded-md" :class="categoryColor(label)">
|
|
385
|
+
<component :is="coreGroupIcon(label)" :size="13" />
|
|
386
|
+
</span>
|
|
387
|
+
<span class="min-w-0 flex-1 truncate text-sm font-medium">{{ label }}</span>
|
|
388
|
+
<span class="text-sm tabular-nums text-muted-foreground">{{ group.count }}</span>
|
|
389
|
+
<Lucide.ChevronRight :size="13" class="text-muted-foreground" />
|
|
390
|
+
</button>
|
|
391
|
+
</div>
|
|
392
|
+
|
|
393
|
+
<div v-if="tree.apps.children.size" class="mt-2">
|
|
394
|
+
<div class="px-2 py-1 text-mono text-muted-foreground">Integrations</div>
|
|
395
|
+
<button
|
|
396
|
+
v-for="[label, group] in appRows"
|
|
397
|
+
:key="`app-${label}`"
|
|
398
|
+
type="button"
|
|
399
|
+
class="flex w-full items-center gap-2 rounded-md border border-transparent px-2 py-1.5 text-left transition hover:border-black/[0.08] hover:bg-muted/40"
|
|
400
|
+
@click="pushPath(['__apps', label])"
|
|
401
|
+
>
|
|
402
|
+
<span class="flex size-6 shrink-0 items-center justify-center rounded-md bg-white ring-1 ring-black/[0.06]">
|
|
403
|
+
<IntegrationsNodeLogo v-if="groupLogoManifest(group)" :manifest="groupLogoManifest(group)" :size="14" />
|
|
404
|
+
<Lucide.Package v-else :size="13" class="text-violet-600" />
|
|
405
|
+
</span>
|
|
406
|
+
<span class="min-w-0 flex-1 truncate text-sm font-medium">{{ label }}</span>
|
|
407
|
+
<span class="text-sm tabular-nums text-muted-foreground">{{ group.count }}</span>
|
|
408
|
+
<Lucide.ChevronRight :size="13" class="text-muted-foreground" />
|
|
409
|
+
</button>
|
|
410
|
+
</div>
|
|
411
|
+
</template>
|
|
412
|
+
|
|
413
|
+
<!-- ── Inside a group: subgroups first, then leaves ─────────────── -->
|
|
414
|
+
<template v-else>
|
|
415
|
+
<button
|
|
416
|
+
v-for="[label, group] in currentGroup.children"
|
|
417
|
+
:key="`sub-${label}`"
|
|
418
|
+
type="button"
|
|
419
|
+
class="flex w-full items-center gap-2 rounded-md border border-transparent px-2 py-1.5 text-left transition hover:border-black/[0.08] hover:bg-muted/40"
|
|
420
|
+
@click="pushChild(label)"
|
|
421
|
+
>
|
|
422
|
+
<span
|
|
423
|
+
class="flex size-6 shrink-0 items-center justify-center rounded-md"
|
|
424
|
+
:class="groupLogoManifest(group) ? 'bg-white ring-1 ring-black/[0.06]' : 'bg-slate-100 text-slate-500'"
|
|
425
|
+
>
|
|
426
|
+
<IntegrationsNodeLogo v-if="groupLogoManifest(group)" :manifest="groupLogoManifest(group)" :size="14" />
|
|
427
|
+
<Lucide.FolderOpen v-else :size="13" />
|
|
428
|
+
</span>
|
|
429
|
+
<span class="min-w-0 flex-1 truncate text-sm font-medium">{{ label }}</span>
|
|
430
|
+
<span class="text-sm tabular-nums text-muted-foreground">{{ group.count }}</span>
|
|
431
|
+
<Lucide.ChevronRight :size="13" class="text-muted-foreground" />
|
|
432
|
+
</button>
|
|
433
|
+
|
|
434
|
+
<div
|
|
435
|
+
v-for="m in currentGroup.leaves"
|
|
436
|
+
:key="`${m.slug}@${m.version}`"
|
|
437
|
+
class="group flex cursor-grab items-start gap-2 rounded-md border border-transparent px-2 py-1.5 transition hover:border-black/[0.08] hover:bg-muted/40 active:cursor-grabbing"
|
|
438
|
+
draggable="true"
|
|
439
|
+
:title="loc(m.name)"
|
|
440
|
+
@dragstart="onManifestDragStart(m, $event)"
|
|
441
|
+
@dragend="onDragEnd"
|
|
442
|
+
@click="insertManifest(m)"
|
|
443
|
+
>
|
|
444
|
+
<span class="flex size-6 shrink-0 items-center justify-center rounded-md" :class="hasLogo(m) ? 'bg-white ring-1 ring-black/[0.06]' : categoryColor(groupPath(m)[0] ?? '')">
|
|
445
|
+
<IntegrationsNodeLogo :manifest="m" :size="14" />
|
|
446
|
+
</span>
|
|
447
|
+
<div class="min-w-0 flex-1">
|
|
448
|
+
<div class="truncate text-sm font-medium">{{ loc(m.name) }}</div>
|
|
449
|
+
<div class="text-xs leading-snug text-muted-foreground">{{ loc(m.description) }}</div>
|
|
129
450
|
</div>
|
|
130
451
|
</div>
|
|
131
|
-
</
|
|
452
|
+
</template>
|
|
132
453
|
</div>
|
|
133
|
-
</
|
|
454
|
+
</Transition>
|
|
134
455
|
</div>
|
|
135
456
|
|
|
136
457
|
<div class="border-t border-black/[0.06] px-3 py-2 text-sm text-muted-foreground">
|
|
137
|
-
Drag
|
|
458
|
+
Drag onto the canvas — or click to insert.
|
|
138
459
|
</div>
|
|
139
460
|
</aside>
|
|
140
461
|
</template>
|
|
@@ -1,2 +1,23 @@
|
|
|
1
|
-
|
|
1
|
+
import { type TriggerTemplate } from '../../data/integrationNodeCatalog.js';
|
|
2
|
+
declare const _default: import("vue").DefineComponent<{}, {
|
|
3
|
+
focusSearch: () => void | undefined;
|
|
4
|
+
}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
5
|
+
insert: (payload: {
|
|
6
|
+
kind: "manifest";
|
|
7
|
+
slug: string;
|
|
8
|
+
version: string;
|
|
9
|
+
} | {
|
|
10
|
+
kind: "trigger";
|
|
11
|
+
type: TriggerTemplate["type"];
|
|
12
|
+
}) => any;
|
|
13
|
+
}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{
|
|
14
|
+
onInsert?: ((payload: {
|
|
15
|
+
kind: "manifest";
|
|
16
|
+
slug: string;
|
|
17
|
+
version: string;
|
|
18
|
+
} | {
|
|
19
|
+
kind: "trigger";
|
|
20
|
+
type: TriggerTemplate["type"];
|
|
21
|
+
}) => any) | undefined;
|
|
22
|
+
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
2
23
|
export default _default;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
type __VLS_Props = {
|
|
2
|
+
modelValue: unknown;
|
|
3
|
+
};
|
|
4
|
+
declare const _default: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
5
|
+
"update:modelValue": (value: unknown) => any;
|
|
6
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
7
|
+
"onUpdate:modelValue"?: ((value: unknown) => any) | undefined;
|
|
8
|
+
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
9
|
+
export default _default;
|