From a3d2df8b828718c49fed8ff72a5f958e558ea0bb Mon Sep 17 00:00:00 2001 From: Ryan Mathis Date: Tue, 29 Oct 2019 10:46:51 -0700 Subject: [PATCH 1/5] removed default input directive --- .../resources/metadata-sources-ui-schema.json | 38 ++++++++---- ui/src/app/shared/constant.ts | 2 +- .../input-defaults.directive.spec.ts | 60 ------------------- .../directive/input-defaults.directive.ts | 16 ----- ui/src/app/shared/shared.module.ts | 3 - 5 files changed, 27 insertions(+), 92 deletions(-) delete mode 100644 ui/src/app/shared/directive/input-defaults.directive.spec.ts delete mode 100644 ui/src/app/shared/directive/input-defaults.directive.ts diff --git a/backend/src/main/resources/metadata-sources-ui-schema.json b/backend/src/main/resources/metadata-sources-ui-schema.json index 9d64e75b4..1bf90c362 100644 --- a/backend/src/main/resources/metadata-sources-ui-schema.json +++ b/backend/src/main/resources/metadata-sources-ui-schema.json @@ -31,17 +31,23 @@ "name": { "title": "label.organization-name", "description": "tooltip.organization-name", - "type": "string" + "type": "string", + "minLength": 1, + "maxLength": 255 }, "displayName": { "title": "label.organization-display-name", "description": "tooltip.organization-display-name", - "type": "string" + "type": "string", + "minLength": 1, + "maxLength": 255 }, "url": { "title": "label.organization-url", "description": "tooltip.organization-url", - "type": "string" + "type": "string", + "minLength": 1, + "maxLength": 255 } }, "dependencies": { @@ -101,17 +107,23 @@ "displayName": { "title": "label.display-name", "description": "tooltip.mdui-display-name", - "type": "string" + "type": "string", + "minLength": 1, + "maxLength": 255 }, "informationUrl": { "title": "label.information-url", "description": "tooltip.mdui-information-url", - "type": "string" + "type": "string", + "minLength": 1, + "maxLength": 255 }, "privacyStatementUrl": { "title": "label.privacy-statement-url", "description": "tooltip.mdui-privacy-statement-url", - "type": "string" + "type": "string", + "minLength": 1, + "maxLength": 255 }, "description": { "title": "label.description", @@ -119,26 +131,28 @@ "type": "string", "widget": { "id": "textarea" - } + }, + "minLength": 1, + "maxLength": 255 }, "logoUrl": { "title": "label.logo-url", "description": "tooltip.mdui-logo-url", - "type": "string" + "type": "string", + "minLength": 1, + "maxLength": 255 }, "logoHeight": { "title": "label.logo-height", "description": "tooltip.mdui-logo-height", "min": 0, - "type": "integer", - "default": 0 + "type": "integer" }, "logoWidth": { "title": "label.logo-width", "description": "tooltip.mdui-logo-width", "min": 0, - "type": "integer", - "default": 0 + "type": "integer" } } }, diff --git a/ui/src/app/shared/constant.ts b/ui/src/app/shared/constant.ts index a6e3fde7d..a0eaf09b8 100644 --- a/ui/src/app/shared/constant.ts +++ b/ui/src/app/shared/constant.ts @@ -1 +1 @@ -export const DEFAULT_FIELD_MAX_LENGTH = 255; \ No newline at end of file +export const DEFAULT_FIELD_MAX_LENGTH = 255; diff --git a/ui/src/app/shared/directive/input-defaults.directive.spec.ts b/ui/src/app/shared/directive/input-defaults.directive.spec.ts deleted file mode 100644 index 172c41a3f..000000000 --- a/ui/src/app/shared/directive/input-defaults.directive.spec.ts +++ /dev/null @@ -1,60 +0,0 @@ -import { Component, DebugElement } from '@angular/core'; -import { By } from '@angular/platform-browser'; -import { TestBed, ComponentFixture } from '@angular/core/testing'; -import { ReactiveFormsModule, FormsModule, NgControl } from '@angular/forms'; -import { Router } from '@angular/router'; -import { NoopAnimationsModule } from '@angular/platform-browser/animations'; -import { RouterStub } from '../../../testing/router.stub'; -import { NgbModalStub } from '../../../testing/modal.stub'; -import { InputDefaultsDirective } from './input-defaults.directive'; - -import * as constants from '../../shared/constant'; - -@Component({ - template: `` -}) -class TestComponent { - isDisabled = false; - set disableDefaults(isDisabled: boolean) { - this.isDisabled = isDisabled; - } - get disableDefaults(): boolean { - return this.isDisabled; - } -} - -describe('Input Defaults Directive', () => { - let component: TestComponent; - let fixture: ComponentFixture; - let inputEl: DebugElement; - - beforeEach(() => { - TestBed.configureTestingModule({ - providers: [], - imports: [ - FormsModule, - ReactiveFormsModule - ], - declarations: [ - InputDefaultsDirective, - TestComponent - ], - }); - - fixture = TestBed.createComponent(TestComponent); - inputEl = fixture.debugElement.query(By.css('input')); - }); - - describe('attributes', () => { - it('should add a maxlength attribute based on the constants file', () => { - fixture.detectChanges(); - expect(parseInt(inputEl.attributes.maxlength, 10)).toEqual(constants.DEFAULT_FIELD_MAX_LENGTH); - }); - - it('should be null if disableDefaults is set', () => { - fixture.componentInstance.disableDefaults = true; - fixture.detectChanges(); - expect(inputEl.attributes.maxlength).toBeNull(); - }); - }); -}); diff --git a/ui/src/app/shared/directive/input-defaults.directive.ts b/ui/src/app/shared/directive/input-defaults.directive.ts deleted file mode 100644 index 409d02ea8..000000000 --- a/ui/src/app/shared/directive/input-defaults.directive.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { Directive, Self, HostBinding, Input } from '@angular/core'; -import * as constants from '../../shared/constant'; - -@Directive({ - selector: 'input[type="text"].form-control,textarea.form-control' -}) -export class InputDefaultsDirective { - public constructor() { } - - @Input() disableDefaults = false; - - @HostBinding('attr.maxlength') - get maxlength() { - return this.disableDefaults ? null : constants.DEFAULT_FIELD_MAX_LENGTH; - } -} diff --git a/ui/src/app/shared/shared.module.ts b/ui/src/app/shared/shared.module.ts index 75dd7911c..720f2a407 100644 --- a/ui/src/app/shared/shared.module.ts +++ b/ui/src/app/shared/shared.module.ts @@ -4,7 +4,6 @@ import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { HighlightPipe } from './pipe/highlight.pipe'; import { AutoCompleteComponent } from './autocomplete/autocomplete.component'; import { ValidationClassDirective } from './validation/validation-class.directive'; -import { InputDefaultsDirective } from './directive/input-defaults.directive'; import { ValidFormIconComponent } from './component/valid-form-icon.component'; import { PrettyXml } from './pipe/pretty-xml.pipe'; import { ToggleSwitchComponent } from './switch/switch.component'; @@ -27,7 +26,6 @@ import { NgbPopoverModule } from '@ng-bootstrap/ng-bootstrap'; AutoCompleteComponent, ToggleSwitchComponent, ValidationClassDirective, - InputDefaultsDirective, ValidFormIconComponent, PrettyXml, CustomDatePipe, @@ -41,7 +39,6 @@ import { NgbPopoverModule } from '@ng-bootstrap/ng-bootstrap'; CommonModule, ReactiveFormsModule, FormsModule, - InputDefaultsDirective, ValidFormIconComponent, ValidationClassDirective, ContenteditableDirective, From 81fe87ebbb3f85a5ce3f513d6d02c9cd463e3072 Mon Sep 17 00:00:00 2001 From: Ryan Mathis Date: Tue, 5 Nov 2019 10:39:41 -0700 Subject: [PATCH 2/5] SHIBUI-1549 Fixed issue with min/max length not being applied --- .../resources/metadata-sources-ui-schema.json | 244 +++++++++--------- 1 file changed, 125 insertions(+), 119 deletions(-) diff --git a/backend/src/main/resources/metadata-sources-ui-schema.json b/backend/src/main/resources/metadata-sources-ui-schema.json index 1bf90c362..faea23464 100644 --- a/backend/src/main/resources/metadata-sources-ui-schema.json +++ b/backend/src/main/resources/metadata-sources-ui-schema.json @@ -26,50 +26,7 @@ "default": false }, "organization": { - "type": "object", - "properties": { - "name": { - "title": "label.organization-name", - "description": "tooltip.organization-name", - "type": "string", - "minLength": 1, - "maxLength": 255 - }, - "displayName": { - "title": "label.organization-display-name", - "description": "tooltip.organization-display-name", - "type": "string", - "minLength": 1, - "maxLength": 255 - }, - "url": { - "title": "label.organization-url", - "description": "tooltip.organization-url", - "type": "string", - "minLength": 1, - "maxLength": 255 - } - }, - "dependencies": { - "name": { - "required": [ - "displayName", - "url" - ] - }, - "displayName": { - "required": [ - "name", - "url" - ] - }, - "url": { - "required": [ - "name", - "displayName" - ] - } - } + "$ref": "#/definitions/Organization" }, "contacts": { "title": "label.contact-information", @@ -80,81 +37,7 @@ } }, "mdui": { - "type": "object", - "widget": { - "id": "fieldset" - }, - "fieldsets": [ - { - "type": "group", - "fields": [ - "displayName", - "informationUrl", - "description" - ] - }, - { - "type": "group", - "fields": [ - "privacyStatementUrl", - "logoUrl", - "logoWidth", - "logoHeight" - ] - } - ], - "properties": { - "displayName": { - "title": "label.display-name", - "description": "tooltip.mdui-display-name", - "type": "string", - "minLength": 1, - "maxLength": 255 - }, - "informationUrl": { - "title": "label.information-url", - "description": "tooltip.mdui-information-url", - "type": "string", - "minLength": 1, - "maxLength": 255 - }, - "privacyStatementUrl": { - "title": "label.privacy-statement-url", - "description": "tooltip.mdui-privacy-statement-url", - "type": "string", - "minLength": 1, - "maxLength": 255 - }, - "description": { - "title": "label.description", - "description": "tooltip.mdui-description", - "type": "string", - "widget": { - "id": "textarea" - }, - "minLength": 1, - "maxLength": 255 - }, - "logoUrl": { - "title": "label.logo-url", - "description": "tooltip.mdui-logo-url", - "type": "string", - "minLength": 1, - "maxLength": 255 - }, - "logoHeight": { - "title": "label.logo-height", - "description": "tooltip.mdui-logo-height", - "min": 0, - "type": "integer" - }, - "logoWidth": { - "title": "label.logo-width", - "description": "tooltip.mdui-logo-width", - "min": 0, - "type": "integer" - } - } + "$ref": "#/definitions/MDUI" }, "securityInfo": { "type": "object", @@ -538,6 +421,129 @@ ] } } + }, + "MDUI": { + "type": "object", + "widget": { + "id": "fieldset" + }, + "fieldsets": [ + { + "type": "group", + "fields": [ + "displayName", + "informationUrl", + "description" + ] + }, + { + "type": "group", + "fields": [ + "privacyStatementUrl", + "logoUrl", + "logoWidth", + "logoHeight" + ] + } + ], + "properties": { + "displayName": { + "title": "label.display-name", + "description": "tooltip.mdui-display-name", + "type": "string", + "minLength": 1, + "maxLength": 255 + }, + "informationUrl": { + "title": "label.information-url", + "description": "tooltip.mdui-information-url", + "type": "string", + "minLength": 1, + "maxLength": 255 + }, + "privacyStatementUrl": { + "title": "label.privacy-statement-url", + "description": "tooltip.mdui-privacy-statement-url", + "type": "string", + "minLength": 1, + "maxLength": 255 + }, + "description": { + "title": "label.description", + "description": "tooltip.mdui-description", + "type": "string", + "widget": { + "id": "textarea" + }, + "minLength": 1, + "maxLength": 255 + }, + "logoUrl": { + "title": "label.logo-url", + "description": "tooltip.mdui-logo-url", + "type": "string", + "minLength": 1, + "maxLength": 255 + }, + "logoHeight": { + "title": "label.logo-height", + "description": "tooltip.mdui-logo-height", + "min": 0, + "type": "integer" + }, + "logoWidth": { + "title": "label.logo-width", + "description": "tooltip.mdui-logo-width", + "min": 0, + "type": "integer" + } + } + }, + "Organization": { + "type": "object", + "properties": { + "name": { + "title": "label.organization-name", + "description": "tooltip.organization-name", + "type": "string", + "minLength": 1, + "maxLength": 255 + }, + "displayName": { + "title": "label.organization-display-name", + "description": "tooltip.organization-display-name", + "type": "string", + "minLength": 1, + "maxLength": 255 + }, + "url": { + "title": "label.organization-url", + "description": "tooltip.organization-url", + "type": "string", + "minLength": 1, + "maxLength": 255 + } + }, + "dependencies": { + "name": { + "required": [ + "displayName", + "url" + ] + }, + "displayName": { + "required": [ + "name", + "url" + ] + }, + "url": { + "required": [ + "name", + "displayName" + ] + } + } } } } \ No newline at end of file From a6ac4a87e01a48301f5cc1be882c751558a57ce5 Mon Sep 17 00:00:00 2001 From: Ryan Mathis Date: Tue, 5 Nov 2019 12:15:30 -0700 Subject: [PATCH 3/5] SHIBUI-1582 Fixed requirement in assertion consumer services --- backend/src/main/resources/metadata-sources-ui-schema.json | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/backend/src/main/resources/metadata-sources-ui-schema.json b/backend/src/main/resources/metadata-sources-ui-schema.json index faea23464..e360abdeb 100644 --- a/backend/src/main/resources/metadata-sources-ui-schema.json +++ b/backend/src/main/resources/metadata-sources-ui-schema.json @@ -336,6 +336,10 @@ "AssertionConsumerService": { "type": "object", "title": "label.assertion-consumer-service-endpoint", + "required": [ + "locationUrl", + "binding" + ], "properties": { "locationUrl": { "title": "label.assertion-consumer-service-location", From 3b040156523a58f97b404979fe6edc78d00f7ee5 Mon Sep 17 00:00:00 2001 From: Ryan Mathis Date: Tue, 5 Nov 2019 15:22:18 -0700 Subject: [PATCH 4/5] SHIBUI-1549 Fixed issue with saving/editing sources --- .../model/wizards/metadata-source-base.ts | 5 ++++- .../container/resolver-edit-step.component.ts | 18 ++++++++++++++++-- .../resolver-wizard-step.component.ts | 11 +++++++++-- .../metadata/resolver/effect/entity.effect.ts | 12 +++--------- .../resolver/reducer/collection.reducer.ts | 4 +++- 5 files changed, 35 insertions(+), 15 deletions(-) diff --git a/ui/src/app/metadata/domain/model/wizards/metadata-source-base.ts b/ui/src/app/metadata/domain/model/wizards/metadata-source-base.ts index 54ad0d58a..c011cad6d 100644 --- a/ui/src/app/metadata/domain/model/wizards/metadata-source-base.ts +++ b/ui/src/app/metadata/domain/model/wizards/metadata-source-base.ts @@ -56,7 +56,10 @@ export class MetadataSourceBase implements Wizard { }; parser(changes: Partial, schema?: any): any { - if (!changes.organization) { + if (!schema || !schema.properties) { + return changes; + } + if (schema.properties.hasOwnProperty('organization') && !changes.organization) { changes.organization = {}; } return changes; diff --git a/ui/src/app/metadata/resolver/container/resolver-edit-step.component.ts b/ui/src/app/metadata/resolver/container/resolver-edit-step.component.ts index 1a8d0d648..b00263ea8 100644 --- a/ui/src/app/metadata/resolver/container/resolver-edit-step.component.ts +++ b/ui/src/app/metadata/resolver/container/resolver-edit-step.component.ts @@ -98,9 +98,23 @@ export class ResolverEditStepComponent implements OnDestroy { this.valueChangeEmitted$.pipe( takeUntil(this.ngUnsubscribe), map(changes => changes.value), - withLatestFrom(this.definition$, this.store.select(fromResolver.getSelectedResolver), this.changes$), + withLatestFrom( + this.definition$, + this.store.select(fromResolver.getSelectedResolver), + this.changes$, + this.schema$ + ), filter(([valueChange, definition, resolver]) => definition && resolver), - map(([valueChange, definition, resolver, changes]) => definition.parser({ ...resolver, ...changes, ...valueChange })) + map(([ + valueChange, + definition, + resolver, + changes, + schema + ]) => { + const parsed = definition.parser({ ...valueChange }, schema); + return { ...resolver, ...changes, ...parsed }; + }) ) .subscribe(changes => { this.store.dispatch(new UpdateChangesRequest(changes)); 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 68840c70e..f33f0f958 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 @@ -77,9 +77,16 @@ export class ResolverWizardStepComponent implements OnDestroy { ); this.valueChangeEmitted$.pipe( - withLatestFrom(this.definition$), + withLatestFrom( + this.definition$, + this.schema$, + this.store.select(fromResolver.getSelectedDraft) + ), filter(([ changes, definition ]) => (!!definition && !!changes)), - map(([ changes, definition ]) => definition.parser(changes.value)) + map(([ changes, definition, schema, original ]) => { + const parsed = definition.parser(changes.value, schema); + return { ...original, ...parsed }; + }) ) .subscribe(changes => { this.store.dispatch(new UpdateChangesRequest(changes)); diff --git a/ui/src/app/metadata/resolver/effect/entity.effect.ts b/ui/src/app/metadata/resolver/effect/entity.effect.ts index d28f8a3db..4ad8bb586 100644 --- a/ui/src/app/metadata/resolver/effect/entity.effect.ts +++ b/ui/src/app/metadata/resolver/effect/entity.effect.ts @@ -32,16 +32,10 @@ export class EntityEffects { ofType(ResolverEntityActionTypes.UPDATE_CHANGES_REQUEST), map(action => action.payload), withLatestFrom( - this.store.select(fromResolver.getEntityChanges), - this.store.select(fromWizard.getSchema) + this.store.select(fromResolver.getEntityChanges) ), - map(([changes, stored, schema]) => { - const props = Object.keys(schema.properties); - const diffed = props.reduce((changeObj, prop) => { - changeObj[prop] = !changes.hasOwnProperty(prop) && stored.hasOwnProperty(prop) ? null : changes[prop]; - return changeObj; - }, {}); - const update = { ...stored, ...diffed }; + map(([changes, storedChanges]) => { + const update = { ...storedChanges, ...changes }; return new UpdateChangesSuccess(update); }) ); diff --git a/ui/src/app/metadata/resolver/reducer/collection.reducer.ts b/ui/src/app/metadata/resolver/reducer/collection.reducer.ts index 37fd58bb9..82addcdbd 100644 --- a/ui/src/app/metadata/resolver/reducer/collection.reducer.ts +++ b/ui/src/app/metadata/resolver/reducer/collection.reducer.ts @@ -38,7 +38,9 @@ export function reducer(state = initialState, action: ResolverCollectionActionsU } case ResolverCollectionActionTypes.UPDATE_RESOLVER_SUCCESS: { - return adapter.updateOne(action.payload, state); + const removed = adapter.removeOne(action.payload.id as string, state); + const addBack = adapter.upsertOne(action.payload.changes as MetadataResolver, removed); + return addBack; } case ResolverCollectionActionTypes.SELECT_SUCCESS: { From f93de675f40e2a02f18057f53588171a6bdf483a Mon Sep 17 00:00:00 2001 From: Ryan Mathis Date: Tue, 5 Nov 2019 15:37:59 -0700 Subject: [PATCH 5/5] SHIBUI-1549 Fixed test run --- .../resolver/component/finish-form.component.spec.ts | 2 -- .../metadata/resolver/reducer/collection.reducer.spec.ts | 8 -------- 2 files changed, 10 deletions(-) diff --git a/ui/src/app/metadata/resolver/component/finish-form.component.spec.ts b/ui/src/app/metadata/resolver/component/finish-form.component.spec.ts index 31cd48302..0fefc8788 100644 --- a/ui/src/app/metadata/resolver/component/finish-form.component.spec.ts +++ b/ui/src/app/metadata/resolver/component/finish-form.component.spec.ts @@ -12,7 +12,6 @@ import { RouterStub, RouterLinkStubDirective } from '../../../../testing/router. import { ActivatedRouteStub } from '../../../../testing/activated-route.stub'; import * as stubs from '../../../../testing/resolver.stub'; import { FileBackedHttpMetadataResolver } from '../../domain/entity'; -import { InputDefaultsDirective } from '../../../shared/directive/input-defaults.directive'; import { MockI18nModule } from '../../../../testing/i18n.stub'; import { MockListValueService } from '../../../../testing/list-values.stub'; import { MockSharedModule } from '../../../../testing/shared.stub'; @@ -58,7 +57,6 @@ describe('Finished Form Component', () => { declarations: [ FinishFormComponent, RouterLinkStubDirective, - InputDefaultsDirective, TestHostComponent ], }); diff --git a/ui/src/app/metadata/resolver/reducer/collection.reducer.spec.ts b/ui/src/app/metadata/resolver/reducer/collection.reducer.spec.ts index 80de420e4..98aafb702 100644 --- a/ui/src/app/metadata/resolver/reducer/collection.reducer.spec.ts +++ b/ui/src/app/metadata/resolver/reducer/collection.reducer.spec.ts @@ -62,14 +62,6 @@ describe('Resolver Reducer', () => { Object.assign({}, initialState, expected) ); }); - - it('should return state if the entityId is not found', () => { - let changes = { ...resolvers[1], serviceEnabled: true, id: '4' }; - const action = new resolverActions.UpdateResolverSuccess({id: changes.id, changes}); - const result = reducer({ ...snapshot }, action); - - expect(result).toEqual(snapshot); - }); }); describe('Select Resolver', () => {