- Introduced new components: ArrowEdge, CustomEdge, InteractiveArrowEdge, and EdgeConfiguration for enhanced edge management in the process flow. - Implemented dynamic edge paths with customizable styles, labels, and animations, improving visual representation and user interaction. - Enhanced ProcessFlowCanvas to support new edge types and configurations, allowing for more flexible process designs. - Updated ProcessFlowNodes to include new edge components, ensuring seamless integration with existing node functionalities. - Improved user experience by providing configuration options for edges, including animation and style settings, directly within the process builder.
386 lines
11 KiB
Vue
386 lines
11 KiB
Vue
<template>
|
|
<div v-if="selectedEdge" class="edge-configuration">
|
|
<RsCard>
|
|
<template #header>
|
|
<div class="flex items-center gap-2">
|
|
<svg class="w-5 h-5 text-blue-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13.828 10.172a4 4 0 00-5.656 0l-4 4a4 4 0 105.656 5.656l1.102-1.101m-.758-4.899a4 4 0 005.656 0l4-4a4 4 0 00-5.656-5.656l-1.1 1.1"></path>
|
|
</svg>
|
|
<span class="font-medium">Edge Configuration</span>
|
|
</div>
|
|
</template>
|
|
|
|
<template #body>
|
|
<div class="space-y-4">
|
|
<!-- Edge Information -->
|
|
<div class="bg-gray-50 p-3 rounded-lg">
|
|
<div class="text-sm text-gray-600 mb-2">Connection:</div>
|
|
<div class="text-sm font-mono">
|
|
{{ selectedEdge.sourceNode?.data?.label || selectedEdge.source }}
|
|
→ {{ selectedEdge.targetNode?.data?.label || selectedEdge.target }}
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Edge Label -->
|
|
<FormKit
|
|
type="text"
|
|
name="label"
|
|
label="Label"
|
|
v-model="edgeConfig.label"
|
|
placeholder="Enter edge label"
|
|
help="Text displayed on the edge"
|
|
@input="updateEdge"
|
|
/>
|
|
|
|
<!-- Edge Type -->
|
|
<FormKit
|
|
type="select"
|
|
name="type"
|
|
label="Edge Type"
|
|
v-model="edgeConfig.type"
|
|
:options="edgeTypeOptions"
|
|
help="Visual style of the edge path"
|
|
@input="updateEdge"
|
|
/>
|
|
|
|
<!-- Animation -->
|
|
<FormKit
|
|
type="checkbox"
|
|
name="animated"
|
|
label="Animated"
|
|
v-model="edgeConfig.animated"
|
|
help="Show flowing animation on the edge"
|
|
@input="updateEdge"
|
|
/>
|
|
|
|
<!-- Style Options -->
|
|
<div class="space-y-3">
|
|
<div class="text-sm font-medium text-gray-700">Style</div>
|
|
|
|
<!-- Stroke Color -->
|
|
<FormKit
|
|
type="color"
|
|
name="strokeColor"
|
|
label="Color"
|
|
v-model="edgeConfig.style.stroke"
|
|
@input="updateEdge"
|
|
/>
|
|
|
|
<!-- Stroke Width -->
|
|
<FormKit
|
|
type="range"
|
|
name="strokeWidth"
|
|
label="Width"
|
|
v-model="edgeConfig.style.strokeWidth"
|
|
:min="1"
|
|
:max="8"
|
|
:step="0.5"
|
|
help="Line thickness"
|
|
@input="updateEdge"
|
|
/>
|
|
|
|
<!-- Dash Pattern -->
|
|
<FormKit
|
|
type="select"
|
|
name="dashPattern"
|
|
label="Line Style"
|
|
v-model="edgeConfig.dashPattern"
|
|
:options="dashPatternOptions"
|
|
help="Solid or dashed line"
|
|
@input="updateEdge"
|
|
/>
|
|
</div>
|
|
|
|
<!-- Arrow Configuration -->
|
|
<div class="space-y-3">
|
|
<div class="text-sm font-medium text-gray-700">Arrows</div>
|
|
|
|
<FormKit
|
|
type="checkbox"
|
|
name="showStartArrow"
|
|
label="Start Arrow"
|
|
v-model="edgeConfig.showStartArrow"
|
|
help="Show arrow at the start of the edge"
|
|
@input="updateEdge"
|
|
/>
|
|
|
|
<FormKit
|
|
type="checkbox"
|
|
name="showEndArrow"
|
|
label="End Arrow"
|
|
v-model="edgeConfig.showEndArrow"
|
|
help="Show arrow at the end of the edge"
|
|
@input="updateEdge"
|
|
/>
|
|
</div>
|
|
|
|
<!-- Path Customization -->
|
|
<div class="space-y-3">
|
|
<div class="text-sm font-medium text-gray-700">Path Adjustment</div>
|
|
|
|
<div class="text-sm text-gray-600 mb-2">
|
|
Select the edge to see control points for custom positioning
|
|
</div>
|
|
|
|
<RsButton
|
|
v-if="edgeConfig.customPath"
|
|
@click="resetPath"
|
|
variant="secondary"
|
|
size="sm"
|
|
class="w-full"
|
|
>
|
|
Reset to Auto Path
|
|
</RsButton>
|
|
</div>
|
|
|
|
<!-- Advanced Options -->
|
|
<RsCollapse>
|
|
<RsCollapseItem title="Advanced Options">
|
|
<!-- Z-Index -->
|
|
<FormKit
|
|
type="range"
|
|
name="zIndex"
|
|
label="Layer (Z-Index)"
|
|
v-model="edgeConfig.zIndex"
|
|
:min="0"
|
|
:max="1000"
|
|
:step="1"
|
|
help="Higher values appear on top"
|
|
@input="updateEdge"
|
|
/>
|
|
|
|
<!-- Interaction Width -->
|
|
<FormKit
|
|
type="range"
|
|
name="interactionWidth"
|
|
label="Click Area Width"
|
|
v-model="edgeConfig.interactionWidth"
|
|
:min="5"
|
|
:max="30"
|
|
:step="1"
|
|
help="Invisible area around edge for easier clicking"
|
|
@input="updateEdge"
|
|
/>
|
|
|
|
<!-- Updatable -->
|
|
<FormKit
|
|
type="checkbox"
|
|
name="updatable"
|
|
label="Allow Reconnection"
|
|
v-model="edgeConfig.updatable"
|
|
help="Allow dragging edge endpoints to reconnect"
|
|
@input="updateEdge"
|
|
/>
|
|
</RsCollapseItem>
|
|
</RsCollapse>
|
|
</div>
|
|
</template>
|
|
|
|
<template #footer>
|
|
<div class="flex justify-between gap-2">
|
|
<RsButton @click="deleteEdge" variant="danger" size="sm">
|
|
Delete Edge
|
|
</RsButton>
|
|
<RsButton @click="closeConfiguration" variant="secondary" size="sm">
|
|
Close
|
|
</RsButton>
|
|
</div>
|
|
</template>
|
|
</RsCard>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup>
|
|
import { ref, watch, computed } from 'vue'
|
|
import RsCard from '~/components/RsCard.vue'
|
|
import RsButton from '~/components/RsButton.vue'
|
|
import RsCollapse from '~/components/RsCollapse.vue'
|
|
import RsCollapseItem from '~/components/RsCollapseItem.vue'
|
|
|
|
const props = defineProps({
|
|
selectedEdge: {
|
|
type: Object,
|
|
default: null
|
|
}
|
|
})
|
|
|
|
const emit = defineEmits(['updateEdge', 'deleteEdge', 'close'])
|
|
|
|
// Edge configuration object
|
|
const edgeConfig = ref({
|
|
label: '',
|
|
type: 'custom',
|
|
animated: true,
|
|
style: {
|
|
stroke: '#555',
|
|
strokeWidth: 2,
|
|
strokeDasharray: ''
|
|
},
|
|
showStartArrow: false,
|
|
showEndArrow: true,
|
|
dashPattern: 'solid',
|
|
customPath: null,
|
|
zIndex: 0,
|
|
interactionWidth: 10,
|
|
updatable: true
|
|
})
|
|
|
|
// Edge type options
|
|
const edgeTypeOptions = [
|
|
{ label: 'Custom (Smooth Step)', value: 'custom' },
|
|
{ label: 'Bezier Curve', value: 'bezier' },
|
|
{ label: 'Straight Line', value: 'straight' },
|
|
{ label: 'Step', value: 'step' },
|
|
{ label: 'Smooth Step', value: 'smoothstep' }
|
|
]
|
|
|
|
// Dash pattern options
|
|
const dashPatternOptions = [
|
|
{ label: 'Solid', value: 'solid' },
|
|
{ label: 'Dashed', value: 'dashed' },
|
|
{ label: 'Dotted', value: 'dotted' },
|
|
{ label: 'Dash-Dot', value: 'dashdot' }
|
|
]
|
|
|
|
// Watch for selected edge changes
|
|
watch(() => props.selectedEdge, (newEdge) => {
|
|
if (newEdge) {
|
|
// Load edge configuration
|
|
edgeConfig.value = {
|
|
label: newEdge.label || '',
|
|
type: newEdge.type || 'custom',
|
|
animated: newEdge.animated !== undefined ? newEdge.animated : true,
|
|
style: {
|
|
stroke: newEdge.style?.stroke || '#555',
|
|
strokeWidth: newEdge.style?.strokeWidth || 2,
|
|
strokeDasharray: newEdge.style?.strokeDasharray || ''
|
|
},
|
|
showStartArrow: !!newEdge.markerStart,
|
|
showEndArrow: !!newEdge.markerEnd,
|
|
dashPattern: getDashPatternFromStyle(newEdge.style?.strokeDasharray),
|
|
customPath: newEdge.data?.customPath || null,
|
|
zIndex: newEdge.zIndex || 0,
|
|
interactionWidth: newEdge.interactionWidth || 10,
|
|
updatable: newEdge.updatable !== undefined ? newEdge.updatable : true
|
|
}
|
|
}
|
|
}, { immediate: true })
|
|
|
|
// Helper function to determine dash pattern from style
|
|
function getDashPatternFromStyle(dasharray) {
|
|
if (!dasharray) return 'solid'
|
|
if (dasharray === '5 5') return 'dashed'
|
|
if (dasharray === '2 2') return 'dotted'
|
|
if (dasharray === '5 2 2 2') return 'dashdot'
|
|
return 'solid'
|
|
}
|
|
|
|
// Helper function to get dash array from pattern
|
|
function getDashArrayFromPattern(pattern) {
|
|
switch (pattern) {
|
|
case 'dashed': return '5 5'
|
|
case 'dotted': return '2 2'
|
|
case 'dashdot': return '5 2 2 2'
|
|
default: return ''
|
|
}
|
|
}
|
|
|
|
// Update edge function
|
|
function updateEdge() {
|
|
if (!props.selectedEdge) return
|
|
|
|
const updates = {
|
|
label: edgeConfig.value.label,
|
|
type: edgeConfig.value.type,
|
|
animated: edgeConfig.value.animated,
|
|
style: {
|
|
...edgeConfig.value.style,
|
|
strokeDasharray: getDashArrayFromPattern(edgeConfig.value.dashPattern)
|
|
},
|
|
markerStart: edgeConfig.value.showStartArrow ? 'url(#arrow)' : undefined,
|
|
markerEnd: edgeConfig.value.showEndArrow ? 'url(#arrow)' : undefined,
|
|
zIndex: edgeConfig.value.zIndex,
|
|
interactionWidth: edgeConfig.value.interactionWidth,
|
|
updatable: edgeConfig.value.updatable
|
|
}
|
|
|
|
emit('updateEdge', props.selectedEdge.id, updates)
|
|
}
|
|
|
|
// Reset path to auto-generated
|
|
function resetPath() {
|
|
if (!props.selectedEdge) return
|
|
|
|
edgeConfig.value.customPath = null
|
|
emit('updateEdge', props.selectedEdge.id, {
|
|
data: {
|
|
...props.selectedEdge.data,
|
|
customPath: null
|
|
}
|
|
})
|
|
}
|
|
|
|
// Delete edge
|
|
function deleteEdge() {
|
|
if (!props.selectedEdge) return
|
|
emit('deleteEdge', props.selectedEdge.id)
|
|
}
|
|
|
|
// Close configuration
|
|
function closeConfiguration() {
|
|
emit('close')
|
|
}
|
|
</script>
|
|
|
|
<style scoped>
|
|
.edge-configuration {
|
|
width: 300px;
|
|
max-height: 80vh;
|
|
overflow-y: auto;
|
|
}
|
|
|
|
:deep(.formkit-outer) {
|
|
margin-bottom: 1rem;
|
|
}
|
|
|
|
:deep(.formkit-label) {
|
|
font-size: 0.875rem;
|
|
font-weight: 500;
|
|
color: rgb(55 65 81);
|
|
}
|
|
|
|
:deep(.formkit-help) {
|
|
font-size: 0.75rem;
|
|
color: rgb(107 114 128);
|
|
}
|
|
|
|
:deep(.formkit-input[type="color"]) {
|
|
width: 100%;
|
|
height: 2.5rem;
|
|
border-radius: 0.375rem;
|
|
border: 1px solid rgb(209 213 219);
|
|
}
|
|
|
|
:deep(.formkit-input[type="range"]) {
|
|
width: 100%;
|
|
}
|
|
|
|
/* Custom scrollbar */
|
|
.edge-configuration::-webkit-scrollbar {
|
|
width: 6px;
|
|
}
|
|
|
|
.edge-configuration::-webkit-scrollbar-track {
|
|
background: #f1f1f1;
|
|
border-radius: 3px;
|
|
}
|
|
|
|
.edge-configuration::-webkit-scrollbar-thumb {
|
|
background: #c1c1c1;
|
|
border-radius: 3px;
|
|
}
|
|
|
|
.edge-configuration::-webkit-scrollbar-thumb:hover {
|
|
background: #a8a8a8;
|
|
}
|
|
</style> |