Skip to content

Commit 449b33a

Browse files
Merge pull request #454 from dreamfactorysoftware/DP-772
[DP-772] Fix for Role Based Access Tab delete/update bug
2 parents b6ad3cd + 59623f7 commit 449b33a

File tree

3 files changed

+130
-21
lines changed

3 files changed

+130
-21
lines changed

src/app/adf-roles/df-role-details/df-role-details.component.ts

Lines changed: 55 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -259,9 +259,62 @@ export class DfRoleDetailsComponent implements OnInit {
259259
}
260260

261261
onSubmit() {
262-
if (this.roleForm.invalid) return;
262+
// Clear validators for all hidden items before validation
263+
const serviceAccess = this.roleForm.get('serviceAccess') as FormArray;
264+
serviceAccess.controls.forEach((control, index) => {
265+
if (!this.visibilityArray[index]) {
266+
console.log(`Clearing validators for hidden item at index ${index}`);
267+
control.get('service')?.clearValidators();
268+
control.get('component')?.clearValidators();
269+
control.get('access')?.clearValidators();
270+
control.get('requester')?.clearValidators();
271+
control.get('service')?.updateValueAndValidity();
272+
control.get('component')?.updateValueAndValidity();
273+
control.get('access')?.updateValueAndValidity();
274+
control.get('requester')?.updateValueAndValidity();
275+
}
276+
});
277+
278+
if (this.roleForm.invalid) {
279+
// Mark all controls as touched to show validation errors
280+
this.roleForm.markAllAsTouched();
281+
282+
console.log('Form is invalid:', this.roleForm.errors);
283+
console.log('Form controls validity:', {
284+
name: this.roleForm.get('name')?.errors,
285+
description: this.roleForm.get('description')?.errors,
286+
active: this.roleForm.get('active')?.errors,
287+
serviceAccess: this.roleForm.get('serviceAccess')?.errors,
288+
lookupKeys: this.roleForm.get('lookupKeys')?.errors,
289+
});
290+
291+
serviceAccess.controls.forEach((control, index) => {
292+
console.log(`ServiceAccess[${index}] valid:`, control.valid, 'visibility:', this.visibilityArray[index]);
293+
if (control.invalid) {
294+
console.log(`ServiceAccess[${index}] errors:`, control.errors);
295+
console.log(`ServiceAccess[${index}] controls errors:`, {
296+
service: control.get('service')?.errors,
297+
component: control.get('component')?.errors,
298+
access: control.get('access')?.errors,
299+
requester: control.get('requester')?.errors,
300+
});
301+
console.log(`ServiceAccess[${index}] controls valid:`, {
302+
service: control.get('service')?.valid,
303+
component: control.get('component')?.valid,
304+
access: control.get('access')?.valid,
305+
requester: control.get('requester')?.valid,
306+
});
307+
console.log(`ServiceAccess[${index}] values:`, control.value);
308+
}
309+
});
310+
311+
return;
312+
}
263313
const formValue = this.roleForm.getRawValue();
264-
if (formValue.name === '' || formValue.name === null) return;
314+
if (formValue.name === '' || formValue.name === null) {
315+
console.log('Form name is empty');
316+
return;
317+
}
265318
const payload: RolePayload = {
266319
id: formValue.id,
267320
name: formValue.name,

src/app/adf-roles/df-roles-access/df-roles-access.component.html

Lines changed: 30 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -21,22 +21,26 @@
2121
<td
2222
mat-cell
2323
*matCellDef="let row; let i = dataIndex"
24-
[formGroupName]="i">
24+
[formGroupName]="getFormArrayIndex(i)">
2525
<mat-form-field subscriptSizing="dynamic" appearance="outline">
2626
<mat-label>{{
2727
'roles.accessOverview.tableHeadings.service' | transloco
2828
}}</mat-label>
2929
<mat-select
3030
formControlName="service"
3131
panelWidth="null"
32-
(selectionChange)="getComponents(i)">
32+
(selectionChange)="getComponents(getFormArrayIndex(i))"
33+
required>
3334
<mat-option [value]="0">All</mat-option>
3435
<mat-option
3536
*ngFor="let option of serviceOptions"
3637
[value]="option.id"
3738
>{{ option.name }}</mat-option
3839
>
3940
</mat-select>
41+
<mat-error *ngIf="formArray.controls[getFormArrayIndex(i)]?.get('service')?.hasError('required')">
42+
Service is required
43+
</mat-error>
4044
</mat-form-field>
4145
</td>
4246
</ng-container>
@@ -48,18 +52,21 @@
4852
<td
4953
mat-cell
5054
*matCellDef="let row; let i = dataIndex"
51-
[formGroupName]="i">
55+
[formGroupName]="getFormArrayIndex(i)">
5256
<mat-form-field subscriptSizing="dynamic" appearance="outline">
5357
<mat-label>{{
5458
'roles.accessOverview.tableHeadings.component' | transloco
5559
}}</mat-label>
56-
<mat-select formControlName="component" panelWdith="null">
60+
<mat-select formControlName="component" panelWdith="null" required>
5761
<mat-option
58-
*ngFor="let option of getComponentArray(i)"
62+
*ngFor="let option of getComponentArray(getFormArrayIndex(i))"
5963
[value]="option"
6064
>{{ option }}</mat-option
6165
>
6266
</mat-select>
67+
<mat-error *ngIf="formArray.controls[getFormArrayIndex(i)]?.get('component')?.hasError('required')">
68+
Component is required
69+
</mat-error>
6370
</mat-form-field>
6471
</td>
6572
</ng-container>
@@ -71,7 +78,7 @@
7178
<td
7279
mat-cell
7380
*matCellDef="let row; let i = dataIndex"
74-
[formGroupName]="i">
81+
[formGroupName]="getFormArrayIndex(i)">
7582
<mat-form-field subscriptSizing="dynamic" appearance="outline">
7683
<mat-label>{{
7784
'roles.accessOverview.tableHeadings.access' | transloco
@@ -80,27 +87,31 @@
8087
formControlName="access"
8188
multiple
8289
panelWidth="null"
83-
(selectionChange)="accessChange(i, $event.value)">
90+
(selectionChange)="accessChange(getFormArrayIndex(i), $event.value)"
91+
required>
8492
<mat-option
8593
*ngFor="let option of accessOptions"
8694
[value]="option.value"
8795
>{{ option.label }}
8896
<span
8997
class="example-additional-selection"
9098
*ngIf="
91-
(formArray.controls[i].value.access.length || 0) > 1
99+
(formArray.controls[getFormArrayIndex(i)]?.value.access.length || 0) > 1
92100
">
93101
(+{{
94-
(formArray.controls[i].value.access.length || 0) - 1
102+
(formArray.controls[getFormArrayIndex(i)]?.value.access.length || 0) - 1
95103
}}
96104
{{
97-
formArray.controls[i].value.access.length === 2
105+
formArray.controls[getFormArrayIndex(i)]?.value.access.length === 2
98106
? 'other'
99107
: 'others'
100108
}})
101109
</span>
102110
</mat-option>
103111
</mat-select>
112+
<mat-error *ngIf="formArray.controls[getFormArrayIndex(i)]?.get('access')?.hasError('required')">
113+
Access is required
114+
</mat-error>
104115
</mat-form-field>
105116
</td>
106117
</ng-container>
@@ -112,7 +123,7 @@
112123
<td
113124
mat-cell
114125
*matCellDef="let row; let i = dataIndex"
115-
[formGroupName]="i">
126+
[formGroupName]="getFormArrayIndex(i)">
116127
<mat-form-field subscriptSizing="dynamic" appearance="outline">
117128
<mat-label>{{
118129
'roles.accessOverview.tableHeadings.requester' | transloco
@@ -140,12 +151,12 @@
140151
<td
141152
mat-cell
142153
*matCellDef="let row; let i = dataIndex"
143-
[formGroupName]="i">
154+
[formGroupName]="getFormArrayIndex(i)">
144155
<button
145156
mat-icon-button
146157
color="primary"
147158
type="button"
148-
(click)="toggleRow(row, i)">
159+
(click)="toggleRow(row, getFormArrayIndex(i))">
149160
<fa-icon [icon]="faPlus" size="xs"></fa-icon>
150161
</button>
151162
</td>
@@ -165,7 +176,7 @@
165176
<td
166177
mat-cell
167178
*matCellDef="let row; let i = dataIndex"
168-
[formGroupName]="i">
179+
[formGroupName]="getFormArrayIndex(i)">
169180
<button mat-icon-button (click)="remove(i)">
170181
<fa-icon [icon]="faTrashCan" size="xs"></fa-icon>
171182
</button>
@@ -177,7 +188,7 @@
177188
mat-cell
178189
*matCellDef="let element; let i = dataIndex"
179190
[attr.colspan]="6"
180-
[formGroupName]="i">
191+
[formGroupName]="getFormArrayIndex(i)">
181192
<div
182193
class="element-detail"
183194
formArrayName="advancedFilters"
@@ -186,7 +197,7 @@
186197
">
187198
<ng-container
188199
*ngFor="
189-
let advancedFilter of getAdvancedFilters(i).controls;
200+
let advancedFilter of getAdvancedFilters(getFormArrayIndex(i)).controls;
190201
let j = index
191202
">
192203
<div [formArrayName]="j" class="expandedItems">
@@ -220,7 +231,7 @@
220231
<mat-button-toggle-group
221232
aria-label="Service Definition Type"
222233
formControlName="filterOp"
223-
(change)="filterOpChange($event, i)">
234+
(change)="filterOpChange($event, getFormArrayIndex(i))">
224235
<mat-button-toggle value="AND">AND</mat-button-toggle>
225236
<mat-button-toggle value="OR">OR</mat-button-toggle>
226237
</mat-button-toggle-group>
@@ -229,13 +240,13 @@
229240
<button
230241
mat-icon-button
231242
type="button"
232-
(click)="addAdvancedFilter(i)">
243+
(click)="addAdvancedFilter(getFormArrayIndex(i))">
233244
<fa-icon [icon]="faPlus" size="xs"></fa-icon>
234245
</button>
235246
<button
236247
mat-icon-button
237248
type="button"
238-
(click)="removeAdvancedFilter(i, j)">
249+
(click)="removeAdvancedFilter(getFormArrayIndex(i), j)">
239250
<fa-icon [icon]="faTrashCan" size="xs"></fa-icon>
240251
</button>
241252
</div>

src/app/adf-roles/df-roles-access/df-roles-access.component.ts

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,19 @@ export class DfRolesAccessComponent implements OnInit {
204204
return components || [];
205205
}
206206

207+
getFormArrayIndex(visibleIndex: number): number {
208+
let visibleCount = 0;
209+
for (let i = 0; i < this.visible.length; i++) {
210+
if (this.visible[i]) {
211+
if (visibleCount === visibleIndex) {
212+
return i;
213+
}
214+
visibleCount++;
215+
}
216+
}
217+
return -1;
218+
}
219+
207220
filterOptions(event: Event, index: number) {
208221
const input = (event.target as HTMLInputElement).value.toLowerCase();
209222
const serviceId = this.formArray.at(index).get('service')?.value;
@@ -294,6 +307,7 @@ export class DfRolesAccessComponent implements OnInit {
294307
})
295308
);
296309
this.visible.push(true);
310+
console.log('FormArray after add:', this.formArray.value, 'Visible:', this.visible);
297311
this.updateDataSource();
298312
}
299313

@@ -323,9 +337,40 @@ export class DfRolesAccessComponent implements OnInit {
323337
}
324338

325339
remove(index: number) {
340+
console.log('Remove called with index:', index, 'Visible array before:', [...this.visible]);
326341
if (index >= 0 && index < this.formArray.length) {
342+
// Find the actual form array index for the nth visible item BEFORE updating visible array
343+
let visibleCount = 0;
344+
let actualIndex = -1;
345+
for (let i = 0; i < this.visible.length; i++) {
346+
if (this.visible[i]) {
347+
if (visibleCount === index) {
348+
actualIndex = i;
349+
break;
350+
}
351+
visibleCount++;
352+
}
353+
}
354+
console.log('Actual form array index to hide:', actualIndex);
355+
327356
this.visible = this.updateNthTrueToFalse(this.visible, index);
357+
358+
// Clear validators for the hidden item
359+
if (actualIndex !== -1 && actualIndex < this.formArray.length) {
360+
const formGroup = this.formArray.at(actualIndex);
361+
console.log('Clearing validators for form group at index:', actualIndex);
362+
formGroup.get('service')?.clearValidators();
363+
formGroup.get('component')?.clearValidators();
364+
formGroup.get('access')?.clearValidators();
365+
formGroup.get('requester')?.clearValidators();
366+
formGroup.get('service')?.updateValueAndValidity();
367+
formGroup.get('component')?.updateValueAndValidity();
368+
formGroup.get('access')?.updateValueAndValidity();
369+
formGroup.get('requester')?.updateValueAndValidity();
370+
console.log('Form group validity after clearing:', formGroup.valid);
371+
}
328372
}
373+
console.log('FormArray after remove:', this.formArray.value, 'Visible:', this.visible);
329374
this.updateDataSource();
330375
}
331376

0 commit comments

Comments
 (0)