diff --git a/ui/public/group.json b/ui/public/group.json new file mode 100644 index 000000000..07a21daa2 --- /dev/null +++ b/ui/public/group.json @@ -0,0 +1,3 @@ +{ + "name": "foo" +} \ No newline at end of file diff --git a/ui/src/app/admin/component/GroupForm.js b/ui/src/app/admin/component/GroupForm.js index 85a08d587..2f738c321 100644 --- a/ui/src/app/admin/component/GroupForm.js +++ b/ui/src/app/admin/component/GroupForm.js @@ -8,20 +8,18 @@ import Translate from '../../i18n/components/translate'; import { useGroupUiSchema } from '../hooks'; import { fields, widgets } from '../../form/component'; import { templates } from '../../form/component'; +import { FormContext, setFormDataAction } from '../../form/FormManager'; function ErrorListTemplate() { return (<>); } -export function GroupForm ({schema}) { +export function GroupForm ({group = {}, errors = [], loading = false, schema, onSave, onCancel}) { - const [errors, setErrors] = React.useState([]); - const [loading, setLoading] = React.useState(false); - const [metadata, setMetadata] = React.useState({}); - - const save = () => { }; - const cancel = () => { }; - const onChange = () => { }; + const { dispatch } = React.useContext(FormContext); + const onChange = ({formData}) => { + dispatch(setFormDataAction(formData)); + }; const uiSchema = useGroupUiSchema(); @@ -31,7 +29,7 @@ export function GroupForm ({schema}) { @@ -47,7 +45,7 @@ export function GroupForm ({schema}) {
-
onChange(form)} schema={schema} diff --git a/ui/src/app/admin/container/EditGroup.js b/ui/src/app/admin/container/EditGroup.js index 355a1d6e2..eedc86e6d 100644 --- a/ui/src/app/admin/container/EditGroup.js +++ b/ui/src/app/admin/container/EditGroup.js @@ -1,5 +1,79 @@ import React from 'react'; -export function EditGroup () { - return (<>Edit Group); +import { Prompt, useHistory } from 'react-router'; +import { useParams } from 'react-router-dom'; +import Translate from '../../i18n/components/translate'; +import { useGroups } from '../hooks'; +import { Schema } from '../../form/Schema'; +import { FormManager } from '../../form/FormManager'; + +import { GroupForm } from '../component/GroupForm'; +import { GroupProvider } from '../hoc/GroupProvider'; + +export function EditGroup() { + + const { id } = useParams(); + + const history = useHistory(); + + const { post, response, loading } = useGroups({}); + + const [blocking, setBlocking] = React.useState(false); + + async function save(metadata) { + await post(``, metadata); + if (response.ok) { + gotoDetail({ refresh: true }); + } + }; + + const cancel = () => { + gotoDetail(); + }; + + const gotoDetail = (state = null) => { + setBlocking(false); + history.push(`/groups`, state); + }; + + return ( +
+ + `message.unsaved-editor` + } + /> +
+
+
+
+ Add a new group +
+
+
+
+ + {(group) => + + {(schema) => + <>{group && + + {(data, errors) => + save(data)} + onCancel={() => cancel()} />} + + }} + + } + +
+
+
+ ); } \ No newline at end of file diff --git a/ui/src/app/admin/container/GroupsList.js b/ui/src/app/admin/container/GroupsList.js index 023b86ff5..b94a3019f 100644 --- a/ui/src/app/admin/container/GroupsList.js +++ b/ui/src/app/admin/container/GroupsList.js @@ -51,7 +51,7 @@ export function GroupsList({ groups, onDelete }) { {group.name} - + Edit diff --git a/ui/src/app/admin/container/NewGroup.js b/ui/src/app/admin/container/NewGroup.js index ab5e7d3ee..1fabd0508 100644 --- a/ui/src/app/admin/container/NewGroup.js +++ b/ui/src/app/admin/container/NewGroup.js @@ -4,7 +4,7 @@ import { Prompt, useHistory } from 'react-router'; import Translate from '../../i18n/components/translate'; import { useGroups } from '../hooks'; import { Schema } from '../../form/Schema'; - +import { FormManager } from '../../form/FormManager'; import { GroupForm } from '../component/GroupForm'; export function NewGroup() { @@ -14,8 +14,8 @@ export function NewGroup() { const [blocking, setBlocking] = React.useState(false); - async function save(metadata) { - await post(``, metadata); + async function save(group) { + await post(``, group); if (response.ok) { gotoDetail({ refresh: true }); } @@ -30,8 +30,6 @@ export function NewGroup() { history.push(`/groups`, state); }; - const [group, setGroup] = React.useState({}); - return (
- {(schema) => } + {(schema) => + + {(data, errors) => + save(data)} + onCancel={() => cancel()} />} + }
diff --git a/ui/src/app/admin/hoc/GroupProvider.js b/ui/src/app/admin/hoc/GroupProvider.js new file mode 100644 index 000000000..83674e51e --- /dev/null +++ b/ui/src/app/admin/hoc/GroupProvider.js @@ -0,0 +1,24 @@ +import React from 'react'; +import { useGroup } from '../hooks'; + +export function GroupProvider({ id, children }) { + + const [group, setGroup] = React.useState(); + + + const { get, response } = useGroup({ + cachePolicy: 'no-cache' + }); + + async function loadGroup() { + const group = await get(``); + if (response.ok) { + setGroup(group); + } + } + + /*eslint-disable react-hooks/exhaustive-deps*/ + React.useEffect(() => { loadGroup() }, []); + + return (<>{children(group)}); +} \ No newline at end of file diff --git a/ui/src/app/admin/hooks.js b/ui/src/app/admin/hooks.js index d071fb5e4..96a391944 100644 --- a/ui/src/app/admin/hooks.js +++ b/ui/src/app/admin/hooks.js @@ -6,9 +6,13 @@ export function useGroups () { } export function useGroup() { - return useFetch(`${API_BASE_PATH}/group`); + return useFetch(`/group.json`); } +/*export function useGroup() { + return useFetch(`${API_BASE_PATH}/group`); +}*/ + export function useGroupUiSchema () { return { diff --git a/ui/src/app/form/FormManager.js b/ui/src/app/form/FormManager.js new file mode 100644 index 000000000..17691970c --- /dev/null +++ b/ui/src/app/form/FormManager.js @@ -0,0 +1,107 @@ +import React from 'react'; + +const initialState = { + data: {}, + errors: [] +}; + +const FormContext = React.createContext(); + +const { Provider, Consumer } = FormContext; + +export const FormActions = { + SET_FORM_ERROR: 'set form error', + SET_FORM_DATA: 'set form data' +}; + +export const setFormDataAction = (payload) => { + return { + type: FormActions.SET_FORM_DATA, + payload + } +} + +export const setFormErrorAction = (errors) => { + return { + type: FormActions.SET_FORM_ERROR, + payload: errors + } +} + +function reducer(state, action) { + switch (action.type) { + + case FormActions.SET_FORM_ERROR: + return { + ...state, + errors: action.payload + }; + case FormActions.SET_FORM_DATA: + return { + ...state, + data: action.payload + }; + default: + return state; + } +} + +/*eslint-disable react-hooks/exhaustive-deps*/ +function FormManager({ children, initial = {} }) { + + const data = { + ...initial + }; + + const [state, dispatch] = React.useReducer(reducer, { + ...initialState, + data + }); + + + const contextValue = React.useMemo(() => ({ state, dispatch }), [state, dispatch]); + + return ( + + {children(state.data, state.errors)} + + ); +} + +function useFormErrors() { + const { state } = React.useContext(FormContext); + const { errors } = state; + + return errors; +} + +function useFormContext() { + return React.useContext(FormContext); +} + +function useFormDispatcher() { + const { dispatch } = useFormContext(); + return dispatch; +} + +function useFormState() { + const { state } = useFormContext(); + return state; +} + +function useFormData() { + const { data } = useFormContext(); + return data; +} + +export { + useFormErrors, + useFormContext, + useFormDispatcher, + useFormState, + useFormData, + FormManager, + FormContext, + Provider as FormProvider, + Consumer as FormConsumer +}; \ 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 bfae1bb73..61a67a510 100644 --- a/ui/src/app/metadata/editor/MetadataEditorNav.js +++ b/ui/src/app/metadata/editor/MetadataEditorNav.js @@ -5,15 +5,12 @@ import Dropdown from 'react-bootstrap/Dropdown'; import Button from 'react-bootstrap/Button'; import Translate from '../../i18n/components/translate'; -// import { usePagesWithErrors } from '../hoc/MetadataFormContext'; export function MetadataEditorNav ({ definition, current, children, format = 'tabs', onNavigate }) { const [routes, setRoutes] = React.useState([]); const [active, setActive] = React.useState(null); - // const errors = usePagesWithErrors(definition); - React.useEffect(() => { setRoutes(definition ? definition.steps.map(step => ({ path: step.id, label: step.label })) : []) }, [definition]);