Skip to content

Commit c6cb9f8

Browse files
Merge pull request #500 from MetaCell/feature/483
Feature/483
2 parents 5fdc39e + a5d3e44 commit c6cb9f8

File tree

4 files changed

+250
-30
lines changed

4 files changed

+250
-30
lines changed

webapp/components/general/ControlPanelTreeItem.js

Lines changed: 123 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -7,32 +7,108 @@ import IconButton from '@material-ui/core/IconButton';
77
import TreeItem from '@material-ui/lab/TreeItem';
88
import Visibility from '@material-ui/icons/Visibility';
99
import VisibilityOff from '@material-ui/icons/VisibilityOff';
10-
import ColorLens from '@material-ui/icons/ColorLens';
11-
import Shuffle from '@material-ui/icons/Shuffle';
1210
import { ChromePicker } from 'react-color';
1311
import { useDispatch, useSelector } from 'react-redux';
14-
import { experimentLabelColor } from '../../theme';
15-
import { changeInstanceColor, selectInstances } from '../../redux/actions/general';
12+
import {
13+
experimentLabelColor,
14+
bgDarker,
15+
bgLight,
16+
radius,
17+
} from '../../theme';
18+
import {
19+
RandomColorLensIcon,
20+
ColorLensIcon,
21+
TriangleIcon,
22+
} from './NetPyNEIcons';
23+
import { changeInstanceColor } from '../../redux/actions/general';
1624

1725
const useStyles = makeStyles((theme) => ({
18-
networkItem: {
19-
paddingTop: '2px',
20-
paddingBottom: '2px',
26+
treeItem: {
27+
'& .MuiTreeItem-iconContainer': {
28+
marginRight: '5px',
29+
},
30+
'& .MuiTreeItem-label': {
31+
paddingTop: '2px',
32+
paddingBottom: '2px',
33+
paddingRight: '8px',
34+
borderRadius: radius,
35+
'&:hover': {
36+
backgroundColor: '#333333',
37+
},
38+
},
39+
},
40+
leafTreeItem: {
41+
'& .MuiTreeItem-iconContainer': {
42+
width: 0,
43+
},
2144
},
2245
controls: {
2346
'& .MuiIconButton-root': {
24-
padding: 0,
47+
padding: '0 !important',
2548
marginLeft: '0.5rem',
2649
color: experimentLabelColor,
2750
'&:hover': {
2851
color: 'white',
2952
},
3053
},
3154
},
55+
colorPickerBox: {
56+
position: 'absolute',
57+
top: '1.6rem',
58+
right: '2.7rem',
59+
height: '3rem',
60+
},
61+
triangleIcon: {
62+
marginBottom: '-7px',
63+
color: bgDarker,
64+
},
3265
colorPicker: {
3366
position: 'absolute',
3467
zIndex: 1000,
3568
right: 0,
69+
backgroundColor: `${bgDarker} !important`,
70+
padding: '0.2rem',
71+
'& label': {
72+
color: '#ffffff !important',
73+
fontFamily: 'Roboto, arial',
74+
fontSize: '11px',
75+
fontWeight: 400,
76+
},
77+
'& input': {
78+
backgroundColor: `${bgLight} !important`,
79+
color: '#ffffff !important',
80+
boxShadow: 'none !important',
81+
fontFamily: 'Roboto, arial',
82+
fontSize: '11px',
83+
fontWeight: 400,
84+
},
85+
'& svg': {
86+
fill: '#ffffff !important',
87+
},
88+
'& svg:hover': {
89+
background: 'transparent !important',
90+
},
91+
'& .hue-horizontal': {
92+
borderRadius: '10px',
93+
},
94+
'& :nth-child(2)': {
95+
'& :nth-child(1)': {
96+
'& :nth-child(2)': {
97+
'& :nth-child(2)': {
98+
'& :nth-child(1)': {
99+
'& :nth-child(2)': {
100+
borderRadius: '10px',
101+
},
102+
},
103+
},
104+
},
105+
},
106+
},
107+
},
108+
activeColorPicker: {
109+
'& path': {
110+
fill: '#ffffff',
111+
},
36112
},
37113
}));
38114

@@ -60,6 +136,8 @@ const ControlPanelTreeItem = (props) => {
60136
});
61137
dispatch(changeInstanceColor(newInstances));
62138
setColor(_color.rgb);
139+
event.stopPropagation();
140+
event.preventDefault();
63141
};
64142

65143
const getRandomColor = () => ({
@@ -70,6 +148,8 @@ const ControlPanelTreeItem = (props) => {
70148
});
71149

72150
const generateRandomColor = (event, nodeId) => {
151+
event.stopPropagation();
152+
event.preventDefault();
73153
const children = window.Instances.getInstance(nodeId).getChildren().map((instance) => instance.getInstancePath());
74154
// const newInstances = instances.filter((instance) => !(instance.instancePath.startsWith(nodeId)));
75155
const newInstances = instances.filter((instance) => {
@@ -98,6 +178,8 @@ const ControlPanelTreeItem = (props) => {
98178
};
99179

100180
const changeVisibility = (event, nodeId) => {
181+
event.stopPropagation();
182+
event.preventDefault();
101183
const copiedInstances = instances.slice();
102184
let oldIndex = null;
103185
let oldInstance = copiedInstances.find((pInstance, index) => {
@@ -145,51 +227,71 @@ const ControlPanelTreeItem = (props) => {
145227

146228
return (
147229
<TreeItem
230+
className={`${classes.treeItem} ${children?.length === 0 ? classes.leafTreeItem : ''}`}
148231
nodeId={nodeId}
149-
onLabelClick={(e) => { e.stopPropagation(); e.preventDefault(); }}
150232
label={(
151233
<Grid
152234
container
153-
className={classes.networkItem}
154-
onMouseEnter={() => setIsHoveredOver(true)}
155-
onMouseLeave={() => setIsHoveredOver(false)}
235+
onMouseEnter={() => setTimeout(setIsHoveredOver(true), 10000)}
236+
onMouseLeave={() => setTimeout(setIsHoveredOver(false), 10000)}
156237
display="flex"
157238
flexDirection="row"
158239
justifyContent="space-between"
159240
>
160-
<Grid item xs={4}><Typography onClick={() => onNodeSelect(nodeId)}>{label}</Typography></Grid>
241+
242+
<Grid item xs={4}>
243+
<Typography onClick={(event) => {
244+
onNodeSelect(nodeId);
245+
event.stopPropagation();
246+
event.preventDefault();
247+
}}
248+
>
249+
{label}
250+
</Typography>
251+
</Grid>
161252
<Grid item xs={4} justifyContent="center"><Typography>{type}</Typography></Grid>
162253
<Grid item xs={4} justifyContent="flex-end" className={classes.controls}>
163254
{isHoveredOver
164255
? (
165256
<>
166-
167257
<IconButton onClick={(event) => changeVisibility(event, nodeId)}>
168-
{ visibility ? <Visibility /> : <VisibilityOff /> }
258+
{ visibility ? <Visibility style={{ marginRight: '0.5rem' }} /> : <VisibilityOff style={{ marginRight: '0.5rem' }} /> }
259+
</IconButton>
260+
<IconButton onClick={(event) => {
261+
event.stopPropagation();
262+
event.preventDefault();
263+
setShowColorPicker(true);
264+
}}
265+
>
266+
<ColorLensIcon className={showColorPicker ? classes.activeColorPicker : ''} />
267+
</IconButton>
268+
<IconButton disabled={disableRandom} onClick={(event) => generateRandomColor(event, nodeId)}>
269+
<RandomColorLensIcon />
169270
</IconButton>
170-
<IconButton disabled={disableRandom} onClick={(event) => generateRandomColor(event, nodeId)}><Shuffle /></IconButton>
171-
<IconButton onClick={() => setShowColorPicker(true)}><ColorLens /></IconButton>
172271
{
173272
showColorPicker
174273
? (
175274
<Box
176-
onMouseLeave={() => setShowColorPicker(false)}
275+
className={classes.colorPickerBox}
276+
onMouseLeave={() => setTimeout(setShowColorPicker(false), 30000)}
177277
>
278+
{/* <TriangleIcon className={classes.triangleIcon} /> */}
178279
<ChromePicker
179280
className={classes.colorPicker}
180281
color={color}
181-
onChangeComplete={(color, event) => handleColorSelection(color, event, nodeId)}
282+
onChangeComplete={(color, event) => {
283+
handleColorSelection(color, event, nodeId);
284+
}}
182285
/>
183286
</Box>
184287
) : null
185288
}
186-
187289
</>
188290
)
189291
: null}
190292
</Grid>
191293
</Grid>
192-
)}
294+
)}
193295
>
194296
{children}
195297
</TreeItem>

webapp/components/general/ExperimentControlPanel.js

Lines changed: 62 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,70 @@ import Box from '@material-ui/core/Box';
66
import Typography from '@material-ui/core/Typography';
77
import TextField from '@material-ui/core/TextField';
88
import TreeView from '@material-ui/lab/TreeView';
9-
import ExpandMoreIcon from '@material-ui/icons/ExpandMore';
10-
import ChevronRightIcon from '@material-ui/icons/ChevronRight';
119
import ControlPanelTreeItem from './ControlPanelTreeItem';
1210
import { experimentLabelColor } from '../../theme';
11+
import { MODEL_STATE } from '../../constants';
1312
import { selectInstances } from '../../redux/actions/general';
13+
import { TreeItemArrowRightIcon, TreeItemArrowDownIcon } from './NetPyNEIcons';
1414

1515
const useStyles = makeStyles(() => ({
16+
root: {
17+
'& ul': {
18+
position: 'relative',
19+
'&::before': {
20+
content: '""',
21+
height: 'calc(100% - 1.1rem)',
22+
width: '0.0625rem',
23+
position: 'absolute',
24+
left: '-0.65rem',
25+
borderRadius: '3.125rem',
26+
top: '0rem',
27+
backgroundImage: 'url("data:image/svg+xml,%3Csvg width=\'1\' height=\'8\' viewBox=\'0 0 1 8\' fill=\'none\' xmlns=\'http://www.w3.org/2000/svg\'%3E%3Cpath d=\'M0 0H1V8H0V0Z\' fill=\'%23989898\'/%3E%3C/svg%3E")',
28+
backgroundRepeat: 'repeat',
29+
},
30+
'& .MuiTreeItem-root': {
31+
position: 'relative',
32+
'&::before': {
33+
content: '""',
34+
height: '0.875rem',
35+
width: '1.4375rem',
36+
backgroundImage: 'url("data:image/svg+xml,%3Csvg width=\'12\' height=\'6\' viewBox=\'0 0 12 6\' fill=\'none\' xmlns=\'http://www.w3.org/2000/svg\'%3E%3Cpath d=\'M6 6C2.68629 6 0 3.31371 0 0H1C1 2.80391 3.19609 5 6 5V6Z\' fill=\'%23989898\'/%3E%3Cpath d=\'M6 5H11.5C11.7761 5 12 5.22386 12 5.5C12 5.77614 11.7761 6 11.5 6H6V5Z\' fill=\'%23989898\'/%3E%3C/svg%3E")',
37+
position: 'absolute',
38+
top: '0.5rem',
39+
backgroundRepeat: 'no-repeat',
40+
left: '-0.65rem',
41+
},
42+
'&::after': {
43+
content: '""',
44+
height: '0.0625rem',
45+
borderRadius: '3.125rem',
46+
width: '0.5rem',
47+
backgroundColor: '#ffffff',
48+
position: 'absolute',
49+
left: '0',
50+
top: '1.0625rem',
51+
display: 'none',
52+
},
53+
'&:hover': {
54+
background: 'transparent',
55+
},
56+
'&:focus > .MuiTreeItem-content': {
57+
backgroundColor: 'transparent',
58+
},
59+
},
60+
},
61+
},
1662
header: {
1763
'& .MuiTypography-root': {
1864
color: experimentLabelColor,
1965
fontWeight: 'bold',
2066
},
2167
},
68+
svgContainer: {
69+
fontSize: '12px',
70+
width: '10px',
71+
height: '10px',
72+
},
2273
}));
2374

2475
const ExperimentControlPanel = (props) => {
@@ -66,7 +117,9 @@ const ExperimentControlPanel = (props) => {
66117

67118
const flatList = [];
68119
instancesMap.forEach((value, key) => {
69-
flatList.push(value);
120+
if (value.key.includes(filter)) {
121+
flatList.push(value);
122+
}
70123
});
71124
return flatList;
72125
};
@@ -95,22 +148,23 @@ const ExperimentControlPanel = (props) => {
95148
return (
96149
<>
97150
{
98-
window.Instances // temporary change to -> props.modelState === MODEL_STATE.INSTANTIATED
151+
props.modelState === MODEL_STATE.INSTANTIATED || props.modelState === MODEL_STATE.SIMULATED
99152
? (
100153
window.Instances
101154
? (
102155
<Box display="flex" flexDirection="column" p={1}>
103156
<TextField label="Filter results" variant="outlined" fullWidth onChange={(e) => setFilter(e.target.value)} />
104157
<Box className={classes.header} display="flex" justifyContent="space-between" mt={1}>
105158
<Typography>Name</Typography>
106-
<Typography>Type(s)</Typography>
107-
<Typography />
159+
<Typography style={{ marginLeft: '3rem' }}>Type(s)</Typography>
160+
<Typography>Controls</Typography>
108161
</Box>
109162
<TreeView
163+
className={classes.root}
110164
aria-label="Network data navigator"
111165
defaultExpanded={['network']}
112-
defaultCollapseIcon={<ExpandMoreIcon />}
113-
defaultExpandIcon={<ChevronRightIcon />}
166+
defaultCollapseIcon={<TreeItemArrowDownIcon className={classes.svgContainer} />}
167+
defaultExpandIcon={<TreeItemArrowRightIcon className={classes.svgContainer} />}
114168
>
115169
{filter === ''
116170
? getTreeItemsFromData([window.Instances.getInstance('network')])

0 commit comments

Comments
 (0)