diff --git a/ui/package-lock.json b/ui/package-lock.json
index 0cc5f3665..2083b22a0 100644
--- a/ui/package-lock.json
+++ b/ui/package-lock.json
@@ -25,7 +25,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",
@@ -13536,9 +13536,9 @@
"dev": true
},
"node_modules/react-hook-form": {
- "version": "7.30.0",
- "resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.30.0.tgz",
- "integrity": "sha512-DzjiM6o2vtDGNMB9I4yCqW8J21P314SboNG1O0obROkbg7KVS0I7bMtwSdKyapnCPjHgnxc3L7E5PEdISeEUcQ==",
+ "version": "7.34.2",
+ "resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.34.2.tgz",
+ "integrity": "sha512-1lYWbEqr0GW7HHUjMScXMidGvV0BE2RJV3ap2BL7G0EJirkqpccTaawbsvBO8GZaB3JjCeFBEbnEWI1P8ZoLRQ==",
"engines": {
"node": ">=12.22.0"
},
@@ -26712,9 +26712,9 @@
"dev": true
},
"react-hook-form": {
- "version": "7.30.0",
- "resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.30.0.tgz",
- "integrity": "sha512-DzjiM6o2vtDGNMB9I4yCqW8J21P314SboNG1O0obROkbg7KVS0I7bMtwSdKyapnCPjHgnxc3L7E5PEdISeEUcQ==",
+ "version": "7.34.2",
+ "resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.34.2.tgz",
+ "integrity": "sha512-1lYWbEqr0GW7HHUjMScXMidGvV0BE2RJV3ap2BL7G0EJirkqpccTaawbsvBO8GZaB3JjCeFBEbnEWI1P8ZoLRQ==",
"requires": {}
},
"react-infinite-scroll-component": {
diff --git a/ui/package.json b/ui/package.json
index 25cc8cd8a..b32a48b1d 100644
--- a/ui/package.json
+++ b/ui/package.json
@@ -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",
diff --git a/ui/public/assets/data/configuration.json b/ui/public/assets/data/configuration.json
new file mode 100644
index 000000000..82e86dd4d
--- /dev/null
+++ b/ui/public/assets/data/configuration.json
@@ -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"
+ }
+ ]
+}
diff --git a/ui/src/app/admin/component/ConfigurationForm.js b/ui/src/app/admin/component/ConfigurationForm.js
index ff890a6a2..9db9756da 100644
--- a/ui/src/app/admin/component/ConfigurationForm.js
+++ b/ui/src/app/admin/component/ConfigurationForm.js
@@ -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) => (
-
- {index !== 0 && }
-
-
-
- {grouped[item].map((i) => {
- const item =
- ;
- index += 1;
- return item;
- })}
-
- ));
-
- return
;
- }, [config.properties]);
-
- const token = (option, { onRemove }, index) => (
-
- {`${option.propertyName}`}
-
- );
+ 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)];
@@ -77,17 +37,20 @@ 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 (<>
@@ -95,7 +58,7 @@ export function ConfigurationForm({ configuration = {}, errors = [], schema, onS
-
-
-
-
-
-
select(selected)}
- options={[...properties]}
- selected={selected}
- labelKey={option => `${option.propertyName}`}
- filterBy={['propertyName', 'category', 'displayType']}
- renderMenu={ menu }
- multiple={ true }
- renderToken={ token }
- >
- {({ isMenuShown, toggleMenu }) => (
- toggleMenu()}>
- Options
-
- )}
-
+
-
-
>)
-}
-/**/
\ No newline at end of file
+}
\ No newline at end of file
diff --git a/ui/src/app/admin/component/PropertySelector.js b/ui/src/app/admin/component/PropertySelector.js
new file mode 100644
index 000000000..44cdfd085
--- /dev/null
+++ b/ui/src/app/admin/component/PropertySelector.js
@@ -0,0 +1,92 @@
+import React, { Fragment, useCallback } from 'react';
+import { groupBy } from 'lodash';
+import { Highlighter, Menu, MenuItem, Token, Typeahead } from 'react-bootstrap-typeahead';
+import Button from 'react-bootstrap/Button';
+
+import { ToggleButton } from '../../form/component/ToggleButton';
+
+export function PropertySelector ({ properties, options, onAddProperties }) {
+
+ // React.useEffect(() => console.log(properties), [properties]);
+
+ 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) => (
+
+ {index !== 0 && }
+
+
+
+ {grouped[item].map((i) => {
+ const item =
+ ;
+ index += 1;
+ return item;
+ })}
+
+ ));
+
+ return
;
+ }, [properties]);
+
+ const token = (option, { onRemove }, index) => (
+
+ {`${option.propertyName}`}
+
+ );
+
+ const select = (data) => {
+ setSelected(data);
+ };
+
+ const [selected, setSelected] = React.useState([]);
+
+ const add = (s) => {
+ onAddProperties(s);
+ setSelected([]);
+ }
+
+ return (
+
+
+
+ select(selected)}
+ options={[...options]}
+ selected={selected}
+ labelKey={option => `${option.propertyName}`}
+ filterBy={['propertyName', 'category', 'displayType']}
+ renderMenu={ menu }
+ multiple={ true }
+ renderToken={ token }
+ >
+ {({ isMenuShown, toggleMenu }) => (
+ toggleMenu()}>
+ Options
+
+ )}
+
+
+
+
+ )
+}
+
+export default PropertySelector;
\ No newline at end of file
diff --git a/ui/src/app/admin/container/ConfigurationList.js b/ui/src/app/admin/container/ConfigurationList.js
index fcad47048..4acffc1c2 100644
--- a/ui/src/app/admin/container/ConfigurationList.js
+++ b/ui/src/app/admin/container/ConfigurationList.js
@@ -1,5 +1,5 @@
import React from 'react';
-import { faDownload, faEdit, faPlusCircle, faTrash } from '@fortawesome/free-solid-svg-icons';
+import { faDownload, faPlusCircle, faTrash } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import Button from 'react-bootstrap/Button';
@@ -46,13 +46,17 @@ export function ConfigurationList({ configurations, onDelete }) {
{(configurations?.length > 0) ? configurations.map((c, i) =>
- | {c.name} |
+
+
+ {c.name}
+
+ |
-
+
|