From a4e52f7004680a3e16b2e95ad0e10c5fb9a9cda7 Mon Sep 17 00:00:00 2001 From: Ryan Mathis Date: Tue, 23 Feb 2021 07:17:42 -0700 Subject: [PATCH 01/26] UI Tweaks --- .../src/main/resources/metadata-sources-ui-schema.json | 6 ++++++ ui/src/app/contention/effect/contention.effect.ts | 4 ++-- .../resolver/container/resolver-edit.component.ts | 7 +++---- .../app/schema-form/widget/array/array.component.html | 5 +++-- .../widget/boolean-radio/boolean-radio.component.html | 10 +++++----- .../schema-form/widget/check/checkbox.component.html | 6 +++--- .../app/schema-form/widget/radio/radio.component.html | 10 ++++------ 7 files changed, 26 insertions(+), 22 deletions(-) diff --git a/backend/src/main/resources/metadata-sources-ui-schema.json b/backend/src/main/resources/metadata-sources-ui-schema.json index 9a0b4fb9e..156dffce2 100644 --- a/backend/src/main/resources/metadata-sources-ui-schema.json +++ b/backend/src/main/resources/metadata-sources-ui-schema.json @@ -446,6 +446,12 @@ "urn:oasis:names:tc:SAML:2.0:bindings:SOAP" ], "description": "urn:oasis:names:tc:SAML:2.0:bindings:SOAP" + }, + { + "enum": [ + "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact" + ], + "description": "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact" } ] } diff --git a/ui/src/app/contention/effect/contention.effect.ts b/ui/src/app/contention/effect/contention.effect.ts index aa89ffbd1..f6845df3f 100644 --- a/ui/src/app/contention/effect/contention.effect.ts +++ b/ui/src/app/contention/effect/contention.effect.ts @@ -23,12 +23,12 @@ export class ContentionEffects { switchMap(contention => { const resolutionAction = of(new ResolveContentionAction({ value: contention.resolutionObject, handlers: contention.handlers })); const rejectionAction = of(new CancelContentionAction({ value: contention.rejectionObject, handlers: contention.handlers })); - if (contention.ourChanges.length < 1) { + /*if (contention.ourChanges.length < 1) { return rejectionAction; } if (contention.theirChanges.length < 1) { return resolutionAction; - } + }*/ return this.modal .open(ContentionDialogComponent, DEFAULT_MODAL_OPTIONS, { contention }) .pipe( diff --git a/ui/src/app/metadata/resolver/container/resolver-edit.component.ts b/ui/src/app/metadata/resolver/container/resolver-edit.component.ts index 6d5e802d2..c5cc6b324 100644 --- a/ui/src/app/metadata/resolver/container/resolver-edit.component.ts +++ b/ui/src/app/metadata/resolver/container/resolver-edit.component.ts @@ -1,11 +1,11 @@ import { Component, OnDestroy } from '@angular/core'; -import { Router, ActivatedRoute, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router'; +import { Router, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router'; import { Observable, of, Subject } from 'rxjs'; -import { skipWhile, map, combineLatest, filter, takeUntil } from 'rxjs/operators'; +import { map, filter } from 'rxjs/operators'; import { Store } from '@ngrx/store'; import * as fromWizard from '../../../wizard/reducer'; import * as fromResolver from '../reducer'; -import { ClearWizard, SetIndex, LoadSchemaRequest } from '../../../wizard/action/wizard.action'; +import { LoadSchemaRequest } from '../../../wizard/action/wizard.action'; import { MetadataResolver } from '../../domain/model'; import { Clear } from '../action/entity.action'; import { Wizard } from '../../../wizard/model'; @@ -41,7 +41,6 @@ export class ResolverEditComponent implements OnDestroy, CanComponentDeactivate constructor( private store: Store, private router: Router, - private route: ActivatedRoute, private modalService: NgbModal, private diffService: DifferentialService ) { diff --git a/ui/src/app/schema-form/widget/array/array.component.html b/ui/src/app/schema-form/widget/array/array.component.html index 2bcf6271b..84a5a1e9b 100644 --- a/ui/src/app/schema-form/widget/array/array.component.html +++ b/ui/src/app/schema-form/widget/array/array.component.html @@ -38,9 +38,10 @@
-
+
- + +   diff --git a/ui/src/app/schema-form/widget/boolean-radio/boolean-radio.component.html b/ui/src/app/schema-form/widget/boolean-radio/boolean-radio.component.html index 8b335f58e..217dd94ee 100644 --- a/ui/src/app/schema-form/widget/boolean-radio/boolean-radio.component.html +++ b/ui/src/app/schema-form/widget/boolean-radio/boolean-radio.component.html @@ -8,18 +8,18 @@ {{ schema.description }}
-
+
+ [attr.disabled]="schema.readOnly" + disableValidation="true">
diff --git a/ui/src/app/schema-form/widget/check/checkbox.component.html b/ui/src/app/schema-form/widget/check/checkbox.component.html index 62be86566..538251826 100644 --- a/ui/src/app/schema-form/widget/check/checkbox.component.html +++ b/ui/src/app/schema-form/widget/check/checkbox.component.html @@ -1,17 +1,17 @@
-
-
diff --git a/ui/src/app/schema-form/widget/radio/radio.component.html b/ui/src/app/schema-form/widget/radio/radio.component.html index 316161909..de9187120 100644 --- a/ui/src/app/schema-form/widget/radio/radio.component.html +++ b/ui/src/app/schema-form/widget/radio/radio.component.html @@ -4,16 +4,14 @@ {{schema.description}} -
- + -
From d817386ba1234cd0a55c891c2e1beb93e9c83d6a Mon Sep 17 00:00:00 2001 From: Ryan Mathis Date: Mon, 1 Mar 2021 10:24:43 -0700 Subject: [PATCH 02/26] Fixed issue with contention --- backend/src/main/resources/i18n/messages.properties | 1 + .../component/contention-dialog.component.html | 12 ++++++++---- ui/src/app/contention/effect/contention.effect.ts | 6 ------ .../metadata/provider/effect/collection.effect.ts | 4 ++-- .../app/metadata/provider/effect/editor.effect.ts | 13 ++++++++----- .../app/metadata/resolver/effect/entity.effect.ts | 11 +++++++++-- 6 files changed, 28 insertions(+), 19 deletions(-) diff --git a/backend/src/main/resources/i18n/messages.properties b/backend/src/main/resources/i18n/messages.properties index 0d5356269..0032a25ed 100644 --- a/backend/src/main/resources/i18n/messages.properties +++ b/backend/src/main/resources/i18n/messages.properties @@ -453,6 +453,7 @@ message.protocol-support-required=Protocol Support Enumeration is required if an message.conflict=Conflict message.data-version-contention=Data Version Contention message.contention-new-version=A newer version of this metadata source has been saved. Below are a list of changes. You can use your changes or their changes. +message.contention-error=There was a problem saving due to a mismatched version. message.organization-feedback=These three fields must all be entered if any single field has a value. message.valid-email=Must be a valid Email Address message.valid-url=Must be a valid URL diff --git a/ui/src/app/contention/component/contention-dialog.component.html b/ui/src/app/contention/component/contention-dialog.component.html index 0922f982f..1ff63bb4b 100644 --- a/ui/src/app/contention/component/contention-dialog.component.html +++ b/ui/src/app/contention/component/contention-dialog.component.html @@ -3,12 +3,16 @@
-
+
@@ -22,8 +22,8 @@
- -
diff --git a/ui/src/app/metadata/filter/container/edit-filter.component.ts b/ui/src/app/metadata/filter/container/edit-filter.component.ts index d70537a3f..6eb9e7908 100644 --- a/ui/src/app/metadata/filter/container/edit-filter.component.ts +++ b/ui/src/app/metadata/filter/container/edit-filter.component.ts @@ -3,17 +3,16 @@ import { Store } from '@ngrx/store'; import { Subject, Observable, Subscription } from 'rxjs'; import * as fromFilter from '../reducer'; -import { MetadataFilterTypes } from '../model'; import { FormDefinition } from '../../../wizard/model'; import { MetadataFilter } from '../../domain/model'; -import { SchemaService } from '../../../schema-form/service/schema.service'; import { UpdateFilterRequest } from '../action/collection.action'; -import { CancelCreateFilter, UpdateFilterChanges } from '../action/filter.action'; +import { CancelCreateFilter } from '../action/filter.action'; import { PreviewEntity } from '../../domain/action/entity.action'; import { NAV_FORMATS } from '../../domain/component/editor-nav.component'; -import { shareReplay, map, withLatestFrom, filter, switchMap, takeUntil } from 'rxjs/operators'; +import { map, filter } from 'rxjs/operators'; import * as fromWizard from '../../../wizard/reducer'; import { ActivatedRoute } from '@angular/router'; +import { LoadSchemaRequest, SetIndex } from '../../../wizard/action/wizard.action'; @Component({ selector: 'edit-filter-page', @@ -23,12 +22,6 @@ export class EditFilterComponent implements OnDestroy { private ngUnsubscribe: Subject = new Subject(); - valueChangeSubject = new Subject>(); - private valueChangeEmitted$ = this.valueChangeSubject.asObservable(); - - statusChangeSubject = new Subject<{ value: any[] }>(); - private statusChangeEmitted$ = this.statusChangeSubject.asObservable(); - definition$: Observable>; definition: FormDefinition; schema$: Observable; @@ -36,13 +29,12 @@ export class EditFilterComponent implements OnDestroy { model$: Observable; isSaving$: Observable; filter: MetadataFilter; - isValid: boolean; + isValid$: Observable; + isInvalid$: Observable; type$: Observable; status$: Observable; - validators$: Observable<{ [key: string]: any }>; - actions: any; defSub: Subscription; @@ -51,7 +43,6 @@ export class EditFilterComponent implements OnDestroy { constructor( private store: Store, - private schemaService: SchemaService, private route: ActivatedRoute ) { @@ -59,34 +50,27 @@ export class EditFilterComponent implements OnDestroy { this.defSub = this.definition$.subscribe(d => this.definition = d); - this.schema$ = this.definition$.pipe( - takeUntil(this.ngUnsubscribe), - filter(d => !!d), - switchMap(d => this.schemaService.get(d.schema).pipe(takeUntil(this.ngUnsubscribe))), - shareReplay() - ); + this.store + .select(fromWizard.getCurrentWizardSchema) + .pipe(filter(s => !!s)) + .subscribe(s => { + if (s) { + this.store.dispatch(new LoadSchemaRequest(s)); + } + }); + + let startIndex$ = this.route.firstChild.params.pipe(map(p => p.form || 'filters')); + startIndex$.subscribe(index => this.store.dispatch(new SetIndex(index))); + this.isSaving$ = this.store.select(fromFilter.getCollectionSaving); this.model$ = this.store.select(fromFilter.getSelectedFilter); this.type$ = this.model$.pipe(map(f => f && f.hasOwnProperty('@type') ? f['@type'] : '')); - this.valueChangeEmitted$.subscribe(changes => this.store.dispatch(new UpdateFilterChanges(changes.value))); - this.statusChangeEmitted$.subscribe(valid => { - this.isValid = valid.value ? valid.value.length === 0 : true; - }); - this.status$ = this.store.select(fromFilter.getInvalidEditorForms); - this.validators$ = this.store.select(fromFilter.getFilterNames).pipe( - takeUntil(this.ngUnsubscribe), - withLatestFrom( - this.store.select(fromFilter.getSelectedFilter), - this.definition$ - ), - map(([names, provider, definition]) => definition.getValidators( - names.filter(n => n !== provider.name) - )) - ); + this.isValid$ = this.store.select(fromFilter.getEditorIsValid); + this.isInvalid$ = this.isValid$.pipe(map(v => !v)); this.store .select(fromFilter.getFilter) diff --git a/ui/src/app/metadata/filter/effect/collection.effect.ts b/ui/src/app/metadata/filter/effect/collection.effect.ts index 683d71b17..9e15e691c 100644 --- a/ui/src/app/metadata/filter/effect/collection.effect.ts +++ b/ui/src/app/metadata/filter/effect/collection.effect.ts @@ -162,13 +162,16 @@ export class FilterCollectionEffects { updateFilter$ = this.actions$.pipe( ofType(FilterCollectionActionTypes.UPDATE_FILTER_REQUEST), map(action => action.payload), - switchMap((action) => { + withLatestFrom(this.store.select(fromFilter.getSelectedFilter)), + switchMap(([action, original]) => { const { filter, providerId } = action; delete filter.modifiedDate; delete filter.createdDate; + const updates = ({ ...original, ...filter }); + return this.filterService - .update(providerId, filter) + .update(providerId, updates) .pipe( map(resp => new UpdateFilterSuccess({ providerId, @@ -178,7 +181,7 @@ export class FilterCollectionEffects { } })), catchError(err => of(err.status === 409 ? new UpdateFilterConflict({ - filter, + filter: updates, providerId }) : new UpdateFilterFail(err))) ); diff --git a/ui/src/app/metadata/filter/filter.module.ts b/ui/src/app/metadata/filter/filter.module.ts index f30d517df..6514b5a06 100644 --- a/ui/src/app/metadata/filter/filter.module.ts +++ b/ui/src/app/metadata/filter/filter.module.ts @@ -23,11 +23,13 @@ import { FormModule } from '../../schema-form/schema-form.module'; import { I18nModule } from '../../i18n/i18n.module'; import { FilterComponent } from './container/filter.component'; import { FilterListComponent } from './component/filter-list.component'; +import { EditFilterStepComponent } from './container/edit-filter-step.component'; @NgModule({ declarations: [ NewFilterComponent, EditFilterComponent, + EditFilterStepComponent, SelectFilterComponent, SearchDialogComponent, FilterComponent, diff --git a/ui/src/app/metadata/filter/model/entity-attributes-configuration.filter.ts b/ui/src/app/metadata/filter/model/entity-attributes-configuration.filter.ts index 081aed521..6117c9427 100644 --- a/ui/src/app/metadata/filter/model/entity-attributes-configuration.filter.ts +++ b/ui/src/app/metadata/filter/model/entity-attributes-configuration.filter.ts @@ -6,10 +6,14 @@ export const EntityAttributesFilterConfiguration: Wizard = { ...EntityAttributesFilter, steps: [ { - id: 'target', + id: 'common', label: 'label.target', index: 1, fields: [ + 'name', + '@type', + 'resourceId', + 'filterEnabled', 'entityAttributesFilterTarget' ] }, @@ -19,10 +23,6 @@ export const EntityAttributesFilterConfiguration: Wizard = { index: 2, initialValues: [], fields: [ - 'name', - '@type', - 'resourceId', - 'filterEnabled', 'relyingPartyOverrides' ] }, diff --git a/ui/src/app/metadata/provider/provider.routing.ts b/ui/src/app/metadata/provider/provider.routing.ts index ee73ed01b..975b9b427 100644 --- a/ui/src/app/metadata/provider/provider.routing.ts +++ b/ui/src/app/metadata/provider/provider.routing.ts @@ -9,6 +9,7 @@ import { ProviderFilterListComponent } from './container/provider-filter-list.co import { NewFilterComponent } from '../filter/container/new-filter.component'; import { SelectFilterComponent } from '../filter/container/select-filter.component'; import { EditFilterComponent } from '../filter/container/edit-filter.component'; +import { EditFilterStepComponent } from '../filter/container/edit-filter-step.component'; import { CanDeactivateGuard } from '../../core/service/can-deactivate.guard'; import { FilterComponent } from '../filter/container/filter.component'; import { AdminGuard } from '../../core/service/admin.guard'; @@ -79,7 +80,15 @@ export const ProviderRoutes: Routes = [ { path: 'edit', component: EditFilterComponent, - data: { title: `Edit Metadata Filter` } + data: { title: `Edit Metadata Filter` }, + children: [ + { path: '', redirectTo: 'common', pathMatch: 'prefix' }, + { + path: ':form', + component: EditFilterStepComponent, + data: { title: `Edit Metadata Filter`, subtitle: true } + } + ] } ] } From f5c20ad493c4a6dd25b3c022282658359461f153 Mon Sep 17 00:00:00 2001 From: Shad Vider Date: Wed, 17 Mar 2021 12:08:55 -0700 Subject: [PATCH 08/26] added test for added test for 1772, and enabled previously ignored test --- .../EntityDescriptorControllerTests.groovy | 3 +- .../EntityDescriptorRepositoryTest.groovy | 9 +++ .../test/resources/metadata/SHIBUI-1772.xml | 81 +++++++++++++++++++ 3 files changed, 91 insertions(+), 2 deletions(-) create mode 100644 backend/src/test/resources/metadata/SHIBUI-1772.xml diff --git a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/EntityDescriptorControllerTests.groovy b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/EntityDescriptorControllerTests.groovy index ed721055a..4bf4fe7b2 100644 --- a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/EntityDescriptorControllerTests.groovy +++ b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/EntityDescriptorControllerTests.groovy @@ -707,7 +707,6 @@ class EntityDescriptorControllerTests extends Specification { result.andExpect(status().is(403)) } - @Ignore("until we handle the workaround for SHIBUI-1237") def "POST /EntityDescriptor handles XML happily"() { given: def username = 'admin' @@ -785,7 +784,7 @@ class EntityDescriptorControllerTests extends Specification { then: result.andExpect(status().isCreated()) - .andExpect(content().json(expectedJson, true)) + .andExpect(content().json(expectedJson, false)) } def "POST /EntityDescriptor returns error for duplicate entity id"() { diff --git a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/repository/EntityDescriptorRepositoryTest.groovy b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/repository/EntityDescriptorRepositoryTest.groovy index 9719ada72..86fe1b74e 100644 --- a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/repository/EntityDescriptorRepositoryTest.groovy +++ b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/repository/EntityDescriptorRepositoryTest.groovy @@ -76,6 +76,15 @@ class EntityDescriptorRepositoryTest extends Specification { noExceptionThrown() } + def "SHIBUI-1772"() { + when: + def input = openSamlObjects.unmarshalFromXml(this.class.getResource('/metadata/SHIBUI-1772.xml').bytes) as EntityDescriptor + entityDescriptorRepository.save(input) + + then: + noExceptionThrown() + } + @TestConfiguration static class Config { @Bean diff --git a/backend/src/test/resources/metadata/SHIBUI-1772.xml b/backend/src/test/resources/metadata/SHIBUI-1772.xml new file mode 100644 index 000000000..e0961dc71 --- /dev/null +++ b/backend/src/test/resources/metadata/SHIBUI-1772.xml @@ -0,0 +1,81 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 67af3237368e + + CN=67af3237368e + MIID6zCCAlOgAwIBAgIJALaLIs8AvRgDMA0GCSqGSIb3DQEBCwUAMBcxFTATBgNV + BAMTDDY3YWYzMjM3MzY4ZTAeFw0xODAxMDkyMDUxMzlaFw0yODAxMDcyMDUxMzla + MBcxFTATBgNVBAMTDDY3YWYzMjM3MzY4ZTCCAaIwDQYJKoZIhvcNAQEBBQADggGP + ADCCAYoCggGBAKes3NT2GqXPDrl8OwrDRARLoBxKJ8ALZ0Ipj1sbYcUEv8aZ4ElR + +G4xf/KL/nF77ctc9WzE/fUlFG55lVKF7l2heKenweXsmeInmOj0MqXpIIofF1G2 + Sh4xUGACQp0OT7ndNlk2+mHK9zuCNA5o3VrAhJuWAruL3nRk14+DE7UkqF+oBZaF + k5/U7W2sa6R1+UHXvSI823O5jAjhSSIfY/N2mME7QogU3P6ETa7BSRS3IvZ8oJvU + T2Ss2ai1qZoiR/0Exeyj5nc026XEAQ675WAcxpAfxu+uDVQ274nPrvOdqUtUeaiU + nc3kIdorXx/m8+WjYT4rGAXx2NbRRC/wRc7ilptLtL/5iHGJkIieFbzHWJXRRMzT + /wWuYM8lr6lqEiOW/2B6z6kQpuGZoinQYBrNU+xYelkfK+jc1IZgR5wOP2aVJ2Gj + DAarnNHkkd36sxOUKw+4f2R2K5obwzHqJl7jySW2p0KldjobQLt0M1DswK0U478R + qqItwPfsTxju0wIDAQABozowODAXBgNVHREEEDAOggw2N2FmMzIzNzM2OGUwHQYD + VR0OBBYEFAvZyUZ8LY3YacgpZSzgQMYSFmptMA0GCSqGSIb3DQEBCwUAA4IBgQCM + IBtz+5mfFtRwmcScYdUzIujCbGfnY6+YsjGMa0jDDfyS1kFfNrj9VRl6uuPO8gWu + BOxR9asm96FOC/tZOQ9SZgQN6ltQsfAMhl+cnI80Qwx8pUXt+iUtM+IgTUFqiv51 + Oy2GyFJGr1QIq4/iF8Q6k27ar73qVGFAYtGgOO5va4hKk6wPgiTHtIqgut6nbWD3 + ErCB28sMnNVYUVhQUxVf9c/9sXC8UIj9Ze0xrclhOeHwrwr9G5EZzyxK8VPFkv0Q + Xrz01BXy/DcbIkcuFFvXE+BMeaziT4FofvvPXWpM1i+FX0wlkCXLj4GNsTuVspfi + T5uUQUubf52kpO5tkPmF9JdM25qmVu5IgpqCMbm1mqrq7qAEFjzOtIp4f0EmHUSy + /BNdo6DT14p56KA0DyrkBCR1UUgzBJcFNJLBLbyEHnHL8fXDcIhjjKJETYoKdsHT + NEi6AB6UOCbYz//CwA96sW154Lu4CpMKrm5fZHLPQ+7UeE9UOQidzHLJ3Vb54BY= + + + + + + + + + + + + + + + + + + + + + + + + + From 98be18508836185fa4bf46ecc5eac97e7ba5ac17 Mon Sep 17 00:00:00 2001 From: Ryan Mathis Date: Wed, 17 Mar 2021 13:23:36 -0700 Subject: [PATCH 09/26] Fixed validation --- .../component/editor-nav.component.html | 4 +- .../domain/component/editor-nav.component.ts | 1 + .../filter/action/collection.action.ts | 10 +- .../metadata/filter/action/editor.action.ts | 8 -- .../filter/action/filter.action.spec.ts | 2 +- .../container/edit-filter-step.component.ts | 42 +++++-- .../container/edit-filter.component.html | 26 ++--- .../filter/container/edit-filter.component.ts | 15 ++- .../container/new-filter-step.component.html | 15 +++ .../container/new-filter-step.component.ts | 104 ++++++++++++++++++ .../container/new-filter.component.html | 51 +++++---- .../filter/container/new-filter.component.ts | 94 ++++++++-------- .../filter/effect/collection.effect.ts | 16 +-- .../metadata/filter/effect/filter.effect.ts | 1 + ui/src/app/metadata/filter/filter.module.ts | 2 + .../model/nameid-configuration.filter.ts | 10 +- .../metadata/filter/reducer/editor.reducer.ts | 11 +- .../metadata/filter/reducer/filter.reducer.ts | 3 +- ui/src/app/metadata/filter/reducer/index.ts | 12 +- .../container/provider-select.component.ts | 1 - .../app/metadata/provider/provider.routing.ts | 13 ++- 21 files changed, 300 insertions(+), 141 deletions(-) create mode 100644 ui/src/app/metadata/filter/container/new-filter-step.component.html create mode 100644 ui/src/app/metadata/filter/container/new-filter-step.component.ts diff --git a/ui/src/app/metadata/domain/component/editor-nav.component.html b/ui/src/app/metadata/domain/component/editor-nav.component.html index 9fe804c85..7307e79fb 100644 --- a/ui/src/app/metadata/domain/component/editor-nav.component.html +++ b/ui/src/app/metadata/domain/component/editor-nav.component.html @@ -15,7 +15,7 @@ @@ -32,7 +32,7 @@ href="" class="nav-link" [ngClass]="{'active': (currentPage$ | async) === route.path}" - [routerLink]="['../', 'edit', route.path]" + [routerLink]="['../', path, route.path]" role="button" [attr.aria-label]="route.label"> diff --git a/ui/src/app/metadata/domain/component/editor-nav.component.ts b/ui/src/app/metadata/domain/component/editor-nav.component.ts index 32653fb43..7cf57ed1b 100644 --- a/ui/src/app/metadata/domain/component/editor-nav.component.ts +++ b/ui/src/app/metadata/domain/component/editor-nav.component.ts @@ -21,6 +21,7 @@ export enum NAV_FORMATS { export class EditorNavComponent { @Input() format: string; @Input() status: string[] = []; + @Input() path: string = 'edit'; @Output() onPageSelect: EventEmitter = new EventEmitter(); diff --git a/ui/src/app/metadata/filter/action/collection.action.ts b/ui/src/app/metadata/filter/action/collection.action.ts index 11ffad3ca..8c14693e2 100644 --- a/ui/src/app/metadata/filter/action/collection.action.ts +++ b/ui/src/app/metadata/filter/action/collection.action.ts @@ -112,13 +112,19 @@ export class UpdateFilterConflict implements Action { export class AddFilterRequest implements Action { readonly type = FilterCollectionActionTypes.ADD_FILTER_REQUEST; - constructor(public payload: MetadataFilter) { } + constructor(public payload: { + filter: MetadataFilter, + providerId: string + }) { } } export class AddFilterSuccess implements Action { readonly type = FilterCollectionActionTypes.ADD_FILTER_SUCCESS; - constructor(public payload: MetadataFilter) { } + constructor(public payload: { + filter: MetadataFilter, + providerId: string + }) { } } export class AddFilterFail implements Action { diff --git a/ui/src/app/metadata/filter/action/editor.action.ts b/ui/src/app/metadata/filter/action/editor.action.ts index 7c4dba2cf..7ea0a867b 100644 --- a/ui/src/app/metadata/filter/action/editor.action.ts +++ b/ui/src/app/metadata/filter/action/editor.action.ts @@ -2,7 +2,6 @@ import { Action } from '@ngrx/store'; export enum EditorActionTypes { UPDATE_STATUS = '[Filter Editor] Update Status', - SELECT_PROVIDER_TYPE = '[Filter Editor] Select Filter Type', CLEAR = '[Filter Editor] Clear' } @@ -12,17 +11,10 @@ export class UpdateStatus implements Action { constructor(public payload: { [key: string]: string }) { } } -export class SelectFilterType implements Action { - readonly type = EditorActionTypes.SELECT_PROVIDER_TYPE; - - constructor(public payload: string) { } -} - export class ClearEditor implements Action { readonly type = EditorActionTypes.CLEAR; } export type EditorActionUnion = | UpdateStatus - | SelectFilterType | ClearEditor; diff --git a/ui/src/app/metadata/filter/action/filter.action.spec.ts b/ui/src/app/metadata/filter/action/filter.action.spec.ts index db844107e..921f12385 100644 --- a/ui/src/app/metadata/filter/action/filter.action.spec.ts +++ b/ui/src/app/metadata/filter/action/filter.action.spec.ts @@ -2,7 +2,7 @@ import { FilterActionTypes, CancelCreateFilter, SelectId } from './filter.action describe('Filter Actions', () => { it('should provide actions', () => { - expect(new CancelCreateFilter().type).toBe(FilterActionTypes.CANCEL_CREATE_FILTER); + expect(new CancelCreateFilter('id').type).toBe(FilterActionTypes.CANCEL_CREATE_FILTER); expect(new SelectId('foo').type).toBe(FilterActionTypes.SELECT_ID); }); }); diff --git a/ui/src/app/metadata/filter/container/edit-filter-step.component.ts b/ui/src/app/metadata/filter/container/edit-filter-step.component.ts index d09f78cbf..963add6bf 100644 --- a/ui/src/app/metadata/filter/container/edit-filter-step.component.ts +++ b/ui/src/app/metadata/filter/container/edit-filter-step.component.ts @@ -1,4 +1,4 @@ -import { Component, OnDestroy } from '@angular/core'; +import { ChangeDetectorRef, Component, OnDestroy } from '@angular/core'; import { Store } from '@ngrx/store'; import { Subject, Observable, Subscription } from 'rxjs'; @@ -8,9 +8,10 @@ import { MetadataFilter } from '../../domain/model'; import { SchemaService } from '../../../schema-form/service/schema.service'; import { UpdateFilterChanges } from '../action/filter.action'; import { PreviewEntity } from '../../domain/action/entity.action'; -import { shareReplay, map, withLatestFrom, filter, switchMap, takeUntil } from 'rxjs/operators'; +import { map, withLatestFrom, filter, takeUntil, distinctUntilChanged, skip } from 'rxjs/operators'; import * as fromWizard from '../../../wizard/reducer'; import { LockEditor, UnlockEditor } from '../../../wizard/action/wizard.action'; +import { UpdateStatus } from '../action/editor.action'; @Component({ selector: 'edit-filter-step-page', @@ -44,12 +45,13 @@ export class EditFilterStepComponent implements OnDestroy { actions: any; defSub: Subscription; + currentPage: string; constructor( private store: Store, - private schemaService: SchemaService + private ref: ChangeDetectorRef ) { - this.definition$ = this.store.select(fromWizard.getWizardDefinition).pipe(filter(d => !!d)) + this.definition$ = this.store.select(fromWizard.getWizardDefinition).pipe(filter(d => !!d)); this.defSub = this.definition$.subscribe(d => this.definition = d); @@ -70,13 +72,29 @@ export class EditFilterStepComponent implements OnDestroy { this.model$ = this.store.select(fromFilter.getSelectedFilter); this.type$ = this.model$.pipe(map(f => f && f.hasOwnProperty('@type') ? f['@type'] : '')); - this.valueChangeEmitted$.subscribe(changes => this.store.dispatch(new UpdateFilterChanges(changes.value))); - this.statusChangeEmitted$.subscribe(valid => { - this.isValid = valid.value ? valid.value.length === 0 : true; - }); + this.valueChangeEmitted$.pipe(takeUntil(this.ngUnsubscribe)).subscribe(changes => this.store.dispatch(new UpdateFilterChanges(changes.value))); + + this.statusChangeEmitted$ + .pipe( + skip(1), + takeUntil(this.ngUnsubscribe), + withLatestFrom(this.model$), + distinctUntilChanged() + ) + .subscribe(([errors, model]) => { + this.updateStatus(errors); + }); this.status$ = this.store.select(fromFilter.getInvalidEditorForms); + this.status$.pipe(takeUntil(this.ngUnsubscribe)).subscribe(() => { + this.ref.detach(); + setTimeout(() => { + this.ref.detectChanges(); + this.ref.reattach(); + }, 250); + }) + this.validators$ = this.store.select(fromFilter.getFilterNames).pipe( takeUntil(this.ngUnsubscribe), withLatestFrom( @@ -90,6 +108,7 @@ export class EditFilterStepComponent implements OnDestroy { this.store .select(fromFilter.getFilter) + .pipe(takeUntil(this.ngUnsubscribe)) .subscribe(filter => this.filter = filter); this.actions = { @@ -97,6 +116,13 @@ export class EditFilterStepComponent implements OnDestroy { this.preview(parameters.filterId); } }; + + this.store.select(fromWizard.getWizardIndex).pipe(takeUntil(this.ngUnsubscribe)).subscribe(i => this.currentPage = i); + } + + updateStatus(errors: any): void { + const status = { [this.currentPage]: !(errors.value) ? 'VALID' : 'INVALID' }; + this.store.dispatch(new UpdateStatus(status)); } ngOnDestroy(): void { diff --git a/ui/src/app/metadata/filter/container/edit-filter.component.html b/ui/src/app/metadata/filter/container/edit-filter.component.html index c003e2ddf..fa9e113b5 100644 --- a/ui/src/app/metadata/filter/container/edit-filter.component.html +++ b/ui/src/app/metadata/filter/container/edit-filter.component.html @@ -22,20 +22,18 @@
- - -   - - + +   +

diff --git a/ui/src/app/metadata/filter/container/edit-filter.component.ts b/ui/src/app/metadata/filter/container/edit-filter.component.ts index 6eb9e7908..9f6bbfba7 100644 --- a/ui/src/app/metadata/filter/container/edit-filter.component.ts +++ b/ui/src/app/metadata/filter/container/edit-filter.component.ts @@ -1,6 +1,6 @@ import { Component, OnDestroy } from '@angular/core'; import { Store } from '@ngrx/store'; -import { Subject, Observable, Subscription } from 'rxjs'; +import { Subject, Observable, Subscription, combineLatest } from 'rxjs'; import * as fromFilter from '../reducer'; import { FormDefinition } from '../../../wizard/model'; @@ -9,7 +9,7 @@ import { UpdateFilterRequest } from '../action/collection.action'; import { CancelCreateFilter } from '../action/filter.action'; import { PreviewEntity } from '../../domain/action/entity.action'; import { NAV_FORMATS } from '../../domain/component/editor-nav.component'; -import { map, filter } from 'rxjs/operators'; +import { map, filter, takeUntil, withLatestFrom, skip } from 'rxjs/operators'; import * as fromWizard from '../../../wizard/reducer'; import { ActivatedRoute } from '@angular/router'; import { LoadSchemaRequest, SetIndex } from '../../../wizard/action/wizard.action'; @@ -31,6 +31,7 @@ export class EditFilterComponent implements OnDestroy { filter: MetadataFilter; isValid$: Observable; isInvalid$: Observable; + cantSave$: Observable; type$: Observable; status$: Observable; @@ -40,6 +41,7 @@ export class EditFilterComponent implements OnDestroy { defSub: Subscription; formats = NAV_FORMATS; + currentPage constructor( private store: Store, @@ -52,7 +54,7 @@ export class EditFilterComponent implements OnDestroy { this.store .select(fromWizard.getCurrentWizardSchema) - .pipe(filter(s => !!s)) + .pipe(filter(s => !!s), takeUntil(this.ngUnsubscribe)) .subscribe(s => { if (s) { this.store.dispatch(new LoadSchemaRequest(s)); @@ -61,7 +63,6 @@ export class EditFilterComponent implements OnDestroy { let startIndex$ = this.route.firstChild.params.pipe(map(p => p.form || 'filters')); startIndex$.subscribe(index => this.store.dispatch(new SetIndex(index))); - this.isSaving$ = this.store.select(fromFilter.getCollectionSaving); this.model$ = this.store.select(fromFilter.getSelectedFilter); @@ -69,8 +70,9 @@ export class EditFilterComponent implements OnDestroy { this.status$ = this.store.select(fromFilter.getInvalidEditorForms); - this.isValid$ = this.store.select(fromFilter.getEditorIsValid); + this.isValid$ = this.store.select(fromFilter.getFilterIsValid); this.isInvalid$ = this.isValid$.pipe(map(v => !v)); + this.cantSave$ = this.store.select(fromFilter.cantSaveFilter).pipe(skip(1)); this.store .select(fromFilter.getFilter) @@ -96,7 +98,8 @@ export class EditFilterComponent implements OnDestroy { })); } - cancel(): void { + cancel(event: MouseEvent): void { + event.preventDefault(); this.store.dispatch(new CancelCreateFilter(this.route.snapshot.params.providerId)); } diff --git a/ui/src/app/metadata/filter/container/new-filter-step.component.html b/ui/src/app/metadata/filter/container/new-filter-step.component.html new file mode 100644 index 000000000..f8d748c37 --- /dev/null +++ b/ui/src/app/metadata/filter/container/new-filter-step.component.html @@ -0,0 +1,15 @@ + +
+ + + {{ lock.value ? 'Locked' : 'Unlocked' }} + + For Advanced Knowledge Only +
+ +
\ No newline at end of file diff --git a/ui/src/app/metadata/filter/container/new-filter-step.component.ts b/ui/src/app/metadata/filter/container/new-filter-step.component.ts new file mode 100644 index 000000000..a927b5d8c --- /dev/null +++ b/ui/src/app/metadata/filter/container/new-filter-step.component.ts @@ -0,0 +1,104 @@ +import { Component, OnDestroy, OnInit } from '@angular/core'; +import { Store } from '@ngrx/store'; +import { FormBuilder } from '@angular/forms'; +import { Subject, Observable } from 'rxjs'; + +import { takeUntil, shareReplay, withLatestFrom, map, switchMap, filter, distinctUntilChanged } from 'rxjs/operators'; + + +import * as fromFilter from '../reducer'; +import { FormDefinition, WizardStep } from '../../../wizard/model'; +import { MetadataFilter } from '../../domain/model'; +import { SchemaService } from '../../../schema-form/service/schema.service'; +import { UpdateFilterChanges } from '../action/filter.action'; +import { ActivatedRoute } from '@angular/router'; +import * as fromWizard from '../../../wizard/reducer'; +import { SetIndex } from '../../../wizard/action/wizard.action'; +import { UpdateStatus } from '../action/editor.action'; + +@Component({ + selector: 'new-filter-step-page', + templateUrl: './new-filter-step.component.html' +}) +export class NewFilterStepComponent implements OnDestroy, OnInit { + + private ngUnsubscribe: Subject = new Subject(); + + valueChangeSubject = new Subject>(); + private valueChangeEmitted$ = this.valueChangeSubject.asObservable(); + + statusChangeSubject = new Subject<{ value: any[] }>(); + private statusChangeEmitted$ = this.statusChangeSubject.asObservable(); + + definition$: Observable>; + schema$: Observable; + + changes$: Observable; + isSaving$: Observable; + filter: MetadataFilter; + + validators$: Observable<{ [key: string]: any }>; + + options$: Observable[]>; + + step$: Observable; + + currentPage: string; + + constructor( + private store: Store, + private schemaService: SchemaService, + private fb: FormBuilder, + private route: ActivatedRoute + ) { + this.isSaving$ = this.store.select(fromFilter.getCollectionSaving); + this.changes$ = this.store.select(fromFilter.getFilter); + this.step$ = this.store.select(fromWizard.getCurrent); + this.definition$ = this.store.select(fromWizard.getWizardDefinition).pipe(filter(d => !!d)); + this.schema$ = this.store.select(fromWizard.getSchema); + + this.validators$ = this.definition$.pipe( + takeUntil(this.ngUnsubscribe), + withLatestFrom(this.store.select(fromFilter.getFilterNames)), + map(([definition, names]) => definition.getValidators(names)) + ); + + let startIndex$ = this.route.params.pipe(map(p => p.form || 'filters')); + startIndex$.subscribe(index => this.store.dispatch(new SetIndex(index))); + } + + ngOnInit(): void { + this.valueChangeEmitted$ + .pipe(takeUntil(this.ngUnsubscribe)) + .subscribe(changes => this.store.dispatch(new UpdateFilterChanges(changes.value))); + this.statusChangeEmitted$ + .pipe( + takeUntil(this.ngUnsubscribe), + distinctUntilChanged() + ) + .subscribe(errors => { + this.updateStatus(errors); + }); + + this.store + .select(fromFilter.getFilter) + .pipe( + takeUntil(this.ngUnsubscribe), + withLatestFrom(this.definition$), + map(([filter, definition]) => definition.parser(filter)) + ) + .subscribe(filter => this.filter = filter); + + this.store.select(fromWizard.getWizardIndex).subscribe(i => this.currentPage = i); + } + + updateStatus(errors: any): void { + const status = { [this.currentPage]: !(errors.value) ? 'VALID' : 'INVALID' }; + this.store.dispatch(new UpdateStatus(status)); + } + + ngOnDestroy(): void { + this.ngUnsubscribe.next(); + this.ngUnsubscribe.complete(); + } +} diff --git a/ui/src/app/metadata/filter/container/new-filter.component.html b/ui/src/app/metadata/filter/container/new-filter.component.html index a30cb77fc..3976b1ff9 100644 --- a/ui/src/app/metadata/filter/container/new-filter.component.html +++ b/ui/src/app/metadata/filter/container/new-filter.component.html @@ -12,9 +12,9 @@
-
+
-
+
-
- - -   - - +
+ +   +
-
- +
+
+
+ + +
+
+ +
diff --git a/ui/src/app/metadata/filter/container/new-filter.component.ts b/ui/src/app/metadata/filter/container/new-filter.component.ts index 785473738..51907707a 100644 --- a/ui/src/app/metadata/filter/container/new-filter.component.ts +++ b/ui/src/app/metadata/filter/container/new-filter.component.ts @@ -1,20 +1,19 @@ import { Component, OnDestroy, OnInit } from '@angular/core'; import { Store } from '@ngrx/store'; import { Validators, FormBuilder, FormGroup } from '@angular/forms'; -import { Subject, Observable, of } from 'rxjs'; - -import { takeUntil, shareReplay, withLatestFrom, map, switchMap, filter, startWith, distinctUntilChanged, share } from 'rxjs/operators'; - +import { Subject, Observable, of, combineLatest } from 'rxjs'; +import { ActivatedRoute } from '@angular/router'; +import { takeUntil, withLatestFrom, map, filter, distinctUntilChanged, skip } from 'rxjs/operators'; import * as fromFilter from '../reducer'; -import { MetadataFilterTypes } from '../model'; +import { MetadataFilterEditorTypes, MetadataFilterTypes } from '../model'; import { FormDefinition } from '../../../wizard/model'; import { MetadataFilter } from '../../domain/model'; -import { SchemaService } from '../../../schema-form/service/schema.service'; import { AddFilterRequest } from '../action/collection.action'; -import { CancelCreateFilter, UpdateFilterChanges, SelectFilterType } from '../action/filter.action'; -import { ActivatedRoute } from '@angular/router'; - +import { CancelCreateFilter, SelectFilterType } from '../action/filter.action'; +import * as fromWizard from '../../../wizard/reducer'; +import { LoadSchemaRequest, SetDefinition, SetIndex } from '../../../wizard/action/wizard.action'; +import { NAV_FORMATS } from '../../domain/component/editor-nav.component'; @Component({ selector: 'new-filter-page', @@ -24,20 +23,14 @@ export class NewFilterComponent implements OnDestroy, OnInit { private ngUnsubscribe: Subject = new Subject(); - valueChangeSubject = new Subject>(); - private valueChangeEmitted$ = this.valueChangeSubject.asObservable(); - - statusChangeSubject = new Subject<{ value: any[] }>(); - private statusChangeEmitted$ = this.statusChangeSubject.asObservable(); - definition$: Observable>; schema$: Observable; - changes$: Observable; - model: any; isSaving$: Observable; filter: MetadataFilter; - isValid: boolean; + isValid$: Observable; + isInvalid$: Observable; + cantSave$: Observable; validators$: Observable<{ [key: string]: any }>; @@ -47,17 +40,22 @@ export class NewFilterComponent implements OnDestroy, OnInit { options$: Observable[]>; + formats = NAV_FORMATS; + + status$: Observable; + + type$: Observable = this.store.select(fromFilter.getFilterType); + constructor( private store: Store, - private schemaService: SchemaService, private fb: FormBuilder, private route: ActivatedRoute ) { this.isSaving$ = this.store.select(fromFilter.getCollectionSaving); + this.isValid$ = this.store.select(fromFilter.getFilterIsValid); + this.isInvalid$ = this.isValid$.pipe(map(v => !v)); - this.changes$ = this.store.select(fromFilter.getFilter); - - this.model = {}; + this.cantSave$ = this.store.select(fromFilter.cantSaveFilter).pipe(skip(1)); this.definition$ = this.store.select(fromFilter.getFilterType).pipe( takeUntil(this.ngUnsubscribe), @@ -65,21 +63,19 @@ export class NewFilterComponent implements OnDestroy, OnInit { map(t => MetadataFilterTypes[t]) ); - this.schema$ = this.definition$.pipe( - takeUntil(this.ngUnsubscribe), - filter(d => !!d), - switchMap(d => { - return this.schemaService.get(d.schema).pipe(takeUntil(this.ngUnsubscribe)); - }), - shareReplay() - ); + this.store + .select(fromWizard.getCurrentWizardSchema) + .pipe(filter(s => !!s), takeUntil(this.ngUnsubscribe)) + .subscribe(s => { + if (s) { + this.store.dispatch(new LoadSchemaRequest(s)); + } + }); - this.validators$ = this.definition$.pipe( - takeUntil(this.ngUnsubscribe), - withLatestFrom(this.store.select(fromFilter.getFilterNames)), - map(([definition, names]) => definition.getValidators(names)) - ); + let startIndex$ = this.route.params.pipe(map(p => p.form || 'filters'), takeUntil(this.ngUnsubscribe)); + startIndex$.subscribe(index => this.store.dispatch(new SetIndex(index))); + this.status$ = this.store.select(fromFilter.getInvalidEditorForms); this.options$ = of(Object.values(MetadataFilterTypes)); this.form.get('type').valueChanges @@ -87,19 +83,22 @@ export class NewFilterComponent implements OnDestroy, OnInit { takeUntil(this.ngUnsubscribe), distinctUntilChanged() ) - .subscribe(type => this.store.dispatch(new SelectFilterType(type))); + .subscribe(type => { + this.store.dispatch(new SelectFilterType(type)); + }); + + this.type$.pipe( + takeUntil(this.ngUnsubscribe) + ).subscribe((t: string) => { + if (t) { + this.store.dispatch(new SetDefinition({ + ...MetadataFilterEditorTypes.find(def => def.type === t) + })); + } + }); } ngOnInit(): void { - this.valueChangeEmitted$ - .pipe(takeUntil(this.ngUnsubscribe)) - .subscribe(changes => this.store.dispatch(new UpdateFilterChanges(changes.value))); - this.statusChangeEmitted$ - .pipe(takeUntil(this.ngUnsubscribe)) - .subscribe(valid => { - this.isValid = valid.value ? valid.value.length === 0 : true; - }); - this.store .select(fromFilter.getFilter) .pipe( @@ -116,7 +115,10 @@ export class NewFilterComponent implements OnDestroy, OnInit { } save(): void { - this.store.dispatch(new AddFilterRequest(this.filter)); + this.store.dispatch(new AddFilterRequest({ + filter: this.filter, + providerId: this.route.snapshot.params.providerId + })); } cancel(): void { diff --git a/ui/src/app/metadata/filter/effect/collection.effect.ts b/ui/src/app/metadata/filter/effect/collection.effect.ts index 9e15e691c..db94eacaf 100644 --- a/ui/src/app/metadata/filter/effect/collection.effect.ts +++ b/ui/src/app/metadata/filter/effect/collection.effect.ts @@ -90,12 +90,14 @@ export class FilterCollectionEffects { addFilter$ = this.actions$.pipe( ofType(FilterCollectionActionTypes.ADD_FILTER_REQUEST), map(action => action.payload), - withLatestFrom(this.store.select(fromProvider.getSelectedProviderId).pipe(skipWhile(id => !id))), - switchMap(([unsaved, providerId]) => { + switchMap(({filter, providerId}) => { return this.filterService - .save(providerId, unsaved as MetadataFilter) + .save(providerId, filter as MetadataFilter) .pipe( - map(saved => new AddFilterSuccess(saved)), + map(saved => new AddFilterSuccess({ + filter: saved, + providerId: providerId + })), catchError(error => of(new AddFilterFail(error))) ); }) @@ -104,16 +106,14 @@ export class FilterCollectionEffects { addFilterSuccessRedirect$ = this.actions$.pipe( ofType(FilterCollectionActionTypes.ADD_FILTER_SUCCESS), map(action => action.payload), - withLatestFrom(this.store.select(fromProvider.getSelectedProviderId).pipe(skipWhile(id => !id))), - tap(([filter, provider]) => this.navigateToParent(provider)) + tap(({ providerId }) => this.navigateToParent(providerId)) ); @Effect() addFilterSuccessReloadParent$ = this.actions$.pipe( ofType(FilterCollectionActionTypes.ADD_FILTER_SUCCESS), map(action => action.payload), - withLatestFrom(this.store.select(fromProvider.getSelectedProviderId).pipe(skipWhile(id => !id))), - map(([filter, provider]) => new SelectProviderRequest(provider)) + map(({ providerId }) => new SelectProviderRequest(providerId)) ); @Effect() diff --git a/ui/src/app/metadata/filter/effect/filter.effect.ts b/ui/src/app/metadata/filter/effect/filter.effect.ts index 65c5f8e89..2bdc60bc9 100644 --- a/ui/src/app/metadata/filter/effect/filter.effect.ts +++ b/ui/src/app/metadata/filter/effect/filter.effect.ts @@ -65,6 +65,7 @@ export class FilterEffects { @Effect({ dispatch: false }) cancelChanges$ = this.actions$.pipe( ofType(FilterActionTypes.CANCEL_CREATE_FILTER), + map(action => action.payload), tap((providerId) => { this.router.navigate(['/', 'metadata', 'provider', providerId, 'configuration']); }) diff --git a/ui/src/app/metadata/filter/filter.module.ts b/ui/src/app/metadata/filter/filter.module.ts index 6514b5a06..e7c3bfcff 100644 --- a/ui/src/app/metadata/filter/filter.module.ts +++ b/ui/src/app/metadata/filter/filter.module.ts @@ -24,10 +24,12 @@ import { I18nModule } from '../../i18n/i18n.module'; import { FilterComponent } from './container/filter.component'; import { FilterListComponent } from './component/filter-list.component'; import { EditFilterStepComponent } from './container/edit-filter-step.component'; +import { NewFilterStepComponent } from './container/new-filter-step.component'; @NgModule({ declarations: [ NewFilterComponent, + NewFilterStepComponent, EditFilterComponent, EditFilterStepComponent, SelectFilterComponent, diff --git a/ui/src/app/metadata/filter/model/nameid-configuration.filter.ts b/ui/src/app/metadata/filter/model/nameid-configuration.filter.ts index 4ff615ac6..5520f4919 100644 --- a/ui/src/app/metadata/filter/model/nameid-configuration.filter.ts +++ b/ui/src/app/metadata/filter/model/nameid-configuration.filter.ts @@ -6,10 +6,14 @@ export const NameIDFilterConfiguration: Wizard = { ...NameIDFilter, steps: [ { - id: 'target', + id: 'common', label: 'label.target', index: 1, fields: [ + 'name', + 'filterEnabled', + '@type', + 'resourceId', 'nameIdFormatFilterTarget' ] }, @@ -19,10 +23,6 @@ export const NameIDFilterConfiguration: Wizard = { index: 1, initialValues: [], fields: [ - 'name', - 'filterEnabled', - '@type', - 'resourceId', 'removeExistingFormats', 'formats' ] diff --git a/ui/src/app/metadata/filter/reducer/editor.reducer.ts b/ui/src/app/metadata/filter/reducer/editor.reducer.ts index 0d56550b7..dcb0620f4 100644 --- a/ui/src/app/metadata/filter/reducer/editor.reducer.ts +++ b/ui/src/app/metadata/filter/reducer/editor.reducer.ts @@ -2,28 +2,21 @@ import { EditorActionTypes, EditorActionUnion } from '../action/editor.action'; export interface EditorState { status: { [key: string]: string }; - type: string; } export const initialState: EditorState = { - status: {}, - type: null + status: {} }; export function reducer(state = initialState, action: EditorActionUnion): EditorState { switch (action.type) { - case EditorActionTypes.SELECT_PROVIDER_TYPE: { - return { - ...state, - type: action.payload - }; - } case EditorActionTypes.CLEAR: { return { ...initialState }; } case EditorActionTypes.UPDATE_STATUS: { + //console.log(action) return { ...state, status: { diff --git a/ui/src/app/metadata/filter/reducer/filter.reducer.ts b/ui/src/app/metadata/filter/reducer/filter.reducer.ts index 68aaf40ed..bda4668ca 100644 --- a/ui/src/app/metadata/filter/reducer/filter.reducer.ts +++ b/ui/src/app/metadata/filter/reducer/filter.reducer.ts @@ -39,13 +39,14 @@ export function reducer(state = initialState, action: FilterActionsUnion): Filte }; } case FilterActionTypes.UPDATE_FILTER: { - return { + const s = { ...state, changes: { ...state.changes, ...action.payload } }; + return s; } case FilterActionTypes.CLEAR_FILTER: case FilterActionTypes.CANCEL_CREATE_FILTER: { diff --git a/ui/src/app/metadata/filter/reducer/index.ts b/ui/src/app/metadata/filter/reducer/index.ts index 71d71707e..ee2da9bf3 100644 --- a/ui/src/app/metadata/filter/reducer/index.ts +++ b/ui/src/app/metadata/filter/reducer/index.ts @@ -85,10 +85,10 @@ Editor State */ export const getEditorIsValid = createSelector(getEditorState, fromEditor.isEditorValid); - export const getFormStatus = createSelector(getEditorState, fromEditor.getFormStatus); export const getInvalidEditorForms = createSelector(getEditorState, fromEditor.getInvalidForms); + /* * Combine pieces of State */ @@ -97,8 +97,12 @@ export const mergeFn = (changes, filter) => ({ ...filter, ...changes }); export const detectFilterType = (changes) => changes.type ? changes.type : changes.hasOwnProperty('@type') ? changes['@type'] : null; export const getFilterWithChanges = createSelector(getFilter, getSelectedFilter, mergeFn); -export const getFilterType = createSelector(getFilter, (changes: MetadataFilter) => { - const type = changes ? detectFilterType(changes) : null; - return type; +export const getFilterType = createSelector(getFilter, (changes: MetadataFilter) => changes ? detectFilterType(changes) : null); + +export const getFilterIsValid = createSelector(getEditorIsValid, getFilterType, getFormStatus, (isValid, type, status) => { + return isValid && type !== null && Object.keys(status).length > 0; }); +export const cantSaveFilter = createSelector(getCollectionSaving, getFilterIsValid, (isSaving, isValid) => { + return (isSaving || !isValid); +}); \ No newline at end of file diff --git a/ui/src/app/metadata/provider/container/provider-select.component.ts b/ui/src/app/metadata/provider/container/provider-select.component.ts index 160ad8332..6e300d302 100644 --- a/ui/src/app/metadata/provider/container/provider-select.component.ts +++ b/ui/src/app/metadata/provider/container/provider-select.component.ts @@ -37,7 +37,6 @@ export class ProviderSelectComponent implements OnDestroy { this.providerSubscription = this.provider$.subscribe(provider => { this.setDefinition(provider); }); - console.log('hi there') } setDefinition(provider: MetadataProvider): void { diff --git a/ui/src/app/metadata/provider/provider.routing.ts b/ui/src/app/metadata/provider/provider.routing.ts index 975b9b427..635edc45f 100644 --- a/ui/src/app/metadata/provider/provider.routing.ts +++ b/ui/src/app/metadata/provider/provider.routing.ts @@ -14,6 +14,7 @@ import { CanDeactivateGuard } from '../../core/service/can-deactivate.guard'; import { FilterComponent } from '../filter/container/filter.component'; import { AdminGuard } from '../../core/service/admin.guard'; import { MetadataProviderPageComponent } from './provider.component'; +import { NewFilterStepComponent } from '../filter/container/new-filter-step.component'; export const ProviderRoutes: Routes = [ { @@ -33,7 +34,7 @@ export const ProviderRoutes: Routes = [ { path: 'new', component: ProviderWizardStepComponent, - data: { title: `Create Provider`, subtitle: true } + data: { title: `Create Provider`, subtitle: true }, } ] }, @@ -70,7 +71,15 @@ export const ProviderRoutes: Routes = [ { path: 'new', component: NewFilterComponent, - data: { title: `Create New Filter` } + data: { title: `Create New Filter` }, + children: [ + { path: '', redirectTo: 'common', pathMatch: 'prefix' }, + { + path: ':form', + component: NewFilterStepComponent, + data: { title: `Create Filter`, subtitle: true } + } + ] }, { path: ':filterId', From af8c08a3c21bbadbfa9086ad87ea753667df4307 Mon Sep 17 00:00:00 2001 From: Ryan Mathis Date: Wed, 17 Mar 2021 14:37:59 -0700 Subject: [PATCH 10/26] fixed test --- ui/karma.conf.js | 6 +- ui/package-lock.json | 213 +++++++----------- ui/package.json | 2 +- .../container/edit-filter.component.html | 4 +- .../container/edit-filter.component.spec.ts | 40 ++-- .../filter/container/edit-filter.component.ts | 13 +- .../container/new-filter.component.spec.ts | 39 ++-- .../filter/reducer/collection.reducer.spec.ts | 20 +- .../filter/reducer/filter.reducer.spec.ts | 2 +- .../filter/reducer/search.reducer.spec.ts | 10 +- ui/src/testing/activated-route.stub.ts | 3 + 11 files changed, 152 insertions(+), 200 deletions(-) diff --git a/ui/karma.conf.js b/ui/karma.conf.js index b69d2eda1..347949dd4 100644 --- a/ui/karma.conf.js +++ b/ui/karma.conf.js @@ -10,14 +10,14 @@ module.exports = function (config) { require('karma-jasmine'), require('karma-chrome-launcher'), require('karma-jasmine-html-reporter'), - require('karma-coverage-istanbul-reporter'), + require('karma-coverage'), require('karma-spec-reporter'), require('@angular-devkit/build-angular/plugins/karma') ], client: { clearContext: false // leave Jasmine Spec Runner output visible in browser }, - coverageIstanbulReporter: { + coverageReporter: { dir: require('path').join(__dirname, 'coverage'), reports: ['html', 'lcovonly', 'text-summary'], fixWebpackSourcePaths: true, skipFilesWithNoCoverage: false, @@ -41,7 +41,7 @@ module.exports = function (config) { angularCli: { environment: 'dev' }, - reporters: ['spec', 'coverage-istanbul'], + reporters: ['spec', 'coverage'], port: 9876, colors: true, logLevel: config.LOG_WARN, diff --git a/ui/package-lock.json b/ui/package-lock.json index 922d700dd..12b4ccd70 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -1323,7 +1323,6 @@ "version": "7.12.10", "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.12.10.tgz", "integrity": "sha512-eTAlQKq65zHfkHZV0sIVODCPGVgoo1HdBlbSLi9CqOzuZanMv2ihzY+4paiKr1mH+XmYESMAmJ/dpZ68eN6d8w==", - "dev": true, "requires": { "@babel/code-frame": "^7.10.4", "@babel/generator": "^7.12.10", @@ -1346,7 +1345,6 @@ "version": "7.12.11", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==", - "dev": true, "requires": { "@babel/highlight": "^7.10.4" } @@ -1355,7 +1353,6 @@ "version": "7.12.11", "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.12.11.tgz", "integrity": "sha512-Ggg6WPOJtSi8yYQvLVjG8F/TlpWDlKx0OpS4Kt+xMQPs5OaGYWy+v1A+1TvxI6sAMGZpKWWoAQ1DaeQbImlItA==", - "dev": true, "requires": { "@babel/types": "^7.12.11", "jsesc": "^2.5.1", @@ -1366,7 +1363,6 @@ "version": "7.12.11", "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.12.11.tgz", "integrity": "sha512-AtQKjtYNolKNi6nNNVLQ27CP6D9oFR6bq/HPYSizlzbp7uC1M59XJe8L+0uXjbIaZaUJF99ruHqVGiKXU/7ybA==", - "dev": true, "requires": { "@babel/helper-get-function-arity": "^7.12.10", "@babel/template": "^7.12.7", @@ -1377,7 +1373,6 @@ "version": "7.12.10", "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.12.10.tgz", "integrity": "sha512-mm0n5BPjR06wh9mPQaDdXWDoll/j5UpCAPl1x8fS71GHm7HA6Ua2V4ylG1Ju8lvcTOietbPNNPaSilKj+pj+Ag==", - "dev": true, "requires": { "@babel/types": "^7.12.10" } @@ -1386,7 +1381,6 @@ "version": "7.12.11", "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.12.11.tgz", "integrity": "sha512-LsIVN8j48gHgwzfocYUSkO/hjYAOJqlpJEc7tGXcIm4cubjVUf8LGW6eWRyxEu7gA25q02p0rQUWoCI33HNS5g==", - "dev": true, "requires": { "@babel/types": "^7.12.11" } @@ -1395,7 +1389,6 @@ "version": "7.10.4", "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.4.tgz", "integrity": "sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA==", - "dev": true, "requires": { "@babel/helper-validator-identifier": "^7.10.4", "chalk": "^2.0.0", @@ -1405,14 +1398,12 @@ "@babel/parser": { "version": "7.12.11", "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.12.11.tgz", - "integrity": "sha512-N3UxG+uuF4CMYoNj8AhnbAcJF0PiuJ9KHuy1lQmkYsxTer/MAH9UBNHsBoAX/4s6NvlDD047No8mYVGGzLL4hg==", - "dev": true + "integrity": "sha512-N3UxG+uuF4CMYoNj8AhnbAcJF0PiuJ9KHuy1lQmkYsxTer/MAH9UBNHsBoAX/4s6NvlDD047No8mYVGGzLL4hg==" }, "@babel/template": { "version": "7.12.7", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.12.7.tgz", "integrity": "sha512-GkDzmHS6GV7ZeXfJZ0tLRBhZcMcY0/Lnb+eEbXDBfCAcZCjrZKe6p3J4we/D24O9Y8enxWAg1cWwof59yLh2ow==", - "dev": true, "requires": { "@babel/code-frame": "^7.10.4", "@babel/parser": "^7.12.7", @@ -1423,7 +1414,6 @@ "version": "7.12.12", "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.12.12.tgz", "integrity": "sha512-s88i0X0lPy45RrLM8b9mz8RPH5FqO9G9p7ti59cToE44xFm1Q+Pjh5Gq4SXBbtb88X7Uy7pexeqRIQDDMNkL0w==", - "dev": true, "requires": { "@babel/code-frame": "^7.12.11", "@babel/generator": "^7.12.11", @@ -1440,7 +1430,6 @@ "version": "7.12.12", "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.12.tgz", "integrity": "sha512-lnIX7piTxOH22xE7fDXDbSHg9MM1/6ORnafpJmov5rs0kX5g4BZxeXNJLXsMRiO0U5Rb8/FvMS6xlTnTHvxonQ==", - "dev": true, "requires": { "@babel/helper-validator-identifier": "^7.12.11", "lodash": "^4.17.19", @@ -1451,7 +1440,6 @@ "version": "1.7.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.7.0.tgz", "integrity": "sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA==", - "dev": true, "requires": { "safe-buffer": "~5.1.1" } @@ -1460,7 +1448,6 @@ "version": "4.3.1", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", - "dev": true, "requires": { "ms": "2.1.2" } @@ -1468,14 +1455,12 @@ "jsesc": { "version": "2.5.2", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", - "dev": true + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==" }, "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" } } }, @@ -1882,7 +1867,6 @@ "version": "7.12.7", "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.12.7.tgz", "integrity": "sha512-DCsuPyeWxeHgh1Dus7APn7iza42i/qXqiFPWyBDdOFtvS581JQePsc1F/nD+fHrcswhLlRc2UpYS1NwERxZhHw==", - "dev": true, "requires": { "@babel/types": "^7.12.7" }, @@ -1891,7 +1875,6 @@ "version": "7.12.12", "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.12.tgz", "integrity": "sha512-lnIX7piTxOH22xE7fDXDbSHg9MM1/6ORnafpJmov5rs0kX5g4BZxeXNJLXsMRiO0U5Rb8/FvMS6xlTnTHvxonQ==", - "dev": true, "requires": { "@babel/helper-validator-identifier": "^7.12.11", "lodash": "^4.17.19", @@ -1904,7 +1887,6 @@ "version": "7.12.5", "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.12.5.tgz", "integrity": "sha512-SR713Ogqg6++uexFRORf/+nPXMmWIn80TALu0uaFb+iQIUoR7bOC7zBWyzBs5b3tBBJXuyD0cRu1F15GyzjOWA==", - "dev": true, "requires": { "@babel/types": "^7.12.5" }, @@ -1913,7 +1895,6 @@ "version": "7.12.12", "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.12.tgz", "integrity": "sha512-lnIX7piTxOH22xE7fDXDbSHg9MM1/6ORnafpJmov5rs0kX5g4BZxeXNJLXsMRiO0U5Rb8/FvMS6xlTnTHvxonQ==", - "dev": true, "requires": { "@babel/helper-validator-identifier": "^7.12.11", "lodash": "^4.17.19", @@ -1926,7 +1907,6 @@ "version": "7.12.1", "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.12.1.tgz", "integrity": "sha512-QQzehgFAZ2bbISiCpmVGfiGux8YVFXQ0abBic2Envhej22DVXV9nCFaS5hIQbkyo1AdGb+gNME2TSh3hYJVV/w==", - "dev": true, "requires": { "@babel/helper-module-imports": "^7.12.1", "@babel/helper-replace-supers": "^7.12.1", @@ -1943,7 +1923,6 @@ "version": "7.12.11", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==", - "dev": true, "requires": { "@babel/highlight": "^7.10.4" } @@ -1952,7 +1931,6 @@ "version": "7.12.11", "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.12.11.tgz", "integrity": "sha512-Ggg6WPOJtSi8yYQvLVjG8F/TlpWDlKx0OpS4Kt+xMQPs5OaGYWy+v1A+1TvxI6sAMGZpKWWoAQ1DaeQbImlItA==", - "dev": true, "requires": { "@babel/types": "^7.12.11", "jsesc": "^2.5.1", @@ -1963,7 +1941,6 @@ "version": "7.12.11", "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.12.11.tgz", "integrity": "sha512-AtQKjtYNolKNi6nNNVLQ27CP6D9oFR6bq/HPYSizlzbp7uC1M59XJe8L+0uXjbIaZaUJF99ruHqVGiKXU/7ybA==", - "dev": true, "requires": { "@babel/helper-get-function-arity": "^7.12.10", "@babel/template": "^7.12.7", @@ -1974,7 +1951,6 @@ "version": "7.12.10", "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.12.10.tgz", "integrity": "sha512-mm0n5BPjR06wh9mPQaDdXWDoll/j5UpCAPl1x8fS71GHm7HA6Ua2V4ylG1Ju8lvcTOietbPNNPaSilKj+pj+Ag==", - "dev": true, "requires": { "@babel/types": "^7.12.10" } @@ -1983,7 +1959,6 @@ "version": "7.12.11", "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.12.11.tgz", "integrity": "sha512-LsIVN8j48gHgwzfocYUSkO/hjYAOJqlpJEc7tGXcIm4cubjVUf8LGW6eWRyxEu7gA25q02p0rQUWoCI33HNS5g==", - "dev": true, "requires": { "@babel/types": "^7.12.11" } @@ -1992,7 +1967,6 @@ "version": "7.10.4", "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.4.tgz", "integrity": "sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA==", - "dev": true, "requires": { "@babel/helper-validator-identifier": "^7.10.4", "chalk": "^2.0.0", @@ -2002,14 +1976,12 @@ "@babel/parser": { "version": "7.12.11", "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.12.11.tgz", - "integrity": "sha512-N3UxG+uuF4CMYoNj8AhnbAcJF0PiuJ9KHuy1lQmkYsxTer/MAH9UBNHsBoAX/4s6NvlDD047No8mYVGGzLL4hg==", - "dev": true + "integrity": "sha512-N3UxG+uuF4CMYoNj8AhnbAcJF0PiuJ9KHuy1lQmkYsxTer/MAH9UBNHsBoAX/4s6NvlDD047No8mYVGGzLL4hg==" }, "@babel/template": { "version": "7.12.7", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.12.7.tgz", "integrity": "sha512-GkDzmHS6GV7ZeXfJZ0tLRBhZcMcY0/Lnb+eEbXDBfCAcZCjrZKe6p3J4we/D24O9Y8enxWAg1cWwof59yLh2ow==", - "dev": true, "requires": { "@babel/code-frame": "^7.10.4", "@babel/parser": "^7.12.7", @@ -2020,7 +1992,6 @@ "version": "7.12.12", "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.12.12.tgz", "integrity": "sha512-s88i0X0lPy45RrLM8b9mz8RPH5FqO9G9p7ti59cToE44xFm1Q+Pjh5Gq4SXBbtb88X7Uy7pexeqRIQDDMNkL0w==", - "dev": true, "requires": { "@babel/code-frame": "^7.12.11", "@babel/generator": "^7.12.11", @@ -2037,7 +2008,6 @@ "version": "7.12.12", "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.12.tgz", "integrity": "sha512-lnIX7piTxOH22xE7fDXDbSHg9MM1/6ORnafpJmov5rs0kX5g4BZxeXNJLXsMRiO0U5Rb8/FvMS6xlTnTHvxonQ==", - "dev": true, "requires": { "@babel/helper-validator-identifier": "^7.12.11", "lodash": "^4.17.19", @@ -2048,7 +2018,6 @@ "version": "4.3.1", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", - "dev": true, "requires": { "ms": "2.1.2" } @@ -2056,14 +2025,12 @@ "jsesc": { "version": "2.5.2", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", - "dev": true + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==" }, "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" } } }, @@ -2071,7 +2038,6 @@ "version": "7.12.10", "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.12.10.tgz", "integrity": "sha512-4tpbU0SrSTjjt65UMWSrUOPZTsgvPgGG4S8QSTNHacKzpS51IVWGDj0yCwyeZND/i+LSN2g/O63jEXEWm49sYQ==", - "dev": true, "requires": { "@babel/types": "^7.12.10" }, @@ -2080,7 +2046,6 @@ "version": "7.12.12", "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.12.tgz", "integrity": "sha512-lnIX7piTxOH22xE7fDXDbSHg9MM1/6ORnafpJmov5rs0kX5g4BZxeXNJLXsMRiO0U5Rb8/FvMS6xlTnTHvxonQ==", - "dev": true, "requires": { "@babel/helper-validator-identifier": "^7.12.11", "lodash": "^4.17.19", @@ -2123,7 +2088,6 @@ "version": "7.12.11", "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.12.11.tgz", "integrity": "sha512-q+w1cqmhL7R0FNzth/PLLp2N+scXEK/L2AHbXUyydxp828F4FEa5WcVoqui9vFRiHDQErj9Zof8azP32uGVTRA==", - "dev": true, "requires": { "@babel/helper-member-expression-to-functions": "^7.12.7", "@babel/helper-optimise-call-expression": "^7.12.10", @@ -2135,7 +2099,6 @@ "version": "7.12.11", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==", - "dev": true, "requires": { "@babel/highlight": "^7.10.4" } @@ -2144,7 +2107,6 @@ "version": "7.12.11", "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.12.11.tgz", "integrity": "sha512-Ggg6WPOJtSi8yYQvLVjG8F/TlpWDlKx0OpS4Kt+xMQPs5OaGYWy+v1A+1TvxI6sAMGZpKWWoAQ1DaeQbImlItA==", - "dev": true, "requires": { "@babel/types": "^7.12.11", "jsesc": "^2.5.1", @@ -2155,7 +2117,6 @@ "version": "7.12.11", "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.12.11.tgz", "integrity": "sha512-AtQKjtYNolKNi6nNNVLQ27CP6D9oFR6bq/HPYSizlzbp7uC1M59XJe8L+0uXjbIaZaUJF99ruHqVGiKXU/7ybA==", - "dev": true, "requires": { "@babel/helper-get-function-arity": "^7.12.10", "@babel/template": "^7.12.7", @@ -2166,7 +2127,6 @@ "version": "7.12.10", "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.12.10.tgz", "integrity": "sha512-mm0n5BPjR06wh9mPQaDdXWDoll/j5UpCAPl1x8fS71GHm7HA6Ua2V4ylG1Ju8lvcTOietbPNNPaSilKj+pj+Ag==", - "dev": true, "requires": { "@babel/types": "^7.12.10" } @@ -2175,7 +2135,6 @@ "version": "7.12.11", "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.12.11.tgz", "integrity": "sha512-LsIVN8j48gHgwzfocYUSkO/hjYAOJqlpJEc7tGXcIm4cubjVUf8LGW6eWRyxEu7gA25q02p0rQUWoCI33HNS5g==", - "dev": true, "requires": { "@babel/types": "^7.12.11" } @@ -2184,7 +2143,6 @@ "version": "7.10.4", "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.4.tgz", "integrity": "sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA==", - "dev": true, "requires": { "@babel/helper-validator-identifier": "^7.10.4", "chalk": "^2.0.0", @@ -2194,14 +2152,12 @@ "@babel/parser": { "version": "7.12.11", "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.12.11.tgz", - "integrity": "sha512-N3UxG+uuF4CMYoNj8AhnbAcJF0PiuJ9KHuy1lQmkYsxTer/MAH9UBNHsBoAX/4s6NvlDD047No8mYVGGzLL4hg==", - "dev": true + "integrity": "sha512-N3UxG+uuF4CMYoNj8AhnbAcJF0PiuJ9KHuy1lQmkYsxTer/MAH9UBNHsBoAX/4s6NvlDD047No8mYVGGzLL4hg==" }, "@babel/template": { "version": "7.12.7", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.12.7.tgz", "integrity": "sha512-GkDzmHS6GV7ZeXfJZ0tLRBhZcMcY0/Lnb+eEbXDBfCAcZCjrZKe6p3J4we/D24O9Y8enxWAg1cWwof59yLh2ow==", - "dev": true, "requires": { "@babel/code-frame": "^7.10.4", "@babel/parser": "^7.12.7", @@ -2212,7 +2168,6 @@ "version": "7.12.12", "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.12.12.tgz", "integrity": "sha512-s88i0X0lPy45RrLM8b9mz8RPH5FqO9G9p7ti59cToE44xFm1Q+Pjh5Gq4SXBbtb88X7Uy7pexeqRIQDDMNkL0w==", - "dev": true, "requires": { "@babel/code-frame": "^7.12.11", "@babel/generator": "^7.12.11", @@ -2229,7 +2184,6 @@ "version": "7.12.12", "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.12.tgz", "integrity": "sha512-lnIX7piTxOH22xE7fDXDbSHg9MM1/6ORnafpJmov5rs0kX5g4BZxeXNJLXsMRiO0U5Rb8/FvMS6xlTnTHvxonQ==", - "dev": true, "requires": { "@babel/helper-validator-identifier": "^7.12.11", "lodash": "^4.17.19", @@ -2240,7 +2194,6 @@ "version": "4.3.1", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", - "dev": true, "requires": { "ms": "2.1.2" } @@ -2248,14 +2201,12 @@ "jsesc": { "version": "2.5.2", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", - "dev": true + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==" }, "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" } } }, @@ -2263,7 +2214,6 @@ "version": "7.12.1", "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.12.1.tgz", "integrity": "sha512-OxBp7pMrjVewSSC8fXDFrHrBcJATOOFssZwv16F3/6Xtc138GHybBfPbm9kfiqQHKhYQrlamWILwlDCeyMFEaA==", - "dev": true, "requires": { "@babel/types": "^7.12.1" }, @@ -2272,7 +2222,6 @@ "version": "7.12.12", "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.12.tgz", "integrity": "sha512-lnIX7piTxOH22xE7fDXDbSHg9MM1/6ORnafpJmov5rs0kX5g4BZxeXNJLXsMRiO0U5Rb8/FvMS6xlTnTHvxonQ==", - "dev": true, "requires": { "@babel/helper-validator-identifier": "^7.12.11", "lodash": "^4.17.19", @@ -2328,8 +2277,7 @@ "@babel/helper-validator-identifier": { "version": "7.12.11", "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz", - "integrity": "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==", - "dev": true + "integrity": "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==" }, "@babel/helper-validator-option": { "version": "7.12.11", @@ -2481,7 +2429,6 @@ "version": "7.12.5", "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.12.5.tgz", "integrity": "sha512-lgKGMQlKqA8meJqKsW6rUnc4MdUk35Ln0ATDqdM1a/UpARODdI4j5Y5lVfUScnSNkJcdCRAaWkspykNoFg9sJA==", - "dev": true, "requires": { "@babel/template": "^7.10.4", "@babel/traverse": "^7.12.5", @@ -2492,7 +2439,6 @@ "version": "7.12.11", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==", - "dev": true, "requires": { "@babel/highlight": "^7.10.4" } @@ -2501,7 +2447,6 @@ "version": "7.12.11", "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.12.11.tgz", "integrity": "sha512-Ggg6WPOJtSi8yYQvLVjG8F/TlpWDlKx0OpS4Kt+xMQPs5OaGYWy+v1A+1TvxI6sAMGZpKWWoAQ1DaeQbImlItA==", - "dev": true, "requires": { "@babel/types": "^7.12.11", "jsesc": "^2.5.1", @@ -2512,7 +2457,6 @@ "version": "7.12.11", "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.12.11.tgz", "integrity": "sha512-AtQKjtYNolKNi6nNNVLQ27CP6D9oFR6bq/HPYSizlzbp7uC1M59XJe8L+0uXjbIaZaUJF99ruHqVGiKXU/7ybA==", - "dev": true, "requires": { "@babel/helper-get-function-arity": "^7.12.10", "@babel/template": "^7.12.7", @@ -2523,7 +2467,6 @@ "version": "7.12.10", "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.12.10.tgz", "integrity": "sha512-mm0n5BPjR06wh9mPQaDdXWDoll/j5UpCAPl1x8fS71GHm7HA6Ua2V4ylG1Ju8lvcTOietbPNNPaSilKj+pj+Ag==", - "dev": true, "requires": { "@babel/types": "^7.12.10" } @@ -2532,7 +2475,6 @@ "version": "7.12.11", "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.12.11.tgz", "integrity": "sha512-LsIVN8j48gHgwzfocYUSkO/hjYAOJqlpJEc7tGXcIm4cubjVUf8LGW6eWRyxEu7gA25q02p0rQUWoCI33HNS5g==", - "dev": true, "requires": { "@babel/types": "^7.12.11" } @@ -2541,7 +2483,6 @@ "version": "7.10.4", "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.4.tgz", "integrity": "sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA==", - "dev": true, "requires": { "@babel/helper-validator-identifier": "^7.10.4", "chalk": "^2.0.0", @@ -2551,14 +2492,12 @@ "@babel/parser": { "version": "7.12.11", "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.12.11.tgz", - "integrity": "sha512-N3UxG+uuF4CMYoNj8AhnbAcJF0PiuJ9KHuy1lQmkYsxTer/MAH9UBNHsBoAX/4s6NvlDD047No8mYVGGzLL4hg==", - "dev": true + "integrity": "sha512-N3UxG+uuF4CMYoNj8AhnbAcJF0PiuJ9KHuy1lQmkYsxTer/MAH9UBNHsBoAX/4s6NvlDD047No8mYVGGzLL4hg==" }, "@babel/template": { "version": "7.12.7", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.12.7.tgz", "integrity": "sha512-GkDzmHS6GV7ZeXfJZ0tLRBhZcMcY0/Lnb+eEbXDBfCAcZCjrZKe6p3J4we/D24O9Y8enxWAg1cWwof59yLh2ow==", - "dev": true, "requires": { "@babel/code-frame": "^7.10.4", "@babel/parser": "^7.12.7", @@ -2569,7 +2508,6 @@ "version": "7.12.12", "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.12.12.tgz", "integrity": "sha512-s88i0X0lPy45RrLM8b9mz8RPH5FqO9G9p7ti59cToE44xFm1Q+Pjh5Gq4SXBbtb88X7Uy7pexeqRIQDDMNkL0w==", - "dev": true, "requires": { "@babel/code-frame": "^7.12.11", "@babel/generator": "^7.12.11", @@ -2586,7 +2524,6 @@ "version": "7.12.12", "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.12.tgz", "integrity": "sha512-lnIX7piTxOH22xE7fDXDbSHg9MM1/6ORnafpJmov5rs0kX5g4BZxeXNJLXsMRiO0U5Rb8/FvMS6xlTnTHvxonQ==", - "dev": true, "requires": { "@babel/helper-validator-identifier": "^7.12.11", "lodash": "^4.17.19", @@ -2597,7 +2534,6 @@ "version": "4.3.1", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", - "dev": true, "requires": { "ms": "2.1.2" } @@ -2605,14 +2541,12 @@ "jsesc": { "version": "2.5.2", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", - "dev": true + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==" }, "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" } } }, @@ -3614,8 +3548,7 @@ "@istanbuljs/schema": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.2.tgz", - "integrity": "sha512-tsAQNx32a8CoFhjhijUIhI4kccIAgmGhy8LZMZgGfmXcpMbPRUqn5LWmgRttILi6yeGmBJd2xsPkFMs0PzgPCw==", - "dev": true + "integrity": "sha512-tsAQNx32a8CoFhjhijUIhI4kccIAgmGhy8LZMZgGfmXcpMbPRUqn5LWmgRttILi6yeGmBJd2xsPkFMs0PzgPCw==" }, "@jsdevtools/coverage-istanbul-loader": { "version": "3.0.5", @@ -4606,7 +4539,6 @@ "version": "3.2.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.0.tgz", "integrity": "sha512-NnSOmMEYtVR2JVMIGTzynRkkaxtiq1xnFBcdQD/DnNCYPoEPsVJhM98BDyaoNOQIi7p4okdi3E27eN7GQbsUug==", - "dev": true, "requires": { "color-convert": "^1.9.0" } @@ -4925,8 +4857,7 @@ "balanced-match": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", - "dev": true + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" }, "base": { "version": "0.11.2", @@ -4989,7 +4920,8 @@ }, "kind-of": { "version": "6.0.2", - "resolved": "", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", "dev": true } } @@ -5234,7 +5166,6 @@ "version": "1.1.8", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.8.tgz", "integrity": "sha1-wHshHHyVLsH479Uad+8NHTmQopI=", - "dev": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -5647,7 +5578,6 @@ "version": "2.2.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.2.2.tgz", "integrity": "sha512-LvixLAQ4MYhbf7hgL4o5PeK32gJKvVzDRiSNIApDofQvyhl8adgG2lJVXn4+ekQoK7HL9RF8lqxwerpe0x2pCw==", - "dev": true, "requires": { "ansi-styles": "^3.1.0", "escape-string-regexp": "^1.0.5", @@ -6025,7 +5955,6 @@ "version": "1.9.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.1.tgz", "integrity": "sha512-mjGanIiwQJskCC18rPR6OmrZ6fm2Lc7PeGFYwCmy5J34wC6F1PzdGL6xeMfmgicfYcNLGuVFA3WzXtIDCQSZxQ==", - "dev": true, "requires": { "color-name": "^1.1.1" } @@ -6033,8 +5962,7 @@ "color-name": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" }, "color-string": { "version": "1.5.4", @@ -6179,8 +6107,7 @@ "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "dev": true + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" }, "concat-stream": { "version": "1.6.0", @@ -8038,8 +7965,7 @@ "escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" }, "eslint-scope": { "version": "4.0.3", @@ -9002,8 +8928,7 @@ "gensync": { "version": "1.0.0-beta.2", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "dev": true + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==" }, "get-caller-file": { "version": "2.0.5", @@ -9098,8 +9023,7 @@ "globals": { "version": "11.12.0", "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "dev": true + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==" }, "globby": { "version": "11.0.2", @@ -9265,8 +9189,7 @@ "has-flag": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", - "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=", - "dev": true + "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=" }, "has-symbols": { "version": "1.0.0", @@ -9464,8 +9387,7 @@ "html-escaper": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", - "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", - "dev": true + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==" }, "http-cache-semantics": { "version": "4.1.0", @@ -10220,14 +10142,12 @@ "istanbul-lib-coverage": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.0.0.tgz", - "integrity": "sha512-UiUIqxMgRDET6eR+o5HbfRYP1l0hqkWOs7vNxC/mggutCMUIhWMm8gAHb8tHlyfD3/l6rlgNA5cKdDzEAf6hEg==", - "dev": true + "integrity": "sha512-UiUIqxMgRDET6eR+o5HbfRYP1l0hqkWOs7vNxC/mggutCMUIhWMm8gAHb8tHlyfD3/l6rlgNA5cKdDzEAf6hEg==" }, "istanbul-lib-instrument": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.3.tgz", "integrity": "sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ==", - "dev": true, "requires": { "@babel/core": "^7.7.5", "@istanbuljs/schema": "^0.1.2", @@ -10238,8 +10158,7 @@ "semver": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" } } }, @@ -10247,7 +10166,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", - "dev": true, "requires": { "istanbul-lib-coverage": "^3.0.0", "make-dir": "^3.0.0", @@ -10257,14 +10175,12 @@ "has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, "requires": { "has-flag": "^4.0.0" } @@ -10356,7 +10272,6 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.0.2.tgz", "integrity": "sha512-9tZvz7AiR3PEDNGiV9vIouQ/EAcqMXFmkcA1CDFTwOB98OZVDL0PH9glHotf5Ugp6GCOTypfzGWI/OqjWNCRUw==", - "dev": true, "requires": { "html-escaper": "^2.0.0", "istanbul-lib-report": "^3.0.0" @@ -10439,8 +10354,7 @@ "js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" }, "js-yaml": { "version": "3.14.1", @@ -10504,7 +10418,6 @@ "version": "2.1.3", "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.3.tgz", "integrity": "sha512-KXPvOm8K9IJKFM0bmdn8QXh7udDh1g/giieX0NLCaMnb4hEiVFqnop2ImTXCc5e0/oHz3LTqmHGtExn5hfMkOA==", - "dev": true, "requires": { "minimist": "^1.2.5" } @@ -10844,6 +10757,49 @@ "resolve": "^1.3.3" } }, + "karma-coverage": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/karma-coverage/-/karma-coverage-2.0.3.tgz", + "integrity": "sha512-atDvLQqvPcLxhED0cmXYdsPMCQuh6Asa9FMZW1bhNqlVEhJoB9qyZ2BY1gu7D/rr5GLGb5QzYO4siQskxaWP/g==", + "requires": { + "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-instrument": "^4.0.1", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.0", + "istanbul-reports": "^3.0.0", + "minimatch": "^3.0.4" + }, + "dependencies": { + "debug": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", + "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", + "requires": { + "ms": "2.1.2" + } + }, + "istanbul-lib-source-maps": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.0.tgz", + "integrity": "sha512-c16LpFRkR8vQXyHZ5nLpY35JZtzj1PQY1iZmesUbf1FZHbIupcWfjgOXBY9YHkLEQ6puz1u4Dgj6qmU/DisrZg==", + "requires": { + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0", + "source-map": "^0.6.1" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + } + } + }, "karma-coverage-istanbul-reporter": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/karma-coverage-istanbul-reporter/-/karma-coverage-istanbul-reporter-3.0.3.tgz", @@ -11124,8 +11080,7 @@ "lodash": { "version": "4.17.20", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz", - "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==", - "dev": true + "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==" }, "lodash.get": { "version": "4.4.2", @@ -11278,7 +11233,6 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "dev": true, "requires": { "semver": "^6.0.0" }, @@ -11286,8 +11240,7 @@ "semver": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" } } }, @@ -11675,7 +11628,6 @@ "version": "3.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "dev": true, "requires": { "brace-expansion": "^1.1.7" } @@ -11683,8 +11635,7 @@ "minimist": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", - "dev": true + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" }, "minipass": { "version": "3.1.3", @@ -16649,8 +16600,7 @@ "safe-buffer": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", - "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==", - "dev": true + "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==" }, "safe-regex": { "version": "1.1.0", @@ -16838,8 +16788,7 @@ "semver": { "version": "5.4.1", "resolved": "https://registry.npmjs.org/semver/-/semver-5.4.1.tgz", - "integrity": "sha512-WfG/X9+oATh81XtllIo/I8gOiY9EXRdv1cQdyykeXK17YcUW3EXUAi2To4pcH6nZtJPr7ZOpM5OMyWJZm+8Rsg==", - "dev": true + "integrity": "sha512-WfG/X9+oATh81XtllIo/I8gOiY9EXRdv1cQdyykeXK17YcUW3EXUAi2To4pcH6nZtJPr7ZOpM5OMyWJZm+8Rsg==" }, "semver-dsl": { "version": "1.0.1", @@ -17186,7 +17135,8 @@ }, "kind-of": { "version": "6.0.2", - "resolved": "", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", "dev": true } } @@ -17427,8 +17377,7 @@ "source-map": { "version": "0.5.7", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" }, "source-map-loader": { "version": "1.1.3", @@ -18171,7 +18120,6 @@ "version": "4.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.5.0.tgz", "integrity": "sha1-vnoN5ITexcXN34s9WRJQRJEvY1s=", - "dev": true, "requires": { "has-flag": "^2.0.0" } @@ -18593,8 +18541,7 @@ "to-fast-properties": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", - "dev": true + "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=" }, "to-object-path": { "version": "0.3.0", diff --git a/ui/package.json b/ui/package.json index 7b4de1ad9..320fb8095 100644 --- a/ui/package.json +++ b/ui/package.json @@ -65,9 +65,9 @@ "karma": "~5.0.0", "karma-chrome-launcher": "~3.1.0", "karma-cli": "^2.0.0", - "karma-coverage-istanbul-reporter": "~3.0.2", "karma-jasmine": "~4.0.0", "karma-jasmine-html-reporter": "^1.5.0", + "karma-coverage": "^2.0.3", "karma-spec-reporter": "0.0.32", "ncp": "^2.0.0", "node-sass": "^4.14.1", diff --git a/ui/src/app/metadata/filter/container/edit-filter.component.html b/ui/src/app/metadata/filter/container/edit-filter.component.html index fa9e113b5..394c27aea 100644 --- a/ui/src/app/metadata/filter/container/edit-filter.component.html +++ b/ui/src/app/metadata/filter/container/edit-filter.component.html @@ -22,7 +22,7 @@
-   -
diff --git a/ui/src/app/metadata/filter/container/edit-filter.component.spec.ts b/ui/src/app/metadata/filter/container/edit-filter.component.spec.ts index 660bf53fb..9d7e31a46 100644 --- a/ui/src/app/metadata/filter/container/edit-filter.component.spec.ts +++ b/ui/src/app/metadata/filter/container/edit-filter.component.spec.ts @@ -2,22 +2,32 @@ import { TestBed, ComponentFixture } from '@angular/core/testing'; import { ReactiveFormsModule, FormBuilder } from '@angular/forms'; import { StoreModule, Store, combineReducers } from '@ngrx/store'; import * as fromFilter from '../reducer'; +import * as fromWizard from '../../../wizard/reducer'; import { ProviderStatusEmitter, ProviderValueEmitter } from '../../domain/service/provider-change-emitter.service'; import { NgbPopoverModule, NgbPopoverConfig } from '@ng-bootstrap/ng-bootstrap'; import { NavigatorService } from '../../../core/service/navigator.service'; import { SharedModule } from '../../../shared/shared.module'; import { EditFilterComponent } from './edit-filter.component'; -import { SchemaFormModule, WidgetRegistry, DefaultWidgetRegistry } from 'ngx-schema-form'; +import { SchemaFormModule } from 'ngx-schema-form'; import { SchemaService } from '../../../schema-form/service/schema.service'; import { HttpClientModule } from '@angular/common/http'; import { MockI18nModule } from '../../../../testing/i18n.stub'; import { MetadataFilterTypes } from '../model'; +import { RouterTestingModule } from '@angular/router/testing'; +import { ActivatedRouteStub } from '../../../../testing/activated-route.stub'; +import { ActivatedRoute } from '@angular/router'; describe('Edit Metadata Filter Page', () => { let fixture: ComponentFixture; let store: Store; let instance: EditFilterComponent; + let activatedRoute: ActivatedRouteStub = new ActivatedRouteStub(); + activatedRoute.testParamMap = { providerId: 'foo' }; + let child: ActivatedRouteStub = new ActivatedRouteStub(); + child.testParamMap = { form: 'common' }; + activatedRoute.firstChild = child; + beforeEach(() => { TestBed.configureTestingModule({ providers: [ @@ -26,11 +36,15 @@ describe('Edit Metadata Filter Page', () => { FormBuilder, NgbPopoverConfig, NavigatorService, - SchemaService + SchemaService, + { + provide: ActivatedRoute, useValue: activatedRoute + } ], imports: [ StoreModule.forRoot({ 'filter': combineReducers(fromFilter.reducers), + 'wizard': combineReducers(fromWizard.reducers) }), ReactiveFormsModule, NgbPopoverModule, @@ -60,7 +74,7 @@ describe('Edit Metadata Filter Page', () => { describe('cancel method', () => { it('should dispatch a cancel changes action', () => { fixture.detectChanges(); - instance.cancel(); + instance.cancel('foo'); expect(store.dispatch).toHaveBeenCalled(); }); }); @@ -73,24 +87,4 @@ describe('Edit Metadata Filter Page', () => { expect(store.dispatch).toHaveBeenCalled(); }); }); - - describe('status emitter', () => { - it('should set the isValid property to true', () => { - fixture.detectChanges(); - instance.statusChangeSubject.next({value: []}); - expect(instance.isValid).toBe(true); - }); - - it('should set the isValid property to true if value is undefined', () => { - fixture.detectChanges(); - instance.statusChangeSubject.next({value: null}); - expect(instance.isValid).toBe(true); - }); - - it('should set the isValid property to false', () => { - fixture.detectChanges(); - instance.statusChangeSubject.next({ value: [{control: 'foo'}] }); - expect(instance.isValid).toBe(false); - }); - }); }); diff --git a/ui/src/app/metadata/filter/container/edit-filter.component.ts b/ui/src/app/metadata/filter/container/edit-filter.component.ts index 9f6bbfba7..1df2ac5d6 100644 --- a/ui/src/app/metadata/filter/container/edit-filter.component.ts +++ b/ui/src/app/metadata/filter/container/edit-filter.component.ts @@ -41,7 +41,7 @@ export class EditFilterComponent implements OnDestroy { defSub: Subscription; formats = NAV_FORMATS; - currentPage + providerId: string; constructor( private store: Store, @@ -52,6 +52,8 @@ export class EditFilterComponent implements OnDestroy { this.defSub = this.definition$.subscribe(d => this.definition = d); + this.providerId = this.route.snapshot.params.providerId; + this.store .select(fromWizard.getCurrentWizardSchema) .pipe(filter(s => !!s), takeUntil(this.ngUnsubscribe)) @@ -91,16 +93,15 @@ export class EditFilterComponent implements OnDestroy { this.defSub.unsubscribe(); } - save(): void { + save(id: string): void { this.store.dispatch(new UpdateFilterRequest({ filter: this.filter, - providerId: this.route.snapshot.params.providerId + providerId: id })); } - cancel(event: MouseEvent): void { - event.preventDefault(); - this.store.dispatch(new CancelCreateFilter(this.route.snapshot.params.providerId)); + cancel(id: string): void { + this.store.dispatch(new CancelCreateFilter(id)); } preview(id: string): void { diff --git a/ui/src/app/metadata/filter/container/new-filter.component.spec.ts b/ui/src/app/metadata/filter/container/new-filter.component.spec.ts index b872f2f09..18c7e067e 100644 --- a/ui/src/app/metadata/filter/container/new-filter.component.spec.ts +++ b/ui/src/app/metadata/filter/container/new-filter.component.spec.ts @@ -3,6 +3,7 @@ import { ReactiveFormsModule, FormBuilder } from '@angular/forms'; import { StoreModule, Store, combineReducers } from '@ngrx/store'; import { NewFilterComponent } from './new-filter.component'; import * as fromFilter from '../reducer'; +import * as fromWizard from '../../../wizard/reducer'; import { ProviderStatusEmitter, ProviderValueEmitter } from '../../domain/service/provider-change-emitter.service'; import { NgbPopoverModule, NgbPopoverConfig } from '@ng-bootstrap/ng-bootstrap'; import { NavigatorService } from '../../../core/service/navigator.service'; @@ -11,12 +12,18 @@ import { SchemaFormModule, WidgetRegistry, DefaultWidgetRegistry } from 'ngx-sch import { SchemaService } from '../../../schema-form/service/schema.service'; import { HttpClientModule } from '@angular/common/http'; import { MockI18nModule } from '../../../../testing/i18n.stub'; +import { RouterTestingModule } from '@angular/router/testing'; +import { ActivatedRoute } from '@angular/router'; +import { ActivatedRouteStub } from '../../../../testing/activated-route.stub'; describe('New Metadata Filter Page', () => { let fixture: ComponentFixture; let store: Store; let instance: NewFilterComponent; + let activatedRoute: ActivatedRouteStub = new ActivatedRouteStub(); + activatedRoute.testParamMap = { providerId: 'foo' }; + beforeEach(() => { TestBed.configureTestingModule({ providers: [ @@ -26,18 +33,23 @@ describe('New Metadata Filter Page', () => { NgbPopoverConfig, NavigatorService, SchemaService, - { provide: WidgetRegistry, useClass: DefaultWidgetRegistry } + { provide: WidgetRegistry, useClass: DefaultWidgetRegistry }, + { + provide: ActivatedRoute, useValue: activatedRoute + } ], imports: [ StoreModule.forRoot({ 'filter': combineReducers(fromFilter.reducers), + 'wizard': combineReducers(fromWizard.reducers) }), ReactiveFormsModule, NgbPopoverModule, SharedModule, HttpClientModule, SchemaFormModule.forRoot(), - MockI18nModule + MockI18nModule, + RouterTestingModule ], declarations: [ NewFilterComponent @@ -64,27 +76,4 @@ describe('New Metadata Filter Page', () => { expect(store.dispatch).toHaveBeenCalled(); }); }); - - describe('status emitter', () => { - it('should set the isValid property to true', () => { - fixture.detectChanges(); - instance.statusChangeSubject.next({ value: [] }); - fixture.detectChanges(); - expect(instance.isValid).toBe(true); - }); - - it('should set the isValid property to true if value is undefined', () => { - fixture.detectChanges(); - instance.statusChangeSubject.next({ value: null }); - fixture.detectChanges(); - expect(instance.isValid).toBe(true); - }); - - it('should set the isValid property to false', () => { - fixture.detectChanges(); - instance.statusChangeSubject.next({ value: [{ control: 'foo' }] }); - fixture.detectChanges(); - expect(instance.isValid).toBe(false); - }); - }); }); diff --git a/ui/src/app/metadata/filter/reducer/collection.reducer.spec.ts b/ui/src/app/metadata/filter/reducer/collection.reducer.spec.ts index d044e66df..5c11032cd 100644 --- a/ui/src/app/metadata/filter/reducer/collection.reducer.spec.ts +++ b/ui/src/app/metadata/filter/reducer/collection.reducer.spec.ts @@ -61,14 +61,20 @@ describe('Filter Reducer', () => { describe(`${FilterCollectionActionTypes.ADD_FILTER_REQUEST}`, () => { it('should set saving to true', () => { const filter = new EntityAttributesFilterEntity({ resourceId: 'foo', createdDate: new Date().toLocaleDateString() }); - const action = new AddFilterRequest(filter); + const action = new AddFilterRequest({ + filter, + providerId: 'foo' + }); expect(reducer(snapshot, action).saving).toBe(true); }); }); describe(`${FilterCollectionActionTypes.UPDATE_FILTER_REQUEST}`, () => { it('should set saving to true', () => { const filter = new EntityAttributesFilterEntity({ resourceId: 'foo', createdDate: new Date().toLocaleDateString() }); - const action = new UpdateFilterRequest(filter); + const action = new UpdateFilterRequest({ + filter, + providerId: 'foo' + }); expect(reducer(snapshot, action).saving).toBe(true); }); }); @@ -76,7 +82,10 @@ describe('Filter Reducer', () => { describe(`${FilterCollectionActionTypes.ADD_FILTER_SUCCESS}`, () => { it('should set saving to false', () => { const filter = new EntityAttributesFilterEntity({ resourceId: 'foo', createdDate: new Date().toLocaleDateString() }); - const action = new AddFilterSuccess(filter); + const action = new AddFilterSuccess({ + filter, + providerId: 'foo' + }); expect(reducer(snapshot, action).saving).toBe(false); }); }); @@ -124,7 +133,10 @@ describe('Filter Reducer', () => { id: 'foo', changes: new EntityAttributesFilterEntity({ resourceId: 'foo', name: 'bar', createdDate: new Date().toLocaleDateString() }), }; - const action = new UpdateFilterSuccess(update); + const action = new UpdateFilterSuccess({ + update, + providerId: 'foo' + }); const result = reducer(snapshot, action); expect(fromFilter.adapter.updateOne).toHaveBeenCalled(); }); diff --git a/ui/src/app/metadata/filter/reducer/filter.reducer.spec.ts b/ui/src/app/metadata/filter/reducer/filter.reducer.spec.ts index 229478811..3689e9f16 100644 --- a/ui/src/app/metadata/filter/reducer/filter.reducer.spec.ts +++ b/ui/src/app/metadata/filter/reducer/filter.reducer.spec.ts @@ -49,7 +49,7 @@ describe('Filter Reducer', () => { }); describe(`${FilterActionTypes.CANCEL_CREATE_FILTER} action`, () => { it('should set saving to true', () => { - const result = reducer(snapshot, new CancelCreateFilter()); + const result = reducer(snapshot, new CancelCreateFilter('foo')); expect(result).toEqual(fromFilter.initialState); }); }); diff --git a/ui/src/app/metadata/filter/reducer/search.reducer.spec.ts b/ui/src/app/metadata/filter/reducer/search.reducer.spec.ts index 4b18f91f4..32af51486 100644 --- a/ui/src/app/metadata/filter/reducer/search.reducer.spec.ts +++ b/ui/src/app/metadata/filter/reducer/search.reducer.spec.ts @@ -71,7 +71,10 @@ describe('Filter Reducer', () => { id: 'foo', changes: new EntityAttributesFilterEntity({ resourceId: 'foo', name: 'bar', createdDate: new Date().toLocaleDateString() }), }; - const action = new UpdateFilterSuccess(update); + const action = new UpdateFilterSuccess({ + update, + providerId: 'foo' + }); const result = reducer(snapshot, action); expect(result).toEqual(snapshot); @@ -83,7 +86,10 @@ describe('Filter Reducer', () => { const filter = new EntityAttributesFilterEntity( { resourceId: 'foo', name: 'bar', createdDate: new Date().toLocaleDateString() } ); - const action = new AddFilterSuccess(filter); + const action = new AddFilterSuccess({ + filter, + providerId: 'foo' + }); const result = reducer(snapshot, action); expect(result).toEqual(snapshot); diff --git a/ui/src/testing/activated-route.stub.ts b/ui/src/testing/activated-route.stub.ts index 7e222b6ce..4f7a58f5b 100644 --- a/ui/src/testing/activated-route.stub.ts +++ b/ui/src/testing/activated-route.stub.ts @@ -14,6 +14,7 @@ export class ActivatedRouteStub { // Test parameters private _testParamMap: ParamMap; + private _params: any; private _firstChild: ActivatedRouteStub; @@ -22,12 +23,14 @@ export class ActivatedRouteStub { get testParamMap() { return this._testParamMap; } set testParamMap(params: {}) { this._testParamMap = convertToParamMap(params); + this._params = params; this.subject.next(this._testParamMap); } // ActivatedRoute.snapshot.paramMap get snapshot() { return { + params: this._params, paramMap: this.testParamMap, }; } From e74d6bf86686e1681887c6c14a1fd31d50138d8b Mon Sep 17 00:00:00 2001 From: Shad Vider Date: Wed, 24 Mar 2021 16:31:24 -0700 Subject: [PATCH 11/26] SHIBUI-1791: fixed error reporting failure when saving metadata --- .../support/RestControllersSupport.java | 22 ++++++++++++++++++- .../JsonSchemaValidationFailedException.java | 4 ++-- 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/controller/support/RestControllersSupport.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/controller/support/RestControllersSupport.java index f4bc81df4..1642fe2c9 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/controller/support/RestControllersSupport.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/controller/support/RestControllersSupport.java @@ -1,10 +1,12 @@ package edu.internet2.tier.shibboleth.admin.ui.controller.support; import edu.internet2.tier.shibboleth.admin.ui.controller.ErrorResponse; +import edu.internet2.tier.shibboleth.admin.ui.domain.Attribute; import edu.internet2.tier.shibboleth.admin.ui.domain.exceptions.MetadataFileNotFoundException; import edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.MetadataResolver; import edu.internet2.tier.shibboleth.admin.ui.jsonschema.JsonSchemaValidationFailedException; import edu.internet2.tier.shibboleth.admin.ui.repository.MetadataResolverRepository; +import edu.internet2.tier.shibboleth.admin.util.MDDCConstants; import org.hibernate.exception.ConstraintViolationException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; @@ -13,6 +15,7 @@ import org.springframework.web.bind.annotation.RestControllerAdvice; import org.springframework.web.client.HttpClientErrorException; +import java.util.*; import static org.springframework.http.HttpStatus.BAD_REQUEST; import static org.springframework.http.HttpStatus.INTERNAL_SERVER_ERROR; import static org.springframework.http.HttpStatus.NOT_FOUND; @@ -60,6 +63,23 @@ public final ResponseEntity metadataFileNotFoundHandler(MetadataF @ExceptionHandler(JsonSchemaValidationFailedException.class) public final ResponseEntity handleJsonSchemaValidationFailedException(JsonSchemaValidationFailedException ex) { - return ResponseEntity.status(BAD_REQUEST).body(new ErrorResponse("400", String.join("\n", ex.getErrors()))); + return ResponseEntity.status(BAD_REQUEST).body(new ErrorResponse("400", String.join("\n", flattenErrorsList(ex.getErrors())))); + } + + private List flattenErrorsList(List errors) { + List theseErrors = new ArrayList<>(); + processErrorsList(theseErrors, errors); + return theseErrors; + } + + private static void processErrorsList(List outputErrorList, Object errors){ + if(errors instanceof String){ + outputErrorList.add((String)errors); + } + else if(errors instanceof List){ + for(Object error2:(List)errors){ + processErrorsList(outputErrorList, error2); + } + } } } diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/jsonschema/JsonSchemaValidationFailedException.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/jsonschema/JsonSchemaValidationFailedException.java index fac8d91fb..9ebc11713 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/jsonschema/JsonSchemaValidationFailedException.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/jsonschema/JsonSchemaValidationFailedException.java @@ -13,9 +13,9 @@ @Getter public class JsonSchemaValidationFailedException extends RuntimeException { - List errors; + List errors; JsonSchemaValidationFailedException(List errors) { - this.errors = (List) errors; + this.errors = errors; } } From ca9e8b4ebbe1a91b4f453d72c2e566edfb69fd72 Mon Sep 17 00:00:00 2001 From: Jj! Date: Fri, 2 Apr 2021 09:44:27 -0500 Subject: [PATCH 12/26] [SHIBUI-1772] WIP update schema write test --- .../admin/ui/domain/DigestMethod.java | 4 +- .../EntityDescriptorRepresentation.java | 7 +- .../frontend/OrganizationRepresentation.java | 5 ++ .../resources/metadata-sources-ui-schema.json | 6 ++ .../service/AuxiliaryIntegrationTests.groovy | 59 ++++++++++++++ ...on => metadata-sources-ui-schema.json.old} | 0 .../test/resources/metadata/SHIBUI-1723-1.xml | 81 +++++++++++++++++++ 7 files changed, 159 insertions(+), 3 deletions(-) create mode 100644 backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/service/AuxiliaryIntegrationTests.groovy rename backend/src/test/resources/{metadata-sources-ui-schema.json => metadata-sources-ui-schema.json.old} (100%) create mode 100644 backend/src/test/resources/metadata/SHIBUI-1723-1.xml diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/DigestMethod.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/DigestMethod.java index bb0fe5359..199947f88 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/DigestMethod.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/DigestMethod.java @@ -19,11 +19,11 @@ public DigestMethod(String algorithm) { @Nullable @Override public String getAlgorithm() { - return null; + return this.algorithm; } @Override public void setAlgorithm(@Nullable String value) { - + this.algorithm = value; } } diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/frontend/EntityDescriptorRepresentation.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/frontend/EntityDescriptorRepresentation.java index 44f1463c5..2131696c4 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/frontend/EntityDescriptorRepresentation.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/frontend/EntityDescriptorRepresentation.java @@ -1,5 +1,6 @@ package edu.internet2.tier.shibboleth.admin.ui.domain.frontend; +import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; import javax.validation.constraints.NotNull; @@ -38,10 +39,12 @@ public EntityDescriptorRepresentation(String id, @NotNull private String entityId; - private OrganizationRepresentation organization; + //TODO: review requirement + private OrganizationRepresentation organization = new OrganizationRepresentation(); private List contacts; + @JsonInclude(JsonInclude.Include.NON_EMPTY) private MduiRepresentation mdui; private ServiceProviderSsoDescriptorRepresentation serviceProviderSsoDescriptor; @@ -58,8 +61,10 @@ public EntityDescriptorRepresentation(String id, private LocalDateTime modifiedDate; + @JsonInclude(JsonInclude.Include.NON_EMPTY) private Map relyingPartyOverrides; + @JsonInclude(JsonInclude.Include.NON_EMPTY) private List attributeRelease; private int version; diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/frontend/OrganizationRepresentation.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/frontend/OrganizationRepresentation.java index 00d98797c..bbcf20a3b 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/frontend/OrganizationRepresentation.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/frontend/OrganizationRepresentation.java @@ -1,15 +1,20 @@ package edu.internet2.tier.shibboleth.admin.ui.domain.frontend; +import com.fasterxml.jackson.annotation.JsonInclude; + import java.io.Serializable; public class OrganizationRepresentation implements Serializable { private static final long serialVersionUID = 802722455433573538L; + @JsonInclude(JsonInclude.Include.NON_EMPTY) private String name; + @JsonInclude(JsonInclude.Include.NON_EMPTY) private String displayName; + @JsonInclude(JsonInclude.Include.NON_EMPTY) private String url; public String getName() { diff --git a/backend/src/main/resources/metadata-sources-ui-schema.json b/backend/src/main/resources/metadata-sources-ui-schema.json index 9a0b4fb9e..156dffce2 100644 --- a/backend/src/main/resources/metadata-sources-ui-schema.json +++ b/backend/src/main/resources/metadata-sources-ui-schema.json @@ -446,6 +446,12 @@ "urn:oasis:names:tc:SAML:2.0:bindings:SOAP" ], "description": "urn:oasis:names:tc:SAML:2.0:bindings:SOAP" + }, + { + "enum": [ + "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact" + ], + "description": "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact" } ] } diff --git a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/service/AuxiliaryIntegrationTests.groovy b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/service/AuxiliaryIntegrationTests.groovy new file mode 100644 index 000000000..02fde7269 --- /dev/null +++ b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/service/AuxiliaryIntegrationTests.groovy @@ -0,0 +1,59 @@ +package edu.internet2.tier.shibboleth.admin.ui.service + +import com.fasterxml.jackson.databind.ObjectMapper +import edu.internet2.tier.shibboleth.admin.ui.configuration.JsonSchemaComponentsConfiguration +import edu.internet2.tier.shibboleth.admin.ui.domain.EntityDescriptor +import edu.internet2.tier.shibboleth.admin.ui.jsonschema.LowLevelJsonSchemaValidator +import edu.internet2.tier.shibboleth.admin.ui.opensaml.OpenSamlObjects +import org.springframework.core.io.DefaultResourceLoader +import org.springframework.core.io.ResourceLoader +import org.springframework.mock.http.MockHttpInputMessage +import spock.lang.Shared +import spock.lang.Specification + +import java.time.LocalDateTime + +class AuxiliaryIntegrationTests extends Specification { + @Shared + OpenSamlObjects openSamlObjects = new OpenSamlObjects().with { + it.init() + it + } + + @Shared + EntityDescriptorService entityDescriptorService + + @Shared + ObjectMapper objectMapper + + @Shared + ResourceLoader resourceLoader + + void setup() { + this.entityDescriptorService = new JPAEntityDescriptorServiceImpl(openSamlObjects, null, null) + this.objectMapper = new ObjectMapper() + this.resourceLoader = new DefaultResourceLoader() + } + + def "SHIBUI-1723: after enabling saved entity descriptor, it should still have valid xml"() { + given: + def entityDescriptor = openSamlObjects.unmarshalFromXml(this.class.getResource('/metadata/SHIBUI-1723-1.xml').bytes) as EntityDescriptor + def entityDescriptorRepresentation = this.entityDescriptorService.createRepresentationFromDescriptor(entityDescriptor).with { + it.serviceProviderName = 'testme' + it.contacts = [] + it.securityInfo.x509Certificates[0].name = 'testcert' + it.createdBy = 'root' + it.setCreatedDate(LocalDateTime.now()) + it.setModifiedDate(LocalDateTime.now()) + it + } + def json = this.objectMapper.writeValueAsString(entityDescriptorRepresentation) + def schemaUri = edu.internet2.tier.shibboleth.admin.ui.jsonschema.JsonSchemaLocationLookup.metadataSourcesSchema(new JsonSchemaComponentsConfiguration().jsonSchemaResourceLocationRegistry(this.resourceLoader, this.objectMapper)).uri + + when: + LowLevelJsonSchemaValidator.validatePayloadAgainstSchema(new MockHttpInputMessage(json.bytes), schemaUri) + + then: + noExceptionThrown() + } +} diff --git a/backend/src/test/resources/metadata-sources-ui-schema.json b/backend/src/test/resources/metadata-sources-ui-schema.json.old similarity index 100% rename from backend/src/test/resources/metadata-sources-ui-schema.json rename to backend/src/test/resources/metadata-sources-ui-schema.json.old diff --git a/backend/src/test/resources/metadata/SHIBUI-1723-1.xml b/backend/src/test/resources/metadata/SHIBUI-1723-1.xml new file mode 100644 index 000000000..98c1b5a8a --- /dev/null +++ b/backend/src/test/resources/metadata/SHIBUI-1723-1.xml @@ -0,0 +1,81 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 67af3237368e + + CN=67af3237368e + MIID6zCCAlOgAwIBAgIJALaLIs8AvRgDMA0GCSqGSIb3DQEBCwUAMBcxFTATBgNV +BAMTDDY3YWYzMjM3MzY4ZTAeFw0xODAxMDkyMDUxMzlaFw0yODAxMDcyMDUxMzla +MBcxFTATBgNVBAMTDDY3YWYzMjM3MzY4ZTCCAaIwDQYJKoZIhvcNAQEBBQADggGP +ADCCAYoCggGBAKes3NT2GqXPDrl8OwrDRARLoBxKJ8ALZ0Ipj1sbYcUEv8aZ4ElR ++G4xf/KL/nF77ctc9WzE/fUlFG55lVKF7l2heKenweXsmeInmOj0MqXpIIofF1G2 +Sh4xUGACQp0OT7ndNlk2+mHK9zuCNA5o3VrAhJuWAruL3nRk14+DE7UkqF+oBZaF +k5/U7W2sa6R1+UHXvSI823O5jAjhSSIfY/N2mME7QogU3P6ETa7BSRS3IvZ8oJvU +T2Ss2ai1qZoiR/0Exeyj5nc026XEAQ675WAcxpAfxu+uDVQ274nPrvOdqUtUeaiU +nc3kIdorXx/m8+WjYT4rGAXx2NbRRC/wRc7ilptLtL/5iHGJkIieFbzHWJXRRMzT +/wWuYM8lr6lqEiOW/2B6z6kQpuGZoinQYBrNU+xYelkfK+jc1IZgR5wOP2aVJ2Gj +DAarnNHkkd36sxOUKw+4f2R2K5obwzHqJl7jySW2p0KldjobQLt0M1DswK0U478R +qqItwPfsTxju0wIDAQABozowODAXBgNVHREEEDAOggw2N2FmMzIzNzM2OGUwHQYD +VR0OBBYEFAvZyUZ8LY3YacgpZSzgQMYSFmptMA0GCSqGSIb3DQEBCwUAA4IBgQCM +IBtz+5mfFtRwmcScYdUzIujCbGfnY6+YsjGMa0jDDfyS1kFfNrj9VRl6uuPO8gWu +BOxR9asm96FOC/tZOQ9SZgQN6ltQsfAMhl+cnI80Qwx8pUXt+iUtM+IgTUFqiv51 +Oy2GyFJGr1QIq4/iF8Q6k27ar73qVGFAYtGgOO5va4hKk6wPgiTHtIqgut6nbWD3 +ErCB28sMnNVYUVhQUxVf9c/9sXC8UIj9Ze0xrclhOeHwrwr9G5EZzyxK8VPFkv0Q +Xrz01BXy/DcbIkcuFFvXE+BMeaziT4FofvvPXWpM1i+FX0wlkCXLj4GNsTuVspfi +T5uUQUubf52kpO5tkPmF9JdM25qmVu5IgpqCMbm1mqrq7qAEFjzOtIp4f0EmHUSy +/BNdo6DT14p56KA0DyrkBCR1UUgzBJcFNJLBLbyEHnHL8fXDcIhjjKJETYoKdsHT +NEi6AB6UOCbYz//CwA96sW154Lu4CpMKrm5fZHLPQ+7UeE9UOQidzHLJ3Vb54BY= + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From 70159e38b1128004b6fa67e33a3e975167e2e921 Mon Sep 17 00:00:00 2001 From: Jj! Date: Fri, 2 Apr 2021 14:23:59 -0500 Subject: [PATCH 13/26] [SHIBUI-1772] new test --- .../admin/ui/domain/VersioningTests.groovy | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/domain/VersioningTests.groovy diff --git a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/domain/VersioningTests.groovy b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/domain/VersioningTests.groovy new file mode 100644 index 000000000..649d8d5a4 --- /dev/null +++ b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/domain/VersioningTests.groovy @@ -0,0 +1,25 @@ +package edu.internet2.tier.shibboleth.admin.ui.domain + +import edu.internet2.tier.shibboleth.admin.ui.opensaml.OpenSamlObjects +import spock.lang.Shared +import spock.lang.Specification + +class VersioningTests extends Specification{ + @Shared + OpenSamlObjects openSamlObjects + + def setup() { + this.openSamlObjects = new OpenSamlObjects() + this.openSamlObjects.init() + } + + def "test that two loaded entity descriptors gets the same version when load from the same file"() { + given: + def xmlBytes = this.class.getResource('/metadata/SHIBUI-1723-1.xml').bytes + def ed1 = openSamlObjects.unmarshalFromXml(xmlBytes) + def ed2 = openSamlObjects.unmarshalFromXml(xmlBytes) + + expect: + ed1.hashCode() == ed2.hashCode() + } +} From 9f8f007878d0d09039899ef7c57c598c266effae Mon Sep 17 00:00:00 2001 From: Jj! Date: Mon, 5 Apr 2021 10:16:40 -0500 Subject: [PATCH 14/26] [SHIBUI-1772] update test (missed field) hashcode enhancement for request initiator --- .../shibboleth/admin/ui/domain/RequestInitiator.java | 11 ++++++++++- .../shibboleth/admin/ui/domain/VersioningTests.groovy | 3 +++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/RequestInitiator.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/RequestInitiator.java index dbd667ff9..e4d87f302 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/RequestInitiator.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/domain/RequestInitiator.java @@ -12,10 +12,12 @@ import javax.xml.namespace.QName; import java.util.HashMap; import java.util.Map; +import java.util.Set; @Entity -@EqualsAndHashCode(callSuper = true, exclude = {"storageAttributeMap"}) +@EqualsAndHashCode(callSuper = true, onlyExplicitlyIncluded = true) public class RequestInitiator extends AbstractElementExtensibleXMLObject implements org.opensaml.saml.ext.saml2mdreqinit.RequestInitiator { + @EqualsAndHashCode.Include private String binding; @Override public String getBinding() { @@ -27,6 +29,7 @@ public void setBinding(String binding) { this.binding = binding; } + @EqualsAndHashCode.Include private String location; @Override @@ -39,6 +42,7 @@ public void setLocation(String location) { this.location = location; } + @EqualsAndHashCode.Include private String responseLocation; @Override @@ -57,6 +61,11 @@ public void setResponseLocation(String location) { @Transient private AttributeMap attributeMap = new AttributeMap(this); + @EqualsAndHashCode.Include + private Set> attributeMapEntrySet() { + return this.attributeMap.entrySet(); + } + @PrePersist void prePersist() { this.storageAttributeMap = this.attributeMap; diff --git a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/domain/VersioningTests.groovy b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/domain/VersioningTests.groovy index 649d8d5a4..0e9ecaf10 100644 --- a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/domain/VersioningTests.groovy +++ b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/domain/VersioningTests.groovy @@ -15,9 +15,12 @@ class VersioningTests extends Specification{ def "test that two loaded entity descriptors gets the same version when load from the same file"() { given: + def resourceId = "testme" def xmlBytes = this.class.getResource('/metadata/SHIBUI-1723-1.xml').bytes def ed1 = openSamlObjects.unmarshalFromXml(xmlBytes) + ed1.resourceId = resourceId def ed2 = openSamlObjects.unmarshalFromXml(xmlBytes) + ed2.resourceId = resourceId expect: ed1.hashCode() == ed2.hashCode() From 029fe7533bb654aee0add25d890944156e3814a9 Mon Sep 17 00:00:00 2001 From: Bill Smith Date: Tue, 6 Apr 2021 15:54:59 -0700 Subject: [PATCH 15/26] SHIBUI-1730 Updated classpath handling so that the classpath is built properly when executing the selenium tests. --- backend/build.gradle | 2 +- .../shibboleth/admin/ui/controller/RootUiViewController.java | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/backend/build.gradle b/backend/build.gradle index 59bb93bc1..9744cbf84 100644 --- a/backend/build.gradle +++ b/backend/build.gradle @@ -215,7 +215,7 @@ dependencies { task copyUI(type: Copy) { from tasks.findByPath(':ui:npm_run_buildProd').outputs - into new File(buildDir, 'generated/ui/static') + into new File(buildDir, 'generated/ui/resources') } task integrationTest(type: Test) { diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/controller/RootUiViewController.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/controller/RootUiViewController.java index fe9e4b246..333f5c8c9 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/controller/RootUiViewController.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/controller/RootUiViewController.java @@ -30,8 +30,8 @@ public String index() { public void indexHtml(HttpServletRequest request, HttpServletResponse response) throws IOException, URISyntaxException { //This method is necessary in order for Angular framework to honor dynamic ServletContext //under which shib ui application is deployed, both during initial index.html load and subsequest page refreshes - String content = new BufferedReader(new InputStreamReader(request.getServletContext() - .getResourceAsStream("/WEB-INF/classes/resources/index.html"))) + String content = new BufferedReader(new InputStreamReader(this.getClass() + .getResourceAsStream("/resources/index.html"))) .lines() .collect(Collectors.joining("\n")); From ea4ba6220b721f46651829a0727b6c7917721555 Mon Sep 17 00:00:00 2001 From: Bill Smith Date: Wed, 7 Apr 2021 13:17:54 -0700 Subject: [PATCH 16/26] SHIBUI-1795 Fix for json schema validation from Ryan. --- backend/src/main/resources/metadata-sources-ui-schema.json | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/backend/src/main/resources/metadata-sources-ui-schema.json b/backend/src/main/resources/metadata-sources-ui-schema.json index 9a0b4fb9e..156dffce2 100644 --- a/backend/src/main/resources/metadata-sources-ui-schema.json +++ b/backend/src/main/resources/metadata-sources-ui-schema.json @@ -446,6 +446,12 @@ "urn:oasis:names:tc:SAML:2.0:bindings:SOAP" ], "description": "urn:oasis:names:tc:SAML:2.0:bindings:SOAP" + }, + { + "enum": [ + "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact" + ], + "description": "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact" } ] } From 748fd14d5b1428e5fd204e53929f0dcbe66db454 Mon Sep 17 00:00:00 2001 From: Ryan Mathis Date: Wed, 7 Apr 2021 15:07:23 -0700 Subject: [PATCH 17/26] Fixed buttons for failed contention modal --- .../contention-dialog.component.html | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/ui/src/app/contention/component/contention-dialog.component.html b/ui/src/app/contention/component/contention-dialog.component.html index 1ff63bb4b..18b436d03 100644 --- a/ui/src/app/contention/component/contention-dialog.component.html +++ b/ui/src/app/contention/component/contention-dialog.component.html @@ -35,16 +35,17 @@