diff --git a/client/src/components/dynamic-groups/condition-builder.tsx b/client/src/components/dynamic-groups/condition-builder.tsx index be9b9be..af9a525 100644 --- a/client/src/components/dynamic-groups/condition-builder.tsx +++ b/client/src/components/dynamic-groups/condition-builder.tsx @@ -6,22 +6,7 @@ import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@ import { Card, CardContent } from '@/components/ui/card'; import { useToast } from '@/hooks/use-toast'; import { useQuery } from '@tanstack/react-query'; -import { - DndContext, - closestCenter, - KeyboardSensor, - PointerSensor, - useSensor, - useSensors, - DragEndEvent -} from '@dnd-kit/core'; -import { - arrayMove, - SortableContext, - sortableKeyboardCoordinates, - useSortable -} from '@dnd-kit/sortable'; -import { Trash, Plus, Move, PlusCircle, FolderPlus, ChevronDown, ChevronRight } from 'lucide-react'; +import { Trash, Plus, Move, FolderPlus, ChevronDown, ChevronRight } from 'lucide-react'; import { Condition } from './rule-editor'; import { LdapAttribute } from '@shared/schema'; @@ -61,6 +46,7 @@ const defaultGroup: Condition = { isGroup: true }; +// This is a completely new implementation of the condition builder to avoid recursive rendering const ConditionBuilder: React.FC = ({ conditions, onChange, @@ -186,42 +172,6 @@ const ConditionBuilder: React.FC = ({ } }; - // Setup drag sensors - const sensors = useSensors( - useSensor(PointerSensor), - useSensor(KeyboardSensor, { - coordinateGetter: sortableKeyboardCoordinates, - }) - ); - - // Handle drag and drop - const handleDragEnd = (event: DragEndEvent) => { - const { active, over } = event; - - if (!over) return; - - if (active.id !== over.id) { - const activeIndex = conditions.findIndex(c => c.id === active.id); - const overIndex = conditions.findIndex(c => c.id === over.id); - - // Don't allow dropping a condition outside its parent group - const sourceCondition = conditions[activeIndex]; - const overCondition = conditions[overIndex]; - - if (sourceCondition.parentId !== overCondition.parentId) { - toast({ - title: "Invalid Move", - description: "Conditions can only be reordered within the same group", - variant: "destructive" - }); - return; - } - - const newConditions = arrayMove(conditions, activeIndex, overIndex); - onChange(newConditions); - } - }; - // Toggle group expansion const toggleGroupExpand = (groupId: number) => { setExpandedGroups(prev => { @@ -244,182 +194,162 @@ const ConditionBuilder: React.FC = ({ ); }; - // Removed unused renderConditionGroup function - - // Sortable Item wrapper component - const SortableItem = ({ - condition, - index, - level = 0 - }: { - condition: Condition; - index: number; - level?: number; - }) => { - const { - attributes, - listeners, - setNodeRef, - transform, - transition, - isDragging - } = useSortable({ - id: condition.id || index, - data: { - condition, - index, - level, - type: condition.isGroup ? 'group' : 'condition' - } - }); - - const style = { - transform: transform ? `translate3d(${transform.x}px, ${transform.y}px, 0)` : undefined, - transition, - marginLeft: level > 0 ? `${level * 20}px` : '0', - zIndex: isDragging ? 100 : 1, - position: 'relative' as 'relative', - opacity: isDragging ? 0.5 : 1, - }; - - return ( -
- {condition.isGroup ? ( -
-
-
- - - - Condition Group ({condition.logicalOperator}) - -
+ // Render a single condition + const renderCondition = (condition: Condition, index: number, level = 0) => { + if (condition.isGroup) { + // Render condition group + return ( +
0 ? `${level * 20}px` : '0' }} + > +
+
+ -
- - - - - - - - - -
+ + Condition Group ({condition.logicalOperator}) +
- {condition.id && expandedGroups.has(condition.id) && ( -
- {condition.id ? ( - (() => { - const childConditions = getConditionsForParent(condition.id); - return childConditions.length === 0 ? ( -
- No conditions in this group. Add one using the buttons above. -
- ) : ( - childConditions.map((child, childIndex) => { - const originalIndex = conditions.findIndex(c => c === child); - return ; - }) - ); - })() - ) : null} -
- )} +
+ + + + + + + +
- ) : ( - renderConditionContent(condition, index, level, listeners) - )} -
- ); - }; - - // Render condition content (without the wrapper) - const renderConditionContent = ( - condition: Condition, - index: number, - level = 0, - listeners?: ReturnType['listeners'] - ) => { - return ( -
-
- + + {condition.id && expandedGroups.has(condition.id) && ( +
+ {renderChildConditions(condition.id, level + 1)} +
+ )}
- {index > 0 && !condition.isGroup && condition.parentId === conditions[index-1].parentId && ( -
+ ); + } else { + // Render regular condition (not a group) + return ( +
0 ? `${level * 20}px` : '0' }} + > +
+ +
+ + {index > 0 && !condition.isGroup && condition.parentId === conditions[index-1].parentId && ( +
+ +
+ )} + + {(index === 0 || condition.parentId !== conditions[index-1].parentId) && ( +
+ )} + +
+ + {condition.attribute === 'custom' && ( + updateCondition(index, 'customAttribute', e.target.value)} + /> + )} +
+ +
+
- )} - - {(index === 0 || condition.parentId !== conditions[index-1].parentId) && ( -
- )} - -
- - {condition.attribute === 'custom' && ( - updateCondition(index, 'customAttribute', e.target.value)} - /> - )} +
+ {condition.operator !== 'present' && condition.operator !== 'notPresent' && ( + updateCondition(index, 'value', e.target.value)} + /> + )} +
+ +
+ +
- -
- + ); + } + }; + + // Render all child conditions of a parent + const renderChildConditions = (parentId: number, level = 0) => { + const childConditions = getConditionsForParent(parentId); + + if (childConditions.length === 0) { + return ( +
+ No conditions in this group. Add one using the buttons above.
- -
- {condition.operator !== 'present' && condition.operator !== 'notPresent' && ( - updateCondition(index, 'value', e.target.value)} - /> - )} -
- -
- -
-
- ); + ); + } + + return childConditions.map((condition, i) => { + const index = conditions.findIndex(c => c === condition); + return renderCondition(condition, index, level); + }); }; return ( @@ -531,25 +429,16 @@ const ConditionBuilder: React.FC = ({ ) : ( <> - - c.id || 0)}> -
- {conditions.map((condition, index) => ( - condition.parentId === null || condition.parentId === undefined ? ( - - ) : null - ))} -
-
-
+
+ {/* Render root-level conditions */} + {conditions + .filter(c => c.parentId === null || c.parentId === undefined) + .map((condition, i) => { + const index = conditions.findIndex(c => c === condition); + return renderCondition(condition, index, 0); + }) + } +