Skip to content

Commit 25c272a

Browse files
committed
refactor!: [PROD-14779] replace react-sortable-tree by MUI tree view
BREAKING CHANGES: - removed deprecated props showDeleteIcon and userId in ScenarioManagerTreeList (use prop canUserDeleteScenario instead) - removed deprecated prop buildSearchInfo in ScenarioManagerTreeList
1 parent 1a5ae17 commit 25c272a

File tree

4 files changed

+138
-204
lines changed

4 files changed

+138
-204
lines changed

rollup.config.mjs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,7 @@ export default {
2828
external: [
2929
'react',
3030
'react-dom',
31-
'react-dnd',
3231
'prop-types',
33-
'react-dnd-html5-backend',
34-
'@nosferatu500/react-dnd-scrollzone',
35-
'react-virtualized',
3632
'@mui/material',
3733
'@mui/icons-material',
3834
'@mui/styles',

src/charts/ScenarioManagerTreeList/ScenarioManagerTreeList.js

Lines changed: 29 additions & 116 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
// Copyright (c) Cosmo Tech.
22
// Licensed under the MIT license.
3-
import '@nosferatu500/react-sortable-tree/style.css';
4-
import React, { useEffect, useMemo, useState, useRef, useReducer } from 'react';
3+
import React, { useEffect, useMemo, useState } from 'react';
54
import PropTypes from 'prop-types';
65
import {
76
UnfoldMore as UnfoldMoreIcon,
@@ -13,16 +12,9 @@ import { ScenarioUtils } from '@cosmotech/core';
1312
import { SearchBar } from '../../inputs';
1413
import { FadingTooltip } from '../../misc';
1514
import { ScenarioSortableTree } from './components';
15+
import { DEFAULT_LABELS } from './labels';
1616
import useStyles from './style';
1717

18-
const initNodesDict = (scenarios, defaultExpanded) => {
19-
const nodesDict = {};
20-
scenarios.forEach((scenario) => {
21-
nodesDict[scenario.id] = defaultExpanded;
22-
});
23-
return nodesDict;
24-
};
25-
2618
const filterMatchesName = (scenario, searchStr) => scenario.name.toLowerCase().indexOf(searchStr.toLowerCase()) !== -1;
2719
const filterMatchesValidationStatus = (labels, scenario, searchStr) => {
2820
if (!scenario.validationStatus) return false;
@@ -41,47 +33,13 @@ const filterMatchesTag = (scenario, searchString) =>
4133
const filterMatchesOwner = (scenario, searchString) =>
4234
scenario.ownerName?.toLowerCase().includes(searchString.toLowerCase());
4335

44-
const DEFAULT_LABELS = {
45-
status: 'Run status:',
46-
runTemplateLabel: 'Run type:',
47-
successful: 'Successful',
48-
running: 'Running',
49-
dataingestioninprogress: 'Transferring results',
50-
failed: 'Failed',
51-
created: 'Created',
52-
delete: 'Delete this scenario',
53-
edit: 'Edit scenario name',
54-
scenarioRename: {
55-
title: 'Scenario name',
56-
errors: {
57-
emptyScenarioName: 'Scenario name cannot be empty',
58-
forbiddenCharsInScenarioName:
59-
'Scenario name has to start with a letter, and can only contain ' +
60-
'letters, digits, spaces, underscores, hyphens and dots.',
61-
},
62-
},
63-
deleteDialog: {
64-
description:
65-
'This operation is irreversible. Dataset(s) will not be removed, but the scenario parameters will be lost. ' +
66-
'If this scenario has children, they will be moved to a new parent. ' +
67-
'The new parent will be the parent of the deleted scenario.',
68-
cancel: 'Cancel',
69-
confirm: 'Confirm',
70-
},
71-
dataset: 'Dataset:',
72-
noDataset: 'None',
73-
datasetNotFound: 'Not Found',
74-
searchField: 'Filter',
75-
toolbar: {
76-
expandAll: 'Expand all',
77-
expandTree: 'Expand tree',
78-
collapseAll: 'Collapse all',
79-
},
80-
validationStatus: {
81-
rejected: 'Rejected',
82-
validated: 'Validated',
83-
},
84-
};
36+
const doesScenarioMatchFilter = (labels, scenario, searchStr) =>
37+
filterMatchesName(scenario, searchStr) ||
38+
filterMatchesValidationStatus(labels, scenario, searchStr) ||
39+
filterMatchesRunStatus(labels, scenario, searchStr) ||
40+
filterMatchesDescription(scenario, searchStr) ||
41+
filterMatchesTag(scenario, searchStr) ||
42+
filterMatchesOwner(scenario, searchStr);
8543

8644
export const ScenarioManagerTreeList = (props) => {
8745
const classes = useStyles();
@@ -92,42 +50,24 @@ export const ScenarioManagerTreeList = (props) => {
9250
deleteScenario,
9351
onScenarioRename,
9452
checkScenarioNameValue = () => null,
95-
userId,
96-
buildSearchInfo,
9753
buildDatasetInfo,
9854
labels: tmpLabels,
9955
buildScenarioNameToDelete,
100-
showDeleteIcon,
10156
canUserDeleteScenario,
10257
canUserRenameScenario = () => true,
10358
canUpdateScenario,
10459
onScenarioUpdate = () => null,
10560
} = props;
10661

10762
const labels = useMemo(() => ({ ...DEFAULT_LABELS, ...tmpLabels }), [tmpLabels]);
108-
109-
if (buildSearchInfo) {
110-
console.warn(
111-
'"buildSearchInfo" prop is deprecated in ScenarioManagerTreeList. Please consider removing this prop.'
112-
);
113-
}
114-
if (showDeleteIcon != null) {
115-
console.warn(
116-
'"showDeleteIcon" prop is deprecated in ScenarioManagerTreeList. Please use "canUserDeleteScenario" instead.'
117-
);
118-
}
63+
const allScenarioIds = useMemo(() => scenarios.map((scenario) => scenario.id), [scenarios]);
11964

12065
const [searchText, setSearchText] = useState('');
121-
const nodesExpandedChildren = useRef(initNodesDict(scenarios, true));
122-
const nodesExpandedDetails = useRef(initNodesDict(scenarios, false));
66+
const [treeExpandedNodes, setTreeExpandedNodes] = useState(allScenarioIds);
67+
const [detailExpandedNodes, setDetailExpandedNodes] = useState([]);
12368

12469
const formatScenariosToScenariosTree = (scenariosToFormat) => {
125-
const scenarioTree = scenariosToFormat.map((scenario) => {
126-
const displayDeleteIcon =
127-
canUserDeleteScenario != null
128-
? canUserDeleteScenario(scenario)
129-
: showDeleteIcon !== false && scenario.ownerId === userId;
130-
70+
const scenarioList = scenariosToFormat.map((scenario) => {
13171
labels.dataset = buildDatasetInfo(scenario.datasetList);
13272

13373
return {
@@ -137,7 +77,7 @@ export const ScenarioManagerTreeList = (props) => {
13777
scenarioNodeProps: {
13878
datasets,
13979
scenario,
140-
showDeleteIcon: displayDeleteIcon,
80+
showDeleteIcon: canUserDeleteScenario(scenario),
14181
onScenarioRedirect,
14282
deleteScenario,
14383
checkScenarioNameValue,
@@ -150,7 +90,7 @@ export const ScenarioManagerTreeList = (props) => {
15090
},
15191
};
15292
});
153-
return ScenarioUtils.getScenarioTree(scenarioTree, (scenA, scenB) => scenA.name.localeCompare(scenB.name));
93+
return ScenarioUtils.getScenarioTree(scenarioList, (scenA, scenB) => scenA.name.localeCompare(scenB.name));
15494
};
15595

15696
const scenarioTreeFull = useMemo(
@@ -167,22 +107,17 @@ export const ScenarioManagerTreeList = (props) => {
167107
// eslint-disable-next-line react-hooks/exhaustive-deps
168108
}, [scenarios, searchText, labels]);
169109

170-
const [refreshTick, forceRefresh] = useReducer((x) => x + 1, 0);
171-
172110
const collapseAll = () => {
173-
nodesExpandedChildren.current = initNodesDict(scenarios, false);
174-
nodesExpandedDetails.current = initNodesDict(scenarios, false);
175-
forceRefresh();
111+
setTreeExpandedNodes([]);
112+
setDetailExpandedNodes([]);
176113
};
177114
const expandTree = () => {
178-
nodesExpandedChildren.current = initNodesDict(scenarios, true);
179-
nodesExpandedDetails.current = initNodesDict(scenarios, false);
180-
forceRefresh();
115+
setTreeExpandedNodes(allScenarioIds);
116+
setDetailExpandedNodes([]);
181117
};
182118
const expandAll = () => {
183-
nodesExpandedChildren.current = initNodesDict(scenarios, true);
184-
nodesExpandedDetails.current = initNodesDict(scenarios, true);
185-
forceRefresh();
119+
setTreeExpandedNodes(allScenarioIds);
120+
setDetailExpandedNodes(allScenarioIds);
186121
};
187122

188123
const filterScenarios = (searchStr) => {
@@ -192,15 +127,7 @@ export const ScenarioManagerTreeList = (props) => {
192127
return;
193128
}
194129
// Otherwise, filter scenarios based on their name
195-
const filtered = scenarios.filter(
196-
(scenario) =>
197-
filterMatchesName(scenario, searchStr) ||
198-
filterMatchesValidationStatus(labels, scenario, searchStr) ||
199-
filterMatchesRunStatus(labels, scenario, searchStr) ||
200-
filterMatchesDescription(scenario, searchStr) ||
201-
filterMatchesTag(scenario, searchStr) ||
202-
filterMatchesOwner(scenario, searchStr)
203-
);
130+
const filtered = scenarios.filter((scenario) => doesScenarioMatchFilter(labels, scenario, searchStr));
204131
// Format list and set as tree data
205132
setScenariosTree(formatScenariosToScenariosTree(filtered));
206133
};
@@ -233,15 +160,16 @@ export const ScenarioManagerTreeList = (props) => {
233160
</div>
234161
</div>
235162
<div data-cy="scenario-manager-view" className={classes.treesContainer}>
236-
{scenariosTree.map((scenarioTree) => {
163+
{scenariosTree.map((rootScenario) => {
237164
return (
238165
<ScenarioSortableTree
239-
key={scenarioTree.id}
166+
key={rootScenario.id}
240167
classes={classes}
241-
nodesExpandedChildrenRef={nodesExpandedChildren}
242-
nodesExpandedDetailsRef={nodesExpandedDetails}
243-
scenarioTree={scenarioTree}
244-
refreshTick={refreshTick}
168+
treeExpandedNodes={treeExpandedNodes}
169+
setTreeExpandedNodes={setTreeExpandedNodes}
170+
detailExpandedNodes={detailExpandedNodes}
171+
setDetailExpandedNodes={setDetailExpandedNodes}
172+
scenarioTree={rootScenario}
245173
/>
246174
);
247175
})}
@@ -279,25 +207,10 @@ ScenarioManagerTreeList.propTypes = {
279207
* Function bound to handle a scenario movement (moving a scenario = changing its parent)
280208
*/
281209
moveScenario: PropTypes.func.isRequired,
282-
/**
283-
* Current user id
284-
*/
285-
userId: PropTypes.string.isRequired,
286-
/**
287-
* DEPRECATED: Function building scenario search label
288-
*/
289-
buildSearchInfo: PropTypes.func,
290210
/**
291211
* Function building scenario dataset label
292212
*/
293213
buildDatasetInfo: PropTypes.func.isRequired,
294-
/**
295-
* DEPRECATED: this prop is deprecated, use 'canUserDeleteScenario' instead
296-
* Boolean value to define whether scenario delete buttons must be shown in ScenarioNode elements:
297-
* - false: delete buttons are always hidden
298-
* - true: delete buttons are shown if the user id matches the scenario owner id
299-
*/
300-
showDeleteIcon: PropTypes.bool,
301214
/**
302215
* Function returning whether the current user can delete a given scenario. This function receives as parameter
303216
* the scenario data and must return a boolean.

0 commit comments

Comments
 (0)