From 591f5ca4d873d865d3e0f44bde110e27b54bbdd3 Mon Sep 17 00:00:00 2001 From: Md Afiq Iskandar Date: Wed, 23 Apr 2025 10:47:26 +0800 Subject: [PATCH] Add Process Builder Functionality and Vue Flow Integration - Introduced a new process builder feature with a dedicated page for managing processes. - Implemented a `ProcessFlowCanvas` component utilizing Vue Flow for visual process management. - Created custom node types for the process flow, including Start, Task, Form, Gateway, Script, and End nodes. - Developed a Pinia store for managing process data, including actions for creating, updating, and deleting processes and nodes. - Added a search functionality for filtering processes and a confirmation dialog for process deletion. - Integrated responsive design adjustments for better usability across devices. - Included styles for custom nodes and flow components to enhance visual representation. - Updated navigation to include links to the new process builder and management features. --- components/process-flow/ProcessFlowCanvas.vue | 550 ++++++++++++++++++ components/process-flow/ProcessFlowNodes.js | 297 ++++++++++ navigation/index.js | 173 +++--- package.json | 4 + pages/process-builder/index.vue | 487 ++++++++++++++++ pages/process-builder/manage.vue | 244 ++++++++ plugins/process-flow-styles.client.js | 10 + stores/processBuilder.js | 363 ++++++++++++ yarn.lock | 122 ++++ 9 files changed, 2159 insertions(+), 91 deletions(-) create mode 100644 components/process-flow/ProcessFlowCanvas.vue create mode 100644 components/process-flow/ProcessFlowNodes.js create mode 100644 pages/process-builder/index.vue create mode 100644 pages/process-builder/manage.vue create mode 100644 plugins/process-flow-styles.client.js create mode 100644 stores/processBuilder.js diff --git a/components/process-flow/ProcessFlowCanvas.vue b/components/process-flow/ProcessFlowCanvas.vue new file mode 100644 index 0000000..cce5d3d --- /dev/null +++ b/components/process-flow/ProcessFlowCanvas.vue @@ -0,0 +1,550 @@ + + + + + \ No newline at end of file diff --git a/components/process-flow/ProcessFlowNodes.js b/components/process-flow/ProcessFlowNodes.js new file mode 100644 index 0000000..e796bfd --- /dev/null +++ b/components/process-flow/ProcessFlowNodes.js @@ -0,0 +1,297 @@ +import { h, markRaw } from 'vue'; +import { Handle, Position } from '@vue-flow/core'; + +// Custom node renderer +const CustomNode = markRaw({ + template: ` +
+ + +
+
+ +
+
{{ label }}
+
+ +
+
+
+ +
+ + +
+ `, + props: ['id', 'type', 'label', 'selected', 'data'], + computed: { + showBadge() { + return this.$slots.badge; + } + }, + methods: { + onClick() { + this.$emit('node-click', this.id); + } + }, + components: { + Handle + } +}); + +// Task node +export const TaskNode = markRaw({ + props: ['id', 'type', 'label', 'selected', 'data'], + render() { + return h(CustomNode, { + id: this.id, + type: 'task', + label: this.label, + selected: this.selected, + data: this.data, + onClick: () => this.$emit('node-click', this.id) + }, { + icon: () => h('i', { class: 'material-icons' }, 'assignment'), + default: () => h('div', { class: 'node-details' }, [ + h('p', { class: 'node-description' }, this.data?.description || 'Task node'), + h('div', { class: 'node-assignee' }, [ + h('span', { class: 'node-assignee-label' }, 'Assigned to: '), + h('span', { class: 'node-assignee-value' }, this.data?.assignee || 'Unassigned') + ]) + ]) + }); + } +}); + +// Start node +export const StartNode = markRaw({ + props: ['id', 'type', 'label', 'selected', 'data'], + render() { + return h(CustomNode, { + id: this.id, + type: 'start', + label: this.label || 'Start', + selected: this.selected, + data: this.data, + onClick: () => this.$emit('node-click', this.id) + }, { + icon: () => h('i', { class: 'material-icons' }, 'play_circle_filled'), + default: () => h('div', { class: 'node-details' }, [ + h('p', { class: 'node-description' }, this.data?.description || 'Process starts here') + ]) + }); + } +}); + +// End node +export const EndNode = markRaw({ + props: ['id', 'type', 'label', 'selected', 'data'], + render() { + return h(CustomNode, { + id: this.id, + type: 'end', + label: this.label || 'End', + selected: this.selected, + data: this.data, + onClick: () => this.$emit('node-click', this.id) + }, { + icon: () => h('i', { class: 'material-icons' }, 'stop_circle'), + default: () => h('div', { class: 'node-details' }, [ + h('p', { class: 'node-description' }, this.data?.description || 'Process ends here') + ]) + }); + } +}); + +// Decision/Gateway node +export const GatewayNode = markRaw({ + props: ['id', 'type', 'label', 'selected', 'data'], + render() { + return h(CustomNode, { + id: this.id, + type: 'gateway', + label: this.label || 'Decision', + selected: this.selected, + data: this.data, + onClick: () => this.$emit('node-click', this.id) + }, { + icon: () => h('i', { class: 'material-icons' }, 'call_split'), + default: () => h('div', { class: 'node-details' }, [ + h('p', { class: 'node-description' }, this.data?.description || 'Decision point'), + h('div', { class: 'node-conditions' }, [ + h('span', { class: 'node-conditions-label' }, 'Conditions: '), + h('span', { class: 'node-conditions-value' }, this.data?.conditions?.length || '0') + ]) + ]) + }); + } +}); + +// Form node +export const FormNode = markRaw({ + props: ['id', 'type', 'label', 'selected', 'data'], + render() { + return h(CustomNode, { + id: this.id, + type: 'form', + label: this.label || 'Form', + selected: this.selected, + data: this.data, + onClick: () => this.$emit('node-click', this.id) + }, { + icon: () => h('i', { class: 'material-icons' }, 'description'), + badge: () => this.data?.formId ? h('span', { class: 'node-badge' }, 'F') : null, + default: () => h('div', { class: 'node-details' }, [ + h('p', { class: 'node-description' }, this.data?.description || 'Form submission'), + h('div', { class: 'node-form-info' }, [ + h('span', { class: 'node-form-label' }, 'Form: '), + h('span', { class: 'node-form-value' }, this.data?.formName || 'None selected') + ]) + ]) + }); + } +}); + +// Script node +export const ScriptNode = markRaw({ + props: ['id', 'type', 'label', 'selected', 'data'], + render() { + return h(CustomNode, { + id: this.id, + type: 'script', + label: this.label || 'Script', + selected: this.selected, + data: this.data, + onClick: () => this.$emit('node-click', this.id) + }, { + icon: () => h('i', { class: 'material-icons' }, 'code'), + default: () => h('div', { class: 'node-details' }, [ + h('p', { class: 'node-description' }, this.data?.description || 'Script execution'), + h('div', { class: 'node-script-info' }, [ + h('span', { class: 'node-script-label' }, 'Language: '), + h('span', { class: 'node-script-value' }, this.data?.language || 'Not specified') + ]) + ]) + }); + } +}); + +// Export the node types object to use with Vue Flow +export const nodeTypes = markRaw({ + task: TaskNode, + start: StartNode, + end: EndNode, + gateway: GatewayNode, + form: FormNode, + script: ScriptNode +}); + +// Default CSS for the nodes to be imported where needed +export const nodeStyles = ` +.custom-node { + border-radius: 6px; + padding: 12px; + color: #333; + background: white; + box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1); + width: 200px; + font-size: 12px; + border: 2px solid transparent; + transition: all 0.2s; + position: relative; +} + +.custom-node.selected { + border-color: #ff6b6b; + box-shadow: 0 0 0 2px rgba(255, 107, 107, 0.2); +} + +.custom-node-header { + display: flex; + align-items: center; + margin-bottom: 8px; +} + +.custom-node-icon { + margin-right: 8px; +} + +.custom-node-icon .material-icons { + font-size: 20px; +} + +.custom-node-title { + font-weight: 500; + flex-grow: 1; +} + +.custom-node-content { + font-size: 12px; + color: #666; +} + +.node-details { + margin-top: 8px; +} + +.node-description { + margin-bottom: 4px; + color: #666; +} + +.node-assignee, +.node-form-info, +.node-script-info, +.node-conditions { + font-size: 11px; + color: #888; + display: flex; + gap: 4px; +} + +.node-badge { + background: #e2e8f0; + padding: 2px 6px; + border-radius: 4px; + font-size: 10px; + font-weight: 500; +} + +/* Node type specific styles */ +.node-start .custom-node-icon .material-icons { + color: #4CAF50; +} + +.node-end .custom-node-icon .material-icons { + color: #f44336; +} + +.node-task .custom-node-icon .material-icons { + color: #2196F3; +} + +.node-form .custom-node-icon .material-icons { + color: #9C27B0; +} + +.node-gateway .custom-node-icon .material-icons { + color: #FF9800; +} + +.node-script .custom-node-icon .material-icons { + color: #607D8B; +} +`; \ No newline at end of file diff --git a/navigation/index.js b/navigation/index.js index 251f94f..dc68702 100644 --- a/navigation/index.js +++ b/navigation/index.js @@ -1,120 +1,111 @@ export default [ { - "header": "", - "description": "", - "child": [ + header: "", + description: "", + child: [ { - "title": "Dashboard", - "path": "/dashboard", - "icon": "ic:outline-dashboard", - "child": [], - "meta": {} - } - ] + title: "Dashboard", + path: "/dashboard", + icon: "ic:outline-dashboard", + child: [], + meta: {}, + }, + ], }, { - "header": "Administration", - "description": "Manage your application", - "child": [ + header: "Administration", + description: "Manage your application", + child: [ { - "title": "Configuration", - "icon": "ic:outline-settings", - "child": [ + title: "Configuration", + icon: "ic:outline-settings", + child: [ { - "title": "Environment", - "path": "/devtool/config/environment" - } - ] + title: "Environment", + path: "/devtool/config/environment", + }, + ], }, { - "title": "Menu Editor", - "icon": "ci:menu-alt-03", - "path": "/devtool/menu-editor", - "child": [] - }, - { - "title": "Manage Users", - "path": "/devtool/user-management", - "icon": "ph:user-circle-gear", - "child": [ + title: "Manage Users", + path: "/devtool/user-management", + icon: "ph:user-circle-gear", + child: [ { - "title": "User List", - "path": "/devtool/user-management/user", - "icon": "", - "child": [] + title: "User List", + path: "/devtool/user-management/user", + icon: "", + child: [], }, { - "title": "Role List", - "path": "/devtool/user-management/role", - "icon": "", - "child": [] - } - ] + title: "Role List", + path: "/devtool/user-management/role", + icon: "", + child: [], + }, + ], }, { - "title": "Content", - "icon": "mdi:pencil-ruler", - "child": [ + title: "Content", + icon: "mdi:pencil-ruler", + child: [ { - "title": "Editor", - "path": "/devtool/content-editor" + title: "Editor", + path: "/devtool/content-editor", }, { - "title": "Template", - "path": "/devtool/content-editor/template" - } - ] + title: "Template", + path: "/devtool/content-editor/template", + }, + ], }, { - "title": "API Editor", - "path": "/devtool/api-editor", - "icon": "material-symbols:api-rounded", - "child": [] + title: "API Editor", + path: "/devtool/api-editor", + icon: "material-symbols:api-rounded", + child: [], }, { - "title": "Code Playground", - "path": "/devtool/code-playground", - "icon": "mdi:code-braces", - "child": [] + title: "Code Playground", + path: "/devtool/code-playground", + icon: "mdi:code-braces", + child: [], }, - { - "title": "Form Builder", - "path": "/form-builder/manage", - "icon": "mdi:form-select", - "child": [] - } ], - "meta": { - "auth": { - "role": [ - "Developer" - ] - } - } + meta: { + auth: { + role: ["Developer"], + }, + }, }, { - "header": "Help", - "description": "Help and documentation", - "child": [ + header: "Process Builder", + description: "Build and manage your processes", + child: [ { - "title": "Documentation", - "icon": "solar:book-bookmark-minimalistic-bold", - "path": "https://manual.corrad.ai", - "external": true + title: "Process Management", + icon: "mdi:sitemap", + child: [ + { + title: "Process Builder", + path: "/process-builder", + icon: "material-symbols:network-node", + child: [], + }, + { + title: "Process List", + path: "/process-builder/manage", + icon: "mdi:format-list-bulleted", + child: [], + }, + ], }, { - "title": "UI Components", - "icon": "material-symbols:settings-input-component-outline-rounded", - "path": "https://ui.corrad.ai", - "external": true - } + title: "Form Builder", + path: "/form-builder/manage", + icon: "mdi:form-select", + child: [], + }, ], - "meta": { - "auth": { - "role": [ - "Developer" - ] - } - } - } -]; \ No newline at end of file + }, +]; diff --git a/package.json b/package.json index 5afccef..b5d3914 100644 --- a/package.json +++ b/package.json @@ -47,6 +47,10 @@ "@prisma/client": "^5.1.1", "@shimyshack/uid": "^0.1.7", "@sweetalert2/theme-dark": "^5.0.14", + "@vue-flow/background": "^1.3.2", + "@vue-flow/controls": "^1.1.2", + "@vue-flow/core": "^1.42.5", + "@vue-flow/minimap": "^1.5.3", "@vueup/vue-quill": "^1.0.0", "@vueuse/core": "^9.5.0", "@vueuse/nuxt": "^9.5.0", diff --git a/pages/process-builder/index.vue b/pages/process-builder/index.vue new file mode 100644 index 0000000..59768ad --- /dev/null +++ b/pages/process-builder/index.vue @@ -0,0 +1,487 @@ + + + + + \ No newline at end of file diff --git a/pages/process-builder/manage.vue b/pages/process-builder/manage.vue new file mode 100644 index 0000000..9507bc5 --- /dev/null +++ b/pages/process-builder/manage.vue @@ -0,0 +1,244 @@ + + + + + \ No newline at end of file diff --git a/plugins/process-flow-styles.client.js b/plugins/process-flow-styles.client.js new file mode 100644 index 0000000..5929ec3 --- /dev/null +++ b/plugins/process-flow-styles.client.js @@ -0,0 +1,10 @@ +import { nodeStyles } from '~/components/process-flow/ProcessFlowNodes'; + +export default defineNuxtPlugin(() => { + // Create a style element + const styleEl = document.createElement('style'); + styleEl.textContent = nodeStyles; + + // Append to document head + document.head.appendChild(styleEl); +}); \ No newline at end of file diff --git a/stores/processBuilder.js b/stores/processBuilder.js new file mode 100644 index 0000000..fa398b2 --- /dev/null +++ b/stores/processBuilder.js @@ -0,0 +1,363 @@ +import { defineStore } from 'pinia'; +import { v4 as uuidv4 } from 'uuid'; + +export const useProcessBuilderStore = defineStore('processBuilder', { + state: () => ({ + processes: [], + currentProcess: null, + selectedNodeId: null, + selectedEdgeId: null, + history: [], + historyIndex: -1, + unsavedChanges: false + }), + + getters: { + /** + * Get the current process object + */ + process: (state) => { + return state.currentProcess; + }, + + /** + * Get the selected node + */ + selectedNode: (state) => { + if (!state.currentProcess || !state.selectedNodeId) return null; + return state.currentProcess.nodes.find(node => node.id === state.selectedNodeId); + }, + + /** + * Get the selected edge + */ + selectedEdge: (state) => { + if (!state.currentProcess || !state.selectedEdgeId) return null; + return state.currentProcess.edges.find(edge => edge.id === state.selectedEdgeId); + }, + + /** + * Check if there are unsaved changes + */ + hasUnsavedChanges: (state) => { + return state.unsavedChanges; + }, + + /** + * Check if undo is available + */ + canUndo: (state) => { + return state.historyIndex > 0; + }, + + /** + * Check if redo is available + */ + canRedo: (state) => { + return state.historyIndex < state.history.length - 1; + } + }, + + actions: { + /** + * Create a new process + */ + createProcess(name, description = '') { + const newProcess = { + id: uuidv4(), + name, + description, + createdAt: new Date().toISOString(), + updatedAt: new Date().toISOString(), + nodes: [], + edges: [] + }; + + this.processes.push(newProcess); + this.setCurrentProcess(newProcess.id); + this.saveToHistory('Create process'); + this.unsavedChanges = true; + + return newProcess; + }, + + /** + * Load a process + */ + loadProcess(processId) { + const process = this.processes.find(p => p.id === processId); + if (process) { + this.currentProcess = JSON.parse(JSON.stringify(process)); // Deep clone + this.selectedNodeId = null; + this.selectedEdgeId = null; + this.clearHistory(); + this.unsavedChanges = false; + } + }, + + /** + * Set the current process + */ + setCurrentProcess(processId) { + const process = this.processes.find(p => p.id === processId); + if (process) { + this.currentProcess = JSON.parse(JSON.stringify(process)); // Deep clone + this.selectedNodeId = null; + this.selectedEdgeId = null; + this.clearHistory(); + this.unsavedChanges = false; + } + }, + + /** + * Save the current process + */ + saveProcess() { + if (!this.currentProcess) return; + + const index = this.processes.findIndex(p => p.id === this.currentProcess.id); + if (index !== -1) { + this.currentProcess.updatedAt = new Date().toISOString(); + this.processes[index] = JSON.parse(JSON.stringify(this.currentProcess)); // Deep clone + this.unsavedChanges = false; + } + }, + + /** + * Delete a process + */ + deleteProcess(processId) { + const index = this.processes.findIndex(p => p.id === processId); + if (index !== -1) { + this.processes.splice(index, 1); + if (this.currentProcess && this.currentProcess.id === processId) { + this.currentProcess = null; + this.selectedNodeId = null; + this.selectedEdgeId = null; + this.clearHistory(); + } + } + }, + + /** + * Add a node to the current process + */ + addNode(node) { + if (!this.currentProcess) return; + + const newNode = { + id: node.id || uuidv4(), + type: node.type, + label: node.label || 'New Node', + position: node.position || { x: 0, y: 0 }, + data: node.data || {} + }; + + this.currentProcess.nodes.push(newNode); + this.selectedNodeId = newNode.id; + this.saveToHistory('Add node'); + this.unsavedChanges = true; + + return newNode; + }, + + /** + * Update a node in the current process + */ + updateNode(nodeId, updates) { + if (!this.currentProcess) return; + + const node = this.currentProcess.nodes.find(n => n.id === nodeId); + if (node) { + Object.assign(node, updates); + this.saveToHistory('Update node'); + this.unsavedChanges = true; + } + }, + + /** + * Delete a node from the current process + */ + deleteNode(nodeId) { + if (!this.currentProcess) return; + + const index = this.currentProcess.nodes.findIndex(n => n.id === nodeId); + if (index !== -1) { + this.currentProcess.nodes.splice(index, 1); + + // Remove any edges connected to this node + this.currentProcess.edges = this.currentProcess.edges.filter( + edge => edge.source !== nodeId && edge.target !== nodeId + ); + + if (this.selectedNodeId === nodeId) { + this.selectedNodeId = null; + } + + this.saveToHistory('Delete node'); + this.unsavedChanges = true; + } + }, + + /** + * Add an edge to the current process + */ + addEdge(edge) { + if (!this.currentProcess) return; + + const newEdge = { + id: edge.id || `${edge.source}-${edge.target}`, + source: edge.source, + target: edge.target, + label: edge.label || '', + type: edge.type || 'default', + animated: edge.animated !== undefined ? edge.animated : true, + data: edge.data || {} + }; + + this.currentProcess.edges.push(newEdge); + this.selectedEdgeId = newEdge.id; + this.saveToHistory('Add edge'); + this.unsavedChanges = true; + + return newEdge; + }, + + /** + * Update an edge in the current process + */ + updateEdge(edgeId, updates) { + if (!this.currentProcess) return; + + const edge = this.currentProcess.edges.find(e => e.id === edgeId); + if (edge) { + Object.assign(edge, updates); + this.saveToHistory('Update edge'); + this.unsavedChanges = true; + } + }, + + /** + * Delete an edge from the current process + */ + deleteEdge(edgeId) { + if (!this.currentProcess) return; + + const index = this.currentProcess.edges.findIndex(e => e.id === edgeId); + if (index !== -1) { + this.currentProcess.edges.splice(index, 1); + + if (this.selectedEdgeId === edgeId) { + this.selectedEdgeId = null; + } + + this.saveToHistory('Delete edge'); + this.unsavedChanges = true; + } + }, + + /** + * Update node positions after drag + */ + updateNodePositions(nodePositions) { + if (!this.currentProcess) return; + + Object.entries(nodePositions).forEach(([nodeId, position]) => { + const node = this.currentProcess.nodes.find(n => n.id === nodeId); + if (node) { + node.position = position; + } + }); + + this.saveToHistory('Move nodes'); + this.unsavedChanges = true; + }, + + /** + * Select a node + */ + selectNode(nodeId) { + this.selectedNodeId = nodeId; + this.selectedEdgeId = null; + }, + + /** + * Select an edge + */ + selectEdge(edgeId) { + this.selectedEdgeId = edgeId; + this.selectedNodeId = null; + }, + + /** + * Clear selection + */ + clearSelection() { + this.selectedNodeId = null; + this.selectedEdgeId = null; + }, + + /** + * Save the current state to history + */ + saveToHistory(actionName) { + // Remove any future states if we're in the middle of the history + if (this.historyIndex < this.history.length - 1) { + this.history = this.history.slice(0, this.historyIndex + 1); + } + + // Add current state to history + this.history.push({ + state: JSON.parse(JSON.stringify(this.currentProcess)), + action: actionName, + timestamp: new Date().toISOString() + }); + + // Move history pointer + this.historyIndex = this.history.length - 1; + + // Limit history size + if (this.history.length > 50) { + this.history.shift(); + this.historyIndex--; + } + }, + + /** + * Undo the last action + */ + undo() { + if (this.historyIndex > 0) { + this.historyIndex--; + this.currentProcess = JSON.parse(JSON.stringify(this.history[this.historyIndex].state)); + this.unsavedChanges = true; + } + }, + + /** + * Redo the last undone action + */ + redo() { + if (this.historyIndex < this.history.length - 1) { + this.historyIndex++; + this.currentProcess = JSON.parse(JSON.stringify(this.history[this.historyIndex].state)); + this.unsavedChanges = true; + } + }, + + /** + * Clear history + */ + clearHistory() { + this.history = []; + if (this.currentProcess) { + this.history.push({ + state: JSON.parse(JSON.stringify(this.currentProcess)), + action: 'Initial state', + timestamp: new Date().toISOString() + }); + } + this.historyIndex = 0; + } + } +}); \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index 95a205d..959765f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2335,6 +2335,11 @@ resolved "https://registry.yarnpkg.com/@types/web-bluetooth/-/web-bluetooth-0.0.16.tgz#1d12873a8e49567371f2a75fe3e7f7edca6662d8" integrity sha512-oh8q2Zc32S6gd/j50GowEjKLoOVOwHP/bWVjKJInBwQqdOYMdPrf1oVlelTlyfFK3CKxL1uahMDAr+vy8T7yMQ== +"@types/web-bluetooth@^0.0.20": + version "0.0.20" + resolved "https://registry.yarnpkg.com/@types/web-bluetooth/-/web-bluetooth-0.0.20.tgz#f066abfcd1cbe66267cdbbf0de010d8a41b41597" + integrity sha512-g9gZnnXVq7gM7v3tJCWV/qw7w+KeOlSHAhgF9RytFyifW6AF61hdT2ucrYhPq9hLs5JIryeupHV3qGk95dH9ow== + "@typescript-eslint/eslint-plugin@~5.37.0": version "5.37.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.37.0.tgz#5ccdd5d9004120f28fc6e717fb4b5c9bddcfbc04" @@ -2544,6 +2549,34 @@ resolved "https://registry.yarnpkg.com/@vitejs/plugin-vue/-/plugin-vue-4.2.3.tgz#ee0b6dfcc62fe65364e6395bf38fa2ba10bb44b6" integrity sha512-R6JDUfiZbJA9cMiguQ7jxALsgiprjBeHL5ikpXfJCH62pPHtI+JdJ5xWj6Ev73yXSlYl86+blXn1kZHQ7uElxw== +"@vue-flow/background@^1.3.2": + version "1.3.2" + resolved "https://registry.yarnpkg.com/@vue-flow/background/-/background-1.3.2.tgz#0c90cd05e5d60da017bbaf5a1c3eb6af7ed9b778" + integrity sha512-eJPhDcLj1wEo45bBoqTXw1uhl0yK2RaQGnEINqvvBsAFKh/camHJd5NPmOdS1w+M9lggc9igUewxaEd3iCQX2w== + +"@vue-flow/controls@^1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@vue-flow/controls/-/controls-1.1.2.tgz#d71899ed793f741400d043efdd49765a3a94c75f" + integrity sha512-6dtl/JnwDBNau5h3pDBdOCK6tdxiVAOL3cyruRL61gItwq5E97Hmjmj2BIIqX2p7gU1ENg3z80Z4zlu58fGlsg== + +"@vue-flow/core@^1.42.5": + version "1.42.5" + resolved "https://registry.yarnpkg.com/@vue-flow/core/-/core-1.42.5.tgz#c4bd1d1b1fafd6e3c1807bbfe2124111c82b0e14" + integrity sha512-fNaBzt5i/JYHIzfmR4wtT1TkpfZBgB+Pe/LjCG+aXdNOpeveuegv3AmEcU3GFqf/uYrd1rsma877Lncu1uwz1w== + dependencies: + "@vueuse/core" "^10.5.0" + d3-drag "^3.0.0" + d3-selection "^3.0.0" + d3-zoom "^3.0.0" + +"@vue-flow/minimap@^1.5.3": + version "1.5.3" + resolved "https://registry.yarnpkg.com/@vue-flow/minimap/-/minimap-1.5.3.tgz#de0a6031668c94874e6d66d7830c7ba05c366c88" + integrity sha512-w8VQc8orPdzfstIPI4/u6H7qlc/uVM1W6b5Upd5NQi0+S9seYl3CiUrzO9liW/f8Fuvr5oHVQg0X6nn2K083rA== + dependencies: + d3-selection "^3.0.0" + d3-zoom "^3.0.0" + "@vue-macros/common@^1.3.1": version "1.7.0" resolved "https://registry.yarnpkg.com/@vue-macros/common/-/common-1.7.0.tgz#67e4ee8831ad70383c9496cebeb23850e6a6e3c5" @@ -2698,6 +2731,21 @@ "@vueuse/shared" "9.13.0" vue-demi "*" +"@vueuse/core@^10.5.0": + version "10.11.1" + resolved "https://registry.yarnpkg.com/@vueuse/core/-/core-10.11.1.tgz#15d2c0b6448d2212235b23a7ba29c27173e0c2c6" + integrity sha512-guoy26JQktXPcz+0n3GukWIy/JDNKti9v6VEMu6kV2sYBsWuGiTU8OWdg+ADfUbHg3/3DlqySDe7JmdHrktiww== + dependencies: + "@types/web-bluetooth" "^0.0.20" + "@vueuse/metadata" "10.11.1" + "@vueuse/shared" "10.11.1" + vue-demi ">=0.14.8" + +"@vueuse/metadata@10.11.1": + version "10.11.1" + resolved "https://registry.yarnpkg.com/@vueuse/metadata/-/metadata-10.11.1.tgz#209db7bb5915aa172a87510b6de2ca01cadbd2a7" + integrity sha512-IGa5FXd003Ug1qAZmyE8wF3sJ81xGLSqTqtQ6jaVfkeZ4i5kS2mwQF61yhVqojRnenVew5PldLyRgvdl4YYuSw== + "@vueuse/metadata@9.13.0": version "9.13.0" resolved "https://registry.yarnpkg.com/@vueuse/metadata/-/metadata-9.13.0.tgz#bc25a6cdad1b1a93c36ce30191124da6520539ff" @@ -2714,6 +2762,13 @@ local-pkg "^0.4.3" vue-demi "*" +"@vueuse/shared@10.11.1": + version "10.11.1" + resolved "https://registry.yarnpkg.com/@vueuse/shared/-/shared-10.11.1.tgz#62b84e3118ae6e1f3ff38f4fbe71b0c5d0f10938" + integrity sha512-LHpC8711VFZlDaYUXEBbFBCQ7GS3dVU9mjOhhMhXP6txTV4EhYQg/KGnQuvt/sPAtoUKq7VVUnL6mVtFoL42sA== + dependencies: + vue-demi ">=0.14.8" + "@vueuse/shared@9.13.0": version "9.13.0" resolved "https://registry.yarnpkg.com/@vueuse/shared/-/shared-9.13.0.tgz#089ff4cc4e2e7a4015e57a8f32e4b39d096353b9" @@ -3793,6 +3848,68 @@ cuint@^0.2.2: resolved "https://registry.yarnpkg.com/cuint/-/cuint-0.2.2.tgz#408086d409550c2631155619e9fa7bcadc3b991b" integrity sha512-d4ZVpCW31eWwCMe1YT3ur7mUDnTXbgwyzaL320DrcRT45rfjYxkt5QWLrmOJ+/UEAI2+fQgKe/fCjR8l4TpRgw== +"d3-color@1 - 3": + version "3.1.0" + resolved "https://registry.yarnpkg.com/d3-color/-/d3-color-3.1.0.tgz#395b2833dfac71507f12ac2f7af23bf819de24e2" + integrity sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA== + +"d3-dispatch@1 - 3": + version "3.0.1" + resolved "https://registry.yarnpkg.com/d3-dispatch/-/d3-dispatch-3.0.1.tgz#5fc75284e9c2375c36c839411a0cf550cbfc4d5e" + integrity sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg== + +"d3-drag@2 - 3", d3-drag@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/d3-drag/-/d3-drag-3.0.0.tgz#994aae9cd23c719f53b5e10e3a0a6108c69607ba" + integrity sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg== + dependencies: + d3-dispatch "1 - 3" + d3-selection "3" + +"d3-ease@1 - 3": + version "3.0.1" + resolved "https://registry.yarnpkg.com/d3-ease/-/d3-ease-3.0.1.tgz#9658ac38a2140d59d346160f1f6c30fda0bd12f4" + integrity sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w== + +"d3-interpolate@1 - 3": + version "3.0.1" + resolved "https://registry.yarnpkg.com/d3-interpolate/-/d3-interpolate-3.0.1.tgz#3c47aa5b32c5b3dfb56ef3fd4342078a632b400d" + integrity sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g== + dependencies: + d3-color "1 - 3" + +"d3-selection@2 - 3", d3-selection@3, d3-selection@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/d3-selection/-/d3-selection-3.0.0.tgz#c25338207efa72cc5b9bd1458a1a41901f1e1b31" + integrity sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ== + +"d3-timer@1 - 3": + version "3.0.1" + resolved "https://registry.yarnpkg.com/d3-timer/-/d3-timer-3.0.1.tgz#6284d2a2708285b1abb7e201eda4380af35e63b0" + integrity sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA== + +"d3-transition@2 - 3": + version "3.0.1" + resolved "https://registry.yarnpkg.com/d3-transition/-/d3-transition-3.0.1.tgz#6869fdde1448868077fdd5989200cb61b2a1645f" + integrity sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w== + dependencies: + d3-color "1 - 3" + d3-dispatch "1 - 3" + d3-ease "1 - 3" + d3-interpolate "1 - 3" + d3-timer "1 - 3" + +d3-zoom@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/d3-zoom/-/d3-zoom-3.0.0.tgz#d13f4165c73217ffeaa54295cd6969b3e7aee8f3" + integrity sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw== + dependencies: + d3-dispatch "1 - 3" + d3-drag "2 - 3" + d3-interpolate "1 - 3" + d3-selection "2 - 3" + d3-transition "2 - 3" + damerau-levenshtein@^1.0.8: version "1.0.8" resolved "https://registry.yarnpkg.com/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz#b43d286ccbd36bc5b2f7ed41caf2d0aba1f8a6e7" @@ -9221,6 +9338,11 @@ vue-demi@*, vue-demi@>=0.14.5: resolved "https://registry.yarnpkg.com/vue-demi/-/vue-demi-0.14.5.tgz#676d0463d1a1266d5ab5cba932e043d8f5f2fbd9" integrity sha512-o9NUVpl/YlsGJ7t+xuqJKx8EBGf1quRhCiT6D/J0pfwmk9zUwYkC7yrF4SZCe6fETvSM3UNL2edcbYrSyc4QHA== +vue-demi@>=0.14.8: + version "0.14.10" + resolved "https://registry.yarnpkg.com/vue-demi/-/vue-demi-0.14.10.tgz#afc78de3d6f9e11bf78c55e8510ee12814522f04" + integrity sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg== + vue-devtools-stub@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/vue-devtools-stub/-/vue-devtools-stub-0.1.0.tgz#a65b9485edecd4273cedcb8102c739b83add2c81"