From ed5fe9f325e74b3076145676a92e99c28f0305dd Mon Sep 17 00:00:00 2001 From: Ryan Mathis Date: Tue, 14 Aug 2018 07:55:23 -0700 Subject: [PATCH] SHIBUI-331 Implemented unsaved changes modal in provider editor --- .../domain/service/provider.service.ts | 6 +++- .../dashboard-providers-list.component.ts | 1 - .../component/unsaved-provider.dialog.html | 16 +++++++++ .../component/unsaved-provider.dialog.ts | 28 +++++++++++++++ .../container/provider-edit.component.ts | 34 +++++++++++++++++-- .../app/metadata/provider/provider.module.ts | 8 +++-- .../app/metadata/provider/provider.routing.ts | 7 ++-- .../provider/reducer/entity.reducer.ts | 2 +- .../resolver/container/editor.component.ts | 1 - 9 files changed, 92 insertions(+), 11 deletions(-) create mode 100644 ui/src/app/metadata/provider/component/unsaved-provider.dialog.html create mode 100644 ui/src/app/metadata/provider/component/unsaved-provider.dialog.ts diff --git a/ui/src/app/metadata/domain/service/provider.service.ts b/ui/src/app/metadata/domain/service/provider.service.ts index 3d83d3c55..ede4bb172 100644 --- a/ui/src/app/metadata/domain/service/provider.service.ts +++ b/ui/src/app/metadata/domain/service/provider.service.ts @@ -1,11 +1,13 @@ import { Injectable } from '@angular/core'; import { HttpClient } from '@angular/common/http'; import { Observable } from 'rxjs'; +import { map } from 'rxjs/operators'; import { MetadataProvider } from '../../domain/model'; import { FileBackedHttpMetadataProvider } from '../model/providers'; import { ProviderOrder } from '../model/metadata-order'; + @Injectable() export class MetadataProviderService { @@ -17,7 +19,9 @@ export class MetadataProviderService { private http: HttpClient ) {} query(): Observable { - return this.http.get(`${this.base}${this.endpoint}`, {}); + return this.http.get(`${this.base}${this.endpoint}`).pipe( + map(providers => providers.filter(p => p['@type'] !== 'BaseMetadataResolver')) + ); } find(id: string): Observable { diff --git a/ui/src/app/metadata/manager/container/dashboard-providers-list.component.ts b/ui/src/app/metadata/manager/container/dashboard-providers-list.component.ts index 1815d4ccf..88ec0b19e 100644 --- a/ui/src/app/metadata/manager/container/dashboard-providers-list.component.ts +++ b/ui/src/app/metadata/manager/container/dashboard-providers-list.component.ts @@ -28,7 +28,6 @@ export class DashboardProvidersListComponent implements OnInit { ngOnInit(): void { this.providers$ = this.store.select(getOrderedProviders); this.providersOpen$ = this.store.select(getOpenProviders); - this.providers$.subscribe(p => console.log(p)); } view(id: string, page: string): void { diff --git a/ui/src/app/metadata/provider/component/unsaved-provider.dialog.html b/ui/src/app/metadata/provider/component/unsaved-provider.dialog.html new file mode 100644 index 000000000..f556f49cd --- /dev/null +++ b/ui/src/app/metadata/provider/component/unsaved-provider.dialog.html @@ -0,0 +1,16 @@ + +
+ + + +
+
\ No newline at end of file diff --git a/ui/src/app/metadata/provider/component/unsaved-provider.dialog.ts b/ui/src/app/metadata/provider/component/unsaved-provider.dialog.ts new file mode 100644 index 000000000..beafacf87 --- /dev/null +++ b/ui/src/app/metadata/provider/component/unsaved-provider.dialog.ts @@ -0,0 +1,28 @@ +import { Component, Input } from '@angular/core'; + +import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; +import { Store, Action } from '@ngrx/store'; +import { Subject } from 'rxjs/Subject'; + +import * as fromEditor from '../reducer'; + +@Component({ + selector: 'unsaved-provider', + templateUrl: './unsaved-provider.dialog.html' +}) +export class UnsavedProviderComponent { + readonly subject: Subject = new Subject(); + + constructor( + public activeModal: NgbActiveModal, + private store: Store + ) { } + + close(): void { + this.activeModal.close(); + } + + dismiss(): void { + this.activeModal.dismiss(); + } +} diff --git a/ui/src/app/metadata/provider/container/provider-edit.component.ts b/ui/src/app/metadata/provider/container/provider-edit.component.ts index 07a79a7cf..ea7114022 100644 --- a/ui/src/app/metadata/provider/container/provider-edit.component.ts +++ b/ui/src/app/metadata/provider/container/provider-edit.component.ts @@ -1,6 +1,6 @@ import { Component, OnDestroy } from '@angular/core'; -import { Router, ActivatedRoute } from '@angular/router'; -import { Observable } from 'rxjs'; +import { Router, ActivatedRoute, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router'; +import { Observable, of } from 'rxjs'; import { skipWhile, map, combineLatest } from 'rxjs/operators'; import { Store } from '@ngrx/store'; import * as fromWizard from '../../../wizard/reducer'; @@ -12,6 +12,9 @@ import { ClearProvider } from '../action/entity.action'; import { Wizard } from '../../../wizard/model'; import { UpdateProviderRequest } from '../action/collection.action'; import { NAV_FORMATS } from '../component/provider-editor-nav.component'; +import { NgbModal } from '../../../../../node_modules/@ng-bootstrap/ng-bootstrap'; +import { UnsavedDialogComponent } from '../../resolver/component/unsaved-dialog.component'; +import { UnsavedProviderComponent } from '../component/unsaved-provider.dialog'; @Component({ selector: 'provider-edit', @@ -36,7 +39,8 @@ export class ProviderEditComponent implements OnDestroy { constructor( private store: Store, private router: Router, - private route: ActivatedRoute + private route: ActivatedRoute, + private modalService: NgbModal ) { this.provider$ = this.store.select(fromProvider.getSelectedProvider).pipe(skipWhile(d => !d)); this.definition$ = this.store.select(fromWizard.getWizardDefinition).pipe(skipWhile(d => !d)); @@ -77,6 +81,10 @@ export class ProviderEditComponent implements OnDestroy { } ngOnDestroy() { + this.clear(); + } + + clear(): void { this.store.dispatch(new ClearProvider()); this.store.dispatch(new ClearWizard()); this.store.dispatch(new ClearEditor()); @@ -87,7 +95,27 @@ export class ProviderEditComponent implements OnDestroy { } cancel(): void { + this.clear(); this.router.navigate(['metadata', 'manager', 'providers']); } + + canDeactivate( + currentRoute: ActivatedRouteSnapshot, + currentState: RouterStateSnapshot, + nextState: RouterStateSnapshot + ): Observable { + if (nextState.url.match('edit')) { return of(true); } + if (Object.keys({ ...this.latest }).length > 0) { + let modal = this.modalService.open(UnsavedProviderComponent); + modal.result.then( + () => { + this.clear(); + this.router.navigate([nextState.url]); + }, + () => console.warn('denied') + ); + } + return this.store.select(fromProvider.getEntityIsSaved); + } } diff --git a/ui/src/app/metadata/provider/provider.module.ts b/ui/src/app/metadata/provider/provider.module.ts index dfd95fa8f..95d037256 100644 --- a/ui/src/app/metadata/provider/provider.module.ts +++ b/ui/src/app/metadata/provider/provider.module.ts @@ -28,6 +28,7 @@ import { EntityEffects } from './effect/entity.effect'; import { ProviderFilterListComponent } from './container/provider-filter-list.component'; import { ProviderEditorNavComponent } from './component/provider-editor-nav.component'; +import { UnsavedProviderComponent } from './component/unsaved-provider.dialog'; @NgModule({ declarations: [ @@ -40,9 +41,12 @@ import { ProviderEditorNavComponent } from './component/provider-editor-nav.comp ProviderSelectComponent, ProviderFilterListComponent, SummaryPropertyComponent, - ProviderEditorNavComponent + ProviderEditorNavComponent, + UnsavedProviderComponent + ], + entryComponents: [ + UnsavedProviderComponent ], - entryComponents: [], imports: [ ReactiveFormsModule, CommonModule, diff --git a/ui/src/app/metadata/provider/provider.routing.ts b/ui/src/app/metadata/provider/provider.routing.ts index 8e6ecc3f5..7acd52fec 100644 --- a/ui/src/app/metadata/provider/provider.routing.ts +++ b/ui/src/app/metadata/provider/provider.routing.ts @@ -10,6 +10,7 @@ import { ProviderFilterListComponent } from './container/provider-filter-list.co import { NewFilterComponent } from '../filter/container/new-filter.component'; import { FilterComponent } from '../filter/container/filter.component'; import { EditFilterComponent } from '../filter/container/edit-filter.component'; +import { CanDeactivateGuard } from '../../core/service/can-deactivate.guard'; export const ProviderRoutes: Routes = [ { @@ -44,6 +45,9 @@ export const ProviderRoutes: Routes = [ path: ':form', component: ProviderEditStepComponent } + ], + canDeactivate: [ + CanDeactivateGuard ] }, { @@ -61,8 +65,7 @@ export const ProviderRoutes: Routes = [ children: [ { path: 'edit', - component: EditFilterComponent, - canDeactivate: [] + component: EditFilterComponent } ] } diff --git a/ui/src/app/metadata/provider/reducer/entity.reducer.ts b/ui/src/app/metadata/provider/reducer/entity.reducer.ts index d5b63eca1..175c769d8 100644 --- a/ui/src/app/metadata/provider/reducer/entity.reducer.ts +++ b/ui/src/app/metadata/provider/reducer/entity.reducer.ts @@ -41,7 +41,7 @@ export function reducer(state = initialState, action: EntityActionUnion): Entity } } -export const isEntitySaved = (state: EntityState) => !Object.keys(state.changes).length && !state.saving; +export const isEntitySaved = (state: EntityState) => state.changes ? !Object.keys(state.changes).length && !state.saving : true; export const getEntityChanges = (state: EntityState) => state.changes; export const isEditorSaving = (state: EntityState) => state.saving; export const getUpdatedEntity = (state: EntityState) => state.changes; diff --git a/ui/src/app/metadata/resolver/container/editor.component.ts b/ui/src/app/metadata/resolver/container/editor.component.ts index 6aa252abe..5d4b6e1c3 100644 --- a/ui/src/app/metadata/resolver/container/editor.component.ts +++ b/ui/src/app/metadata/resolver/container/editor.component.ts @@ -76,7 +76,6 @@ export class EditorComponent implements OnInit, OnDestroy { ); this.providerName$ = this.resolver$.pipe(map(p => p.serviceProviderName)); - this.changes$ = this.store.select(fromResolver.getEditorChanges); this.editorIndex$ = this.route.params.pipe(map(params => Number(params.index))); this.currentPage$ = this.editorIndex$.pipe(map(index => EditorDef.find(r => r.index === index))); this.editor = EditorDef;