diff --git a/src/modules/RA/Scene/assets/List.svg b/src/modules/RA/Scene/assets/List.svg
new file mode 100644
index 000000000..7b0fe2133
--- /dev/null
+++ b/src/modules/RA/Scene/assets/List.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/modules/RA/Scene/components/GeolayerSelect.js b/src/modules/RA/Scene/components/GeolayerSelect.js
index ff09e71f1..2cd9f912d 100644
--- a/src/modules/RA/Scene/components/GeolayerSelect.js
+++ b/src/modules/RA/Scene/components/GeolayerSelect.js
@@ -5,6 +5,7 @@ import { LinearProgress, withDataProvider, GET_LIST } from 'react-admin';
import debounce from 'lodash.debounce';
import uniqBy from 'lodash.uniqby';
+import Box from '@material-ui/core/Box';
import FormControl from '@material-ui/core/FormControl';
import InputLabel from '@material-ui/core/InputLabel';
import MenuItem from '@material-ui/core/MenuItem';
@@ -120,7 +121,11 @@ const GeolayerSelect = ({ dataProvider, onChange, excludeIds = [], includeIds =
* Display progress bar until we have geolayers
*/
if (!geolayers) {
- return ;
+ return (
+
+
+
+ );
}
if (!geolayers.length) {
diff --git a/src/modules/RA/Scene/components/TreeInput.js b/src/modules/RA/Scene/components/TreeInput.js
index ed1c98fb1..e08e800a0 100644
--- a/src/modules/RA/Scene/components/TreeInput.js
+++ b/src/modules/RA/Scene/components/TreeInput.js
@@ -35,6 +35,7 @@ const generateNodeProps = (treeData, setTreeData, includeIds) =>
className: classnames({
treeGroup: node.group,
treeGroupExclusive: node.exclusive,
+ treeGroupByVariable: node.byVariable,
}),
buttons: [],
};
@@ -91,7 +92,7 @@ const TreeInput = ({ input: { value, onChange }, ...props }) => {
*/
const addGroup = () => onChange([
...value,
- { label: 'New group name', group: true },
+ { label: 'New group name', group: true, children: [], expanded: true },
]);
if (!value) {
diff --git a/src/modules/RA/Scene/components/TreeInput.scss b/src/modules/RA/Scene/components/TreeInput.scss
index 81952e100..c664e18cc 100644
--- a/src/modules/RA/Scene/components/TreeInput.scss
+++ b/src/modules/RA/Scene/components/TreeInput.scss
@@ -31,4 +31,10 @@
background-image: url(../assets/RadioButton.svg);
}
}
+
+ &ByVariable {
+ .rst__moveHandle {
+ background-image: url(../assets/List.svg);
+ }
+ }
}
diff --git a/src/modules/RA/Scene/components/TreeNodeLabelInput.js b/src/modules/RA/Scene/components/TreeNodeLabelInput.js
index 6b1cb5e0a..6ecadd7b2 100644
--- a/src/modules/RA/Scene/components/TreeNodeLabelInput.js
+++ b/src/modules/RA/Scene/components/TreeNodeLabelInput.js
@@ -1,6 +1,7 @@
import React from 'react';
-import { changeNodeAtPath } from 'react-sortable-tree';
+import { changeNodeAtPath, getNodeAtPath } from 'react-sortable-tree';
+import Box from '@material-ui/core/Box';
import TextField from '@material-ui/core/TextField';
@@ -16,9 +17,31 @@ const NodeLabel = ({ treeData, setTreeData, path, node }) => {
newNode: { ...node, label },
}));
+
+ const parentVariables = React.useMemo(
+ () => getNodeAtPath({
+ treeData,
+ path: path.slice(0, -1),
+ getNodeKey: ({ treeIndex }) => treeIndex,
+ })?.node?.variables,
+ [path, treeData],
+ );
+
/* Only groups have editable labels */
if (!node.group) {
- return node.label;
+ return (
+ <>
+ {node.label}
+
+ {Boolean(parentVariables?.length) && (
+
+ {parentVariables.map(({ id, label }) =>
+ // eslint-disable-next-line no-irregular-whitespace
+ `${label} : ${node.variables?.[id]}`).join(', ')}
+
+ )}
+ >
+ );
}
return ;
diff --git a/src/modules/RA/Scene/components/TreeNodeToolbar.js b/src/modules/RA/Scene/components/TreeNodeToolbar.js
index ff8ada1c2..7a4b94b53 100644
--- a/src/modules/RA/Scene/components/TreeNodeToolbar.js
+++ b/src/modules/RA/Scene/components/TreeNodeToolbar.js
@@ -4,11 +4,17 @@ import {
addNodeUnderParent,
removeNodeAtPath,
changeNodeAtPath,
+ getNodeAtPath,
getFlatDataFromTree,
} from 'react-sortable-tree';
+import { v4 as uuid } from 'uuid';
+
+import Box from '@material-ui/core/Box';
import Button from '@material-ui/core/Button';
+import Chip from '@material-ui/core/Chip';
import AddIcon from '@material-ui/icons/Add';
+import EditIcon from '@material-ui/icons/Edit';
import DeleteIcon from '@material-ui/icons/Delete';
import IconButton from '@material-ui/core/IconButton';
import FormLabel from '@material-ui/core/FormLabel';
@@ -16,7 +22,10 @@ import FormControl from '@material-ui/core/FormControl';
import Menu from '@material-ui/core/Menu';
import MenuItem from '@material-ui/core/MenuItem';
import Modal from '@material-ui/core/Modal';
-import Switch from '@material-ui/core/Switch';
+import FormControlLabel from '@material-ui/core/FormControlLabel';
+import Radio from '@material-ui/core/Radio';
+import RadioGroup from '@material-ui/core/RadioGroup';
+import TextField from '@material-ui/core/TextField';
import MoreVertIcon from '@material-ui/icons/MoreVert';
import GeolayerSelect from './GeolayerSelect';
@@ -54,6 +63,18 @@ const TreeNodeToolbar = ({ treeData, setTreeData, path, node, includeIds }) => {
const [newLayerProps, setNewLayerProps] = React.useState({});
const [groupNewSettings, setGroupNewSettings] = React.useState({});
+ React.useEffect(
+ () => {
+ if (displaySettingsModal.node) {
+ setGroupNewSettings({
+ exclusive: Boolean(displaySettingsModal.node.exclusive),
+ byVariable: Boolean(displaySettingsModal.node.byVariable),
+ variables: displaySettingsModal.node.variables || [],
+ });
+ }
+ },
+ [displaySettingsModal],
+ );
const handleClick = ({ currentTarget }) => setAnchorEl(currentTarget);
const closeMenu = () => setAnchorEl(null);
@@ -91,6 +112,19 @@ const TreeNodeToolbar = ({ treeData, setTreeData, path, node, includeIds }) => {
*/
const editItem = newProps => {
closeMenu();
+
+ // Remove dropped variables from children
+ const removedVariables = node.variables?.filter(
+ variable => !newProps.variables.includes(variable),
+ );
+
+ const newChildren = JSON.parse(JSON.stringify(node.children));
+ newChildren?.forEach(child => {
+ removedVariables?.forEach(removedVariable => {
+ delete child[removedVariable.id]; // eslint-disable-line no-param-reassign
+ });
+ });
+
setTreeData(changeNodeAtPath({
treeData,
path,
@@ -98,6 +132,7 @@ const TreeNodeToolbar = ({ treeData, setTreeData, path, node, includeIds }) => {
newNode: {
...node,
...newProps,
+ children: newChildren,
},
}));
};
@@ -110,14 +145,26 @@ const TreeNodeToolbar = ({ treeData, setTreeData, path, node, includeIds }) => {
setDisplayLayerModal(true);
};
+ const openEditLayerModal = editNode => {
+ closeMenu();
+ setNewLayerProps(editNode);
+ setDisplayLayerModal(editNode);
+ };
+
/**
* Close modal for new layer node creation
*/
- const closeNewLayerModal = (doCreate = false) => () => {
- if (doCreate && newLayerProps.geolayer) {
+ const closeLayerModal = (save = false, edit = false) => () => {
+ if (save && !edit && newLayerProps.geolayer) {
newSubItem(newLayerProps)();
+ } else if (save && edit) {
+ setTreeData(changeNodeAtPath({
+ treeData,
+ path,
+ getNodeKey: ({ treeIndex }) => treeIndex,
+ newNode: { ...node, ...newLayerProps },
+ }));
}
-
/* Close modal */
setDisplayLayerModal(false);
@@ -130,7 +177,11 @@ const TreeNodeToolbar = ({ treeData, setTreeData, path, node, includeIds }) => {
*/
const openSettingsModal = () => {
closeMenu();
- setDisplaySettingsModal(true);
+ setDisplaySettingsModal(getNodeAtPath({
+ treeData,
+ path,
+ getNodeKey: ({ treeIndex }) => treeIndex,
+ }));
};
/**
@@ -148,9 +199,14 @@ const TreeNodeToolbar = ({ treeData, setTreeData, path, node, includeIds }) => {
setDisplaySettingsModal(false);
};
- const isGroupExclusive = typeof groupNewSettings.exclusive !== 'undefined'
- ? groupNewSettings.exclusive
- : node.exclusive;
+ const getRadioValue = React.useCallback(
+ () => {
+ if (groupNewSettings.byVariable) { return 'byVariable'; }
+ return groupNewSettings.exclusive ? 'exclusive' : 'inclusive';
+ },
+ [groupNewSettings.byVariable, groupNewSettings.exclusive],
+ );
+ const radioValue = getRadioValue();
/**
* Array of all nodes in treeData
@@ -169,56 +225,197 @@ const TreeNodeToolbar = ({ treeData, setTreeData, path, node, includeIds }) => {
new Set(),
)).filter(Boolean);
+ const parentNode = getNodeAtPath({
+ treeData,
+ path: path.slice(0, -1),
+ getNodeKey: ({ treeIndex }) => treeIndex,
+ })?.node;
+ const variables =
+ node.variables?.length
+ ? node.variables
+ : (parentNode?.variables || []);
+
+ const newVariableFieldRef = React.useRef();
+ const handleVariableAdd = React.useCallback(
+ () => {
+ const label = newVariableFieldRef?.current?.value?.trim();
+ if (!label) {
+ return;
+ }
+
+ setGroupNewSettings(({ variables: vars = [], ...prevSettings }) => ({
+ ...prevSettings,
+ variables: [
+ ...vars,
+ { id: uuid(), label },
+ ],
+ }));
+ newVariableFieldRef.current.value = '';
+ },
+ [],
+ );
+
return (
<>
{isGroup && }
{isGroup && }
- {!isGroup && }
+ {!isGroup && (
+ openEditLayerModal(node)}>
+
+
+ )}
+ {!isGroup && }
-
+
-
-
+
+
+ )}
+
+ {Boolean(displayLayerModal.geolayer) && (
+
{
+ const label = event?.target?.value;
+ setNewLayerProps(prevProps => ({ ...prevProps, label }));
+ }}
/>
-
+ )}
+
+ {(node.byVariable || Boolean(displayLayerModal.geolayer)) && (
+
+ {variables?.map(({ id, label }) => (
+ {
+ const fieldValue = event?.target?.value;
+ setNewLayerProps(
+ prevProps => ({
+ ...prevProps,
+ variables: { ...prevProps.variables, [id]: fieldValue },
+ }),
+ );
+ }}
+ />
+ ))}
+
+ )}
-
-
+
+
-
+
-
- Mode de sélection des couches
-
- Inclusif
-
- setGroupNewSettings({ ...groupNewSettings, exclusive })}
- />
- Exclusif
-
+
+ Mode de sélection des couches
+ {
+ switch (choice) {
+ case 'inclusive':
+ setGroupNewSettings(
+ { ...groupNewSettings, exclusive: false, byVariable: false },
+ );
+ break;
+ case 'exclusive':
+ setGroupNewSettings(
+ { ...groupNewSettings, exclusive: true, byVariable: false },
+ );
+ break;
+ case 'byVariable':
+ setGroupNewSettings(
+ { ...groupNewSettings, exclusive: true, byVariable: true },
+ );
+ break;
+ default:
+ }
+ }}
+ >
+ } label="Inclusif" />
+ } label="Exclusif" />
+ } label="Par variables" />
+
+
+
+
+ Ajouter
+
+ ),
+ }}
+ />
+
+
+
+ {groupNewSettings.variables?.map(({ id, label }) => (
+ {
+ setGroupNewSettings(({ variables: prevVariables = [], ...prevsettings }) => ({
+ ...prevsettings,
+ variables: prevVariables.filter(({ id: cId }) => cId !== id),
+ }));
+ }}
+ />
+ ))}
+
+
+
-
+