From 33837ffcb3ff5ec55376b40832a1821e326d35be Mon Sep 17 00:00:00 2001 From: "Mohd. Shariq" Date: Wed, 22 May 2024 15:13:44 +0530 Subject: [PATCH 1/4] unsaved changes alert on different entities Signed-off-by: Mohd. Shariq --- .../unsaved-changes-dialog.component.css | 0 .../unsaved-changes-dialog.component.html | 13 + .../unsaved-changes-dialog.component.ts | 29 + .../configuration-manager.component.html | 8 +- .../configuration-manager.component.ts | 15 +- .../configuration.module.ts | 4 +- .../add-control-acl.component.html | 17 +- .../add-control-acl.component.ts | 5 + .../add-control-script.component.html | 5 +- .../add-control-script.component.ts | 7 +- .../add-edit-api-flow.component.html | 966 +++++++++--------- .../add-edit-api-flow.component.ts | 860 ++++++++-------- .../control-dispatcher.module.ts | 18 +- .../add-control-pipeline.component.ts | 2 +- .../core/scheduler/scheduler.module.ts | 4 +- .../update-schedule.component.html | 8 +- .../update-schedule.component.ts | 13 +- src/app/shared.module.ts | 5 +- 18 files changed, 1058 insertions(+), 921 deletions(-) create mode 100644 src/app/components/common/unsaved-changes-dialog/unsaved-changes-dialog.component.css create mode 100644 src/app/components/common/unsaved-changes-dialog/unsaved-changes-dialog.component.html create mode 100644 src/app/components/common/unsaved-changes-dialog/unsaved-changes-dialog.component.ts diff --git a/src/app/components/common/unsaved-changes-dialog/unsaved-changes-dialog.component.css b/src/app/components/common/unsaved-changes-dialog/unsaved-changes-dialog.component.css new file mode 100644 index 000000000..e69de29bb diff --git a/src/app/components/common/unsaved-changes-dialog/unsaved-changes-dialog.component.html b/src/app/components/common/unsaved-changes-dialog/unsaved-changes-dialog.component.html new file mode 100644 index 000000000..031a6b00f --- /dev/null +++ b/src/app/components/common/unsaved-changes-dialog/unsaved-changes-dialog.component.html @@ -0,0 +1,13 @@ + + + +
+ + +
+
diff --git a/src/app/components/common/unsaved-changes-dialog/unsaved-changes-dialog.component.ts b/src/app/components/common/unsaved-changes-dialog/unsaved-changes-dialog.component.ts new file mode 100644 index 000000000..5d503df8d --- /dev/null +++ b/src/app/components/common/unsaved-changes-dialog/unsaved-changes-dialog.component.ts @@ -0,0 +1,29 @@ +import { Component, OnInit } from '@angular/core'; +import { DialogService } from '../../common/confirmation-dialog/dialog.service'; + +@Component({ + selector: 'app-unsaved-changes-dialog', + templateUrl: './unsaved-changes-dialog.component.html', + styleUrls: ['./unsaved-changes-dialog.component.css'] +}) +export class UnsavedChangesDialogComponent implements OnInit { + + modalId = 'unsaved-changes-dialog'; + constructor(private dialogService: DialogService) { } + + ngOnInit() { + } + + openModal(id: string) { + this.dialogService.open(id); + } + + closeModal(id: string) { + this.dialogService.close(id); + } + + discardUnsavedChanges() { + this.dialogService.resetChangesEmitter?.emit(true); + } + +} diff --git a/src/app/components/core/configuration-manager/configuration-manager.component.html b/src/app/components/core/configuration-manager/configuration-manager.component.html index b9546ed3d..99eb92b43 100644 --- a/src/app/components/core/configuration-manager/configuration-manager.component.html +++ b/src/app/components/core/configuration-manager/configuration-manager.component.html @@ -49,7 +49,8 @@
+ (click)="save(category.name, category.description)" + [appDisableUntilResponse]="reenableButton">Save
@@ -71,4 +72,7 @@ - \ No newline at end of file + + + + diff --git a/src/app/components/core/configuration-manager/configuration-manager.component.ts b/src/app/components/core/configuration-manager/configuration-manager.component.ts index e054a9cee..e42d62263 100644 --- a/src/app/components/core/configuration-manager/configuration-manager.component.ts +++ b/src/app/components/core/configuration-manager/configuration-manager.component.ts @@ -6,6 +6,8 @@ import { AlertService, ConfigurationControlService, ConfigurationService, FileUploaderService, ProgressBarService, RolesService, SchedulesService } from '../../../services'; +import { Observable } from 'rxjs'; +import { DialogService } from '../../common/confirmation-dialog/dialog.service'; @Component({ selector: 'app-configuration-manager', @@ -35,9 +37,14 @@ export class ConfigurationManagerComponent implements OnInit { public ngProgress: ProgressBarService, private configurationControlService: ConfigurationControlService, private fileUploaderService: FileUploaderService, - public schedulesService: SchedulesService + public schedulesService: SchedulesService, + public unsavedChangesService: DialogService, ) { } + canDeactivate(): Observable | boolean { + return this.unsavedChangesService.confirm({ id: 'unsaved-changes-dialog', changeExist: !isEmpty(this.changedConfig) }); + } + ngOnInit() { this.getSchedules(); this.getTreeStructure(); @@ -51,7 +58,7 @@ export class ConfigurationManagerComponent implements OnInit { (data: any) => { this.categoryData = data.categories; const excludeCategories = this.scheduleNames.concat(["SOUTH", "NORTH", "NOTIFICATIONS"]); - + // filter south, north, notification, management, bucket, dispatcher categories this.categoryData = this.categoryData.filter((n: any) => { return !excludeCategories.includes(n.key.toUpperCase()); @@ -89,7 +96,7 @@ export class ConfigurationManagerComponent implements OnInit { node.id = node.key; node.name = (node.hasOwnProperty('displayName')) ? node.displayName : node.description; node.hasChildren = false; - // If the object has 'children' property recurse + // If the object has 'children' property recurse if (Array.isArray(node.children) && node.children.length > 0) { node.hasChildren = true; this.updateIdAndNameInTreeObject(node.children); @@ -113,7 +120,7 @@ export class ConfigurationManagerComponent implements OnInit { public onNodeActive(tree: TreeComponent) { const rootId = tree.treeModel.focusedNodeId?.toString(); - // In case of root node is in ['Advanced', 'General', 'Utilities'], + // In case of root node is in ['Advanced', 'General', 'Utilities'], // Expand the group and select first child if (['Advanced', 'General', 'Utilities'].includes(rootId)) { const nodes = tree.treeModel.nodes; diff --git a/src/app/components/core/configuration-manager/configuration.module.ts b/src/app/components/core/configuration-manager/configuration.module.ts index dcce513e6..9adf99a6e 100644 --- a/src/app/components/core/configuration-manager/configuration.module.ts +++ b/src/app/components/core/configuration-manager/configuration.module.ts @@ -8,11 +8,13 @@ import { ConfigurationManagerComponent } from '.'; import { DirectivesModule } from '../../../directives/directives.module'; import { ConfigurationService } from '../../../services'; import { SharedModule } from '../../../shared.module'; +import { canDeactivateGuard } from '../../../guards/can-deactivate/can-deactivate.guard'; const routes: Routes = [ { path: '', - component: ConfigurationManagerComponent + component: ConfigurationManagerComponent, + canDeactivate: [canDeactivateGuard] } ]; diff --git a/src/app/components/core/control-dispatcher/add-control-acl/add-control-acl.component.html b/src/app/components/core/control-dispatcher/add-control-acl/add-control-acl.component.html index 739ab3da3..2e968cd3f 100644 --- a/src/app/components/core/control-dispatcher/add-control-acl/add-control-acl.component.html +++ b/src/app/components/core/control-dispatcher/add-control-acl/add-control-acl.component.html @@ -18,7 +18,8 @@
+ class=" icon is-small has-tooltip-left has-tooltip-arrow tooltip is-pulled-right is-hovered help-icon" + data-tooltip="Help">
@@ -56,7 +57,8 @@
-
@@ -79,7 +81,8 @@
-
@@ -284,6 +287,10 @@
- +
- \ No newline at end of file + + + + diff --git a/src/app/components/core/control-dispatcher/add-control-acl/add-control-acl.component.ts b/src/app/components/core/control-dispatcher/add-control-acl/add-control-acl.component.ts index a7d6bc2a9..8c6907d87 100644 --- a/src/app/components/core/control-dispatcher/add-control-acl/add-control-acl.component.ts +++ b/src/app/components/core/control-dispatcher/add-control-acl/add-control-acl.component.ts @@ -8,6 +8,7 @@ import { uniqBy } from 'lodash'; import { DocService } from '../../../../services/doc.service'; import { CustomValidator } from '../../../../directives/custom-validator'; import { SUPPORTED_SERVICE_TYPES, QUOTATION_VALIDATION_PATTERN } from '../../../../utils'; +import { Observable } from 'rxjs'; @Component({ selector: 'app-add-control-acl', @@ -45,6 +46,10 @@ export class AddControlAclComponent implements OnInit { private servicesApiService: ServicesApiService, public sharedService: SharedService) { } + canDeactivate(): Observable | boolean { + return this.dialogService.confirm({ id: 'unsaved-changes-dialog', changeExist: this.aclForm.dirty }); + } + ngOnInit(): void { this.route.params.subscribe(params => { this.name = params['name']; diff --git a/src/app/components/core/control-dispatcher/add-control-script/add-control-script.component.html b/src/app/components/core/control-dispatcher/add-control-script/add-control-script.component.html index 446052453..3cd223339 100644 --- a/src/app/components/core/control-dispatcher/add-control-script/add-control-script.component.html +++ b/src/app/components/core/control-dispatcher/add-control-script/add-control-script.component.html @@ -135,4 +135,7 @@ - \ No newline at end of file + + + + diff --git a/src/app/components/core/control-dispatcher/add-control-script/add-control-script.component.ts b/src/app/components/core/control-dispatcher/add-control-script/add-control-script.component.ts index dd8297144..399ab2cd2 100644 --- a/src/app/components/core/control-dispatcher/add-control-script/add-control-script.component.ts +++ b/src/app/components/core/control-dispatcher/add-control-script/add-control-script.component.ts @@ -9,6 +9,7 @@ import { DocService } from '../../../../services/doc.service'; import { DialogService } from '../../../common/confirmation-dialog/dialog.service'; import { AddStepComponent } from './add-step/add-step.component'; import { QUOTATION_VALIDATION_PATTERN } from '../../../../utils'; +import { Observable } from 'rxjs'; @Component({ @@ -44,6 +45,10 @@ export class AddControlScriptComponent implements OnInit { public rolesService: RolesService, private router: Router) { } + canDeactivate(): Observable | boolean { + return this.dialogService.confirm({ id: 'unsaved-changes-dialog', changeExist: this.scriptForm.dirty }); + } + ngOnInit(): void { this.route.params.subscribe(params => { this.scriptName = params['name']; @@ -157,7 +162,7 @@ export class AddControlScriptComponent implements OnInit { steps.forEach((val: any) => { const keys = Object.keys(val); keys.forEach(key => { - // remove invalid(null, undefined) values from object + // remove invalid(null, undefined) values from object val[key] = pickBy(val[key]); if ('condition' in val[key]) { if (isEmpty(val[key]['condition'].key) || val[key]['condition'].value == null) { diff --git a/src/app/components/core/control-dispatcher/api-flow/add-edit-api-flow/add-edit-api-flow.component.html b/src/app/components/core/control-dispatcher/api-flow/add-edit-api-flow/add-edit-api-flow.component.html index ea0f133f4..4d7adaaf2 100644 --- a/src/app/components/core/control-dispatcher/api-flow/add-edit-api-flow/add-edit-api-flow.component.html +++ b/src/app/components/core/control-dispatcher/api-flow/add-edit-api-flow/add-edit-api-flow.component.html @@ -1,525 +1,563 @@
- - -
-
- - - - -
-
-
- + + +
+
+ + + + +
+
+
+ +
+
+
+
+
-
-
-
- -
-
-
- *required -
-
-
+
+
+ *required +
+
-
-
- -
-
-
-
- +
+
+ +
+
+
+
+
- +
+ +
+ +
+ +
+
+ *required +
+
+
+ +
- -
- -
-
- *required -
-
+
+ +
- - + +
-
- -
+
- -
-
- -
-
-
- -
+
+ +
- -
-
- -
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
- - -
- - - -
-
-
-
-
- -
-
-
-
- - -
-
- *required -
- - - -
-
-
-
-
-
+
+ +
+
+ +
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+ + +
+ + +
+
+
+
+ +
+
+
+
+ + +
+
+ *required +
+ + + +
+
+
+
+
+
+
-
+
-
-
- -
+
+
+
+ +
+
+
-
-
-
-
-
-
-
- -
-
-
- -
-
- -
-
-
- -
-
- -
-
- -
-
-
-
- - -
-
-
-
- -
-
-
- -
-
-
-
-
+
+
+
+
+
+ +
+
+
+ +
+
+ +
-
-
-
-
- -
+
+ +
+
+ +
+
+ +
+
+
+
+ + +
-
-
- -
-
-
- -
-
- -
-
-
- -
-
- -
-
- -
-
-
-
- - -
-
-
-
- -
-
-
- -
-
-
-
-
-
-
-
-
-
- -
+
+
+ +
+
+ +
+
+ + +
+
+
+
+
+ +
-
-
-
-
-
-
-
-
-
- -
-
- -
-
-
-
-
-
-
-
-
-
-
- Setting execution access to be anonymous will allow any user to execute this entry point. It's recommended to disable the anonymous access & allow specific authorized users only. -
-
-
-
- -
-
-
- -
- -
-
-
-
-
-
- +
+
+ +
+
+
+ +
+
+ +
+
+
+ +
+
+ +
+
+ +
+
+
+
+ + +
-
-
-
- - -
- - - -

*Allow list will only be applicable when the anonymous access is disabled.

-
+
+
+ +
+
+
+
- -
-
+ + +
+
+
+
+
+ +
+
+
+
+
+
-
+
+
-
-
- -
-
-
- -
- -
-
-
- *required -
-
-
- - - -
-
+
+
+
- - + +
+ - + -
+ +
- -
+ +
- - -
- - -
-
\ No newline at end of file + + +
+ + +
+ + + + diff --git a/src/app/components/core/control-dispatcher/api-flow/add-edit-api-flow/add-edit-api-flow.component.ts b/src/app/components/core/control-dispatcher/api-flow/add-edit-api-flow/add-edit-api-flow.component.ts index e5014d16d..3d1ba69ee 100644 --- a/src/app/components/core/control-dispatcher/api-flow/add-edit-api-flow/add-edit-api-flow.component.ts +++ b/src/app/components/core/control-dispatcher/api-flow/add-edit-api-flow/add-edit-api-flow.component.ts @@ -9,235 +9,239 @@ import { ActivatedRoute, Router } from '@angular/router'; import { ControlUtilsService } from '../../control-utils.service'; import { DocService } from '../../../../../services/doc.service'; -import { Subject } from 'rxjs'; +import { Observable, Subject } from 'rxjs'; import { takeUntil } from 'rxjs/operators'; import { - AlertService, - ControlAPIFlowService, - ProgressBarService, - SchedulesService, - UserService, - RolesService, - SharedService, - AssetsService, - ControlPipelinesService - } from '../../../../../services'; - import { ControlDispatcherService } from '../../../../../services/control-dispatcher.service'; - import { DialogService } from '../../../../common/confirmation-dialog/dialog.service'; - import { QUOTATION_VALIDATION_PATTERN } from '../../../../../utils'; + AlertService, + ControlAPIFlowService, + ProgressBarService, + SchedulesService, + UserService, + RolesService, + SharedService, + AssetsService, + ControlPipelinesService +} from '../../../../../services'; +import { ControlDispatcherService } from '../../../../../services/control-dispatcher.service'; +import { DialogService } from '../../../../common/confirmation-dialog/dialog.service'; +import { QUOTATION_VALIDATION_PATTERN } from '../../../../../utils'; @Component({ - selector: 'app-add-edit-api-flow', - templateUrl: './add-edit-api-flow.component.html', - styleUrls: ['./add-edit-api-flow.component.css'] + selector: 'app-add-edit-api-flow', + templateUrl: './add-edit-api-flow.component.html', + styleUrls: ['./add-edit-api-flow.component.css'] }) export class AddEditAPIFlowComponent implements OnInit { - QUOTATION_VALIDATION_PATTERN = QUOTATION_VALIDATION_PATTERN; - - selectedType; - types = []; - - selectedDestinationType = { cpdid: 0, name: "Broadcast" }; // Typecast with DestinationType enum - selectedDestinationName = null; - - destinationTypes = []; - destinationNames = []; - - editMode = false; - - apiFlowName: string; - af: APIFlow; - - apiFlowForm: UntypedFormGroup; - - allUsers: User[]; - loggedInUsername: string; - - APIFlowType = ['write', 'operation']; - - destroy$: Subject = new Subject(); - - public reenableButton = new EventEmitter(false); - constructor( - private route: ActivatedRoute, - private assetService: AssetsService, - private controlAPIFlowService: ControlAPIFlowService, - private controlService: ControlDispatcherService, - private controlPipelinesService: ControlPipelinesService, - private schedulesService: SchedulesService, - private alertService: AlertService, - private ngProgress: ProgressBarService, - private fb: UntypedFormBuilder, - public rolesService: RolesService, - private dialogService: DialogService, - public docService: DocService, - public sharedService: SharedService, - private userService: UserService, - private controlUtilsService: ControlUtilsService, - private titlecasePipe: TitleCasePipe, - private router: Router) { - this.apiFlowForm = this.fb.group({ - name: ['', Validators.required], - description: ['', Validators.required], - operation_name: [''], - variables: this.fb.array([]), - constants: this.fb.array([]) - }); - this.sharedService.isUserLoggedIn - .pipe(takeUntil(this.destroy$)) - .subscribe(value => { - this.loggedInUsername = value.userName; - }); - } - - ngOnInit() { - this.af = { - name: '', - type: 'write', - description: '', - operation_name: '', - permitted: false, - destination: 'broadcast', - constants: {}, - variables: {}, - anonymous: false, - allow: [] - }; - this.getDestTypes(); - this.getUsers(); - this.route.params.subscribe(params => { - this.apiFlowName = params['name']; - if (this.apiFlowName) { - this.getAPIFlow(); - } else { - this.selectedType = 'write'; - } - }); - } - - addParameter(param = null, controlType = null) { - if (controlType == null) { - const variableControl = this.apiFlowForm.controls['variables']; - const constControl = this.apiFlowForm.controls['constants']; - variableControl.push(this.initParameter(param, 'variables')); - constControl.push(this.initParameter(param, 'constants')); - } else { - const control = this.apiFlowForm.controls[controlType]; - control.push(this.initParameter(param, controlType)); - } + QUOTATION_VALIDATION_PATTERN = QUOTATION_VALIDATION_PATTERN; + + selectedType; + types = []; + + selectedDestinationType = { cpdid: 0, name: "Broadcast" }; // Typecast with DestinationType enum + selectedDestinationName = null; + + destinationTypes = []; + destinationNames = []; + + editMode = false; + + apiFlowName: string; + af: APIFlow; + + apiFlowForm: UntypedFormGroup; + + allUsers: User[]; + loggedInUsername: string; + + APIFlowType = ['write', 'operation']; + + destroy$: Subject = new Subject(); + + public reenableButton = new EventEmitter(false); + constructor( + private route: ActivatedRoute, + private assetService: AssetsService, + private controlAPIFlowService: ControlAPIFlowService, + private controlService: ControlDispatcherService, + private controlPipelinesService: ControlPipelinesService, + private schedulesService: SchedulesService, + private alertService: AlertService, + private ngProgress: ProgressBarService, + private fb: UntypedFormBuilder, + public rolesService: RolesService, + private dialogService: DialogService, + public docService: DocService, + public sharedService: SharedService, + private userService: UserService, + private controlUtilsService: ControlUtilsService, + private titlecasePipe: TitleCasePipe, + private router: Router) { + this.apiFlowForm = this.fb.group({ + name: ['', Validators.required], + description: ['', Validators.required], + operation_name: [''], + variables: this.fb.array([]), + constants: this.fb.array([]) + }); + this.sharedService.isUserLoggedIn + .pipe(takeUntil(this.destroy$)) + .subscribe(value => { + this.loggedInUsername = value.userName; + }); + } + + canDeactivate(): Observable | boolean { + return this.dialogService.confirm({ id: 'unsaved-changes-dialog', changeExist: this.apiFlowForm.dirty }); + } + + ngOnInit() { + this.af = { + name: '', + type: 'write', + description: '', + operation_name: '', + permitted: false, + destination: 'broadcast', + constants: {}, + variables: {}, + anonymous: false, + allow: [] + }; + this.getDestTypes(); + this.getUsers(); + this.route.params.subscribe(params => { + this.apiFlowName = params['name']; + if (this.apiFlowName) { + this.getAPIFlow(); + } else { + this.selectedType = 'write'; + } + }); + } + + addParameter(param = null, controlType = null) { + if (controlType == null) { + const variableControl = this.apiFlowForm.controls['variables']; + const constControl = this.apiFlowForm.controls['constants']; + variableControl.push(this.initParameter(param, 'variables')); + constControl.push(this.initParameter(param, 'constants')); + } else { + const control = this.apiFlowForm.controls[controlType]; + control.push(this.initParameter(param, controlType)); } - - removeParameter(index: number, param) { - // remove parameter from the list - const control = this.apiFlowForm.controls[param]; - control.removeAt(index); - this.apiFlowForm.markAsDirty(); + } + + removeParameter(index: number, param) { + // remove parameter from the list + const control = this.apiFlowForm.controls[param]; + control.removeAt(index); + this.apiFlowForm.markAsDirty(); + } + + initParameter(param = null, controlType) { + if (controlType === 'variables') { + return this.fb.group({ + vName: [param?.key, Validators.required], + vValue: [param?.value] + }); + } else { + return this.fb.group({ + cName: [param?.key, Validators.required], + cValue: [param?.value] + }); } - - initParameter(param = null, controlType) { - if (controlType === 'variables') { - return this.fb.group({ - vName: [param?.key, Validators.required], - vValue: [param?.value] - }); - } else { - return this.fb.group({ - cName: [param?.key, Validators.required], - cValue: [param?.value] - }); - } + } + + fillParameters(param, controlType) { + let c = this.apiFlowForm.controls[controlType]; + c.clear(); + let i = 0; + for (const [key, value] of Object.entries(param)) { + this.addParameter({ index: i, key: key, value: value }, controlType); + i++; } + } - fillParameters(param, controlType) { - let c = this.apiFlowForm.controls[controlType]; - c.clear(); - let i = 0; - for (const [key, value] of Object.entries(param)) { - this.addParameter({ index: i, key: key, value: value }, controlType); - i++; + public toggleDropdown(id) { + const activeDropDowns = Array.prototype.slice.call(document.querySelectorAll('.dropdown.is-active')); + if (activeDropDowns.length > 0) { + if (activeDropDowns[0].id !== id) { + activeDropDowns[0].classList.remove('is-active'); } } + const dropDown = document.querySelector(`#${id}`); + dropDown.classList.toggle('is-active'); + } + + getAPIFlow() { + /** request started */ + this.ngProgress.start(); + this.controlAPIFlowService.getAPIFlow(this.apiFlowName) + .subscribe((data: APIFlow) => { + this.editMode = true; + this.ngProgress.done(); + this.af = data; + + this.apiFlowForm.get('name').setValue(data.name); + this.apiFlowForm.get('description').setValue(data.description); + if (data.type === 'operation') { + this.apiFlowForm.get('operation_name').setValue(data.operation_name); + } - public toggleDropdown(id) { - const activeDropDowns = Array.prototype.slice.call(document.querySelectorAll('.dropdown.is-active')); - if (activeDropDowns.length > 0) { - if (activeDropDowns[0].id !== id) { - activeDropDowns[0].classList.remove('is-active'); + this.getDestinationNames({ 'name': this.titlecasePipe.transform(this.af.destination) }); + if (this.af.destination.toLowerCase() !== 'broadcast') { + this.selectedDestinationName = this.af[this.af.destination.toLowerCase()]; } - } - const dropDown = document.querySelector(`#${id}`); - dropDown.classList.toggle('is-active'); - } + this.selectedType = data.type; + + this.fillParameters(data.variables, 'variables'); + this.fillParameters(data.constants, 'constants'); + }, error => { + /** request completed */ + this.ngProgress.done(); + if (error.status === 0) { + console.log('service down ', error); + } else { + this.alertService.error(error.statusText); + } + }); + } - getAPIFlow() { - /** request started */ - this.ngProgress.start(); - this.controlAPIFlowService.getAPIFlow(this.apiFlowName) - .subscribe((data: APIFlow) => { - this.editMode = true; - this.ngProgress.done(); - this.af = data; - - this.apiFlowForm.get('name').setValue(data.name); - this.apiFlowForm.get('description').setValue(data.description); - if (data.type === 'operation') { - this.apiFlowForm.get('operation_name').setValue(data.operation_name); - } - - this.getDestinationNames({'name': this.titlecasePipe.transform(this.af.destination)}); - if (this.af.destination.toLowerCase() !== 'broadcast') { - this.selectedDestinationName = this.af[this.af.destination.toLowerCase()]; - } - this.selectedType = data.type; - - this.fillParameters(data.variables, 'variables'); - this.fillParameters(data.constants, 'constants'); - }, error => { - /** request completed */ - this.ngProgress.done(); - if (error.status === 0) { - console.log('service down ', error); - } else { - this.alertService.error(error.statusText); - } - }); + saveAPIFlow(data) { + let payload = this.af; + + payload.name = data.name; + payload.description = data.description; + payload.type = this.selectedType; + if (payload.type === 'operation') { + payload.operation_name = data.operation_name; } - saveAPIFlow(data) { - let payload = this.af; - - payload.name = data.name; - payload.description = data.description; - payload.type = this.selectedType; - if (payload.type === 'operation') { - payload.operation_name = data.operation_name; - } - - const destination = this.af.destination.toLowerCase(); - payload.destination = destination; - if (destination !== 'broadcast') { - payload[destination] = this.selectedDestinationName; - } + const destination = this.af.destination.toLowerCase(); + payload.destination = destination; + if (destination !== 'broadcast') { + payload[destination] = this.selectedDestinationName; + } - let variables = {}; - let constants = {}; - data.variables.forEach(v => { variables[v.vName] = v.vValue }); - data.constants.forEach(c => { constants[c.cName] = c.cValue }); - payload.variables = variables; - payload.constants = constants; + let variables = {}; + let constants = {}; + data.variables.forEach(v => { variables[v.vName] = v.vValue }); + data.constants.forEach(c => { constants[c.cName] = c.cValue }); + payload.variables = variables; + payload.constants = constants; - if (this.editMode) { - this.updateAPIFlow(); - return; - } - this.addAPIFlow(); + if (this.editMode) { + this.updateAPIFlow(); + return; } + this.addAPIFlow(); + } - addAPIFlow() { - this.controlAPIFlowService.createAPIFlow(this.af) + addAPIFlow() { + this.controlAPIFlowService.createAPIFlow(this.af) .subscribe( (data: any) => { /** request completed */ @@ -255,11 +259,11 @@ export class AddEditAPIFlowComponent implements OnInit { } else { this.alertService.error(error.statusText); } - }); - } + }); + } - updateAPIFlow() { - this.controlAPIFlowService.updateAPIFlow(this.apiFlowName, this.af) + updateAPIFlow() { + this.controlAPIFlowService.updateAPIFlow(this.apiFlowName, this.af) .subscribe( (data: any) => { /** request completed */ @@ -277,236 +281,236 @@ export class AddEditAPIFlowComponent implements OnInit { } else { this.alertService.error(error.statusText); } - }); - } + }); + } - deleteAPIFlow() { - this.controlAPIFlowService.deleteAPIFlow(this.apiFlowName) - .subscribe( - (data: any) => { - /** request completed */ - this.ngProgress.done(); - this.reenableButton.emit(false); - this.alertService.success(data.message, true); - this.navigateToList(); - }, - error => { - /** request completed but error */ - this.ngProgress.done(); - this.reenableButton.emit(false); - if (error.status === 0) { - console.log('service down ', error); - } else { - this.alertService.error(error.statusText); - } - }); - } + deleteAPIFlow() { + this.controlAPIFlowService.deleteAPIFlow(this.apiFlowName) + .subscribe( + (data: any) => { + /** request completed */ + this.ngProgress.done(); + this.reenableButton.emit(false); + this.alertService.success(data.message, true); + this.navigateToList(); + }, + error => { + /** request completed but error */ + this.ngProgress.done(); + this.reenableButton.emit(false); + if (error.status === 0) { + console.log('service down ', error); + } else { + this.alertService.error(error.statusText); + } + }); + } - checkAndRequestAPIFlow() { - if (this.getFormControls('variables').length > 0) { - this.openModal('confirmation-execute-dialog') - } else { + checkAndRequestAPIFlow() { + if (this.getFormControls('variables').length > 0) { + this.openModal('confirmation-execute-dialog') + } else { this.requestAPIFlow({}); - } - } - - requestAPIFlow(payload) { - this.controlUtilsService.requestAPIFlow(this.af.name, payload); - this.getAPIFlow(); - } - - changeType(value) { - this.selectedType = value === 'Select Type' ? '' : value; } - - getDestTypes() { - this.controlPipelinesService.getSourceDestinationTypeList('destination') - .subscribe((data: any) => { - this.ngProgress.done(); - this.destinationTypes = data.filter(d => d.name !== 'Any'); - }, error => { - if (error.status === 0) { - console.log('service down ', error); - } else { - this.alertService.error(error.statusText); - } - }); - } - - navigateToList() { - this.router.navigate(['control-dispatcher/entry-points']); - } - - onCheckboxClicked(event) { - this.af.anonymous = event.target.checked; - } - - getFormControls(type): AbstractControl[] { - return (this.apiFlowForm.get(type)).controls; - } - - selectDestinationName(value) { - this.selectedDestinationName = value === 'Select Destination Name' ? null : value; - } - - getDestinationNames(selectedType) { - this.destinationNames = []; - this.selectedDestinationName = null; - this.af.destination = selectedType.name === 'Select Destination Type' ? '' : selectedType.name; - switch (selectedType.name) { - case 'Broadcast': - this.selectedDestinationName = null; - break; - case 'Service': - this.getServiceNames(); - break; - case 'Asset': - this.getAssetNames(); - break; - case 'Script': - this.getScriptNames(); - break; - default: - break; - } + } + + requestAPIFlow(payload) { + this.controlUtilsService.requestAPIFlow(this.af.name, payload); + this.getAPIFlow(); + } + + changeType(value) { + this.selectedType = value === 'Select Type' ? '' : value; + } + + getDestTypes() { + this.controlPipelinesService.getSourceDestinationTypeList('destination') + .subscribe((data: any) => { + this.ngProgress.done(); + this.destinationTypes = data.filter(d => d.name !== 'Any'); + }, error => { + if (error.status === 0) { + console.log('service down ', error); + } else { + this.alertService.error(error.statusText); + } + }); + } + + navigateToList() { + this.router.navigate(['control-dispatcher/entry-points']); + } + + onCheckboxClicked(event) { + this.af.anonymous = event.target.checked; + } + + getFormControls(type): AbstractControl[] { + return (this.apiFlowForm.get(type)).controls; + } + + selectDestinationName(value) { + this.selectedDestinationName = value === 'Select Destination Name' ? null : value; + } + + getDestinationNames(selectedType) { + this.destinationNames = []; + this.selectedDestinationName = null; + this.af.destination = selectedType.name === 'Select Destination Type' ? '' : selectedType.name; + switch (selectedType.name) { + case 'Broadcast': + this.selectedDestinationName = null; + break; + case 'Service': + this.getServiceNames(); + break; + case 'Asset': + this.getAssetNames(); + break; + case 'Script': + this.getScriptNames(); + break; + default: + break; } - - getServiceNames() { - let names = []; - /** request started */ - this.ngProgress.start(); - this.schedulesService.getSchedules(). - subscribe( - (data: any) => { - /** request completed */ - this.ngProgress.done(); - data.schedules.forEach(sch => { - if (this.af.destination === 'Service') { - if (['STARTUP'].includes(sch.type) && ['south_c', 'north_C'].includes(sch.processName)) { - if (sch.processName === 'south_c') { - sch.groupbyType = 'Southbound'; - } - if (sch.processName === 'north_C') { - sch.groupbyType = 'Northbound'; - } - names.push(sch); - } - } else { - if (!['STARTUP'].includes(sch.type)) { - names.push(sch); - } + } + + getServiceNames() { + let names = []; + /** request started */ + this.ngProgress.start(); + this.schedulesService.getSchedules(). + subscribe( + (data: any) => { + /** request completed */ + this.ngProgress.done(); + data.schedules.forEach(sch => { + if (this.af.destination === 'Service') { + if (['STARTUP'].includes(sch.type) && ['south_c', 'north_C'].includes(sch.processName)) { + if (sch.processName === 'south_c') { + sch.groupbyType = 'Southbound'; } - }); - let southboundSvc = []; - let northboundSvc = []; - names.forEach(svc => { - if (svc.processName === 'south_c') { - southboundSvc.push(svc); - } else { - northboundSvc.push(svc); + if (sch.processName === 'north_C') { + sch.groupbyType = 'Northbound'; } - }) - const SortedSouthboundSvc = southboundSvc.sort((a, b) => a.name.localeCompare(b.name)); - const SortedNorthboundSvc = northboundSvc.sort((a, b) => a.name.localeCompare(b.name)); - this.destinationNames = SortedSouthboundSvc.concat(SortedNorthboundSvc); - }, - error => { - /** request completed */ - this.ngProgress.done(); - if (error.status === 0) { - console.log('service down ', error); - } else { - this.alertService.error(error.statusText); + names.push(sch); } - }); - } - - getAssetNames() { - let nameList = []; - /** request started */ - this.ngProgress.start(); - this.assetService.getAsset() - .subscribe( - (data: any[]) => { - /** request completed */ - this.ngProgress.done(); - data.forEach(asset => { - asset['name'] = asset.assetCode; - nameList.push(asset); - }); - this.destinationNames = nameList.sort((a, b) => a.name.localeCompare(b.name)); - }, - error => { - /** request completed but error */ - this.ngProgress.done(); - if (error.status === 0) { - console.log('service down ', error); - } else { - this.alertService.error(error.statusText); + } else { + if (!['STARTUP'].includes(sch.type)) { + names.push(sch); } - }); - } - - getScriptNames() { - /** request started */ - this.ngProgress.start(); - this.controlService.fetchControlServiceScripts() - .subscribe((data: any) => { - this.ngProgress.done(); - this.destinationNames = data.scripts.sort((a, b) => a.name.localeCompare(b.name)); - }, error => { - /** request completed */ - this.ngProgress.done(); - if (error.status === 0) { - console.log('service down ', error); + } + }); + let southboundSvc = []; + let northboundSvc = []; + names.forEach(svc => { + if (svc.processName === 'south_c') { + southboundSvc.push(svc); } else { - this.alertService.error(error.statusText); + northboundSvc.push(svc); } + }) + const SortedSouthboundSvc = southboundSvc.sort((a, b) => a.name.localeCompare(b.name)); + const SortedNorthboundSvc = northboundSvc.sort((a, b) => a.name.localeCompare(b.name)); + this.destinationNames = SortedSouthboundSvc.concat(SortedNorthboundSvc); + }, + error => { + /** request completed */ + this.ngProgress.done(); + if (error.status === 0) { + console.log('service down ', error); + } else { + this.alertService.error(error.statusText); + } + }); + } + + getAssetNames() { + let nameList = []; + /** request started */ + this.ngProgress.start(); + this.assetService.getAsset() + .subscribe( + (data: any[]) => { + /** request completed */ + this.ngProgress.done(); + data.forEach(asset => { + asset['name'] = asset.assetCode; + nameList.push(asset); }); - } - - addValueControl(controlType) { - const control = this.apiFlowForm.controls[controlType]; - this.addParameter({index: control.value.length, key: '', value: ''}, controlType); - } - - getUsers() { - this.ngProgress.start(); - this.userService.getAllUsers() - .subscribe( - (userData) => { - /** request completed */ - this.ngProgress.done(); - this.allUsers = userData['users'].map(user => { - return user.userName; - }); - }, - error => { - /** request completed */ - this.ngProgress.done(); - if (error.status === 0) { - console.log('service down ', error); - } else { - this.alertService.error(error.statusText); - } - }); - } - - selectAllowedUsers(usernames) { - this.af.allow = usernames; - } + this.destinationNames = nameList.sort((a, b) => a.name.localeCompare(b.name)); + }, + error => { + /** request completed but error */ + this.ngProgress.done(); + if (error.status === 0) { + console.log('service down ', error); + } else { + this.alertService.error(error.statusText); + } + }); + } + + getScriptNames() { + /** request started */ + this.ngProgress.start(); + this.controlService.fetchControlServiceScripts() + .subscribe((data: any) => { + this.ngProgress.done(); + this.destinationNames = data.scripts.sort((a, b) => a.name.localeCompare(b.name)); + }, error => { + /** request completed */ + this.ngProgress.done(); + if (error.status === 0) { + console.log('service down ', error); + } else { + this.alertService.error(error.statusText); + } + }); + } - openModal(id: string) { - this.reenableButton.emit(false); - this.dialogService.open(id); - } - - closeModal(id: string) { - this.reenableButton.emit(false); - this.dialogService.close(id); - } + addValueControl(controlType) { + const control = this.apiFlowForm.controls[controlType]; + this.addParameter({ index: control.value.length, key: '', value: '' }, controlType); + } - goToLink(urlSlug: string) { - this.docService.goToSetPointControlDocLink(urlSlug); - } -} \ No newline at end of file + getUsers() { + this.ngProgress.start(); + this.userService.getAllUsers() + .subscribe( + (userData) => { + /** request completed */ + this.ngProgress.done(); + this.allUsers = userData['users'].map(user => { + return user.userName; + }); + }, + error => { + /** request completed */ + this.ngProgress.done(); + if (error.status === 0) { + console.log('service down ', error); + } else { + this.alertService.error(error.statusText); + } + }); + } + + selectAllowedUsers(usernames) { + this.af.allow = usernames; + } + + openModal(id: string) { + this.reenableButton.emit(false); + this.dialogService.open(id); + } + + closeModal(id: string) { + this.reenableButton.emit(false); + this.dialogService.close(id); + } + + goToLink(urlSlug: string) { + this.docService.goToSetPointControlDocLink(urlSlug); + } +} diff --git a/src/app/components/core/control-dispatcher/control-dispatcher.module.ts b/src/app/components/core/control-dispatcher/control-dispatcher.module.ts index 6cbe54478..91937b0f8 100644 --- a/src/app/components/core/control-dispatcher/control-dispatcher.module.ts +++ b/src/app/components/core/control-dispatcher/control-dispatcher.module.ts @@ -46,11 +46,13 @@ const routes: Routes = [ { path: 'script/add', component: AddControlScriptComponent, - canActivate: [RolesGuard] + canActivate: [RolesGuard], + canDeactivate: [canDeactivateGuard] }, { path: 'script/:name/details', - component: AddControlScriptComponent + component: AddControlScriptComponent, + canDeactivate: [canDeactivateGuard] }, { path: 'acl', @@ -59,11 +61,13 @@ const routes: Routes = [ { path: 'acl/add', component: AddControlAclComponent, - canActivate: [RolesGuard] + canActivate: [RolesGuard], + canDeactivate: [canDeactivateGuard] }, { path: 'acl/:name/details', - component: AddControlAclComponent + component: AddControlAclComponent, + canDeactivate: [canDeactivateGuard] }, { path: 'task/add', @@ -96,11 +100,13 @@ const routes: Routes = [ { path: 'entry-points/add', component: AddEditAPIFlowComponent, - canActivate: [RolesGuard] + canActivate: [RolesGuard], + canDeactivate: [canDeactivateGuard] }, { path: 'entry-points/:name/details', - component: AddEditAPIFlowComponent + component: AddEditAPIFlowComponent, + canDeactivate: [canDeactivateGuard] } ]; diff --git a/src/app/components/core/control-dispatcher/pipelines/add-pipeline/add-control-pipeline.component.ts b/src/app/components/core/control-dispatcher/pipelines/add-pipeline/add-control-pipeline.component.ts index dc43ce9d6..dde59e7ae 100644 --- a/src/app/components/core/control-dispatcher/pipelines/add-pipeline/add-control-pipeline.component.ts +++ b/src/app/components/core/control-dispatcher/pipelines/add-pipeline/add-control-pipeline.component.ts @@ -98,7 +98,7 @@ export class AddControlPipelineComponent implements OnInit { } canDeactivate(): Observable | boolean { - return this.dialogService.confirm({ id: 'unsaved-changes-dialog', changeExist: this.unsavedChangesInFilterForm }); + return this.dialogService.confirm({ id: 'unsaved-changes-dialog', changeExist: this.pipelineForm.dirty || this.unsavedChangesInFilterForm }); } ngOnInit(): void { let callsStack = { diff --git a/src/app/components/core/scheduler/scheduler.module.ts b/src/app/components/core/scheduler/scheduler.module.ts index 9aee0b742..9481986a8 100644 --- a/src/app/components/core/scheduler/scheduler.module.ts +++ b/src/app/components/core/scheduler/scheduler.module.ts @@ -11,6 +11,7 @@ import { ListSchedulesComponent } from './list-schedules/list-schedules.componen import { UpdateScheduleComponent } from './update-schedule/update-schedule.component'; import { NgSelectModule } from '@ng-select/ng-select'; import { ScheduleTypeResolver } from './update-schedule/schedule-type.resolver'; +import { canDeactivateGuard } from '../../../guards/can-deactivate/can-deactivate.guard'; const routes: Routes = [ { @@ -23,7 +24,8 @@ const routes: Routes = [ component: UpdateScheduleComponent, resolve: { data: ScheduleTypeResolver - } + }, + canDeactivate: [canDeactivateGuard] } ]; diff --git a/src/app/components/core/scheduler/update-schedule/update-schedule.component.html b/src/app/components/core/scheduler/update-schedule/update-schedule.component.html index 30c7cb03f..66db327a4 100644 --- a/src/app/components/core/scheduler/update-schedule/update-schedule.component.html +++ b/src/app/components/core/scheduler/update-schedule/update-schedule.component.html @@ -241,8 +241,10 @@
+ [disabled]="form?.invalid || (!form.dirty && form.pristine)" (click)="form?.valid && updateSchedule()" + [appDisableUntilResponse]="reenableButton">Save
-
\ No newline at end of file +
+ + diff --git a/src/app/components/core/scheduler/update-schedule/update-schedule.component.ts b/src/app/components/core/scheduler/update-schedule/update-schedule.component.ts index 7204e98e6..e686e7e94 100644 --- a/src/app/components/core/scheduler/update-schedule/update-schedule.component.ts +++ b/src/app/components/core/scheduler/update-schedule/update-schedule.component.ts @@ -7,6 +7,8 @@ import Utils, { QUOTATION_VALIDATION_PATTERN, weekDays } from '../../../../utils import { cloneDeep, isEmpty } from 'lodash'; import { Schedule } from '../schedule'; import { ActivatedRoute, Router } from '@angular/router'; +import { Observable } from 'rxjs'; +import { DialogService } from '../../../common/confirmation-dialog/dialog.service'; @Component({ selector: 'app-update-schedule', @@ -32,6 +34,7 @@ export class UpdateScheduleComponent implements OnInit { public router: Router, private schedulesService: SchedulesService, public fb: UntypedFormBuilder, + public unsavedChangesService: DialogService, private alertService: AlertService, public rolesService: RolesService) { this.form = this.fb.group({ @@ -60,6 +63,10 @@ export class UpdateScheduleComponent implements OnInit { }); } + canDeactivate(): Observable | boolean { + return this.unsavedChangesService.confirm({ id: 'unsaved-changes-dialog', changeExist: this.form.dirty }); + } + ngOnInit() { } public getWeekDays() { @@ -78,11 +85,11 @@ export class UpdateScheduleComponent implements OnInit { if (type.name == 'TIMED') { const time = Utils.convertTimeToSec(this.form.get('time').value); - // Set time control value when type is TIMED + // Set time control value when type is TIMED if (time == 0) { this.form.controls['time'].patchValue('00:00:01') } } - // Enable repeat & time control + // Enable repeat & time control this.form.controls['time'].enable(); this.form.controls['day'].enable(); this.form.controls['repeat'].enable(); @@ -130,7 +137,7 @@ export class UpdateScheduleComponent implements OnInit { const day = this.days.find(day => day.index == index); this.form.controls['day'].patchValue(day); this.form.controls['day'].updateValueAndValidity(); - // set default time + // set default time this.form.controls['time'].patchValue('00:00:01'); this.form.controls['time'].updateValueAndValidity(); return day; diff --git a/src/app/shared.module.ts b/src/app/shared.module.ts index ab6fd199c..04312e7b6 100644 --- a/src/app/shared.module.ts +++ b/src/app/shared.module.ts @@ -21,6 +21,7 @@ import { AddTaskWizardComponent } from './components/core/north/add-task-wizard/ import { TaskScheduleComponent } from './components/core/north/task-schedule/task-schedule.component'; import { ListTypeConfigurationComponent } from './components/core/configuration-manager/list-type-configuration/list-type-configuration.component'; import { KvListTypeConfigurationComponent } from './components/core/configuration-manager/kv-list-type-configuration/kv-list-type-configuration.component'; +import { UnsavedChangesDialogComponent } from './components/common/unsaved-changes-dialog/unsaved-changes-dialog.component'; @NgModule({ imports: [ @@ -48,6 +49,7 @@ import { KvListTypeConfigurationComponent } from './components/core/configuratio AddServiceWizardComponent, AddTaskWizardComponent, TaskScheduleComponent, + UnsavedChangesDialogComponent ], exports: [ ConfigurationGroupComponent, @@ -61,7 +63,8 @@ import { KvListTypeConfigurationComponent } from './components/core/configuratio TabNavigationComponent, AddServiceWizardComponent, AddTaskWizardComponent, - TaskScheduleComponent + TaskScheduleComponent, + UnsavedChangesDialogComponent ] }) export class SharedModule { } From fb7cebbe656ab4a4e31ce99e6d86f85aab787fa4 Mon Sep 17 00:00:00 2001 From: "Mohd. Shariq" Date: Thu, 23 May 2024 17:11:01 +0530 Subject: [PATCH 2/4] unsaved changes alert on add/edit south service page Signed-off-by: Mohd. Shariq --- .../add-service-wizard.component.html | 16 +++++++++++----- .../add-service-wizard.component.ts | 10 ++++++++-- .../south-service-modal.component.html | 5 ++++- .../south-service-modal.component.ts | 6 +++++- src/app/components/core/south/south.module.ts | 7 +++++-- 5 files changed, 33 insertions(+), 11 deletions(-) diff --git a/src/app/components/core/south/add-service-wizard/add-service-wizard.component.html b/src/app/components/core/south/add-service-wizard/add-service-wizard.component.html index f8586286d..d69af80ce 100644 --- a/src/app/components/core/south/add-service-wizard/add-service-wizard.component.html +++ b/src/app/components/core/south/add-service-wizard/add-service-wizard.component.html @@ -21,7 +21,8 @@
- @@ -85,7 +86,8 @@
+ formControlName="name" title="No single quotes and double quotes!" + [pattern]="QUOTATION_VALIDATION_PATTERN"> Service name is required @@ -99,7 +101,7 @@ (changedConfigEvent)="getChangedConfig($event)" [from]="'add-service-form'" (formStatusEvent)="validConfigurationForm = $event">
-
+
@@ -126,9 +128,13 @@
+ [disabled]="serviceForm.invalid || !validConfigurationForm" + [appDisableUntilResponse]="reenableButton">Next
- \ No newline at end of file + + + + diff --git a/src/app/components/core/south/add-service-wizard/add-service-wizard.component.ts b/src/app/components/core/south/add-service-wizard/add-service-wizard.component.ts index 9d2e0f787..e6f0fe956 100644 --- a/src/app/components/core/south/add-service-wizard/add-service-wizard.component.ts +++ b/src/app/components/core/south/add-service-wizard/add-service-wizard.component.ts @@ -1,7 +1,7 @@ import { Component, Input, OnInit, ViewChild, OnDestroy, ChangeDetectorRef, EventEmitter } from '@angular/core'; import { UntypedFormBuilder, UntypedFormControl, UntypedFormGroup, Validators } from '@angular/forms'; import { ActivatedRoute, Router } from '@angular/router'; -import { Subscription } from 'rxjs'; +import { Observable, Subscription } from 'rxjs'; import { cloneDeep, sortBy } from 'lodash'; import { @@ -13,6 +13,7 @@ import { ViewLogsComponent } from '../../logs/packages-log/view-logs/view-logs.c import { DocService } from '../../../../services/doc.service'; import { CustomValidator } from '../../../../directives/custom-validator'; import { QUOTATION_VALIDATION_PATTERN } from '../../../../utils'; +import { DialogService } from '../../../common/confirmation-dialog/dialog.service'; @Component({ selector: 'app-add-service-wizard', @@ -61,7 +62,8 @@ export class AddServiceWizardComponent implements OnInit, OnDestroy { private docService: DocService, private configurationControlService: ConfigurationControlService, private fileUploaderService: FileUploaderService, - private cdRef: ChangeDetectorRef + private cdRef: ChangeDetectorRef, + private dialogService: DialogService ) { this.route.queryParams.subscribe(params => { if (params['source']) { @@ -70,6 +72,10 @@ export class AddServiceWizardComponent implements OnInit, OnDestroy { }); } + canDeactivate(): Observable | boolean { + return this.dialogService.confirm({ id: 'unsaved-changes-dialog', changeExist: this.serviceForm.dirty }); + } + ngOnInit() { this.getSchedules(); this.serviceForm = this.formBuilder.group({ diff --git a/src/app/components/core/south/south-service-modal/south-service-modal.component.html b/src/app/components/core/south/south-service-modal/south-service-modal.component.html index 593b0919e..679325d79 100644 --- a/src/app/components/core/south/south-service-modal/south-service-modal.component.html +++ b/src/app/components/core/south/south-service-modal/south-service-modal.component.html @@ -133,4 +133,7 @@ - \ No newline at end of file + + + + diff --git a/src/app/components/core/south/south-service-modal/south-service-modal.component.ts b/src/app/components/core/south/south-service-modal/south-service-modal.component.ts index 791bfc2a5..056c853d6 100644 --- a/src/app/components/core/south/south-service-modal/south-service-modal.component.ts +++ b/src/app/components/core/south/south-service-modal/south-service-modal.component.ts @@ -22,7 +22,7 @@ import { MAX_INT_SIZE } from '../../../../utils'; import { DialogService } from '../../../common/confirmation-dialog/dialog.service'; import { FilterAlertComponent } from '../../filter/filter-alert/filter-alert.component'; import { ConfigurationGroupComponent } from '../../configuration-manager/configuration-group/configuration-group.component'; -import { Subject, forkJoin, of } from 'rxjs'; +import { Observable, Subject, forkJoin, of } from 'rxjs'; import { catchError, map, takeUntil } from 'rxjs/operators'; import { Service } from '../south-service'; import { FilterListComponent } from '../../filter/filter-list/filter-list.component'; @@ -107,6 +107,10 @@ export class SouthServiceModalComponent implements OnInit { } } + canDeactivate(): Observable | boolean { + return this.dialogService.confirm({ id: 'unsaved-changes-dialog', changeExist: !isEmpty(this.changedConfig) }); + } + ngOnInit() { } public getSouthboundServices(caching: boolean) { diff --git a/src/app/components/core/south/south.module.ts b/src/app/components/core/south/south.module.ts index 603d5a09e..80a05940d 100644 --- a/src/app/components/core/south/south.module.ts +++ b/src/app/components/core/south/south.module.ts @@ -13,6 +13,7 @@ import { AddServiceWizardComponent } from './add-service-wizard/add-service-wiza import { SouthServiceModalComponent } from './south-service-modal/south-service-modal.component'; import { SouthComponent } from './south.component'; import { FlowEditorModule } from '../../common/node-editor/flow-editor.module'; +import { canDeactivateGuard } from '../../../guards/can-deactivate/can-deactivate.guard'; const routes: Routes = [ { @@ -22,11 +23,13 @@ const routes: Routes = [ { path: 'add', component: AddServiceWizardComponent, - canActivate: [RolesGuard] + canActivate: [RolesGuard], + canDeactivate: [canDeactivateGuard] }, { path: ':name/details', - component: SouthServiceModalComponent + component: SouthServiceModalComponent, + canDeactivate: [canDeactivateGuard] }, ]; From 7ab0151cfa42ef122d8207b18f901670564ea9fb Mon Sep 17 00:00:00 2001 From: "Mohd. Shariq" Date: Thu, 23 May 2024 17:16:34 +0530 Subject: [PATCH 3/4] unsaved changes alert on add/edit north page Signed-off-by: Mohd. Shariq --- .../add-task-wizard.component.html | 21 ++++++++++++------- .../add-task-wizard.component.ts | 10 +++++++-- .../north-task-modal.component.html | 14 +++++++++---- .../north-task-modal.component.ts | 13 ++++++++---- src/app/components/core/north/north.module.ts | 7 +++++-- 5 files changed, 46 insertions(+), 19 deletions(-) diff --git a/src/app/components/core/north/add-task-wizard/add-task-wizard.component.html b/src/app/components/core/north/add-task-wizard/add-task-wizard.component.html index db0a0b628..c3aef5f6c 100644 --- a/src/app/components/core/north/add-task-wizard/add-task-wizard.component.html +++ b/src/app/components/core/north/add-task-wizard/add-task-wizard.component.html @@ -21,7 +21,8 @@
- @@ -83,8 +84,9 @@
- + *North instance name is required. @@ -109,7 +111,8 @@
@@ -145,7 +148,7 @@ (changedConfigEvent)="getChangedConfig($event)" [from]="'add-task-form'" (formStatusEvent)="validConfigurationForm = $event">
-
+
@@ -172,9 +175,13 @@
+ [disabled]="taskForm.invalid || !validConfigurationForm" + [appDisableUntilResponse]="reenableButton">Next
-
\ No newline at end of file +
+ + + diff --git a/src/app/components/core/north/add-task-wizard/add-task-wizard.component.ts b/src/app/components/core/north/add-task-wizard/add-task-wizard.component.ts index c9ae56112..62296f3a3 100644 --- a/src/app/components/core/north/add-task-wizard/add-task-wizard.component.ts +++ b/src/app/components/core/north/add-task-wizard/add-task-wizard.component.ts @@ -2,7 +2,7 @@ import { Component, Input, OnInit, ViewChild, OnDestroy, ChangeDetectorRef, Even import { UntypedFormControl, UntypedFormGroup, Validators } from '@angular/forms'; import { ActivatedRoute, Router } from '@angular/router'; import { cloneDeep, sortBy } from 'lodash'; -import { Subscription } from 'rxjs'; +import { Observable, Subscription } from 'rxjs'; import { AlertService, SchedulesService, SharedService, PluginService, ProgressBarService, @@ -12,6 +12,7 @@ import Utils, { QUOTATION_VALIDATION_PATTERN } from '../../../../utils'; import { ViewLogsComponent } from '../../logs/packages-log/view-logs/view-logs.component'; import { DocService } from '../../../../services/doc.service'; import { CustomValidator } from '../../../../directives/custom-validator'; +import { DialogService } from '../../../common/confirmation-dialog/dialog.service'; @Component({ selector: 'app-add-task-wizard', @@ -68,7 +69,8 @@ export class AddTaskWizardComponent implements OnInit, OnDestroy { private docService: DocService, private fileUploaderService: FileUploaderService, private configurationControlService: ConfigurationControlService, - private cdRef: ChangeDetectorRef + private cdRef: ChangeDetectorRef, + private dialogService: DialogService ) { this.route.queryParams.subscribe(params => { if (params['source']) { @@ -77,6 +79,10 @@ export class AddTaskWizardComponent implements OnInit, OnDestroy { }); } + canDeactivate(): Observable | boolean { + return this.dialogService.confirm({ id: 'unsaved-changes-dialog', changeExist: this.taskForm.dirty }); + } + ngOnInit() { this.getSchedules(); this.taskForm.get('repeatDays').setValue('0'); diff --git a/src/app/components/core/north/north-task-modal/north-task-modal.component.html b/src/app/components/core/north/north-task-modal/north-task-modal.component.html index 82b4e1d3c..9f484aca1 100644 --- a/src/app/components/core/north/north-task-modal/north-task-modal.component.html +++ b/src/app/components/core/north/north-task-modal/north-task-modal.component.html @@ -4,7 +4,8 @@
@@ -176,6 +178,10 @@
- +
- \ No newline at end of file + + + + diff --git a/src/app/components/core/north/north-task-modal/north-task-modal.component.ts b/src/app/components/core/north/north-task-modal/north-task-modal.component.ts index f42571a57..20fe4538c 100644 --- a/src/app/components/core/north/north-task-modal/north-task-modal.component.ts +++ b/src/app/components/core/north/north-task-modal/north-task-modal.component.ts @@ -18,7 +18,7 @@ import Utils from '../../../../utils'; import { DialogService } from '../../../common/confirmation-dialog/dialog.service'; import { FilterAlertComponent } from '../../filter/filter-alert/filter-alert.component'; import { ConfigurationGroupComponent } from '../../configuration-manager/configuration-group/configuration-group.component'; -import { Subject, forkJoin, of } from 'rxjs'; +import { Observable, Subject, forkJoin, of } from 'rxjs'; import { catchError, map, takeUntil } from 'rxjs/operators'; import { NorthTask } from '../north-task'; import { FilterListComponent } from '../../filter/filter-list/filter-list.component'; @@ -94,7 +94,7 @@ export class NorthTaskModalComponent implements OnInit, OnChanges { this.getNorthTasks(true) } }) - } + } @HostListener('document:keydown.escape', ['$event']) onKeydownHandler() { const alertModal = document.getElementById('modal-box'); @@ -103,6 +103,11 @@ export class NorthTaskModalComponent implements OnInit, OnChanges { } } + canDeactivate(): Observable | boolean { + return this.dialogService.confirm({ id: 'unsaved-changes-dialog', changeExist: !isEmpty(this.changedConfig) }); + } + + ngOnInit() { } ngOnChanges(changes: SimpleChanges) { @@ -496,11 +501,11 @@ export class NorthTaskModalComponent implements OnInit, OnChanges { return noChange; } - navToNorthPage(){ + navToNorthPage() { this.router.navigate(['/north']); } - getNorthTasks(caching: boolean){ + getNorthTasks(caching: boolean) { this.northService.getNorthTasks(caching) .pipe(takeUntil(this.destroy$)) .subscribe( diff --git a/src/app/components/core/north/north.module.ts b/src/app/components/core/north/north.module.ts index 28e938665..71c0e052a 100644 --- a/src/app/components/core/north/north.module.ts +++ b/src/app/components/core/north/north.module.ts @@ -14,6 +14,7 @@ import { NorthTaskModalComponent } from './north-task-modal/north-task-modal.com import { NorthComponent } from './north.component'; import { FilterModule } from '../filter/filter.module'; import { DragDropModule } from '@angular/cdk/drag-drop'; +import { canDeactivateGuard } from '../../../guards/can-deactivate/can-deactivate.guard'; const routes: Routes = [ { @@ -23,11 +24,13 @@ const routes: Routes = [ { path: 'add', component: AddTaskWizardComponent, - canActivate: [RolesGuard] + canActivate: [RolesGuard], + canDeactivate: [canDeactivateGuard] }, { path: ':name/details', - component: NorthTaskModalComponent + component: NorthTaskModalComponent, + canDeactivate: [canDeactivateGuard] } ]; From bc04694f708bc0566946de4a31e39f7582931916 Mon Sep 17 00:00:00 2001 From: "Mohd. Shariq" Date: Tue, 28 May 2024 16:00:06 +0530 Subject: [PATCH 4/4] change config dialog on right side drawer Signed-off-by: Mohd. Shariq --- .../common/node-editor/flow-editor.module.ts | 2 ++ .../node-editor/node-editor.component.html | 9 ++++-- .../node-editor/node-editor.component.ts | 28 +++++++++++++++++-- .../common/quickview/quickview.component.html | 10 +++---- .../common/quickview/quickview.component.ts | 23 +++++++++------ .../common/quickview/quickview.module.ts | 2 -- .../unsaved-changes-dialog.component.ts | 8 ++++-- 7 files changed, 60 insertions(+), 22 deletions(-) diff --git a/src/app/components/common/node-editor/flow-editor.module.ts b/src/app/components/common/node-editor/flow-editor.module.ts index 79c4f926d..16e3e9920 100644 --- a/src/app/components/common/node-editor/flow-editor.module.ts +++ b/src/app/components/common/node-editor/flow-editor.module.ts @@ -17,11 +17,13 @@ import { AddTaskWizardComponent } from '../../core/north/add-task-wizard/add-tas import { ReadingsCountComponent } from './south/asset-readings/readings-count.component'; import { DirectivesModule } from '../../../directives/directives.module'; import { AssetTrackerComponent } from './south/asset-tracker/asset-tracker.component'; +import { canDeactivateGuard } from '../../../guards/can-deactivate/can-deactivate.guard'; const routes: Routes = [ { path: 'editor/:from', component: NodeEditorComponent, + canDeactivate: [canDeactivateGuard] }, { path: 'editor/:from/:name/details', diff --git a/src/app/components/common/node-editor/node-editor.component.html b/src/app/components/common/node-editor/node-editor.component.html index ea0b19fc4..7123e9114 100644 --- a/src/app/components/common/node-editor/node-editor.component.html +++ b/src/app/components/common/node-editor/node-editor.component.html @@ -40,7 +40,7 @@
- + + (selectedAsset)="selectAsset($event)" (reloadReadings)="getSouthervices()" + (exportReading)="getAssetReadings(readingService)">
@@ -128,3 +128,6 @@ + + + diff --git a/src/app/components/common/node-editor/node-editor.component.ts b/src/app/components/common/node-editor/node-editor.component.ts index 68044c38b..f474e5fd5 100644 --- a/src/app/components/common/node-editor/node-editor.component.ts +++ b/src/app/components/common/node-editor/node-editor.component.ts @@ -18,12 +18,13 @@ import { } from './../../../services'; import { catchError, delay, map, mergeMap, repeatWhen, skip, take, takeUntil, takeWhile } from 'rxjs/operators'; import { Service } from '../../core/south/south-service'; -import { EMPTY, Subject, Subscription, forkJoin, interval, of } from 'rxjs'; +import { EMPTY, Observable, Subject, Subscription, forkJoin, interval, of } from 'rxjs'; import { FlowEditorService } from './flow-editor.service'; import { cloneDeep, isEmpty } from 'lodash'; import { DialogService } from '../confirmation-dialog/dialog.service'; import { NorthTask } from '../../core/north/north-task'; import Utils, { MAX_INT_SIZE, POLLING_INTERVAL } from '../../../utils'; +import { QuickviewComponent } from '../quickview/quickview.component'; @Component({ selector: 'app-node-editor', @@ -31,7 +32,6 @@ import Utils, { MAX_INT_SIZE, POLLING_INTERVAL } from '../../../utils'; styleUrls: ['./node-editor.component.css'] }) export class NodeEditorComponent implements OnInit { - @ViewChild("rete") container!: ElementRef; public source = ''; public from = ''; @@ -82,6 +82,8 @@ export class NodeEditorComponent implements OnInit { selectedAsset = ''; MAX_RANGE = MAX_INT_SIZE / 2; + @ViewChild('quickView') private quickView: QuickviewComponent; + constructor(public injector: Injector, private route: ActivatedRoute, private filterService: FilterService, @@ -124,6 +126,28 @@ export class NodeEditorComponent implements OnInit { this.flowEditorService.canvasClick.next({ canvasClicked: true, connectionId: this.selectedConnectionId }); } } + + canDeactivate(): Observable | boolean { + return this.dialogService.confirm({ id: 'unsaved-changes-dialog', changeExist: this.changeExist() }); + } + + closeRightDrawer() { + // this.dialogService.confirm({ id: 'unsaved-changes-dialog', changeExist: this.changeExist() }); + this.canDeactivate() + if (isEmpty(this.changedConfig)) { + this.quickView.close(); + } + } + + changeExist(): boolean { + return !isEmpty(this.changedConfig) || !isEmpty(this.changedFilterConfig) + } + + resetForm() { + this.changedConfig = {}; + this.closeRightDrawer(); + } + ngOnInit(): void { this.subscription = this.flowEditorService.showItemsInQuickview.pipe(skip(1)).subscribe(data => { this.showPluginConfiguration = data.showPluginConfiguration ? true : false; diff --git a/src/app/components/common/quickview/quickview.component.html b/src/app/components/common/quickview/quickview.component.html index b09b0ca94..0924b7ee4 100644 --- a/src/app/components/common/quickview/quickview.component.html +++ b/src/app/components/common/quickview/quickview.component.html @@ -1,8 +1,8 @@
-
-
- -
- +
+
+
+ +
diff --git a/src/app/components/common/quickview/quickview.component.ts b/src/app/components/common/quickview/quickview.component.ts index f13ae6816..e043087cc 100644 --- a/src/app/components/common/quickview/quickview.component.ts +++ b/src/app/components/common/quickview/quickview.component.ts @@ -1,5 +1,5 @@ -import { Component, HostListener, Input, OnInit, ViewChild } from '@angular/core'; -import * as bulmaQuickview from './../../../../../node_modules/bulma-quickview/dist/js/bulma-quickview.min.js' +import { Component, HostListener, Input, OnInit, ViewChild, Output, EventEmitter } from '@angular/core'; +import * as bulmaQuickview from './../../../../../node_modules/bulma-quickview/dist/js/bulma-quickview.min.js'; @Component({ selector: 'app-quickview', @@ -7,18 +7,18 @@ import * as bulmaQuickview from './../../../../../node_modules/bulma-quickview/d styleUrls: ['./quickview.component.css'] }) export class QuickviewComponent implements OnInit { - @ViewChild('quickView') quickView; @ViewChild('quickViewBlock') quickViewBlock; @Input() showReadings: boolean; - constructor() { - } + @Output() closeAction = new EventEmitter(false); + + constructor() { } @HostListener('document:keydown.escape', ['$event']) onKeydownHandler() { this.quickView.nativeElement.classList.remove('is-active'); } - + ngOnInit(): void { // this is a work around to attach quickview component after the data is loaded in child component (which is rendered through ng-content) var count = 0; @@ -32,15 +32,22 @@ export class QuickviewComponent implements OnInit { } ngOnChanges() { - if(this.showReadings){ + if (this.showReadings) { this.quickView.nativeElement.style.width = '35%'; this.quickViewBlock.nativeElement.style.width = '80%'; return; } - if(this.quickView){ + if (this.quickView) { this.quickView.nativeElement.style.width = '66%'; this.quickViewBlock.nativeElement.style.width = '95%'; } } + dismiss() { + this.closeAction.emit(true); + } + + close() { + this.quickView.nativeElement.classList.remove('is-active'); + } } diff --git a/src/app/components/common/quickview/quickview.module.ts b/src/app/components/common/quickview/quickview.module.ts index bdd411486..41f70370d 100644 --- a/src/app/components/common/quickview/quickview.module.ts +++ b/src/app/components/common/quickview/quickview.module.ts @@ -2,8 +2,6 @@ import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; import { QuickviewComponent } from './quickview.component'; - - @NgModule({ declarations: [QuickviewComponent], imports: [ diff --git a/src/app/components/common/unsaved-changes-dialog/unsaved-changes-dialog.component.ts b/src/app/components/common/unsaved-changes-dialog/unsaved-changes-dialog.component.ts index 5d503df8d..efe078196 100644 --- a/src/app/components/common/unsaved-changes-dialog/unsaved-changes-dialog.component.ts +++ b/src/app/components/common/unsaved-changes-dialog/unsaved-changes-dialog.component.ts @@ -1,5 +1,5 @@ -import { Component, OnInit } from '@angular/core'; -import { DialogService } from '../../common/confirmation-dialog/dialog.service'; +import { Component, EventEmitter, OnInit, Output } from '@angular/core'; +import { DialogService } from '../confirmation-dialog/dialog.service'; @Component({ selector: 'app-unsaved-changes-dialog', @@ -9,6 +9,8 @@ import { DialogService } from '../../common/confirmation-dialog/dialog.service'; export class UnsavedChangesDialogComponent implements OnInit { modalId = 'unsaved-changes-dialog'; + @Output() discardChanges = new EventEmitter(false); + constructor(private dialogService: DialogService) { } ngOnInit() { @@ -23,6 +25,8 @@ export class UnsavedChangesDialogComponent implements OnInit { } discardUnsavedChanges() { + this.closeModal(this.modalId) + this.discardChanges.emit(true); this.dialogService.resetChangesEmitter?.emit(true); }