+ format='dropdown'
+ errors={errors}>
@@ -88,15 +91,23 @@ export function MetadataEditor () {
-
+ format='tabs'
+ errors={errors}>
-
+ {definition && schema && metadata &&
+
+ }
diff --git a/ui/src/app/metadata/editor/MetadataEditorForm.js b/ui/src/app/metadata/editor/MetadataEditorForm.js
index 34cf03c68..82bca797b 100644
--- a/ui/src/app/metadata/editor/MetadataEditorForm.js
+++ b/ui/src/app/metadata/editor/MetadataEditorForm.js
@@ -16,17 +16,12 @@ export function MetadataEditorForm ({ metadata, definition, schema, current, onC
const onSubmit = () => {};
- const [context, setContext] = React.useState(definition.steps.find(s => s.id === current));
-
- React.useEffect(() => {
- setContext(definition.steps.find(s => s.id === current))
- }, [current, definition]);
return (
<>
-
-
-
{JSON.stringify(data, null, 4)}
-
-
-
{JSON.stringify(schema, 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 6304c5be8..ecbc587b1 100644
--- a/ui/src/app/metadata/editor/MetadataEditorNav.js
+++ b/ui/src/app/metadata/editor/MetadataEditorNav.js
@@ -1,16 +1,20 @@
-import { faBars } from '@fortawesome/free-solid-svg-icons';
+import { faBars, faExclamationTriangle } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import React from 'react';
-import { NavLink } from 'react-router-dom';
import Dropdown from 'react-bootstrap/Dropdown';
import Translate from '../../i18n/components/translate';
+import { usePagesWithErrors } from '../hoc/MetadataFormContext';
-export function MetadataEditorNav ({ definition, current, base, children, format = 'tabs' }) {
+export function MetadataEditorNav ({ definition, current, base, children, format = 'tabs', onNavigate }) {
const [routes, setRoutes] = React.useState([]);
const [active, setActive] = React.useState(null);
+ const errors = usePagesWithErrors();
+
+ console.log(errors);
+
React.useEffect(() => {
setRoutes(definition ? definition.steps.map(step => ({ path: step.id, label: step.label })) : [])
}, [definition]);
@@ -29,13 +33,14 @@ export function MetadataEditorNav ({ definition, current, base, children, format
{routes.map((route, idx) =>
- onNavigate(route.path)}
aria-label={route.label}>
-
+
)}
{children &&
@@ -49,14 +54,17 @@ export function MetadataEditorNav ({ definition, current, base, children, format
diff --git a/ui/src/app/metadata/hoc/MetadataFormContext.js b/ui/src/app/metadata/hoc/MetadataFormContext.js
new file mode 100644
index 000000000..36db6a4ad
--- /dev/null
+++ b/ui/src/app/metadata/hoc/MetadataFormContext.js
@@ -0,0 +1,116 @@
+import React from 'react';
+import { MetadataDefinitionContext } from './MetadataSchema';
+import { MetadataObjectContext } from './MetadataSelector';
+
+const initialState = {
+ metadata: {},
+ errors: {}
+};
+
+const MetadataFormContext = React.createContext();
+
+const { Provider, Consumer } = MetadataFormContext;
+
+export const MetadataFormActions = {
+ SET_FORM_ERROR: 'set form error',
+ SET_FORM_DATA: 'set form data'
+};
+
+export const updateFormDataAction = (payload) => {
+ return {
+ type: MetadataFormActions.UPDATE_FORM_DATA,
+ payload
+ }
+}
+
+export const setFormDataAction = (payload) => {
+ return {
+ type: MetadataFormActions.SET_FORM_DATA,
+ payload
+ }
+}
+
+export const setFormErrorAction = (page, errors) => {
+ return {
+ type: MetadataFormActions.SET_FORM_ERROR,
+ payload: {
+ page,
+ errors
+ }
+ }
+}
+
+function reducer(state, action) {
+ switch (action.type) {
+ case MetadataFormActions.SET_FORM_ERROR:
+ return {
+ ...state,
+ errors: {
+ ...state.errors,
+ [action.payload.page]: action.payload.errors
+ }
+ };
+ case MetadataFormActions.SET_FORM_DATA:
+ return {
+ ...state,
+ metadata: action.payload
+ };
+ case MetadataFormActions.UPDATE_FORM_DATA:
+ return {
+ ...state,
+ metadata: action.payload.metadata,
+ errors: {
+ ...action.payload.errors
+ }
+ };
+ default:
+ return state;
+ }
+}
+
+/*eslint-disable react-hooks/exhaustive-deps*/
+function MetadataForm({ children }) {
+
+ const metadata = useFormattedMetadata();
+
+ const [state, dispatch] = React.useReducer(reducer, {
+ ...initialState,
+ metadata
+ });
+
+ const contextValue = React.useMemo(() => ({ state, dispatch }), [state, dispatch]);
+
+ return (
+ {children}
+ );
+}
+
+function useFormErrors () {
+ const { state } = React.useContext(MetadataFormContext);
+ const { errors } = state;
+
+ console.log(errors)
+
+ return errors;
+}
+
+function usePagesWithErrors() {
+ const errors = useFormErrors();
+
+ return Object.keys(errors).filter(p => errors[p] && Array.isArray(errors[p]) && errors[p].length > 0);
+}
+
+function useFormattedMetadata() {
+ const definition = React.useContext(MetadataDefinitionContext);
+ return definition.formatter(React.useContext(MetadataObjectContext))
+}
+
+export {
+ usePagesWithErrors,
+ useFormErrors,
+ useFormattedMetadata,
+ MetadataForm,
+ MetadataFormContext,
+ Provider as MetadataFormProvider,
+ Consumer as MetadataFormConsumer
+};
\ No newline at end of file
diff --git a/ui/src/app/metadata/view/MetadataEdit.js b/ui/src/app/metadata/view/MetadataEdit.js
new file mode 100644
index 000000000..65fce53bf
--- /dev/null
+++ b/ui/src/app/metadata/view/MetadataEdit.js
@@ -0,0 +1,11 @@
+import React from 'react';
+import { MetadataForm } from '../hoc/MetadataFormContext';
+import { MetadataEditor } from '../editor/MetadataEditor';
+
+export function MetadataEdit() {
+ return (
+
+
+
+ );
+}
\ No newline at end of file