From 4b0f3f669e2c7c50bdfbea2c9eb1c5474dccb955 Mon Sep 17 00:00:00 2001 From: Ryan Mathis Date: Tue, 14 Aug 2018 14:05:57 +0000 Subject: [PATCH] Merged in feature/SHIBUI-707 (pull request #154) * SHIBUI-707 Implemented provider re-ordering Approved-by: Shibui Jenkins Approved-by: Ryan Mathis --- .../preview-dialog.component.spec.ts | 46 +++++++++ .../metadata/domain/model/metadata-order.ts | 3 + .../domain/service/provider.service.ts | 10 ++ .../component/provider-item.component.html | 6 +- .../component/provider-item.component.ts | 6 ++ .../dashboard-providers-list.component.html | 9 +- .../dashboard-providers-list.component.ts | 28 ++++-- .../provider/action/collection.action.ts | 72 +++++++++++++- .../provider/effect/collection.effect.ts | 90 ++++++++++++++++- .../reducer/collection.reducer.spec.ts | 9 +- .../provider/reducer/collection.reducer.ts | 19 ++-- .../provider/reducer/entity.reducer.spec.ts | 21 +++- .../metadata/provider/reducer/index.spec.ts | 96 +++++++++++++++++++ ui/src/app/metadata/provider/reducer/index.ts | 12 +++ .../shared/switch/switch.component.spec.ts | 15 +++ 15 files changed, 410 insertions(+), 32 deletions(-) create mode 100644 ui/src/app/metadata/domain/component/preview-dialog.component.spec.ts create mode 100644 ui/src/app/metadata/domain/model/metadata-order.ts create mode 100644 ui/src/app/metadata/provider/reducer/index.spec.ts diff --git a/ui/src/app/metadata/domain/component/preview-dialog.component.spec.ts b/ui/src/app/metadata/domain/component/preview-dialog.component.spec.ts new file mode 100644 index 000000000..d08b873ba --- /dev/null +++ b/ui/src/app/metadata/domain/component/preview-dialog.component.spec.ts @@ -0,0 +1,46 @@ +import { TestBed, ComponentFixture } from '@angular/core/testing'; +import { ReactiveFormsModule } from '@angular/forms'; +import { NoopAnimationsModule } from '@angular/platform-browser/animations'; +import { ViewChild, Component } from '@angular/core'; +import { Observable, of } from 'rxjs'; +import { PreviewDialogComponent } from './preview-dialog.component'; +import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; +import { NgbActiveModalStub } from '../../../../testing/modal.stub'; + +@Component({ + template: `` +}) +class TestHostComponent { + @ViewChild(PreviewDialogComponent) + public formUnderTest: PreviewDialogComponent; +} + + +describe('Advanced Info Form Component', () => { + let fixture: ComponentFixture; + let instance: TestHostComponent; + + beforeEach(() => { + TestBed.configureTestingModule({ + providers: [ + { provide: NgbActiveModal, useClass: NgbActiveModalStub } + ], + imports: [ + NoopAnimationsModule, + ReactiveFormsModule + ], + declarations: [ + PreviewDialogComponent, + TestHostComponent + ], + }); + + fixture = TestBed.createComponent(TestHostComponent); + instance = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should compile', () => { + expect(fixture).toBeDefined(); + }); +}); diff --git a/ui/src/app/metadata/domain/model/metadata-order.ts b/ui/src/app/metadata/domain/model/metadata-order.ts new file mode 100644 index 000000000..b365af3b0 --- /dev/null +++ b/ui/src/app/metadata/domain/model/metadata-order.ts @@ -0,0 +1,3 @@ +export interface ProviderOrder { + resourceIds: string[]; +} diff --git a/ui/src/app/metadata/domain/service/provider.service.ts b/ui/src/app/metadata/domain/service/provider.service.ts index 39258be42..3d83d3c55 100644 --- a/ui/src/app/metadata/domain/service/provider.service.ts +++ b/ui/src/app/metadata/domain/service/provider.service.ts @@ -4,11 +4,13 @@ import { Observable } from 'rxjs'; import { MetadataProvider } from '../../domain/model'; import { FileBackedHttpMetadataProvider } from '../model/providers'; +import { ProviderOrder } from '../model/metadata-order'; @Injectable() export class MetadataProviderService { readonly endpoint = '/MetadataResolvers'; + readonly order = '/MetadataResolversPositionOrder'; readonly base = '/api'; constructor( @@ -29,4 +31,12 @@ export class MetadataProviderService { save(provider: MetadataProvider): Observable { return this.http.post(`${this.base}${this.endpoint}`, provider); } + + getOrder(): Observable { + return this.http.get(`${this.base}${this.order}`); + } + + setOrder(order: ProviderOrder): Observable { + return this.http.post(`${this.base}${this.order}`, order); + } } diff --git a/ui/src/app/metadata/manager/component/provider-item.component.html b/ui/src/app/metadata/manager/component/provider-item.component.html index f8441c696..1ca8f575b 100644 --- a/ui/src/app/metadata/manager/component/provider-item.component.html +++ b/ui/src/app/metadata/manager/component/provider-item.component.html @@ -2,11 +2,11 @@
-

1

- -
diff --git a/ui/src/app/metadata/manager/component/provider-item.component.ts b/ui/src/app/metadata/manager/component/provider-item.component.ts index b8f676f40..ad8fa572b 100644 --- a/ui/src/app/metadata/manager/component/provider-item.component.ts +++ b/ui/src/app/metadata/manager/component/provider-item.component.ts @@ -12,6 +12,12 @@ import { EntityItemComponent } from './entity-item.component'; export class ProviderItemComponent extends EntityItemComponent { @Input() provider: MetadataProvider; + @Input() index: number; + @Input() first: boolean; + @Input() last: boolean; @Output() viewFilters: EventEmitter = new EventEmitter(); + + @Output() changeOrderUp: EventEmitter = new EventEmitter(); + @Output() changeOrderDown: EventEmitter = new EventEmitter(); } diff --git a/ui/src/app/metadata/manager/container/dashboard-providers-list.component.html b/ui/src/app/metadata/manager/container/dashboard-providers-list.component.html index 7d2eab50a..467538039 100644 --- a/ui/src/app/metadata/manager/container/dashboard-providers-list.component.html +++ b/ui/src/app/metadata/manager/container/dashboard-providers-list.component.html @@ -9,14 +9,19 @@
    -
  • + (toggle)="toggleEntity(provider)" + (changeOrderUp)="updateOrderUp($event)" + (changeOrderDown)="updateOrderDown($event)">
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 bc2e609c4..1815d4ccf 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 @@ -1,20 +1,21 @@ -import { Component } from '@angular/core'; +import { Component, OnInit } from '@angular/core'; import { Router } from '@angular/router'; import { MetadataProvider } from '../../domain/model'; import { Observable } from '../../../../../node_modules/rxjs'; import { Store } from '@ngrx/store'; -import { ProviderState, getAllProviders } from '../../provider/reducer'; -import * as fromDashboard from '../reducer'; +import { ProviderState, getOrderedProviders } from '../../provider/reducer'; +import { getOpenProviders } from '../reducer'; import { ToggleEntityDisplay } from '../action/manager.action'; import { map } from 'rxjs/operators'; +import { ChangeOrderUp, ChangeOrderDown } from '../../provider/action/collection.action'; @Component({ selector: 'dashboard-providers-list', templateUrl: './dashboard-providers-list.component.html' }) -export class DashboardProvidersListComponent { +export class DashboardProvidersListComponent implements OnInit { providers$: Observable; providersOpen$: Observable<{ [key: string]: boolean }>; @@ -22,11 +23,12 @@ export class DashboardProvidersListComponent { constructor( private store: Store, private router: Router - ) { - this.providers$ = this.store.select(getAllProviders).pipe( - map(providers => providers.filter(p => p['@type'] !== 'BaseMetadataResolver')) - ); - this.providersOpen$ = store.select(fromDashboard.getOpenProviders); + ) { } + + 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 { @@ -44,4 +46,12 @@ export class DashboardProvidersListComponent { toggleEntity(provider: MetadataProvider): void { this.store.dispatch(new ToggleEntityDisplay(provider.resourceId)); } + + updateOrderUp(provider: MetadataProvider): void { + this.store.dispatch(new ChangeOrderUp(provider.resourceId)); + } + + updateOrderDown(provider: MetadataProvider): void { + this.store.dispatch(new ChangeOrderDown(provider.resourceId)); + } } diff --git a/ui/src/app/metadata/provider/action/collection.action.ts b/ui/src/app/metadata/provider/action/collection.action.ts index 6746ffad5..637c58115 100644 --- a/ui/src/app/metadata/provider/action/collection.action.ts +++ b/ui/src/app/metadata/provider/action/collection.action.ts @@ -1,6 +1,7 @@ import { Action } from '@ngrx/store'; import { MetadataProvider } from '../../domain/model/metadata-provider'; import { Update } from '@ngrx/entity'; +import { ProviderOrder } from '../../domain/model/metadata-order'; export enum ProviderCollectionActionTypes { UPDATE_PROVIDER_REQUEST = '[Metadata Provider] Update Request', @@ -21,7 +22,18 @@ export enum ProviderCollectionActionTypes { REMOVE_PROVIDER_REQUEST = '[Metadata Provider Collection] Remove Provider Request', REMOVE_PROVIDER_SUCCESS = '[Metadata Provider Collection] Remove Provider Success', - REMOVE_PROVIDER_FAIL = '[Metadata Provider Collection] Remove Provider Fail' + REMOVE_PROVIDER_FAIL = '[Metadata Provider Collection] Remove Provider Fail', + + SET_ORDER_PROVIDER_REQUEST = '[Metadata Provider Collection] Set Order Provider Request', + SET_ORDER_PROVIDER_SUCCESS = '[Metadata Provider Collection] Set Order Remove Provider Success', + SET_ORDER_PROVIDER_FAIL = '[Metadata Provider Collection] Set Order Remove Provider Fail', + + GET_ORDER_PROVIDER_REQUEST = '[Metadata Provider Collection] Get Order Remove Provider Request', + GET_ORDER_PROVIDER_SUCCESS = '[Metadata Provider Collection] Get Order Remove Provider Success', + GET_ORDER_PROVIDER_FAIL = '[Metadata Provider Collection] Get Order Remove Provider Fail', + + CHANGE_PROVIDER_ORDER_UP = '[Metadata Provider Collection] Change Order Up', + CHANGE_PROVIDER_ORDER_DOWN = '[Metadata Provider Collection] Change Order Down', } export class LoadProviderRequest implements Action { @@ -114,6 +126,54 @@ export class RemoveProviderFail implements Action { constructor(public payload: MetadataProvider) { } } +export class SetOrderProviderRequest implements Action { + readonly type = ProviderCollectionActionTypes.SET_ORDER_PROVIDER_REQUEST; + + constructor(public payload: ProviderOrder) { } +} + +export class SetOrderProviderSuccess implements Action { + readonly type = ProviderCollectionActionTypes.SET_ORDER_PROVIDER_SUCCESS; + + constructor() { } +} + +export class SetOrderProviderFail implements Action { + readonly type = ProviderCollectionActionTypes.SET_ORDER_PROVIDER_FAIL; + + constructor(public payload: Error) { } +} + +export class GetOrderProviderRequest implements Action { + readonly type = ProviderCollectionActionTypes.GET_ORDER_PROVIDER_REQUEST; + + constructor() { } +} + +export class GetOrderProviderSuccess implements Action { + readonly type = ProviderCollectionActionTypes.GET_ORDER_PROVIDER_SUCCESS; + + constructor(public payload: ProviderOrder) { } +} + +export class GetOrderProviderFail implements Action { + readonly type = ProviderCollectionActionTypes.GET_ORDER_PROVIDER_FAIL; + + constructor(public payload: Error) { } +} + +export class ChangeOrderUp implements Action { + readonly type = ProviderCollectionActionTypes.CHANGE_PROVIDER_ORDER_UP; + + constructor(public payload: string) { } +} + +export class ChangeOrderDown implements Action { + readonly type = ProviderCollectionActionTypes.CHANGE_PROVIDER_ORDER_DOWN; + + constructor(public payload: string) { } +} + export type ProviderCollectionActionsUnion = | LoadProviderRequest | LoadProviderSuccess @@ -129,4 +189,12 @@ export type ProviderCollectionActionsUnion = | RemoveProviderFail | UpdateProviderRequest | UpdateProviderSuccess - | UpdateProviderFail; + | UpdateProviderFail + | SetOrderProviderRequest + | SetOrderProviderSuccess + | SetOrderProviderFail + | GetOrderProviderRequest + | GetOrderProviderSuccess + | GetOrderProviderFail + | ChangeOrderUp + | ChangeOrderDown; diff --git a/ui/src/app/metadata/provider/effect/collection.effect.ts b/ui/src/app/metadata/provider/effect/collection.effect.ts index fbf4a6c1e..55528b395 100644 --- a/ui/src/app/metadata/provider/effect/collection.effect.ts +++ b/ui/src/app/metadata/provider/effect/collection.effect.ts @@ -19,7 +19,15 @@ import { SelectProviderError, UpdateProviderRequest, UpdateProviderSuccess, - UpdateProviderFail + UpdateProviderFail, + GetOrderProviderRequest, + GetOrderProviderSuccess, + GetOrderProviderFail, + SetOrderProviderRequest, + SetOrderProviderSuccess, + SetOrderProviderFail, + ChangeOrderUp, + ChangeOrderDown } from '../action/collection.action'; import { MetadataProviderService } from '../../domain/service/provider.service'; import * as fromProvider from '../reducer'; @@ -118,6 +126,86 @@ export class CollectionEffects { map(provider => new LoadProviderRequest()) ); + @Effect() + getOrderWithLoad$ = this.actions$.pipe( + ofType(ProviderCollectionActionTypes.LOAD_PROVIDER_SUCCESS), + map(() => new GetOrderProviderRequest()) + ); + + @Effect() + getProviderOrder$ = this.actions$.pipe( + ofType(ProviderCollectionActionTypes.GET_ORDER_PROVIDER_REQUEST), + switchMap(() => + this.providerService.getOrder().pipe( + map(order => new GetOrderProviderSuccess(order)), + catchError(err => of(new GetOrderProviderFail(err))) + ) + ) + ); + + @Effect() + reloadProviderOrderAfterChange$ = this.actions$.pipe( + ofType(ProviderCollectionActionTypes.SET_ORDER_PROVIDER_SUCCESS), + map(() => new GetOrderProviderRequest()) + ); + + @Effect() + setProviderOrder$ = this.actions$.pipe( + ofType(ProviderCollectionActionTypes.SET_ORDER_PROVIDER_REQUEST), + map(action => action.payload), + switchMap(order => + this.providerService.setOrder(order).pipe( + map(() => new SetOrderProviderSuccess()), + catchError(err => of(new SetOrderProviderFail(err))) + ) + ) + ); + + @Effect() + changeOrderUp$ = this.actions$.pipe( + ofType(ProviderCollectionActionTypes.CHANGE_PROVIDER_ORDER_UP), + map(action => action.payload), + withLatestFrom(this.store.select(fromProvider.getProviderOrder)), + map(([id, orderSet]) => { + const order = orderSet.resourceIds; + const index = order.indexOf(id); + if (index > 0) { + const newOrder = this.array_move(order, index, index - 1); + return new SetOrderProviderRequest({ resourceIds: newOrder }); + } else { + return new SetOrderProviderFail(new Error(`could not change order: ${ id }`)); + } + }) + ); + + @Effect() + changeOrderDown$ = this.actions$.pipe( + ofType(ProviderCollectionActionTypes.CHANGE_PROVIDER_ORDER_DOWN), + map(action => action.payload), + withLatestFrom(this.store.select(fromProvider.getProviderOrder)), + map(([id, orderSet]) => { + const order = orderSet.resourceIds; + const index = order.indexOf(id); + if (index < order.length - 1) { + const newOrder = this.array_move(order, index, index + 1); + return new SetOrderProviderRequest({ resourceIds: newOrder }); + } else { + return new SetOrderProviderFail(new Error(`could not change order: ${id}`)); + } + }) + ); + + array_move(arr, old_index, new_index): any[] { + if (new_index >= arr.length) { + let k = new_index - arr.length + 1; + while (k--) { + arr.push(undefined); + } + } + arr.splice(new_index, 0, arr.splice(old_index, 1)[0]); + return arr; + } + constructor( private actions$: Actions, private router: Router, diff --git a/ui/src/app/metadata/provider/reducer/collection.reducer.spec.ts b/ui/src/app/metadata/provider/reducer/collection.reducer.spec.ts index 3e716c212..5feb8ed5b 100644 --- a/ui/src/app/metadata/provider/reducer/collection.reducer.spec.ts +++ b/ui/src/app/metadata/provider/reducer/collection.reducer.spec.ts @@ -1,4 +1,4 @@ -import { reducer } from './collection.reducer'; +import { reducer, initialState as snapshot } from './collection.reducer'; import * as fromProvider from './collection.reducer'; import { ProviderCollectionActionTypes, @@ -6,13 +6,6 @@ import { UpdateProviderSuccess } from '../action/collection.action'; -const snapshot: fromProvider.CollectionState = { - ids: [], - entities: {}, - selectedProviderId: null, - loaded: false -}; - describe('Provider Collection Reducer', () => { describe('undefined action', () => { it('should return the default state', () => { diff --git a/ui/src/app/metadata/provider/reducer/collection.reducer.ts b/ui/src/app/metadata/provider/reducer/collection.reducer.ts index 7d74cb5af..04dfb0297 100644 --- a/ui/src/app/metadata/provider/reducer/collection.reducer.ts +++ b/ui/src/app/metadata/provider/reducer/collection.reducer.ts @@ -1,24 +1,22 @@ import { EntityState, EntityAdapter, createEntityAdapter } from '@ngrx/entity'; import { ProviderCollectionActionTypes, ProviderCollectionActionsUnion } from '../action/collection.action'; import { MetadataProvider } from '../../domain/model'; +import { ProviderOrder } from '../../domain/model/metadata-order'; export interface CollectionState extends EntityState { selectedProviderId: string | null; loaded: boolean; -} - -export function sortByDate(a: MetadataProvider, b: MetadataProvider): number { - return a.createdDate.localeCompare(b.createdDate); + order: ProviderOrder; } export const adapter: EntityAdapter = createEntityAdapter({ - sortComparer: sortByDate, selectId: (model: MetadataProvider) => model.resourceId }); export const initialState: CollectionState = adapter.getInitialState({ selectedProviderId: null, - loaded: false + loaded: false, + order: { resourceIds: [] } }); export function reducer(state = initialState, action: ProviderCollectionActionsUnion): CollectionState { @@ -42,6 +40,13 @@ export function reducer(state = initialState, action: ProviderCollectionActionsU return adapter.updateOne(action.payload, state); } + case ProviderCollectionActionTypes.GET_ORDER_PROVIDER_SUCCESS: { + return { + ...state, + order: action.payload + }; + } + default: { return state; } @@ -56,3 +61,5 @@ export const { selectAll: selectAllProviders, selectTotal: selectProviderTotal } = adapter.getSelectors(); + +export const getProviderOrder = (state: CollectionState) => state.order; diff --git a/ui/src/app/metadata/provider/reducer/entity.reducer.spec.ts b/ui/src/app/metadata/provider/reducer/entity.reducer.spec.ts index 3079a99cd..a37687766 100644 --- a/ui/src/app/metadata/provider/reducer/entity.reducer.spec.ts +++ b/ui/src/app/metadata/provider/reducer/entity.reducer.spec.ts @@ -1,5 +1,6 @@ -import { reducer, initialState as snapshot } from './entity.reducer'; +import { reducer, initialState as snapshot, isEntitySaved } from './entity.reducer'; import { EntityActionTypes, ClearProvider } from '../action/entity.action'; +import { MetadataProvider } from '../../domain/model'; describe('Provider Editor Reducer', () => { describe('undefined action', () => { @@ -15,4 +16,22 @@ describe('Provider Editor Reducer', () => { expect(reducer(snapshot, new ClearProvider())).toEqual(snapshot); }); }); + + describe(`isEntitySaved method`, () => { + it('should return false if there are changes', () => { + expect(isEntitySaved({ + ...snapshot, + changes: { + name: 'bar' + } + })).toBe(false); + }); + + it('should return true if there are no changes', () => { + expect(isEntitySaved({ + ...snapshot, + changes: {} + })).toBe(true); + }); + }); }); diff --git a/ui/src/app/metadata/provider/reducer/index.spec.ts b/ui/src/app/metadata/provider/reducer/index.spec.ts new file mode 100644 index 000000000..f595dea38 --- /dev/null +++ b/ui/src/app/metadata/provider/reducer/index.spec.ts @@ -0,0 +1,96 @@ +import * as fromProvider from './'; +import { MetadataProvider } from '../../domain/model'; + +describe(`provider reducer/selector functions`, () => { + + describe('getSchemaParseFn', () => { + const schema = { + properties: { + foo: { + type: 'string' + } + } + }; + const schema2 = { + properties: { + foo: { + type: 'object', + properties: { + bar: { + type: 'string' + } + } + } + } + }; + it('should lock all properties', () => { + expect(fromProvider.getSchemaParseFn(schema, true)).toEqual({ + ...schema, + properties: { + ...schema.properties, + foo: { + ...schema.properties.foo, + readOnly: true + } + } + }); + }); + + it('should unlock all properties', () => { + expect(fromProvider.getSchemaParseFn(schema, false)).toEqual({ + ...schema, + properties: { + ...schema.properties, + foo: { + type: 'string', + readOnly: false + } + } + }); + }); + + it('should lock child properties properties', () => { + expect(fromProvider.getSchemaParseFn(schema2, true)).toEqual({ + ...schema, + properties: { + ...schema2.properties, + foo: { + ...schema2.properties.foo, + readOnly: true, + properties: { + bar: { + ...schema2.properties.foo.properties.bar, + readOnly: true + } + } + } + } + }); + }); + }); + + describe('getSchemaLockedFn', () => { + it('should return true if the step is locked', () => { + expect(fromProvider.getSchemaLockedFn({ locked: true }, false)).toEqual(false); + }); + }); + + describe('mergeProviderOrderFn', () => { + const providers = [ + { resourceId: 'foo', name: 'foo', '@type': 'foo', enabled: true, xmlId: 'id', sortKey: 1, metadataFilters: [] }, + { resourceId: 'bar', name: 'bar', '@type': 'bar', enabled: false, xmlId: 'id2', sortKey: 2, metadataFilters: [] }, + { resourceId: 'baz', name: 'baz', '@type': 'baz', enabled: false, xmlId: 'id3', sortKey: 3, metadataFilters: [] } + ]; + it('1 should sort the list accordingly', () => { + let order = {resourceIds: ['bar', 'foo', 'baz']}, + ordered = fromProvider.mergeProviderOrderFn([...providers], order); + expect(ordered.indexOf(providers[0])).toBe(1); + }); + + it('2 should sort the list accordingly', () => { + let order = { resourceIds: ['foo', 'bar', 'baz'] }, + ordered = fromProvider.mergeProviderOrderFn(providers, order); + expect(ordered.indexOf(providers[0])).toBe(0); + }); + }); +}); diff --git a/ui/src/app/metadata/provider/reducer/index.ts b/ui/src/app/metadata/provider/reducer/index.ts index d56ba8c0a..1fefd6406 100644 --- a/ui/src/app/metadata/provider/reducer/index.ts +++ b/ui/src/app/metadata/provider/reducer/index.ts @@ -9,6 +9,7 @@ import * as fromWizard from '../../../wizard/reducer'; import { MetadataProvider } from '../../domain/model'; import { WizardStep } from '../../../wizard/model'; +import { ProviderOrder } from '../../domain/model/metadata-order'; export interface ProviderState { editor: fromEditor.EditorState; @@ -87,6 +88,7 @@ export const getUpdatedEntity = createSelector(getEntityState, fromEntity.getUpd /* * Select pieces of Provider Collection */ +export const getProviderOrder = createSelector(getCollectionState, fromCollection.getProviderOrder); export const getAllProviders = createSelector(getCollectionState, fromCollection.selectAllProviders); export const getProviderEntities = createSelector(getCollectionState, fromCollection.selectProviderEntities); export const getSelectedProviderId = createSelector(getCollectionState, fromCollection.getSelectedProviderId); @@ -100,3 +102,13 @@ export const getProviderFilters = createSelector(getSelectedProvider, provider = export const getProviderXmlIds = createSelector(getAllProviders, (providers: MetadataProvider[]) => providers.map(p => p.xmlId)); +export const mergeProviderOrderFn = (providers: MetadataProvider[], order: ProviderOrder): MetadataProvider[] => { + return [...providers.sort( + (a: MetadataProvider, b: MetadataProvider) => { + const aIndex = order.resourceIds.indexOf(a.resourceId); + const bIndex = order.resourceIds.indexOf(b.resourceId); + return aIndex > bIndex ? 1 : bIndex > aIndex ? -1 : 0; + } + )]; +}; +export const getOrderedProviders = createSelector(getAllProviders, getProviderOrder, mergeProviderOrderFn); diff --git a/ui/src/app/shared/switch/switch.component.spec.ts b/ui/src/app/shared/switch/switch.component.spec.ts index 144dd8b71..16933e729 100644 --- a/ui/src/app/shared/switch/switch.component.spec.ts +++ b/ui/src/app/shared/switch/switch.component.spec.ts @@ -20,6 +20,7 @@ class TestHostComponent { describe('Toggle Switch Component', () => { let fixture: ComponentFixture; let instance: TestHostComponent; + let cmp: ToggleSwitchComponent; beforeEach(() => { TestBed.configureTestingModule({ @@ -37,10 +38,24 @@ describe('Toggle Switch Component', () => { fixture = TestBed.createComponent(TestHostComponent); instance = fixture.componentInstance; + cmp = instance.instanceUnderTest; fixture.detectChanges(); }); it('should compile', () => { expect(fixture).toBeDefined(); }); + + describe('value getter', () => { + it('should return the checked value', () => { + expect(cmp.value).toBe(false); + }); + }); + + describe('setDisabledState', () => { + it('should set the disabled property', () => { + cmp.setDisabledState(true); + expect(cmp.disabled).toBe(true); + }) + }); });