From cfcb8ab4b72292ad0a0b03933c96958dc13cbdd4 Mon Sep 17 00:00:00 2001 From: Ryan Mathis Date: Mon, 14 Jun 2021 10:13:31 -0700 Subject: [PATCH 1/5] Added custom entity attribute fields --- .../main/resources/i18n/messages.properties | 7 +++++ .../schema/attribute/attribute.schema.json | 26 ++++++++++++++++++- .../attribute/CustomAttributeDefinition.js | 3 +++ 3 files changed, 35 insertions(+), 1 deletion(-) diff --git a/backend/src/main/resources/i18n/messages.properties b/backend/src/main/resources/i18n/messages.properties index 50049f5cb..802f36372 100644 --- a/backend/src/main/resources/i18n/messages.properties +++ b/backend/src/main/resources/i18n/messages.properties @@ -140,11 +140,18 @@ label.entity-attribute-default=Default Value tooltip.entity-attribute-default=Default Value label.entity-attribute-list-options=List options tooltip.entity-attribute-list-options=List options +label.entity-attribute-friendly-name=Friendly name +tooltip.entity-attribute-friendly-name=Friendly name +label.entity-attribute-attr-name=Attribute name +tooltip.entity-attribute-attr-name=This is normally a uri or urn +label.entity-attribute-display-name=Display name +tooltip.entity-attribute-display-name=Display name label.entity-attributes=Entity Attributes label.custom-entity-attributes=Custom Entity Attributes label.help-text=Help text label.default-value=Default Value +label.new-attribute=New Custom Entity Attribute label.metadata-source=Metadata Source label.metadata-sources=Metadata Sources diff --git a/ui/public/assets/schema/attribute/attribute.schema.json b/ui/public/assets/schema/attribute/attribute.schema.json index cc99dc3a6..b821ed7bb 100644 --- a/ui/public/assets/schema/attribute/attribute.schema.json +++ b/ui/public/assets/schema/attribute/attribute.schema.json @@ -2,7 +2,10 @@ "type": "object", "required": [ "name", - "attributeType" + "attributeType", + "attributeFriendlyName", + "attributeName", + "displayName" ], "properties": { "name": { @@ -27,6 +30,27 @@ "value.list" ] }, + "attributeFriendlyName": { + "type": "string", + "title": "label.entity-attribute-friendly-name", + "description": "tooltip.entity-attribute-friendly-name", + "minLength": 1, + "maxLength": 255 + }, + "attributeName": { + "type": "string", + "title": "label.entity-attribute-attr-name", + "description": "tooltip.entity-attribute-attr-name", + "minLength": 1, + "maxLength": 255 + }, + "displayName": { + "type": "string", + "title": "label.entity-attribute-display-name", + "description": "tooltip.entity-attribute-display-name", + "minLength": 1, + "maxLength": 255 + }, "helpText": { "title": "label.entity-attribute-help", "description": "tooltip.entity-attribute-help", diff --git a/ui/src/app/metadata/domain/attribute/CustomAttributeDefinition.js b/ui/src/app/metadata/domain/attribute/CustomAttributeDefinition.js index d04cfab6e..a5ea258c6 100644 --- a/ui/src/app/metadata/domain/attribute/CustomAttributeDefinition.js +++ b/ui/src/app/metadata/domain/attribute/CustomAttributeDefinition.js @@ -15,6 +15,9 @@ export const CustomAttributeDefinition = { fields: [ 'name', 'attributeType', + 'attributeName', + 'attributeFriendlyName', + 'displayName', 'helpText' ] }, From fa801f2642817591bf5dbd5b7e21736d02780db5 Mon Sep 17 00:00:00 2001 From: Ryan Mathis Date: Thu, 17 Jun 2021 14:45:39 -0700 Subject: [PATCH 2/5] adding custom attribute types --- .../schema/attribute/attribute.schema.json | 107 ++++++++++++++++-- ui/src/app/App.js | 1 + 2 files changed, 101 insertions(+), 7 deletions(-) diff --git a/ui/public/assets/schema/attribute/attribute.schema.json b/ui/public/assets/schema/attribute/attribute.schema.json index b821ed7bb..97bf5c4f0 100644 --- a/ui/public/assets/schema/attribute/attribute.schema.json +++ b/ui/public/assets/schema/attribute/attribute.schema.json @@ -22,12 +22,20 @@ "enum": [ "STRING", "BOOLEAN", - "SELECTION_LIST" + "SELECTION_LIST", + "LONG", + "DOUBLE", + "DURATION", + "SPRING_BEAN_ID" ], "enumNames": [ "value.string", "value.boolean", - "value.list" + "value.list", + "value.long", + "value.double", + "value.duration", + "value.spring-bean-id" ] }, "attributeFriendlyName": { @@ -44,6 +52,30 @@ "minLength": 1, "maxLength": 255 }, + "persistFriendlyName": { + "type": "string", + "title": "label.entity-attribute-friendly-name", + "description": "tooltip.entity-attribute-friendly-name", + "minLength": 1, + "maxLength": 255 + }, + "persistType": { + "type": "string", + "title": "label.entity-attribute-attr-name", + "description": "tooltip.entity-attribute-attr-name", + "minLength": 1, + "maxLength": 255, + "enum": [ + "boolean", + "string", + "number" + ], + "enumNames": [ + "boolean", + "string", + "number" + ] + }, "displayName": { "type": "string", "title": "label.entity-attribute-display-name", @@ -69,7 +101,7 @@ "STRING" ] }, - "defaultValueString": { + "defaultValue": { "title": "label.entity-attribute-default", "description": "tooltip.entity-attribute-default", "type": "string" @@ -83,12 +115,73 @@ "BOOLEAN" ] }, - "defaultValueBoolean": { + "defaultValue": { + "title": "label.entity-attribute-default", + "description": "tooltip.entity-attribute-default", + "type": "string", + "default": "true", + "enumNames": [ + "True", + "False" + ] + } + } + }, + { + "properties": { + "attributeType": { + "enum": [ + "DURATION" + ] + }, + "defaultValue": { + "title": "label.entity-attribute-default", + "description": "tooltip.entity-attribute-default", + "type": "string", + "pattern": "^(R\\d*\\/)?P(?:\\d+(?:\\.\\d+)?Y)?(?:\\d+(?:\\.\\d+)?M)?(?:\\d+(?:\\.\\d+)?W)?(?:\\d+(?:\\.\\d+)?D)?(?:T(?:\\d+(?:\\.\\d+)?H)?(?:\\d+(?:\\.\\d+)?M)?(?:\\d+(?:\\.\\d+)?S)?)?$" + } + } + }, + { + "properties": { + "attributeType": { + "enum": [ + "LONG" + ] + }, + "defaultValue": { + "title": "label.entity-attribute-default", + "description": "tooltip.entity-attribute-default", + "type": "string" + } + } + }, + { + "properties": { + "attributeType": { + "enum": [ + "DOUBLE" + ] + }, + "defaultValue": { + "title": "label.entity-attribute-default", + "description": "tooltip.entity-attribute-default", + "type": "string" + } + } + }, + { + "properties": { + "attributeType": { + "enum": [ + "INTEGER" + ] + }, + "defaultValue": { "title": "label.entity-attribute-default", "description": "tooltip.entity-attribute-default", - "type": "boolean", - "default": true, - "enumNames": ["True", "False"] + "type": "string", + "pattern": "^\\d+$" } } }, diff --git a/ui/src/app/App.js b/ui/src/app/App.js index 097c0095d..5d0c4e1e4 100644 --- a/ui/src/app/App.js +++ b/ui/src/app/App.js @@ -34,6 +34,7 @@ function App() { const [showTimeout] = React.useState(); const httpOptions = { + cachePolicy: 'no-cache', redirect: 'manual', interceptors: { request: async ({options, url, path, route}) => { From 23a1c6ee7b759de4bbfea2b8f0697bb3bdd12c19 Mon Sep 17 00:00:00 2001 From: Ryan Mathis Date: Fri, 18 Jun 2021 13:08:20 -0700 Subject: [PATCH 3/5] implemented check for rawErrors length --- ui/src/app/form/component/fields/FilterTargetField.js | 2 +- ui/src/app/form/component/templates/FieldTemplate.js | 4 ++-- ui/src/app/form/component/widgets/OptionWidget.js | 6 +++--- ui/src/app/form/component/widgets/SelectWidget.js | 6 +++--- ui/src/app/form/component/widgets/TextWidget.js | 8 ++++---- ui/src/app/form/component/widgets/TextareaWidget.js | 4 ++-- ui/src/app/form/component/widgets/UpDownWidget.js | 2 +- 7 files changed, 16 insertions(+), 16 deletions(-) diff --git a/ui/src/app/form/component/fields/FilterTargetField.js b/ui/src/app/form/component/fields/FilterTargetField.js index bad90052e..2bfd8484d 100644 --- a/ui/src/app/form/component/fields/FilterTargetField.js +++ b/ui/src/app/form/component/fields/FilterTargetField.js @@ -74,7 +74,7 @@ const FilterTargetField = ({ /*eslint-disable react-hooks/exhaustive-deps*/ React.useEffect(() => { - if (term && term.length >= 4) { + if (term?.length >= 4) { searchIds(term); } }, [term]); diff --git a/ui/src/app/form/component/templates/FieldTemplate.js b/ui/src/app/form/component/templates/FieldTemplate.js index 1e2b8f7eb..1203d543a 100644 --- a/ui/src/app/form/component/templates/FieldTemplate.js +++ b/ui/src/app/form/component/templates/FieldTemplate.js @@ -24,8 +24,8 @@ export function FieldTemplate ({ {children}
- {rawHelp && rawErrors.length < 1 && ( - 0 ? "text-danger" : "text-muted"} id={id}> + {rawHelp && rawErrors?.length < 1 && ( + 0 ? "text-danger" : "text-muted"} id={id}> )} diff --git a/ui/src/app/form/component/widgets/OptionWidget.js b/ui/src/app/form/component/widgets/OptionWidget.js index 88648c0c5..142941dd3 100644 --- a/ui/src/app/form/component/widgets/OptionWidget.js +++ b/ui/src/app/form/component/widgets/OptionWidget.js @@ -90,7 +90,7 @@ const OptionWidget = ({ return ( - 0) ? "text-danger" : ""}`}> + 0) ? "text-danger" : ""}`}> {(label || schema.title) && required ? : null} @@ -104,7 +104,7 @@ const OptionWidget = ({ onChange={ _onChange } allowNew={true} multiple={false} - className={`toggle-typeahead ${rawErrors.length > 0 ? "is-invalid" : ""}`} + className={`toggle-typeahead ${rawErrors?.length > 0 ? "is-invalid" : ""}`} options={opts} placeholder={uiSchema['ui:placeholder'] ? translator(uiSchema['ui:placeholder'] ): ''} disabled={disabled || readonly} @@ -122,7 +122,7 @@ const OptionWidget = ({ toggleMenu()} disabled={disabled || readonly} /> )} - {rawErrors.length > 0 && touched && ( + {rawErrors?.length > 0 && touched && ( {rawErrors.map((error, i) => { return ( diff --git a/ui/src/app/form/component/widgets/SelectWidget.js b/ui/src/app/form/component/widgets/SelectWidget.js index 9a2cd421c..76dc99ec6 100644 --- a/ui/src/app/form/component/widgets/SelectWidget.js +++ b/ui/src/app/form/component/widgets/SelectWidget.js @@ -86,7 +86,7 @@ const SelectWidget = ({ return ( - 0 ? "text-danger" : ""}`}> + 0 ? "text-danger" : ""}`}> {(label || schema.title) && required ? : null} @@ -103,7 +103,7 @@ const SelectWidget = ({ disabled={disabled} readOnly={readonly} autoFocus={autofocus} - className={touched && rawErrors.length > 0 ? "is-invalid" : ""} + className={touched && rawErrors?.length > 0 ? "is-invalid" : ""} onBlur={ onBlur && ((event) => { @@ -132,7 +132,7 @@ const SelectWidget = ({ )} - {rawErrors.length > 0 && touched && ( + {rawErrors?.length > 0 && touched && ( {rawErrors.map((error, i) => { return ( diff --git a/ui/src/app/form/component/widgets/TextWidget.js b/ui/src/app/form/component/widgets/TextWidget.js index 08343905f..8554be911 100644 --- a/ui/src/app/form/component/widgets/TextWidget.js +++ b/ui/src/app/form/component/widgets/TextWidget.js @@ -38,10 +38,10 @@ const TextWidget = ({ _onBlur(evt); }; - // const classNames = [rawErrors.length > 0 ? "is-invalid" : "", type === 'file' ? 'custom-file-label': ""] + // const classNames = [rawErrors?.length > 0 ? "is-invalid" : "", type === 'file' ? 'custom-file-label': ""] return ( - 0 && touched ? "text-danger" : ""}`}> + 0 && touched ? "text-danger" : ""}`}> {(label || schema.title) && required ? @@ -56,7 +56,7 @@ const TextWidget = ({ required={required} disabled={disabled} readOnly={readonly} - className={rawErrors.length > 0 && touched ? "is-invalid" : ""} + className={rawErrors?.length > 0 && touched ? "is-invalid" : ""} list={schema.examples ? `examples_${id}` : undefined} type={inputType} value={value || value === 0 ? value : ""} @@ -73,7 +73,7 @@ const TextWidget = ({ })} ) : null} - {rawErrors.length > 0 && touched && ( + {rawErrors?.length > 0 && touched && ( {rawErrors.map((error, i) => { return ( diff --git a/ui/src/app/form/component/widgets/TextareaWidget.js b/ui/src/app/form/component/widgets/TextareaWidget.js index 9afdace93..4dad923ef 100644 --- a/ui/src/app/form/component/widgets/TextareaWidget.js +++ b/ui/src/app/form/component/widgets/TextareaWidget.js @@ -46,7 +46,7 @@ const TextareaWidget = ({ return ( <> - 0 ? "text-danger" : ""}`}> + 0 ? "text-danger" : ""}`}> {(label || schema.title) && required ? : null} @@ -69,7 +69,7 @@ const TextareaWidget = ({ onFocus={_onFocus} /> - {rawErrors.length > 0 && touched && ( + {rawErrors?.length > 0 && touched && ( {rawErrors.map((error, i) => { return ( diff --git a/ui/src/app/form/component/widgets/UpDownWidget.js b/ui/src/app/form/component/widgets/UpDownWidget.js index 4394a070f..9a6941852 100644 --- a/ui/src/app/form/component/widgets/UpDownWidget.js +++ b/ui/src/app/form/component/widgets/UpDownWidget.js @@ -66,7 +66,7 @@ const UpDownWidget = ({ onBlur={onCustomBlur} onFocus={_onFocus} /> - {rawErrors.length > 0 && touched && ( + {rawErrors?.length > 0 && touched && ( {rawErrors.map((error, i) => { return ( From 8db84a6e20d695d6cc665169e460aab99d980cee Mon Sep 17 00:00:00 2001 From: Ryan Mathis Date: Fri, 18 Jun 2021 14:19:56 -0700 Subject: [PATCH 4/5] fixed typeahead --- ui/src/app/form/component/widgets/OptionWidget.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/src/app/form/component/widgets/OptionWidget.js b/ui/src/app/form/component/widgets/OptionWidget.js index 142941dd3..534595ead 100644 --- a/ui/src/app/form/component/widgets/OptionWidget.js +++ b/ui/src/app/form/component/widgets/OptionWidget.js @@ -80,7 +80,7 @@ const OptionWidget = ({ } }; - const defaultInputValue = typeof value === 'object' && value && value.label ? value.label : value; + const defaultInputValue = typeof value === 'object' && value && value.label ? value.label : value ? value : ''; const [ inputValue, setInputValue ] = React.useState( defaultInputValue ); From d064f0acac055f82a5a18b2904f53922085e968b Mon Sep 17 00:00:00 2001 From: Ryan Mathis Date: Mon, 21 Jun 2021 13:31:29 -0700 Subject: [PATCH 5/5] Updated attributes definition --- backend/src/main/resources/i18n/messages.properties | 13 +++++++++++++ .../assets/schema/attribute/attribute.schema.json | 8 ++++---- .../domain/attribute/CustomAttributeDefinition.js | 2 ++ .../app/metadata/editor/MetadataAttributeEditor.js | 4 +++- 4 files changed, 22 insertions(+), 5 deletions(-) diff --git a/backend/src/main/resources/i18n/messages.properties b/backend/src/main/resources/i18n/messages.properties index 802f36372..5ed4a9874 100644 --- a/backend/src/main/resources/i18n/messages.properties +++ b/backend/src/main/resources/i18n/messages.properties @@ -104,9 +104,17 @@ value.template=Template value.string=String value.boolean=Boolean value.list=List +value.long=Long +value.double=Double +value.duration=Duration +value.spring-bean-id=Spring Bean ID value.BOOLEAN=Boolean value.SELECTION_LIST=List value.STRING=String +value.LONG=Long +value.DOUBLE=Double +value.DURATION=Duration +value.SPRING_BEAN_ID=Spring Bean ID brand.header.title=Source Management brand.logo-link-label=Shibboleth @@ -147,6 +155,11 @@ tooltip.entity-attribute-attr-name=This is normally a uri or urn label.entity-attribute-display-name=Display name tooltip.entity-attribute-display-name=Display name +label.entity-attribute-persist-friendly-name=Persist Friendly Name +label.entity-attribute-persist-type=Persist Type +tooltip.entity-attribute-persist-friendly-name=Persist Friendly Name +tooltip.entity-attribute-persist-type=Persist Type + label.entity-attributes=Entity Attributes label.custom-entity-attributes=Custom Entity Attributes label.help-text=Help text diff --git a/ui/public/assets/schema/attribute/attribute.schema.json b/ui/public/assets/schema/attribute/attribute.schema.json index 97bf5c4f0..bb731f20b 100644 --- a/ui/public/assets/schema/attribute/attribute.schema.json +++ b/ui/public/assets/schema/attribute/attribute.schema.json @@ -54,15 +54,15 @@ }, "persistFriendlyName": { "type": "string", - "title": "label.entity-attribute-friendly-name", - "description": "tooltip.entity-attribute-friendly-name", + "title": "label.entity-attribute-persist-friendly-name", + "description": "tooltip.entity-attribute-persist-friendly-name", "minLength": 1, "maxLength": 255 }, "persistType": { "type": "string", - "title": "label.entity-attribute-attr-name", - "description": "tooltip.entity-attribute-attr-name", + "title": "label.entity-attribute-persist-type", + "description": "tooltip.entity-attribute-persist-type", "minLength": 1, "maxLength": 255, "enum": [ diff --git a/ui/src/app/metadata/domain/attribute/CustomAttributeDefinition.js b/ui/src/app/metadata/domain/attribute/CustomAttributeDefinition.js index a5ea258c6..833a3962d 100644 --- a/ui/src/app/metadata/domain/attribute/CustomAttributeDefinition.js +++ b/ui/src/app/metadata/domain/attribute/CustomAttributeDefinition.js @@ -18,6 +18,8 @@ export const CustomAttributeDefinition = { 'attributeName', 'attributeFriendlyName', 'displayName', + 'persistFriendlyName', + 'persistType', 'helpText' ] }, diff --git a/ui/src/app/metadata/editor/MetadataAttributeEditor.js b/ui/src/app/metadata/editor/MetadataAttributeEditor.js index 9c13e2a5f..126444729 100644 --- a/ui/src/app/metadata/editor/MetadataAttributeEditor.js +++ b/ui/src/app/metadata/editor/MetadataAttributeEditor.js @@ -1,6 +1,7 @@ import React from 'react'; import { MetadataFormContext, setFormDataAction, setFormErrorAction } from '../hoc/MetadataFormContext'; import { MetadataDefinitionContext, MetadataSchemaContext } from '../hoc/MetadataSchema'; +import { transformErrors } from '../domain/transform'; import Form from '@rjsf/bootstrap-4'; @@ -44,7 +45,8 @@ export function MetadataAttributeEditor({ children }) { fields={fields} widgets={widgets} liveValidate={true} - ErrorList={ErrorListTemplate}> + ErrorList={ErrorListTemplate} + transformErrors={transformErrors}> <>