corrad-bp/components/process-flow/ValidationIndicator.vue
Md Afiq Iskandar ed00664882 Implement Node Validation System for Process Flow
- 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.
2025-07-28 11:35:38 +08:00

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>