Refactor FormNodeConfiguration and ProcessFlowCanvas for Improved Usability and Code Clarity

- Adjusted indentation and formatting in FormNodeConfiguration.vue for better readability.
- Updated FormKit component usage to ensure consistent styling and functionality in user and role selection dropdowns.
- Enhanced computed properties for filtered users and roles to maintain consistent formatting.
- Changed connection mode in ProcessFlowCanvas.vue from 'loose' to 'strict' to enforce stricter connection rules.
- Improved comments in ProcessFlowCanvas.vue to clarify edge handling logic and preserve existing handle positions during updates.
This commit is contained in:
Afiq 2025-07-03 12:51:59 +08:00
parent 0cb5ed10b5
commit 99b2e43cfe
2 changed files with 24 additions and 25 deletions

View File

@ -473,14 +473,14 @@
<div class="space-y-3"> <div class="space-y-3">
<!-- User Dropdown --> <!-- User Dropdown -->
<div class="relative"> <div class="relative">
<FormKit <FormKit
type="select" type="select"
v-model="selectedUserId" v-model="selectedUserId"
:options="filteredAvailableUsers" :options="filteredAvailableUsers"
placeholder="Select a user to add..." placeholder="Select a user to add..."
:classes="{ outer: 'mb-0' }" :classes="{ outer: 'mb-0' }"
@input="handleUserSelection" @input="handleUserSelection"
/> />
<p class="mt-1 text-xs text-blue-700">Select users who will be able to complete this form task</p> <p class="mt-1 text-xs text-blue-700">Select users who will be able to complete this form task</p>
</div> </div>
@ -510,14 +510,14 @@
<div class="space-y-3"> <div class="space-y-3">
<!-- Role Dropdown --> <!-- Role Dropdown -->
<div class="relative"> <div class="relative">
<FormKit <FormKit
type="select" type="select"
v-model="selectedRoleId" v-model="selectedRoleId"
:options="filteredAvailableRoles" :options="filteredAvailableRoles"
placeholder="Select a role to add..." placeholder="Select a role to add..."
:classes="{ outer: 'mb-0' }" :classes="{ outer: 'mb-0' }"
@input="handleRoleSelection" @input="handleRoleSelection"
/> />
<p class="mt-1 text-xs text-purple-700">Select roles that will be able to complete this form task</p> <p class="mt-1 text-xs text-purple-700">Select roles that will be able to complete this form task</p>
</div> </div>
@ -904,11 +904,11 @@ const filteredAvailableUsers = computed(() => {
return users.value return users.value
.filter(user => !selectedUserIds.includes(String(user.userID))) .filter(user => !selectedUserIds.includes(String(user.userID)))
.map(user => ({ .map(user => ({
label: user.userFullName ? `${user.userFullName} (${user.userUsername})` : user.userUsername, label: user.userFullName ? `${user.userFullName} (${user.userUsername})` : user.userUsername,
value: String(user.userID), // Ensure value is a string value: String(user.userID), // Ensure value is a string
username: user.userUsername, username: user.userUsername,
email: user.userEmail email: user.userEmail
})); }));
}); });
// Computed property for available roles with filtering out already selected roles // Computed property for available roles with filtering out already selected roles
@ -919,10 +919,10 @@ const filteredAvailableRoles = computed(() => {
return roles.value return roles.value
.filter(role => !selectedRoleIds.includes(String(role.roleID))) .filter(role => !selectedRoleIds.includes(String(role.roleID)))
.map(role => ({ .map(role => ({
label: role.roleName, label: role.roleName,
value: String(role.roleID), // Ensure value is a string value: String(role.roleID), // Ensure value is a string
description: role.roleDescription description: role.roleDescription
})); }));
}); });
// Fetch users and roles data // Fetch users and roles data
@ -1046,7 +1046,7 @@ function handleUserSelection(userId) {
selectedUserId.value = ''; selectedUserId.value = '';
// Save changes // Save changes
saveChanges(); saveChanges();
} else { } else {
console.warn('Selected user not found in filtered available users', userIdStr); console.warn('Selected user not found in filtered available users', userIdStr);

View File

@ -54,9 +54,9 @@ const {
deleteKeyCode: 'Delete', deleteKeyCode: 'Delete',
selectionKeyCode: 'Shift', selectionKeyCode: 'Shift',
multiSelectionKeyCode: 'Control', multiSelectionKeyCode: 'Control',
connectionMode: 'loose', connectionMode: 'strict',
isValidConnection: (connection) => { isValidConnection: (connection) => {
// console.log('Validating connection:', connection); console.log('Validating connection:', connection);
return true; return true;
} }
}); });
@ -76,7 +76,7 @@ const flowOptions = ref({
snapToGrid: true, snapToGrid: true,
snapGrid: [15, 15], snapGrid: [15, 15],
edgeUpdaterRadius: 10, edgeUpdaterRadius: 10,
connectionMode: 'loose', connectionMode: 'strict',
connectionRadius: 25, connectionRadius: 25,
elevateEdgesOnSelect: true, elevateEdgesOnSelect: true,
nodesDraggable: true, nodesDraggable: true,
@ -282,7 +282,7 @@ watch(() => [props.initialEdges, nodes.value.length], async ([newEdges, nodeCoun
if (edgesToAdd.length > 0) { if (edgesToAdd.length > 0) {
// Ensure all edges have proper handle specifications // Ensure all edges have proper handle specifications
const edgesWithHandles = edgesToAdd.map(edge => { const edgesWithHandles = edgesToAdd.map(edge => {
// If edge already has sourceHandle and targetHandle, use them // IMPORTANT: If edge already has sourceHandle and targetHandle, preserve them exactly as they are
if (edge.sourceHandle && edge.targetHandle) { if (edge.sourceHandle && edge.targetHandle) {
return edge; return edge;
} }
@ -325,23 +325,22 @@ watch(() => [props.initialEdges, nodes.value.length], async ([newEdges, nodeCoun
// console.log('ProcessFlowCanvas: Successfully added edges with handles:', edgesWithHandles.length); // console.log('ProcessFlowCanvas: Successfully added edges with handles:', edgesWithHandles.length);
} }
// Update existing edges that have changed // Update existing edges that have changed - IMPORTANT: preserve handle positions
newEdges.forEach(newEdge => { newEdges.forEach(newEdge => {
const existingEdge = edges.value.find(e => e.id === newEdge.id); const existingEdge = edges.value.find(e => e.id === newEdge.id);
if (existingEdge) { if (existingEdge) {
// Check if the edge has actually changed before updating // Check if the edge has actually changed before updating
const hasChanges = ( const hasChanges = (
existingEdge.label !== newEdge.label || existingEdge.label !== newEdge.label ||
existingEdge.sourceHandle !== newEdge.sourceHandle ||
existingEdge.targetHandle !== newEdge.targetHandle ||
JSON.stringify(existingEdge.style) !== JSON.stringify(newEdge.style) JSON.stringify(existingEdge.style) !== JSON.stringify(newEdge.style)
); );
if (hasChanges) { if (hasChanges) {
Object.assign(existingEdge, { Object.assign(existingEdge, {
label: newEdge.label, label: newEdge.label,
sourceHandle: newEdge.sourceHandle, // Preserve existing handles if they exist
targetHandle: newEdge.targetHandle, sourceHandle: existingEdge.sourceHandle || newEdge.sourceHandle,
targetHandle: existingEdge.targetHandle || newEdge.targetHandle,
style: newEdge.style ? { ...newEdge.style } : undefined style: newEdge.style ? { ...newEdge.style } : undefined
}); });
} }