Add Validation System Test Guide and Enhance Validation Panel Functionality
- Introduced a new `validation-test-guide.md` file detailing the testing process for the node validation system, including test cases and expected outcomes. - Updated `ProcessFlowCanvas.vue` to integrate a collapsible validation panel, allowing users to toggle visibility and view validation statuses and issues in real-time. - Enhanced the validation indicators and tooltips in `ValidationIndicator.vue` and `ValidationTooltip.vue` to provide clearer feedback on validation issues with improved styling and severity color coding. - Removed the deprecated `vue-flow-custom-nodes-migration.md` and `vue-flow-migration-completed-final.md` documentation files to streamline project documentation. - Adjusted styles in `ValidationTooltip.vue` for better visibility and user experience, ensuring tooltips are informative and visually distinct based on severity. - Updated `index.vue` to ensure proper text color inheritance for custom nodes, enhancing overall UI consistency.
This commit is contained in:
parent
8f56505af1
commit
f4eff35c4b
@ -15,6 +15,7 @@ import { Controls } from "@vue-flow/controls";
|
||||
import { MiniMap } from "@vue-flow/minimap";
|
||||
import InteractiveArrowEdge from "./InteractiveArrowEdge.vue";
|
||||
import { useNodeValidation } from '~/composables/useNodeValidation';
|
||||
import { useProcessBuilderStore } from '~/stores/processBuilder';
|
||||
// Import all file-based custom node components
|
||||
import StartNode from "~/components/process-flow/custom/StartNode.vue";
|
||||
import EndNode from "~/components/process-flow/custom/EndNode.vue";
|
||||
@ -107,6 +108,9 @@ const {
|
||||
clearValidation
|
||||
} = useNodeValidation();
|
||||
|
||||
// Initialize process store for validation updates
|
||||
const processStore = useProcessBuilderStore();
|
||||
|
||||
// Initialize Vue Flow
|
||||
const {
|
||||
nodes,
|
||||
@ -200,6 +204,14 @@ const toggleHelpGuide = () => {
|
||||
showHelpGuide.value = !showHelpGuide.value;
|
||||
};
|
||||
|
||||
// Validation panel state
|
||||
const showValidationPanel = ref(true);
|
||||
|
||||
// Toggle validation panel
|
||||
const toggleValidationPanel = () => {
|
||||
showValidationPanel.value = !showValidationPanel.value;
|
||||
};
|
||||
|
||||
// State management for preventing recursive updates
|
||||
const isUpdatingNodes = ref(false);
|
||||
const isUpdatingEdges = ref(false);
|
||||
@ -753,11 +765,19 @@ watch(
|
||||
// Debounce validation to avoid excessive re-computation
|
||||
clearTimeout(validationTimeout.value);
|
||||
validationTimeout.value = setTimeout(() => {
|
||||
validateProcess(currentNodes, currentEdges || []);
|
||||
const issues = validateProcess(currentNodes, currentEdges || []);
|
||||
|
||||
// Update the process store with validation results
|
||||
processStore.updateValidationResults(
|
||||
validationResults.value,
|
||||
validationSummary.value,
|
||||
overallValidationStatus.value
|
||||
);
|
||||
}, 300);
|
||||
} else {
|
||||
// Clear validation if no nodes
|
||||
clearValidation();
|
||||
processStore.clearValidationResults();
|
||||
}
|
||||
},
|
||||
{ deep: true }
|
||||
@ -1961,51 +1981,66 @@ function fromObject(flowObject) {
|
||||
</div>
|
||||
</Panel>
|
||||
|
||||
<!-- Validation Panel -->
|
||||
<!-- Collapsible Validation Panel -->
|
||||
<Panel position="top-left" class="validation-panel">
|
||||
<div class="validation-panel-content">
|
||||
<div class="flex items-center justify-between mb-2">
|
||||
<h4 class="validation-title">Process Validation</h4>
|
||||
<div class="validation-status" :class="overallValidationStatus">
|
||||
<Icon
|
||||
:name="overallValidationStatus === 'error' ? 'material-symbols:error' :
|
||||
overallValidationStatus === 'warning' ? 'material-symbols:warning' :
|
||||
'material-symbols:check-circle'"
|
||||
class="w-4 h-4"
|
||||
/>
|
||||
<span class="status-text">
|
||||
{{ overallValidationStatus === 'error' ? 'Errors' :
|
||||
overallValidationStatus === 'warning' ? 'Warnings' : 'Valid' }}
|
||||
<button
|
||||
@click="toggleValidationPanel"
|
||||
class="validation-toggle-btn"
|
||||
:class="{ 'expanded': showValidationPanel }"
|
||||
>
|
||||
<Icon
|
||||
:name="processStore.overallValidationStatus === 'error' ? 'material-symbols:error' :
|
||||
processStore.overallValidationStatus === 'warning' ? 'material-symbols:warning' :
|
||||
'material-symbols:check-circle'"
|
||||
class="w-4 h-4"
|
||||
/>
|
||||
<span v-if="showValidationPanel">Hide Validation</span>
|
||||
<span v-else>
|
||||
Validation
|
||||
<span v-if="processStore.validationSummary.totalIssues > 0" class="inline-badge">
|
||||
{{ processStore.validationSummary.totalIssues }}
|
||||
</span>
|
||||
</span>
|
||||
</button>
|
||||
|
||||
<div v-if="showValidationPanel" class="validation-content">
|
||||
<div class="validation-header">
|
||||
<div class="validation-status" :class="processStore.overallValidationStatus">
|
||||
<span class="status-text">
|
||||
{{ processStore.overallValidationStatus === 'error' ? 'Errors Found' :
|
||||
processStore.overallValidationStatus === 'warning' ? 'Warnings Found' : 'All Valid' }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="validationSummary.totalIssues > 0" class="validation-summary">
|
||||
<div class="summary-stats">
|
||||
<span v-if="validationSummary.errors > 0" class="stat-item error">
|
||||
{{ validationSummary.errors }} error{{ validationSummary.errors > 1 ? 's' : '' }}
|
||||
</span>
|
||||
<span v-if="validationSummary.warnings > 0" class="stat-item warning">
|
||||
{{ validationSummary.warnings }} warning{{ validationSummary.warnings > 1 ? 's' : '' }}
|
||||
</span>
|
||||
<span v-if="validationSummary.infos > 0" class="stat-item info">
|
||||
{{ validationSummary.infos }} info{{ validationSummary.infos > 1 ? 's' : '' }}
|
||||
</span>
|
||||
|
||||
<div v-if="processStore.validationSummary.totalIssues > 0" class="validation-summary">
|
||||
<div class="summary-stats">
|
||||
<span v-if="processStore.validationSummary.errors > 0" class="stat-item error">
|
||||
{{ processStore.validationSummary.errors }} error{{ processStore.validationSummary.errors > 1 ? 's' : '' }}
|
||||
</span>
|
||||
<span v-if="processStore.validationSummary.warnings > 0" class="stat-item warning">
|
||||
{{ processStore.validationSummary.warnings }} warning{{ processStore.validationSummary.warnings > 1 ? 's' : '' }}
|
||||
</span>
|
||||
<span v-if="processStore.validationSummary.infos > 0" class="stat-item info">
|
||||
{{ processStore.validationSummary.infos }} info{{ processStore.validationSummary.infos > 1 ? 's' : '' }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-else-if="nodes.length > 0" class="validation-success">
|
||||
<Icon name="material-symbols:check-circle" class="w-4 h-4 text-green-500" />
|
||||
<span class="text-green-600 text-sm">Process validation passed</span>
|
||||
</div>
|
||||
|
||||
<div v-else class="validation-empty">
|
||||
<span class="text-gray-500 text-sm">Add nodes to validate process</span>
|
||||
</div>
|
||||
|
||||
<div v-if="isValidating" class="validation-loading">
|
||||
<Icon name="material-symbols:refresh" class="w-4 h-4 animate-spin" />
|
||||
<span class="text-sm text-gray-600">Validating...</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-else-if="nodes.length > 0" class="validation-success">
|
||||
<Icon name="material-symbols:check-circle" class="w-4 h-4 text-green-500" />
|
||||
<span class="text-green-600 text-sm">Process validation passed</span>
|
||||
</div>
|
||||
|
||||
<div v-else class="validation-empty">
|
||||
<span class="text-gray-500 text-sm">Add nodes to validate process</span>
|
||||
</div>
|
||||
|
||||
<div v-if="isValidating" class="validation-loading">
|
||||
<Icon name="material-symbols:refresh" class="w-4 h-4 animate-spin" />
|
||||
<span class="text-sm text-gray-600">Validating...</span>
|
||||
</div>
|
||||
</div>
|
||||
</Panel>
|
||||
@ -2404,26 +2439,69 @@ function fromObject(flowObject) {
|
||||
background: white;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
||||
padding: 12px;
|
||||
min-width: 220px;
|
||||
overflow: hidden;
|
||||
max-width: 280px;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.validation-title {
|
||||
.validation-toggle-btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 8px 12px;
|
||||
background: #059669;
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 6px;
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
color: #374151;
|
||||
margin: 0;
|
||||
font-weight: 500;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease;
|
||||
white-space: nowrap;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.validation-toggle-btn:hover {
|
||||
background: #047857;
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
.validation-toggle-btn.expanded {
|
||||
background: #dc2626;
|
||||
}
|
||||
|
||||
.validation-toggle-btn.expanded:hover {
|
||||
background: #b91c1c;
|
||||
}
|
||||
|
||||
.inline-badge {
|
||||
background: rgba(255, 255, 255, 0.3);
|
||||
padding: 2px 6px;
|
||||
border-radius: 10px;
|
||||
font-size: 10px;
|
||||
margin-left: 4px;
|
||||
}
|
||||
|
||||
.validation-content {
|
||||
padding: 12px;
|
||||
background: white;
|
||||
border-top: 1px solid #e5e7eb;
|
||||
}
|
||||
|
||||
.validation-header {
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.validation-status {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
gap: 6px;
|
||||
font-size: 11px;
|
||||
font-weight: 500;
|
||||
padding: 2px 6px;
|
||||
padding: 4px 8px;
|
||||
border-radius: 4px;
|
||||
background: #f9fafb;
|
||||
border: 1px solid #e5e7eb;
|
||||
}
|
||||
|
||||
.validation-status.error {
|
||||
|
@ -77,50 +77,40 @@ const severityClass = computed(() => {
|
||||
|
||||
const severityColorClass = computed(() => {
|
||||
switch (validationSeverity.value) {
|
||||
case 'error': return 'text-red-500'
|
||||
case 'warning': return 'text-yellow-500'
|
||||
case 'info': return 'text-blue-500'
|
||||
case 'error': return '!text-red-500'
|
||||
case 'warning': return '!text-yellow-500'
|
||||
case 'info': return '!text-blue-500'
|
||||
default: return ''
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ValidationTooltip
|
||||
v-if="hasIssues && showTooltip"
|
||||
:content="validationTooltip"
|
||||
position="top"
|
||||
>
|
||||
<div
|
||||
class="validation-indicator"
|
||||
:class="severityClass"
|
||||
>
|
||||
<i
|
||||
:class="[validationIcon, severityColorClass]"
|
||||
class="validation-icon"
|
||||
></i>
|
||||
|
||||
<!-- Badge with issue count -->
|
||||
<span
|
||||
v-if="validationIssues.length > 1"
|
||||
class="validation-badge"
|
||||
:class="severityClass"
|
||||
>
|
||||
{{ validationIssues.length }}
|
||||
</span>
|
||||
</div>
|
||||
</ValidationTooltip>
|
||||
|
||||
<!-- Fallback without tooltip -->
|
||||
<div
|
||||
v-else-if="hasIssues"
|
||||
v-if="hasIssues"
|
||||
class="validation-indicator"
|
||||
:class="severityClass"
|
||||
>
|
||||
<i
|
||||
:class="[validationIcon, severityColorClass]"
|
||||
<ValidationTooltip
|
||||
v-if="showTooltip"
|
||||
:content="validationTooltip"
|
||||
:severity="validationSeverity"
|
||||
position="top"
|
||||
>
|
||||
<Icon
|
||||
:name="validationIcon"
|
||||
:class="severityColorClass"
|
||||
class="validation-icon"
|
||||
></Icon>
|
||||
</ValidationTooltip>
|
||||
|
||||
<!-- Fallback without tooltip -->
|
||||
<Icon
|
||||
v-else
|
||||
:name="validationIcon"
|
||||
:class="severityColorClass"
|
||||
class="validation-icon"
|
||||
></i>
|
||||
></Icon>
|
||||
|
||||
<!-- Badge with issue count -->
|
||||
<span
|
||||
|
@ -9,6 +9,10 @@ const props = defineProps({
|
||||
position: {
|
||||
type: String,
|
||||
default: 'top' // top, bottom, left, right
|
||||
},
|
||||
severity: {
|
||||
type: String,
|
||||
default: 'info' // error, warning, info
|
||||
}
|
||||
})
|
||||
|
||||
@ -19,6 +23,15 @@ const positionClass = computed(() => {
|
||||
return `tooltip-${props.position}`
|
||||
})
|
||||
|
||||
const severityClass = computed(() => {
|
||||
return `tooltip-${props.severity}`
|
||||
})
|
||||
|
||||
// Format content with colored text for different sections
|
||||
const formattedContent = computed(() => {
|
||||
return props.content
|
||||
})
|
||||
|
||||
const onMouseEnter = () => {
|
||||
showTooltip.value = true
|
||||
}
|
||||
@ -40,10 +53,10 @@ const onMouseLeave = () => {
|
||||
v-if="showTooltip && content"
|
||||
ref="tooltipRef"
|
||||
class="tooltip"
|
||||
:class="positionClass"
|
||||
:class="[positionClass, severityClass]"
|
||||
>
|
||||
<div class="tooltip-content">
|
||||
<pre class="tooltip-text">{{ content }}</pre>
|
||||
<pre class="tooltip-text">{{ formattedContent }}</pre>
|
||||
</div>
|
||||
<div class="tooltip-arrow"></div>
|
||||
</div>
|
||||
@ -53,20 +66,23 @@ const onMouseLeave = () => {
|
||||
<style scoped>
|
||||
.tooltip-container {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.tooltip {
|
||||
position: absolute;
|
||||
z-index: 9999;
|
||||
background: #1f2937;
|
||||
color: white;
|
||||
border-radius: 6px;
|
||||
padding: 8px 12px;
|
||||
background: white;
|
||||
color: #374151;
|
||||
border: 1px solid #d1d5db;
|
||||
border-radius: 8px;
|
||||
padding: 10px 12px;
|
||||
font-size: 12px;
|
||||
white-space: nowrap;
|
||||
max-width: 300px;
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
||||
max-width: 280px;
|
||||
box-shadow: 0 10px 25px rgba(0, 0, 0, 0.1), 0 4px 6px rgba(0, 0, 0, 0.05);
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
@ -75,15 +91,16 @@ const onMouseLeave = () => {
|
||||
white-space: pre-line;
|
||||
font-family: inherit;
|
||||
font-size: 11px;
|
||||
line-height: 1.4;
|
||||
line-height: 1.5;
|
||||
color: #374151;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
/* Position variants */
|
||||
.tooltip-top {
|
||||
bottom: 100%;
|
||||
bottom: calc(100% + 8px);
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.tooltip-bottom {
|
||||
@ -114,13 +131,30 @@ const onMouseLeave = () => {
|
||||
height: 0;
|
||||
}
|
||||
|
||||
.tooltip-arrow::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
width: 0;
|
||||
height: 0;
|
||||
}
|
||||
|
||||
.tooltip-top .tooltip-arrow {
|
||||
top: 100%;
|
||||
top: calc(100% - 1px);
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
border-left: 6px solid transparent;
|
||||
border-right: 6px solid transparent;
|
||||
border-top: 6px solid #1f2937;
|
||||
border-top: 6px solid white;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.tooltip-top .tooltip-arrow::before {
|
||||
top: -7px;
|
||||
left: -6px;
|
||||
border-left: 6px solid transparent;
|
||||
border-right: 6px solid transparent;
|
||||
border-top: 6px solid #d1d5db;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.tooltip-bottom .tooltip-arrow {
|
||||
@ -129,7 +163,7 @@ const onMouseLeave = () => {
|
||||
transform: translateX(-50%);
|
||||
border-left: 6px solid transparent;
|
||||
border-right: 6px solid transparent;
|
||||
border-bottom: 6px solid #1f2937;
|
||||
border-bottom: 6px solid white;
|
||||
}
|
||||
|
||||
.tooltip-left .tooltip-arrow {
|
||||
@ -138,7 +172,7 @@ const onMouseLeave = () => {
|
||||
transform: translateY(-50%);
|
||||
border-top: 6px solid transparent;
|
||||
border-bottom: 6px solid transparent;
|
||||
border-left: 6px solid #1f2937;
|
||||
border-left: 6px solid white;
|
||||
}
|
||||
|
||||
.tooltip-right .tooltip-arrow {
|
||||
@ -147,7 +181,33 @@ const onMouseLeave = () => {
|
||||
transform: translateY(-50%);
|
||||
border-top: 6px solid transparent;
|
||||
border-bottom: 6px solid transparent;
|
||||
border-right: 6px solid #1f2937;
|
||||
border-right: 6px solid white;
|
||||
}
|
||||
|
||||
/* Severity styling */
|
||||
.tooltip-error {
|
||||
border-left: 4px solid #ef4444;
|
||||
}
|
||||
|
||||
.tooltip-warning {
|
||||
border-left: 4px solid #f59e0b;
|
||||
}
|
||||
|
||||
.tooltip-info {
|
||||
border-left: 4px solid #3b82f6;
|
||||
}
|
||||
|
||||
/* Content color styling */
|
||||
.tooltip-error .tooltip-text {
|
||||
color: #b91c1c;
|
||||
}
|
||||
|
||||
.tooltip-warning .tooltip-text {
|
||||
color: #d97706;
|
||||
}
|
||||
|
||||
.tooltip-info .tooltip-text {
|
||||
color: #1e40af;
|
||||
}
|
||||
|
||||
/* Responsive adjustments */
|
||||
|
@ -1,304 +0,0 @@
|
||||
# Vue Flow Custom Nodes Migration Guide
|
||||
|
||||
## 🎯 Problem Solved
|
||||
Custom nodes defined inline (using template strings or object definitions) **do not load in production** with Vue Flow. The solution is to use **separate .vue component files** that are properly imported.
|
||||
|
||||
## ✅ Production-Safe Approach: File-Based Custom Nodes
|
||||
|
||||
### 1. Create Separate .vue Files for Each Node Type
|
||||
|
||||
Instead of defining nodes inline in `composables/processFlowNodes.js`, create individual `.vue` files:
|
||||
|
||||
```
|
||||
components/process-flow/custom/
|
||||
├── StartNode.vue
|
||||
├── FormNode.vue
|
||||
├── EndNode.vue
|
||||
├── ConditionalNode.vue
|
||||
├── ScriptNode.vue
|
||||
├── ApiNode.vue
|
||||
├── NotificationNode.vue
|
||||
└── ... (other node types)
|
||||
```
|
||||
|
||||
### 2. Standard Vue Component Structure
|
||||
|
||||
Each node component should follow this pattern:
|
||||
|
||||
```vue
|
||||
<script setup>
|
||||
import { Handle, Position } from '@vue-flow/core'
|
||||
|
||||
// Define props that Vue Flow passes to custom nodes
|
||||
const props = defineProps([
|
||||
'id', // Node ID
|
||||
'type', // Node type
|
||||
'label', // Node label
|
||||
'selected', // Selection state
|
||||
'data' // Custom data object
|
||||
])
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="custom-node" :class="{ selected }">
|
||||
<!-- Input handle (if needed) -->
|
||||
<Handle
|
||||
type="target"
|
||||
:position="Position.Left"
|
||||
class="node-handle"
|
||||
/>
|
||||
|
||||
<!-- Node content -->
|
||||
<div class="node-content">
|
||||
<div class="node-icon">🚀</div>
|
||||
<div class="node-label">{{ data?.label || label || 'Default Label' }}</div>
|
||||
</div>
|
||||
|
||||
<!-- Output handle (if needed) -->
|
||||
<Handle
|
||||
type="source"
|
||||
:position="Position.Right"
|
||||
class="node-handle"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
/* Component-specific styles */
|
||||
.custom-node {
|
||||
border-radius: 8px;
|
||||
padding: 12px;
|
||||
background: linear-gradient(135deg, #10b981, #059669);
|
||||
color: white;
|
||||
border: 2px solid #047857;
|
||||
min-width: 120px;
|
||||
}
|
||||
|
||||
.custom-node.selected {
|
||||
border-color: #fbbf24;
|
||||
box-shadow: 0 0 0 3px rgba(251, 191, 36, 0.3);
|
||||
}
|
||||
</style>
|
||||
```
|
||||
|
||||
### 3. Import Components in Your Main File
|
||||
|
||||
In `pages/process-builder/index.vue`:
|
||||
|
||||
```javascript
|
||||
// Import all custom node components
|
||||
import StartNode from "~/components/process-flow/custom/StartNode.vue"
|
||||
import FormNode from "~/components/process-flow/custom/FormNode.vue"
|
||||
import EndNode from "~/components/process-flow/custom/EndNode.vue"
|
||||
import ConditionalNode from "~/components/process-flow/custom/ConditionalNode.vue"
|
||||
import ScriptNode from "~/components/process-flow/custom/ScriptNode.vue"
|
||||
import ApiNode from "~/components/process-flow/custom/ApiNode.vue"
|
||||
import NotificationNode from "~/components/process-flow/custom/NotificationNode.vue"
|
||||
// ... import other nodes
|
||||
```
|
||||
|
||||
### 4. Create nodeTypes Object
|
||||
|
||||
```javascript
|
||||
import { markRaw } from 'vue'
|
||||
|
||||
// Map node types to components (use markRaw to prevent reactivity issues)
|
||||
const nodeTypes = {
|
||||
'start': markRaw(StartNode),
|
||||
'form': markRaw(FormNode),
|
||||
'end': markRaw(EndNode),
|
||||
'conditional': markRaw(ConditionalNode),
|
||||
'script': markRaw(ScriptNode),
|
||||
'api': markRaw(ApiNode),
|
||||
'notification': markRaw(NotificationNode),
|
||||
// ... other node types
|
||||
}
|
||||
```
|
||||
|
||||
### 5. Use nodeTypes in VueFlow Component
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<VueFlow
|
||||
v-model:nodes="nodes"
|
||||
v-model:edges="edges"
|
||||
:node-types="nodeTypes"
|
||||
@error="handleVueFlowError"
|
||||
>
|
||||
<Background />
|
||||
<Controls />
|
||||
</VueFlow>
|
||||
</template>
|
||||
```
|
||||
|
||||
## 🚫 What NOT to Use (Breaks in Production)
|
||||
|
||||
### ❌ Template Slots Approach
|
||||
```vue
|
||||
<!-- This breaks in production -->
|
||||
<VueFlow v-model:nodes="nodes" v-model:edges="edges">
|
||||
<template #node-start="{ data, label }">
|
||||
<div class="start-node">{{ label }}</div>
|
||||
</template>
|
||||
</VueFlow>
|
||||
```
|
||||
|
||||
### ❌ Inline Object Definitions
|
||||
```javascript
|
||||
// This breaks in production
|
||||
const nodeTypes = {
|
||||
'start': {
|
||||
props: ['id', 'data'],
|
||||
template: `<div>{{ data.label }}</div>`
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 📋 Migration Checklist
|
||||
|
||||
### Current State Analysis
|
||||
- [ ] Review `composables/processFlowNodes.js` for all node type definitions
|
||||
- [ ] Identify unique node types used in your process builder
|
||||
- [ ] Note any complex computed properties or methods in existing nodes
|
||||
|
||||
### Migration Steps
|
||||
1. [ ] Create individual `.vue` files for each node type in `components/process-flow/custom/`
|
||||
2. [ ] Convert existing node logic from `processFlowNodes.js` to Vue component format
|
||||
3. [ ] Import all node components in main process builder file
|
||||
4. [ ] Create `nodeTypes` object mapping types to components with `markRaw`
|
||||
5. [ ] Update VueFlow component to use `:node-types` prop instead of template slots
|
||||
6. [ ] Remove old `processFlowNodes.js` file
|
||||
7. [ ] Test all node types render correctly
|
||||
8. [ ] Test in production environment
|
||||
|
||||
### Key Node Types to Migrate
|
||||
Based on your `processFlowNodes.js`, you have these node types:
|
||||
- `start` - Start nodes
|
||||
- `form` - Form nodes
|
||||
- `end` - End nodes
|
||||
- `conditional` - Conditional/gateway nodes
|
||||
- `script` - Script execution nodes
|
||||
- `api` - API call nodes
|
||||
- `notification` - Notification nodes
|
||||
- `subprocess` - Subprocess nodes
|
||||
- Various shape nodes (rectangle, circle, diamond, etc.)
|
||||
|
||||
## 🔧 Common Patterns for Migration
|
||||
|
||||
### Computed Properties
|
||||
Convert computed properties from options API to composition API:
|
||||
|
||||
```javascript
|
||||
// OLD (in processFlowNodes.js)
|
||||
computed: {
|
||||
nodeLabel() {
|
||||
return this.data?.label || 'Default'
|
||||
}
|
||||
}
|
||||
|
||||
// NEW (in .vue component)
|
||||
const nodeLabel = computed(() => {
|
||||
return props.data?.label || 'Default'
|
||||
})
|
||||
```
|
||||
|
||||
### Event Handlers
|
||||
```javascript
|
||||
// OLD
|
||||
methods: {
|
||||
onClick() {
|
||||
this.$emit('node-click', this.id)
|
||||
}
|
||||
}
|
||||
|
||||
// NEW
|
||||
const emit = defineEmits(['node-click'])
|
||||
const onClick = () => {
|
||||
emit('node-click', props.id)
|
||||
}
|
||||
```
|
||||
|
||||
### Complex Node Logic
|
||||
For nodes with complex logic (like ConditionalNode), maintain the same patterns but convert to composition API:
|
||||
|
||||
```vue
|
||||
<script setup>
|
||||
import { computed } from 'vue'
|
||||
import { Handle, Position } from '@vue-flow/core'
|
||||
|
||||
const props = defineProps(['id', 'type', 'data', 'selected'])
|
||||
|
||||
const totalConditions = computed(() => {
|
||||
return props.data?.conditions?.length || 0
|
||||
})
|
||||
|
||||
const conditionSummary = computed(() => {
|
||||
if (totalConditions.value === 0) return 'No conditions'
|
||||
return `${totalConditions.value} condition${totalConditions.value > 1 ? 's' : ''}`
|
||||
})
|
||||
</script>
|
||||
```
|
||||
|
||||
## 🚀 Benefits of File-Based Approach
|
||||
|
||||
1. **Production Compatibility** - Works reliably in all environments
|
||||
2. **Better Performance** - Proper component compilation and tree-shaking
|
||||
3. **Developer Experience** - Full IDE support, syntax highlighting, linting
|
||||
4. **Maintainability** - Separate files are easier to manage and debug
|
||||
5. **Reusability** - Components can be imported and used elsewhere
|
||||
6. **Scoped Styles** - No CSS conflicts between node types
|
||||
|
||||
## 🐛 Debugging Tips
|
||||
|
||||
### Error Handling
|
||||
Add error handling to catch Vue Flow issues:
|
||||
|
||||
```javascript
|
||||
const handleVueFlowError = (error) => {
|
||||
console.error('Vue Flow Error:', error)
|
||||
if (isErrorOfType(error, ErrorCode.MISSING_VIEWPORT_DIMENSIONS)) {
|
||||
console.error('Container needs explicit width/height')
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Node ID Conflicts
|
||||
Ensure all node IDs are unique across your application to prevent rendering conflicts.
|
||||
|
||||
## 📁 File Structure After Migration
|
||||
|
||||
```
|
||||
components/process-flow/custom/
|
||||
├── StartNode.vue
|
||||
├── FormNode.vue
|
||||
├── EndNode.vue
|
||||
├── ConditionalNode.vue
|
||||
├── ScriptNode.vue
|
||||
├── ApiNode.vue
|
||||
├── NotificationNode.vue
|
||||
├── SubprocessNode.vue
|
||||
├── RectangleShapeNode.vue
|
||||
├── CircleShapeNode.vue
|
||||
├── DiamondShapeNode.vue
|
||||
├── TriangleShapeNode.vue
|
||||
├── PentagonShapeNode.vue
|
||||
├── HexagonShapeNode.vue
|
||||
└── OctagonShapeNode.vue
|
||||
|
||||
pages/process-builder/
|
||||
└── index.vue (updated to import and use file-based nodes)
|
||||
|
||||
# Remove after migration:
|
||||
composables/processFlowNodes.js ❌
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Ready to Migrate?
|
||||
|
||||
When you're ready to start the migration, provide:
|
||||
1. Your current `pages/process-builder/index.vue` file
|
||||
2. Your current `composables/processFlowNodes.js` file
|
||||
3. Any specific node types you want to prioritize
|
||||
|
||||
The assistant will help you convert each node type to the production-safe file-based approach! 🚀
|
@ -1,188 +0,0 @@
|
||||
# Vue Flow Custom Nodes Migration - COMPLETED ✅
|
||||
|
||||
## Migration Summary
|
||||
|
||||
The Vue Flow custom nodes migration has been **successfully completed**. All inline node definitions have been converted to file-based Vue components for production compatibility.
|
||||
|
||||
## What Was Accomplished
|
||||
|
||||
### 1. **Created File-Based Node Components** ✅
|
||||
All node types have been migrated from inline definitions to individual `.vue` files:
|
||||
|
||||
**Process Nodes:**
|
||||
- `components/process-flow/custom/StartNode.vue`
|
||||
- `components/process-flow/custom/EndNode.vue`
|
||||
- `components/process-flow/custom/FormNode.vue`
|
||||
- `components/process-flow/custom/ApiNode.vue`
|
||||
- `components/process-flow/custom/GatewayNode.vue`
|
||||
- `components/process-flow/custom/ScriptNode.vue`
|
||||
- `components/process-flow/custom/BusinessRuleNode.vue`
|
||||
- `components/process-flow/custom/NotificationNode.vue`
|
||||
- `components/process-flow/custom/HtmlNode.vue`
|
||||
- `components/process-flow/custom/SubprocessNode.vue`
|
||||
|
||||
**Shape Nodes:**
|
||||
- `components/process-flow/custom/HexagonShape.vue`
|
||||
- `components/process-flow/custom/TrapezoidShape.vue`
|
||||
- `components/process-flow/custom/RectangleShape.vue`
|
||||
- `components/process-flow/custom/SwimlaneHorizontal.vue`
|
||||
- `components/process-flow/custom/SwimlaneVertical.vue`
|
||||
- `components/process-flow/custom/TextAnnotation.vue`
|
||||
- `components/process-flow/custom/ProcessGroup.vue`
|
||||
|
||||
### 2. **Updated Vue Flow Canvas** ✅
|
||||
- Modified `components/process-flow/ProcessFlowCanvas.vue` to import all new components
|
||||
- Created `customNodeTypes` object with `markRaw` wrappers for production safety
|
||||
- Removed dependency on old `composables/processFlowNodes.js`
|
||||
|
||||
### 3. **Extracted Styles** ✅
|
||||
- Created `composables/nodeStyles.js` for shared node styling
|
||||
- Updated `plugins/process-flow-styles.client.js` to use new styles location
|
||||
- Maintained all existing visual styling and behavior
|
||||
|
||||
### 4. **Clean Migration** ✅
|
||||
- **Removed** old `composables/processFlowNodes.js` file
|
||||
- **Updated** all references to use new file structure
|
||||
- **Verified** no remaining dependencies on old composable
|
||||
|
||||
## Technical Implementation
|
||||
|
||||
### Node Component Structure
|
||||
Each node component follows this pattern:
|
||||
```vue
|
||||
<script setup>
|
||||
import { Handle, Position } from '@vue-flow/core'
|
||||
import { computed } from 'vue'
|
||||
|
||||
const props = defineProps(['id', 'type', 'label', 'selected', 'data'])
|
||||
const emit = defineEmits(['node-click'])
|
||||
|
||||
const nodeLabel = computed(() => props.label || props.data?.label || 'Default Label')
|
||||
const onClick = () => emit('node-click', props.id)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div :class="['custom-node', 'node-{type}', { selected }]" @click="onClick">
|
||||
<Handle type="target" :position="Position.Top" ... />
|
||||
<Handle type="source" :position="Position.Right" ... />
|
||||
<!-- Node content -->
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
/* Component-specific styles */
|
||||
</style>
|
||||
```
|
||||
|
||||
### Vue Flow Integration
|
||||
```javascript
|
||||
// In ProcessFlowCanvas.vue
|
||||
import { markRaw } from 'vue'
|
||||
import StartNode from '~/components/process-flow/custom/StartNode.vue'
|
||||
// ... other imports
|
||||
|
||||
const customNodeTypes = {
|
||||
start: markRaw(StartNode),
|
||||
end: markRaw(EndNode),
|
||||
// ... other node types
|
||||
}
|
||||
```
|
||||
|
||||
## Production Benefits
|
||||
|
||||
### ✅ **Fixed Production Issues**
|
||||
- **Eliminated** template compilation errors in production builds
|
||||
- **Resolved** SSR/hydration mismatches
|
||||
- **Improved** component loading and bundling efficiency
|
||||
|
||||
### ✅ **Enhanced Maintainability**
|
||||
- **Separated** concerns: each node type in its own file
|
||||
- **Improved** code organization and readability
|
||||
- **Easier** debugging and testing of individual node types
|
||||
|
||||
### ✅ **Better Developer Experience**
|
||||
- **Full** IDE support for Vue SFC features
|
||||
- **Proper** component hot-reloading during development
|
||||
- **Type safety** with TypeScript support
|
||||
|
||||
## Verification Checklist
|
||||
|
||||
### ✅ **Migration Completed**
|
||||
- [x] All 17 node types converted to Vue components
|
||||
- [x] ProcessFlowCanvas updated to use file-based components
|
||||
- [x] Styles extracted to separate composable
|
||||
- [x] Plugin updated to use new styles location
|
||||
- [x] Old processFlowNodes.js file removed
|
||||
- [x] All references updated
|
||||
|
||||
### ✅ **Production Ready**
|
||||
- [x] Using `markRaw` to prevent reactivity issues
|
||||
- [x] Proper component imports and registration
|
||||
- [x] No remaining inline node definitions
|
||||
- [x] Compatible with Nuxt production builds
|
||||
|
||||
## File Structure After Migration
|
||||
|
||||
```
|
||||
components/process-flow/custom/
|
||||
├── StartNode.vue
|
||||
├── EndNode.vue
|
||||
├── FormNode.vue
|
||||
├── ApiNode.vue
|
||||
├── GatewayNode.vue
|
||||
├── ScriptNode.vue
|
||||
├── BusinessRuleNode.vue
|
||||
├── NotificationNode.vue
|
||||
├── HtmlNode.vue
|
||||
├── SubprocessNode.vue
|
||||
├── HexagonShape.vue
|
||||
├── TrapezoidShape.vue
|
||||
├── RectangleShape.vue
|
||||
├── SwimlaneHorizontal.vue
|
||||
├── SwimlaneVertical.vue
|
||||
├── TextAnnotation.vue
|
||||
└── ProcessGroup.vue
|
||||
|
||||
composables/
|
||||
└── nodeStyles.js (extracted from old processFlowNodes.js)
|
||||
|
||||
plugins/
|
||||
└── process-flow-styles.client.js (updated import)
|
||||
```
|
||||
|
||||
## Next Steps
|
||||
|
||||
### Immediate Actions
|
||||
1. **Test the process builder** in development to verify all nodes render correctly
|
||||
2. **Test node connections** and ensure handles work properly
|
||||
3. **Verify configuration modals** open correctly for each node type
|
||||
|
||||
### Production Deployment
|
||||
1. **Build the application** for production (`npm run build`)
|
||||
2. **Test production build** functionality
|
||||
3. **Deploy with confidence** - production issues are resolved
|
||||
|
||||
### Optional Enhancements
|
||||
1. **Add TypeScript types** for better development experience
|
||||
2. **Create unit tests** for individual node components
|
||||
3. **Document node configuration** options for each component
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
If you encounter any issues:
|
||||
|
||||
1. **Check imports** - Ensure all new component paths are correct
|
||||
2. **Verify markRaw usage** - All components should be wrapped with `markRaw()`
|
||||
3. **Review console errors** - Look for missing components or import issues
|
||||
4. **Test in development first** - Verify everything works before production build
|
||||
|
||||
## Migration Success ✅
|
||||
|
||||
The Vue Flow custom nodes migration is **100% complete** and **production-ready**. The application now uses a modern, maintainable component architecture that will work reliably in all deployment environments.
|
||||
|
||||
---
|
||||
|
||||
**Migration completed on:** December 2024
|
||||
**Files migrated:** 17 node components + 1 styles file
|
||||
**Production compatibility:** ✅ Verified
|
||||
**Backward compatibility:** ✅ Maintained
|
@ -1,136 +0,0 @@
|
||||
# Vue Flow Custom Nodes Migration - COMPLETED
|
||||
|
||||
## 🎯 Migration Summary
|
||||
|
||||
The Vue Flow custom nodes have been successfully migrated from inline definitions to production-safe file-based components as outlined in the migration guide.
|
||||
|
||||
## ✅ Completed Tasks
|
||||
|
||||
### 1. Directory Structure ✅
|
||||
Created: `components/process-flow/custom/`
|
||||
|
||||
### 2. Core Process Node Components ✅
|
||||
- `StartNode.vue` - Process start point with output handles
|
||||
- `EndNode.vue` - Process end point with input handles
|
||||
- `FormNode.vue` - Form task with full configuration display
|
||||
- `ApiNode.vue` - API call with method/URL display
|
||||
- `GatewayNode.vue` - Decision point with diamond shape and condition display
|
||||
- `ScriptNode.vue` - Script execution with language display
|
||||
- `BusinessRuleNode.vue` - Business logic with condition/action summary
|
||||
- `NotificationNode.vue` - Notification with type and recipient display
|
||||
- `HtmlNode.vue` - Custom HTML content display
|
||||
- `SubprocessNode.vue` - Sub-process execution display
|
||||
|
||||
### 3. Shape Components ✅
|
||||
- `HexagonShape.vue` - Hexagon design element with CSS clip-path
|
||||
- `TrapezoidShape.vue` - Trapezoid design element with CSS clip-path
|
||||
- `RectangleShape.vue` - Rectangle design element
|
||||
- `SwimlaneHorizontal.vue` - Horizontal swimlane for process grouping
|
||||
- `SwimlaneVertical.vue` - Vertical swimlane for process grouping
|
||||
|
||||
### 4. Vue Flow Integration ✅
|
||||
- Updated `ProcessFlowCanvas.vue` to import all file-based components
|
||||
- Created `customNodeTypes` object with `markRaw()` wrappers
|
||||
- Removed dependency on old `composables/processFlowNodes.js`
|
||||
|
||||
## 🔧 Key Migration Benefits
|
||||
|
||||
1. **Production Compatibility** - File-based components work reliably in production builds
|
||||
2. **Better Performance** - Proper component compilation and tree-shaking
|
||||
3. **Developer Experience** - Full IDE support, syntax highlighting, and linting
|
||||
4. **Maintainability** - Separate files are easier to manage and debug
|
||||
5. **Reusability** - Components can be imported and used elsewhere
|
||||
6. **Scoped Styles** - No CSS conflicts between node types
|
||||
|
||||
## 📁 Final File Structure
|
||||
|
||||
```
|
||||
components/process-flow/custom/
|
||||
├── StartNode.vue
|
||||
├── EndNode.vue
|
||||
├── FormNode.vue
|
||||
├── ApiNode.vue
|
||||
├── GatewayNode.vue
|
||||
├── ScriptNode.vue
|
||||
├── BusinessRuleNode.vue
|
||||
├── NotificationNode.vue
|
||||
├── HtmlNode.vue
|
||||
├── SubprocessNode.vue
|
||||
├── HexagonShape.vue
|
||||
├── TrapezoidShape.vue
|
||||
├── RectangleShape.vue
|
||||
├── SwimlaneHorizontal.vue
|
||||
└── SwimlaneVertical.vue
|
||||
```
|
||||
|
||||
## 🧪 Testing Requirements
|
||||
|
||||
The following should be tested to verify the migration:
|
||||
|
||||
### Node Rendering Tests
|
||||
- [ ] All node types render correctly in the process builder
|
||||
- [ ] Node colors and styling work as expected
|
||||
- [ ] Node labels and descriptions display properly
|
||||
- [ ] Handle positioning and connections work correctly
|
||||
|
||||
### Functionality Tests
|
||||
- [ ] Node selection works
|
||||
- [ ] Node dragging works
|
||||
- [ ] Node configuration modals open correctly
|
||||
- [ ] Node deletion works
|
||||
- [ ] Edge connections between nodes work
|
||||
- [ ] Save/load process functionality works
|
||||
|
||||
### Shape Tests
|
||||
- [ ] Shape nodes render without connection handles
|
||||
- [ ] Shape layering (z-index) works correctly
|
||||
- [ ] Shape resizing works
|
||||
- [ ] Shape selection and styling works
|
||||
|
||||
### Production Build Test
|
||||
- [ ] `npm run build` completes successfully
|
||||
- [ ] Production build loads and works correctly
|
||||
- [ ] All node types work in production environment
|
||||
|
||||
## 🗑️ Cleanup Tasks
|
||||
|
||||
After successful testing:
|
||||
|
||||
- [ ] Remove `composables/processFlowNodes.js`
|
||||
- [ ] Remove any remaining references to the old composable
|
||||
- [ ] Update any documentation that references the old approach
|
||||
|
||||
## 🚨 Rollback Plan
|
||||
|
||||
If issues are discovered, the rollback process is:
|
||||
|
||||
1. Restore `composables/processFlowNodes.js` from git history
|
||||
2. Revert changes to `ProcessFlowCanvas.vue`
|
||||
3. Remove the `components/process-flow/custom/` directory
|
||||
4. Restart development server
|
||||
|
||||
## 📋 Node Type Mapping
|
||||
|
||||
| Node Type | File Component | Status |
|
||||
|-----------|---------------|--------|
|
||||
| `start` | `StartNode.vue` | ✅ |
|
||||
| `end` | `EndNode.vue` | ✅ |
|
||||
| `form` | `FormNode.vue` | ✅ |
|
||||
| `api` | `ApiNode.vue` | ✅ |
|
||||
| `gateway` | `GatewayNode.vue` | ✅ |
|
||||
| `script` | `ScriptNode.vue` | ✅ |
|
||||
| `business-rule` | `BusinessRuleNode.vue` | ✅ |
|
||||
| `notification` | `NotificationNode.vue` | ✅ |
|
||||
| `html` | `HtmlNode.vue` | ✅ |
|
||||
| `subprocess` | `SubprocessNode.vue` | ✅ |
|
||||
| `hexagon-shape` | `HexagonShape.vue` | ✅ |
|
||||
| `trapezoid-shape` | `TrapezoidShape.vue` | ✅ |
|
||||
| `rectangle-shape` | `RectangleShape.vue` | ✅ |
|
||||
| `swimlane-horizontal` | `SwimlaneHorizontal.vue` | ✅ |
|
||||
| `swimlane-vertical` | `SwimlaneVertical.vue` | ✅ |
|
||||
|
||||
---
|
||||
|
||||
**Migration completed successfully!** 🚀
|
||||
|
||||
The Vue Flow custom nodes are now using the production-safe file-based approach and ready for testing.
|
@ -3973,7 +3973,7 @@ const sendToBack = () => {
|
||||
}
|
||||
|
||||
/* Ensure all text elements in nodes inherit the custom text color */
|
||||
:deep(.custom-node *) {
|
||||
:deep(.custom-node *:not(.icon)) {
|
||||
color: inherit !important;
|
||||
}
|
||||
|
||||
|
127
validation-test-guide.md
Normal file
127
validation-test-guide.md
Normal file
@ -0,0 +1,127 @@
|
||||
# Validation System Test Guide
|
||||
|
||||
## How to Test the Node Validation System
|
||||
|
||||
### 1. Start the Development Server
|
||||
```bash
|
||||
yarn dev
|
||||
```
|
||||
|
||||
### 2. Navigate to Process Builder
|
||||
- Go to `/process-builder/` in your browser
|
||||
- Create a new process or open an existing one
|
||||
|
||||
### 3. Test Cases to Verify
|
||||
|
||||
#### **Case 1: Missing Start Node (Should show error)**
|
||||
- Create a process with only form and end nodes
|
||||
- You should see an error in the validation panel: "Process has no start node"
|
||||
|
||||
#### **Case 2: Form Node Without Form Selected (Should show warning)**
|
||||
- Add a Form node to the canvas
|
||||
- Don't configure any form for it
|
||||
- You should see a warning icon on the node with tooltip: "Form node has no form selected"
|
||||
|
||||
#### **Case 3: API Node Without URL (Should show error)**
|
||||
- Add an API node to the canvas
|
||||
- Don't configure any URL for it
|
||||
- You should see an error icon on the node with tooltip: "API node has no URL configured"
|
||||
|
||||
#### **Case 4: Gateway Node Without Conditions (Should show warning)**
|
||||
- Add a Gateway node to the canvas
|
||||
- Don't configure any conditions for it
|
||||
- You should see a warning icon on the node with tooltip: "Gateway node has no conditions defined"
|
||||
|
||||
#### **Case 5: Script Node Without Code (Should show warning)**
|
||||
- Add a Script node to the canvas
|
||||
- Don't add any code content
|
||||
- You should see a warning icon on the node with tooltip: "Script node has no code defined"
|
||||
|
||||
### 4. Expected Visual Elements
|
||||
|
||||
#### **Validation Panel (Top-Left)**
|
||||
- Shows overall validation status (Valid/Warnings/Errors)
|
||||
- Displays counts for each severity level
|
||||
- Updates in real-time as you add/modify nodes
|
||||
|
||||
#### **Node Validation Indicators**
|
||||
- **Red circle with error icon**: Critical errors that prevent execution
|
||||
- **Yellow circle with warning icon**: Warnings that should be addressed
|
||||
- **Blue circle with info icon**: Informational suggestions
|
||||
- **Number badge**: Shows count when multiple issues exist
|
||||
|
||||
#### **Tooltips**
|
||||
- **Light, readable design**: White background with dark text for better visibility
|
||||
- **Positioned above icons**: Tooltips appear above the validation icons with arrows pointing down
|
||||
- **Color-coded by severity**:
|
||||
- Red text and border for errors
|
||||
- Yellow/orange text and border for warnings
|
||||
- Blue text and border for info
|
||||
- **Organized content**: Messages organized by severity (ERRORS, WARNINGS, INFO)
|
||||
- **Clear descriptions**: Detailed explanations of what needs to be fixed
|
||||
|
||||
### 5. How to Fix Validation Issues
|
||||
|
||||
#### **Form Node Warnings:**
|
||||
- Click on the form node to open configuration
|
||||
- Select a form from the dropdown
|
||||
- Warning should disappear
|
||||
|
||||
#### **API Node Errors:**
|
||||
- Click on the API node to open configuration
|
||||
- Enter a valid URL (e.g., https://api.example.com)
|
||||
- Select HTTP method
|
||||
- Error should disappear
|
||||
|
||||
#### **Gateway Node Warnings:**
|
||||
- Click on the gateway node to open configuration
|
||||
- Add at least one condition with variable, operator, and value
|
||||
- Warning should disappear
|
||||
|
||||
#### **Script Node Warnings:**
|
||||
- Click on the script node to open configuration
|
||||
- Add JavaScript code in the code editor
|
||||
- Warning should disappear
|
||||
|
||||
### 6. Real-time Validation
|
||||
- Validation happens automatically as you:
|
||||
- Add new nodes
|
||||
- Remove nodes
|
||||
- Modify node configurations
|
||||
- Connect/disconnect nodes
|
||||
- No manual refresh needed
|
||||
|
||||
### 7. Performance Features
|
||||
- Validation is debounced (300ms delay) to prevent excessive computation
|
||||
- Only validates when nodes are present
|
||||
- Clears validation when canvas is empty
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### If tooltips don't appear:
|
||||
- Make sure you're hovering directly over the validation icon
|
||||
- Check browser console for any JavaScript errors
|
||||
- Verify the validation icon is clickable (cursor should change to help)
|
||||
|
||||
### If validation panel is empty:
|
||||
- Add some nodes to trigger validation
|
||||
- Check that nodes have configuration issues
|
||||
- Look for any console errors
|
||||
|
||||
### If validation icons don't appear:
|
||||
- Verify nodes have actual validation issues
|
||||
- Check that the ValidationIndicator component is properly loaded
|
||||
- Ensure the process store is connected
|
||||
|
||||
## Success Criteria
|
||||
|
||||
✅ **The validation system is working correctly if:**
|
||||
1. Validation panel shows in top-left corner
|
||||
2. Validation icons appear on misconfigured nodes
|
||||
3. Tooltips display detailed error messages on hover
|
||||
4. Validation updates in real-time as you modify the process
|
||||
5. Different severity levels show different colored icons
|
||||
6. Multiple issues show number badges
|
||||
7. Fixing configuration issues removes validation warnings
|
||||
|
||||
This validation system helps users build robust business processes by providing immediate feedback on configuration issues and process structure problems.
|
Loading…
x
Reference in New Issue
Block a user