- Introduced a comprehensive node validation system in the process flow builder, enhancing the user experience by providing real-time feedback on node configurations and process integrity. - Added `useNodeValidation` composable to manage validation logic, including checks for required nodes, configuration completeness, and flow logic. - Integrated validation indicators in node components (ApiNode, FormNode, GatewayNode, ScriptNode) to visually represent validation issues. - Created `ValidationIndicator` and `ValidationTooltip` components for displaying validation statuses and detailed messages. - Updated `ProcessFlowCanvas.vue` to trigger validation on node and edge changes, ensuring immediate feedback during process design. - Enhanced `processBuilder` store to manage validation results and summary statistics, allowing for a centralized validation state. - Documented the validation system implementation plan to guide future enhancements and user training.
175 lines
4.1 KiB
Vue
175 lines
4.1 KiB
Vue
<script setup>
|
|
import { computed } from 'vue'
|
|
import ValidationTooltip from './ValidationTooltip.vue'
|
|
|
|
const props = defineProps({
|
|
nodeId: {
|
|
type: String,
|
|
required: true
|
|
},
|
|
validationIssues: {
|
|
type: Array,
|
|
default: () => []
|
|
},
|
|
showTooltip: {
|
|
type: Boolean,
|
|
default: true
|
|
}
|
|
})
|
|
|
|
// Computed properties for validation display
|
|
const hasIssues = computed(() => props.validationIssues.length > 0)
|
|
|
|
const validationSeverity = computed(() => {
|
|
if (!hasIssues.value) return null
|
|
|
|
const hasError = props.validationIssues.some(issue => issue.severity === 'error')
|
|
const hasWarning = props.validationIssues.some(issue => issue.severity === 'warning')
|
|
|
|
if (hasError) return 'error'
|
|
if (hasWarning) return 'warning'
|
|
return 'info'
|
|
})
|
|
|
|
const validationIcon = computed(() => {
|
|
switch (validationSeverity.value) {
|
|
case 'error': return 'material-symbols:error'
|
|
case 'warning': return 'material-symbols:warning'
|
|
case 'info': return 'material-symbols:info'
|
|
default: return null
|
|
}
|
|
})
|
|
|
|
const validationTooltip = computed(() => {
|
|
if (!hasIssues.value) return null
|
|
|
|
const issuesByType = {
|
|
error: props.validationIssues.filter(i => i.severity === 'error'),
|
|
warning: props.validationIssues.filter(i => i.severity === 'warning'),
|
|
info: props.validationIssues.filter(i => i.severity === 'info')
|
|
}
|
|
|
|
const lines = []
|
|
|
|
if (issuesByType.error.length > 0) {
|
|
lines.push('ERRORS:')
|
|
issuesByType.error.forEach(issue => lines.push(`• ${issue.message}`))
|
|
}
|
|
|
|
if (issuesByType.warning.length > 0) {
|
|
if (lines.length > 0) lines.push('')
|
|
lines.push('WARNINGS:')
|
|
issuesByType.warning.forEach(issue => lines.push(`• ${issue.message}`))
|
|
}
|
|
|
|
if (issuesByType.info.length > 0) {
|
|
if (lines.length > 0) lines.push('')
|
|
lines.push('INFO:')
|
|
issuesByType.info.forEach(issue => lines.push(`• ${issue.message}`))
|
|
}
|
|
|
|
return lines.join('\n')
|
|
})
|
|
|
|
const severityClass = computed(() => {
|
|
return `validation-${validationSeverity.value}`
|
|
})
|
|
|
|
const severityColorClass = computed(() => {
|
|
switch (validationSeverity.value) {
|
|
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"
|
|
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>
|
|
</template>
|
|
|
|
<style scoped>
|
|
.validation-indicator {
|
|
@apply absolute -top-2 -right-2 z-50 flex items-center justify-center;
|
|
@apply w-6 h-6 rounded-full bg-white border-2 shadow-sm;
|
|
pointer-events: auto;
|
|
cursor: help;
|
|
}
|
|
|
|
.validation-indicator.validation-error {
|
|
@apply border-red-500 bg-red-50;
|
|
}
|
|
|
|
.validation-indicator.validation-warning {
|
|
@apply border-yellow-500 bg-yellow-50;
|
|
}
|
|
|
|
.validation-indicator.validation-info {
|
|
@apply border-blue-500 bg-blue-50;
|
|
}
|
|
|
|
.validation-icon {
|
|
@apply text-sm;
|
|
}
|
|
|
|
.validation-badge {
|
|
@apply absolute -top-1 -right-1 w-4 h-4 rounded-full text-xs;
|
|
@apply flex items-center justify-center text-white font-bold;
|
|
@apply bg-red-500;
|
|
}
|
|
|
|
.validation-badge.validation-warning {
|
|
@apply bg-yellow-500;
|
|
}
|
|
|
|
.validation-badge.validation-info {
|
|
@apply bg-blue-500;
|
|
}
|
|
|
|
/* Remove old tooltip styles - now using ValidationTooltip component */
|
|
</style> |