From 0df65be90b11ae3b187ea0dd160e29b428591093 Mon Sep 17 00:00:00 2001 From: Alex Karpov Date: Fri, 3 Jan 2025 12:37:53 +0200 Subject: [PATCH] NAS-133358: Add more warnings about unsaved changes #2 --- .../catalog-settings/apps-settings.component.ts | 4 ++++ .../pull-image-form/pull-image-form.component.ts | 7 ++++++- .../api-key-form/api-key-form.component.ts | 5 ++++- .../widget-group-form.component.ts | 1 + ...-backup-restore-from-snapshot-form.component.ts | 4 ++++ .../replication-what-and-where.component.ts | 8 ++++++-- .../snapshot-task-form.component.ts | 3 +++ .../vmware-snapshot-form.component.ts | 3 +++ .../dataset-capacity-settings.component.ts | 4 ++++ .../dataset-form/dataset-form.component.ts | 9 +++++++++ .../dataset-quota-add-form.component.ts | 6 +++++- .../dataset-quota-edit-form.component.ts | 4 ++++ .../components/zvol-form/zvol-form.component.ts | 4 ++++ .../snapshot-add-form.component.ts | 3 +++ .../active-directory/active-directory.component.ts | 8 ++++++-- .../components/idmap-form/idmap-form.component.ts | 3 +++ .../kerberos-keytabs-form.component.ts | 5 ++++- .../kerberos-realms-form.component.ts | 5 ++++- .../kerberos-settings.component.ts | 7 ++++++- .../components/ldap/ldap.component.ts | 7 ++++++- .../configuration/configuration.component.ts | 6 +++++- .../interface-form/interface-form.component.ts | 3 +++ .../ipmi-card/ipmi-form/ipmi-form.component.ts | 3 +++ .../reporting-exporters-form.component.ts | 3 +++ .../service-ftp/service-ftp.component.ts | 6 +++++- .../service-nfs/service-nfs.component.ts | 6 +++++- .../service-smart/service-smart.component.ts | 6 +++++- .../service-smb/service-smb.component.ts | 6 +++++- .../service-snmp/service-snmp.component.ts | 6 +++++- .../service-ssh/service-ssh.component.ts | 6 +++++- .../service-ups/service-ups.component.ts | 6 +++++- .../authorized-access-form.component.ts | 3 +++ .../extent/extent-form/extent-form.component.ts | 3 +++ .../global-target-configuration.component.ts | 7 ++++++- .../iscsi/iscsi-wizard/iscsi-wizard.component.ts | 5 +++++ .../portal/portal-form/portal-form.component.ts | 5 ++++- .../target/target-form/target-form.component.ts | 4 ++++ .../sharing/nfs/nfs-form/nfs-form.component.ts | 3 +++ .../pages/sharing/smb/smb-acl/smb-acl.component.ts | 3 +++ .../sharing/smb/smb-form/smb-form.component.ts | 4 ++++ .../import-pool/import-pool.component.ts | 6 +++++- .../disk-bulk-edit/disk-bulk-edit.component.ts | 3 +++ .../components/disk-form/disk-form.component.ts | 3 +++ .../access/access-form/access-form.component.ts | 8 ++++++-- .../allowed-addresses-form.component.ts | 6 +++++- .../audit/audit-form/audit-form.component.spec.ts | 6 +++++- .../audit/audit-form/audit-form.component.ts | 7 ++++++- .../isolated-gpus-form.component.spec.ts | 2 +- .../isolated-gpus-form.component.ts | 8 ++++++-- .../kernel-form/kernel-form.component.spec.ts | 12 ++++++++++-- .../kernel/kernel-form/kernel-form.component.ts | 5 +++++ .../system-security-form.component.ts | 2 +- .../alert-service/alert-service.component.ts | 3 +++ .../bootenv/bootenv-form/bootenv-form.component.ts | 4 ++++ .../jbof-list/jbof-form/jbof-form.component.ts | 5 ++++- .../email/email-form/email-form.component.ts | 3 +++ .../gui/gui-form/gui-form.component.ts | 4 ++++ .../localization-form.component.ts | 4 ++++ .../ntp-server-form/ntp-server-form.component.ts | 5 ++++- .../support/license/license.component.ts | 7 ++++++- .../support/proactive/proactive.component.ts | 8 ++++++-- .../instance-disk-form.component.spec.ts | 2 ++ .../instance-disk-form.component.ts | 10 +++++++--- .../instance-proxy-form.component.spec.ts | 2 ++ .../instance-proxy-form.component.ts | 8 ++++++-- .../devices/device-form/device-form.component.ts | 3 +++ src/app/pages/vm/vm-wizard/vm-wizard.component.ts | 14 +++++++++++++- 67 files changed, 300 insertions(+), 44 deletions(-) diff --git a/src/app/pages/apps/components/catalog-settings/apps-settings.component.ts b/src/app/pages/apps/components/catalog-settings/apps-settings.component.ts index 9e06975a4bc..e24e0525ee9 100644 --- a/src/app/pages/apps/components/catalog-settings/apps-settings.component.ts +++ b/src/app/pages/apps/components/catalog-settings/apps-settings.component.ts @@ -13,6 +13,7 @@ import { combineLatest, filter, forkJoin, + of, take, } from 'rxjs'; import { RequiresRolesDirective } from 'app/directives/requires-roles/requires-roles.directive'; @@ -97,6 +98,9 @@ export class AppsSettingsComponent implements OnInit { private errorHandler: FormErrorHandlerService, private fb: FormBuilder, ) { + this.slideInRef.requireConfirmationWhen(() => { + return of(this.form.dirty); + }); this.dockerStore.initialize(); } diff --git a/src/app/pages/apps/components/docker-images/pull-image-form/pull-image-form.component.ts b/src/app/pages/apps/components/docker-images/pull-image-form/pull-image-form.component.ts index c26d4f341d3..cfc755fd353 100644 --- a/src/app/pages/apps/components/docker-images/pull-image-form/pull-image-form.component.ts +++ b/src/app/pages/apps/components/docker-images/pull-image-form/pull-image-form.component.ts @@ -4,6 +4,7 @@ import { MatButton } from '@angular/material/button'; import { MatCard, MatCardContent } from '@angular/material/card'; import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy'; import { TranslateModule, TranslateService } from '@ngx-translate/core'; +import { of } from 'rxjs'; import { latestVersion } from 'app/constants/catalog.constants'; import { RequiresRolesDirective } from 'app/directives/requires-roles/requires-roles.directive'; import { Role } from 'app/enums/role.enum'; @@ -67,7 +68,11 @@ export class PullImageFormComponent { private fb: FormBuilder, private translate: TranslateService, private dialogService: DialogService, - ) {} + ) { + this.slideInRef.requireConfirmationWhen(() => { + return of(this.form.dirty); + }); + } onSubmit(): void { const values = this.form.value; diff --git a/src/app/pages/credentials/users/user-api-keys/components/api-key-form/api-key-form.component.ts b/src/app/pages/credentials/users/user-api-keys/components/api-key-form/api-key-form.component.ts index 497ba13d24f..5018bc20705 100644 --- a/src/app/pages/credentials/users/user-api-keys/components/api-key-form/api-key-form.component.ts +++ b/src/app/pages/credentials/users/user-api-keys/components/api-key-form/api-key-form.component.ts @@ -9,7 +9,7 @@ import { MatCard, MatCardContent } from '@angular/material/card'; import { MatDialog } from '@angular/material/dialog'; import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy'; import { TranslateModule } from '@ngx-translate/core'; -import { map } from 'rxjs'; +import { map, of } from 'rxjs'; import { RequiresRolesDirective } from 'app/directives/requires-roles/requires-roles.directive'; import { Role } from 'app/enums/role.enum'; import { ParamsBuilder } from 'app/helpers/params-builder/params-builder.class'; @@ -113,6 +113,9 @@ export class ApiKeyFormComponent implements OnInit { private authService: AuthService, public slideInRef: SlideInRef, ) { + this.slideInRef.requireConfirmationWhen(() => { + return of(this.form.dirty); + }); this.editingRow.set(slideInRef.getData()); } diff --git a/src/app/pages/dashboard/components/widget-group-form/widget-group-form.component.ts b/src/app/pages/dashboard/components/widget-group-form/widget-group-form.component.ts index a141ccae026..d88a18dedee 100644 --- a/src/app/pages/dashboard/components/widget-group-form/widget-group-form.component.ts +++ b/src/app/pages/dashboard/components/widget-group-form/widget-group-form.component.ts @@ -85,6 +85,7 @@ export class WidgetGroupFormComponent { this.slideInRef.requireConfirmationWhen(() => { return of(this.layoutControl.dirty || this.widgetGroupSlotForm()?.form?.dirty); }); + this.setupLayoutUpdates(); this.setInitialFormValues(); } diff --git a/src/app/pages/data-protection/cloud-backup/cloud-backup-details/cloud-backup-restore-form-snapshot-form/cloud-backup-restore-from-snapshot-form.component.ts b/src/app/pages/data-protection/cloud-backup/cloud-backup-details/cloud-backup-restore-form-snapshot-form/cloud-backup-restore-from-snapshot-form.component.ts index c2ee446fdba..593c7a2fbdf 100644 --- a/src/app/pages/data-protection/cloud-backup/cloud-backup-details/cloud-backup-restore-form-snapshot-form/cloud-backup-restore-from-snapshot-form.component.ts +++ b/src/app/pages/data-protection/cloud-backup/cloud-backup-details/cloud-backup-restore-form-snapshot-form/cloud-backup-restore-from-snapshot-form.component.ts @@ -120,6 +120,10 @@ export class CloudBackupRestoreFromSnapshotFormComponent implements OnInit { public slideInRef: SlideInRef<{ backup: CloudBackup; snapshot: CloudBackupSnapshot } | undefined, boolean>, ) { + this.slideInRef.requireConfirmationWhen(() => { + return of(this.form.dirty); + }); + this.data = this.slideInRef.getData(); this.form.patchValue({ subFolder: this.data.backup.path, diff --git a/src/app/pages/data-protection/replication/replication-wizard/steps/replication-what-and-where/replication-what-and-where.component.ts b/src/app/pages/data-protection/replication/replication-wizard/steps/replication-what-and-where/replication-what-and-where.component.ts index 7d18e4db917..b0fae24dc08 100644 --- a/src/app/pages/data-protection/replication/replication-wizard/steps/replication-what-and-where/replication-what-and-where.component.ts +++ b/src/app/pages/data-protection/replication/replication-wizard/steps/replication-what-and-where/replication-what-and-where.component.ts @@ -162,7 +162,6 @@ export class ReplicationWhatAndWhereComponent implements OnInit, SummaryProvider } constructor( - public slideInRef: SlideInRef, private formBuilder: FormBuilder, private replicationService: ReplicationService, private keychainCredentials: KeychainCredentialService, @@ -174,7 +173,12 @@ export class ReplicationWhatAndWhereComponent implements OnInit, SummaryProvider private api: ApiService, private cdr: ChangeDetectorRef, private errorHandler: ErrorHandlerService, - ) {} + public slideInRef: SlideInRef, + ) { + this.slideInRef.requireConfirmationWhen(() => { + return of(this.form.dirty); + }); + } ngOnInit(): void { this.disableSource(); diff --git a/src/app/pages/data-protection/snapshot-task/snapshot-task-form/snapshot-task-form.component.ts b/src/app/pages/data-protection/snapshot-task/snapshot-task-form/snapshot-task-form.component.ts index c279ab5817e..02b2798381c 100644 --- a/src/app/pages/data-protection/snapshot-task/snapshot-task-form/snapshot-task-form.component.ts +++ b/src/app/pages/data-protection/snapshot-task/snapshot-task-form/snapshot-task-form.component.ts @@ -131,6 +131,9 @@ export class SnapshotTaskFormComponent implements OnInit { protected storageService: StorageService, public slideInRef: SlideInRef, ) { + this.slideInRef.requireConfirmationWhen(() => { + return of(this.form.dirty); + }); this.editingTask = slideInRef.getData(); } diff --git a/src/app/pages/data-protection/vmware-snapshot/vmware-snapshot-form/vmware-snapshot-form.component.ts b/src/app/pages/data-protection/vmware-snapshot/vmware-snapshot-form/vmware-snapshot-form.component.ts index b33382356e8..fc293812105 100644 --- a/src/app/pages/data-protection/vmware-snapshot/vmware-snapshot-form/vmware-snapshot-form.component.ts +++ b/src/app/pages/data-protection/vmware-snapshot/vmware-snapshot-form/vmware-snapshot-form.component.ts @@ -103,6 +103,9 @@ export class VmwareSnapshotFormComponent implements OnInit { protected dialogService: DialogService, public slideInRef: SlideInRef, ) { + this.slideInRef.requireConfirmationWhen(() => { + return of(this.form.dirty); + }); this.editingSnapshot = slideInRef.getData(); } diff --git a/src/app/pages/datasets/components/dataset-capacity-management-card/dataset-capacity-settings/dataset-capacity-settings.component.ts b/src/app/pages/datasets/components/dataset-capacity-management-card/dataset-capacity-settings/dataset-capacity-settings.component.ts index e3f6dae0664..9a4d2d27d4d 100644 --- a/src/app/pages/datasets/components/dataset-capacity-management-card/dataset-capacity-settings/dataset-capacity-settings.component.ts +++ b/src/app/pages/datasets/components/dataset-capacity-management-card/dataset-capacity-settings/dataset-capacity-settings.component.ts @@ -6,6 +6,7 @@ import { MatButton } from '@angular/material/button'; import { MatCard, MatCardContent } from '@angular/material/card'; import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy'; import { TranslateModule, TranslateService } from '@ngx-translate/core'; +import { of } from 'rxjs'; import { GiB } from 'app/constants/bytes.constant'; import { RequiresRolesDirective } from 'app/directives/requires-roles/requires-roles.directive'; import { Role } from 'app/enums/role.enum'; @@ -113,6 +114,9 @@ export class DatasetCapacitySettingsComponent implements OnInit { private validators: IxValidatorsService, public slideInRef: SlideInRef, ) { + this.slideInRef.requireConfirmationWhen(() => { + return of(this.form.dirty); + }); this.dataset = slideInRef.getData(); this.setFormRelations(); } diff --git a/src/app/pages/datasets/components/dataset-form/dataset-form.component.ts b/src/app/pages/datasets/components/dataset-form/dataset-form.component.ts index 2d0267621db..53e358c184d 100644 --- a/src/app/pages/datasets/components/dataset-form/dataset-form.component.ts +++ b/src/app/pages/datasets/components/dataset-form/dataset-form.component.ts @@ -140,6 +140,15 @@ export class DatasetFormComponent implements OnInit, AfterViewInit { private store$: Store, public slideInRef: SlideInRef<{ datasetId: string; isNew?: boolean } | undefined, Dataset>, ) { + this.slideInRef.requireConfirmationWhen(() => { + return of( + this.form.dirty + || this.nameAndOptionsSection().form.dirty + || this.encryptionSection().form.dirty + || this.otherOptionsSection().form.dirty + || this.quotasSection()?.form.dirty, + ); + }); this.slideInData = slideInRef.getData(); } diff --git a/src/app/pages/datasets/components/dataset-quotas/dataset-quota-add-form/dataset-quota-add-form.component.ts b/src/app/pages/datasets/components/dataset-quotas/dataset-quota-add-form/dataset-quota-add-form.component.ts index eddc8851e74..e69d99c9236 100644 --- a/src/app/pages/datasets/components/dataset-quotas/dataset-quota-add-form/dataset-quota-add-form.component.ts +++ b/src/app/pages/datasets/components/dataset-quotas/dataset-quota-add-form/dataset-quota-add-form.component.ts @@ -7,7 +7,7 @@ import { MatCard, MatCardContent } from '@angular/material/card'; import { FormBuilder } from '@ngneat/reactive-forms'; import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy'; import { TranslateModule, TranslateService } from '@ngx-translate/core'; -import { combineLatest, map } from 'rxjs'; +import { combineLatest, map, of } from 'rxjs'; import { RequiresRolesDirective } from 'app/directives/requires-roles/requires-roles.directive'; import { DatasetQuotaType } from 'app/enums/dataset.enum'; import { Role } from 'app/enums/role.enum'; @@ -138,6 +138,10 @@ export class DatasetQuotaAddFormComponent implements OnInit { private userService: UserService, public slideInRef: SlideInRef<{ quotaType: DatasetQuotaType; datasetId: string } | undefined, boolean>, ) { + this.slideInRef.requireConfirmationWhen(() => { + return of(this.form.dirty); + }); + this.quotaType = slideInRef.getData().quotaType; this.datasetId = slideInRef.getData().datasetId; } diff --git a/src/app/pages/datasets/components/dataset-quotas/dataset-quota-edit-form/dataset-quota-edit-form.component.ts b/src/app/pages/datasets/components/dataset-quotas/dataset-quota-edit-form/dataset-quota-edit-form.component.ts index 190def5c9f3..7219459c4af 100644 --- a/src/app/pages/datasets/components/dataset-quotas/dataset-quota-edit-form/dataset-quota-edit-form.component.ts +++ b/src/app/pages/datasets/components/dataset-quotas/dataset-quota-edit-form/dataset-quota-edit-form.component.ts @@ -134,6 +134,10 @@ export class DatasetQuotaEditFormComponent implements OnInit { protected dialogService: DialogService, public slideInRef: SlideInRef<{ quotaType: DatasetQuotaType; datasetId: string; id: number } | undefined, boolean>, ) { + this.slideInRef.requireConfirmationWhen(() => { + return of(this.form.dirty); + }); + this.datasetId = slideInRef.getData().datasetId; this.quotaType = slideInRef.getData().quotaType; this.id = slideInRef.getData().id; diff --git a/src/app/pages/datasets/components/zvol-form/zvol-form.component.ts b/src/app/pages/datasets/components/zvol-form/zvol-form.component.ts index 3cefc1a876e..11bedf42282 100644 --- a/src/app/pages/datasets/components/zvol-form/zvol-form.component.ts +++ b/src/app/pages/datasets/components/zvol-form/zvol-form.component.ts @@ -230,6 +230,10 @@ export class ZvolFormComponent implements OnInit { protected snackbar: SnackbarService, public slideInRef: SlideInRef<{ isNew: boolean; parentId: string } | undefined, Dataset>, ) { + this.slideInRef.requireConfirmationWhen(() => { + return of(this.form.dirty); + }); + this.slideInData = slideInRef.getData(); this.form.controls.key.disable(); this.form.controls.passphrase.disable(); diff --git a/src/app/pages/datasets/modules/snapshots/snapshot-add-form/snapshot-add-form.component.ts b/src/app/pages/datasets/modules/snapshots/snapshot-add-form/snapshot-add-form.component.ts index eec261395d7..cb0a8ffdc5b 100644 --- a/src/app/pages/datasets/modules/snapshots/snapshot-add-form/snapshot-add-form.component.ts +++ b/src/app/pages/datasets/modules/snapshots/snapshot-add-form/snapshot-add-form.component.ts @@ -104,6 +104,9 @@ export class SnapshotAddFormComponent implements OnInit { private datasetStore: DatasetTreeStore, public slideInRef: SlideInRef, ) { + this.slideInRef.requireConfirmationWhen(() => { + return of(this.form.dirty); + }); this.datasetId = slideInRef.getData(); } diff --git a/src/app/pages/directory-service/components/active-directory/active-directory.component.ts b/src/app/pages/directory-service/components/active-directory/active-directory.component.ts index 863e4ecb7b6..6f91e5ae472 100644 --- a/src/app/pages/directory-service/components/active-directory/active-directory.component.ts +++ b/src/app/pages/directory-service/components/active-directory/active-directory.component.ts @@ -9,7 +9,7 @@ import { MatDialog } from '@angular/material/dialog'; import { FormBuilder } from '@ngneat/reactive-forms'; import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy'; import { TranslateService, TranslateModule } from '@ngx-translate/core'; -import { forkJoin, Observable } from 'rxjs'; +import { forkJoin, Observable, of } from 'rxjs'; import { map } from 'rxjs/operators'; import { RequiresRolesDirective } from 'app/directives/requires-roles/requires-roles.directive'; import { DirectoryServiceState } from 'app/enums/directory-service-state.enum'; @@ -115,7 +115,11 @@ export class ActiveDirectoryComponent implements OnInit { private translate: TranslateService, private snackbarService: SnackbarService, public slideInRef: SlideInRef, - ) {} + ) { + this.slideInRef.requireConfirmationWhen(() => { + return of(this.form.dirty); + }); + } ngOnInit(): void { this.loadFormValues(); diff --git a/src/app/pages/directory-service/components/idmap-form/idmap-form.component.ts b/src/app/pages/directory-service/components/idmap-form/idmap-form.component.ts index 4cbbcffba12..363c7407c7f 100644 --- a/src/app/pages/directory-service/components/idmap-form/idmap-form.component.ts +++ b/src/app/pages/directory-service/components/idmap-form/idmap-form.component.ts @@ -197,6 +197,9 @@ export class IdmapFormComponent implements OnInit { private snackbar: SnackbarService, public slideInRef: SlideInRef, ) { + this.slideInRef.requireConfirmationWhen(() => { + return of(this.form.dirty); + }); this.existingIdmap = slideInRef.getData(); } diff --git a/src/app/pages/directory-service/components/kerberos-keytabs/kerberos-keytabs-form/kerberos-keytabs-form.component.ts b/src/app/pages/directory-service/components/kerberos-keytabs/kerberos-keytabs-form/kerberos-keytabs-form.component.ts index fda3d21726d..e6c339771ac 100644 --- a/src/app/pages/directory-service/components/kerberos-keytabs/kerberos-keytabs-form/kerberos-keytabs-form.component.ts +++ b/src/app/pages/directory-service/components/kerberos-keytabs/kerberos-keytabs-form/kerberos-keytabs-form.component.ts @@ -6,7 +6,7 @@ import { MatButton } from '@angular/material/button'; import { MatCard, MatCardContent } from '@angular/material/card'; import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy'; import { TranslateService, TranslateModule } from '@ngx-translate/core'; -import { Observable } from 'rxjs'; +import { Observable, of } from 'rxjs'; import { RequiresRolesDirective } from 'app/directives/requires-roles/requires-roles.directive'; import { Role } from 'app/enums/role.enum'; import { helptextKerberosKeytabs } from 'app/helptext/directory-service/kerberos-keytabs-form-list'; @@ -73,6 +73,9 @@ export class KerberosKeytabsFormComponent implements OnInit { private api: ApiService, public slideInRef: SlideInRef, ) { + this.slideInRef.requireConfirmationWhen(() => { + return of(this.form.dirty); + }); this.editingKerberosKeytab = slideInRef.getData(); } diff --git a/src/app/pages/directory-service/components/kerberos-realms-form/kerberos-realms-form.component.ts b/src/app/pages/directory-service/components/kerberos-realms-form/kerberos-realms-form.component.ts index 64cc63130e6..369330cf077 100644 --- a/src/app/pages/directory-service/components/kerberos-realms-form/kerberos-realms-form.component.ts +++ b/src/app/pages/directory-service/components/kerberos-realms-form/kerberos-realms-form.component.ts @@ -6,7 +6,7 @@ import { MatButton } from '@angular/material/button'; import { MatCard, MatCardContent } from '@angular/material/card'; import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy'; import { TranslateService, TranslateModule } from '@ngx-translate/core'; -import { Observable } from 'rxjs'; +import { Observable, of } from 'rxjs'; import { RequiresRolesDirective } from 'app/directives/requires-roles/requires-roles.directive'; import { Role } from 'app/enums/role.enum'; import { helptextKerberosRealms } from 'app/helptext/directory-service/kerberos-realms-form-list'; @@ -80,6 +80,9 @@ export class KerberosRealmsFormComponent implements OnInit { private translate: TranslateService, public slideInRef: SlideInRef, ) { + this.slideInRef.requireConfirmationWhen(() => { + return of(this.form.dirty); + }); this.editingRealm = slideInRef.getData(); } diff --git a/src/app/pages/directory-service/components/kerberos-settings/kerberos-settings.component.ts b/src/app/pages/directory-service/components/kerberos-settings/kerberos-settings.component.ts index 386ee07729d..8745c5fedae 100644 --- a/src/app/pages/directory-service/components/kerberos-settings/kerberos-settings.component.ts +++ b/src/app/pages/directory-service/components/kerberos-settings/kerberos-settings.component.ts @@ -6,6 +6,7 @@ import { MatButton } from '@angular/material/button'; import { MatCard, MatCardContent } from '@angular/material/card'; import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy'; import { TranslateModule } from '@ngx-translate/core'; +import { of } from 'rxjs'; import { RequiresRolesDirective } from 'app/directives/requires-roles/requires-roles.directive'; import { Role } from 'app/enums/role.enum'; import { helptextKerberosSettings } from 'app/helptext/directory-service/kerberos-settings'; @@ -64,7 +65,11 @@ export class KerberosSettingsComponent implements OnInit { private fb: FormBuilder, private dialogService: DialogService, public slideInRef: SlideInRef, - ) {} + ) { + this.slideInRef.requireConfirmationWhen(() => { + return of(this.form.dirty); + }); + } ngOnInit(): void { this.isFormLoading = true; diff --git a/src/app/pages/directory-service/components/ldap/ldap.component.ts b/src/app/pages/directory-service/components/ldap/ldap.component.ts index 769201e66d2..06c807dca49 100644 --- a/src/app/pages/directory-service/components/ldap/ldap.component.ts +++ b/src/app/pages/directory-service/components/ldap/ldap.component.ts @@ -8,6 +8,7 @@ import { MatCard, MatCardContent } from '@angular/material/card'; import { FormBuilder } from '@ngneat/reactive-forms'; import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy'; import { TranslateService, TranslateModule } from '@ngx-translate/core'; +import { of } from 'rxjs'; import { map } from 'rxjs/operators'; import { RequiresRolesDirective } from 'app/directives/requires-roles/requires-roles.directive'; import { Role } from 'app/enums/role.enum'; @@ -113,7 +114,11 @@ export class LdapComponent implements OnInit { private translate: TranslateService, private snackbar: SnackbarService, public slideInRef: SlideInRef, - ) {} + ) { + this.slideInRef.requireConfirmationWhen(() => { + return of(this.form.dirty); + }); + } ngOnInit(): void { this.loadFormValues(); diff --git a/src/app/pages/network/components/configuration/configuration.component.ts b/src/app/pages/network/components/configuration/configuration.component.ts index 7eb4c7db58c..161423c8b1f 100644 --- a/src/app/pages/network/components/configuration/configuration.component.ts +++ b/src/app/pages/network/components/configuration/configuration.component.ts @@ -229,7 +229,11 @@ export class NetworkConfigurationComponent implements OnInit { private systemGeneralService: SystemGeneralService, private store$: Store, public slideInRef: SlideInRef, - ) {} + ) { + this.slideInRef.requireConfirmationWhen(() => { + return of(this.form.dirty); + }); + } ngOnInit(): void { this.isFormLoading = true; diff --git a/src/app/pages/network/components/interface-form/interface-form.component.ts b/src/app/pages/network/components/interface-form/interface-form.component.ts index 70fc3f2cfdc..ad6e9ed017f 100644 --- a/src/app/pages/network/components/interface-form/interface-form.component.ts +++ b/src/app/pages/network/components/interface-form/interface-form.component.ts @@ -186,6 +186,9 @@ export class InterfaceFormComponent implements OnInit { private store$: Store, public slideInRef: SlideInRef, ) { + this.slideInRef.requireConfirmationWhen(() => { + return of(this.form.dirty); + }); this.existingInterface = slideInRef.getData(); } diff --git a/src/app/pages/network/components/ipmi-card/ipmi-form/ipmi-form.component.ts b/src/app/pages/network/components/ipmi-card/ipmi-form/ipmi-form.component.ts index 2d4669acfac..acf63044d86 100644 --- a/src/app/pages/network/components/ipmi-card/ipmi-form/ipmi-form.component.ts +++ b/src/app/pages/network/components/ipmi-card/ipmi-form/ipmi-form.component.ts @@ -124,6 +124,9 @@ export class IpmiFormComponent implements OnInit { private dialogService: DialogService, public slideInRef: SlideInRef, ) { + this.slideInRef.requireConfirmationWhen(() => { + return of(this.form.dirty); + }); this.ipmiId = this.slideInRef.getData(); } diff --git a/src/app/pages/reports-dashboard/components/exporters/reporting-exporters-form/reporting-exporters-form.component.ts b/src/app/pages/reports-dashboard/components/exporters/reporting-exporters-form/reporting-exporters-form.component.ts index 820093820a7..230ca7a5ae5 100644 --- a/src/app/pages/reports-dashboard/components/exporters/reporting-exporters-form/reporting-exporters-form.component.ts +++ b/src/app/pages/reports-dashboard/components/exporters/reporting-exporters-form/reporting-exporters-form.component.ts @@ -105,6 +105,9 @@ export class ReportingExportersFormComponent implements OnInit { private dialogService: DialogService, public slideInRef: SlideInRef, ) { + this.slideInRef.requireConfirmationWhen(() => { + return of(this.form.dirty); + }); this.editingExporter = this.slideInRef.getData(); } diff --git a/src/app/pages/services/components/service-ftp/service-ftp.component.ts b/src/app/pages/services/components/service-ftp/service-ftp.component.ts index b2a2e1b63a2..ca06b5ba386 100644 --- a/src/app/pages/services/components/service-ftp/service-ftp.component.ts +++ b/src/app/pages/services/components/service-ftp/service-ftp.component.ts @@ -136,7 +136,11 @@ export class ServiceFtpComponent implements OnInit { private snackbar: SnackbarService, public iecFormatter: IxFormatterService, public slideInRef: SlideInRef, - ) {} + ) { + this.slideInRef.requireConfirmationWhen(() => { + return of(this.form.dirty); + }); + } ngOnInit(): void { this.loadConfig(); diff --git a/src/app/pages/services/components/service-nfs/service-nfs.component.ts b/src/app/pages/services/components/service-nfs/service-nfs.component.ts index d1846c9c019..1868fe54421 100644 --- a/src/app/pages/services/components/service-nfs/service-nfs.component.ts +++ b/src/app/pages/services/components/service-nfs/service-nfs.component.ts @@ -137,7 +137,11 @@ export class ServiceNfsComponent implements OnInit { private matDialog: MatDialog, private validatorsService: IxValidatorsService, public slideInRef: SlideInRef, - ) {} + ) { + this.slideInRef.requireConfirmationWhen(() => { + return of(this.form.dirty); + }); + } ngOnInit(): void { this.isFormLoading.set(true); diff --git a/src/app/pages/services/components/service-smart/service-smart.component.ts b/src/app/pages/services/components/service-smart/service-smart.component.ts index 5743cee43f6..75a2c847326 100644 --- a/src/app/pages/services/components/service-smart/service-smart.component.ts +++ b/src/app/pages/services/components/service-smart/service-smart.component.ts @@ -85,7 +85,11 @@ export class ServiceSmartComponent implements OnInit { private dialogService: DialogService, private snackbar: SnackbarService, public slideInRef: SlideInRef, - ) {} + ) { + this.slideInRef.requireConfirmationWhen(() => { + return of(this.form.dirty); + }); + } ngOnInit(): void { this.isFormLoading = true; diff --git a/src/app/pages/services/components/service-smb/service-smb.component.ts b/src/app/pages/services/components/service-smb/service-smb.component.ts index 6ecd5ad4b5c..e90875616de 100644 --- a/src/app/pages/services/components/service-smb/service-smb.component.ts +++ b/src/app/pages/services/components/service-smb/service-smb.component.ts @@ -159,7 +159,11 @@ export class ServiceSmbComponent implements OnInit { private validatorsService: IxValidatorsService, private snackbar: SnackbarService, public slideInRef: SlideInRef, - ) {} + ) { + this.slideInRef.requireConfirmationWhen(() => { + return of(this.form.dirty); + }); + } ngOnInit(): void { this.isFormLoading = true; diff --git a/src/app/pages/services/components/service-snmp/service-snmp.component.ts b/src/app/pages/services/components/service-snmp/service-snmp.component.ts index 935a5e24487..4b70a28c286 100644 --- a/src/app/pages/services/components/service-snmp/service-snmp.component.ts +++ b/src/app/pages/services/components/service-snmp/service-snmp.component.ts @@ -113,7 +113,11 @@ export class ServiceSnmpComponent implements OnInit { private snackbar: SnackbarService, private translate: TranslateService, public slideInRef: SlideInRef, - ) {} + ) { + this.slideInRef.requireConfirmationWhen(() => { + return of(this.form.dirty); + }); + } ngOnInit(): void { this.loadCurrentSettings(); diff --git a/src/app/pages/services/components/service-ssh/service-ssh.component.ts b/src/app/pages/services/components/service-ssh/service-ssh.component.ts index 56d9ff21211..c73fd3b9cce 100644 --- a/src/app/pages/services/components/service-ssh/service-ssh.component.ts +++ b/src/app/pages/services/components/service-ssh/service-ssh.component.ts @@ -112,7 +112,11 @@ export class ServiceSshComponent implements OnInit { private translate: TranslateService, private snackbar: SnackbarService, public slideInRef: SlideInRef, - ) {} + ) { + this.slideInRef.requireConfirmationWhen(() => { + return of(this.form.dirty); + }); + } ngOnInit(): void { this.isFormLoading = true; diff --git a/src/app/pages/services/components/service-ups/service-ups.component.ts b/src/app/pages/services/components/service-ups/service-ups.component.ts index c0f664028e8..114ade1b8d8 100644 --- a/src/app/pages/services/components/service-ups/service-ups.component.ts +++ b/src/app/pages/services/components/service-ups/service-ups.component.ts @@ -155,7 +155,11 @@ export class ServiceUpsComponent implements OnInit { private translate: TranslateService, private snackbar: SnackbarService, public slideInRef: SlideInRef, - ) {} + ) { + this.slideInRef.requireConfirmationWhen(() => { + return of(this.form.dirty); + }); + } ngOnInit(): void { this.isFormLoading = true; diff --git a/src/app/pages/sharing/iscsi/authorized-access/authorized-access-form/authorized-access-form.component.ts b/src/app/pages/sharing/iscsi/authorized-access/authorized-access-form/authorized-access-form.component.ts index d1160d4953f..3136eeebd3a 100644 --- a/src/app/pages/sharing/iscsi/authorized-access/authorized-access-form/authorized-access-form.component.ts +++ b/src/app/pages/sharing/iscsi/authorized-access/authorized-access-form/authorized-access-form.component.ts @@ -141,6 +141,9 @@ export class AuthorizedAccessFormComponent implements OnInit { private validatorService: IxValidatorsService, public slideInRef: SlideInRef, ) { + this.slideInRef.requireConfirmationWhen(() => { + return of(this.form.dirty); + }); this.editingAccess = this.slideInRef.getData(); } diff --git a/src/app/pages/sharing/iscsi/extent/extent-form/extent-form.component.ts b/src/app/pages/sharing/iscsi/extent/extent-form/extent-form.component.ts index cebe94acbe0..53adf7cdb6a 100644 --- a/src/app/pages/sharing/iscsi/extent/extent-form/extent-form.component.ts +++ b/src/app/pages/sharing/iscsi/extent/extent-form/extent-form.component.ts @@ -139,6 +139,9 @@ export class ExtentFormComponent implements OnInit { private filesystemService: FilesystemService, public slideInRef: SlideInRef, ) { + this.slideInRef.requireConfirmationWhen(() => { + return of(this.form.dirty); + }); this.editingExtent = this.slideInRef.getData(); } diff --git a/src/app/pages/sharing/iscsi/global-target-configuration/global-target-configuration.component.ts b/src/app/pages/sharing/iscsi/global-target-configuration/global-target-configuration.component.ts index fdbd9bfb17e..d2f8886e875 100644 --- a/src/app/pages/sharing/iscsi/global-target-configuration/global-target-configuration.component.ts +++ b/src/app/pages/sharing/iscsi/global-target-configuration/global-target-configuration.component.ts @@ -9,6 +9,7 @@ import { MatCard, MatCardContent } from '@angular/material/card'; import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy'; import { Store } from '@ngrx/store'; import { TranslateModule, TranslateService } from '@ngx-translate/core'; +import { of } from 'rxjs'; import { RequiresRolesDirective } from 'app/directives/requires-roles/requires-roles.directive'; import { Role } from 'app/enums/role.enum'; import { ServiceName } from 'app/enums/service-name.enum'; @@ -86,7 +87,11 @@ export class GlobalTargetConfigurationComponent implements OnInit { private snackbar: SnackbarService, private translate: TranslateService, public slideInRef: SlideInRef, - ) {} + ) { + this.slideInRef.requireConfirmationWhen(() => { + return of(this.form.dirty); + }); + } ngOnInit(): void { this.loadFormValues(); diff --git a/src/app/pages/sharing/iscsi/iscsi-wizard/iscsi-wizard.component.ts b/src/app/pages/sharing/iscsi/iscsi-wizard/iscsi-wizard.component.ts index c331b7b442e..f5229db5ae0 100644 --- a/src/app/pages/sharing/iscsi/iscsi-wizard/iscsi-wizard.component.ts +++ b/src/app/pages/sharing/iscsi/iscsi-wizard/iscsi-wizard.component.ts @@ -13,6 +13,7 @@ import { Store } from '@ngrx/store'; import { TranslateService, TranslateModule } from '@ngx-translate/core'; import { lastValueFrom, forkJoin, + of, } from 'rxjs'; import { patterns } from 'app/constants/name-patterns.constant'; import { RequiresRolesDirective } from 'app/directives/requires-roles/requires-roles.directive'; @@ -258,6 +259,10 @@ export class IscsiWizardComponent implements OnInit { private store$: Store, public slideInRef: SlideInRef, ) { + this.slideInRef.requireConfirmationWhen(() => { + return of(this.form.dirty); + }); + this.iscsiService.getExtents().pipe(untilDestroyed(this)).subscribe((extents) => { this.namesInUse.push(...extents.map((extent) => extent.name)); }); diff --git a/src/app/pages/sharing/iscsi/portal/portal-form/portal-form.component.ts b/src/app/pages/sharing/iscsi/portal/portal-form/portal-form.component.ts index de89f421469..ee741cd80ce 100644 --- a/src/app/pages/sharing/iscsi/portal/portal-form/portal-form.component.ts +++ b/src/app/pages/sharing/iscsi/portal/portal-form/portal-form.component.ts @@ -8,7 +8,7 @@ import { MatCard, MatCardContent } from '@angular/material/card'; import { FormBuilder } from '@ngneat/reactive-forms'; import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy'; import { TranslateService, TranslateModule } from '@ngx-translate/core'; -import { Observable } from 'rxjs'; +import { Observable, of } from 'rxjs'; import { RequiresRolesDirective } from 'app/directives/requires-roles/requires-roles.directive'; import { Role } from 'app/enums/role.enum'; import { choicesToOptions } from 'app/helpers/operators/options.operators'; @@ -102,6 +102,9 @@ export class PortalFormComponent implements OnInit { protected iscsiService: IscsiService, public slideInRef: SlideInRef, ) { + this.slideInRef.requireConfirmationWhen(() => { + return of(this.form.dirty); + }); this.editingIscsiPortal = this.slideInRef.getData(); } diff --git a/src/app/pages/sharing/iscsi/target/target-form/target-form.component.ts b/src/app/pages/sharing/iscsi/target/target-form/target-form.component.ts index 7ceb2a313a9..af1ad64159b 100644 --- a/src/app/pages/sharing/iscsi/target/target-form/target-form.component.ts +++ b/src/app/pages/sharing/iscsi/target/target-form/target-form.component.ts @@ -160,6 +160,10 @@ export class TargetFormComponent implements OnInit { private targetNameValidationService: TargetNameValidationService, public slideInRef: SlideInRef, ) { + this.slideInRef.requireConfirmationWhen(() => { + return of(this.form.dirty); + }); + this.editingTarget = slideInRef.getData(); this.form.controls.name.setAsyncValidators( diff --git a/src/app/pages/sharing/nfs/nfs-form/nfs-form.component.ts b/src/app/pages/sharing/nfs/nfs-form/nfs-form.component.ts index 6c8b5da81ec..18aa92043e8 100644 --- a/src/app/pages/sharing/nfs/nfs-form/nfs-form.component.ts +++ b/src/app/pages/sharing/nfs/nfs-form/nfs-form.component.ts @@ -146,6 +146,9 @@ export class NfsFormComponent implements OnInit { private store$: Store, public slideInRef: SlideInRef<{ existingNfsShare?: NfsShare; defaultNfsShare?: NfsShare } | undefined, boolean>, ) { + this.slideInRef.requireConfirmationWhen(() => { + return of(this.form.dirty); + }); this.existingNfsShare = this.slideInRef.getData()?.existingNfsShare; this.defaultNfsShare = this.slideInRef.getData()?.defaultNfsShare; } diff --git a/src/app/pages/sharing/smb/smb-acl/smb-acl.component.ts b/src/app/pages/sharing/smb/smb-acl/smb-acl.component.ts index e042bccc2d4..3b9a6c5fcd7 100644 --- a/src/app/pages/sharing/smb/smb-acl/smb-acl.component.ts +++ b/src/app/pages/sharing/smb/smb-acl/smb-acl.component.ts @@ -129,6 +129,9 @@ export class SmbAclComponent implements OnInit { private userService: UserService, public slideInRef: SlideInRef, ) { + this.slideInRef.requireConfirmationWhen(() => { + return of(this.form.dirty); + }); this.shareName = slideInRef.getData(); } diff --git a/src/app/pages/sharing/smb/smb-form/smb-form.component.ts b/src/app/pages/sharing/smb/smb-form/smb-form.component.ts index 68826fb5517..30398d7b8db 100644 --- a/src/app/pages/sharing/smb/smb-form/smb-form.component.ts +++ b/src/app/pages/sharing/smb/smb-form/smb-form.component.ts @@ -241,6 +241,10 @@ export class SmbFormComponent implements OnInit, AfterViewInit { private smbValidationService: SmbValidationService, public slideInRef: SlideInRef<{ existingSmbShare?: SmbShare; defaultSmbShare?: SmbShare } | undefined, boolean>, ) { + this.slideInRef.requireConfirmationWhen(() => { + return of(this.form.dirty); + }); + this.existingSmbShare = this.slideInRef.getData()?.existingSmbShare; this.defaultSmbShare = this.slideInRef.getData()?.defaultSmbShare; } diff --git a/src/app/pages/storage/components/import-pool/import-pool.component.ts b/src/app/pages/storage/components/import-pool/import-pool.component.ts index 114fd0b773f..8fefb905da6 100644 --- a/src/app/pages/storage/components/import-pool/import-pool.component.ts +++ b/src/app/pages/storage/components/import-pool/import-pool.component.ts @@ -83,7 +83,11 @@ export class ImportPoolComponent implements OnInit { private snackbar: SnackbarService, private loader: AppLoaderService, public slideInRef: SlideInRef, - ) { } + ) { + this.slideInRef.requireConfirmationWhen(() => { + return of(this.formGroup.dirty); + }); + } ngOnInit(): void { this.isLoading = true; diff --git a/src/app/pages/storage/modules/disks/components/disk-bulk-edit/disk-bulk-edit.component.ts b/src/app/pages/storage/modules/disks/components/disk-bulk-edit/disk-bulk-edit.component.ts index a467181451c..9bce762e12c 100644 --- a/src/app/pages/storage/modules/disks/components/disk-bulk-edit/disk-bulk-edit.component.ts +++ b/src/app/pages/storage/modules/disks/components/disk-bulk-edit/disk-bulk-edit.component.ts @@ -77,6 +77,9 @@ export class DiskBulkEditComponent { private errorHandler: FormErrorHandlerService, public slideInRef: SlideInRef, ) { + this.slideInRef.requireConfirmationWhen(() => { + return of(this.form.dirty); + }); this.setFormDiskBulk(this.slideInRef.getData()); } diff --git a/src/app/pages/storage/modules/disks/components/disk-form/disk-form.component.ts b/src/app/pages/storage/modules/disks/components/disk-form/disk-form.component.ts index 6025061f08b..614986e686b 100644 --- a/src/app/pages/storage/modules/disks/components/disk-form/disk-form.component.ts +++ b/src/app/pages/storage/modules/disks/components/disk-form/disk-form.component.ts @@ -87,6 +87,9 @@ export class DiskFormComponent implements OnInit { private snackbarService: SnackbarService, public slideInRef: SlideInRef, ) { + this.slideInRef.requireConfirmationWhen(() => { + return of(this.form.dirty); + }); this.setFormDisk(this.slideInRef.getData()); } diff --git a/src/app/pages/system/advanced/access/access-form/access-form.component.ts b/src/app/pages/system/advanced/access/access-form/access-form.component.ts index 9e600ad5fd0..4d297ad124a 100644 --- a/src/app/pages/system/advanced/access/access-form/access-form.component.ts +++ b/src/app/pages/system/advanced/access/access-form/access-form.component.ts @@ -8,7 +8,7 @@ import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy'; import { Store } from '@ngrx/store'; import { TranslateService, TranslateModule } from '@ngx-translate/core'; import { - filter, finalize, forkJoin, Observable, take, + filter, finalize, forkJoin, Observable, of, take, } from 'rxjs'; import { RequiresRolesDirective } from 'app/directives/requires-roles/requires-roles.directive'; import { Role } from 'app/enums/role.enum'; @@ -88,7 +88,11 @@ export class AccessFormComponent implements OnInit { private systemGeneralService: SystemGeneralService, private authService: AuthService, public slideInRef: SlideInRef, - ) {} + ) { + this.slideInRef.requireConfirmationWhen(() => { + return of(this.form.dirty); + }); + } ngOnInit(): void { this.store$.pipe(waitForPreferences, untilDestroyed(this)).subscribe((preferences) => { diff --git a/src/app/pages/system/advanced/allowed-addresses/allowed-addresses-form/allowed-addresses-form.component.ts b/src/app/pages/system/advanced/allowed-addresses/allowed-addresses-form/allowed-addresses-form.component.ts index 69a983d7b48..9fe6df2f565 100644 --- a/src/app/pages/system/advanced/allowed-addresses/allowed-addresses-form/allowed-addresses-form.component.ts +++ b/src/app/pages/system/advanced/allowed-addresses/allowed-addresses-form/allowed-addresses-form.component.ts @@ -71,7 +71,11 @@ export class AllowedAddressesFormComponent implements OnInit { private snackbar: SnackbarService, private translate: TranslateService, public slideInRef: SlideInRef, - ) {} + ) { + this.slideInRef.requireConfirmationWhen(() => { + return of(this.form.dirty); + }); + } ngOnInit(): void { this.api.call('system.general.config').pipe(untilDestroyed(this)).subscribe({ diff --git a/src/app/pages/system/advanced/audit/audit-form/audit-form.component.spec.ts b/src/app/pages/system/advanced/audit/audit-form/audit-form.component.spec.ts index 8df9686a307..fdad8321e9a 100644 --- a/src/app/pages/system/advanced/audit/audit-form/audit-form.component.spec.ts +++ b/src/app/pages/system/advanced/audit/audit-form/audit-form.component.spec.ts @@ -41,7 +41,11 @@ describe('AuditFormComponent', () => { }), mockProvider(DialogService), provideMockStore(), - mockProvider(SlideInRef, { close: jest.fn(), getData: jest.fn() }), + mockProvider(SlideInRef, { + close: jest.fn(), + getData: jest.fn(), + requireConfirmationWhen: jest.fn(), + }), mockAuth(), ], }); diff --git a/src/app/pages/system/advanced/audit/audit-form/audit-form.component.ts b/src/app/pages/system/advanced/audit/audit-form/audit-form.component.ts index 41ed5e4526d..9932b056c12 100644 --- a/src/app/pages/system/advanced/audit/audit-form/audit-form.component.ts +++ b/src/app/pages/system/advanced/audit/audit-form/audit-form.component.ts @@ -10,6 +10,7 @@ import { Store } from '@ngrx/store'; import { TranslateService, TranslateModule } from '@ngx-translate/core'; import { EMPTY, + of, } from 'rxjs'; import { catchError, tap, @@ -84,7 +85,11 @@ export class AuditFormComponent implements OnInit { private translate: TranslateService, private formErrorHandler: FormErrorHandlerService, public slideInRef: SlideInRef, - ) {} + ) { + this.slideInRef.requireConfirmationWhen(() => { + return of(this.form.dirty); + }); + } ngOnInit(): void { this.loadForm(); diff --git a/src/app/pages/system/advanced/isolated-gpus/isolated-gpus-form/isolated-gpus-form.component.spec.ts b/src/app/pages/system/advanced/isolated-gpus/isolated-gpus-form/isolated-gpus-form.component.spec.ts index 8aa6cbe4585..7ca21644790 100644 --- a/src/app/pages/system/advanced/isolated-gpus/isolated-gpus-form/isolated-gpus-form.component.spec.ts +++ b/src/app/pages/system/advanced/isolated-gpus/isolated-gpus-form/isolated-gpus-form.component.spec.ts @@ -64,7 +64,7 @@ describe('IsolatedGpuPcisFormComponent', () => { mockProvider(IsolatedGpuValidatorService, { validateGpu: () => of(null), }), - mockProvider(SlideInRef, { close: jest.fn() }), + mockProvider(SlideInRef, { close: jest.fn(), requireConfirmationWhen: jest.fn() }), mockAuth(), ], }); diff --git a/src/app/pages/system/advanced/isolated-gpus/isolated-gpus-form/isolated-gpus-form.component.ts b/src/app/pages/system/advanced/isolated-gpus/isolated-gpus-form/isolated-gpus-form.component.ts index 7c6f7d13566..439fa796139 100644 --- a/src/app/pages/system/advanced/isolated-gpus/isolated-gpus-form/isolated-gpus-form.component.ts +++ b/src/app/pages/system/advanced/isolated-gpus/isolated-gpus-form/isolated-gpus-form.component.ts @@ -7,7 +7,7 @@ import { MatCard, MatCardContent } from '@angular/material/card'; import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy'; import { Store } from '@ngrx/store'; import { TranslateService, TranslateModule } from '@ngx-translate/core'; -import { map, take } from 'rxjs'; +import { map, of, take } from 'rxjs'; import { RequiresRolesDirective } from 'app/directives/requires-roles/requires-roles.directive'; import { Role } from 'app/enums/role.enum'; import { FormActionsComponent } from 'app/modules/forms/ix-forms/components/form-actions/form-actions.component'; @@ -71,7 +71,11 @@ export class IsolatedGpusFormComponent implements OnInit { private gpuValidator: IsolatedGpuValidatorService, private snackbar: SnackbarService, public slideInRef: SlideInRef, - ) { } + ) { + this.slideInRef.requireConfirmationWhen(() => { + return of(this.formGroup.dirty); + }); + } ngOnInit(): void { this.store$.pipe( diff --git a/src/app/pages/system/advanced/kernel/kernel-form/kernel-form.component.spec.ts b/src/app/pages/system/advanced/kernel/kernel-form/kernel-form.component.spec.ts index a6a8870271a..2e0c94ce20e 100644 --- a/src/app/pages/system/advanced/kernel/kernel-form/kernel-form.component.spec.ts +++ b/src/app/pages/system/advanced/kernel/kernel-form/kernel-form.component.spec.ts @@ -30,7 +30,11 @@ describe('KernelFormComponent', () => { open: jest.fn(() => of({ response: true, error: null })), components$: of([]), }), - mockProvider(SlideInRef, { close: jest.fn(), getData: jest.fn(() => undefined) }), + mockProvider(SlideInRef, { + close: jest.fn(), + getData: jest.fn(() => undefined), + requireConfirmationWhen: jest.fn(), + }), provideMockStore(), mockAuth(), ], @@ -39,7 +43,11 @@ describe('KernelFormComponent', () => { beforeEach(() => { spectator = createComponent({ providers: [ - mockProvider(SlideInRef, { close: jest.fn(), getData: jest.fn(() => true) }), + mockProvider(SlideInRef, { + close: jest.fn(), + getData: jest.fn(() => true), + requireConfirmationWhen: jest.fn(), + }), ], }); loader = TestbedHarnessEnvironment.loader(spectator.fixture); diff --git a/src/app/pages/system/advanced/kernel/kernel-form/kernel-form.component.ts b/src/app/pages/system/advanced/kernel/kernel-form/kernel-form.component.ts index b0689a4cc0c..dfd1055fc9a 100644 --- a/src/app/pages/system/advanced/kernel/kernel-form/kernel-form.component.ts +++ b/src/app/pages/system/advanced/kernel/kernel-form/kernel-form.component.ts @@ -7,6 +7,7 @@ import { MatCard, MatCardContent } from '@angular/material/card'; import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy'; import { Store } from '@ngrx/store'; import { TranslateService, TranslateModule } from '@ngx-translate/core'; +import { of } from 'rxjs'; import { RequiresRolesDirective } from 'app/directives/requires-roles/requires-roles.directive'; import { Role } from 'app/enums/role.enum'; import { helptextSystemAdvanced } from 'app/helptext/system/advanced'; @@ -68,6 +69,10 @@ export class KernelFormComponent implements OnInit { private store$: Store, public slideInRef: SlideInRef, ) { + this.slideInRef.requireConfirmationWhen(() => { + return of(this.form.dirty); + }); + if (slideInRef.getData()) { this.debugkernel = true; } diff --git a/src/app/pages/system/advanced/system-security/system-security-form/system-security-form.component.ts b/src/app/pages/system/advanced/system-security/system-security-form/system-security-form.component.ts index c34542860b6..e6147b9ad02 100644 --- a/src/app/pages/system/advanced/system-security/system-security-form/system-security-form.component.ts +++ b/src/app/pages/system/advanced/system-security/system-security-form/system-security-form.component.ts @@ -57,11 +57,11 @@ export class SystemSecurityFormComponent implements OnInit { private cdr: ChangeDetectorRef, private translate: TranslateService, private snackbar: SnackbarService, - public slideInRef: SlideInRef, private store$: Store, private dialogService: DialogService, private api: ApiService, private errorHandler: ErrorHandlerService, + public slideInRef: SlideInRef, ) { this.slideInRef.requireConfirmationWhen(() => { return of(this.form.dirty); diff --git a/src/app/pages/system/alert-service/alert-service/alert-service.component.ts b/src/app/pages/system/alert-service/alert-service/alert-service.component.ts index 907fe85eafa..0392de19195 100644 --- a/src/app/pages/system/alert-service/alert-service/alert-service.component.ts +++ b/src/app/pages/system/alert-service/alert-service/alert-service.component.ts @@ -123,6 +123,9 @@ export class AlertServiceComponent implements OnInit { private dialogService: DialogService, public slideInRef: SlideInRef, ) { + this.slideInRef.requireConfirmationWhen(() => { + return of(this.commonForm.dirty || this.alertServiceForm?.form.dirty); + }); this.existingAlertService = this.slideInRef.getData(); this.setFormEvents(); } diff --git a/src/app/pages/system/bootenv/bootenv-form/bootenv-form.component.ts b/src/app/pages/system/bootenv/bootenv-form/bootenv-form.component.ts index 33c5eaa4e54..f82f9814b58 100644 --- a/src/app/pages/system/bootenv/bootenv-form/bootenv-form.component.ts +++ b/src/app/pages/system/bootenv/bootenv-form/bootenv-form.component.ts @@ -10,6 +10,7 @@ import { MatCard, MatCardContent } from '@angular/material/card'; import { FormBuilder } from '@ngneat/reactive-forms'; import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy'; import { TranslateModule } from '@ngx-translate/core'; +import { of } from 'rxjs'; import { nameValidatorRegex } from 'app/constants/name-validator.constant'; import { RequiresRolesDirective } from 'app/directives/requires-roles/requires-roles.directive'; import { Role } from 'app/enums/role.enum'; @@ -66,6 +67,9 @@ export class BootEnvironmentFormComponent implements OnInit { private errorHandler: FormErrorHandlerService, public slideInRef: SlideInRef, ) { + this.slideInRef.requireConfirmationWhen(() => { + return of(this.formGroup.dirty); + }); this.currentName = this.slideInRef.getData(); } diff --git a/src/app/pages/system/enclosure/components/jbof-list/jbof-form/jbof-form.component.ts b/src/app/pages/system/enclosure/components/jbof-list/jbof-form/jbof-form.component.ts index a7622c33c34..e11a97b479a 100644 --- a/src/app/pages/system/enclosure/components/jbof-list/jbof-form/jbof-form.component.ts +++ b/src/app/pages/system/enclosure/components/jbof-list/jbof-form/jbof-form.component.ts @@ -6,7 +6,7 @@ import { MatButton } from '@angular/material/button'; import { MatCard, MatCardContent } from '@angular/material/card'; import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy'; import { TranslateService, TranslateModule } from '@ngx-translate/core'; -import { Observable } from 'rxjs'; +import { Observable, of } from 'rxjs'; import { RequiresRolesDirective } from 'app/directives/requires-roles/requires-roles.directive'; import { Role } from 'app/enums/role.enum'; import { Jbof, JbofUpdate } from 'app/interfaces/jbof.interface'; @@ -72,6 +72,9 @@ export class JbofFormComponent implements OnInit { private translate: TranslateService, public slideInRef: SlideInRef, ) { + this.slideInRef.requireConfirmationWhen(() => { + return of(this.form.dirty); + }); this.editingJbof = this.slideInRef.getData(); } diff --git a/src/app/pages/system/general-settings/email/email-form/email-form.component.ts b/src/app/pages/system/general-settings/email/email-form/email-form.component.ts index 6a28e35eb31..4a491b4e384 100644 --- a/src/app/pages/system/general-settings/email/email-form/email-form.component.ts +++ b/src/app/pages/system/general-settings/email/email-form/email-form.component.ts @@ -150,6 +150,9 @@ export class EmailFormComponent implements OnInit { private systemGeneralService: SystemGeneralService, public slideInRef: SlideInRef, ) { + this.slideInRef.requireConfirmationWhen(() => { + return of(this.form.dirty); + }); this.emailConfig = this.slideInRef.getData(); } diff --git a/src/app/pages/system/general-settings/gui/gui-form/gui-form.component.ts b/src/app/pages/system/general-settings/gui/gui-form/gui-form.component.ts index bdea1159b7f..2d773b48953 100644 --- a/src/app/pages/system/general-settings/gui/gui-form/gui-form.component.ts +++ b/src/app/pages/system/general-settings/gui/gui-form/gui-form.component.ts @@ -105,6 +105,10 @@ export class GuiFormComponent { public slideInRef: SlideInRef, @Inject(WINDOW) private window: Window, ) { + this.slideInRef.requireConfirmationWhen(() => { + return of(this.formGroup.dirty); + }); + this.loadCurrentValues(); this.setupThemePreview(); } diff --git a/src/app/pages/system/general-settings/localization/localization-form/localization-form.component.ts b/src/app/pages/system/general-settings/localization/localization-form/localization-form.component.ts index 5c6ebfca432..13a527a4f66 100644 --- a/src/app/pages/system/general-settings/localization/localization-form/localization-form.component.ts +++ b/src/app/pages/system/general-settings/localization/localization-form/localization-form.component.ts @@ -149,6 +149,10 @@ export class LocalizationFormComponent implements OnInit { public slideInRef: SlideInRef, @Inject(WINDOW) private window: Window, ) { + this.slideInRef.requireConfirmationWhen(() => { + return of(this.formGroup.dirty); + }); + this.localizationSettings = this.slideInRef.getData(); } diff --git a/src/app/pages/system/general-settings/ntp-server/ntp-server-form/ntp-server-form.component.ts b/src/app/pages/system/general-settings/ntp-server/ntp-server-form/ntp-server-form.component.ts index 9f111a0925d..43ec98e0158 100644 --- a/src/app/pages/system/general-settings/ntp-server/ntp-server-form/ntp-server-form.component.ts +++ b/src/app/pages/system/general-settings/ntp-server/ntp-server-form/ntp-server-form.component.ts @@ -6,7 +6,7 @@ import { MatButton } from '@angular/material/button'; import { MatCard, MatCardContent } from '@angular/material/card'; import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy'; import { TranslateService, TranslateModule } from '@ngx-translate/core'; -import { Observable } from 'rxjs'; +import { Observable, of } from 'rxjs'; import { RequiresRolesDirective } from 'app/directives/requires-roles/requires-roles.directive'; import { Role } from 'app/enums/role.enum'; import { helptextSystemNtpservers as helptext } from 'app/helptext/system/ntp-servers'; @@ -85,6 +85,9 @@ export class NtpServerFormComponent implements OnInit { private errorHandler: FormErrorHandlerService, public slideInRef: SlideInRef, ) { + this.slideInRef.requireConfirmationWhen(() => { + return of(this.formGroup.dirty); + }); this.editingServer = this.slideInRef.getData(); } diff --git a/src/app/pages/system/general-settings/support/license/license.component.ts b/src/app/pages/system/general-settings/support/license/license.component.ts index 131a1f84f71..53c6c08106f 100644 --- a/src/app/pages/system/general-settings/support/license/license.component.ts +++ b/src/app/pages/system/general-settings/support/license/license.component.ts @@ -7,6 +7,7 @@ import { MatButton } from '@angular/material/button'; import { MatCard, MatCardContent } from '@angular/material/card'; import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy'; import { TranslateModule } from '@ngx-translate/core'; +import { of } from 'rxjs'; import { filter } from 'rxjs/operators'; import { RequiresRolesDirective } from 'app/directives/requires-roles/requires-roles.directive'; import { Role } from 'app/enums/role.enum'; @@ -63,7 +64,11 @@ export class LicenseComponent { private cdr: ChangeDetectorRef, private errorHandler: FormErrorHandlerService, public slideInRef: SlideInRef, - ) {} + ) { + this.slideInRef.requireConfirmationWhen(() => { + return of(this.form.dirty); + }); + } onSubmit(): void { this.isFormLoading = true; diff --git a/src/app/pages/system/general-settings/support/proactive/proactive.component.ts b/src/app/pages/system/general-settings/support/proactive/proactive.component.ts index 601a80c65c6..a16fdd26070 100644 --- a/src/app/pages/system/general-settings/support/proactive/proactive.component.ts +++ b/src/app/pages/system/general-settings/support/proactive/proactive.component.ts @@ -11,7 +11,7 @@ import { MatButton } from '@angular/material/button'; import { MatCard, MatCardContent } from '@angular/material/card'; import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy'; import { TranslateService, TranslateModule } from '@ngx-translate/core'; -import { forkJoin } from 'rxjs'; +import { forkJoin, of } from 'rxjs'; import { RequiresRolesDirective } from 'app/directives/requires-roles/requires-roles.directive'; import { Role } from 'app/enums/role.enum'; import { helptextSystemSupport as helptext } from 'app/helptext/system/support'; @@ -80,7 +80,11 @@ export class ProactiveComponent implements OnInit { private translate: TranslateService, private snackbar: SnackbarService, public slideInRef: SlideInRef, - ) {} + ) { + this.slideInRef.requireConfirmationWhen(() => { + return of(this.form.dirty); + }); + } ngOnInit(): void { this.loadConfig(); diff --git a/src/app/pages/virtualization/components/all-instances/instance-details/instance-disks/instance-disk-form/instance-disk-form.component.spec.ts b/src/app/pages/virtualization/components/all-instances/instance-details/instance-disks/instance-disk-form/instance-disk-form.component.spec.ts index 2e86b024dd1..c5499caf271 100644 --- a/src/app/pages/virtualization/components/all-instances/instance-details/instance-disks/instance-disk-form/instance-disk-form.component.spec.ts +++ b/src/app/pages/virtualization/components/all-instances/instance-details/instance-disks/instance-disk-form/instance-disk-form.component.spec.ts @@ -37,6 +37,7 @@ describe('InstanceDiskFormComponent', () => { instanceId: 'my-instance', }), close: jest.fn(), + requireConfirmationWhen: jest.fn(), }), ], }); @@ -85,6 +86,7 @@ describe('InstanceDiskFormComponent', () => { }, }), close: jest.fn(), + requireConfirmationWhen: jest.fn(), }), ], }); diff --git a/src/app/pages/virtualization/components/all-instances/instance-details/instance-disks/instance-disk-form/instance-disk-form.component.ts b/src/app/pages/virtualization/components/all-instances/instance-details/instance-disks/instance-disk-form/instance-disk-form.component.ts index 6f035bc04e8..55b79fa14d0 100644 --- a/src/app/pages/virtualization/components/all-instances/instance-details/instance-disks/instance-disk-form/instance-disk-form.component.ts +++ b/src/app/pages/virtualization/components/all-instances/instance-details/instance-disks/instance-disk-form/instance-disk-form.component.ts @@ -6,7 +6,7 @@ import { MatButton } from '@angular/material/button'; import { MatCard, MatCardContent } from '@angular/material/card'; import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy'; import { TranslateModule, TranslateService } from '@ngx-translate/core'; -import { Observable } from 'rxjs'; +import { Observable, of } from 'rxjs'; import { VirtualizationDeviceType } from 'app/enums/virtualization.enum'; import { VirtualizationDisk } from 'app/interfaces/virtualization.interface'; import { FormActionsComponent } from 'app/modules/forms/ix-forms/components/form-actions/form-actions.component'; @@ -65,11 +65,15 @@ export class InstanceDiskFormComponent implements OnInit { private formBuilder: FormBuilder, private errorHandler: FormErrorHandlerService, private api: ApiService, - public slideInRef: SlideInRef, private translate: TranslateService, private snackbar: SnackbarService, private filesystem: FilesystemService, - ) {} + public slideInRef: SlideInRef, + ) { + this.slideInRef.requireConfirmationWhen(() => { + return of(this.form.dirty); + }); + } ngOnInit(): void { const disk = this.slideInRef.getData().disk; diff --git a/src/app/pages/virtualization/components/all-instances/instance-details/instance-proxies/instance-proxy-form/instance-proxy-form.component.spec.ts b/src/app/pages/virtualization/components/all-instances/instance-details/instance-proxies/instance-proxy-form/instance-proxy-form.component.spec.ts index 15e683ca3df..6b7fa580696 100644 --- a/src/app/pages/virtualization/components/all-instances/instance-details/instance-proxies/instance-proxy-form/instance-proxy-form.component.spec.ts +++ b/src/app/pages/virtualization/components/all-instances/instance-details/instance-proxies/instance-proxy-form/instance-proxy-form.component.spec.ts @@ -35,6 +35,7 @@ describe('InstanceProxyFormComponent', () => { instanceId: 'my-instance', }), close: jest.fn(), + requireConfirmationWhen: jest.fn(), }), ], }); @@ -89,6 +90,7 @@ describe('InstanceProxyFormComponent', () => { }, }), close: jest.fn(), + requireConfirmationWhen: jest.fn(), }), ], }); diff --git a/src/app/pages/virtualization/components/all-instances/instance-details/instance-proxies/instance-proxy-form/instance-proxy-form.component.ts b/src/app/pages/virtualization/components/all-instances/instance-details/instance-proxies/instance-proxy-form/instance-proxy-form.component.ts index bd533757224..dd3906d541c 100644 --- a/src/app/pages/virtualization/components/all-instances/instance-details/instance-proxies/instance-proxy-form/instance-proxy-form.component.ts +++ b/src/app/pages/virtualization/components/all-instances/instance-details/instance-proxies/instance-proxy-form/instance-proxy-form.component.ts @@ -70,13 +70,17 @@ export class InstanceProxyFormComponent implements OnInit { protected readonly protocolOptions$ = of(mapToOptions(virtualizationProxyProtocolLabels, this.translate)); constructor( - public slideInRef: SlideInRef, private formBuilder: FormBuilder, private errorHandler: FormErrorHandlerService, private api: ApiService, private translate: TranslateService, private snackbar: SnackbarService, - ) {} + public slideInRef: SlideInRef, + ) { + this.slideInRef.requireConfirmationWhen(() => { + return of(this.form.dirty); + }); + } ngOnInit(): void { const proxy = this.slideInRef.getData().proxy; diff --git a/src/app/pages/vm/devices/device-form/device-form.component.ts b/src/app/pages/vm/devices/device-form/device-form.component.ts index cdc1a053824..027d7b85a57 100644 --- a/src/app/pages/vm/devices/device-form/device-form.component.ts +++ b/src/app/pages/vm/devices/device-form/device-form.component.ts @@ -244,6 +244,9 @@ export class DeviceFormComponent implements OnInit { private errorHandler: ErrorHandlerService, public slideInRef: SlideInRef<{ virtualMachineId?: number; device?: VmDevice } | undefined, boolean>, ) { + this.slideInRef.requireConfirmationWhen(() => { + return of(this.typeSpecificForm.dirty); + }); this.slideInData = slideInRef.getData(); } diff --git a/src/app/pages/vm/vm-wizard/vm-wizard.component.ts b/src/app/pages/vm/vm-wizard/vm-wizard.component.ts index 6fa33451b82..fa7de450b4a 100644 --- a/src/app/pages/vm/vm-wizard/vm-wizard.component.ts +++ b/src/app/pages/vm/vm-wizard/vm-wizard.component.ts @@ -125,7 +125,19 @@ export class VmWizardComponent implements OnInit { private vmGpuService: VmGpuService, private snackbar: SnackbarService, public slideInRef: SlideInRef, - ) {} + ) { + this.slideInRef.requireConfirmationWhen(() => { + return of( + this.osStep().form.dirty + || this.cpuAndMemoryStep().form.dirty + || this.diskStep().form.dirty + || this.networkInterfaceStep().form.dirty + || this.installationMediaStep().form.dirty + || this.installationMediaStep().form.dirty + || this.gpuStep().form.dirty, + ); + }); + } ngOnInit(): void { this.setDefaultsFromOs();