@@ -6,16 +6,16 @@ import { Button } from 'primeng/button';
66import { Checkbox } from 'primeng/checkbox' ;
77import { DynamicDialogConfig , DynamicDialogRef } from 'primeng/dynamicdialog' ;
88
9- import { ChangeDetectionStrategy , Component , effect , inject , OnInit , signal } from '@angular/core' ;
9+ import { ChangeDetectionStrategy , Component , effect , inject , OnInit , signal , WritableSignal } from '@angular/core' ;
1010import { FormControl , FormsModule , ReactiveFormsModule } from '@angular/forms' ;
1111
1212import { LoadingSpinnerComponent , TextInputComponent } from '@osf/shared/components' ;
1313import { InputLimits } from '@osf/shared/constants' ;
1414import { CustomValidators } from '@osf/shared/helpers' ;
15- import { CurrentResourceSelectors , GetResourceChildren } from '@osf/shared/stores' ;
16- import { ViewOnlyLinkChildren } from '@shared/models' ;
15+ import { CurrentResourceSelectors , GetResourceWithChildren } from '@osf/shared/stores' ;
1716
18- import { ResourceInfoModel } from '../../models' ;
17+ import { ResourceInfoModel , ViewOnlyLinkComponentItem } from '../../models' ;
18+ import { ComponentCheckboxItemComponent } from '../component-checkbox-item/component-checkbox-item.component' ;
1919
2020@Component ( {
2121 selector : 'osf-create-view-link-dialog' ,
@@ -27,6 +27,7 @@ import { ResourceInfoModel } from '../../models';
2727 Checkbox ,
2828 TextInputComponent ,
2929 LoadingSpinnerComponent ,
30+ ComponentCheckboxItemComponent ,
3031 ] ,
3132 templateUrl : './create-view-link-dialog.component.html' ,
3233 styleUrl : './create-view-link-dialog.component.scss' ,
@@ -38,122 +39,103 @@ export class CreateViewLinkDialogComponent implements OnInit {
3839 readonly inputLimits = InputLimits ;
3940
4041 linkName = new FormControl ( '' , { nonNullable : true , validators : [ CustomValidators . requiredTrimmed ( ) ] } ) ;
41-
4242 anonymous = signal ( true ) ;
43- selectedComponents = signal < Record < string , boolean > > ( { } ) ;
44- components = select ( CurrentResourceSelectors . getResourceChildren ) ;
45- isLoading = select ( CurrentResourceSelectors . isResourceChildrenLoading ) ;
46-
47- actions = createDispatchMap ( { getComponents : GetResourceChildren } ) ;
48-
49- get currentResource ( ) {
50- return this . config . data as ResourceInfoModel ;
51- }
52-
53- get allComponents ( ) : ViewOnlyLinkChildren [ ] {
54- const currentResourceData = this . currentResource ;
55- const components = this . components ( ) ;
56-
57- const result : ViewOnlyLinkChildren [ ] = [ ] ;
58-
59- if ( currentResourceData ) {
60- result . push ( {
61- id : currentResourceData . id ,
62- title : currentResourceData . title ,
63- isCurrentResource : true ,
64- } ) ;
65- }
6643
67- components . forEach ( ( comp ) => {
68- result . push ( {
69- id : comp . id ,
70- title : comp . title ,
71- isCurrentResource : false ,
72- } ) ;
73- } ) ;
44+ readonly components = select ( CurrentResourceSelectors . getResourceWithChildren ) ;
45+ readonly isLoading = select ( CurrentResourceSelectors . isResourceWithChildrenLoading ) ;
46+ readonly actions = createDispatchMap ( { getComponents : GetResourceWithChildren } ) ;
7447
75- return result ;
76- }
48+ componentsList : WritableSignal < ViewOnlyLinkComponentItem [ ] > = signal ( [ ] ) ;
7749
7850 constructor ( ) {
7951 effect ( ( ) => {
80- const components = this . allComponents ;
81- if ( components . length ) {
82- this . initializeSelection ( ) ;
83- }
52+ const currentResource = this . config . data as ResourceInfoModel ;
53+ const components = this . components ( ) ;
54+
55+ const items : ViewOnlyLinkComponentItem [ ] = components . map ( ( item ) => ( {
56+ id : item . id ,
57+ title : item . title ,
58+ isCurrentResource : currentResource . id === item . id ,
59+ parentId : item . parentId ,
60+ checked : currentResource . id === item . id ,
61+ disabled : currentResource . id === item . id ,
62+ } ) ) ;
63+
64+ const updatedItems = items . map ( ( item ) => ( {
65+ ...item ,
66+ disabled : item . isCurrentResource ? item . disabled : ! this . isParentChecked ( item , items ) ,
67+ } ) ) ;
68+
69+ this . componentsList . set ( updatedItems ) ;
8470 } ) ;
8571 }
8672
8773 ngOnInit ( ) : void {
88- const projectId = this . currentResource . id ;
74+ const currentResource = this . config . data as ResourceInfoModel ;
75+ const { id, type } = currentResource ;
8976
90- if ( projectId ) {
91- this . actions . getComponents ( projectId , this . currentResource . type ) ;
92- } else {
93- this . initializeSelection ( ) ;
77+ if ( id ) {
78+ this . actions . getComponents ( id , type ) ;
9479 }
9580 }
9681
97- private initializeSelection ( ) : void {
98- const initialState : Record < string , boolean > = { } ;
99-
100- this . allComponents . forEach ( ( component ) => {
101- initialState [ component . id ] = component . isCurrentResource ;
102- } ) ;
103-
104- this . selectedComponents . set ( initialState ) ;
82+ onCheckboxChange ( ) : void {
83+ this . componentsList . update ( ( items ) =>
84+ items . map ( ( item ) => ( {
85+ ...item ,
86+ disabled : item . isCurrentResource ? item . disabled : ! this . isParentChecked ( item , items ) ,
87+ } ) )
88+ ) ;
10589 }
10690
10791 addLink ( ) : void {
10892 if ( this . linkName . invalid ) return ;
10993
110- const selectedIds = Object . entries ( this . selectedComponents ( ) )
111- . filter ( ( [ , checked ] ) => checked )
112- . map ( ( [ id ] ) => id ) ;
94+ const currentResource = this . config . data as ResourceInfoModel ;
95+ const selectedIds = this . componentsList ( )
96+ . filter ( ( x ) => x . checked )
97+ . map ( ( x ) => x . id ) ;
11398
114- const rootProjectId = this . currentResource . id ;
115- const rootProject = selectedIds . includes ( rootProjectId ) ? [ { id : rootProjectId , type : 'nodes' } ] : [ ] ;
99+ const data = this . buildLinkData ( selectedIds , currentResource . id , this . linkName . value , this . anonymous ( ) ) ;
100+
101+ this . dialogRef . close ( data ) ;
102+ }
103+
104+ private isParentChecked ( item : ViewOnlyLinkComponentItem , items : ViewOnlyLinkComponentItem [ ] ) : boolean {
105+ if ( ! item . parentId ) {
106+ return true ;
107+ }
108+
109+ const parent = items . find ( ( x ) => x . id === item . parentId ) ;
116110
111+ return parent ?. checked ?? true ;
112+ }
113+
114+ private buildLinkData (
115+ selectedIds : string [ ] ,
116+ rootProjectId : string ,
117+ linkName : string ,
118+ isAnonymous : boolean
119+ ) : Record < string , unknown > {
120+ const rootProject = selectedIds . includes ( rootProjectId ) ? [ { id : rootProjectId , type : 'nodes' } ] : [ ] ;
117121 const relationshipComponents = selectedIds
118122 . filter ( ( id ) => id !== rootProjectId )
119123 . map ( ( id ) => ( { id, type : 'nodes' } ) ) ;
120124
121125 const data : Record < string , unknown > = {
122126 attributes : {
123- name : this . linkName . value ,
124- anonymous : this . anonymous ( ) ,
127+ name : linkName ,
128+ anonymous : isAnonymous ,
125129 } ,
126130 nodes : rootProject ,
127131 } ;
128132
129133 if ( relationshipComponents . length ) {
130134 data [ 'relationships' ] = {
131- nodes : {
132- data : relationshipComponents ,
133- } ,
135+ nodes : { data : relationshipComponents } ,
134136 } ;
135137 }
136138
137- this . dialogRef . close ( data ) ;
138- }
139-
140- onCheckboxToggle ( id : string , checked : boolean ) : void {
141- this . selectedComponents . update ( ( prev ) => ( { ...prev , [ id ] : checked } ) ) ;
142- }
143-
144- selectAllComponents ( ) : void {
145- const allIds : Record < string , boolean > = { } ;
146- this . allComponents . forEach ( ( component ) => {
147- allIds [ component . id ] = true ;
148- } ) ;
149- this . selectedComponents . set ( allIds ) ;
150- }
151-
152- deselectAllComponents ( ) : void {
153- const allIds : Record < string , boolean > = { } ;
154- this . allComponents . forEach ( ( component ) => {
155- allIds [ component . id ] = component . isCurrentResource ;
156- } ) ;
157- this . selectedComponents . set ( allIds ) ;
139+ return data ;
158140 }
159141}
0 commit comments