From 5a1e9e5e65052eb743321f3d615454f730996cbe Mon Sep 17 00:00:00 2001 From: Ryan Mathis Date: Fri, 8 Jun 2018 13:57:09 +0000 Subject: [PATCH] Merged in feature/SHIBUI-559 (pull request #82) SHIBUI-559: Implemented updates to copy provider * Resolved conflict * SHIBUI-559: Implemented updates to copy provider Approved-by: Shibui Jenkins Approved-by: Ryan Mathis --- .../domain/component/i18n-text.component.html | 5 + .../metadata-provider/action/copy.action.ts | 11 +- .../container/blank-provider.component.html | 112 +++++----- .../container/copy-provider.component.html | 199 +++++++++++------- .../container/copy-provider.component.spec.ts | 42 +++- .../container/copy-provider.component.ts | 44 +++- .../container/new-provider.component.html | 4 +- .../container/new-provider.component.spec.ts | 4 +- .../container/upload-provider.component.html | 122 +++++------ .../metadata-provider/effect/copy.effect.ts | 12 +- .../reducer/copy.reducer.spec.ts | 56 +---- .../metadata-provider/reducer/copy.reducer.ts | 13 +- ui/src/app/metadata-provider/reducer/index.ts | 1 + 13 files changed, 366 insertions(+), 259 deletions(-) diff --git a/ui/src/app/domain/component/i18n-text.component.html b/ui/src/app/domain/component/i18n-text.component.html index 80b821a9f..7484dd61a 100644 --- a/ui/src/app/domain/component/i18n-text.component.html +++ b/ui/src/app/domain/component/i18n-text.component.html @@ -15,6 +15,11 @@ Signing Encryption Both + + SP SSO Descriptor Information + Organization Information + User Interface / MDUI Information + Security Descriptor Information Entity ID Service Provider Name diff --git a/ui/src/app/metadata-provider/action/copy.action.ts b/ui/src/app/metadata-provider/action/copy.action.ts index 198a976db..1343aa9d1 100644 --- a/ui/src/app/metadata-provider/action/copy.action.ts +++ b/ui/src/app/metadata-provider/action/copy.action.ts @@ -8,6 +8,8 @@ export enum CopySourceActionTypes { UPDATE_PROVIDER_COPY = '[Copy Provider] Update Provider Copy Request', + UPDATE_PROVIDER_COPY_SECTIONS = '[Copy Provider] Update Provider Sections', + SAVE_PROVIDER_COPY_REQUEST = '[Copy Provider] Save Provider Copy Request', SAVE_PROVIDER_COPY_SUCCESS = '[Copy Provider] Save Provider Copy Request', SAVE_PROVIDER_COPY_ERROR = '[Copy Provider] Save Provider Copy Request', @@ -37,8 +39,15 @@ export class UpdateProviderCopy implements Action { constructor(public payload: Partial) { } } +export class UpdateProviderCopySections implements Action { + readonly type = CopySourceActionTypes.UPDATE_PROVIDER_COPY_SECTIONS; + + constructor(public payload: string[]) { } +} + export type CopySourceActionUnion = | CreateProviderCopyRequest | CreateProviderCopySuccess | CreateProviderCopyError - | UpdateProviderCopy; + | UpdateProviderCopy + | UpdateProviderCopySections; diff --git a/ui/src/app/metadata-provider/container/blank-provider.component.html b/ui/src/app/metadata-provider/container/blank-provider.component.html index c5aca7057..0f37f6b5b 100644 --- a/ui/src/app/metadata-provider/container/blank-provider.component.html +++ b/ui/src/app/metadata-provider/container/blank-provider.component.html @@ -1,55 +1,59 @@ -
- +
+
+ + + + + Service Provider Name is required + + +
+
+ + + + + Entity ID is required + + + + Entity ID must be unique + +
+ - - -
-
- - - - - Service Provider Name is required - - -
-
- - - - - Entity ID is required - - - - Entity ID must be unique - -
- -
- + + +
+ + + diff --git a/ui/src/app/metadata-provider/container/copy-provider.component.html b/ui/src/app/metadata-provider/container/copy-provider.component.html index ec45620bb..1fd0f0763 100644 --- a/ui/src/app/metadata-provider/container/copy-provider.component.html +++ b/ui/src/app/metadata-provider/container/copy-provider.component.html @@ -1,75 +1,126 @@ -
- +
+
+ + + + + + + + +
+
+ + + + + Service Provider Name is required + + +
+
+ + + + + Entity ID is required + + + + Entity ID must be unique + +
+ - - -
-
- - - - - - - - -
-
- - - - - Service Provider Name is required - - -
-
- - - - - Entity ID is required - - - - Entity ID must be unique - -
- -
- \ No newline at end of file + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + +
Sections to Copy?Yes
+
+
+ + +
+
+
Check All Attributes + +
Clear All Attributes + +
+
+ diff --git a/ui/src/app/metadata-provider/container/copy-provider.component.spec.ts b/ui/src/app/metadata-provider/container/copy-provider.component.spec.ts index 54981361c..1a1b3b406 100644 --- a/ui/src/app/metadata-provider/container/copy-provider.component.spec.ts +++ b/ui/src/app/metadata-provider/container/copy-provider.component.spec.ts @@ -1,3 +1,4 @@ +import { ViewChild, Component } from '@angular/core'; import { TestBed, ComponentFixture } from '@angular/core/testing'; import { ReactiveFormsModule } from '@angular/forms'; import { NoopAnimationsModule } from '@angular/platform-browser/animations'; @@ -8,9 +9,21 @@ import * as fromProvider from '../reducer'; import { CopyProviderComponent } from './copy-provider.component'; import { SharedModule } from '../../shared/shared.module'; import { NavigatorService } from '../../core/service/navigator.service'; +import { I18nTextComponent } from '../../domain/component/i18n-text.component'; + +@Component({ + template: `` +}) +class TestHostComponent { + @ViewChild(CopyProviderComponent) + public formUnderTest: CopyProviderComponent; + + onSave(event: any): void {} +} describe('Copy Provider Page', () => { - let fixture: ComponentFixture; + let fixture: ComponentFixture; let store: Store; let instance: CopyProviderComponent; @@ -26,23 +39,40 @@ describe('Copy Provider Page', () => { SharedModule ], declarations: [ - CopyProviderComponent + CopyProviderComponent, + I18nTextComponent, + TestHostComponent ], providers: [ NavigatorService ] }); - fixture = TestBed.createComponent(CopyProviderComponent); - instance = fixture.componentInstance; + fixture = TestBed.createComponent(TestHostComponent); + instance = fixture.componentInstance.formUnderTest; store = TestBed.get(Store); + fixture.detectChanges(); spyOn(store, 'dispatch').and.callThrough(); }); it('should compile', () => { - fixture.detectChanges(); - expect(fixture).toBeDefined(); }); + + describe('next method', () => { + it('should dispatch an action to create a copy', () => { + instance.next(); + expect(store.dispatch).toHaveBeenCalled(); + }); + }); + + describe('onChange method', () => { + it('should dispatch an action to update the selected sections to copy', () => { + instance.onChange('relyingPartyOverrides'); + expect(store.dispatch).toHaveBeenCalled(); + instance.onChange('relyingPartyOverrides'); + expect(store.dispatch).toHaveBeenCalled(); + }); + }); }); diff --git a/ui/src/app/metadata-provider/container/copy-provider.component.ts b/ui/src/app/metadata-provider/container/copy-provider.component.ts index 6f68a6dcb..c7b59b141 100644 --- a/ui/src/app/metadata-provider/container/copy-provider.component.ts +++ b/ui/src/app/metadata-provider/container/copy-provider.component.ts @@ -5,10 +5,10 @@ import { EventEmitter } from '@angular/core'; import { FormBuilder, FormGroup, FormControl, FormControlName, Validators, AbstractControl } from '@angular/forms'; -import { Observable, Subject } from 'rxjs'; +import { Observable, Subject, of } from 'rxjs'; import { Store } from '@ngrx/store'; -import { startWith, take } from 'rxjs/operators'; +import { startWith, take, last } from 'rxjs/operators'; import { AddDraftRequest } from '../../domain/action/draft-collection.action'; import { AddProviderRequest, UploadProviderRequest } from '../../domain/action/provider-collection.action'; @@ -17,7 +17,7 @@ import { EntityValidators } from '../../domain/service/entity-validators.service import { SearchIds } from '../action/search.action'; import * as fromProvider from '../reducer'; import { Provider } from '../../domain/entity/provider'; -import { CreateProviderCopyRequest } from '../action/copy.action'; +import { CreateProviderCopyRequest, UpdateProviderCopySections} from '../action/copy.action'; @Component({ @@ -30,6 +30,22 @@ export class CopyProviderComponent implements OnInit { providerForm: FormGroup; ids$: Observable; searchResults$: Observable; + selected$: Observable; + selected: string[]; + + sections = [ + { i18nKey: 'organizationInfo', property: 'organization' }, + { i18nKey: 'contacts', property: 'contacts' }, + { i18nKey: 'uiMduiInfo', property: 'mdui' }, + { i18nKey: 'spSsoDescriptorInfo', property: 'serviceProviderSsoDescriptor' }, + { i18nKey: 'logoutEndpoints', property: 'logoutEndpoints' }, + { i18nKey: 'securityDescriptorInfo', property: 'securityInfo' }, + { i18nKey: 'assertionConsumerServices', property: 'assertionConsumerServices' }, + { i18nKey: 'relyingPartyOverrides', property: 'relyingPartyOverrides' }, + { i18nKey: 'attributeRelease', property: 'attributeRelease' } + ]; + + sections$ = of(this.sections); constructor( private store: Store, @@ -37,13 +53,16 @@ export class CopyProviderComponent implements OnInit { ) { this.ids$ = this.store.select(fromCollections.getAllEntityIds); this.searchResults$ = this.store.select(fromProvider.getSearchResults); + this.selected$ = this.store.select(fromProvider.getSectionsToCopy); + + this.selected$.subscribe(selected => this.selected = selected); } ngOnInit(): void { this.providerForm = this.fb.group({ serviceProviderName: ['', [Validators.required]], entityId: ['', Validators.required, EntityValidators.createUniqueIdValidator(this.ids$)], - target: ['', [Validators.required], [EntityValidators.existsInCollection(this.ids$)]] + target: ['', [Validators.required], [EntityValidators.existsInCollection(this.ids$)]], }); this.store.select(fromProvider.getAttributes) @@ -64,5 +83,18 @@ export class CopyProviderComponent implements OnInit { })); } - updateOptions(query: string): void {} -} /* istanbul ignore next */ + onChange(attr: string): void { + this.store.dispatch( + new UpdateProviderCopySections( + this.selected.indexOf(attr) > -1 ? this.selected.filter(a => a !== attr) : [...this.selected, attr] + ) + ); + } + + onCheckAll(): void { + this.store.dispatch(new UpdateProviderCopySections(this.sections.map(section => section.property))); + } + onCheckNone(event: Event | null = null): void { + this.store.dispatch(new UpdateProviderCopySections([])); + } +} diff --git a/ui/src/app/metadata-provider/container/new-provider.component.html b/ui/src/app/metadata-provider/container/new-provider.component.html index 4ba004908..37d373546 100644 --- a/ui/src/app/metadata-provider/container/new-provider.component.html +++ b/ui/src/app/metadata-provider/container/new-provider.component.html @@ -54,11 +54,9 @@

How are you addi
-
- -
+ diff --git a/ui/src/app/metadata-provider/container/new-provider.component.spec.ts b/ui/src/app/metadata-provider/container/new-provider.component.spec.ts index e81de97f1..4c320fa21 100644 --- a/ui/src/app/metadata-provider/container/new-provider.component.spec.ts +++ b/ui/src/app/metadata-provider/container/new-provider.component.spec.ts @@ -16,6 +16,7 @@ import * as fromProvider from '../reducer'; import * as fromCollections from '../../domain/reducer'; import { RouterStub } from '../../../testing/router.stub'; import { ActivatedRouteStub } from '../../../testing/activated-route.stub'; +import { I18nTextComponent } from '../../domain/component/i18n-text.component'; describe('New Provider Page', () => { let fixture: ComponentFixture; @@ -40,7 +41,8 @@ describe('New Provider Page', () => { NewProviderComponent, BlankProviderComponent, UploadProviderComponent, - CopyProviderComponent + CopyProviderComponent, + I18nTextComponent ], providers: [ NavigatorService, diff --git a/ui/src/app/metadata-provider/container/upload-provider.component.html b/ui/src/app/metadata-provider/container/upload-provider.component.html index 86c2b0a3a..3b00d5e1a 100644 --- a/ui/src/app/metadata-provider/container/upload-provider.component.html +++ b/ui/src/app/metadata-provider/container/upload-provider.component.html @@ -1,59 +1,63 @@ -
- -
-
- - - - - Service Provider Name is required - - -
-
- -
- - -
-
-
- — - OR - — -
-
- - -
- -
-
+
+
+
+ +
+
+ + + + + Service Provider Name is required + + +
+
+ +
+ + +
+
+
+ — + OR + — +
+
+ + +
+ +
+
+
+
diff --git a/ui/src/app/metadata-provider/effect/copy.effect.ts b/ui/src/app/metadata-provider/effect/copy.effect.ts index 425657ece..f3b5473d1 100644 --- a/ui/src/app/metadata-provider/effect/copy.effect.ts +++ b/ui/src/app/metadata-provider/effect/copy.effect.ts @@ -25,17 +25,19 @@ export class CopyProviderEffects { copyRequest$ = this.actions$.pipe( ofType(CopySourceActionTypes.CREATE_PROVIDER_COPY_REQUEST), map(action => action.payload), - withLatestFrom(this.store.select(fromCollection.getProviderCollection)), - switchMap(([attrs, providers]) => { + withLatestFrom( + this.store.select(fromCollection.getProviderCollection), + this.store.select(fromProvider.getSectionsToCopy) + ), + switchMap(([attrs, providers, sections]) => { const { serviceProviderName, entityId } = attrs; const provider = providers.find(p => p.entityId === attrs.target); - const { attributeRelease, relyingPartyOverrides } = provider; + const copied = sections.reduce((c, section) => ({ ...c, ...{[section]: provider[section] } }), {}); const action = provider ? new CreateProviderCopySuccess(new Provider({ serviceProviderName, entityId, - attributeRelease, - relyingPartyOverrides + ...copied })) : new CreateProviderCopyError(new Error('Not found')); return of(action); diff --git a/ui/src/app/metadata-provider/reducer/copy.reducer.spec.ts b/ui/src/app/metadata-provider/reducer/copy.reducer.spec.ts index e02339f84..34b69b258 100644 --- a/ui/src/app/metadata-provider/reducer/copy.reducer.spec.ts +++ b/ui/src/app/metadata-provider/reducer/copy.reducer.spec.ts @@ -17,13 +17,7 @@ describe('Provider -> Copy Reducer', () => { describe(`${CopySourceActionTypes.CREATE_PROVIDER_COPY_REQUEST} action`, () => { it('should set properties on the state', () => { - const obj = { - target: null, - serviceProviderName: null, - entityId: null, - provider: null, - saving: false - }; + const obj = { ...snapshot }; const result = reducer(snapshot, new CreateProviderCopyRequest(obj)); expect(result).toEqual(obj); @@ -33,13 +27,7 @@ describe('Provider -> Copy Reducer', () => { describe(`${CopySourceActionTypes.CREATE_PROVIDER_COPY_SUCCESS} action`, () => { it('should set properties on the state', () => { const p = new Provider({}); - const obj = { - target: null, - serviceProviderName: null, - entityId: null, - provider: null, - saving: false - }; + const obj = { ...snapshot }; const result = reducer(snapshot, new actions.CreateProviderCopySuccess(p)); expect(result.provider).toBe(p); @@ -49,13 +37,7 @@ describe('Provider -> Copy Reducer', () => { describe(`${CopySourceActionTypes.CREATE_PROVIDER_COPY_ERROR} action`, () => { it('should set properties on the state', () => { const p = new Provider({}); - const obj = { - target: null, - serviceProviderName: null, - entityId: null, - provider: null, - saving: false - }; + const obj = { ...snapshot }; const result = reducer(snapshot, new actions.CreateProviderCopyError(new Error())); expect(result.provider).toBeNull(); @@ -64,13 +46,7 @@ describe('Provider -> Copy Reducer', () => { describe(`${CopySourceActionTypes.UPDATE_PROVIDER_COPY} action`, () => { it('should set properties on the state', () => { - const obj = { - target: null, - serviceProviderName: null, - entityId: null, - provider: new Provider({}), - saving: false - }; + const obj = { ...snapshot, provider: new Provider({}) }; const result = reducer(snapshot, new actions.UpdateProviderCopy({id: 'foo'})); expect(result.provider.id).toBe('foo'); @@ -80,13 +56,7 @@ describe('Provider -> Copy Reducer', () => { describe(`${ fromCollection.ProviderCollectionActionTypes.ADD_PROVIDER } action`, () => { it('should set properties on the state', () => { const p = new Provider({}); - const obj = { - target: null, - serviceProviderName: null, - entityId: null, - provider: p, - saving: false - }; + const obj = { ...snapshot, provider: p }; const result = reducer(snapshot, new fromCollection.AddProviderRequest(p)); expect(result.saving).toBe(true); @@ -96,13 +66,7 @@ describe('Provider -> Copy Reducer', () => { describe(`${fromCollection.ProviderCollectionActionTypes.ADD_PROVIDER_SUCCESS} action`, () => { it('should set properties on the state', () => { const p = new Provider({}); - const obj = { - target: null, - serviceProviderName: null, - entityId: null, - provider: p, - saving: false - }; + const obj = { ...snapshot, provider: p }; const result = reducer(snapshot, new fromCollection.AddProviderSuccess(p)); expect(result.saving).toBe(false); @@ -112,13 +76,7 @@ describe('Provider -> Copy Reducer', () => { describe(`${fromCollection.ProviderCollectionActionTypes.ADD_PROVIDER_FAIL} action`, () => { it('should set properties on the state', () => { const p = new Provider({}); - const obj = { - target: null, - serviceProviderName: null, - entityId: null, - provider: p, - saving: false - }; + const obj = { ...snapshot, provider: p }; const result = reducer(snapshot, new fromCollection.AddProviderFail(p)); expect(result.saving).toBe(false); diff --git a/ui/src/app/metadata-provider/reducer/copy.reducer.ts b/ui/src/app/metadata-provider/reducer/copy.reducer.ts index 88ce7aaf4..416086eba 100644 --- a/ui/src/app/metadata-provider/reducer/copy.reducer.ts +++ b/ui/src/app/metadata-provider/reducer/copy.reducer.ts @@ -10,6 +10,7 @@ export interface CopyState { entityId: string; provider: MetadataProvider; saving: boolean; + sections: string[]; } export const initialState: CopyState = { @@ -17,11 +18,20 @@ export const initialState: CopyState = { serviceProviderName: null, entityId: null, provider: null, - saving: false + saving: false, + sections: [] }; export function reducer(state = initialState, action: CopySourceActionUnion | ProviderCollectionActionsUnion): CopyState { switch (action.type) { + case CopySourceActionTypes.UPDATE_PROVIDER_COPY_SECTIONS: { + return { + ...state, + sections: [ + ...action.payload + ] + }; + } case CopySourceActionTypes.CREATE_PROVIDER_COPY_REQUEST: { return { ...state, @@ -70,4 +80,5 @@ export const getCopyAttributes = (state: CopyState) => ({ serviceProviderName: state.serviceProviderName, target: state.target }); +export const getCopySections = (state: CopyState) => state.sections; export const getSaving = (state: CopyState) => state.saving; diff --git a/ui/src/app/metadata-provider/reducer/index.ts b/ui/src/app/metadata-provider/reducer/index.ts index 7e6ec4d65..d1981f19a 100644 --- a/ui/src/app/metadata-provider/reducer/index.ts +++ b/ui/src/app/metadata-provider/reducer/index.ts @@ -26,6 +26,7 @@ export const getCopyFromState = createSelector(getProviderState, getCopyFromStat export const getCopy = createSelector(getCopyFromState, fromCopy.getCopy); export const getSaving = createSelector(getCopyFromState, fromCopy.getSaving); export const getAttributes = createSelector(getCopyFromState, fromCopy.getCopyAttributes); +export const getSectionsToCopy = createSelector(getCopyFromState, fromCopy.getCopySections); export const getSearchFromState = createSelector(getProviderState, getSearchFromStateFn); export const getSearchResults = createSelector(getSearchFromState, fromSearch.getMatches);