Skip to content

Commit b30ce1e

Browse files
committed
feat(admin): check disabled and hidden dependencies for application items
* Provide a warning message when trying to change source or destination attribute for items which are marked as hidden or disabled dependency for another form item. * Display an error in dialog when trying to delete an item which is marked as hidden or disabled dependency for another form item (it used to throw an uncatched exception).
1 parent 8682866 commit b30ce1e

File tree

11 files changed

+114
-24
lines changed

11 files changed

+114
-24
lines changed

apps/admin-gui/src/app/shared/components/dialogs/delete-application-form-item-dialog/delete-application-form-item-dialog.component.html

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,23 @@
11
<h1 mat-dialog-title>{{'DIALOGS.DELETE_APPLICATION_FORM_ITEM.TITLE' | translate}}</h1>
22
<div class="dialog-container" mat-dialog-content>
3-
<div class="pb-2 fw-bold">
4-
{{'DIALOGS.DELETE_APPLICATION_FORM_ITEM.INFO_1' | translate}}
3+
<div *ngIf="!deletionDisabled">
4+
<div class="pb-2 fw-bold">
5+
{{'DIALOGS.DELETE_APPLICATION_FORM_ITEM.INFO_1' | translate}}
6+
</div>
7+
<div>{{'DIALOGS.DELETE_APPLICATION_FORM_ITEM.INFO_2' | translate}}</div>
8+
<div class="pb-4 pt-2">{{'DIALOGS.DELETE_APPLICATION_FORM_ITEM.INFO_3' | translate}}</div>
59
</div>
6-
<div>{{'DIALOGS.DELETE_APPLICATION_FORM_ITEM.INFO_2' | translate}}</div>
7-
<div class="pb-4 pt-2">{{'DIALOGS.DELETE_APPLICATION_FORM_ITEM.INFO_3' | translate}}</div>
10+
<perun-web-apps-alert *ngIf="deletionDisabled" alert_type="error">
11+
{{data.errorMessage}}
12+
</perun-web-apps-alert>
813
</div>
914
<div mat-dialog-actions>
1015
<button (click)="onCancel()" class="ms-auto" mat-stroked-button>
1116
{{'DIALOGS.DELETE_APPLICATION_FORM_ITEM.CANCEL_BUTTON' | translate}}
1217
</button>
1318
<button
1419
(click)="submit()"
20+
[disabled]="deletionDisabled"
1521
class="ms-2"
1622
color="warn"
1723
data-cy="delete-application-form-item-dialog"

apps/admin-gui/src/app/shared/components/dialogs/delete-application-form-item-dialog/delete-application-form-item-dialog.component.ts

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,24 @@
1-
import { Component } from '@angular/core';
2-
import { MatDialogRef } from '@angular/material/dialog';
1+
import { Component, Inject } from '@angular/core';
2+
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
3+
4+
export interface DeleteApplicationFormItemDialogData {
5+
errorMessage: string;
6+
}
37

48
@Component({
59
selector: 'app-delete-application-form-item-dialog',
610
templateUrl: './delete-application-form-item-dialog.component.html',
711
styleUrls: ['./delete-application-form-item-dialog.component.scss'],
812
})
913
export class DeleteApplicationFormItemDialogComponent {
10-
constructor(private dialogRef: MatDialogRef<DeleteApplicationFormItemDialogComponent>) {}
14+
deletionDisabled: boolean;
15+
16+
constructor(
17+
private dialogRef: MatDialogRef<DeleteApplicationFormItemDialogComponent>,
18+
@Inject(MAT_DIALOG_DATA) public data: DeleteApplicationFormItemDialogData
19+
) {
20+
this.deletionDisabled = this.data.errorMessage?.length !== 0;
21+
}
1122

1223
onCancel(): void {
1324
this.dialogRef.close(false);

apps/admin-gui/src/app/shared/components/dialogs/edit-application-form-item-dialog/edit-application-form-item-dialog.component.html

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,8 @@ <h1 mat-dialog-title>
6767
<perun-web-apps-selection-item-search-select
6868
[attributes]="sourceAttributes"
6969
[selectedAttribute]="applicationFormItem.perunSourceAttribute"
70-
(itemSelected)="applicationFormItem.perunSourceAttribute = $event.value"
70+
(itemSelected)="applicationFormItem.perunSourceAttribute = $event.value; loadWarning(itemType.SOURCE)"
71+
[warning]="displayWarningForSourceAttr ? warningMessage : ''"
7172
[asGroup]="!!data.group"
7273
[type]="itemType.SOURCE">
7374
</perun-web-apps-selection-item-search-select>
@@ -81,7 +82,8 @@ <h1 mat-dialog-title>
8182
<perun-web-apps-selection-item-search-select
8283
[attributes]="destinationAttributes"
8384
[selectedAttribute]="applicationFormItem.perunDestinationAttribute"
84-
(itemSelected)="applicationFormItem.perunDestinationAttribute = $event.value"
85+
(itemSelected)="applicationFormItem.perunDestinationAttribute = $event.value; loadWarning(itemType.DESTINATION)"
86+
[warning]="displayWarningForDestinationAttr ? warningMessage : ''"
8587
[asGroup]="!!data.group"
8688
[type]="itemType.DESTINATION">
8789
</perun-web-apps-selection-item-search-select>

apps/admin-gui/src/app/shared/components/dialogs/edit-application-form-item-dialog/edit-application-form-item-dialog.component.ts

Lines changed: 39 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import { ChangeDetectorRef, Component, Inject, OnInit } from '@angular/core';
22
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
3-
import { TranslateService } from '@ngx-translate/core';
43
import {
54
ApplicationFormItem,
65
AppType,
@@ -13,7 +12,11 @@ import { createNewApplicationFormItem } from '@perun-web-apps/perun/utils';
1312
import DisabledEnum = ApplicationFormItem.DisabledEnum;
1413
import HiddenEnum = ApplicationFormItem.HiddenEnum;
1514
import { ItemType, NO_FORM_ITEM, SelectionItem } from '@perun-web-apps/perun/components';
16-
import { HtmlEscapeService, StoreService } from '@perun-web-apps/perun/services';
15+
import {
16+
HtmlEscapeService,
17+
PerunTranslateService,
18+
StoreService,
19+
} from '@perun-web-apps/perun/services';
1720
import { FormControl, FormGroup } from '@angular/forms';
1821

1922
export interface EditApplicationFormItemDialogComponentData {
@@ -69,6 +72,9 @@ export class EditApplicationFormItemDialogComponent implements OnInit {
6972

7073
hiddenDependencyItem: ApplicationFormItem = null;
7174
disabledDependencyItem: ApplicationFormItem = null;
75+
warningMessage = '';
76+
displayWarningForSourceAttr = false;
77+
displayWarningForDestinationAttr = false;
7278
languages = ['en'];
7379
private dependencyTypes: Type[] = [
7480
'PASSWORD',
@@ -86,7 +92,7 @@ export class EditApplicationFormItemDialogComponent implements OnInit {
8692
private dialogRef: MatDialogRef<EditApplicationFormItemDialogComponent>,
8793
@Inject(MAT_DIALOG_DATA) public data: EditApplicationFormItemDialogComponentData,
8894
private attributesManager: AttributesManagerService,
89-
private translateService: TranslateService,
95+
private translate: PerunTranslateService,
9096
private store: StoreService,
9197
private cd: ChangeDetectorRef,
9298
private escapeService: HtmlEscapeService
@@ -145,6 +151,36 @@ export class EditApplicationFormItemDialogComponent implements OnInit {
145151
this.getOptions();
146152
}
147153

154+
loadWarning(itemType: ItemType): void {
155+
this.warningMessage = '';
156+
const hiddenDependencyForItem = this.data.allItems.find(
157+
(item) => item.hiddenDependencyItemId === this.data.applicationFormItem.id
158+
);
159+
const disabledDependencyForItem = this.data.allItems.find(
160+
(item) => item.disabledDependencyItemId === this.data.applicationFormItem.id
161+
);
162+
if (hiddenDependencyForItem || disabledDependencyForItem) {
163+
if (itemType === ItemType.SOURCE) {
164+
this.displayWarningForSourceAttr = true;
165+
} else {
166+
this.displayWarningForDestinationAttr = true;
167+
}
168+
this.warningMessage = this.translate.instant(
169+
'DIALOGS.APPLICATION_FORM_EDIT_ITEM.DEPENDENCY_WARNING_MESSAGE',
170+
hiddenDependencyForItem
171+
? {
172+
dependency: 'hidden',
173+
shortname: hiddenDependencyForItem.shortname,
174+
}
175+
: {
176+
dependency: 'disabled',
177+
shortname: disabledDependencyForItem.shortname,
178+
}
179+
);
180+
this.cd.detectChanges();
181+
}
182+
}
183+
148184
cancel(): void {
149185
this.dialogRef.close();
150186
}

apps/admin-gui/src/app/vos/components/application-form-list/application-form-list.component.ts

Lines changed: 35 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,7 @@ import { MatDialog } from '@angular/material/dialog';
1111
import { MatTable } from '@angular/material/table';
1212
import { CdkDragDrop, moveItemInArray } from '@angular/cdk/drag-drop';
1313
import { DeleteApplicationFormItemDialogComponent } from '../../../shared/components/dialogs/delete-application-form-item-dialog/delete-application-form-item-dialog.component';
14-
import { NotificatorService } from '@perun-web-apps/perun/services';
15-
import { TranslateService } from '@ngx-translate/core';
14+
import { NotificatorService, PerunTranslateService } from '@perun-web-apps/perun/services';
1615
import { EditApplicationFormItemDialogComponent } from '../../../shared/components/dialogs/edit-application-form-item-dialog/edit-application-form-item-dialog.component';
1716
import { ApplicationForm, ApplicationFormItem } from '@perun-web-apps/perun/openapi';
1817
import { getDefaultDialogConfig } from '@perun-web-apps/perun/utils';
@@ -67,37 +66,37 @@ export class ApplicationFormListComponent implements OnInit, OnChanges {
6766
private dialog: MatDialog,
6867
private notificator: NotificatorService,
6968
private router: Router,
70-
private translate: TranslateService
69+
private translate: PerunTranslateService
7170
) {}
7271

7372
ngOnInit(): void {
7473
// labels for hidden and disabled icons
7574
this.ifEmpty = this.translate.instant(
7675
'VO_DETAIL.SETTINGS.APPLICATION_FORM.DISABLED_HIDDEN_ICON.IF_EMPTY'
77-
) as string;
76+
);
7877
this.ifPrefilled = this.translate.instant(
7978
'VO_DETAIL.SETTINGS.APPLICATION_FORM.DISABLED_HIDDEN_ICON.IF_PREFILLED'
80-
) as string;
79+
);
8180

8281
// tooltips for hidden and disabled icons
8382
this.alwaysDisabled = this.translate.instant(
8483
'VO_DETAIL.SETTINGS.APPLICATION_FORM.DISABLED_HIDDEN_ICON.ALWAYS_DISABLED_HINT'
85-
) as string;
84+
);
8685
this.alwaysHidden = this.translate.instant(
8786
'VO_DETAIL.SETTINGS.APPLICATION_FORM.DISABLED_HIDDEN_ICON.ALWAYS_HIDDEN_HINT'
88-
) as string;
87+
);
8988
this.isDisabledIf = this.translate.instant(
9089
'VO_DETAIL.SETTINGS.APPLICATION_FORM.DISABLED_HIDDEN_ICON.DISABLED_IF_HINT'
91-
) as string;
90+
);
9291
this.isHiddenIf = this.translate.instant(
9392
'VO_DETAIL.SETTINGS.APPLICATION_FORM.DISABLED_HIDDEN_ICON.HIDDEN_IF_HINT'
94-
) as string;
93+
);
9594
this.isEmpty = this.translate.instant(
9695
'VO_DETAIL.SETTINGS.APPLICATION_FORM.DISABLED_HIDDEN_ICON.IS_EMPTY_HINT'
97-
) as string;
96+
);
9897
this.isPrefilled = this.translate.instant(
9998
'VO_DETAIL.SETTINGS.APPLICATION_FORM.DISABLED_HIDDEN_ICON.IS_PREFILLED_HINT'
100-
) as string;
99+
);
101100
}
102101

103102
ngOnChanges(): void {
@@ -188,8 +187,33 @@ export class ApplicationFormListComponent implements OnInit, OnChanges {
188187
}
189188

190189
delete(applicationFormItem: ApplicationFormItem): void {
190+
let errorMessage = '';
191+
const hiddenDependencyForItem = this.applicationFormItems.find(
192+
(item) => item.hiddenDependencyItemId === applicationFormItem.id
193+
);
194+
const disabledDependencyForItem = this.applicationFormItems.find(
195+
(item) => item.disabledDependencyItemId === applicationFormItem.id
196+
);
197+
if (hiddenDependencyForItem || disabledDependencyForItem) {
198+
errorMessage = this.translate.instant(
199+
'DIALOGS.APPLICATION_FORM_EDIT_ITEM.DEPENDENCY_ERROR_MESSAGE',
200+
hiddenDependencyForItem
201+
? {
202+
dependency: 'hidden',
203+
shortname: hiddenDependencyForItem.shortname,
204+
}
205+
: {
206+
dependency: 'disabled',
207+
shortname: disabledDependencyForItem.shortname,
208+
}
209+
);
210+
}
211+
191212
const config = getDefaultDialogConfig();
192213
config.width = '500px';
214+
config.data = {
215+
errorMessage: errorMessage,
216+
};
193217

194218
const dialog = this.dialog.open(DeleteApplicationFormItemDialogComponent, config);
195219
dialog.afterClosed().subscribe((deleteItem) => {

apps/admin-gui/src/assets/i18n/en.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1378,6 +1378,8 @@
13781378
"SOURCE_ATTRIBUTE_DESCRIPTION": "Select attribute, which will be used to pre-fill form value. You can select also organization attributes.",
13791379
"DESTINATION_ATTRIBUTE": "Destination attribute",
13801380
"DESTINATION_ATTRIBUTE_DESCRIPTION": "Select attribute, where will be submitted value stored after accepting user`s application.",
1381+
"DEPENDENCY_WARNING_MESSAGE": "Be careful when changing this attribute - this item is a {{dependency}} dependency for item {{shortname}}",
1382+
"DEPENDENCY_ERROR_MESSAGE": "You can't delete this item because it is a {{dependency}} dependency for item {{shortname}}",
13811383
"FEDERATION_ATTRIBUTE": "Federation attribute",
13821384
"FEDERATION_ATTRIBUTE_DESCRIPTION": "Select federation attribute to get pre-filed value from.",
13831385
"REQUIRED": "Required",

libs/perun/components/src/lib/entity-search-select/entity-search-select.component.css

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,8 @@
1818
.black {
1919
color: black;
2020
}
21+
22+
.warning {
23+
color: darkorange;
24+
font-weight: bold;
25+
}

libs/perun/components/src/lib/entity-search-select/entity-search-select.component.html

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<div class="d-flex flex-row align-items-center gap-4">
2-
<mat-form-field class="w-100 pb-0">
2+
<mat-form-field class="w-100 pb-0" subscriptSizing="dynamic">
33
<mat-label>{{selectPlaceholder}}</mat-label>
44
<mat-select
55
[required]="required"
@@ -50,6 +50,7 @@
5050
</mat-option>
5151
</cdk-virtual-scroll-viewport>
5252
</mat-select>
53+
<mat-hint *ngIf="warning?.length !== 0" class="warning">{{warning}}</mat-hint>
5354
</mat-form-field>
5455

5556
<perun-web-apps-deselect-button

libs/perun/components/src/lib/entity-search-select/entity-search-select.component.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ export class EntitySearchSelectComponent<T extends PerunBean>
3838
@Input() highlightOption = false;
3939
@Input() theme = '';
4040
@Input() required = false;
41+
@Input() warning: string;
4142
@Output() entitySelected = new EventEmitter<T | T[]>();
4243
@Output() selectClosed = new EventEmitter<boolean>();
4344
@ViewChild('scrollViewport', { static: false }) scrollViewport: CdkVirtualScrollViewport;

libs/perun/components/src/lib/selection-item-search-select/selection-item-search-select.component.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
[searchFunction]="searchFunction"
66
[mainTextFunction]="nameFunction"
77
[secondaryTextFunction]="shortNameFunction"
8+
[warning]="warning"
89
[selectPlaceholder]="'SHARED_LIB.PERUN.COMPONENTS.SELECTION_ITEM_SEARCH_SELECT.SELECT_ITEM' | translate"
910
[findPlaceholder]="'SHARED_LIB.PERUN.COMPONENTS.SELECTION_ITEM_SEARCH_SELECT.FIND_ITEM' | translate"
1011
[noEntriesText]="'SHARED_LIB.PERUN.COMPONENTS.SELECTION_ITEM_SEARCH_SELECT.NO_ITEM_FOUND' | translate">

0 commit comments

Comments
 (0)