Skip to content

Commit

Permalink
added selector widget
Browse files Browse the repository at this point in the history
  • Loading branch information
rmathis committed Oct 12, 2022
1 parent 5e85383 commit abe47db
Show file tree
Hide file tree
Showing 9 changed files with 118 additions and 6 deletions.
3 changes: 3 additions & 0 deletions backend/src/main/resources/i18n/messages.properties
Original file line number Diff line number Diff line change
Expand Up @@ -510,6 +510,9 @@ label.compare-selected=Compare Selected
label.restore-version=Restore Version ({ date })
label.group=Group

label.approvers-list=Approvers
tooltip.approvers-list=List of groups who are able to approve Metadata Sources.

label.saved=Saved
label.by=By

Expand Down
8 changes: 8 additions & 0 deletions ui/public/assets/schema/groups/group.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,14 @@
"title": "label.url-validation-regex",
"description": "tooltip.url-validation-regex",
"type": "string"
},
"approversList": {
"title": "label.approvers-list",
"description": "tooltip.approvers-list",
"type": "array",
"items": {
"type": "string"
}
}
}
}
12 changes: 10 additions & 2 deletions ui/src/app/admin/Groups.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,18 @@ export function Groups() {
</GroupsProvider>
} />
<Route path={`${path}/new`} render={() =>
<NewGroup />
<GroupsProvider>
{(groups) =>
<NewGroup groups={groups} />
}
</GroupsProvider>
} />
<Route path={`${path}/:id/edit`} render={() =>
<EditGroup />
<GroupsProvider>
{(groups) =>
<EditGroup groups={groups} />
}
</GroupsProvider>
} />
<Route path={`${path}`} exact render={() =>
<Redirect to={`${url}/list`} />
Expand Down
3 changes: 2 additions & 1 deletion ui/src/app/admin/component/GroupForm.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import Translate from '../../i18n/components/translate';
import { useGroupUiSchema, useGroupUiValidator } from '../hooks';
import { FormContext, setFormDataAction, setFormErrorAction } from '../../form/FormManager';

export function GroupForm ({group = {}, errors = [], loading = false, schema, onSave, onCancel}) {
export function GroupForm ({group = {}, errors = [], context = {}, loading = false, schema, onSave, onCancel}) {

const { dispatch } = React.useContext(FormContext);
const onChange = ({formData, errors}) => {
Expand Down Expand Up @@ -42,6 +42,7 @@ export function GroupForm ({group = {}, errors = [], loading = false, schema, on
<div className="row">
<div className="col-12 col-lg-6 order-2">
<Form formData={group}
formContext={ context }
noHtml5Validate={true}
onChange={(form) => onChange(form)}
validate={validator}
Expand Down
3 changes: 2 additions & 1 deletion ui/src/app/admin/container/EditGroup.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { createNotificationAction, NotificationTypes, useNotificationDispatcher
import { useTranslator } from '../../i18n/hooks';
import { BASE_PATH } from '../../App.constant';

export function EditGroup() {
export function EditGroup({ groups }) {

const { id } = useParams();

Expand Down Expand Up @@ -74,6 +74,7 @@ export function EditGroup() {
<FormManager initial={group}>
{(data, errors) =>
<GroupForm
context={ { groups } }
group={data}
errors={errors}
schema={schema}
Expand Down
3 changes: 2 additions & 1 deletion ui/src/app/admin/container/NewGroup.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { createNotificationAction, NotificationTypes, useNotificationDispatcher
import { useTranslator } from '../../i18n/hooks';
import { BASE_PATH } from '../../App.constant';

export function NewGroup() {
export function NewGroup({ groups }) {
const history = useHistory();
const notifier = useNotificationDispatcher();
const translator = useTranslator();
Expand Down Expand Up @@ -66,6 +66,7 @@ export function NewGroup() {
{(data, errors) =>
<>
<GroupForm
context={ { groups } }
group={data}
errors={errors}
schema={schema}
Expand Down
9 changes: 9 additions & 0 deletions ui/src/app/admin/hooks.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,15 @@ export function useGroupUiSchema () {
return {
description: {
'ui:widget': 'textarea'
},
approversList: {
'ui:options': {
'widget': 'MultiSelectWidget',
'enum': [
'Foo',
'Bar'
]
}
}
};
}
Expand Down
4 changes: 3 additions & 1 deletion ui/src/app/form/component/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import AttributeReleaseWidget from './widgets/AttributeReleaseWidget';
import RadioWidget from './widgets/RadioWidget';
import OptionWidget from './widgets/OptionWidget';
import UpDownWidget from './widgets/UpDownWidget';
import MultiSelectWidget from './widgets/MultiSelectWidget';

import FieldTemplate from './templates/FieldTemplate';
import ArrayFieldTemplate from './templates/ArrayFieldTemplate';
Expand Down Expand Up @@ -40,5 +41,6 @@ export const widgets = {
CheckboxWidget,
RadioWidget,
UpDownWidget,
AttributeReleaseWidget
AttributeReleaseWidget,
MultiSelectWidget,
};
79 changes: 79 additions & 0 deletions ui/src/app/form/component/widgets/MultiSelectWidget.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import React from "react";

import ListGroup from "react-bootstrap/ListGroup";
import Form from "react-bootstrap/Form";


import Translate from "../../../i18n/components/translate";
import { InfoIcon } from "../InfoIcon";

import { Typeahead } from 'react-bootstrap-typeahead';
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faAsterisk } from "@fortawesome/free-solid-svg-icons";

const MultiSelectWidget = ({
id,
placeholder,
required,
readonly,
disabled,
type,
label,
value,
onChange,
onBlur,
onFocus,
autofocus,
options,
schema,
rawErrors = [],
formContext,
...props
}) => {
// const inputType = (type || schema.type) === 'string' ? 'text' : `${type || schema.type}`;

const opts = [];

React.useEffect(() => console.log(formContext), [formContext]);
React.useEffect(() => console.log(props), [props]);

const [touched, setTouched] = React.useState(false);

const [multiSelections, setMultiSelections] = React.useState([]);

return (
<Form.Group style={{ marginTop: '20px' }}>
<Form.Label className={`${(touched && rawErrors?.length > 0) ? "text-danger" : ""}`} htmlFor={`option-selector-${id}`}>
<span>
<Translate value={label || schema.title} />
{(label || schema.title) && required ? <FontAwesomeIcon icon={faAsterisk} className="text-danger ms-2" size="sm" /> : <span className="sr-only">Item {id + 1}</span>}
</span>
{schema.description && <InfoIcon value={schema.description} />}
</Form.Label>
<Typeahead
id={`option-selector-items-${id}`}
labelKey="name"
multiple
onChange={setMultiSelections}
options={opts}
placeholder="Choose approval groups..."
selected={multiSelections}
/>
{rawErrors?.length > 0 && touched && (
<ListGroup as="ul">
{rawErrors.map((error, i) => {
return (
<ListGroup.Item as="li" key={i} className={`border-0 m-0 p-0 bg-transparent ${i > 0 ? 'sr-only' : ''}`}>
<small className="m-0 text-danger">
<Translate value={error}>{error}</Translate>
</small>
</ListGroup.Item>
);
})}
</ListGroup>
)}
</Form.Group>
);
};

export default MultiSelectWidget;

0 comments on commit abe47db

Please sign in to comment.