Skip to content

Commit

Permalink
Updated configuration builder
Browse files Browse the repository at this point in the history
  • Loading branch information
rmathis committed Aug 29, 2022
1 parent 581050e commit 2813d25
Show file tree
Hide file tree
Showing 13 changed files with 271 additions and 184 deletions.
14 changes: 7 additions & 7 deletions ui/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
"react-bootstrap": "^2.3.0",
"react-bootstrap-typeahead": "^5.1.4",
"react-dom": "^18.0.0",
"react-hook-form": "^7.30.0",
"react-hook-form": "^7.34.0",
"react-infinite-scroll-component": "^6.1.0",
"react-router": "^5.1.0",
"react-router-dom": "^5.1.0",
Expand Down
29 changes: 29 additions & 0 deletions ui/public/assets/data/configuration.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
{
"resourceId": 11,
"name": "setname1",
"properties": [
{
"resourceId":"577",
"category":"OPSubClaim",
"configFile":"oidc.properties",
"description":"The source attribute used in generating the sub claim",
"idpVersion":"4.1",
"module":"idp.oidc.OP",
"moduleVersion":"3",
"propertyName":"idp.oidc.subject.sourceAttribute",
"displayType":"string",
"propertyValue": "foo"
},
{
"resourceId": "393",
"category": "ReloadableServices",
"configFile": "services.properties",
"defaultValue": "false",
"description": "Fail at startup if MetadataConfiguration is invalid",
"idpVersion": "all",
"propertyName": "idp.service.metadata.failFast",
"displayType": "boolean",
"propertyValue": "true"
}
]
}
174 changes: 64 additions & 110 deletions ui/src/app/admin/component/ConfigurationForm.js
Original file line number Diff line number Diff line change
@@ -1,74 +1,34 @@
import React, { Fragment } from 'react';
import React from 'react';
import Button from 'react-bootstrap/Button';
import { useFieldArray, useForm } from 'react-hook-form';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faSpinner, faSave, faTrash } from '@fortawesome/free-solid-svg-icons';
import { Highlighter, Menu, MenuItem, Token, Typeahead } from 'react-bootstrap-typeahead';

import Translate from '../../i18n/components/translate';
import { ToggleButton } from '../../form/component/ToggleButton';
import PropertySelector from './PropertySelector';

import { useProperties, usePropertiesLoading } from '../hoc/PropertiesProvider';
import { groupBy } from 'lodash';
import { useCallback } from 'react';

import Form from 'react-bootstrap/Form';
import FloatingLabel from 'react-bootstrap/FloatingLabel';

export function ConfigurationForm({ configuration = {}, errors = [], schema, onSave, onCancel }) {

const properties = useProperties();
const loading = usePropertiesLoading();
export function ConfigurationForm({ configuration = {}, schema, onSave, onCancel }) {

const select = (data) => {
console.log(data);
setSelected(data);
};
const { control, register, getValues, watch, formState: { errors } } = useForm({
defaultValues: {
...configuration
}
});

const [selected, setSelected] = React.useState([]);
const { fields, prepend, remove } = useFieldArray({
control,
name: "properties",
});

const [config, setConfig] = React.useState({ name: '', properties: [] });

// config.properties.filter(p => p.category === item.category).length === properties.filter(p => p.category === item.category).length

const menu = useCallback((results, menuProps, state) => {
let index = 0;
const mapped = results.map(p => !p.category || p.category === '?' ? { ...p, category: 'Misc' } : p);
const grouped = groupBy(mapped, 'category');
const items = Object.keys(grouped).sort().map((item) => (
<Fragment key={item}>
{index !== 0 && <Menu.Divider />}
<Menu.Header className="p-0">
<MenuItem key={index}
option={{category: item, propertyName: item, isCategory: true}}
position={index}>
{item} - Add all
</MenuItem>
</Menu.Header>
{grouped[item].map((i) => {
const item =
<MenuItem key={index} option={i} position={index} disabled={ config.properties.some((p) => p.propertyName === i.propertyName) }>
<Highlighter search={state.text}>
{`- ${i.propertyName}`}
</Highlighter>
</MenuItem>;
index += 1;
return item;
})}
</Fragment>
));

return <Menu {...menuProps}>{items}</Menu>;
}, [config.properties]);

const token = (option, { onRemove }, index) => (
<Token
key={index}
onRemove={onRemove}
option={option}>
{`${option.propertyName}`}
</Token>
);
const properties = useProperties();
const loading = usePropertiesLoading();

const addProperties = (props) => {

const parsed = props.reduce((coll, prop, idx) => {
if (prop.isCategory) {
return [...coll, ...properties.filter(p => p.category === prop.category)];
Expand All @@ -77,25 +37,28 @@ export function ConfigurationForm({ configuration = {}, errors = [], schema, onS
}
}, []);

setConfig({
...config,
properties: [
...config.properties,
...parsed,
]
});
setSelected([]);
prepend(parsed);
};

React.useEffect(() => console.log(selected), [selected]);
const saveConfig = (formValues) => {
const parsed = formValues.properties.map(p => ({
propertyName: p.propertyName,
propertyValue: p.propertyValue,
configFile: p.configFile,
}));
onSave({
...formValues,
properties: parsed
});
};

return (<>
<div className="container-fluid">
<div className="d-flex justify-content-end align-items-center">
<React.Fragment>
<Button variant="info" className="me-2"
type="button"
onClick={() => onSave(configuration)}
onClick={() => saveConfig(getValues())}
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;
Expand All @@ -109,40 +72,25 @@ export function ConfigurationForm({ configuration = {}, errors = [], schema, onS
</React.Fragment>
</div>
<hr />
<div className="row">
<div className="col-12 col-lg-6 order-2">
<div className="d-flex align-items-end">
<div className="flex-grow w-75">
<label htmlFor="property-selector">Add properties</label>
<Typeahead
id='property-selector'
onChange={selected => select(selected)}
options={[...properties]}
selected={selected}
labelKey={option => `${option.propertyName}`}
filterBy={['propertyName', 'category', 'displayType']}
renderMenu={ menu }
multiple={ true }
renderToken={ token }
>
{({ isMenuShown, toggleMenu }) => (
<ToggleButton isOpen={isMenuShown} onClick={e => toggleMenu()}>
<span className="sr-only">Options</span>
</ToggleButton>
)}
</Typeahead>
<Form>
<div className="row">
<div className="col-12 col-lg-5">
<Form.Group className="mb-3" controlId="formName">
<Form.Label>Name</Form.Label>
<Form.Control type="text" placeholder="Enter name" required {...register(`name`)} />
</Form.Group>
</div>
</div>
<div className="row">
<div className="col-12 col-lg-6 order-2">
<div className="d-flex align-items-end">
<PropertySelector options={properties} properties={fields} onAddProperties={ addProperties } />
</div>
<Button type="button"
variant="outline-secondary"
className="ms-2"
onClick={() => addProperties(selected)}>Add</Button>
</div>
</div>
</div>
<div className="my-4"></div>
<div className='row'>
<div className='col-12'>
<Form>
<div className="my-4"></div>
<div className='row'>
<div className='col-12'>
<table className='w-100 table align-middle'>
<thead>
<tr>
Expand All @@ -154,20 +102,27 @@ export function ConfigurationForm({ configuration = {}, errors = [], schema, onS
</tr>
</thead>
<tbody>
{config.properties.map((p, idx) => (
<tr key={idx}>
{fields.map((p, idx) => (
<tr key={p.id}>
<td>{ p.propertyName }</td>
<td>{ p.category }</td>
<td>{ p.displayType }</td>
<td>
<FloatingLabel
controlId={`valueInput-${p.propertyName}`}
label="value">
<Form.Control type="text" placeholder="Value" />
</FloatingLabel>
{p.displayType !== 'boolean' ?
<FloatingLabel
controlId={`valueInput-${p.propertyName}`}
label="property value">
<Form.Control type={p.displayType === 'number' ? 'number' : 'text'} placeholder="Value" {...register(`properties.${idx}.propertyValue`)} />
</FloatingLabel>
:
<Form.Check type="switch"
label={ watch(`properties.${idx}.propertyValue`) === true ? 'True' : 'False' }
reverse={'true'} {...register(`properties.${idx}.propertyValue`)}
className="my-3" />
}
</td>
<td>
<Button variant="danger">
<Button variant="danger" onClick={() => remove(idx)}>
<FontAwesomeIcon icon={faTrash} size="lg" />
Remove
</Button>
Expand All @@ -176,10 +131,9 @@ export function ConfigurationForm({ configuration = {}, errors = [], schema, onS
))}
</tbody>
</table>
</Form>
</div>
</div>
</div>
</Form>
</div>
</>)
}
/**/
}
Loading

0 comments on commit 2813d25

Please sign in to comment.