@@ -100,11 +100,12 @@ function filterTree(
100100 }
101101 const parent = parentInfo . parent ;
102102 if ( parent . templateId === relationTemplateId ) {
103+ if ( ! relationRules || relationRules . length === 0 ) return true ; // Match if just template id is specified
103104 const matches = ( relationRules || [ ] ) . every ( rule => {
104105 const fieldValue = ( parent . data || { } ) [ rule . fieldId ] ;
105106 return evaluateCondition ( rule . operator , fieldValue , rule . value ) ;
106107 } ) ;
107- if ( matches || ! relationRules || relationRules . length === 0 ) return true ;
108+ if ( matches ) return true ;
108109 }
109110 current = parent ;
110111 }
@@ -115,11 +116,12 @@ function filterTree(
115116 while ( queue . length > 0 ) {
116117 const currentNode = queue . shift ( ) ! ;
117118 if ( currentNode . templateId === relationTemplateId ) {
119+ if ( ! relationRules || relationRules . length === 0 ) return true ;
118120 const matches = ( relationRules || [ ] ) . every ( rule => {
119121 const fieldValue = ( currentNode . data || { } ) [ rule . fieldId ! ] ;
120122 return evaluateCondition ( rule . operator , fieldValue , rule . value ! ) ;
121123 } ) ;
122- if ( matches || ! relationRules || relationRules . length === 0 ) return true ;
124+ if ( matches ) return true ;
123125 }
124126 if ( currentNode . children ) {
125127 queue . push ( ...currentNode . children ) ;
@@ -178,11 +180,11 @@ function filterTree(
178180 }
179181 if ( type === 'ancestor' ) {
180182 if ( ! rule . relationTemplateId ) return false ;
181- return hasMatchingAncestor ( node , rule . relationTemplateId , rule . relationRules ! ) ;
183+ return hasMatchingAncestor ( node , rule . relationTemplateId , rule . relationRules ) ;
182184 }
183185 if ( type === 'descendant' ) {
184186 if ( ! rule . relationTemplateId ) return false ;
185- return hasMatchingDescendant ( node , rule . relationTemplateId , rule . relationRules ! ) ;
187+ return hasMatchingDescendant ( node , rule . relationTemplateId , rule . relationRules ) ;
186188 }
187189 return false ;
188190 } ) ;
@@ -661,66 +663,70 @@ export function TreePage() {
661663 const relationTemplate = rule . relationTemplateId ? getTemplateById ( rule . relationTemplateId ) : null ;
662664 return (
663665 < Card key = { rule . id || ruleIndex } className = "p-2 bg-background space-y-2" >
664- < div className = "flex items-center gap-2" >
665- < Select value = { ruleType } onValueChange = { ( val ) => handleRuleChange ( queryIndex , ruleIndex , 'type' , val ) } >
666- < SelectTrigger className = "w-32" > < SelectValue /> </ SelectTrigger >
667- < SelectContent >
668- < SelectItem value = "field" > Field</ SelectItem >
669- < SelectItem value = "ancestor" > Ancestor</ SelectItem >
670- < SelectItem value = "descendant" > Descendant</ SelectItem >
671- </ SelectContent >
672- </ Select >
666+ < div className = "space-y-4" >
667+ < div className = "flex items-center justify-between" >
668+ < Select value = { ruleType } onValueChange = { ( val ) => handleRuleChange ( queryIndex , ruleIndex , 'type' , val as any ) } >
669+ < SelectTrigger className = "w-auto" > < SelectValue /> </ SelectTrigger >
670+ < SelectContent >
671+ < SelectItem value = "field" > Field</ SelectItem >
672+ < SelectItem value = "ancestor" > Ancestor</ SelectItem >
673+ < SelectItem value = "descendant" > Descendant</ SelectItem >
674+ </ SelectContent >
675+ </ Select >
676+ < Button type = "button" variant = "ghost" size = "icon" className = "text-destructive h-8 w-8" onClick = { ( ) => removeRule ( queryIndex , ruleIndex ) } >
677+ < Trash2 className = "h-4 w-4" />
678+ </ Button >
679+ </ div >
673680 { ruleType === 'field' ? (
674- < >
681+ < div className = "space-y-2" >
675682 < Select value = { rule . fieldId || '' } onValueChange = { ( val ) => handleRuleChange ( queryIndex , ruleIndex , 'fieldId' , val ) } disabled = { ! targetTemplate } >
676683 < SelectTrigger > < SelectValue placeholder = "Field..." /> </ SelectTrigger >
677684 < SelectContent >
678685 { targetTemplate ?. fields . map ( f => < SelectItem key = { f . id } value = { f . id } > { f . name } </ SelectItem > ) }
679686 </ SelectContent >
680687 </ Select >
681- < Select value = { rule . operator || 'equals' } onValueChange = { ( val ) => handleRuleChange ( queryIndex , ruleIndex , 'operator' , val ) } >
682- < SelectTrigger className = "w-48" > < SelectValue placeholder = "Operator..." /> </ SelectTrigger >
688+ < Select value = { rule . operator || 'equals' } onValueChange = { ( val ) => handleRuleChange ( queryIndex , ruleIndex , 'operator' , val as any ) } >
689+ < SelectTrigger > < SelectValue placeholder = "Operator..." /> </ SelectTrigger >
683690 < SelectContent >
684691 { Object . entries ( operatorLabels ) . map ( ( [ op , label ] ) => < SelectItem key = { op } value = { op } > { label } </ SelectItem > ) }
685692 </ SelectContent >
686693 </ Select >
687694 < Input value = { rule . value || '' } onChange = { ( e ) => handleRuleChange ( queryIndex , ruleIndex , 'value' , e . target . value ) } placeholder = "Value..." />
688- </ >
695+ </ div >
689696 ) : (
690- < >
691- < span className = "text-sm" > has { ruleType } with template:</ span >
697+ < div className = "space-y-2" >
698+ < span className = "text-sm p-2 block " > has { ruleType } with template:</ span >
692699 < Select value = { rule . relationTemplateId || '' } onValueChange = { ( val ) => handleRuleChange ( queryIndex , ruleIndex , 'relationTemplateId' , val ) } >
693700 < SelectTrigger > < SelectValue placeholder = "Template..." /> </ SelectTrigger >
694701 < SelectContent >
695702 { templates . map ( t => < SelectItem key = { t . id } value = { t . id } > { t . name } </ SelectItem > ) }
696703 </ SelectContent >
697704 </ Select >
698- </ >
705+ </ div >
699706 ) }
700- < Button type = "button" variant = "ghost" size = "icon" className = "text-destructive h-8 w-8" onClick = { ( ) => removeRule ( queryIndex , ruleIndex ) } >
701- < Trash2 className = "h-4 w-4" />
702- </ Button >
703707 </ div >
704708 { ( ruleType === 'ancestor' || ruleType === 'descendant' ) && rule . relationTemplateId && (
705709 < div className = "pl-6 space-y-2" >
706710 < Label className = "text-xs text-muted-foreground" > Where...</ Label >
707711 { ( rule . relationRules || [ ] ) . map ( ( relRule , relRuleIndex ) => (
708712 < Card key = { relRule . id } className = "p-2 bg-muted/50" >
709- < div className = "flex items-center gap -2" >
713+ < div className = "space-y -2" >
710714 < Select value = { relRule . fieldId } onValueChange = { ( val ) => handleRelationRuleChange ( queryIndex , ruleIndex , relRuleIndex , 'fieldId' , val ) } >
711715 < SelectTrigger > < SelectValue placeholder = "Field..." /> </ SelectTrigger >
712716 < SelectContent > { relationTemplate ?. fields . map ( f => < SelectItem key = { f . id } value = { f . id } > { f . name } </ SelectItem > ) } </ SelectContent >
713717 </ Select >
714- < Select value = { relRule . operator } onValueChange = { ( val ) => handleRelationRuleChange ( queryIndex , ruleIndex , relRuleIndex , 'operator' , val ) } >
715- < SelectTrigger className = "w-48" > < SelectValue placeholder = "Operator..." /> </ SelectTrigger >
718+ < Select value = { relRule . operator } onValueChange = { ( val ) => handleRelationRuleChange ( queryIndex , ruleIndex , relRuleIndex , 'operator' , val as any ) } >
719+ < SelectTrigger > < SelectValue placeholder = "Operator..." /> </ SelectTrigger >
716720 < SelectContent >
717721 { Object . entries ( operatorLabels ) . map ( ( [ op , label ] ) => < SelectItem key = { op } value = { op } > { label } </ SelectItem > ) }
718722 </ SelectContent >
719723 </ Select >
720724 < Input value = { relRule . value } onChange = { ( e ) => handleRelationRuleChange ( queryIndex , ruleIndex , relRuleIndex , 'value' , e . target . value ) } placeholder = "Value..." />
721- < Button type = "button" variant = "ghost" size = "icon" className = "text-destructive h-8 w-8" onClick = { ( ) => removeRelationRule ( queryIndex , ruleIndex , relRuleIndex ) } >
722- < Trash2 className = "h-4 w-4" />
723- </ Button >
725+ < div className = "flex justify-end" >
726+ < Button type = "button" variant = "ghost" size = "icon" className = "text-destructive h-8 w-8" onClick = { ( ) => removeRelationRule ( queryIndex , ruleIndex , relRuleIndex ) } >
727+ < Trash2 className = "h-4 w-4" />
728+ </ Button >
729+ </ div >
724730 </ div >
725731 </ Card >
726732 ) ) }
0 commit comments