Commit 744885eb authored by Lijiao's avatar Lijiao Committed by chicm-ms
Browse files

Update WebUI (#295)

parent c5c0fa2e
const tsImportPluginFactory = require('ts-import-plugin')
const { getLoader } = require("react-app-rewired");
module.exports = function override(config, env) { module.exports = function override(config, env) {
const tsLoader = getLoader(
config.module.rules,
rule =>
rule.loader &&
typeof rule.loader === 'string' &&
rule.loader.includes('ts-loader')
);
tsLoader.options = {
getCustomTransformers: () => ({
before: [ tsImportPluginFactory({
libraryName: 'antd',
libraryDirectory: 'es',
style: 'css',
}) ]
})
};
return config; return config;
} };
\ No newline at end of file \ No newline at end of file
declare module '*.svg'
declare module '*.png'
declare module '*.jpg'
{
"name": "my-app",
"version": "0.1.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
"asap": {
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz",
"integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY="
},
"base16": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/base16/-/base16-1.0.0.tgz",
"integrity": "sha1-4pf2DX7BAUp6lxo568ipjAtoHnA="
},
"core-js": {
"version": "1.2.7",
"resolved": "https://registry.npmjs.org/core-js/-/core-js-1.2.7.tgz",
"integrity": "sha1-ZSKUwUZR2yj6k70tX/KYOk8IxjY="
},
"encoding": {
"version": "0.1.12",
"resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.12.tgz",
"integrity": "sha1-U4tm8+5izRq1HsMjgp0flIDHS+s=",
"requires": {
"iconv-lite": "0.4.21"
}
},
"fbemitter": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/fbemitter/-/fbemitter-2.1.1.tgz",
"integrity": "sha1-Uj4U/a9SSIBbsC9i78M75wP1GGU=",
"requires": {
"fbjs": "0.8.16"
}
},
"fbjs": {
"version": "0.8.16",
"resolved": "https://registry.npmjs.org/fbjs/-/fbjs-0.8.16.tgz",
"integrity": "sha1-XmdDL1UNxBtXK/VYR7ispk5TN9s=",
"requires": {
"core-js": "1.2.7",
"isomorphic-fetch": "2.2.1",
"loose-envify": "1.3.1",
"object-assign": "4.1.1",
"promise": "7.3.1",
"setimmediate": "1.0.5",
"ua-parser-js": "0.7.17"
}
},
"flux": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/flux/-/flux-3.1.3.tgz",
"integrity": "sha1-0jvtUVp5oi2TOrU6tK2hnQWy8Io=",
"requires": {
"fbemitter": "2.1.1",
"fbjs": "0.8.16"
}
},
"iconv-lite": {
"version": "0.4.21",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.21.tgz",
"integrity": "sha512-En5V9za5mBt2oUA03WGD3TwDv0MKAruqsuxstbMUZaj9W9k/m1CV/9py3l0L5kw9Bln8fdHQmzHSYtvpvTLpKw==",
"requires": {
"safer-buffer": "2.1.2"
}
},
"is-stream": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz",
"integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ="
},
"isomorphic-fetch": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz",
"integrity": "sha1-YRrhrPFPXoH3KVB0coGf6XM1WKk=",
"requires": {
"node-fetch": "1.7.3",
"whatwg-fetch": "2.0.4"
}
},
"js-tokens": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz",
"integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls="
},
"lodash.curry": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/lodash.curry/-/lodash.curry-4.1.1.tgz",
"integrity": "sha1-JI42By7ekGUB11lmIAqG2riyMXA="
},
"lodash.flow": {
"version": "3.5.0",
"resolved": "https://registry.npmjs.org/lodash.flow/-/lodash.flow-3.5.0.tgz",
"integrity": "sha1-h79AKSuM+D5OjOGjrkIJ4gBxZ1o="
},
"loose-envify": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.3.1.tgz",
"integrity": "sha1-0aitM/qc4OcT1l/dCsi3SNR4yEg=",
"requires": {
"js-tokens": "3.0.2"
}
},
"node-fetch": {
"version": "1.7.3",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-1.7.3.tgz",
"integrity": "sha512-NhZ4CsKx7cYm2vSrBAr2PvFOe6sWDf0UYLRqA6svUYg7+/TSfVAu49jYC4BvQ4Sms9SZgdqGBgroqfDhJdTyKQ==",
"requires": {
"encoding": "0.1.12",
"is-stream": "1.1.0"
}
},
"object-assign": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
"integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM="
},
"promise": {
"version": "7.3.1",
"resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz",
"integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==",
"requires": {
"asap": "2.0.6"
}
},
"prop-types": {
"version": "15.6.1",
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.6.1.tgz",
"integrity": "sha512-4ec7bY1Y66LymSUOH/zARVYObB23AT2h8cf6e/O6ZALB/N0sqZFEx7rq6EYPX2MkOdKORuooI/H5k9TlR4q7kQ==",
"requires": {
"fbjs": "0.8.16",
"loose-envify": "1.3.1",
"object-assign": "4.1.1"
}
},
"pure-color": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/pure-color/-/pure-color-1.3.0.tgz",
"integrity": "sha1-H+Bk+wrIUfDeYTIKi/eWg2Qi8z4="
},
"react-base16-styling": {
"version": "0.5.3",
"resolved": "https://registry.npmjs.org/react-base16-styling/-/react-base16-styling-0.5.3.tgz",
"integrity": "sha1-OFjyTpxN2MvT9wLz901YHKKRcmk=",
"requires": {
"base16": "1.0.0",
"lodash.curry": "4.1.1",
"lodash.flow": "3.5.0",
"pure-color": "1.3.0"
}
},
"react-json-view": {
"version": "1.16.1",
"resolved": "https://registry.npmjs.org/react-json-view/-/react-json-view-1.16.1.tgz",
"integrity": "sha512-9gx2S+b9+LHbjnIzIXrcDU14YI5KP3hhDgNHrQiLsV3dtnzoT8m6j37h7dpCaO1hPLZEc3Q/6VS1QjiLi0HT/w==",
"requires": {
"flux": "3.1.3",
"react-base16-styling": "0.5.3",
"react-textarea-autosize": "5.2.1"
}
},
"react-textarea-autosize": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/react-textarea-autosize/-/react-textarea-autosize-5.2.1.tgz",
"integrity": "sha512-bx6z2I35aapr71ggw2yZIA4qhmqeTa4ZVsSaTeFvtf9kfcZppDBh2PbMt8lvbdmzEk7qbSFhAxR9vxEVm6oiMg==",
"requires": {
"prop-types": "15.6.1"
}
},
"safer-buffer": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
},
"setimmediate": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz",
"integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU="
},
"ua-parser-js": {
"version": "0.7.17",
"resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.17.tgz",
"integrity": "sha512-uRdSdu1oA1rncCQL7sCj8vSyZkgtL7faaw9Tc9rZ3mGgraQ7+Pdx7w5mnOSF3gw9ZNG6oc+KXfkon3bKuROm0g=="
},
"whatwg-fetch": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-2.0.4.tgz",
"integrity": "sha512-dcQ1GWpOD/eEQ97k66aiEVpNnapVj90/+R+SXTPYGHpYBBypfKJEQjLrvMZ7YXbKm21gXd4NcuxUTjiv1YtLng=="
}
}
}
...@@ -9,24 +9,24 @@ ...@@ -9,24 +9,24 @@
"echarts": "^4.1.0", "echarts": "^4.1.0",
"echarts-for-react": "^2.0.14", "echarts-for-react": "^2.0.14",
"react": "^16.4.2", "react": "^16.4.2",
"react-app-rewired": "^1.5.2",
"react-dom": "^16.4.2", "react-dom": "^16.4.2",
"react-json-tree": "^0.11.0", "react-json-tree": "^0.11.0",
"react-router": "3.2.1" "react-router": "3.2.1",
"react-scripts-ts-antd": "2.17.0"
}, },
"scripts": { "scripts": {
"start": "react-app-rewired start --scripts-version react-scripts-ts", "start": "react-scripts-ts-antd start",
"build": "react-app-rewired build --scripts-version react-scripts-ts", "build": "react-scripts-ts-antd build",
"test": "react-app-rewired test --env=jsdom --scripts-version react-scripts-ts", "test": "react-scripts-ts-antd test --env=jsdom",
"eject": "react-scripts-ts eject" "eject": "react-scripts-ts-antd eject"
}, },
"devDependencies": { "devDependencies": {
"@types/jest": "^23.3.5",
"@types/node": "^10.7.0", "@types/node": "^10.7.0",
"@types/react-router": "3.0.15", "@types/react": "^16.4.17",
"@types/react-json-tree": "^0.6.8",
"@types/react-dom": "^16.0.7", "@types/react-dom": "^16.0.7",
"react-scripts-ts": "^2.17.0", "@types/react-json-tree": "^0.6.8",
"ts-import-plugin": "^1.5.4", "@types/react-router": "3.0.15",
"typescript": "^3.0.1" "typescript": "^3.0.1"
} }
} }
\ No newline at end of file
...@@ -5,6 +5,8 @@ ...@@ -5,6 +5,8 @@
<meta charset="utf-8"> <meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<title>Neural Network Intelligence</title> <title>Neural Network Intelligence</title>
<link rel="manifest" href="%PUBLIC_URL%/manifest.json">
<link rel="shortcut icon" href="%PUBLIC_URL%/icon.png">
</head> </head>
<body> <body>
......
{
"short_name": "React App",
"name": "Create React App Sample",
"icons": [
{
"src": "favicon.ico",
"sizes": "64x64 32x32 24x24 16x16",
"type": "image/x-icon"
}
],
"start_url": "./index.html",
"display": "standalone",
"theme_color": "#000000",
"background_color": "#ffffff"
}
\ No newline at end of file
.header_title{ .nni{
width: 100%; font-family: 'Segoe';
height: 60px; color: #212121;
line-height: 60px; font-size: 14px;
font-size: 24px; }
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
color: white; .header{
background-color: rgb(60,141,188) ;
user-select: none;
text-align: center;
position: fixed; position: fixed;
left: 0; left: 0;
top: 0; top: 0;
z-index: 999; width: 100%;
height: 80px;
background: #0071BC;
border-right: 1px solid #ccc;
z-index: 1000;
} }
.header_title img{ .headerCon{
height: 60px; min-width: 600px
} }
.right{ .content{
position: absolute; width: 86%;
left: 250px; min-width: 1024px;
top: 50px; margin: 0 auto;
width: calc(100% - 250px); margin-top: 90px;
/* padding-left: 20px; */ margin-bottom: 30px;
/* background: rgb(236,240,245); */
} }
import * as React from 'react'; import * as React from 'react';
import { Row, Col } from 'antd';
import './App.css'; import './App.css';
import SlideBar from './components/SlideBar'; import SlideBar from './components/SlideBar';
class App extends React.Component<{}, {}> { class App extends React.Component<{}, {}> {
render () { render() {
return ( return (
<div className="App"> <Row className="nni">
{/* <header className="header_title"><img src={require('./logo.jpg')} alt=""/></header> */} <Row className="header">
<header className="header_title">Neural Network Intelligence</header> <Col span={2} />
<div className="content"> <Col className="headerCon" span={22}>
<SlideBar /> <SlideBar />
<div className="right">{this.props.children}</div> </Col>
</div> </Row>
</div> <Row className="content">
{this.props.children}
</Row>
</Row>
); );
} }
} }
......
import * as React from 'react';
import axios from 'axios';
import { MANAGER_IP } from '../const';
import ReactEcharts from 'echarts-for-react';
const echarts = require('echarts/lib/echarts');
echarts.registerTheme('my_theme', {
color: '#3c8dbc'
});
require('echarts/lib/chart/scatter');
require('echarts/lib/component/tooltip');
require('echarts/lib/component/title');
require('../style/accuracy.css');
const accStyle = {
width: '100%',
height: 600,
margin: '0 auto'
};
interface ChartState {
option: object;
accNodata: string;
}
interface AccurPoint {
yAxis: Array<number>;
}
class Accuracy extends React.Component<{}, ChartState> {
public _isMounted = false;
public intervalID = 0;
constructor(props: {}) {
super(props);
this.state = {
option: {},
accNodata: ''
};
}
getOption = (dataObj: AccurPoint) => {
const yAxis = dataObj.yAxis;
const xAxis: Array<number> = [];
for (let i = 1; i <= yAxis.length; i++) {
xAxis.push(i);
}
return {
tooltip: {
trigger: 'item'
},
xAxis: {
name: 'Trial',
type: 'category',
data: xAxis
},
yAxis: {
name: 'Accuracy',
type: 'value',
data: yAxis
},
series: [{
symbolSize: 6,
type: 'scatter',
data: yAxis
}]
};
}
drawPointGraph = () => {
axios(`${MANAGER_IP}/trial-jobs`, {
method: 'GET'
})
.then(res => {
if (res.status === 200 && this._isMounted) {
const accData = res.data;
const accArr: Array<number> = [];
const accY: Array<AccurPoint> = [];
Object.keys(accData).map(item => {
if (accData[item].status === 'SUCCEEDED' && accData[item].finalMetricData) {
accArr.push(parseFloat(accData[item].finalMetricData.data));
}
});
accY.push({ yAxis: accArr });
let optionObj = this.getOption(accY[0]);
this.setState({ option: optionObj }, () => {
if (accArr.length === 0) {
this.setState({
accNodata: 'No data'
});
} else {
this.setState({
accNodata: ''
});
}
});
}
});
}
componentDidMount() {
this._isMounted = true;
this.drawPointGraph();
this.intervalID = window.setInterval(this.drawPointGraph, 10000);
}
componentWillUnmount() {
this._isMounted = false;
window.clearInterval(this.intervalID);
}
render() {
const { accNodata, option } = this.state;
return (
<div className="graph">
<div className="trial">
<div className="title">
<div>Trial Accuracy</div>
</div>
<div>
<ReactEcharts
option={option}
style={accStyle}
theme="my_theme"
/>
<div className="showMess">{accNodata}</div>
</div>
</div>
</div>
);
}
}
export default Accuracy;
\ No newline at end of file
import * as React from 'react'; import * as React from 'react';
import { Input, Button, message } from 'antd'; import { Input, Button, message } from 'antd';
import axios from 'axios'; import axios from 'axios';
import { MANAGER_IP, CONTROLTYPE } from '../const'; import { MANAGER_IP, CONTROLTYPE } from '../static/const';
const { TextArea } = Input; const { TextArea } = Input;
import '../style/control.css'; import '../static/style/control.scss';
interface ExperimentParams { interface ExperimentParams {
authorName: string; authorName: string;
......
import * as React from 'react'; import * as React from 'react';
import axios from 'axios'; import axios from 'axios';
import { Table, Select, Row, Col, Icon, Button } from 'antd'; import { Row, Col } from 'antd';
import { MANAGER_IP, overviewItem } from '../const'; import { MANAGER_IP, overviewItem } from '../static/const';
const Option = Select.Option; import {
import JSONTree from 'react-json-tree'; Experiment, TableObj,
require('../style/sessionpro.css'); Parameters, AccurPoint, TrialNumber
require('../style/logPath.css'); } from '../static/interface';
import {
getAccuracyData
} from '../static/function';
import SuccessTable from './overview/SuccessTable';
import Title1 from './overview/Title1';
import Progressed from './overview/Progress';
import Accuracy from './overview/Accuracy';
import SearchSpace from './overview/SearchSpace';
import BasicInfo from './overview/BasicInfo';
import TrialPro from './overview/TrialProfile';
interface ErrorPara { require('../static/style/overview.scss');
error?: string; require('../static/style/logPath.scss');
} require('../static/style/accuracy.css');
require('../static/style/table.scss');
interface TableObj { require('../static/style/overviewTitle.scss');
key: number;
id: string;
duration: number;
start: string;
end: string;
status: string;
acc?: number;
description: Parameters;
}
interface Parameters {
parameters: ErrorPara;
logPath?: string;
isLink?: boolean;
}
interface Experiment {
id: string;
author: string;
experName: string;
runConcurren: number;
maxDuration: number;
execDuration: number;
MaxTrialNum: number;
startTime: string;
endTime: string;
}
interface SessionState { interface SessionState {
tableData: Array<TableObj>; tableData: Array<TableObj>;
searchSpace: object; searchSpace: object;
status: string; status: string;
trialProfile: Experiment; trialProfile: Experiment;
tunerAssessor: object;
selNum: number; selNum: number;
option: object; option: object;
noData: string; noData: string;
accuracyData: object;
bestAccuracy: string;
accNodata: string;
trialNumber: TrialNumber;
} }
class Sessionpro extends React.Component<{}, SessionState> { class Overview extends React.Component<{}, SessionState> {
public _isMounted = false; public _isMounted = false;
public intervalID = 0; public intervalID = 0;
public intervalProfile = 1; public intervalProfile = 1;
public intervalAccuracy = 2;
constructor(props: {}) { constructor(props: {}) {
super(props); super(props);
...@@ -70,16 +57,15 @@ class Sessionpro extends React.Component<{}, SessionState> { ...@@ -70,16 +57,15 @@ class Sessionpro extends React.Component<{}, SessionState> {
maxDuration: 0, maxDuration: 0,
execDuration: 0, execDuration: 0,
MaxTrialNum: 0, MaxTrialNum: 0,
startTime: '', startTime: 0,
endTime: '' tuner: {},
trainingServicePlatform: ''
}, },
tunerAssessor: {},
tableData: [{ tableData: [{
key: 0, key: 0,
sequenceId: 0,
id: '', id: '',
duration: 0, duration: 0,
start: '',
end: '',
status: '', status: '',
acc: 0, acc: 0,
description: { description: {
...@@ -88,20 +74,23 @@ class Sessionpro extends React.Component<{}, SessionState> { ...@@ -88,20 +74,23 @@ class Sessionpro extends React.Component<{}, SessionState> {
}], }],
selNum: overviewItem, selNum: overviewItem,
option: {}, option: {},
noData: '' noData: '',
// accuracy
accuracyData: {},
accNodata: '',
bestAccuracy: '',
trialNumber: {
succTrial: 0,
failTrial: 0,
stopTrial: 0,
waitTrial: 0,
runTrial: 0,
unknowTrial: 0,
totalCurrentTrial: 0
}
}; };
} }
convertTime = (num: number) => {
if (num % 3600 === 0) {
return num / 3600 + 'h';
} else {
const hour = Math.floor(num / 3600);
const min = Math.floor(num / 60 % 60);
return hour > 0 ? `${hour}h ${min}min` : `${min}min`;
}
}
// show session // show session
showSessionPro = () => { showSessionPro = () => {
axios(`${MANAGER_IP}/experiment`, { axios(`${MANAGER_IP}/experiment`, {
...@@ -110,29 +99,28 @@ class Sessionpro extends React.Component<{}, SessionState> { ...@@ -110,29 +99,28 @@ class Sessionpro extends React.Component<{}, SessionState> {
.then(res => { .then(res => {
if (res.status === 200) { if (res.status === 200) {
let sessionData = res.data; let sessionData = res.data;
let tunerAsstemp = [];
let trialPro = []; let trialPro = [];
const startExper = new Date(sessionData.startTime).toLocaleString('en-US'); const trainingPlatform = sessionData.params.trainingServicePlatform;
let experEndStr: string; // assessor clusterMeteData
if (sessionData.endTime !== undefined) { const clusterMetaData = sessionData.params.clusterMetaData;
experEndStr = new Date(sessionData.endTime).toLocaleString('en-US'); const endTimenum = sessionData.endTime;
} else { const assessor = sessionData.params.assessor;
experEndStr = 'not over';
}
trialPro.push({ trialPro.push({
id: sessionData.id, id: sessionData.id,
author: sessionData.params.authorName, author: sessionData.params.authorName,
revision: sessionData.revision,
experName: sessionData.params.experimentName, experName: sessionData.params.experimentName,
runConcurren: sessionData.params.trialConcurrency, runConcurren: sessionData.params.trialConcurrency,
logDir: sessionData.logDir ? sessionData.logDir : 'undefined',
maxDuration: sessionData.params.maxExecDuration, maxDuration: sessionData.params.maxExecDuration,
execDuration: sessionData.execDuration, execDuration: sessionData.execDuration,
MaxTrialNum: sessionData.params.maxTrialNum, MaxTrialNum: sessionData.params.maxTrialNum,
startTime: startExper, startTime: sessionData.startTime,
endTime: experEndStr endTime: endTimenum ? endTimenum : undefined,
}); trainingServicePlatform: trainingPlatform,
tunerAsstemp.push({
tuner: sessionData.params.tuner, tuner: sessionData.params.tuner,
assessor: sessionData.params.assessor assessor: assessor ? assessor : undefined,
clusterMetaData: clusterMetaData ? clusterMetaData : undefined
}); });
// search space format loguniform max and min // search space format loguniform max and min
const searchSpace = JSON.parse(sessionData.params.searchSpace); const searchSpace = JSON.parse(sessionData.params.searchSpace);
...@@ -161,8 +149,7 @@ class Sessionpro extends React.Component<{}, SessionState> { ...@@ -161,8 +149,7 @@ class Sessionpro extends React.Component<{}, SessionState> {
if (this._isMounted) { if (this._isMounted) {
this.setState({ this.setState({
trialProfile: trialPro[0], trialProfile: trialPro[0],
searchSpace: searchSpace, searchSpace: searchSpace
tunerAssessor: tunerAsstemp[0]
}); });
} }
} }
...@@ -189,40 +176,69 @@ class Sessionpro extends React.Component<{}, SessionState> { ...@@ -189,40 +176,69 @@ class Sessionpro extends React.Component<{}, SessionState> {
const { selNum } = this.state; const { selNum } = this.state;
const tableData = res.data; const tableData = res.data;
const topTableData: Array<TableObj> = []; const topTableData: Array<TableObj> = [];
const profile: TrialNumber = {
succTrial: 0,
failTrial: 0,
stopTrial: 0,
waitTrial: 0,
runTrial: 0,
unknowTrial: 0,
totalCurrentTrial: 0
};
// currently totoal number
profile.totalCurrentTrial = tableData.length;
Object.keys(tableData).map(item => { Object.keys(tableData).map(item => {
if (tableData[item].status === 'SUCCEEDED') { switch (tableData[item].status) {
const desJobDetail: Parameters = { case 'WAITING':
parameters: {} profile.waitTrial += 1;
}; break;
const startTime = new Date(tableData[item].startTime).toLocaleString('en-US');
const endTime = new Date(tableData[item].endTime).toLocaleString('en-US'); case 'UNKNOWN':
const duration = (tableData[item].endTime - tableData[item].startTime) / 1000; profile.unknowTrial += 1;
let acc; break;
if (tableData[item].finalMetricData) {
acc = parseFloat(tableData[item].finalMetricData.data); case 'FAILED':
} profile.failTrial += 1;
if (tableData[item].hyperParameters) { break;
desJobDetail.parameters = JSON.parse(tableData[item].hyperParameters).parameters;
} else { case 'USER_CANCELED':
desJobDetail.parameters = { error: 'This trial\'s parameters are not available.' }; case 'SYS_CANCELED':
} profile.stopTrial += 1;
if (tableData[item].logPath !== undefined) { break;
desJobDetail.logPath = tableData[item].logPath; case 'SUCCEEDED':
const isSessionLink = /^http/gi.test(tableData[item].logPath); profile.succTrial += 1;
if (isSessionLink) { const desJobDetail: Parameters = {
desJobDetail.isLink = true; parameters: {}
};
const duration = (tableData[item].endTime - tableData[item].startTime) / 1000;
let acc;
if (tableData[item].finalMetricData) {
acc = parseFloat(tableData[item].finalMetricData.data);
} }
} // if hyperparameters is undefine, show error message, else, show parameters value
topTableData.push({ if (tableData[item].hyperParameters) {
key: topTableData.length, desJobDetail.parameters = JSON.parse(tableData[item].hyperParameters).parameters;
id: tableData[item].id, } else {
duration: duration, desJobDetail.parameters = { error: 'This trial\'s parameters are not available.' };
start: startTime, }
end: endTime, if (tableData[item].logPath !== undefined) {
status: tableData[item].status, desJobDetail.logPath = tableData[item].logPath;
acc: acc, const isSessionLink = /^http/gi.test(tableData[item].logPath);
description: desJobDetail if (isSessionLink) {
}); desJobDetail.isLink = true;
}
}
topTableData.push({
key: topTableData.length,
sequenceId: tableData[item].sequenceId,
id: tableData[item].id,
duration: duration,
status: tableData[item].status,
acc: acc,
description: desJobDetail
});
break;
default:
} }
}); });
topTableData.sort((a: TableObj, b: TableObj) => { topTableData.sort((a: TableObj, b: TableObj) => {
...@@ -235,41 +251,14 @@ class Sessionpro extends React.Component<{}, SessionState> { ...@@ -235,41 +251,14 @@ class Sessionpro extends React.Component<{}, SessionState> {
topTableData.length = Math.min(selNum, topTableData.length); topTableData.length = Math.min(selNum, topTableData.length);
if (this._isMounted) { if (this._isMounted) {
this.setState({ this.setState({
tableData: topTableData tableData: topTableData,
trialNumber: profile
}); });
} }
} }
}); });
} }
handleChange = (value: string) => {
let num = parseFloat(value);
window.clearInterval(this.intervalID);
if (this._isMounted) {
this.setState({ selNum: num }, () => {
this.showTrials();
this.intervalID = window.setInterval(this.showTrials, 10000);
});
}
}
// trial's duration, accurate to seconds
convertDuration = (num: number) => {
const hour = Math.floor(num / 3600);
const min = Math.floor(num / 60 % 60);
const second = Math.floor(num % 60);
const result = hour > 0 ? `${hour} h ${min} min ${second}s` : `${min} min ${second}s`;
if (hour <= 0 && min === 0 && second !== 0) {
return `${second}s`;
} else if (hour === 0 && min !== 0 && second === 0) {
return `${min}min`;
} else if (hour === 0 && min !== 0 && second !== 0) {
return `${min}min ${second}s`;
} else {
return result;
}
}
downExperimentContent = () => { downExperimentContent = () => {
axios axios
.all([ .all([
...@@ -319,9 +308,48 @@ class Sessionpro extends React.Component<{}, SessionState> { ...@@ -319,9 +308,48 @@ class Sessionpro extends React.Component<{}, SessionState> {
})); }));
} }
// trial accuracy graph
drawPointGraph = () => {
axios(`${MANAGER_IP}/trial-jobs`, {
method: 'GET'
})
.then(res => {
if (res.status === 200 && this._isMounted) {
const accData = res.data;
const accArr: Array<number> = [];
const accY: Array<AccurPoint> = [];
Object.keys(accData).map(item => {
if (accData[item].status === 'SUCCEEDED' && accData[item].finalMetricData) {
accArr.push(parseFloat(accData[item].finalMetricData.data));
}
});
accArr.sort((a, b) => { return a - b; });
accArr.length = Math.min(10, accArr.length);
accY.push({ yAxis: accArr });
let optionObj = getAccuracyData(accY[0]);
const bestAccnum = Math.max(...accArr);
this.setState({ accuracyData: optionObj }, () => {
if (accArr.length === 0) {
this.setState({
accNodata: 'No data'
});
} else {
this.setState({
accNodata: '',
bestAccuracy: bestAccnum.toFixed(6)
});
}
});
}
});
}
componentDidMount() { componentDidMount() {
this.showSessionPro(); this.showSessionPro();
this.showTrials(); this.showTrials();
this.drawPointGraph();
this.intervalAccuracy = window.setInterval(this.drawPointGraph, 10000);
this._isMounted = true; this._isMounted = true;
this.intervalID = window.setInterval(this.showTrials, 10000); this.intervalID = window.setInterval(this.showTrials, 10000);
this.intervalProfile = window.setInterval(this.showSessionPro, 60000); this.intervalProfile = window.setInterval(this.showSessionPro, 60000);
...@@ -331,254 +359,77 @@ class Sessionpro extends React.Component<{}, SessionState> { ...@@ -331,254 +359,77 @@ class Sessionpro extends React.Component<{}, SessionState> {
this._isMounted = false; this._isMounted = false;
window.clearInterval(this.intervalID); window.clearInterval(this.intervalID);
window.clearInterval(this.intervalProfile); window.clearInterval(this.intervalProfile);
window.clearInterval(this.intervalAccuracy);
} }
render() { render() {
// show better job details
let bgColor = '';
const columns = [{
title: 'Id',
dataIndex: 'id',
key: 'id',
width: 150,
className: 'tableHead',
}, {
title: 'Duration',
dataIndex: 'duration',
key: 'duration',
width: '9%',
sorter: (a: TableObj, b: TableObj) => (a.duration as number) - (b.duration as number),
render: (text: string, record: TableObj) => {
let duration;
if (record.duration) {
duration = this.convertDuration(record.duration);
}
return (
<span>{duration}</span>
);
},
}, {
title: 'Start',
dataIndex: 'start',
key: 'start',
width: 150
}, {
title: 'End',
dataIndex: 'end',
key: 'end',
width: 150
}, {
title: 'Status',
dataIndex: 'status',
key: 'status',
width: 150,
className: 'tableStatus',
render: (text: string, record: TableObj) => {
bgColor = record.status;
return (
<span className={`${bgColor} commonStyle`}>{record.status}</span>
);
}
}, {
title: 'Loss/Accuracy',
dataIndex: 'acc',
key: 'acc',
width: 150
}];
const openRow = (record: TableObj) => {
let isHasParameters = true;
if (record.description.parameters.error) {
isHasParameters = false;
}
const openRowDataSource = {
parameters: record.description.parameters
};
let isLogLink: boolean = false;
const logPathRow = record.description.logPath;
if (record.description.isLink !== undefined) {
isLogLink = true;
}
return (
<pre id="description" className="jsontree">
{
isHasParameters
?
<JSONTree
hideRoot={true}
shouldExpandNode={() => true} // default expandNode
getItemString={() => (<span />)} // remove the {} items
data={openRowDataSource}
/>
:
<div className="logpath">
<span className="logName">Error: </span>
<span className="error">'This trial's parameters are not available.'</span>
</div>
}
{
isLogLink
?
<div className="logpath">
<span className="logName">logPath: </span>
<a className="logContent logHref" href={logPathRow} target="_blank">{logPathRow}</a>
</div>
:
<div className="logpath">
<span className="logName">logPath: </span>
<span className="logContent">{logPathRow}</span>
</div>
}
</pre>
);
};
const { const {
trialProfile, searchSpace, tunerAssessor, tableData, status trialProfile,
searchSpace,
tableData,
accuracyData,
accNodata,
status,
trialNumber,
bestAccuracy
} = this.state; } = this.state;
const maxRuntime = this.convertTime(trialProfile.maxDuration);
let running;
let runningStr = '';
if (trialProfile.endTime === 'not over') {
running = trialProfile.maxDuration - trialProfile.execDuration;
runningStr = this.convertTime(running);
} else {
runningStr = '0';
}
return ( return (
<div className="session" id="session"> <div className="overview">
<div className="head"> {/* status and experiment block */}
<div className="headCon"> <Row className="basicExperiment">
<div className="author"> <Title1 text="Experiment" icon="11.png" />
<div className="message"> <BasicInfo trialProfile={trialProfile} status={status} />
<div className="proKey"> </Row>
<span>Author:</span> <Row className="overMessage">
<span className="messcont">{trialProfile.author}</span> {/* status graph */}
</div> <Col span={8} className="prograph overviewBoder">
<span>Experiment&nbsp;Name:</span> <Title1 text="Status" icon="5.png" />
<p className="messcont">{trialProfile.experName}</p> <Progressed
</div> trialNumber={trialNumber}
<div className="logo"> trialProfile={trialProfile}
<Icon className="bone" type="user" /> bestAccuracy={bestAccuracy}
</div> status={status}
</div> />
<div className="type"> </Col>
<div className="message"> {/* experiment parameters search space tuner assessor... */}
<div className="proKey"> <Col span={8} className="overviewBoder">
id: <Title1 text="Search Space" icon="10.png" />
<span className="messcont">{trialProfile.id}</span> <Row className="experiment">
</div> <SearchSpace searchSpace={searchSpace} />
<p> </Row>
Duration: </Col>
<span className="messcont">{maxRuntime}</span> <Col span={8} className="overviewBoder">
</p> <Title1 text="Trial Profile" icon="4.png" />
<p> <Row className="experiment">
Still&nbsp;run: {/* the scroll bar all the trial profile in the searchSpace div*/}
<span className="messcont">{runningStr}</span> <div className="experiment searchSpace">
</p> <TrialPro
</div> tiralProInfo={trialProfile}
<div className="logo"> />
<Icon className="tyellow" type="bulb" />
</div>
</div>
<div className="runtime message">
<p className="proTime">
<span>Start Time:</span><br />
<span className="messcont">{trialProfile.startTime}</span>
</p>
<span>End Time:</span>
<p className="messcont">{trialProfile.endTime}</p>
</div>
<div className="cdf">
<div className="message">
<div className="proKey trialNum">
Concurrency&nbsp;Trial:
<span className="messcont">{trialProfile.runConcurren}</span>
</div>
<p>
MaxTrial&nbsp;Number:
<span className="messcont">{trialProfile.MaxTrialNum}</span>
</p>
<p className="experStatus">
Status:
<span className="messcont">{status}</span>
</p>
</div>
<div className="logo">
<Icon className="fogreen" type="picture" />
</div> </div>
</div> </Row>
</div> </Col>
</div> </Row>
<div className="clear" /> <Row className="overGraph">
<div className="jsonbox"> <Col span={8} className="overviewBoder">
<div> <Title1 text="Optimization Progress" icon="3.png" />
<h2 className="searchTitle title">Search Space</h2> <Row className="accuracy">
<pre className="searchSpace jsontree"> <Accuracy
<JSONTree accuracyData={accuracyData}
hideRoot={true} accNodata={accNodata}
shouldExpandNode={() => true} height={324}
getItemString={() => (<span />)}
data={searchSpace}
/>
</pre>
</div>
<div>
<h2 className="searchTitle title">Trial Profile</h2>
<pre className="trialProfile jsontree">
<JSONTree
hideRoot={true}
shouldExpandNode={() => true}
getItemString={() => (<span />)}
data={tunerAssessor}
/> />
</pre>
</div>
</div>
<div className="clear" />
<div className="comtable">
<div className="selectInline">
<Row>
<Col span={18}>
<h2>The trials that succeeded</h2>
</Col>
<Col span={6}>
<span className="tabuser1">top</span>
<Select
style={{ width: 200 }}
placeholder="50"
optionFilterProp="children"
onSelect={this.handleChange}
>
<Option value="5">5</Option>
<Option value="50">50</Option>
<Option value="100">100</Option>
<Option value="150">150</Option>
<Option value="200">200</Option>
</Select>
</Col>
</Row> </Row>
</div> </Col>
<Table <Col span={16} id="succeTable">
columns={columns} <Title1 text="Top10 Trials" icon="7.png" />
expandedRowRender={openRow} <SuccessTable tableSource={tableData} />
dataSource={tableData} </Col>
className="tables" </Row>
bordered={true}
/>
</div>
<div className="downExp">
<Button
type="primary"
className="tableButton"
onClick={this.downExperimentContent}
>
Download experiment summary
</Button>
</div>
</div> </div>
); );
} }
} }
export default Sessionpro; export default Overview;
import * as React from 'react'; import * as React from 'react';
import { Link, IndexLink } from 'react-router'; import { Link } from 'react-router';
import { Icon } from 'antd'; import '../static/style/slideBar.scss';
import '../style/slideBar.css';
class SlideBar extends React.Component<{}, {}> { class SlideBar extends React.Component<{}, {}> {
render() { render() {
return ( return (
<div className="slider"> <ul className="nav">
<ul className="nav"> <li className="logo">
<li> <img src={require('../static/img/logo.png')} style={{ width: 156 }} alt="NNI logo" />
<IndexLink to={'/oview'} activeClassName="high"> </li>
<Icon className="icon" type="home" />Overview <li className="tab">
<Icon className="floicon" type="right" /> <Link to={'/oview'} activeClassName="high">
</IndexLink> Overview
</li>
<li>
<Link to={'/all'} activeClassName="high">
<Icon className="icon" type="dot-chart" />Optimization Progress
<Icon className="floicon" type="right" />
</Link> </Link>
</li> </li>
<li> <li className="tab">
<Link to={'/hyper'} activeClassName="high"> <Link to={'/detail'} activeClassName="high">
<Icon className="icon" type="rocket" />Hyper Parameter Trials Detail
<Icon className="floicon" type="right" />
</Link> </Link>
</li> </li>
<li> </ul>
<Link to={'/trastaus'} activeClassName="high">
<Icon className="icon" type="bar-chart" />Trial Status
<Icon className="floicon" type="right" />
</Link>
</li>
<li>
<Link to={'/control'} activeClassName="high">
<Icon className="icon" type="form" />Control
<Icon className="floicon" type="right" />
</Link>
</li>
<li>
<a href="https://github.com/Microsoft/nni/issues" target="_blank">
<Icon className="icon" type="smile" />Feedback
</a>
</li>
</ul>
</div>
); );
} }
} }
......
import * as React from 'react'; import * as React from 'react';
import axios from 'axios'; import axios from 'axios';
import { message } from 'antd'; import { message } from 'antd';
import { MANAGER_IP } from '../const'; import { MANAGER_IP } from '../static/const';
import '../style/tensor.css'; import '../static/style/tensor.scss';
interface TensorState { interface TensorState {
urlTensor: string; urlTensor: string;
......
import * as React from 'react';
import axios from 'axios';
import { MANAGER_IP } from '../static/const';
import { Row, Tabs } from 'antd';
import { getAccuracyData } from '../static/function';
import { TableObj, Parameters, AccurPoint } from '../static/interface';
import Accuracy from './overview/Accuracy';
import Duration from './trial-detail/Duration';
import Title1 from './overview/Title1';
import Para from './trial-detail/Para';
import TableList from './trial-detail/TableList';
const TabPane = Tabs.TabPane;
import '../static/style/trialsDetail.scss';
interface TrialDetailState {
accSource: object;
accNodata: string;
tableListSource: Array<TableObj>;
}
class TrialsDetail extends React.Component<{}, TrialDetailState> {
public _isMounted = false;
public interAccuracy = 0;
public interTableList = 1;
constructor(props: {}) {
super(props);
this.state = {
accSource: {},
accNodata: '',
tableListSource: []
};
}
// trial accuracy graph
drawPointGraph = () => {
axios(`${MANAGER_IP}/trial-jobs`, {
method: 'GET'
})
.then(res => {
if (res.status === 200 && this._isMounted) {
const accData = res.data;
const accArr: Array<number> = [];
const accY: Array<AccurPoint> = [];
Object.keys(accData).map(item => {
if (accData[item].status === 'SUCCEEDED' && accData[item].finalMetricData) {
accArr.push(parseFloat(accData[item].finalMetricData.data));
}
});
accY.push({ yAxis: accArr });
const optionObj = getAccuracyData(accY[0]);
this.setState({ accSource: optionObj }, () => {
if (accArr.length === 0) {
this.setState({
accNodata: 'No data'
});
} else {
this.setState({
accNodata: ''
});
}
});
}
});
}
drawTableList = () => {
axios(`${MANAGER_IP}/trial-jobs`, {
method: 'GET'
})
.then(res => {
if (res.status === 200) {
const trialJobs = res.data;
const trialTable: Array<TableObj> = [];
Object.keys(trialJobs).map(item => {
// only succeeded trials have finalMetricData
let desc: Parameters = {
parameters: {}
};
let acc = 0;
let duration = 0;
const id = trialJobs[item].id !== undefined
? trialJobs[item].id
: '';
const status = trialJobs[item].status !== undefined
? trialJobs[item].status
: '';
const begin = trialJobs[item].startTime;
const end = trialJobs[item].endTime;
if (begin) {
if (end) {
duration = (end - begin) / 1000;
} else {
duration = (new Date().getTime() - begin) / 1000;
}
}
if (trialJobs[item].hyperParameters !== undefined) {
desc.parameters = JSON.parse(trialJobs[item].hyperParameters).parameters;
} else {
desc.parameters = { error: 'This trial\'s parameters are not available.' };
}
if (trialJobs[item].logPath !== undefined) {
desc.logPath = trialJobs[item].logPath;
const isHyperLink = /^http/gi.test(trialJobs[item].logPath);
if (isHyperLink) {
desc.isLink = true;
}
}
if (trialJobs[item].finalMetricData !== undefined) {
acc = parseFloat(trialJobs[item].finalMetricData.data);
}
trialTable.push({
key: trialTable.length,
sequenceId: trialJobs[item].sequenceId,
id: id,
status: status,
duration: duration,
acc: acc,
description: desc
});
});
if (this._isMounted) {
this.setState(() => ({
tableListSource: trialTable
}));
}
}
});
}
callback = (key: string) => {
switch (key) {
case '1':
window.clearInterval(Para.intervalIDPara);
window.clearInterval(Duration.intervalDuration);
this.drawPointGraph();
this.interAccuracy = window.setInterval(this.drawPointGraph, 10000);
break;
case '2':
window.clearInterval(this.interAccuracy);
window.clearInterval(Duration.intervalDuration);
break;
case '3':
window.clearInterval(this.interAccuracy);
window.clearInterval(Para.intervalIDPara);
break;
default:
}
}
componentDidMount() {
this._isMounted = true;
this.drawPointGraph();
this.drawTableList();
this.interAccuracy = window.setInterval(this.drawPointGraph, 10000);
this.interTableList = window.setInterval(this.drawTableList, 10000);
}
componentWillUnmount() {
this._isMounted = false;
window.clearInterval(this.interTableList);
window.clearInterval(this.interAccuracy);
}
render() {
const {
accSource, accNodata,
tableListSource
} = this.state;
const titleOfacc = (
<Title1 text="Trial Accuracy" icon="3.png" />
);
const titleOfhyper = (
<Title1 text="Hyper Parameter" icon="1.png" />
);
const titleOfDuration = (
<Title1 text="Trial Duration" icon="2.png" />
);
return (
<div>
<div className="trial" id="tabsty">
<Tabs onChange={this.callback} type="card">
<TabPane tab={titleOfacc} key="1">
<Row className="graph">
<Accuracy
height={432}
accuracyData={accSource}
accNodata={accNodata}
/>
</Row>
</TabPane>
<TabPane tab={titleOfhyper} key="2">
<Row className="graph"><Para /></Row>
</TabPane>
<TabPane tab={titleOfDuration} key="3">
<Duration />
</TabPane>
</Tabs>
</div>
{/* trial table list */}
<TableList
tableSource={tableListSource}
updateList={this.drawTableList}
/>
</div>
);
}
}
export default TrialsDetail;
\ No newline at end of file
import * as React from 'react';
import ReactEcharts from 'echarts-for-react';
const echarts = require('echarts/lib/echarts');
echarts.registerTheme('my_theme', {
color: '#3c8dbc'
});
require('echarts/lib/chart/scatter');
require('echarts/lib/component/tooltip');
require('echarts/lib/component/title');
interface AccuracyProps {
accuracyData: object;
accNodata: string;
height: number;
}
class Accuracy extends React.Component<AccuracyProps, {}> {
constructor(props: AccuracyProps) {
super(props);
}
render() {
const { accNodata, accuracyData, height } = this.props;
return (
<div>
<ReactEcharts
option={accuracyData}
style={{
width: '100%',
height: height,
margin: '0 auto',
}}
theme="my_theme"
/>
<div className="showMess">{accNodata}</div>
</div>
);
}
}
export default Accuracy;
\ No newline at end of file
import * as React from 'react';
import {
Row, Col,
Tooltip
} from 'antd';
import { Experiment } from '../../static/interface';
interface BasicInfoProps {
trialProfile: Experiment;
status: string;
}
class BasicInfo extends React.Component<BasicInfoProps, {}> {
constructor(props: BasicInfoProps) {
super(props);
}
render() {
const { trialProfile,
// status
} = this.props;
return (
<Row className="main">
<Col span={8} className="padItem basic">
<p>Name</p>
<div>{trialProfile.experName}</div>
<p>ID</p>
<div>{trialProfile.id}</div>
</Col>
<Col span={8} className="padItem basic">
<Row>
<Col span={18}>
<p>Start Time</p>
<div className="nowrap">
{new Date(trialProfile.startTime).toLocaleString('en-US')}
</div>
<p>End Time</p>
<div className="nowrap">
{
trialProfile.endTime
?
new Date(trialProfile.endTime).toLocaleString('en-US')
:
'none'
}
</div>
</Col>
</Row>
</Col>
<Col span={8} className="padItem basic">
<p>LogPath</p>
<div className="logPath">
<Tooltip placement="top" title={trialProfile.logDir}>
{trialProfile.logDir}
</Tooltip>
</div>
<p>TrainingPlatform</p>
<div className="nowrap">
{
trialProfile.trainingServicePlatform
?
trialProfile.trainingServicePlatform
:
'none'
}
</div>
</Col>
</Row>
);
}
}
export default BasicInfo;
\ No newline at end of file
import * as React from 'react';
import {
Row,
Col,
} from 'antd';
import { Experiment, TrialNumber } from '../../static/interface';
import { convertTime } from '../../static/function';
import ProgressBar from './ProgressItem';
import '../../static/style/progress.scss';
interface ProgressProps {
trialProfile: Experiment;
trialNumber: TrialNumber;
bestAccuracy: string;
status: string;
}
class Progressed extends React.Component<ProgressProps, {}> {
constructor(props: ProgressProps) {
super(props);
}
render() {
const { trialProfile,
trialNumber, bestAccuracy,
status
} = this.props;
// remaining time
const bar2 = trialNumber.totalCurrentTrial - trialNumber.waitTrial - trialNumber.unknowTrial;
const bar2Percent = (bar2 / trialProfile.MaxTrialNum) * 100;
const percent = (trialProfile.execDuration / trialProfile.maxDuration) * 100;
const runDuration = convertTime(trialProfile.execDuration);
const remaining = convertTime(trialProfile.maxDuration - trialProfile.execDuration);
return (
<Row className="progress">
<Row className="basic">
<p>Status</p>
<div className="status">{status}</div>
</Row>
<ProgressBar
who="Duration"
percent={percent}
description={runDuration}
maxString={`MaxDuration: ${convertTime(trialProfile.maxDuration)}`}
/>
<ProgressBar
who="TrialNum"
percent={bar2Percent}
description={bar2.toString()}
maxString={`MaxTrialNumber: ${trialProfile.MaxTrialNum}`}
/>
<Row className="basic colorOfbasic mess">
<p>Best Accuracy</p>
<div>{bestAccuracy}</div>
</Row>
<Row className="mess">
<Col span={8}>
<Row className="basic colorOfbasic">
<p>Time Spent</p>
<div>{convertTime(trialProfile.execDuration)}</div>
</Row>
</Col>
<Col span={9}>
<Row className="basic colorOfbasic">
<p>Remaining Time</p>
<div>{remaining}</div>
</Row>
</Col>
<Col span={7}>
<Row className="basic colorOfbasic">
<p>Duration</p>
<div>{convertTime(trialProfile.maxDuration)}</div>
</Row>
</Col>
</Row>
<Row className="mess">
<Col span={8}>
<Row className="basic colorOfbasic">
<p>Succeed Trial</p>
<div>{trialNumber.succTrial}</div>
</Row>
</Col>
<Col span={9}>
<Row className="basic">
<p>Stopped Trial</p>
<div>{trialNumber.stopTrial}</div>
</Row>
</Col>
<Col span={7}>
<Row className="basic">
<p>Failed Trial</p>
<div>{trialNumber.failTrial}</div>
</Row>
</Col>
</Row>
</Row>
);
}
}
export default Progressed;
\ No newline at end of file
import * as React from 'react';
import { Row, Col, Progress } from 'antd';
interface ProItemProps {
who: string;
percent: number;
description: string;
maxString: string;
}
class ProgressBar extends React.Component<ProItemProps, {}> {
constructor(props: ProItemProps) {
super(props);
}
render() {
const { who, percent, description, maxString } = this.props;
return (
<div>
<Row className="probar">
<Col span={6}>
<div className="name">{who}</div>
</Col>
<Col span={17} className="bar">
<div className="showProgress">
<Progress
percent={percent}
strokeWidth={30}
// strokeLinecap={'square'}
format={() => description}
/>
</div>
<Row className="description">
<Col span={12}>0</Col>
<Col className="right" span={12}>{maxString}</Col>
</Row>
</Col>
</Row>
<br/>
</div>
);
}
}
export default ProgressBar;
\ No newline at end of file
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment