From 1166ba4edf048ef68cd298531e942e6407697d2e Mon Sep 17 00:00:00 2001 From: Ryan Mathis Date: Thu, 26 Sep 2019 13:02:36 -0700 Subject: [PATCH 1/3] SHIBUI-1437 Integrated config component to replace summary --- .../configuration/configuration.module.ts | 7 +- .../metadata/configuration/reducer/index.ts | 83 +------------- .../configuration/reducer/utilities.ts | 84 ++++++++++++++ .../service/configuration.service.ts | 2 +- .../component/wizard-summary.component.html | 13 --- .../wizard-summary.component.spec.ts | 103 ------------------ .../component/wizard-summary.component.ts | 81 -------------- ui/src/app/metadata/domain/domain.module.ts | 2 - .../container/provider-wizard.component.html | 6 +- .../container/resolver-wizard.component.html | 10 +- .../container/resolver-wizard.component.ts | 18 +-- ui/src/app/metadata/resolver/reducer/index.ts | 9 ++ .../app/metadata/resolver/resolver.module.ts | 4 +- 13 files changed, 112 insertions(+), 310 deletions(-) create mode 100644 ui/src/app/metadata/configuration/reducer/utilities.ts delete mode 100644 ui/src/app/metadata/domain/component/wizard-summary.component.html delete mode 100644 ui/src/app/metadata/domain/component/wizard-summary.component.spec.ts delete mode 100644 ui/src/app/metadata/domain/component/wizard-summary.component.ts diff --git a/ui/src/app/metadata/configuration/configuration.module.ts b/ui/src/app/metadata/configuration/configuration.module.ts index 338c39ccb..6430886b8 100644 --- a/ui/src/app/metadata/configuration/configuration.module.ts +++ b/ui/src/app/metadata/configuration/configuration.module.ts @@ -84,7 +84,9 @@ import { FilterCompareVersionEffects } from './effect/filter.effect'; WizardModule, FormModule ], - exports: [], + exports: [ + MetadataConfigurationComponent + ], providers: [ DatePipe, IndexResolver @@ -114,7 +116,8 @@ export class MetadataConfigurationModule { RestoreEffects, FilterCompareVersionEffects, VersionEffects - ]) + ] + ) ], providers: [] }) diff --git a/ui/src/app/metadata/configuration/reducer/index.ts b/ui/src/app/metadata/configuration/reducer/index.ts index 13daf9b34..3b08a9367 100644 --- a/ui/src/app/metadata/configuration/reducer/index.ts +++ b/ui/src/app/metadata/configuration/reducer/index.ts @@ -10,6 +10,7 @@ import * as fromFilter from './filter.reducer'; import { WizardStep } from '../../../wizard/model'; import * as utils from '../../domain/utility/configuration'; +import { getConfigurationSectionsFn, assignValueToProperties } from './utilities'; import { getSplitSchema, getModel } from '../../../wizard/reducer'; import { getInCollectionFn } from '../../domain/domain.util'; import { MetadataConfiguration } from '../model/metadata-configuration'; @@ -58,88 +59,6 @@ export const getConfigurationDefinition = createSelector(getConfigurationState, export const getConfigurationSchema = createSelector(getConfigurationState, fromConfiguration.getSchema); export const getConfigurationXml = createSelector(getConfigurationState, fromConfiguration.getXml); -export const assignValueToProperties = (models, properties, definition: any): any[] => { - return properties.map(prop => { - const differences = models.some((model, index, array) => { - if (!array) { - return false; - } - return JSON.stringify(model[prop.id]) !== JSON.stringify(array[0][prop.id]); - }); - - const widget = prop.type === 'array' && prop.widget && prop.widget.data ? ({ - ...prop.widget, - data: prop.widget.data.map(item => ({ - ...item, - differences: models - .map((model) => { - const value = model[prop.id]; - return value ? value.indexOf(item.key) > -1 : false; - }) - .reduce((current, val) => current !== val ? true : false, false) - })) - }) : null; - - switch (prop.type) { - case 'object': - return { - ...prop, - differences, - properties: assignValueToProperties( - models.map(model => definition.formatter(model)[prop.id] || {}), - prop.properties, - definition - ) - }; - default: - return { - ...prop, - differences, - value: models.map(model => { - return model[prop.id]; - }), - widget - }; - } - }); -}; - -export const getConfigurationSectionsFn = (models, definition, schema): MetadataConfiguration => { - return !definition || !schema || !models ? null : - ({ - dates: models.map(m => m ? m.modifiedDate : null), - sections: definition.steps - .filter(step => step.id !== 'summary') - .map( - (step: WizardStep, num: number) => { - return ({ - id: step.id, - pageNumber: num + 1, - index: step.index, - label: step.label, - properties: utils.getStepProperties( - getSplitSchema(schema, step), - definition.formatter({}), - schema.definitions || {} - ) - }); - } - ) - .map((section: any) => { - return { - ...section, - properties: assignValueToProperties(models, section.properties, definition) - }; - }) - .map((section: any) => ({ - ...section, - differences: section.properties.some(prop => prop.differences) - })) - }); - }; - - - export const getConfigurationModelEnabledFn = (config: Metadata) => config ? ('serviceEnabled' in config) ? config.serviceEnabled : config.enabled : false; diff --git a/ui/src/app/metadata/configuration/reducer/utilities.ts b/ui/src/app/metadata/configuration/reducer/utilities.ts new file mode 100644 index 000000000..16668a027 --- /dev/null +++ b/ui/src/app/metadata/configuration/reducer/utilities.ts @@ -0,0 +1,84 @@ +import { MetadataConfiguration } from '../model/metadata-configuration'; +import { WizardStep } from '../../../wizard/model'; +import * as utils from '../../domain/utility/configuration'; +import { getSplitSchema } from '../../../wizard/reducer'; + +export const getConfigurationSectionsFn = (models, definition, schema): MetadataConfiguration => { + return !definition || !schema || !models ? null : + ({ + dates: models.map(m => m ? m.modifiedDate : null), + sections: definition.steps + .filter(step => step.id !== 'summary') + .map( + (step: WizardStep, num: number) => { + return ({ + id: step.id, + pageNumber: num + 1, + index: step.index, + label: step.label, + properties: utils.getStepProperties( + getSplitSchema(schema, step), + definition.formatter({}), + schema.definitions || {} + ) + }); + } + ) + .map((section: any) => { + return { + ...section, + properties: assignValueToProperties(models, section.properties, definition) + }; + }) + .map((section: any) => ({ + ...section, + differences: section.properties.some(prop => prop.differences) + })) + }); +}; + +export const assignValueToProperties = (models, properties, definition: any): any[] => { + return properties.map(prop => { + const differences = models.some((model, index, array) => { + if (!array) { + return false; + } + return JSON.stringify(model[prop.id]) !== JSON.stringify(array[0][prop.id]); + }); + + const widget = prop.type === 'array' && prop.widget && prop.widget.data ? ({ + ...prop.widget, + data: prop.widget.data.map(item => ({ + ...item, + differences: models + .map((model) => { + const value = model[prop.id]; + return value ? value.indexOf(item.key) > -1 : false; + }) + .reduce((current, val) => current !== val ? true : false, false) + })) + }) : null; + + switch (prop.type) { + case 'object': + return { + ...prop, + differences, + properties: assignValueToProperties( + models.map(model => definition.formatter(model)[prop.id] || {}), + prop.properties, + definition + ) + }; + default: + return { + ...prop, + differences, + value: models.map(model => { + return model[prop.id]; + }), + widget + }; + } + }); +}; diff --git a/ui/src/app/metadata/configuration/service/configuration.service.ts b/ui/src/app/metadata/configuration/service/configuration.service.ts index ef03fc2e5..df8a3dba0 100644 --- a/ui/src/app/metadata/configuration/service/configuration.service.ts +++ b/ui/src/app/metadata/configuration/service/configuration.service.ts @@ -10,7 +10,7 @@ import { TYPES } from '../configuration.values'; import { ResolverService } from '../../domain/service/resolver.service'; import { MetadataProviderService } from '../../domain/service/provider.service'; import { MetadataFilterEditorTypes } from '../../filter/model'; -import { getConfigurationSectionsFn } from '../reducer'; +import { getConfigurationSectionsFn } from '../reducer/utilities'; @Injectable() export class MetadataConfigurationService { diff --git a/ui/src/app/metadata/domain/component/wizard-summary.component.html b/ui/src/app/metadata/domain/component/wizard-summary.component.html deleted file mode 100644 index e7ea5dbf6..000000000 --- a/ui/src/app/metadata/domain/component/wizard-summary.component.html +++ /dev/null @@ -1,13 +0,0 @@ -
-
-
- - - - -
-
-
diff --git a/ui/src/app/metadata/domain/component/wizard-summary.component.spec.ts b/ui/src/app/metadata/domain/component/wizard-summary.component.spec.ts deleted file mode 100644 index ecd51b1b9..000000000 --- a/ui/src/app/metadata/domain/component/wizard-summary.component.spec.ts +++ /dev/null @@ -1,103 +0,0 @@ -import { Component, ViewChild } from '@angular/core'; -import { TestBed, async, ComponentFixture } from '@angular/core/testing'; -import { RouterTestingModule } from '@angular/router/testing'; - -import { NgbDropdownModule, NgbPopoverModule } from '@ng-bootstrap/ng-bootstrap'; - -import { WizardSummaryComponent } from './wizard-summary.component'; -import { SchemaFormModule, WidgetRegistry, DefaultWidgetRegistry } from 'ngx-schema-form'; -import { Wizard } from '../../../wizard/model'; -import { MetadataProvider } from '../../domain/model'; -import { SummaryPropertyComponent } from './summary-property.component'; -import { SCHEMA } from '../../../../testing/form-schema.stub'; -import { MockI18nModule } from '../../../../testing/i18n.stub'; -import { MetadataProviderWizard } from '../../provider/model'; -import { AttributesService } from '../service/attributes.service'; -import { MockAttributeService } from '../../../../testing/attributes.stub'; - -@Component({ - template: ` - - ` -}) -class TestHostComponent { - @ViewChild(WizardSummaryComponent) - public componentUnderTest: WizardSummaryComponent; - - private _summary; - - get summary(): { definition: Wizard, schema: { [id: string]: any }, model: any } { - return this._summary; - } - - set summary(summary: { definition: Wizard, schema: { [id: string]: any }, model: any }) { - this._summary = summary; - } -} - -describe('Provider Wizard Summary Component', () => { - - let fixture: ComponentFixture; - let instance: TestHostComponent; - let app: WizardSummaryComponent; - - beforeEach(async(() => { - TestBed.configureTestingModule({ - imports: [ - NgbDropdownModule, - NgbPopoverModule, - RouterTestingModule, - SchemaFormModule.forRoot(), - MockI18nModule - ], - declarations: [ - WizardSummaryComponent, - SummaryPropertyComponent, - TestHostComponent - ], - providers: [ - { provide: WidgetRegistry, useClass: DefaultWidgetRegistry }, - { provide: AttributesService, useClass: MockAttributeService } - ] - }).compileComponents(); - - fixture = TestBed.createComponent(TestHostComponent); - instance = fixture.componentInstance; - app = instance.componentUnderTest; - fixture.detectChanges(); - })); - - it('should instantiate the component', async(() => { - expect(app).toBeTruthy(); - })); - - describe('gotoPage function', () => { - it('should emit an empty string if page is null', () => { - spyOn(app.onPageSelect, 'emit'); - app.gotoPage(); - expect(app.onPageSelect.emit).toHaveBeenCalledWith(''); - }); - - it('should emit the provided page', () => { - spyOn(app.onPageSelect, 'emit'); - app.gotoPage('foo'); - expect(app.onPageSelect.emit).toHaveBeenCalledWith('foo'); - }); - }); - - describe('ngOnChanges', () => { - it('should set columns and sections if summary is provided', () => { - instance.summary = { - model: { - name: 'foo', - '@type': 'MetadataProvider' - }, - schema: SCHEMA, - definition: MetadataProviderWizard - }; - fixture.detectChanges(); - expect(app.sections).toBeDefined(); - expect(app.columns).toBeDefined(); - }); - }); -}); diff --git a/ui/src/app/metadata/domain/component/wizard-summary.component.ts b/ui/src/app/metadata/domain/component/wizard-summary.component.ts deleted file mode 100644 index 80f246c83..000000000 --- a/ui/src/app/metadata/domain/component/wizard-summary.component.ts +++ /dev/null @@ -1,81 +0,0 @@ -import { Component, Input, SimpleChanges, OnChanges, Output, EventEmitter } from '@angular/core'; -import merge from 'deepmerge'; - -import { Wizard, WizardStep } from '../../../wizard/model'; -import { MetadataProvider, MetadataResolver } from '../../domain/model'; -import { Property } from '../model/property'; -import { getSplitSchema } from '../../../wizard/reducer'; -import { getStepProperties } from '../utility/configuration'; - -interface Section { - id: string; - index: number; - label: string; - pageNumber: number; - properties: Property[]; -} - -@Component({ - selector: 'wizard-summary', - templateUrl: './wizard-summary.component.html', - styleUrls: [] -}) - -export class WizardSummaryComponent implements OnChanges { - @Input() summary: { definition: Wizard, schema: { [id: string]: any }, model: any }; - - @Output() onPageSelect: EventEmitter = new EventEmitter(); - - sections: Section[]; - columns: Array
[]; - steps: WizardStep[]; - - constructor() {} - - ngOnChanges(changes: SimpleChanges): void { - if (changes.summary && this.summary) { - const schema = this.summary.schema; - const model = this.summary.model; - const def = this.summary.definition; - const steps = def.steps; - - this.sections = steps - .filter(step => step.id !== 'summary') - .map( - (step: WizardStep, num: number) => { - const { id, index, label } = step; - const split = getSplitSchema(schema, step); - const properties = getStepProperties( - split, - def.formatter(model), - schema.definitions || {} - ); - return ({ - id, - pageNumber: num + 1, - index, - label, - properties - }); - } - ); - - this.columns = this.sections.reduce((resultArray, item, index) => { - const chunkIndex = Math.floor(index / Math.round(this.sections.length / 2)); - - if (!resultArray[chunkIndex]) { - resultArray[chunkIndex] = []; - } - - resultArray[chunkIndex].push(item); - - return resultArray; - }, []); - } - } - - gotoPage(page: string = ''): void { - this.onPageSelect.emit(page); - } -} - diff --git a/ui/src/app/metadata/domain/domain.module.ts b/ui/src/app/metadata/domain/domain.module.ts index ffee8cf1d..b109734a6 100644 --- a/ui/src/app/metadata/domain/domain.module.ts +++ b/ui/src/app/metadata/domain/domain.module.ts @@ -16,7 +16,6 @@ import { PreviewDialogComponent } from './component/preview-dialog.component'; import { MetadataFilterService } from './service/filter.service'; import { AttributesService } from './service/attributes.service'; import { I18nModule } from '../../i18n/i18n.module'; -import { WizardSummaryComponent } from './component/wizard-summary.component'; import { SummaryPropertyComponent } from './component/summary-property.component'; import { UnsavedEntityComponent } from './component/unsaved-entity.dialog'; @@ -26,7 +25,6 @@ import { SharedModule } from '../../shared/shared.module'; export const COMPONENTS = [ PreviewDialogComponent, - WizardSummaryComponent, UnsavedEntityComponent, SummaryPropertyComponent, EditorNavComponent diff --git a/ui/src/app/metadata/provider/container/provider-wizard.component.html b/ui/src/app/metadata/provider/container/provider-wizard.component.html index 366bb70d5..58766e536 100644 --- a/ui/src/app/metadata/provider/container/provider-wizard.component.html +++ b/ui/src/app/metadata/provider/container/provider-wizard.component.html @@ -19,11 +19,7 @@ - - +
diff --git a/ui/src/app/metadata/resolver/container/resolver-wizard.component.html b/ui/src/app/metadata/resolver/container/resolver-wizard.component.html index 87100a871..867ac0584 100644 --- a/ui/src/app/metadata/resolver/container/resolver-wizard.component.html +++ b/ui/src/app/metadata/resolver/container/resolver-wizard.component.html @@ -5,8 +5,8 @@ - - + + + diff --git a/ui/src/app/metadata/resolver/container/resolver-wizard.component.ts b/ui/src/app/metadata/resolver/container/resolver-wizard.component.ts index 56848ad5e..7a3bfc781 100644 --- a/ui/src/app/metadata/resolver/container/resolver-wizard.component.ts +++ b/ui/src/app/metadata/resolver/container/resolver-wizard.component.ts @@ -29,6 +29,8 @@ import { LoadSchemaRequest } from '../../../wizard/action/wizard.action'; import { UnsavedEntityComponent } from '../../domain/component/unsaved-entity.dialog'; import { Clear } from '../action/entity.action'; import { DifferentialService } from '../../../core/service/differential.service'; +import { getConfigurationSections } from '../../configuration/reducer'; +import { MetadataConfiguration } from '../../configuration/model/metadata-configuration'; @Component({ selector: 'resolver-wizard-page', @@ -60,7 +62,7 @@ export class ResolverWizardComponent implements OnDestroy, CanComponentDeactivat valid$: Observable; schema$: Observable; - summary$: Observable<{ definition: Wizard, schema: { [id: string]: any }, model: any }>; + summary$: Observable = this.store.select(fromCollections.getResolverConfiguration); constructor( private store: Store, @@ -115,20 +117,6 @@ export class ResolverWizardComponent implements OnDestroy, CanComponentDeactivat combineLatest(this.resolver$, (changes, base) => ({ ...base, ...changes })) ).subscribe(latest => this.latest = latest); - this.summary$ = combine( - this.store.select(fromWizard.getWizardDefinition), - this.store.select(fromWizard.getSchemaObject), - this.store.select(fromResolver.getDraftModelWithChanges) - ).pipe( - map(([definition, schema, model]) => ( - { - definition, - schema: schema || {}, - model - } - )) - ); - this.changes$.pipe(takeUntil(this.ngUnsubscribe)).subscribe(c => this.changes = c); this.resolver$.pipe(takeUntil(this.ngUnsubscribe)).subscribe(r => this.resolver = r); } diff --git a/ui/src/app/metadata/resolver/reducer/index.ts b/ui/src/app/metadata/resolver/reducer/index.ts index a1cc5256d..e25643a25 100644 --- a/ui/src/app/metadata/resolver/reducer/index.ts +++ b/ui/src/app/metadata/resolver/reducer/index.ts @@ -8,6 +8,7 @@ import * as fromCollection from './collection.reducer'; import * as fromWizard from '../../../wizard/reducer'; import { combineAllFn, getEntityIdsFn, getInCollectionFn, doesExistFn } from '../../domain/domain.util'; +import { getConfigurationSectionsFn } from '../../configuration/reducer/utilities'; export interface ResolverState { entity: fromEntity.EntityState; @@ -124,3 +125,11 @@ export const getDraftModelWithChanges = createSelector( }) ); +export const getDraftModelList = createSelector(getDraftModelWithChanges, (model) => [model]); + +export const getResolverConfiguration = createSelector( + getDraftModelList, + fromWizard.getWizardDefinition, + fromWizard.getSchema, + getConfigurationSectionsFn +); diff --git a/ui/src/app/metadata/resolver/resolver.module.ts b/ui/src/app/metadata/resolver/resolver.module.ts index e0cb4bb5b..e303181fc 100644 --- a/ui/src/app/metadata/resolver/resolver.module.ts +++ b/ui/src/app/metadata/resolver/resolver.module.ts @@ -36,6 +36,7 @@ import { MetadataSourceEditor } from '../domain/model/wizards/metadata-source-ed import { FinishFormComponent } from './component/finish-form.component'; import { ProviderFormFragmentComponent } from './component/provider-form-fragment.component'; import { MetadataResolverPageComponent } from './resolver.component'; +import { MetadataConfigurationModule } from '../configuration/configuration.module'; @NgModule({ declarations: [ @@ -67,7 +68,8 @@ import { MetadataResolverPageComponent } from './resolver.component'; WizardModule, FormModule, NgbPopoverModule, - NgbModalModule + NgbModalModule, + MetadataConfigurationModule ], exports: [], providers: [] From 45711c5daf82e21326b5d497e4b432063826d596 Mon Sep 17 00:00:00 2001 From: Ryan Mathis Date: Fri, 27 Sep 2019 11:41:49 -0700 Subject: [PATCH 2/3] SHIBUI-1437 Implemented updated view for summary --- ...ter-configuration-list-item.component.html | 1 - .../metadata-configuration.component.html | 3 +-- .../metadata-configuration.component.ts | 20 +++++++++---------- .../metadata-comparison.component.html | 7 ++----- .../container/metadata-options.component.html | 6 +++++- .../container/metadata-options.component.ts | 10 ++++++++-- .../container/version-options.component.html | 1 - .../metadata/configuration/reducer/index.ts | 6 ++---- .../container/resolver-wizard.component.html | 5 +++-- .../container/resolver-wizard.component.ts | 17 +++++++--------- ui/src/app/metadata/resolver/reducer/index.ts | 2 +- 11 files changed, 39 insertions(+), 39 deletions(-) diff --git a/ui/src/app/metadata/configuration/component/filter-configuration-list-item.component.html b/ui/src/app/metadata/configuration/component/filter-configuration-list-item.component.html index cf1cfe3be..6a447d6f3 100644 --- a/ui/src/app/metadata/configuration/component/filter-configuration-list-item.component.html +++ b/ui/src/app/metadata/configuration/component/filter-configuration-list-item.component.html @@ -35,7 +35,6 @@ {{ section.label | translate }} -
+
- + [configuration]="versions$ | async">

Metadata Filter @@ -41,8 +39,7 @@


+ [configuration]="filterCompare$ | async">

- + +
diff --git a/ui/src/app/metadata/configuration/container/metadata-options.component.ts b/ui/src/app/metadata/configuration/container/metadata-options.component.ts index 8b3d3281f..484d03bc5 100644 --- a/ui/src/app/metadata/configuration/container/metadata-options.component.ts +++ b/ui/src/app/metadata/configuration/container/metadata-options.component.ts @@ -2,7 +2,7 @@ import { Store } from '@ngrx/store'; import { Component, ChangeDetectionStrategy, OnDestroy } from '@angular/core'; import { Observable, Subject } from 'rxjs'; import { NgbModal } from '@ng-bootstrap/ng-bootstrap'; -import { Router } from '@angular/router'; +import { Router, ActivatedRoute } from '@angular/router'; import { ViewportScroller } from '@angular/common'; import { takeUntil, filter } from 'rxjs/operators'; @@ -53,7 +53,9 @@ export class MetadataOptionsComponent implements OnDestroy { constructor( protected store: Store, protected modalService: NgbModal, - protected scroller: ViewportScroller + protected scroller: ViewportScroller, + protected router: Router, + protected activatedRoute: ActivatedRoute ) { this.model$ .pipe( @@ -63,6 +65,10 @@ export class MetadataOptionsComponent implements OnDestroy { .subscribe(p => this.setModel(p)); } + edit(id: string) { + this.router.navigate(['../', 'edit', id], { relativeTo: this.activatedRoute.parent }); + } + setModel(data: Metadata): void { this.id = 'resourceId' in data ? data.resourceId : data.id; this.kind = '@type' in data ? 'provider' : 'resolver'; diff --git a/ui/src/app/metadata/configuration/container/version-options.component.html b/ui/src/app/metadata/configuration/container/version-options.component.html index c4590848f..f18e661bf 100644 --- a/ui/src/app/metadata/configuration/container/version-options.component.html +++ b/ui/src/app/metadata/configuration/container/version-options.component.html @@ -23,7 +23,6 @@

diff --git a/ui/src/app/metadata/configuration/reducer/index.ts b/ui/src/app/metadata/configuration/reducer/index.ts index 4ffb7e081..1053ada29 100644 --- a/ui/src/app/metadata/configuration/reducer/index.ts +++ b/ui/src/app/metadata/configuration/reducer/index.ts @@ -7,13 +7,11 @@ import * as fromCompare from './compare.reducer'; import * as fromVersion from './version.reducer'; import * as fromRestore from './restore.reducer'; import * as fromFilter from './filter.reducer'; -import { WizardStep } from '../../../wizard/model'; import * as utils from '../../domain/utility/configuration'; -import { getConfigurationSectionsFn, assignValueToProperties } from './utilities'; -import { getSplitSchema, getModel } from '../../../wizard/reducer'; +import { getConfigurationSectionsFn } from './utilities'; +import { getModel } from '../../../wizard/reducer'; import { getInCollectionFn } from '../../domain/domain.util'; -import { MetadataConfiguration } from '../model/metadata-configuration'; import { Metadata } from '../../domain/domain.type'; import * as fromResolver from '../../resolver/reducer'; diff --git a/ui/src/app/metadata/resolver/container/resolver-wizard.component.html b/ui/src/app/metadata/resolver/container/resolver-wizard.component.html index 867ac0584..425a84920 100644 --- a/ui/src/app/metadata/resolver/container/resolver-wizard.component.html +++ b/ui/src/app/metadata/resolver/container/resolver-wizard.component.html @@ -5,8 +5,9 @@
- +
- +
diff --git a/ui/src/app/metadata/resolver/container/resolver-wizard.component.ts b/ui/src/app/metadata/resolver/container/resolver-wizard.component.ts index 7a3bfc781..bd7c6e437 100644 --- a/ui/src/app/metadata/resolver/container/resolver-wizard.component.ts +++ b/ui/src/app/metadata/resolver/container/resolver-wizard.component.ts @@ -9,7 +9,7 @@ import { ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router'; -import { Observable, Subject, of, combineLatest as combine } from 'rxjs'; +import { Observable, Subject, of } from 'rxjs'; import { skipWhile, startWith, distinctUntilChanged, map, takeUntil, combineLatest, withLatestFrom } from 'rxjs/operators'; import { Store } from '@ngrx/store'; import { NgbModal } from '@ng-bootstrap/ng-bootstrap'; @@ -28,8 +28,6 @@ import * as fromWizard from '../../../wizard/reducer'; import { LoadSchemaRequest } from '../../../wizard/action/wizard.action'; import { UnsavedEntityComponent } from '../../domain/component/unsaved-entity.dialog'; import { Clear } from '../action/entity.action'; -import { DifferentialService } from '../../../core/service/differential.service'; -import { getConfigurationSections } from '../../configuration/reducer'; import { MetadataConfiguration } from '../../configuration/model/metadata-configuration'; @Component({ @@ -69,7 +67,6 @@ export class ResolverWizardComponent implements OnDestroy, CanComponentDeactivat private route: ActivatedRoute, private router: Router, private modalService: NgbModal, - private diffService: DifferentialService, @Inject(METADATA_SOURCE_WIZARD) private sourceWizard: Wizard ) { this.store @@ -151,16 +148,16 @@ export class ResolverWizardComponent implements OnDestroy, CanComponentDeactivat this.store.dispatch(new SetIndex(page)); } + get blacklist(): string[] { + return ['id', 'resourceId']; + } + hasChanges(changes: MetadataResolver): boolean { - // const updated = this.diffService.updatedDiff(this.resolver, changes); - // const deleted = this.diffService.deletedDiff(this.resolver, changes); - let blacklist = ['id', 'resourceId']; - return Object.keys(changes).filter(key => !(blacklist.indexOf(key) > -1)).length > 0; + return Object.keys(changes).filter(key => !(this.blacklist.indexOf(key) > -1)).length > 0; } isNew(changes: MetadataResolver): boolean { - let blacklist = ['id', 'resourceId']; - return Object.keys(changes).filter(key => !(blacklist.indexOf(key) > -1)).length === 0; + return Object.keys(changes).filter(key => !(this.blacklist.indexOf(key) > -1)).length === 0; } ngOnDestroy(): void { diff --git a/ui/src/app/metadata/resolver/reducer/index.ts b/ui/src/app/metadata/resolver/reducer/index.ts index e25643a25..a22693e4d 100644 --- a/ui/src/app/metadata/resolver/reducer/index.ts +++ b/ui/src/app/metadata/resolver/reducer/index.ts @@ -130,6 +130,6 @@ export const getDraftModelList = createSelector(getDraftModelWithChanges, (model export const getResolverConfiguration = createSelector( getDraftModelList, fromWizard.getWizardDefinition, - fromWizard.getSchema, + fromWizard.getProcessedSchema, getConfigurationSectionsFn ); From 40feb8a1209c12e922341e736a19dadf23562225 Mon Sep 17 00:00:00 2001 From: Ryan Mathis Date: Fri, 27 Sep 2019 14:07:02 -0700 Subject: [PATCH 3/3] Updated unit tests, improved coverage --- .../metadata-configuration.component.spec.ts | 6 +- .../configuration/reducer/index.spec.ts | 118 +---------------- .../metadata/configuration/reducer/index.ts | 24 +--- .../configuration/reducer/utilities.spec.ts | 120 ++++++++++++++++++ .../configuration/reducer/utilities.ts | 21 +++ .../service/configuration.service.spec.ts | 2 +- .../component/wizard-summary.component.html | 14 ++ .../wizard-summary.component.spec.ts | 103 +++++++++++++++ .../component/wizard-summary.component.ts | 80 ++++++++++++ ui/src/app/metadata/domain/domain.module.ts | 2 + .../model/dynamic-http.provider.form.spec.ts | 85 +++++++++++++ .../metadata/provider/model/utilities.spec.ts | 33 +++++ .../app/metadata/provider/model/utilities.ts | 2 - .../resolver-wizard.component.spec.ts | 6 +- ui/src/app/wizard/reducer/index.ts | 2 +- 15 files changed, 471 insertions(+), 147 deletions(-) create mode 100644 ui/src/app/metadata/configuration/reducer/utilities.spec.ts create mode 100644 ui/src/app/metadata/domain/component/wizard-summary.component.html create mode 100644 ui/src/app/metadata/domain/component/wizard-summary.component.spec.ts create mode 100644 ui/src/app/metadata/domain/component/wizard-summary.component.ts create mode 100644 ui/src/app/metadata/provider/model/utilities.spec.ts diff --git a/ui/src/app/metadata/configuration/component/metadata-configuration.component.spec.ts b/ui/src/app/metadata/configuration/component/metadata-configuration.component.spec.ts index c17a469af..3feb146b5 100644 --- a/ui/src/app/metadata/configuration/component/metadata-configuration.component.spec.ts +++ b/ui/src/app/metadata/configuration/component/metadata-configuration.component.spec.ts @@ -66,10 +66,10 @@ describe('Metadata Configuration Component', () => { })); describe('edit method', () => { - it('should call router.navigate', () => { - spyOn(router, 'navigate'); + it('should call onEdit.emit', () => { + spyOn(app.onEdit, 'emit'); app.edit('foo'); - expect(router.navigate).toHaveBeenCalled(); + expect(app.onEdit.emit).toHaveBeenCalled(); }); }); diff --git a/ui/src/app/metadata/configuration/reducer/index.spec.ts b/ui/src/app/metadata/configuration/reducer/index.spec.ts index 8a1aa3cb7..d9dff5a83 100644 --- a/ui/src/app/metadata/configuration/reducer/index.spec.ts +++ b/ui/src/app/metadata/configuration/reducer/index.spec.ts @@ -1,143 +1,31 @@ import { - getConfigurationSectionsFn, getConfigurationModelNameFn, getConfigurationModelEnabledFn, - assignValueToProperties, - getLimitedPropertiesFn, getConfigurationModelTypeFn, getSelectedVersionNumberFn, getSelectedIsCurrentFn } from './index'; -import { SCHEMA as schema } from '../../../../testing/form-schema.stub'; + import { Metadata } from '../../domain/domain.type'; -import { MockMetadataWizard } from '../../../../testing/mockMetadataWizard'; describe('Configuration Reducer', () => { - const model = { - name: 'foo', - serviceEnabled: true, - foo: { - bar: 'bar', - baz: 'baz' - }, - list: [ - 'super', - 'cool' - ] - }; - - const props = [ - { - id: 'name', - items: null, - name: 'label.metadata-provider-name-dashboard-display-only', - properties: [], - type: 'string', - value: null, - widget: { id: 'string', help: 'message.must-be-unique' } - }, - { - id: 'serviceEnabled', - items: null, - name: 'serviceEnabled', - properties: [], - type: 'string', - value: null, - widget: { id: 'select', disabled: true } - }, - { - id: 'foo', - items: null, - name: 'foo', - type: 'object', - properties: [ - { - id: 'bar', - name: 'bar', - type: 'string', - properties: [] - }, - { - id: 'baz', - name: 'baz', - type: 'string', - properties: [] - } - ] - }, - { - id: 'list', - name: 'list', - type: 'array', - items: { - type: 'string' - }, - widget: { - id: 'datalist', - data: [ - { key: 'super', label: 'super' }, - { key: 'cool', label: 'cool' }, - { key: 'notcool', label: 'notcool' } - ] - } - } - ]; - - const definition = MockMetadataWizard; - - describe('getConfigurationSectionsFn', () => { - it('should parse the schema, definition, and model into a MetadataConfiguration', () => { - const config = getConfigurationSectionsFn([model], definition, schema); - expect(config.sections).toBeDefined(); - }); - }); describe('getConfigurationModelNameFn function', () => { it('should return the name attribute', () => { expect(getConfigurationModelNameFn({ serviceProviderName: 'foo' } as Metadata)).toBe('foo'); expect(getConfigurationModelNameFn({ name: 'bar' } as Metadata)).toBe('bar'); - expect(getConfigurationModelNameFn(null)).toBe(false); + expect(getConfigurationModelNameFn(null)).toBe(''); }); }); describe('getConfigurationModelEnabledFn function', () => { - it('should return the name attribute', () => { + it('should return the enabled attribute', () => { expect(getConfigurationModelEnabledFn({ serviceEnabled: true } as Metadata)).toBe(true); expect(getConfigurationModelEnabledFn({ enabled: true } as Metadata)).toBe(true); expect(getConfigurationModelEnabledFn(null)).toBe(false); }); }); - describe('assignValueToProperties function', () => { - it('should assign appropriate values to the given schema properties', () => { - const assigned = assignValueToProperties([model], props, definition); - expect(assigned[0].value).toEqual(['foo']); - expect(assigned[1].value).toEqual([true]); - }); - - it('should assign differences when passed multiple models', () => { - const assigned = assignValueToProperties([model, { - ...model, - name: 'bar', - list: [ - 'super', - 'notcool' - ] - }], props, definition); - expect(assigned[0].differences).toBe(true); - }); - }); - - describe('getLimitedPropertiesFn function', () => { - it('should filter properties without differences', () => { - const assigned = assignValueToProperties([model, { - ...model, - name: 'bar' - }], props, definition); - expect(getLimitedPropertiesFn(assigned).length).toBe(1); - }); - }); - describe('getConfigurationModelTypeFn function ', () => { it('should return provider type if the object has an @type property', () => { const md = { '@type': 'FilebackedHttpMetadataResolver' } as Metadata; diff --git a/ui/src/app/metadata/configuration/reducer/index.ts b/ui/src/app/metadata/configuration/reducer/index.ts index 1053ada29..58e92562f 100644 --- a/ui/src/app/metadata/configuration/reducer/index.ts +++ b/ui/src/app/metadata/configuration/reducer/index.ts @@ -8,15 +8,13 @@ import * as fromVersion from './version.reducer'; import * as fromRestore from './restore.reducer'; import * as fromFilter from './filter.reducer'; -import * as utils from '../../domain/utility/configuration'; -import { getConfigurationSectionsFn } from './utilities'; +import { getConfigurationSectionsFn, getLimitedPropertiesFn } from './utilities'; import { getModel } from '../../../wizard/reducer'; import { getInCollectionFn } from '../../domain/domain.util'; import { Metadata } from '../../domain/domain.type'; import * as fromResolver from '../../resolver/reducer'; import * as fromProvider from '../../provider/reducer'; -import { SectionProperty } from '../model/section'; export interface ConfigurationState { configuration: fromConfiguration.State; @@ -136,26 +134,6 @@ export const getComparisonConfigurationCount = createSelector(getComparisonConfi export const getViewChangedOnly = createSelector(getCompareState, fromCompare.getViewChangedOnly); -export const getLimitedPropertiesFn = (properties: SectionProperty[]) => { - return ([ - ...properties - .filter(p => p.differences) - .map(p => { - const parsed = { ...p }; - if (p.widget && p.widget.data) { - parsed.widget = { - ...p.widget, - data: p.widget.data.filter(item => item.differences) - }; - } - if (p.properties) { - parsed.properties = getLimitedPropertiesFn(p.properties); - } - return parsed; - }) - ]); -}; - export const getLimitedConfigurationsFn = (configurations, limited) => configurations ? ({ ...configurations, sections: limited ? configurations.sections : diff --git a/ui/src/app/metadata/configuration/reducer/utilities.spec.ts b/ui/src/app/metadata/configuration/reducer/utilities.spec.ts new file mode 100644 index 000000000..0d8234bb5 --- /dev/null +++ b/ui/src/app/metadata/configuration/reducer/utilities.spec.ts @@ -0,0 +1,120 @@ +import { + getConfigurationSectionsFn, + getLimitedPropertiesFn, + assignValueToProperties +} from './utilities'; + +import { SCHEMA as schema } from '../../../../testing/form-schema.stub'; +import { MockMetadataWizard } from '../../../../testing/mockMetadataWizard'; + +describe('config reducer utilities', () => { + + const model = { + name: 'foo', + serviceEnabled: true, + foo: { + bar: 'bar', + baz: 'baz' + }, + list: [ + 'super', + 'cool' + ] + }; + + const props = [ + { + id: 'name', + items: null, + name: 'label.metadata-provider-name-dashboard-display-only', + properties: [], + type: 'string', + value: null, + widget: { id: 'string', help: 'message.must-be-unique' } + }, + { + id: 'serviceEnabled', + items: null, + name: 'serviceEnabled', + properties: [], + type: 'string', + value: null, + widget: { id: 'select', disabled: true } + }, + { + id: 'foo', + items: null, + name: 'foo', + type: 'object', + properties: [ + { + id: 'bar', + name: 'bar', + type: 'string', + properties: [] + }, + { + id: 'baz', + name: 'baz', + type: 'string', + properties: [] + } + ] + }, + { + id: 'list', + name: 'list', + type: 'array', + items: { + type: 'string' + }, + widget: { + id: 'datalist', + data: [ + { key: 'super', label: 'super' }, + { key: 'cool', label: 'cool' }, + { key: 'notcool', label: 'notcool' } + ] + } + } + ]; + + const definition = MockMetadataWizard; + + describe('assignValueToProperties function', () => { + it('should assign appropriate values to the given schema properties', () => { + const assigned = assignValueToProperties([model], props, definition); + expect(assigned[0].value).toEqual(['foo']); + expect(assigned[1].value).toEqual([true]); + }); + + it('should assign differences when passed multiple models', () => { + const assigned = assignValueToProperties([model, { + ...model, + name: 'bar', + list: [ + 'super', + 'notcool' + ] + }], props, definition); + expect(assigned[0].differences).toBe(true); + }); + }); + + describe('getLimitedPropertiesFn function', () => { + it('should filter properties without differences', () => { + const assigned = assignValueToProperties([model, { + ...model, + name: 'bar' + }], props, definition); + expect(getLimitedPropertiesFn(assigned).length).toBe(1); + }); + }); + + describe('getConfigurationSectionsFn', () => { + it('should parse the schema, definition, and model into a MetadataConfiguration', () => { + const config = getConfigurationSectionsFn([model], definition, schema); + expect(config.sections).toBeDefined(); + }); + }); +}); diff --git a/ui/src/app/metadata/configuration/reducer/utilities.ts b/ui/src/app/metadata/configuration/reducer/utilities.ts index 16668a027..f2481e99c 100644 --- a/ui/src/app/metadata/configuration/reducer/utilities.ts +++ b/ui/src/app/metadata/configuration/reducer/utilities.ts @@ -2,6 +2,7 @@ import { MetadataConfiguration } from '../model/metadata-configuration'; import { WizardStep } from '../../../wizard/model'; import * as utils from '../../domain/utility/configuration'; import { getSplitSchema } from '../../../wizard/reducer'; +import { SectionProperty } from '../model/section'; export const getConfigurationSectionsFn = (models, definition, schema): MetadataConfiguration => { return !definition || !schema || !models ? null : @@ -82,3 +83,23 @@ export const assignValueToProperties = (models, properties, definition: any): an } }); }; + +export const getLimitedPropertiesFn = (properties: SectionProperty[]) => { + return ([ + ...properties + .filter(p => p.differences) + .map(p => { + const parsed = { ...p }; + if (p.widget && p.widget.data) { + parsed.widget = { + ...p.widget, + data: p.widget.data.filter(item => item.differences) + }; + } + if (p.properties) { + parsed.properties = getLimitedPropertiesFn(p.properties); + } + return parsed; + }) + ]); +}; \ No newline at end of file diff --git a/ui/src/app/metadata/configuration/service/configuration.service.spec.ts b/ui/src/app/metadata/configuration/service/configuration.service.spec.ts index 43fd99c05..e191471a0 100644 --- a/ui/src/app/metadata/configuration/service/configuration.service.spec.ts +++ b/ui/src/app/metadata/configuration/service/configuration.service.spec.ts @@ -9,7 +9,7 @@ import { of } from 'rxjs'; import { MetadataProviderService } from '../../domain/service/provider.service'; import { Metadata } from '../../domain/domain.type'; import { SCHEMA } from '../../../../testing/form-schema.stub'; -import { getConfigurationSectionsFn } from '../reducer'; +import { getConfigurationSectionsFn } from '../reducer/utilities'; describe(`Configuration Service`, () => { diff --git a/ui/src/app/metadata/domain/component/wizard-summary.component.html b/ui/src/app/metadata/domain/component/wizard-summary.component.html new file mode 100644 index 000000000..349f7cb74 --- /dev/null +++ b/ui/src/app/metadata/domain/component/wizard-summary.component.html @@ -0,0 +1,14 @@ +
+
+
+ + + + +
+
+
\ No newline at end of file diff --git a/ui/src/app/metadata/domain/component/wizard-summary.component.spec.ts b/ui/src/app/metadata/domain/component/wizard-summary.component.spec.ts new file mode 100644 index 000000000..43712bd48 --- /dev/null +++ b/ui/src/app/metadata/domain/component/wizard-summary.component.spec.ts @@ -0,0 +1,103 @@ +import { Component, ViewChild } from '@angular/core'; +import { TestBed, async, ComponentFixture } from '@angular/core/testing'; +import { RouterTestingModule } from '@angular/router/testing'; + +import { NgbDropdownModule, NgbPopoverModule } from '@ng-bootstrap/ng-bootstrap'; + +import { WizardSummaryComponent } from './wizard-summary.component'; +import { SchemaFormModule, WidgetRegistry, DefaultWidgetRegistry } from 'ngx-schema-form'; +import { Wizard } from '../../../wizard/model'; +import { MetadataProvider } from '../../domain/model'; +import { SummaryPropertyComponent } from './summary-property.component'; +import { SCHEMA } from '../../../../testing/form-schema.stub'; +import { MockI18nModule } from '../../../../testing/i18n.stub'; +import { MetadataProviderWizard } from '../../provider/model'; +import { AttributesService } from '../service/attributes.service'; +import { MockAttributeService } from '../../../../testing/attributes.stub'; + +@Component({ + template: ` + + ` +}) +class TestHostComponent { + @ViewChild(WizardSummaryComponent) + public componentUnderTest: WizardSummaryComponent; + + private _summary; + + get summary(): { definition: Wizard, schema: { [id: string]: any }, model: any } { + return this._summary; + } + + set summary(summary: { definition: Wizard, schema: { [id: string]: any }, model: any }) { + this._summary = summary; + } +} + +describe('Wizard Summary Component', () => { + + let fixture: ComponentFixture; + let instance: TestHostComponent; + let app: WizardSummaryComponent; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [ + NgbDropdownModule, + NgbPopoverModule, + RouterTestingModule, + SchemaFormModule.forRoot(), + MockI18nModule + ], + declarations: [ + WizardSummaryComponent, + SummaryPropertyComponent, + TestHostComponent + ], + providers: [ + { provide: WidgetRegistry, useClass: DefaultWidgetRegistry }, + { provide: AttributesService, useClass: MockAttributeService } + ] + }).compileComponents(); + + fixture = TestBed.createComponent(TestHostComponent); + instance = fixture.componentInstance; + app = instance.componentUnderTest; + fixture.detectChanges(); + })); + + it('should instantiate the component', async(() => { + expect(app).toBeTruthy(); + })); + + describe('gotoPage function', () => { + it('should emit an empty string if page is null', () => { + spyOn(app.onPageSelect, 'emit'); + app.gotoPage(); + expect(app.onPageSelect.emit).toHaveBeenCalledWith(''); + }); + + it('should emit the provided page', () => { + spyOn(app.onPageSelect, 'emit'); + app.gotoPage('foo'); + expect(app.onPageSelect.emit).toHaveBeenCalledWith('foo'); + }); + }); + + describe('ngOnChanges', () => { + it('should set columns and sections if summary is provided', () => { + instance.summary = { + model: { + name: 'foo', + '@type': 'MetadataProvider' + }, + schema: SCHEMA, + definition: MetadataProviderWizard + }; + fixture.detectChanges(); + expect(app.sections).toBeDefined(); + expect(app.columns).toBeDefined(); + }); + }); +}); diff --git a/ui/src/app/metadata/domain/component/wizard-summary.component.ts b/ui/src/app/metadata/domain/component/wizard-summary.component.ts new file mode 100644 index 000000000..73a701491 --- /dev/null +++ b/ui/src/app/metadata/domain/component/wizard-summary.component.ts @@ -0,0 +1,80 @@ +import { Component, Input, SimpleChanges, OnChanges, Output, EventEmitter } from '@angular/core'; + +import { Wizard, WizardStep } from '../../../wizard/model'; +import { MetadataProvider, MetadataResolver } from '../../domain/model'; +import { Property } from '../model/property'; +import { getSplitSchema } from '../../../wizard/reducer'; +import { getStepProperties } from '../utility/configuration'; + +interface Section { + id: string; + index: number; + label: string; + pageNumber: number; + properties: Property[]; +} + +@Component({ + selector: 'wizard-summary', + templateUrl: './wizard-summary.component.html', + styleUrls: [] +}) + +export class WizardSummaryComponent implements OnChanges { + @Input() summary: { definition: Wizard, schema: { [id: string]: any }, model: any }; + + @Output() onPageSelect: EventEmitter = new EventEmitter(); + + sections: Section[]; + columns: Array
[]; + steps: WizardStep[]; + + constructor() { } + + ngOnChanges(changes: SimpleChanges): void { + if (changes.summary && this.summary) { + const schema = this.summary.schema; + const model = this.summary.model; + const def = this.summary.definition; + const steps = def.steps; + + this.sections = steps + .filter(step => step.id !== 'summary') + .map( + (step: WizardStep, num: number) => { + const { id, index, label } = step; + const split = getSplitSchema(schema, step); + const properties = getStepProperties( + split, + def.formatter(model), + schema.definitions || {} + ); + return ({ + id, + pageNumber: num + 1, + index, + label, + properties + }); + } + ); + + this.columns = this.sections.reduce((resultArray, item, index) => { + const chunkIndex = Math.floor(index / Math.round(this.sections.length / 2)); + + if (!resultArray[chunkIndex]) { + resultArray[chunkIndex] = []; + } + + resultArray[chunkIndex].push(item); + + return resultArray; + }, []); + } + } + + gotoPage(page: string = ''): void { + this.onPageSelect.emit(page); + } +} + diff --git a/ui/src/app/metadata/domain/domain.module.ts b/ui/src/app/metadata/domain/domain.module.ts index b109734a6..49e1fe685 100644 --- a/ui/src/app/metadata/domain/domain.module.ts +++ b/ui/src/app/metadata/domain/domain.module.ts @@ -22,8 +22,10 @@ import { UnsavedEntityComponent } from './component/unsaved-entity.dialog'; import { EditorNavComponent } from './component/editor-nav.component'; import { RouterModule } from '@angular/router'; import { SharedModule } from '../../shared/shared.module'; +import { WizardSummaryComponent } from './component/wizard-summary.component'; export const COMPONENTS = [ + WizardSummaryComponent, PreviewDialogComponent, UnsavedEntityComponent, SummaryPropertyComponent, diff --git a/ui/src/app/metadata/provider/model/dynamic-http.provider.form.spec.ts b/ui/src/app/metadata/provider/model/dynamic-http.provider.form.spec.ts index bafe25f4b..f561b4e99 100644 --- a/ui/src/app/metadata/provider/model/dynamic-http.provider.form.spec.ts +++ b/ui/src/app/metadata/provider/model/dynamic-http.provider.form.spec.ts @@ -1,5 +1,51 @@ import { DynamicHttpMetadataProviderWizard } from './dynamic-http.provider.form'; +const schema = { + 'type': 'object', + 'required': [ + '@type', + 'content' + ], + 'properties': { + '@type': { + 'title': 'label.md-request-type', + 'description': 'tooltip.md-request-type', + 'type': 'string', + 'widget': { + 'id': 'select' + }, + 'oneOf': [ + { + 'enum': [ + 'MetadataQueryProtocol' + ], + 'description': 'value.md-query-protocol' + }, + { + 'enum': [ + 'Regex' + ], + 'description': 'value.regex' + } + ] + }, + 'content': { + 'title': 'label.md-request-value', + 'description': 'tooltip.md-request-value', + 'type': 'string' + }, + 'match': { + 'title': 'label.match', + 'description': 'tooltip.match', + 'type': 'string', + 'visibleIf': { + '@type': [ + 'Regex' + ] + } + } + } +}; describe('DynamicHttpMetadataProviderWizard', () => { @@ -122,4 +168,43 @@ describe('DynamicHttpMetadataProviderWizard', () => { ]); }); }); + + describe('validators', () => { + let validators, + metadataRequestURLConstructionScheme, + metadataRequestURLConstructionSchemeContent, + metadataRequestURLConstructionSchemeType, + metadataRequestURLConstructionSchemeMatch; + + beforeEach(() => { + validators = getValidators([], []); + }); + + describe('metadataRequestURLConstructionScheme', () => { + it('should check other validators and propagate those errors up', () => { + const value = { + content: null, + '@type': null, + match: 'foo' + }; + const property = { value, schema, properties: null }; + property.properties = { + content: { + path: 'content', + parent: property + }, + '@type': { + path: '@type', + parent: property + }, + match: { + path: 'match', + parent: property + } + }; + const validator = validators['/metadataRequestURLConstructionScheme']; + expect(validator(value, property, null).length).toBe(2); + }); + }); + }); }); diff --git a/ui/src/app/metadata/provider/model/utilities.spec.ts b/ui/src/app/metadata/provider/model/utilities.spec.ts new file mode 100644 index 000000000..5affea1ae --- /dev/null +++ b/ui/src/app/metadata/provider/model/utilities.spec.ts @@ -0,0 +1,33 @@ +import { metadataFilterProcessor } from './utilities'; + +describe('provider model utilities', () => { + describe('metadata filter processor function', () => { + it('should return null if no schema provided', () => { + expect(metadataFilterProcessor(null)).toBe(null); + }); + + it('should return the schema if no properties are detected', () => { + const schema = {}; + expect(metadataFilterProcessor(schema)).toBe(schema); + }); + + it('should return the schema if no metadataFilters property exists in the schema', () => { + const schema = { properties: { foo: 'bar' } }; + expect(metadataFilterProcessor(schema)).toBe(schema); + }); + + it('should turn the filters into an object if provided ', () => { + const schema = { properties: { metadataFilters: { + type: 'array', + items: [ + { + $id: 'foo', + type: 'string' + } + ] + } } }; + const processed = metadataFilterProcessor(schema); + expect(processed.properties.metadataFilters.properties.foo.type).toBe('string'); + }); + }); +}); diff --git a/ui/src/app/metadata/provider/model/utilities.ts b/ui/src/app/metadata/provider/model/utilities.ts index aea90bc21..dc415bae1 100644 --- a/ui/src/app/metadata/provider/model/utilities.ts +++ b/ui/src/app/metadata/provider/model/utilities.ts @@ -1,5 +1,4 @@ export const metadataFilterProcessor = (schema) => { - console.log(schema); if (!schema) { return null; } @@ -20,6 +19,5 @@ export const metadataFilterProcessor = (schema) => { } } }); - console.log(processed); return processed; }; diff --git a/ui/src/app/metadata/resolver/container/resolver-wizard.component.spec.ts b/ui/src/app/metadata/resolver/container/resolver-wizard.component.spec.ts index 3cec9bf25..58191efeb 100644 --- a/ui/src/app/metadata/resolver/container/resolver-wizard.component.spec.ts +++ b/ui/src/app/metadata/resolver/container/resolver-wizard.component.spec.ts @@ -2,7 +2,7 @@ import { Component, ViewChild } from '@angular/core'; import { TestBed, async, ComponentFixture } from '@angular/core/testing'; import { RouterTestingModule } from '@angular/router/testing'; import { StoreModule, Store, combineReducers } from '@ngrx/store'; -import { RouterStateSnapshot, ActivatedRouteSnapshot } from '@angular/router'; +import { RouterStateSnapshot } from '@angular/router'; import { NgbDropdownModule, NgbPopoverModule, NgbModal } from '@ng-bootstrap/ng-bootstrap'; import { of } from 'rxjs'; @@ -18,6 +18,7 @@ import { MockWizardModule } from '../../../../testing/wizard.stub'; import { NgbModalStub } from '../../../../testing/modal.stub'; import { MetadataResolver } from '../../domain/model'; import { DifferentialService } from '../../../core/service/differential.service'; +import { MetadataConfigurationComponentStub } from '../../../../testing/metadata-configuration.stub'; @Component({ template: ` @@ -85,7 +86,8 @@ describe('Resolver Wizard Component', () => { ], declarations: [ ResolverWizardComponent, - TestHostComponent + TestHostComponent, + MetadataConfigurationComponentStub ], providers: [ DifferentialService, diff --git a/ui/src/app/wizard/reducer/index.ts b/ui/src/app/wizard/reducer/index.ts index 027ac1673..255710be0 100644 --- a/ui/src/app/wizard/reducer/index.ts +++ b/ui/src/app/wizard/reducer/index.ts @@ -129,7 +129,7 @@ export const getSchemaLockedFn = (step, locked) => step ? step.locked ? locked : export const getLocked = createSelector(getCurrent, getLockedStatus, getSchemaLockedFn); export const getSchemaProcessedFn = (schema, definition) => - definition.schemaPreprocessor ? definition.schemaPreprocessor(schema) : schema; + definition && definition.schemaPreprocessor ? definition.schemaPreprocessor(schema) : schema; export const getSchemaObject = createSelector(getState, fromWizard.getSchema); export const getProcessedSchema = createSelector(getSchemaObject, getWizardDefinition, getSchemaProcessedFn);