import React, { ChangeEvent } from 'react'; import './App.css'; import 'typeface-roboto'; import { createStyles, withStyles } from '@material-ui/core/styles'; import AppBar from '@material-ui/core/AppBar'; import Button from '@material-ui/core/Button'; import Grid from '@material-ui/core/Grid'; import IconButton from '@material-ui/core/IconButton'; import Slider from '@material-ui/core/Slider'; import Toolbar from '@material-ui/core/Toolbar'; import Typography from '@material-ui/core/Typography'; import RefreshIcon from '@material-ui/icons/Refresh'; import SettingsIcon from '@material-ui/icons/Settings'; import CloseIcon from '@material-ui/icons/Close'; import ShuffleIcon from '@material-ui/icons/Shuffle'; import Snackbar from '@material-ui/core/Snackbar'; import FormControl from '@material-ui/core/FormControl'; import FormControlLabel from '@material-ui/core/FormControlLabel'; import FormGroup from '@material-ui/core/FormGroup'; import Checkbox from '@material-ui/core/Checkbox'; import Dialog from '@material-ui/core/Dialog'; import DialogTitle from '@material-ui/core/DialogTitle'; import DialogContent from '@material-ui/core/DialogContent'; import DialogActions from '@material-ui/core/DialogActions'; import MuiExpansionPanel from '@material-ui/core/ExpansionPanel'; import MuiExpansionPanelSummary from '@material-ui/core/ExpansionPanelSummary'; import MuiExpansionPanelDetails from '@material-ui/core/ExpansionPanelDetails'; import ExpandMoreIcon from '@material-ui/icons/ExpandMore'; import List from '@material-ui/core/List'; import ListItem from '@material-ui/core/ListItem'; import Backdrop from '@material-ui/core/Backdrop'; import Tooltip from '@material-ui/core/Tooltip'; import Chart from './Chart'; import { Graph } from './graphUtils'; const styles = createStyles({ bottomAppBar: { top: 'auto', bottom: 0, zIndex: 'auto', }, title: { flexGrow: 1, textAlign: 'left' }, panel: { position: 'absolute', top: 76, right: 16, width: 400, }, listItem: { paddingLeft: 0, paddingRight: 0, paddingTop: 2, paddingBottom: 2, fontSize: '0.8em', wordBreak: 'break-all', }, listSubtitle: { fontWeight: 600, paddingLeft: 0, paddingRight: 0, fontSize: '0.9em', }, listTitle: { lineHeight: 1.1, wordBreak: 'break-all' }, backdrop: { color: '#fff', zIndex: 100, }, snackbar: { bottom: 76 } }); const ExpansionPanel = withStyles({ root: { '&$expanded': { margin: 'auto', }, }, expanded: {}, })(MuiExpansionPanel); const ExpansionPanelSummary = withStyles({ root: {}, content: { '&$expanded': { margin: '12px 0', }, }, expanded: {}, })(MuiExpansionPanelSummary); const ExpansionPanelDetails = withStyles(theme => ({ root: { paddingTop: 0, paddingBottom: theme.spacing(1), }, }))(MuiExpansionPanelDetails); type AppState = { graph: Graph | undefined, graphData: any, logData: any[], sliderValue: number, maxSliderValue: number, sliderStep: number, settingsOpen: boolean, hideSidechainNodes: boolean, hidePrimitiveNodes: boolean, snackbarOpen: boolean, selectedNode: string, loading: boolean, layout: boolean, } type AppProps = { classes: any } class App extends React.Component { constructor(props: any) { super(props); this.state = { graph: undefined, graphData: undefined, logData: [], sliderValue: 0, maxSliderValue: 0, sliderStep: 1, settingsOpen: false, hideSidechainNodes: true, hidePrimitiveNodes: true, selectedNode: '', loading: false, snackbarOpen: false, layout: false, }; this.refresh = this.refresh.bind(this); } componentDidMount() { this.refresh(); } refresh() { this.setState({ loading: true }); fetch('/refresh') .then((response) => { return response.json() }) .then((data) => { const graph = new Graph(data.graph, this.state.hideSidechainNodes); this.setState({ graphData: data.graph, graph: graph, logData: data.log, maxSliderValue: data.log.length - 1, sliderStep: Math.max(1, Math.floor(data.log.length / 20)), sliderValue: Math.min(data.log.length, this.state.sliderValue), loading: false, snackbarOpen: graph.nodes.length > 100 }); }); } private renderExpansionPanel() { const { classes } = this.props; const { selectedNode, graph } = this.state; if (graph === undefined) return null; const info = graph.nodeSummary(selectedNode); if (info === undefined) return null; const subtitle = info.op ? (info.op === 'IO Node' ? info.op : `Operation: ${info.op}`) : `Subgraph: ${info.nodeCount} nodes, ${info.edgeCount} edges`; return ( } > {info.name}
{subtitle}
{ info.attributes && Attributes {info.attributes} } { info.inputs.length > 0 && Inputs ({info.inputs.length}) { info.inputs.map((item, i) => {item}) } } { info.outputs.length > 0 && Outputs ({info.outputs.length}) { info.outputs.map((item, i) => {item}) } }
); } render() { const { classes } = this.props; const { sliderValue, maxSliderValue, sliderStep, settingsOpen, loading, snackbarOpen } = this.state; const handleSliderChange = (event: ChangeEvent<{}>, value: number | number[]) => { this.setState({ sliderValue: value as number }); }; const handleSettingsDialogToggle = (value: boolean) => () => { this.setState({ settingsOpen: value }); }; const handleSettingsChange = (name: string) => (event: React.ChangeEvent) => { this.setState({ ...this.state, [name]: event.target.checked }, () => { this.setState({ graph: new Graph(this.state.graphData, this.state.hideSidechainNodes), }) }); }; const handleSelectionChange = (node: string) => { this.setState({ selectedNode: node }); }; const handleLoadingState = (state: boolean) => () => { this.setState({ loading: state }); }; const handleSnackbarClose = () => { this.setState({ snackbarOpen: false }); }; const handleLayoutStateChanged = (state: boolean) => () => { this.setState({ layout: state }); }; return (
NNI NAS Board {sliderValue}/{maxSliderValue} Settings } label='Hide sidechain nodes' /> { // TODO: hide primitive nodes /* } label='Hide primitive nodes' /> */} {this.renderExpansionPanel()} } /> { loading && Loading... }
); } } export default withStyles(styles)(App);