diff --git a/ui/src/app/form/component/CustomFieldTemplate.js b/ui/src/app/form/component/CustomFieldTemplate.js
new file mode 100644
index 000000000..39a1a0202
--- /dev/null
+++ b/ui/src/app/form/component/CustomFieldTemplate.js
@@ -0,0 +1,52 @@
+import React from "react";
+
+import Form from "react-bootstrap/Form";
+import ListGroup from "react-bootstrap/ListGroup";
+
+import {Translate} from '../../i18n/components/translate';
+
+export function CustomFieldTemplate ({
+ id,
+ children,
+ displayLabel,
+ rawErrors = [],
+ rawHelp,
+ rawDescription,
+ ...props
+}) {
+
+ console.log(props);
+ return (
+ <>{!props.hidden ?
+ {children}
+ {displayLabel && rawDescription ? (
+ 0 ? "text-danger" : "text-muted"}>
+
+
+ ) : null}
+ {rawErrors.length > 0 && (
+
+ {rawErrors.map((error) => {
+ return (
+
+
+ {error}
+
+
+ );
+ })}
+
+ )}
+ {rawHelp && (
+ 0 ? "text-danger" : "text-muted"}
+ id={id}>
+
+
+ )}
+
+ : <>>}>
+ );
+};
+
+export default CustomFieldTemplate;
\ No newline at end of file
diff --git a/ui/src/app/form/component/index.js b/ui/src/app/form/component/index.js
new file mode 100644
index 000000000..a8888fab1
--- /dev/null
+++ b/ui/src/app/form/component/index.js
@@ -0,0 +1,3 @@
+export const fields = {
+ // SchemaField: CustomSchemaField
+};
\ No newline at end of file
diff --git a/ui/src/app/i18n/hooks.js b/ui/src/app/i18n/hooks.js
index 24555514d..4638d5e8d 100644
--- a/ui/src/app/i18n/hooks.js
+++ b/ui/src/app/i18n/hooks.js
@@ -1,6 +1,17 @@
import { useContext } from 'react';
import { I18nContext } from './context/I18n.provider';
+export function translate(value, interpolated) {
+ return Object.entries(interpolated).reduce((current, interpolate) => {
+ let reg = new RegExp(`{\\s*${interpolate[0]}\\s*}`, 'gm');
+ return current.replace(reg, interpolate[1]);
+ }, value);
+}
+
+export function getMessage(value, messages) {
+ return messages.hasOwnProperty(value) ? messages[value] : (Object.keys(messages).length ? value : '');
+}
+
export function useCurrentLanguage () {
}
@@ -11,13 +22,10 @@ export function useCurrentLocale () {
export function useTranslation (value, interpolated = {}) {
const messages = useContext(I18nContext);
- let val = messages.hasOwnProperty(value) ? messages[value] : (Object.keys(messages).length ? value : '');
+ const val = getMessage(value, messages);
return useInterpolatedTranslation(val, interpolated);
}
export function useInterpolatedTranslation(value, interpolated) {
- return Object.entries(interpolated).reduce((current, interpolate) => {
- let reg = new RegExp(`{\\s*${interpolate[0]}\\s*}`, 'gm');
- return current.replace(reg, interpolate[1]);
- }, value);
-}
+ return translate(value, interpolated);
+}
\ No newline at end of file
diff --git a/ui/src/app/metadata/domain/filter/component/MetadataFilterConfigurationListItem.js b/ui/src/app/metadata/domain/filter/component/MetadataFilterConfigurationListItem.js
index 6b2fa4d09..d99d5767b 100644
--- a/ui/src/app/metadata/domain/filter/component/MetadataFilterConfigurationListItem.js
+++ b/ui/src/app/metadata/domain/filter/component/MetadataFilterConfigurationListItem.js
@@ -6,16 +6,16 @@ import { faArrowCircleDown, faArrowCircleUp, faChevronUp, faEdit, faTrash } from
import { Translate } from '../../../../i18n/components/translate';
import { Link } from 'react-router-dom';
import { getDefinition } from '../../../domain/index';
-import { useMetadataSchema } from '../../../hooks/api';
import { MetadataConfiguration } from '../../../component/MetadataConfiguration';
import { useMetadataConfiguration } from '../../../hooks/configuration';
+import useFetch from 'use-http';
export function MetadataFilterConfigurationListItem ({ filter, isLast, isFirst, onOrderUp, onOrderDown, editable, onRemove, index }) {
const [open, setOpen] = React.useState(false);
const definition = React.useMemo(() => getDefinition(filter['@type'], ), [filter]);
- const { get, response } = useMetadataSchema();
+ const { get, response } = useFetch('');
const [schema, setSchema] = React.useState();
diff --git a/ui/src/app/metadata/domain/filter/component/MetadataFilterVersionListItem.js b/ui/src/app/metadata/domain/filter/component/MetadataFilterVersionListItem.js
index 8a765daf5..3a69b5717 100644
--- a/ui/src/app/metadata/domain/filter/component/MetadataFilterVersionListItem.js
+++ b/ui/src/app/metadata/domain/filter/component/MetadataFilterVersionListItem.js
@@ -3,8 +3,8 @@ import { faCheckSquare, faSquare } from '@fortawesome/free-regular-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { MetadataConfiguration } from '../../../component/MetadataConfiguration';
import { getDefinition } from '../../../domain/index';
-import { useMetadataSchema } from '../../../hooks/api';
import { useMetadataConfiguration } from '../../../hooks/configuration';
+import useFetch from 'use-http';
export function MetadataFilterVersionListItem ({ filters, width, selected, index, comparing, limited, onSelect }) {
@@ -13,7 +13,7 @@ export function MetadataFilterVersionListItem ({ filters, width, selected, index
const definition = React.useMemo(() => getDefinition(type), [type]);
- const { get, response } = useMetadataSchema();
+ const { get, response } = useFetch(``);
const [schema, setSchema] = React.useState();
diff --git a/ui/src/app/metadata/domain/source/SourceDefinition.js b/ui/src/app/metadata/domain/source/SourceDefinition.js
index 39d5ed28d..f838317ac 100644
--- a/ui/src/app/metadata/domain/source/SourceDefinition.js
+++ b/ui/src/app/metadata/domain/source/SourceDefinition.js
@@ -115,6 +115,11 @@ export const SourceBase = {
}
};
return validators;
+ },
+ uiSchema: {
+ mdui: {
+ 'ui:widget': 'hidden'
+ }
}
}
diff --git a/ui/src/app/metadata/editor/MetadataEditor.js b/ui/src/app/metadata/editor/MetadataEditor.js
index 87abaf913..e1998e820 100644
--- a/ui/src/app/metadata/editor/MetadataEditor.js
+++ b/ui/src/app/metadata/editor/MetadataEditor.js
@@ -34,10 +34,6 @@ export function MetadataEditor () {
console.log('cancel!');
};
- React.useEffect(() => {
- console.log(current)
- }, [current]);
-
return (
@@ -96,7 +92,7 @@ export function MetadataEditor () {
-
+
diff --git a/ui/src/app/metadata/editor/MetadataEditorForm.js b/ui/src/app/metadata/editor/MetadataEditorForm.js
index 3c8b325b4..12e6e5e64 100644
--- a/ui/src/app/metadata/editor/MetadataEditorForm.js
+++ b/ui/src/app/metadata/editor/MetadataEditorForm.js
@@ -2,13 +2,27 @@ import React from 'react';
import Form from '@rjsf/bootstrap-4';
-export function MetadataEditorForm ({ metadata, definition, schema }) {
+import { fields } from '../../form/component';
+import { CustomFieldTemplate } from '../../form/component/CustomFieldTemplate';
+import { useUiSchema } from '../hooks/schema';
+export function MetadataEditorForm ({ metadata, definition, schema, current }) {
+ const uiSchema = useUiSchema(definition, schema, current);
+
+ const [data, setData] = React.useState(metadata);
+
+ React.useEffect(() => setData(metadata), [metadata]);
return (
<>
-
+
+ {JSON.stringify(data, null, 4)}
>
);
}
\ No newline at end of file
diff --git a/ui/src/app/metadata/editor/MetadataEditorNav.js b/ui/src/app/metadata/editor/MetadataEditorNav.js
index 5fcb52851..6304c5be8 100644
--- a/ui/src/app/metadata/editor/MetadataEditorNav.js
+++ b/ui/src/app/metadata/editor/MetadataEditorNav.js
@@ -17,15 +17,13 @@ export function MetadataEditorNav ({ definition, current, base, children, format
React.useEffect(() => {
setActive(definition ? definition.steps.find(s => s.id === current)?.label : null);
-
- console.log(definition.steps, current);
}, [current, definition]);
return (
{format === 'dropdown' ?
-
+
diff --git a/ui/src/app/metadata/hoc/MetadataSchema.js b/ui/src/app/metadata/hoc/MetadataSchema.js
index 2dcbb76ae..2a8f4e5f8 100644
--- a/ui/src/app/metadata/hoc/MetadataSchema.js
+++ b/ui/src/app/metadata/hoc/MetadataSchema.js
@@ -1,7 +1,7 @@
import React from 'react';
import { useParams } from 'react-router';
-import { useMetadataSchema } from '../hooks/api';
import { getDefinition } from '../domain/index';
+import useFetch from 'use-http';
export const MetadataSchemaContext = React.createContext();
export const MetadataDefinitionContext = React.createContext();
@@ -14,7 +14,7 @@ export function MetadataSchema({ entity, children }) {
type === 'source' ? type : entity['@type']
), [type, entity]);
- const { get, response } = useMetadataSchema();
+ const { get, response } = useFetch(``, {}, []);
const [schema, setSchema] = React.useState();
diff --git a/ui/src/app/metadata/hooks/api.js b/ui/src/app/metadata/hooks/api.js
index ac2f66355..897ed4cbf 100644
--- a/ui/src/app/metadata/hooks/api.js
+++ b/ui/src/app/metadata/hooks/api.js
@@ -53,10 +53,6 @@ export function useMetadataProviderOrder() {
return useFetch(`${API_BASE_PATH}/MetadataResolversPositionOrder`);
}
-export function useMetadataSchema() {
- return useFetch(``);
-}
-
export function useMetadataHistory(type, id, opts = {}, i) {
return useFetch(`${API_BASE_PATH}${getMetadataPath(type)}/${id}/Versions`, opts, i);
diff --git a/ui/src/app/metadata/hooks/schema.js b/ui/src/app/metadata/hooks/schema.js
index ad5acdb65..f7b3ee2c3 100644
--- a/ui/src/app/metadata/hooks/schema.js
+++ b/ui/src/app/metadata/hooks/schema.js
@@ -1,216 +1,42 @@
-function getDefinition(path, definitions) {
- let def = path.split('/').pop();
- return definitions[def];
-}
-
-export function getPropertyItemSchema(items, definitions) {
- if (!items) { return null; }
- return items.$ref ? getDefinition(items.$ref, definitions) : items;
-}
-
-export function getStepProperty(property, model, definitions) {
- if (!property) { return null; }
- property = property.$ref ? { ...property, ...getDefinition(property.$ref, definitions) } : property;
- return {
- name: property.title,
- value: model,
- type: property.type,
- items: getPropertyItemSchema(property.items, definitions),
- properties: getStepProperties(
- property,
- model,
- definitions
- ),
- widget: property.widget instanceof String ? { id: property.widget } : { ...property.widget }
- };
-}
-
-
-export function getStepProperties(schema, model, definitions = {}) {
- if (!schema || !schema.properties) { return []; }
- return Object
- .keys(schema.properties)
- .map(property => {
- return {
- ...getStepProperty(
- schema.properties[property],
- model && model.hasOwnProperty(property) ? model[property] : null,
- definitions
- ),
- id: property
- };
- });
-}
-
-
-function omit(key, obj) {
- if (!obj) {
- return obj;
- }
- const { [key]: omitted, ...rest } = obj;
- return rest;
-}
-
-export const rollupDifferences = (prop) => {
- let updates = {
- ...prop
- };
+import React from 'react';
- if (prop.properties) {
- updates = {
- ...updates,
- properties: [
- ...prop.properties.map(p => rollupDifferences(p))
- ]
- };
- }
+import assignInWith from 'lodash/assignInWith';
+import { I18nContext } from '../../i18n/context/I18n.provider';
- prop.differences = prop.properties.some(p => p.differences);
-
- return updates;
-};
-
-export const getConfigurationSections = (models, definition, schema) => {
- return !definition || !schema || !models ? null :
- ({
- dates: models.map(m => m ? m.modifiedDate : null),
- sections: definition.steps
- .filter(step => step.id !== 'summary')
- .map(
- (step, num) => {
- return ({
- id: step.id,
- pageNumber: num + 1,
- index: step.index,
- label: step.label,
- properties: getStepProperties(
- getSplitSchema(schema, step),
- definition.formatter({}),
- schema.definitions || {}
- )
- });
- }
- )
- .map((section) => {
- return {
- ...section,
- properties: assignValueToProperties(models, section.properties, definition)
- };
- })
- .map((section) => ({
- ...section,
- differences: section.properties.some(prop => prop.differences)
- }))
- });
-};
-
-const getDifferences = (models, prop) => {
- return models.some((model, index, array) => {
- if (!array) {
- return false;
+const fillInRootProperties = (keys, ui) => {
+ return keys.reduce((sch, key, idx) => {
+ if (!sch.hasOwnProperty(key)) {
+ sch[key] = {};
}
- const prop1 = omit('modifiedDate', model[prop.id]);
- const prop2 = omit('modifiedDate', array[0][prop.id]);
- return JSON.stringify(prop1) !== JSON.stringify(prop2);
- });
-};
-
-export const assignValueToProperties = (models, properties, definition) => {
- return properties.map(prop => {
- const differences = getDifferences(models, prop);
+ return sch;
+ }, ui);
+}
- const widget = prop.type === 'array' && prop.widget && prop.widget.data ? ({
- ...prop.widget,
- data: prop.widget.data.map(item => ({
- ...item,
- differences: models
- .map((model) => {
- const value = model[prop.id];
- return value ? value.indexOf(item.key) > -1 : false;
- })
- .reduce((current, val) => current !== val ? true : false, false)
- }))
- }) : null;
+export function useUiSchema(definition, schema, current) {
- switch (prop.type) {
- case 'object':
- return {
- ...prop,
- properties: assignValueToProperties(
- models.map(model => definition.formatter(model)[prop.id] || {}),
- prop.properties,
- definition
- ),
- differences: getDifferences(models, prop)
- };
- default:
- return {
- ...prop,
- differences,
- value: models.map(model => {
- return model[prop.id];
- }),
- widget
- };
- }
- });
-};
+ const ui = React.useMemo(() => definition ? { ...definition.uiSchema } : {}, [definition]);
+ const schemaKeys = React.useMemo(() => schema ? Object.keys(schema.properties) : [], [schema]);
+ const step = React.useMemo(() => definition ? definition.steps.find(step => step.id === current) : {fields: []}, [definition, current]);
-export const getLimitedPropertiesFn = (properties) => {
- return ([
- ...properties
- .filter(p => p.differences)
- .map(p => {
- const parsed = { ...p };
- if (p.widget && p.widget.data) {
- parsed.widget = {
- ...p.widget,
- data: p.widget.data.filter(item => item.differences)
- };
- }
- if (p.properties) {
- parsed.properties = getLimitedPropertiesFn(p.properties);
- }
- return parsed;
- })
- ]);
-};
+ const filled = React.useMemo(() => fillInRootProperties(schemaKeys, ui), [schemaKeys, ui]);
-export const getSplitSchema = (schema, step) => {
- if (!schema || !step || !step.fields || !step.fields.length || !schema.properties) {
- return schema;
- }
- const keys = Object.keys(schema.properties).filter(key => step.fields.indexOf(key) > -1);
- const required = (schema.required || []).filter(val => keys.indexOf(val) > -1);
- let s = {
- type: schema.type,
- properties: {
- ...keys.reduce((properties, key) => ({ ...properties, [key]: schema.properties[key] }), {})
- }
- };
-
- if (step.override) {
- Object.keys(step.override).forEach(key => {
- let override = step.override[key];
- if (s.properties.hasOwnProperty(key)) {
- s.properties[key] = { ...s.properties[key], ...override };
+ const mapped = React.useMemo(() => {
+ return Object.keys(filled).reduce((sch, key) => {
+ const obj = { ...filled[key] };
+ if (step.fields.indexOf(key) === -1) {
+ obj["ui:widget"] = 'hidden';
}
- });
- }
+ sch[key] = obj;
+ return sch;
+ }, {})
+ }, [filled, step]);
- if (step.order) {
- s.order = step.order;
- }
+ return mapped;
+}
- if (schema.definitions) {
- s.definitions = schema.definitions;
- }
- if (required && required.length) {
- s.required = required;
- }
- if (step.fieldsets) {
- s.fieldsets = step.fieldsets;
- }
- return s;
-};
+export function useMetadataSchema(schema) {
+ return schema;
+}
+
+export * from './utility';
\ No newline at end of file
diff --git a/ui/src/app/metadata/hooks/utility.js b/ui/src/app/metadata/hooks/utility.js
new file mode 100644
index 000000000..ad5acdb65
--- /dev/null
+++ b/ui/src/app/metadata/hooks/utility.js
@@ -0,0 +1,216 @@
+function getDefinition(path, definitions) {
+ let def = path.split('/').pop();
+ return definitions[def];
+}
+
+export function getPropertyItemSchema(items, definitions) {
+ if (!items) { return null; }
+ return items.$ref ? getDefinition(items.$ref, definitions) : items;
+}
+
+export function getStepProperty(property, model, definitions) {
+ if (!property) { return null; }
+ property = property.$ref ? { ...property, ...getDefinition(property.$ref, definitions) } : property;
+ return {
+ name: property.title,
+ value: model,
+ type: property.type,
+ items: getPropertyItemSchema(property.items, definitions),
+ properties: getStepProperties(
+ property,
+ model,
+ definitions
+ ),
+ widget: property.widget instanceof String ? { id: property.widget } : { ...property.widget }
+ };
+}
+
+
+export function getStepProperties(schema, model, definitions = {}) {
+ if (!schema || !schema.properties) { return []; }
+ return Object
+ .keys(schema.properties)
+ .map(property => {
+ return {
+ ...getStepProperty(
+ schema.properties[property],
+ model && model.hasOwnProperty(property) ? model[property] : null,
+ definitions
+ ),
+ id: property
+ };
+ });
+}
+
+
+function omit(key, obj) {
+ if (!obj) {
+ return obj;
+ }
+ const { [key]: omitted, ...rest } = obj;
+ return rest;
+}
+
+export const rollupDifferences = (prop) => {
+ let updates = {
+ ...prop
+ };
+
+ if (prop.properties) {
+ updates = {
+ ...updates,
+ properties: [
+ ...prop.properties.map(p => rollupDifferences(p))
+ ]
+ };
+ }
+
+ prop.differences = prop.properties.some(p => p.differences);
+
+ return updates;
+};
+
+export const getConfigurationSections = (models, definition, schema) => {
+ return !definition || !schema || !models ? null :
+ ({
+ dates: models.map(m => m ? m.modifiedDate : null),
+ sections: definition.steps
+ .filter(step => step.id !== 'summary')
+ .map(
+ (step, num) => {
+ return ({
+ id: step.id,
+ pageNumber: num + 1,
+ index: step.index,
+ label: step.label,
+ properties: getStepProperties(
+ getSplitSchema(schema, step),
+ definition.formatter({}),
+ schema.definitions || {}
+ )
+ });
+ }
+ )
+ .map((section) => {
+ return {
+ ...section,
+ properties: assignValueToProperties(models, section.properties, definition)
+ };
+ })
+ .map((section) => ({
+ ...section,
+ differences: section.properties.some(prop => prop.differences)
+ }))
+ });
+};
+
+const getDifferences = (models, prop) => {
+ return models.some((model, index, array) => {
+ if (!array) {
+ return false;
+ }
+ const prop1 = omit('modifiedDate', model[prop.id]);
+ const prop2 = omit('modifiedDate', array[0][prop.id]);
+ return JSON.stringify(prop1) !== JSON.stringify(prop2);
+ });
+};
+
+export const assignValueToProperties = (models, properties, definition) => {
+ return properties.map(prop => {
+ const differences = getDifferences(models, prop);
+
+ const widget = prop.type === 'array' && prop.widget && prop.widget.data ? ({
+ ...prop.widget,
+ data: prop.widget.data.map(item => ({
+ ...item,
+ differences: models
+ .map((model) => {
+ const value = model[prop.id];
+ return value ? value.indexOf(item.key) > -1 : false;
+ })
+ .reduce((current, val) => current !== val ? true : false, false)
+ }))
+ }) : null;
+
+ switch (prop.type) {
+ case 'object':
+ return {
+ ...prop,
+ properties: assignValueToProperties(
+ models.map(model => definition.formatter(model)[prop.id] || {}),
+ prop.properties,
+ definition
+ ),
+ differences: getDifferences(models, prop)
+ };
+ default:
+ return {
+ ...prop,
+ differences,
+ value: models.map(model => {
+ return model[prop.id];
+ }),
+ widget
+ };
+ }
+ });
+};
+
+export const getLimitedPropertiesFn = (properties) => {
+ return ([
+ ...properties
+ .filter(p => p.differences)
+ .map(p => {
+ const parsed = { ...p };
+ if (p.widget && p.widget.data) {
+ parsed.widget = {
+ ...p.widget,
+ data: p.widget.data.filter(item => item.differences)
+ };
+ }
+ if (p.properties) {
+ parsed.properties = getLimitedPropertiesFn(p.properties);
+ }
+ return parsed;
+ })
+ ]);
+};
+
+export const getSplitSchema = (schema, step) => {
+ if (!schema || !step || !step.fields || !step.fields.length || !schema.properties) {
+ return schema;
+ }
+ const keys = Object.keys(schema.properties).filter(key => step.fields.indexOf(key) > -1);
+ const required = (schema.required || []).filter(val => keys.indexOf(val) > -1);
+ let s = {
+ type: schema.type,
+ properties: {
+ ...keys.reduce((properties, key) => ({ ...properties, [key]: schema.properties[key] }), {})
+ }
+ };
+
+ if (step.override) {
+ Object.keys(step.override).forEach(key => {
+ let override = step.override[key];
+ if (s.properties.hasOwnProperty(key)) {
+ s.properties[key] = { ...s.properties[key], ...override };
+ }
+ });
+ }
+
+ if (step.order) {
+ s.order = step.order;
+ }
+
+ if (schema.definitions) {
+ s.definitions = schema.definitions;
+ }
+ if (required && required.length) {
+ s.required = required;
+ }
+ if (step.fieldsets) {
+ s.fieldsets = step.fieldsets;
+ }
+
+ return s;
+};