Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion webapp/components/general/FileBrowser.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import React from 'react';
import Tree from '@metacell/geppetto-meta-ui/tree-viewer/Tree';
import Button from '@material-ui/core/Button';
import { changeNodeAtPath, walk } from 'react-sortable-tree';
import Dialog from '@material-ui/core/Dialog';
Expand All @@ -10,6 +9,7 @@ import DialogContent from '@material-ui/core/DialogContent';
import { Tooltip } from 'netpyne/components';
import IconButton from '@material-ui/core/IconButton';
import Icon from '@material-ui/core/Icon';
import Tree from './tree/Tree';

import Utils from '../../Utils';
import { bgLight, fontColor } from '../../theme';
Expand Down
196 changes: 196 additions & 0 deletions webapp/components/general/tree/Tree.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
import React from 'react';

var SortableTree = require('react-sortable-tree').default;
var toggleExpandedForAll = require('react-sortable-tree').toggleExpandedForAll;
var changeNodeAtPath = require('react-sortable-tree').changeNodeAtPath;
var walk = require('react-sortable-tree').walk;
require('./Tree.less');

export default class Tree extends React.Component {
constructor (props) {
super(props);

this.updateTreeData = this.updateTreeData.bind(this);
this.expandAll = this.expandAll.bind(this);
this.collapseAll = this.collapseAll.bind(this);
this.state = { treeData: this.props.treeData };
}

updateTreeData(treeData) {
this.setState({ treeData });
}

expand(expanded) {
this.setState({
treeData: toggleExpandedForAll({
treeData: this.state.treeData,
expanded,
}),
});
}

expandAll() {
this.expand(true);
}

collapseAll() {
this.expand(false);
}

handleClick(event, rowInfo) {
var toggleMode = this.props.toggleMode;
var currentTreeData = this.state.treeData;
// If node has children, we expand/collapse the node
if (
rowInfo.node.children != undefined &&
rowInfo.node.children.length > 0
) {
// If parents can be activate, iterate over the whole tree
if (this.props.activateParentsNodeOnClick) {
walk({
treeData: currentTreeData,
getNodeKey: ({ treeIndex }) => treeIndex,
ignoreCollapsed: true,
callback: (rowInfoIter) => {
var isActive = rowInfoIter.treeIndex == rowInfo.treeIndex;
/*
* If toggleMode just toggle to activate/inactivate selected node and expand/collapse
* If non toggle mode inactive all nodes but selected and expand/collapse
*/
if (isActive && toggleMode) {
rowInfoIter.node.active = !rowInfoIter.node.active;
rowInfoIter.node.expanded = !rowInfoIter.node.expanded;
currentTreeData = changeNodeAtPath({
treeData: currentTreeData,
path: rowInfoIter.path,
newNode: rowInfoIter.node,
getNodeKey: ({ treeIndex }) => treeIndex,
ignoreCollapsed: true,
});
} else if (isActive && !toggleMode) {
rowInfoIter.node.active = isActive;
rowInfoIter.node.expanded = !rowInfoIter.node.expanded;
currentTreeData = changeNodeAtPath({
treeData: currentTreeData,
path: rowInfoIter.path,
newNode: rowInfoIter.node,
getNodeKey: ({ treeIndex }) => treeIndex,
ignoreCollapsed: true,
});
} else if (isActive != rowInfoIter.node.active && !toggleMode) {
rowInfoIter.node.active = isActive;
currentTreeData = changeNodeAtPath({
treeData: currentTreeData,
path: rowInfoIter.path,
newNode: rowInfoIter.node,
getNodeKey: ({ treeIndex }) => treeIndex,
ignoreCollapsed: true,
});
}
},
});
} else {
rowInfo.node.expanded = !rowInfo.node.expanded;
currentTreeData = changeNodeAtPath({
treeData: currentTreeData,
path: rowInfo.path,
newNode: rowInfo.node,
getNodeKey: ({ treeIndex }) => treeIndex,
ignoreCollapsed: true,
});
}
} else if (rowInfo.node.children == undefined) {
// If node has no children, we select the node
walk({
treeData: currentTreeData,
getNodeKey: ({ treeIndex }) => treeIndex,
ignoreCollapsed: true,
callback: (rowInfoIter) => {
var isActive = rowInfoIter.treeIndex == rowInfo.treeIndex;
/*
* If toggleMode just toggle to activate/inactivate selected node
* If non toggle mode inactive all nodes but selected
*/
if (isActive && toggleMode) {
rowInfoIter.node.active = !rowInfoIter.node.active;
currentTreeData = changeNodeAtPath({
treeData: currentTreeData,
path: rowInfoIter.path,
newNode: rowInfoIter.node,
getNodeKey: ({ treeIndex }) => treeIndex,
ignoreCollapsed: true,
});
} else if (isActive != rowInfoIter.node.active && !toggleMode) {
rowInfoIter.node.active = isActive;
currentTreeData = changeNodeAtPath({
treeData: currentTreeData,
path: rowInfoIter.path,
newNode: rowInfoIter.node,
getNodeKey: ({ treeIndex }) => treeIndex,
ignoreCollapsed: true,
});
}
},
});
}

// Update tree with latest changes
this.updateTreeData(currentTreeData);

// If there is a callback, we use it
if (this.props.handleClick != undefined) {
this.props.handleClick(event, rowInfo);
}
}

getNodeProps(rowInfo) {
var nodeProps = {};
nodeProps['onClick'] = (event) => this.handleClick(event, rowInfo);

if (this.props.getButtons !== undefined) {
nodeProps['buttons'] = this.props.getButtons(rowInfo);
}
if (rowInfo.node.instance !== undefined) {
nodeProps['style'] = { cursor: 'pointer' };
}
if (rowInfo.node.active) {
nodeProps['className'] = 'activeNode';
}
if (this.props.getNodesProps !== undefined) {
nodeProps['title'] = this.props.getNodesProps(rowInfo);
}
return nodeProps;
}

render() {
var onlyExpandSearchedNodes =
this.props.searchQuery !== undefined && this.props.searchQuery !== null;
return (
<div
key={this.props.id + '_component'}
id={this.props.id + '_component'}
className="treeViewer"
style={this.props.style}
>
{this.props.controls ? this.props.controls : null}
<SortableTree
style={this.props.style}
treeData={this.state.treeData}
canDrag={false}
rowHeight={this.props.rowHeight}
scaffoldBlockPxWidth={22}
generateNodeProps={(rowInfo) => this.getNodeProps(rowInfo)}
onChange={(treeData) => this.updateTreeData(treeData)}
searchQuery={
this.props.searchQuery !== undefined ? this.props.searchQuery : null
}
onlyExpandSearchedNodes={
this.props.onlyExpandSearchedNodes !== undefined
? this.props.onlyExpandSearchedNodes
: false
}
/>
</div>
);
}
};
47 changes: 47 additions & 0 deletions webapp/components/general/tree/Tree.less
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
.treeViewer {
height: 100%;
}
.rst__tree {
height:100%;
}
.rst__rowTitleWithSubtitle{
height: initial;
}
.rst__rowContents{
background: #2e2a2a;
border: 0px;
color: #e9e9e9;
min-width: 160px;
}

.rst__lineChildren:after {
background-color: white;
}

.rst__lineBlock:before,
.rst__lineBlock:after {
background-color: white;
}

.rst__rowWrapper {
padding: 3px 10px 2px 0;
}

.rst__collapseButton,
.rst__expandButton {
box-shadow: 0 0 0 1px #FFF;
width: 12px;
height: 12px;
}

.rst__collapseButton:hover:not(:active),
.rst__expandButton:hover:not(:active){
width: 12px;
height: 12px;
background-size: initial;
}

.rst__collapseButton:focus,
.rst__expandButton:focus{
box-shadow: 0 0 0 1px #FFF, 0 0 1px 3px #83bef9;
}
4 changes: 2 additions & 2 deletions webapp/components/instantiation/NetPyNEInstantiated.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import CameraControls from '@metacell/geppetto-meta-ui/camera-controls/CameraCon
// import ControlPanel from 'geppetto-client/js/components/interface/controlPanel/controlpanel';

import { NetWorkControlButtons } from 'netpyne/components';
import { primaryColor, canvasBgDark, canvasBgLight } from '../../theme';
import { primaryColor, canvasBgDark, canvasBgLight, bgRegular } from '../../theme';
import { THEMES } from '../../constants';

const CANVAS_LIGHT = 'canvas-toolbar-btns-light';
Expand Down Expand Up @@ -222,7 +222,7 @@ class NetPyNEInstantiated extends React.Component {
cameraOptions={camOptions}
key="CanvasContainer"
data={canvasData}
backgroundColor="#000000"
backgroundColor={bgRegular}
/>
<div id="controlpanel" style={{ top: 0 }}>
{/* TODO: refactor the control panel with the list viewer
Expand Down
32 changes: 31 additions & 1 deletion webapp/css/flexlayout.less
Original file line number Diff line number Diff line change
@@ -1,12 +1,42 @@
@import "variables";

.flexlayout__layout {
div.flexlayout__layout {
border-left: none !important;
border-right: none !important;
background-color: transparent;
top: 0px;
border-top: none;

.flexlayout__tab_button {
&:hover {
.flexlayout__tab_button_trailing {
background: none;
}
}

&.flexlayout__tab_button--selected {
.flexlayout__tab_button_trailing {
background: none;
}
}
}

.flexlayout__tab_button_top {
box-shadow: none;
}

.flexlayout__tabset_tabbar_outer {
background-color: transparent;
}

.flexlayout__tabset_tabbar_outer_top {
border-bottom: none;
}

.flexlayout__tabset_tabbar_inner_tab_container_top {
border-top: none;
}

a {
color: @colorLink;
}
Expand Down
37 changes: 33 additions & 4 deletions webapp/css/netpyne.less
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,16 @@ body {
font-size: 16px;
}

html {
* {
box-sizing: border-box;
}
body {
background: @bgDarker;
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
}
}

:root {
--m2: 8px;
--m4: 16px;
Expand Down Expand Up @@ -142,6 +152,7 @@ button.actionButton {
color: white;
left: 22px;
pointer-events: none;
word-wrap: break-word;
z-index: 10;
}
.breadcrumbButtony button {
Expand Down Expand Up @@ -574,17 +585,35 @@ div.flexlayout__layout {
}
}
@-webkit-keyframes spin {
0% { -webkit-transform: rotate(0deg); }
100% { -webkit-transform: rotate(360deg); }
0% {
-webkit-transform: rotate(0deg);
}
100% {
-webkit-transform: rotate(360deg);
}
}

@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}

body {
.MuiTable-root {
border-collapse: separate;
}
}

.instantiatedContainer {
.position-toolbar {
button {
background-color: rgba(255, 255, 255, 0.2);
font-size: 0.875rem;
border-radius: 0;
}
}
}