diff --git a/backend/src/main/resources/i18n/messages_en.properties b/backend/src/main/resources/i18n/messages_en.properties index 7ae90de03..3d4670252 100644 --- a/backend/src/main/resources/i18n/messages_en.properties +++ b/backend/src/main/resources/i18n/messages_en.properties @@ -433,7 +433,7 @@ tooltip.backing-file=Specifies where the backing file is located. If the remote tooltip.backup-file-init-refresh-delay=Delay duration after which to schedule next HTTP refresh when initialized from the backing file. tooltip.require-valid-metadata=Whether candidate metadata found by the resolver must be valid in order to be returned (where validity is implementation specific, but in SAML cases generally depends on a validUntil attribute.) If this flag is true, then invalid candidate metadata will not be returned. tooltip.fail-fast-init=Whether to fail initialization of the underlying MetadataResolverService (and possibly the IdP as a whole) if the initialization of a metadata provider fails. When false, the IdP may start, and will continue to attempt to reload valid metadata if configured to do so, but operations that require valid metadata will fail until it does. -tooltip.use-default-predicate-reg=Whether to fail initialization of the underlying MetadataResolverService (and possibly the IdP as a whole) if the initialization of a metadata provider fails. When false, the IdP may start, and will continue to attempt to reload valid metadata if configured to do so, but operations that require valid metadata will fail until it does. +tooltip.use-default-predicate-reg=Flag which determines whether the default CriterionPredicateRegistry will be used if a custom one is not supplied explicitly. tooltip.satisfy-any-predicates=Flag which determines whether predicates used in filtering are connected by a logical 'OR' (true) or by logical 'AND' (false). tooltip.enable-provider-upon-saving=Enable Metadata Provider upon saving? diff --git a/ui/src/app/metadata/domain/component/unsaved-entity.dialog.html b/ui/src/app/metadata/domain/component/unsaved-entity.dialog.html index 6c210c045..5966b73c8 100644 --- a/ui/src/app/metadata/domain/component/unsaved-entity.dialog.html +++ b/ui/src/app/metadata/domain/component/unsaved-entity.dialog.html @@ -1,14 +1,28 @@ - +
diff --git a/ui/src/app/metadata/domain/component/unsaved-entity.dialog.ts b/ui/src/app/metadata/domain/component/unsaved-entity.dialog.ts index 7efe195c8..10180a2a8 100644 --- a/ui/src/app/metadata/domain/component/unsaved-entity.dialog.ts +++ b/ui/src/app/metadata/domain/component/unsaved-entity.dialog.ts @@ -10,6 +10,8 @@ import { Subject } from 'rxjs/Subject'; export class UnsavedEntityComponent { readonly subject: Subject = new Subject(); + @Input() message; + constructor( public activeModal: NgbActiveModal ) { } diff --git a/ui/src/app/metadata/provider/container/provider-wizard-step.component.ts b/ui/src/app/metadata/provider/container/provider-wizard-step.component.ts index 05d121bba..9ff4ded23 100644 --- a/ui/src/app/metadata/provider/container/provider-wizard-step.component.ts +++ b/ui/src/app/metadata/provider/container/provider-wizard-step.component.ts @@ -1,6 +1,6 @@ import { Component, OnDestroy } from '@angular/core'; import { Observable, Subject } from 'rxjs'; -import { withLatestFrom, map, distinctUntilChanged, skipWhile } from 'rxjs/operators'; +import { withLatestFrom, map, distinctUntilChanged, skipWhile, filter } from 'rxjs/operators'; import { Store } from '@ngrx/store'; import * as fromProvider from '../reducer'; @@ -42,7 +42,9 @@ export class ProviderWizardStepComponent implements OnDestroy { constructor( private store: Store, ) { - this.schema$ = this.store.select(fromWizard.getParsedSchema); + this.schema$ = this.store.select(fromWizard.getSchema).pipe( + filter(s => s && Object.keys(s.properties).length > 0) + ); this.definition$ = this.store.select(fromWizard.getWizardDefinition); this.changes$ = this.store.select(fromProvider.getEntityChanges); diff --git a/ui/src/app/metadata/provider/model/base.provider.form.ts b/ui/src/app/metadata/provider/model/base.provider.form.ts index 459eaa956..ecbcab666 100644 --- a/ui/src/app/metadata/provider/model/base.provider.form.ts +++ b/ui/src/app/metadata/provider/model/base.provider.form.ts @@ -1,6 +1,5 @@ import { Wizard } from '../../../wizard/model'; import { BaseMetadataProvider } from '../../domain/model/providers'; -import { UriValidator } from '../../../shared/validation/uri.validator'; export const BaseMetadataProviderEditor: Wizard = { label: 'BaseMetadataProvider', @@ -30,14 +29,6 @@ export const BaseMetadataProviderEditor: Wizard = { params: [value] } : null; return err; - }, - '/metadataURL': (value, property, form) => { - return !UriValidator.isUri(value) ? { - code: 'INVALID_URI', - path: `#${property.path}`, - message: 'message.uri-valid-format', - params: [value] - } : null; } }; return validators; diff --git a/ui/src/app/metadata/provider/model/file-backed-http.provider.form.spec.ts b/ui/src/app/metadata/provider/model/file-backed-http.provider.form.spec.ts index aa07918f0..68e19359b 100644 --- a/ui/src/app/metadata/provider/model/file-backed-http.provider.form.spec.ts +++ b/ui/src/app/metadata/provider/model/file-backed-http.provider.form.spec.ts @@ -113,8 +113,8 @@ describe('FileBackedHttpMetadataProviderWizard', () => { expect(Object.keys(getValidators([]))).toEqual([ '/', '/name', - '/metadataURL', - '/xmlId' + '/xmlId', + '/metadataURL' ]); }); }); diff --git a/ui/src/app/metadata/provider/model/file-backed-http.provider.form.ts b/ui/src/app/metadata/provider/model/file-backed-http.provider.form.ts index 2c8103438..8dbe80204 100644 --- a/ui/src/app/metadata/provider/model/file-backed-http.provider.form.ts +++ b/ui/src/app/metadata/provider/model/file-backed-http.provider.form.ts @@ -1,6 +1,7 @@ import { Wizard } from '../../../wizard/model'; import { FileBackedHttpMetadataProvider } from '../../domain/model/providers/file-backed-http-metadata-provider'; import { BaseMetadataProviderEditor } from './base.provider.form'; +import UriValidator from '../../../shared/validation/uri.validator'; export const FileBackedHttpMetadataProviderWizard: Wizard = { ...BaseMetadataProviderEditor, @@ -17,6 +18,15 @@ export const FileBackedHttpMetadataProviderWizard: Wizard { + return !UriValidator.isUri(value) ? { + code : 'INVALID_URI', + path: `#${property.path}`, + message: 'message.uri-valid-format', + params: [value] + } : null; + }; + return validators; }, steps: [ diff --git a/ui/src/app/metadata/provider/model/provider.form.ts b/ui/src/app/metadata/provider/model/provider.form.ts index 28e5794c5..71ba6174b 100644 --- a/ui/src/app/metadata/provider/model/provider.form.ts +++ b/ui/src/app/metadata/provider/model/provider.form.ts @@ -17,6 +17,16 @@ export const MetadataProviderWizard: Wizard = { fields: [ 'name', '@type' + ], + fieldsets: [ + { + type: 'section', + class: ['col-12'], + fields: [ + 'name', + '@type' + ] + } ] } ] as WizardStep[] diff --git a/ui/src/app/metadata/resolver/container/resolver-wizard.component.ts b/ui/src/app/metadata/resolver/container/resolver-wizard.component.ts index bf886ae6d..ba2221fda 100644 --- a/ui/src/app/metadata/resolver/container/resolver-wizard.component.ts +++ b/ui/src/app/metadata/resolver/container/resolver-wizard.component.ts @@ -28,7 +28,7 @@ import { LoadSchemaRequest } from '../../../wizard/action/wizard.action'; import { UnsavedEntityComponent } from '../../domain/component/unsaved-entity.dialog'; import { ModalService } from '../../../core/service/modal.service'; import { NgbModal } from '@ng-bootstrap/ng-bootstrap'; -import { UpdateChanges } from '../action/entity.action'; +import { UpdateChanges, Clear } from '../action/entity.action'; @Component({ selector: 'resolver-wizard-page', @@ -127,6 +127,8 @@ export class ResolverWizardComponent implements OnDestroy, CanComponentDeactivat } )) ); + + this.changes$.pipe(takeUntil(this.ngUnsubscribe)).subscribe(c => this.changes = c); } next(): void { @@ -170,12 +172,15 @@ export class ResolverWizardComponent implements OnDestroy, CanComponentDeactivat currentState: RouterStateSnapshot, nextState: RouterStateSnapshot ): Observable { - if (nextState.url.match('wizard')) { return of(true); } + if (nextState.url.match('blank')) { return of(true); } if (Object.keys(this.changes).length > 0) { let modal = this.modalService.open(UnsavedEntityComponent); - modal.componentInstance.action = new UpdateChanges(this.latest); + modal.componentInstance.message = 'resolver'; modal.result.then( - () => this.router.navigate([nextState.url]), + () => { + this.store.dispatch(new Clear()); + this.router.navigate([nextState.url]); + }, () => console.warn('denied') ); } diff --git a/ui/src/app/metadata/resolver/resolver.routing.ts b/ui/src/app/metadata/resolver/resolver.routing.ts index 5312f5537..1d080bd5f 100644 --- a/ui/src/app/metadata/resolver/resolver.routing.ts +++ b/ui/src/app/metadata/resolver/resolver.routing.ts @@ -26,7 +26,9 @@ export const ResolverRoutes: Routes = [ { path: 'blank/:index', component: ResolverWizardComponent, - canDeactivate: [], + canDeactivate: [ + CanDeactivateGuard + ], children: [ { path: '', diff --git a/ui/src/app/wizard/reducer/index.ts b/ui/src/app/wizard/reducer/index.ts index 0d7176565..56054616c 100644 --- a/ui/src/app/wizard/reducer/index.ts +++ b/ui/src/app/wizard/reducer/index.ts @@ -61,12 +61,15 @@ export const getSplitSchema = (schema: any, step: WizardStep) => { const required = (schema.required || []).filter(val => keys.indexOf(val) > -1); let s: any = { type: schema.type, - definitions: schema.definitions, properties: { ...keys.reduce( (properties, key) => ({ ...properties, [key]: schema.properties[key] }) , {}) } }; + if (schema.definitions) { + s.definitions = schema.definitions; + } + if (required && required.length) { s.required = required; }