Skip to content

Commit

Permalink
Added groups management code behind
Browse files Browse the repository at this point in the history
  • Loading branch information
rmathis committed Jun 22, 2021
1 parent db73700 commit 6fb2663
Show file tree
Hide file tree
Showing 9 changed files with 239 additions and 24 deletions.
3 changes: 3 additions & 0 deletions ui/public/group.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"name": "foo"
}
20 changes: 9 additions & 11 deletions ui/src/app/admin/component/GroupForm.js
Original file line number Diff line number Diff line change
Expand Up @@ -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();

Expand All @@ -31,23 +29,23 @@ export function GroupForm ({schema}) {
<React.Fragment>
<Button variant="info" className="mr-2"
type="button"
onClick={() => save()}
onClick={() => onSave(group)}
disabled={errors.length > 0 || loading}
aria-label="Save changes to the metadata source. You will return to the dashboard">
<FontAwesomeIcon icon={loading ? faSpinner : faSave} pulse={loading} />&nbsp;
<Translate value="action.save">Save</Translate>
</Button>
<Button variant="secondary"
type="button"
onClick={() => cancel()} aria-label="Cancel changes, go back to dashboard">
onClick={() => onCancel()} aria-label="Cancel changes, go back to dashboard">
<Translate value="action.cancel">Cancel</Translate>
</Button>
</React.Fragment>
</div>
<hr />
<div className="row">
<div className="col-12 col-lg-12 order-2">
<Form formData={metadata}
<Form formData={group}
noHtml5Validate={true}
onChange={(form) => onChange(form)}
schema={schema}
Expand Down
78 changes: 76 additions & 2 deletions ui/src/app/admin/container/EditGroup.js
Original file line number Diff line number Diff line change
@@ -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 (
<div className="container-fluid p-3">
<Prompt
when={blocking}
message={location =>
`message.unsaved-editor`
}
/>
<section className="section" tabIndex="0">
<div className="section-header bg-info p-2 text-white">
<div className="row justify-content-between">
<div className="col-md-12">
<span className="display-6"><Translate value="label.new-group">Add a new group</Translate></span>
</div>
</div>
</div>
<div className="section-body p-4 border border-top-0 border-info">
<GroupProvider id={id}>
{(group) =>
<Schema path={`/assets/schema/groups/group.json`}>
{(schema) =>
<>{group &&
<FormManager initial={group}>
{(data, errors) =>
<GroupForm
group={data}
errors={errors}
schema={schema}
loading={loading}
onSave={(data) => save(data)}
onCancel={() => cancel()} />}
</FormManager>
}</>}
</Schema>
}
</GroupProvider>
</div>
</section>
</div>
);
}
2 changes: 1 addition & 1 deletion ui/src/app/admin/container/GroupsList.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ export function GroupsList({ groups, onDelete }) {
<tr key={i}>
<td>{group.name}</td>
<td className="text-right">
<Link to={`../attributes/${group.name}/edit`} className="btn btn-link text-primary">
<Link to={`../groups/${group.name}/edit`} className="btn btn-link text-primary">
<FontAwesomeIcon icon={faEdit} size="lg" />
<span className="sr-only">
<Translate value="action.edit">Edit</Translate>
Expand Down
20 changes: 14 additions & 6 deletions ui/src/app/admin/container/NewGroup.js
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand All @@ -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 });
}
Expand All @@ -30,8 +30,6 @@ export function NewGroup() {
history.push(`/groups`, state);
};

const [group, setGroup] = React.useState({});

return (
<div className="container-fluid p-3">
<Prompt
Expand All @@ -50,7 +48,17 @@ export function NewGroup() {
</div>
<div className="section-body p-4 border border-top-0 border-info">
<Schema path={`/assets/schema/groups/group.json`}>
{(schema) => <GroupForm group={group} schema={schema} /> }
{(schema) =>
<FormManager initial={{}}>
{(data, errors) =>
<GroupForm
group={data}
errors={errors}
schema={schema}
loading={loading}
onSave={(data) => save(data)}
onCancel={() => cancel()} />}
</FormManager> }
</Schema>
</div>
</section>
Expand Down
24 changes: 24 additions & 0 deletions ui/src/app/admin/hoc/GroupProvider.js
Original file line number Diff line number Diff line change
@@ -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)}</>);
}
6 changes: 5 additions & 1 deletion ui/src/app/admin/hooks.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 {

Expand Down
107 changes: 107 additions & 0 deletions ui/src/app/form/FormManager.js
Original file line number Diff line number Diff line change
@@ -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 (
<React.Fragment>
<Provider value={contextValue}>{children(state.data, state.errors)}</Provider>
</React.Fragment>
);
}

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
};
3 changes: 0 additions & 3 deletions ui/src/app/metadata/editor/MetadataEditorNav.js
Original file line number Diff line number Diff line change
Expand Up @@ -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]);
Expand Down

0 comments on commit 6fb2663

Please sign in to comment.