From 12b959ee638dc1f17a8f8f3895657c4bc009ae99 Mon Sep 17 00:00:00 2001 From: Ryan Mathis Date: Tue, 16 Oct 2018 11:16:55 -0700 Subject: [PATCH] SHIBUI-914 Fixed issues with summary page, fixed issues with bindings --- .../main/resources/i18n/messages.properties | 2 + .../resources/i18n/messages_en.properties | 2 + package-lock.json | 3 + .../component/summary-property.component.html | 54 +++++++++ .../summary-property.component.spec.ts | 0 .../component/summary-property.component.ts | 4 + .../component/wizard-summary.component.html} | 0 .../wizard-summary.component.spec.ts} | 0 .../component/wizard-summary.component.ts | 113 ++++++++++++++++++ ui/src/app/metadata/domain/domain.module.ts | 10 +- .../{provider => domain}/model/property.ts | 1 + .../model/wizards/metadata-source-wizard.ts | 47 ++++++-- .../provider-wizard-summary.component.ts | 83 ------------- .../component/summary-property.component.html | 18 --- .../container/provider-wizard.component.html | 4 +- .../app/metadata/provider/provider.module.ts | 8 +- .../container/new-resolver.component.html | 2 +- .../container/new-resolver.component.ts | 15 ++- .../resolver-wizard-step.component.html | 1 + .../resolver-wizard-step.component.ts | 48 +++++++- .../container/resolver-wizard.component.html | 7 +- .../container/resolver-wizard.component.ts | 34 +++++- .../resolver/effect/collection.effects.ts | 11 +- .../effect/draft-collection.effects.ts | 15 ++- ui/src/app/schema-form/registry.ts | 5 +- ui/src/app/schema-form/schema-form.module.ts | 2 + .../widget/array/array.component.html | 49 ++++++-- .../widget/array/array.component.ts | 6 +- .../widget/object/object.component.html | 3 +- .../widget/radio/radio.component.html | 11 ++ .../widget/radio/radio.component.ts | 8 ++ ui/src/app/wizard/model/wizard.ts | 1 + .../assets/schema/source/metadata-source.json | 26 ++-- ui/src/theme/list.scss | 10 +- 34 files changed, 434 insertions(+), 169 deletions(-) create mode 100644 package-lock.json create mode 100644 ui/src/app/metadata/domain/component/summary-property.component.html rename ui/src/app/metadata/{provider => domain}/component/summary-property.component.spec.ts (100%) rename ui/src/app/metadata/{provider => domain}/component/summary-property.component.ts (77%) rename ui/src/app/metadata/{provider/component/provider-wizard-summary.component.html => domain/component/wizard-summary.component.html} (100%) rename ui/src/app/metadata/{provider/component/provider-wizard-summary.component.spec.ts => domain/component/wizard-summary.component.spec.ts} (100%) create mode 100644 ui/src/app/metadata/domain/component/wizard-summary.component.ts rename ui/src/app/metadata/{provider => domain}/model/property.ts (84%) delete mode 100644 ui/src/app/metadata/provider/component/provider-wizard-summary.component.ts delete mode 100644 ui/src/app/metadata/provider/component/summary-property.component.html create mode 100644 ui/src/app/schema-form/widget/radio/radio.component.html create mode 100644 ui/src/app/schema-form/widget/radio/radio.component.ts diff --git a/backend/src/main/resources/i18n/messages.properties b/backend/src/main/resources/i18n/messages.properties index 72d6e706d..9af594612 100644 --- a/backend/src/main/resources/i18n/messages.properties +++ b/backend/src/main/resources/i18n/messages.properties @@ -253,6 +253,8 @@ label.make-default=Make Default label.metadata-provider-name-dashboard-display-only=Metadata Provider Name (Dashboard Display Only) label.default-authentication-methods=Default Authentication Method(s) +label.new-of-type=New { type } + label.filter-name=Filter Name (Dashboard Display Only) label.metadata-filter-name=Metadata Filter Name (Dashboard Display Only) label.filter-enable=Enable this Filter? diff --git a/backend/src/main/resources/i18n/messages_en.properties b/backend/src/main/resources/i18n/messages_en.properties index 6d64dd72a..9ce0bb57e 100644 --- a/backend/src/main/resources/i18n/messages_en.properties +++ b/backend/src/main/resources/i18n/messages_en.properties @@ -235,6 +235,8 @@ label.make-default=Make Default label.metadata-provider-name-dashboard-display-only=Metadata Provider Name (Dashboard Display Only) label.default-authentication-methods=Default Authentication Method(s) +label.new-of-type=New { type } + label.filter-name=Filter Name (Dashboard Display Only) label.metadata-filter-name=Metadata Filter Name (Dashboard Display Only) label.filter-enable=Enable this Filter? diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 000000000..48e341a09 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,3 @@ +{ + "lockfileVersion": 1 +} diff --git a/ui/src/app/metadata/domain/component/summary-property.component.html b/ui/src/app/metadata/domain/component/summary-property.component.html new file mode 100644 index 000000000..399b0d7fc --- /dev/null +++ b/ui/src/app/metadata/domain/component/summary-property.component.html @@ -0,0 +1,54 @@ +
+ + + + {{ property.name }} + {{ property.value || property.value === false ? property.value : '-' }} + + + + + {{ property.name }} + + +

+ + + + + + + + + + + +
+ +
+ {{ value[prop] }} +
+
+ +

+
    +
  • + {{ item }} +
  • +
+
+
+ + + {{ property.name }} + + + + + +
+
diff --git a/ui/src/app/metadata/provider/component/summary-property.component.spec.ts b/ui/src/app/metadata/domain/component/summary-property.component.spec.ts similarity index 100% rename from ui/src/app/metadata/provider/component/summary-property.component.spec.ts rename to ui/src/app/metadata/domain/component/summary-property.component.spec.ts diff --git a/ui/src/app/metadata/provider/component/summary-property.component.ts b/ui/src/app/metadata/domain/component/summary-property.component.ts similarity index 77% rename from ui/src/app/metadata/provider/component/summary-property.component.ts rename to ui/src/app/metadata/domain/component/summary-property.component.ts index 6dbd0c716..359bd223d 100644 --- a/ui/src/app/metadata/provider/component/summary-property.component.ts +++ b/ui/src/app/metadata/domain/component/summary-property.component.ts @@ -9,5 +9,9 @@ import { Property } from '../model/property'; export class SummaryPropertyComponent { @Input() property: Property; + + getKeys(schema): string[] { + return Object.keys(schema.properties); + } } diff --git a/ui/src/app/metadata/provider/component/provider-wizard-summary.component.html b/ui/src/app/metadata/domain/component/wizard-summary.component.html similarity index 100% rename from ui/src/app/metadata/provider/component/provider-wizard-summary.component.html rename to ui/src/app/metadata/domain/component/wizard-summary.component.html diff --git a/ui/src/app/metadata/provider/component/provider-wizard-summary.component.spec.ts b/ui/src/app/metadata/domain/component/wizard-summary.component.spec.ts similarity index 100% rename from ui/src/app/metadata/provider/component/provider-wizard-summary.component.spec.ts rename to ui/src/app/metadata/domain/component/wizard-summary.component.spec.ts diff --git a/ui/src/app/metadata/domain/component/wizard-summary.component.ts b/ui/src/app/metadata/domain/component/wizard-summary.component.ts new file mode 100644 index 000000000..3d2b14912 --- /dev/null +++ b/ui/src/app/metadata/domain/component/wizard-summary.component.ts @@ -0,0 +1,113 @@ +import { Component, Input, SimpleChanges, OnChanges, Output, EventEmitter } from '@angular/core'; + +import { Wizard, WizardStep } from '../../../wizard/model'; +import { MetadataProvider, MetadataResolver } from '../../domain/model'; +import { Property } from '../model/property'; +import { getSplitSchema } from '../../../wizard/reducer'; + +interface Section { + id: string; + index: number; + label: string; + properties: Property[]; +} + +export function getDefinition(path: string, definitions): any { + let def = path.split('/').pop(); + return definitions[def]; +} + +export function getPropertyItemSchema(items: any, definitions: any): any { + if (!items) { return null; } + return items.$ref ? getDefinition(items.$ref, definitions) : items; +} + +export function getStepProperty(property, model, definitions): Property { + property = property.$ref ? getDefinition(property.$ref, definitions) : property; + return { + name: property.title, + value: model, + type: property.type, + items: getPropertyItemSchema(property.items, definitions), + properties: getStepProperties( + property, + model, + definitions + ) + }; +} + + +export function getStepProperties(schema: any, model: any, definitions: any = {}): Property[] { + if (!schema || !schema.properties) { return []; } + return Object + .keys(schema.properties) + .map(property => { + return getStepProperty( + schema.properties[property], + model[property], + definitions + ); + }); +} + +@Component({ + selector: 'wizard-summary', + templateUrl: './wizard-summary.component.html', + styleUrls: [] +}) + +export class WizardSummaryComponent implements OnChanges { + @Input() summary: { definition: Wizard, schema: { [id: string]: any }, model: any }; + + @Output() onPageSelect: EventEmitter = new EventEmitter(); + + sections: Section[]; + columns: Array
[]; + steps: WizardStep[]; + + constructor() {} + + ngOnChanges(changes: SimpleChanges): void { + if (changes.summary && this.summary) { + const schemas = this.summary.schema; + const model = this.summary.model; + const def = this.summary.definition; + const steps = def.steps; + + this.sections = steps + .filter(step => step.id !== 'summary') + .map( + (step: WizardStep) => { + return ({ + id: step.id, + index: step.index, + label: step.label, + properties: getStepProperties( + schemas[step.id] || getSplitSchema(schemas['summary'], step), + def.formatter(model), + schemas.definitions || schemas.hasOwnProperty('summary') ? schemas['summary'].definitions : {} + ) + }); + } + ); + + this.columns = this.sections.reduce((resultArray, item, index) => { + const chunkIndex = Math.floor(index / Math.round(this.sections.length / 2)); + + if (!resultArray[chunkIndex]) { + resultArray[chunkIndex] = []; + } + + resultArray[chunkIndex].push(item); + + return resultArray; + }, []); + } + } + + gotoPage(page: string = ''): void { + this.onPageSelect.emit(page); + } +} + diff --git a/ui/src/app/metadata/domain/domain.module.ts b/ui/src/app/metadata/domain/domain.module.ts index a9120f45d..359f101fb 100644 --- a/ui/src/app/metadata/domain/domain.module.ts +++ b/ui/src/app/metadata/domain/domain.module.ts @@ -15,9 +15,14 @@ import { PreviewDialogComponent } from './component/preview-dialog.component'; import { MetadataFilterService } from './service/filter.service'; import { AttributesService } from './service/attributes.service'; import { I18nModule } from '../../i18n/i18n.module'; +import { WizardSummaryComponent } from './component/wizard-summary.component'; +import { SummaryPropertyComponent } from './component/summary-property.component'; +import { NgbPopoverModule } from '@ng-bootstrap/ng-bootstrap'; export const COMPONENTS = [ - PreviewDialogComponent + PreviewDialogComponent, + WizardSummaryComponent, + SummaryPropertyComponent ]; export const DECLARATIONS = [ @@ -30,7 +35,8 @@ export const DECLARATIONS = [ imports: [ HttpModule, CommonModule, - I18nModule + I18nModule, + NgbPopoverModule ], exports: DECLARATIONS, providers: [] diff --git a/ui/src/app/metadata/provider/model/property.ts b/ui/src/app/metadata/domain/model/property.ts similarity index 84% rename from ui/src/app/metadata/provider/model/property.ts rename to ui/src/app/metadata/domain/model/property.ts index 031dce75c..3bb96b6b8 100644 --- a/ui/src/app/metadata/provider/model/property.ts +++ b/ui/src/app/metadata/domain/model/property.ts @@ -2,5 +2,6 @@ export interface Property { type: string; name: string; value: string[]; + items: Property; properties: Property[]; } diff --git a/ui/src/app/metadata/domain/model/wizards/metadata-source-wizard.ts b/ui/src/app/metadata/domain/model/wizards/metadata-source-wizard.ts index 32e938008..82c929cea 100644 --- a/ui/src/app/metadata/domain/model/wizards/metadata-source-wizard.ts +++ b/ui/src/app/metadata/domain/model/wizards/metadata-source-wizard.ts @@ -9,7 +9,7 @@ export class MetadataSourceWizard implements Wizard { index: 1, id: 'common', label: 'label.resolver-common-attributes', - schema: '/api/ui/MetadataSources', + schema: 'assets/schema/source/metadata-source.json', fields: [ 'serviceProviderName', 'entityId' @@ -17,6 +17,7 @@ export class MetadataSourceWizard implements Wizard { fieldsets: [ { type: 'section', + class: ['col-6'], fields: [ 'serviceProviderName', 'entityId' @@ -28,7 +29,7 @@ export class MetadataSourceWizard implements Wizard { index: 2, id: 'org-info', label: 'label.org-info', - schema: '/api/ui/MetadataSources', + schema: 'assets/schema/source/metadata-source.json', fields: [ 'organization', 'contacts' @@ -52,7 +53,7 @@ export class MetadataSourceWizard implements Wizard { index: 3, id: 'metadata-ui', label: 'label.metadata-ui', - schema: '/api/ui/MetadataSources', + schema: 'assets/schema/source/metadata-source.json', fields: [ 'mdui' ] @@ -61,7 +62,7 @@ export class MetadataSourceWizard implements Wizard { index: 4, id: 'descriptor-info', label: 'label.descriptor-info', - schema: '/api/ui/MetadataSources', + schema: 'assets/schema/source/metadata-source.json', fields: [ 'serviceProviderSsoDescriptor' ] @@ -70,7 +71,7 @@ export class MetadataSourceWizard implements Wizard { index: 5, id: 'logout-endpoints', label: 'label.logout-endpoints', - schema: '/api/ui/MetadataSources', + schema: 'assets/schema/source/metadata-source.json', fields: [ 'logoutEndpoints' ], @@ -87,7 +88,7 @@ export class MetadataSourceWizard implements Wizard { index: 6, id: 'key-info', label: 'label.key-info', - schema: '/api/ui/MetadataSources', + schema: 'assets/schema/source/metadata-source.json', fields: [ 'securityInfo' ] @@ -96,34 +97,58 @@ export class MetadataSourceWizard implements Wizard { index: 7, id: 'assertion', label: 'label.assertion', - schema: '/api/ui/MetadataSources', + schema: 'assets/schema/source/metadata-source.json', fields: [ 'assertionConsumerServices' + ], + fieldsets: [ + { + type: 'group', + fields: [ + 'assertionConsumerServices' + ] + } ] }, { index: 8, id: 'relying-party', label: 'label.relying-party', - schema: '/api/ui/MetadataSources', + schema: 'assets/schema/source/metadata-source.json', fields: [ 'relyingPartyOverrides' + ], + fieldsets: [ + { + type: 'group', + fields: [ + 'relyingPartyOverrides' + ] + } ] }, { index: 9, id: 'attribute', label: 'label.attribute-release', - schema: '/api/ui/MetadataSources', + schema: 'assets/schema/source/metadata-source.json', fields: [ 'attributeRelease' + ], + fieldsets: [ + { + type: 'group', + fields: [ + 'attributeRelease' + ] + } ] }, { index: 10, - id: 'finish', + id: 'summary', label: 'label.finished', - schema: '/api/ui/MetadataSources', + schema: 'assets/schema/source/metadata-source.json', fields: [ 'serviceEnabled' ], diff --git a/ui/src/app/metadata/provider/component/provider-wizard-summary.component.ts b/ui/src/app/metadata/provider/component/provider-wizard-summary.component.ts deleted file mode 100644 index 8d350d163..000000000 --- a/ui/src/app/metadata/provider/component/provider-wizard-summary.component.ts +++ /dev/null @@ -1,83 +0,0 @@ -import { Component, Input, SimpleChanges, OnChanges, Output, EventEmitter } from '@angular/core'; -import { Store } from '@ngrx/store'; - -import * as fromProvider from '../reducer'; -import { Wizard, WizardStep } from '../../../wizard/model'; -import { MetadataProvider } from '../../domain/model'; -import { Property } from '../model/property'; - -interface Section { - id: string; - index: number; - label: string; - properties: Property[]; -} - -export function getStepProperties(schema: any, model: any): Property[] { - if (!schema || !schema.properties) { return []; } - return Object.keys(schema.properties).map(property => ({ - name: schema.properties[property].title, - value: (model && model.hasOwnProperty(property)) ? model[property] : null, - type: schema.properties[property].type, - properties: schema.properties ? getStepProperties( - schema.properties[property], - (model && model.hasOwnProperty(property)) ? model[property] : null - ) : [] - })); -} - -@Component({ - selector: 'provider-wizard-summary', - templateUrl: './provider-wizard-summary.component.html', - styleUrls: [] -}) - -export class ProviderWizardSummaryComponent implements OnChanges { - @Input() summary: { definition: Wizard, schema: { [id: string]: any }, model: any }; - - @Output() onPageSelect: EventEmitter = new EventEmitter(); - - sections: Section[]; - columns: Array
[]; - - constructor( - private store: Store - ) {} - - ngOnChanges(changes: SimpleChanges): void { - if (changes.summary && this.summary) { - const schemas = this.summary.schema; - const model = this.summary.model; - const def = this.summary.definition; - const steps = def.steps; - - this.sections = steps - .filter(step => step.id !== 'summary') - .map( - (step: WizardStep) => ({ - id: step.id, - index: step.index, - label: step.label, - properties: getStepProperties(schemas[step.id], def.formatter(model)) - }) - ); - - this.columns = this.sections.reduce((resultArray, item, index) => { - const chunkIndex = Math.floor(index / Math.round(this.sections.length / 2)); - - if (!resultArray[chunkIndex]) { - resultArray[chunkIndex] = []; - } - - resultArray[chunkIndex].push(item); - - return resultArray; - }, []); - } - } - - gotoPage(page: string = ''): void { - this.onPageSelect.emit(page); - } -} - diff --git a/ui/src/app/metadata/provider/component/summary-property.component.html b/ui/src/app/metadata/provider/component/summary-property.component.html deleted file mode 100644 index a4b4b57b5..000000000 --- a/ui/src/app/metadata/provider/component/summary-property.component.html +++ /dev/null @@ -1,18 +0,0 @@ -
- - - - {{ property.name }} - {{ property.value || property.value === false ? property.value : '-' }} - - - - - {{ property.name }} - - - - - - -
diff --git a/ui/src/app/metadata/provider/container/provider-wizard.component.html b/ui/src/app/metadata/provider/container/provider-wizard.component.html index 650a2ed82..b1027711b 100644 --- a/ui/src/app/metadata/provider/container/provider-wizard.component.html +++ b/ui/src/app/metadata/provider/container/provider-wizard.component.html @@ -18,11 +18,11 @@ - - +
diff --git a/ui/src/app/metadata/provider/provider.module.ts b/ui/src/app/metadata/provider/provider.module.ts index 550b5c198..1aaedf997 100644 --- a/ui/src/app/metadata/provider/provider.module.ts +++ b/ui/src/app/metadata/provider/provider.module.ts @@ -9,14 +9,12 @@ import { NgbDropdownModule, NgbModalModule } from '@ng-bootstrap/ng-bootstrap'; import { ProviderWizardComponent } from './container/provider-wizard.component'; import { ProviderWizardStepComponent } from './container/provider-wizard-step.component'; -import { ProviderWizardSummaryComponent } from './component/provider-wizard-summary.component'; import { ProviderComponent } from './container/provider.component'; import { WizardModule } from '../../wizard/wizard.module'; import * as fromProvider from './reducer'; import { EditorEffects } from './effect/editor.effect'; import { FormModule } from '../../schema-form/schema-form.module'; -import { SummaryPropertyComponent } from './component/summary-property.component'; import { CollectionEffects } from './effect/collection.effect'; import { SharedModule } from '../../shared/shared.module'; import { ProviderEditComponent } from './container/provider-edit.component'; @@ -30,18 +28,17 @@ import { UnsavedProviderComponent } from './component/unsaved-provider.dialog'; import { ContentionModule } from '../../contention/contention.module'; import { DeleteFilterComponent } from './component/delete-filter.component'; import { I18nModule } from '../../i18n/i18n.module'; +import { DomainModule } from '../domain/domain.module'; @NgModule({ declarations: [ ProviderComponent, ProviderWizardComponent, ProviderWizardStepComponent, - ProviderWizardSummaryComponent, ProviderEditComponent, ProviderEditStepComponent, ProviderSelectComponent, ProviderFilterListComponent, - SummaryPropertyComponent, ProviderEditorNavComponent, UnsavedProviderComponent, DeleteFilterComponent @@ -61,7 +58,8 @@ import { I18nModule } from '../../i18n/i18n.module'; ContentionModule, NgbDropdownModule, NgbModalModule, - I18nModule + I18nModule, + DomainModule ], exports: [] }) diff --git a/ui/src/app/metadata/resolver/container/new-resolver.component.html b/ui/src/app/metadata/resolver/container/new-resolver.component.html index 6773f845b..924321a93 100644 --- a/ui/src/app/metadata/resolver/container/new-resolver.component.html +++ b/ui/src/app/metadata/resolver/container/new-resolver.component.html @@ -33,7 +33,7 @@

How are you ad class="btn btn-lg btn-block btn-secondary" aria-label="Create metadata source using the wizard" role="button" - routerLink="blank" + [routerLink]="['./']" routerLinkActive="btn-info"> Create diff --git a/ui/src/app/metadata/resolver/container/new-resolver.component.ts b/ui/src/app/metadata/resolver/container/new-resolver.component.ts index cf654069c..ab4f09103 100644 --- a/ui/src/app/metadata/resolver/container/new-resolver.component.ts +++ b/ui/src/app/metadata/resolver/container/new-resolver.component.ts @@ -1,7 +1,7 @@ import { Component } from '@angular/core'; -import { ActivatedRoute } from '@angular/router'; +import { ActivatedRoute, Router } from '@angular/router'; import { Observable, Subscription } from 'rxjs'; -import { map, withLatestFrom, distinctUntilChanged } from 'rxjs/operators'; +import { map, startWith, distinctUntilChanged, debounceTime } from 'rxjs/operators'; import { SelectDraftRequest } from '../action/draft.action'; import { Store } from '@ngrx/store'; import * as fromCollection from '../reducer'; @@ -19,11 +19,16 @@ export class NewResolverComponent { constructor( private route: ActivatedRoute, + private router: Router, private store: Store ) { - this.canSetNewType$ = this.route.queryParams.pipe( - withLatestFrom(this.route.url), - map(([params, url]) => this.route.snapshot.firstChild.routeConfig.path !== 'blank' || params.index === 'common') + this.canSetNewType$ = this.router.events.pipe( + startWith(this.route), + debounceTime(10), + map(url => { + let child = this.route.snapshot.firstChild; + return child.routeConfig.path.match('blank').length === 0 || child.params.index === 'common'; + }) ); this.actionsSubscription = this.route.queryParams.pipe( diff --git a/ui/src/app/metadata/resolver/container/resolver-wizard-step.component.html b/ui/src/app/metadata/resolver/container/resolver-wizard-step.component.html index 5d07730fd..f69fbfdf5 100644 --- a/ui/src/app/metadata/resolver/container/resolver-wizard-step.component.html +++ b/ui/src/app/metadata/resolver/container/resolver-wizard-step.component.html @@ -2,6 +2,7 @@ diff --git a/ui/src/app/metadata/resolver/container/resolver-wizard-step.component.ts b/ui/src/app/metadata/resolver/container/resolver-wizard-step.component.ts index 6b37348aa..478d569f4 100644 --- a/ui/src/app/metadata/resolver/container/resolver-wizard-step.component.ts +++ b/ui/src/app/metadata/resolver/container/resolver-wizard-step.component.ts @@ -9,6 +9,9 @@ import * as fromWizard from '../../../wizard/reducer'; import { UpdateStatus, UpdateChanges } from '../action/entity.action'; import { Wizard } from '../../../wizard/model'; import { MetadataResolver } from '../../domain/model'; +import { FormProperty } from 'ngx-schema-form/lib/model/formproperty'; +import { ArrayProperty } from 'ngx-schema-form/lib/model/arrayproperty'; +import { ObjectProperty } from 'ngx-schema-form/lib/model/objectproperty'; @Component({ selector: 'resolver-wizard-step', @@ -35,6 +38,8 @@ export class ResolverWizardStepComponent implements OnDestroy { validators$: Observable<{ [key: string]: any }>; + bindings: any; + constructor( private store: Store, ) { @@ -42,8 +47,6 @@ export class ResolverWizardStepComponent implements OnDestroy { this.definition$ = this.store.select(fromWizard.getWizardDefinition); this.changes$ = this.store.select(fromResolver.getEntityChanges); - // this.schema$.subscribe(s => console.log(s)); - this.validators$ = this.definition$.pipe( map((def) => def.getValidators()) ); @@ -83,6 +86,47 @@ export class ResolverWizardStepComponent implements OnDestroy { this.statusChangeEmitted$.pipe(distinctUntilChanged()).subscribe(errors => this.updateStatus(errors)); this.store.select(fromWizard.getWizardIndex).subscribe(i => this.currentPage = i); + + this.bindings = { + '/securityInfo/x509CertificateAvailable': [ + { + 'input': (event, property: FormProperty) => { + let available = !property.value, + parent = property.parent, + certs = parent.getProperty('x509Certificates'); + if (available && !certs.value.length) { + certs.setValue([ + { + name: '', + type: 'both', + value: '' + } + ], true); + } + + if (!available && certs.value.length > 0) { + certs.setValue([], true); + } + } + } + ], + '/assertionConsumerServices/*/makeDefault': [ + { + 'input': (event, property: FormProperty) => { + let parent = property.parent.parent as ArrayProperty; + let props = parent.properties as ObjectProperty[]; + props.forEach(prop => { + if (prop !== property) { + prop.setValue({ + ...prop.value, + makeDefault: false + }, false); + } + }); + } + } + ] + }; } updateStatus(errors: any): void { diff --git a/ui/src/app/metadata/resolver/container/resolver-wizard.component.html b/ui/src/app/metadata/resolver/container/resolver-wizard.component.html index f5d57a27d..1163fe889 100644 --- a/ui/src/app/metadata/resolver/container/resolver-wizard.component.html +++ b/ui/src/app/metadata/resolver/container/resolver-wizard.component.html @@ -2,4 +2,9 @@
-
\ No newline at end of file + + + \ No newline at end of file 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 1f98d87ed..ab205e613 100644 --- a/ui/src/app/metadata/resolver/container/resolver-wizard.component.ts +++ b/ui/src/app/metadata/resolver/container/resolver-wizard.component.ts @@ -9,8 +9,8 @@ import { ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router'; -import { Observable, Subject, of } from 'rxjs'; -import { skipWhile, startWith, distinctUntilChanged, map, defaultIfEmpty } from 'rxjs/operators'; +import { Observable, Subject, of, combineLatest as combine } from 'rxjs'; +import { skipWhile, startWith, distinctUntilChanged, map, takeUntil, combineLatest } from 'rxjs/operators'; import { Store } from '@ngrx/store'; import { NgbModal } from '@ng-bootstrap/ng-bootstrap'; @@ -58,6 +58,8 @@ export class ResolverWizardComponent implements OnDestroy, CanComponentDeactivat valid$: Observable; schema$: Observable; + summary$: Observable<{ definition: Wizard, schema: { [id: string]: any }, model: any }>; + constructor( private store: Store, private route: ActivatedRoute, @@ -92,6 +94,8 @@ export class ResolverWizardComponent implements OnDestroy, CanComponentDeactivat this.changes$ = this.store.select(fromResolver.getEntityChanges); this.schema$ = this.store.select(fromWizard.getSchema); + this.resolver$ = this.store.select(fromCollections.getSelectedDraft); + this.route.params .pipe( map(params => params.index), @@ -100,6 +104,26 @@ export class ResolverWizardComponent implements OnDestroy, CanComponentDeactivat .subscribe(index => { this.store.dispatch(new SetIndex(index)); }); + + this.changes$.pipe( + takeUntil(this.ngUnsubscribe), + skipWhile(() => this.saving), + combineLatest(this.resolver$, (changes, base) => ({ ...base, ...changes })) + ).subscribe(latest => this.latest = latest); + + this.summary$ = combine( + this.store.select(fromWizard.getWizardDefinition), + this.store.select(fromWizard.getSchemaCollection), + this.store.select(fromResolver.getEntityChanges) + ).pipe( + map(([definition, schema, model]) => ( + { + definition, + schema, + model + } + )) + ); } next(): void { @@ -112,7 +136,7 @@ export class ResolverWizardComponent implements OnDestroy, CanComponentDeactivat save(): void { this.store.dispatch(new SetDisabled(true)); - this.store.dispatch(new AddResolverRequest(this.resolver)); + this.store.dispatch(new AddResolverRequest(this.latest)); } go(index: string): void { @@ -128,6 +152,10 @@ export class ResolverWizardComponent implements OnDestroy, CanComponentDeactivat ); } + gotoPage(page: string): void { + this.store.dispatch(new SetIndex(page)); + } + ngOnDestroy(): void { this.ngUnsubscribe.next(); this.ngUnsubscribe.complete(); diff --git a/ui/src/app/metadata/resolver/effect/collection.effects.ts b/ui/src/app/metadata/resolver/effect/collection.effects.ts index cb237aace..bf85c44f1 100644 --- a/ui/src/app/metadata/resolver/effect/collection.effects.ts +++ b/ui/src/app/metadata/resolver/effect/collection.effects.ts @@ -78,10 +78,13 @@ export class ResolverCollectionEffects { addResolverRequest$ = this.actions$.pipe( ofType(ResolverCollectionActionTypes.ADD_RESOLVER), map(action => action.payload), - map(provider => ({ - ...provider, - relyingPartyOverrides: removeNulls(provider.relyingPartyOverrides) - })), + map(provider => { + console.log(provider); + return ({ + ...provider, + relyingPartyOverrides: removeNulls(provider.relyingPartyOverrides) + }); + }), switchMap(provider => this.descriptorService .save(provider) diff --git a/ui/src/app/metadata/resolver/effect/draft-collection.effects.ts b/ui/src/app/metadata/resolver/effect/draft-collection.effects.ts index 8b73d331e..e731d4070 100644 --- a/ui/src/app/metadata/resolver/effect/draft-collection.effects.ts +++ b/ui/src/app/metadata/resolver/effect/draft-collection.effects.ts @@ -13,6 +13,10 @@ import { } from '../action/draft.action'; import * as actions from '../action/draft.action'; import { EntityDraftService } from '../../domain/service/draft.service'; +import * as fromResolver from '../reducer'; +import { Store } from '@ngrx/store'; +import { Clear } from '../action/entity.action'; +import { ClearWizard } from '../../../wizard/action/wizard.action'; export const getPayload = (action: any) => action.payload; @@ -75,7 +79,7 @@ export class DraftCollectionEffects { .update(provider) .pipe( map(p => new actions.UpdateDraftSuccess({ - id: p.entityId, + id: p.resourceId, changes: p })) ); @@ -114,7 +118,11 @@ export class DraftCollectionEffects { map(p => new SelectDraftRequest(p.resourceId)), catchError(e => of(new SelectDraftError())) ) - ) + ), + tap(() => { + this.store.dispatch(new ClearWizard()); + this.store.dispatch(new Clear()); + }) ); @Effect() @@ -137,6 +145,7 @@ export class DraftCollectionEffects { constructor( private draftService: EntityDraftService, private actions$: Actions, - private router: Router + private router: Router, + private store: Store ) { } } /* istanbul ignore next */ diff --git a/ui/src/app/schema-form/registry.ts b/ui/src/app/schema-form/registry.ts index b081e2cfa..f372e88f6 100644 --- a/ui/src/app/schema-form/registry.ts +++ b/ui/src/app/schema-form/registry.ts @@ -18,6 +18,7 @@ import { FilterTargetComponent } from './widget/filter-target/filter-target.comp import { ChecklistComponent } from './widget/check/checklist.component'; import { IconButtonComponent } from './widget/button/icon-button.component'; import { CustomObjectWidget } from './widget/object/object.component'; +import { CustomRadioComponent } from './widget/radio/radio.component'; export class CustomWidgetRegistry extends WidgetRegistry { constructor() { @@ -58,12 +59,12 @@ export class CustomWidgetRegistry extends WidgetRegistry { this.register('icon-button', IconButtonComponent); + this.register('radio', CustomRadioComponent); + /* NGX-Form */ this.register('range', RangeWidget); this.register('file', FileWidget); - this.register('radio', RadioWidget); - this.register('button', ButtonWidget); this.setDefaultWidget(CustomStringComponent); diff --git a/ui/src/app/schema-form/schema-form.module.ts b/ui/src/app/schema-form/schema-form.module.ts index ea7e4289a..8927b9876 100644 --- a/ui/src/app/schema-form/schema-form.module.ts +++ b/ui/src/app/schema-form/schema-form.module.ts @@ -20,6 +20,7 @@ import { ChecklistComponent } from './widget/check/checklist.component'; import { IconButtonComponent } from './widget/button/icon-button.component'; import { I18nModule } from '../i18n/i18n.module'; import { CustomObjectWidget } from './widget/object/object.component'; +import { CustomRadioComponent } from './widget/radio/radio.component'; export const COMPONENTS = [ BooleanRadioComponent, @@ -34,6 +35,7 @@ export const COMPONENTS = [ FilterTargetComponent, ChecklistComponent, IconButtonComponent, + CustomRadioComponent, CustomObjectWidget ]; 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 ebdf58ab0..4588dfb4b 100644 --- a/ui/src/app/schema-form/widget/array/array.component.html +++ b/ui/src/app/schema-form/widget/array/array.component.html @@ -13,17 +13,46 @@ -
-
- -
- +
    +
  • +
    + + + +
    + +
    +
    + +
    +
    + + +   + + + +
    +
    +
    + +
    +
    +
    +
    -
-
+ + {{ schema.description }} diff --git a/ui/src/app/schema-form/widget/array/array.component.ts b/ui/src/app/schema-form/widget/array/array.component.ts index 52987cda7..53dfb1798 100644 --- a/ui/src/app/schema-form/widget/array/array.component.ts +++ b/ui/src/app/schema-form/widget/array/array.component.ts @@ -6,4 +6,8 @@ import { ArrayWidget } from 'ngx-schema-form'; selector: 'array-component', templateUrl: `./array.component.html` }) -export class CustomArrayComponent extends ArrayWidget {} +export class CustomArrayComponent extends ArrayWidget { + getListType(property: any): string { + return property.properties.length ? property.properties[0].type : null; + } +} diff --git a/ui/src/app/schema-form/widget/object/object.component.html b/ui/src/app/schema-form/widget/object/object.component.html index 8d9a8535f..83a1f90c9 100644 --- a/ui/src/app/schema-form/widget/object/object.component.html +++ b/ui/src/app/schema-form/widget/object/object.component.html @@ -5,7 +5,8 @@ class="col" [class.d-none]="fieldset.type === 'hidden'" [class.col-lg-6]="fieldset.type === 'group'" - [class.col-lg-12]="fieldset.type === 'group-lg'"> + [class.col-lg-12]="fieldset.type === 'group-lg'" + [ngClass]="fieldset.class"> {{ fieldset.title }} diff --git a/ui/src/app/schema-form/widget/radio/radio.component.html b/ui/src/app/schema-form/widget/radio/radio.component.html new file mode 100644 index 000000000..0f2d396cf --- /dev/null +++ b/ui/src/app/schema-form/widget/radio/radio.component.html @@ -0,0 +1,11 @@ +
+ + {{schema.description}} + +
+ + +
+
+ +
\ No newline at end of file diff --git a/ui/src/app/schema-form/widget/radio/radio.component.ts b/ui/src/app/schema-form/widget/radio/radio.component.ts new file mode 100644 index 000000000..23faf2cc0 --- /dev/null +++ b/ui/src/app/schema-form/widget/radio/radio.component.ts @@ -0,0 +1,8 @@ +import { Component } from '@angular/core'; +import { RadioWidget } from 'ngx-schema-form'; + +@Component({ + selector: 'custom-radio-widget', + templateUrl: `./radio.component.html` +}) +export class CustomRadioComponent extends RadioWidget {} diff --git a/ui/src/app/wizard/model/wizard.ts b/ui/src/app/wizard/model/wizard.ts index 1a0fa48bc..35ae220c6 100644 --- a/ui/src/app/wizard/model/wizard.ts +++ b/ui/src/app/wizard/model/wizard.ts @@ -18,6 +18,7 @@ export interface WizardStep { export interface WizardFieldset { type: string; + class?: string[]; fields: string[]; } diff --git a/ui/src/assets/schema/source/metadata-source.json b/ui/src/assets/schema/source/metadata-source.json index 4784deeea..582af2b42 100644 --- a/ui/src/assets/schema/source/metadata-source.json +++ b/ui/src/assets/schema/source/metadata-source.json @@ -343,16 +343,16 @@ "description": "tooltip.omit-not-before-condition", "default": false }, - "responderId": { - "title": "label.responder-id", - "description": "tooltip.responder-id", - "type": "string" - }, "nameIdFormats": { "$ref": "#/definitions/NameIdFormatList" }, "authenticationMethods": { "$ref": "#/definitions/AuthenticationMethodList" + }, + "responderId": { + "title": "label.responder-id", + "description": "tooltip.responder-id", + "type": "string" } } }, @@ -429,9 +429,6 @@ }, "Certificate": { "type": "object", - "widget": { - "id": "fieldset" - }, "required": [ "name", "type", @@ -449,7 +446,10 @@ "title": "label.type", "description": "tooltip.certificate-type", "type": "string", - "widget": "radio", + "widget": { + "id": "radio", + "class": "form-check-inline" + }, "oneOf": [ { "enum": [ @@ -498,6 +498,7 @@ "title": "label.assertion-consumer-service-location-binding", "description": "tooltip.assertion-consumer-service-location-binding", "type": "string", + "widget": "select", "oneOf": [ { "enum": [ @@ -516,7 +517,8 @@ "makeDefault": { "title": "label.mark-as-default", "description": "tooltip.mark-as-default", - "type": "boolean" + "type": "boolean", + "default": false } } }, @@ -568,12 +570,8 @@ "title": "label.new-endpoint", "description": "tooltip.new-endpoint", "type": "object", - "widget": { - "id": "fieldset" - }, "fieldsets": [ { - "type": "section", "fields": [ "url", "bindingType" diff --git a/ui/src/theme/list.scss b/ui/src/theme/list.scss index 2fa09b033..5acc06806 100644 --- a/ui/src/theme/list.scss +++ b/ui/src/theme/list.scss @@ -13,4 +13,12 @@ min-height: 30px; } } -} \ No newline at end of file +} + +.no-style { + list-style: none; + padding: 0px; + & > li { + padding: 0px; + } +}