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

Update WebUI (#295)

parent c5c0fa2e
import * as React from 'react';
interface SearchspaceProps {
searchSpace: object;
}
class SearchSpace extends React.Component<SearchspaceProps, {}> {
constructor(props: SearchspaceProps) {
super(props);
}
render() {
const { searchSpace } = this.props;
return (
<pre className="experiment searchSpace" style={{paddingLeft: 20}}>
{JSON.stringify(searchSpace, null, 4)}
</pre>
);
}
}
export default SearchSpace;
\ No newline at end of file
import * as React from 'react';
import JSONTree from 'react-json-tree';
import { Table } from 'antd';
import { TableObj } from '../../static/interface';
import { convertDuration } from '../../static/function';
import '../../static/style/tableStatus.css';
interface SuccessTableProps {
tableSource: Array<TableObj>;
}
class SuccessTable extends React.Component<SuccessTableProps, {}> {
constructor(props: SuccessTableProps) {
super(props);
}
render() {
const { tableSource } = this.props;
let bgColor = '';
const columns = [{
title: 'Number',
dataIndex: 'sequenceId',
key: 'sequenceId',
width: 60,
className: 'tableHead',
render: (text: string, record: TableObj) => {
return (
<span>#{record.sequenceId}</span>
);
}
}, {
title: 'Id',
dataIndex: 'id',
key: 'id',
width: 150,
className: 'tableHead'
}, {
title: 'Duration',
dataIndex: 'duration',
key: 'duration',
width: 150,
render: (text: string, record: TableObj) => {
let duration;
if (record.duration) {
duration = convertDuration(record.duration);
}
return (
<div>{duration}</div>
);
},
}, {
title: 'Status',
dataIndex: 'status',
key: 'status',
width: 150,
className: 'tableStatus',
render: (text: string, record: TableObj) => {
bgColor = record.status;
return (
<div className={`${bgColor} commonStyle`}>
{record.status}
</div>
);
}
}, {
title: 'Default Metric',
dataIndex: 'acc',
key: 'acc',
render: (text: string, record: TableObj) => {
return (
<div>
{
record.acc
?
record.acc.toFixed(6)
:
record.acc
}
</div>
);
}
// 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="hyperpar">
{
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>
);
};
return (
<div className="tabScroll">
<Table
columns={columns}
expandedRowRender={openRow}
dataSource={tableSource}
className="commonTableStyle"
pagination={false}
/>
</div>
);
}
}
export default SuccessTable;
\ No newline at end of file
import * as React from 'react';
interface Title1Props {
text: string;
icon: string;
}
class Title1 extends React.Component<Title1Props, {}> {
constructor(props: Title1Props) {
super(props);
}
render() {
const { text, icon } = this.props;
return (
<div>
<div className="panelTitle">
<img src={require(`../../static/img/icon/${icon}`)} alt="icon" />
<span>{text}</span>
</div>
</div>
);
}
}
export default Title1;
\ No newline at end of file
import * as React from 'react';
import { Experiment } from '../../static/interface';
interface TrialInfoProps {
tiralProInfo: Experiment;
}
class TrialInfo extends React.Component<TrialInfoProps, {}> {
constructor(props: TrialInfoProps) {
super(props);
}
render() {
const { tiralProInfo } = this.props;
const showProInfo = [];
showProInfo.push({
revision: tiralProInfo.revision,
authorName: tiralProInfo.author,
trialConcurrency: tiralProInfo.runConcurren,
tuner: tiralProInfo.tuner,
assessor: tiralProInfo.assessor ? tiralProInfo.assessor : undefined,
clusterMetaData: tiralProInfo.clusterMetaData ? tiralProInfo.clusterMetaData : undefined
});
return (
<div style={{ paddingLeft: 20 }}>
<pre>
{JSON.stringify(showProInfo[0], null, 4)}
</pre>
</div>
);
}
}
export default TrialInfo;
\ No newline at end of file
import * as React from 'react';
import axios from 'axios';
import { MANAGER_IP } from '../../static/const';
import ReactEcharts from 'echarts-for-react';
const echarts = require('echarts/lib/echarts');
require('echarts/lib/chart/bar');
require('echarts/lib/component/tooltip');
require('echarts/lib/component/title');
echarts.registerTheme('my_theme', {
color: '#3c8dbc'
});
interface Runtrial {
trialId: Array<string>;
trialTime: Array<number>;
}
interface DurationState {
durationSource: {};
}
class Duration extends React.Component<{}, DurationState> {
static intervalDuration = 1;
public _isMounted = false;
constructor(props: {}) {
super(props);
this.state = {
durationSource: {}
};
}
getOption = (dataObj: Runtrial) => {
let xAxis = dataObj.trialTime;
let yAxis = dataObj.trialId;
let option = {
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'shadow'
}
},
// title: {
// left: 'center',
// text: 'Trial Duration',
// textStyle: {
// fontSize: 18,
// color: '#333'
// }
// },
grid: {
bottom: '3%',
containLabel: true,
left: '1%',
right: '4%'
},
dataZoom: [{
type: 'slider',
name: 'trial',
filterMode: 'filter',
yAxisIndex: 0,
orient: 'vertical'
}, {
type: 'slider',
name: 'trial',
filterMode: 'filter',
xAxisIndex: 0
}],
xAxis: {
name: 'Time',
type: 'value',
},
yAxis: {
name: 'Trial',
type: 'category',
data: yAxis
},
series: [{
type: 'bar',
data: xAxis
}]
};
return option;
}
drawRunGraph = () => {
axios(`${MANAGER_IP}/trial-jobs`, {
method: 'GET'
})
.then(res => {
if (res.status === 200) {
const trialJobs = res.data;
const trialId: Array<string> = [];
const trialTime: Array<number> = [];
const trialRun: Array<Runtrial> = [];
Object.keys(trialJobs).map(item => {
if (trialJobs[item].status !== 'WAITING') {
let duration: number = 0;
const end = trialJobs[item].endTime;
const start = trialJobs[item].startTime;
if (start && end) {
duration = (end - start) / 1000;
} else {
duration = (new Date().getTime() - start) / 1000;
}
trialId.push(trialJobs[item].id);
trialTime.push(duration);
}
});
trialRun.push({
trialId: trialId,
trialTime: trialTime
});
if (this._isMounted && res.status === 200) {
this.setState({
durationSource: this.getOption(trialRun[0])
});
}
}
});
}
componentDidMount() {
this._isMounted = true;
this.drawRunGraph();
Duration.intervalDuration = window.setInterval(this.drawRunGraph, 10000);
}
componentWillUnmount() {
this._isMounted = false;
window.clearInterval(Duration.intervalDuration);
}
render() {
const { durationSource } = this.state;
return (
<div>
<ReactEcharts
option={durationSource}
style={{ width: '100%', height: 412, margin: '0 auto' }}
theme="my_theme"
/>
</div>
);
}
}
export default Duration;
\ No newline at end of file
import * as React from 'react';
import axios from 'axios';
import { MANAGER_IP } from '../const';
import { MANAGER_IP } from '../../static/const';
import ReactEcharts from 'echarts-for-react';
import { Select, Button, message } from 'antd';
import { Row, Col, Select, Button, message } from 'antd';
import { HoverName, ParaObj, VisualMapValue, Dimobj } from '../../static/interface';
const Option = Select.Option;
require('echarts/lib/chart/parallel');
require('echarts/lib/component/tooltip');
require('echarts/lib/component/title');
require('echarts/lib/component/visualMap');
require('../style/para.css');
interface Dimobj {
dim: number;
name: string;
max?: number;
min?: number;
type?: string;
data?: string[];
}
interface HoverName {
name: string;
}
interface ParaObj {
data: number[][];
parallelAxis: Array<Dimobj>;
}
interface VisualMapValue {
maxAccuracy: number;
minAccuracy: number;
}
require('../../static/style/para.scss');
require('../../static/style/button.scss');
interface ParaState {
option: object;
......@@ -50,7 +29,7 @@ message.config({
class Para extends React.Component<{}, ParaState> {
public intervalIDPara = 4;
static intervalIDPara = 4;
public _isMounted = false;
constructor(props: {}) {
......@@ -224,7 +203,7 @@ class Para extends React.Component<{}, ParaState> {
// get percent value number
percentNum = (value: string) => {
window.clearInterval(this.intervalIDPara);
window.clearInterval(Para.intervalIDPara);
let vals = parseFloat(value);
if (this._isMounted) {
this.setState(() => ({
......@@ -232,7 +211,7 @@ class Para extends React.Component<{}, ParaState> {
}));
}
this.hyperParaPic();
this.intervalIDPara = window.setInterval(this.hyperParaPic, 10000);
Para.intervalIDPara = window.setInterval(this.hyperParaPic, 10000);
}
// deal with response data into pic data
......@@ -321,13 +300,12 @@ class Para extends React.Component<{}, ParaState> {
swapBtn = () => {
window.clearInterval(this.intervalIDPara);
window.clearInterval(Para.intervalIDPara);
this.hyperParaPic();
this.intervalIDPara = window.setInterval(this.hyperParaPic, 10000);
Para.intervalIDPara = window.setInterval(this.hyperParaPic, 10000);
}
sortDimY = (a: Dimobj, b: Dimobj) => {
return a.dim - b.dim;
}
......@@ -389,33 +367,32 @@ class Para extends React.Component<{}, ParaState> {
this._isMounted = true;
// default draw all data pic
this.hyperParaPic();
this.intervalIDPara = window.setInterval(this.hyperParaPic, 10000);
Para.intervalIDPara = window.setInterval(this.hyperParaPic, 10000);
}
componentWillUnmount() {
this._isMounted = false;
window.clearInterval(this.intervalIDPara);
window.clearInterval(Para.intervalIDPara);
}
render() {
const { option, paraNodata, dimName } = this.state;
const chartMulineStyle = {
width: '100%',
height: 600,
height: 392,
margin: '0 auto',
padding: 15
padding: '0 15 10 15'
};
return (
<div className="para">
<div className="paraCon">
<div className="paraTitle">
<div className="paraLeft">Hyper Parameter</div>
<div className="paraRight">
<Row className="parameter">
<Row>
<Col span={6} />
<Col span={18}>
<Row className="meline">
<span>top</span>
<Select
className="parapercent"
style={{ width: '15%' }}
style={{ width: '20%', marginRight: 10 }}
placeholder="100%"
optionFilterProp="children"
onSelect={this.percentNum}
......@@ -426,7 +403,7 @@ class Para extends React.Component<{}, ParaState> {
<Option value="1">100%</Option>
</Select>
<Select
style={{ width: '50%' }}
style={{ width: '60%' }}
mode="multiple"
placeholder="Please select two items to swap"
onChange={this.getSwapArr}
......@@ -447,20 +424,19 @@ class Para extends React.Component<{}, ParaState> {
>
Confirm
</Button>
</div>
</div>
<div className="paraGra">
</Row>
</Col>
</Row>
<Row className="searcHyper">
<ReactEcharts
className="testt"
option={option}
style={chartMulineStyle}
// lazyUpdate={true}
notMerge={true} // update now
/>
<div className="paraNodata">{paraNodata}</div>
</div>
</div>
</div>
<div className="noneData">{paraNodata}</div>
</Row>
</Row>
);
}
}
......
body {
/* http://meyerweb.com/eric/tools/css/reset/
v4.0 | 20180602
License: none (public domain)
*/
html, body, div, span, applet, object, iframe,
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
a, abbr, acronym, address, big, cite, code,
del, dfn, em, img, ins, kbd, q, s, samp,
small, strike, strong, sub, sup, tt, var,
b, u, i, center,
dl, dt, dd, ol, ul, li,
fieldset, form, label, legend,
table, caption, tbody, tfoot, thead, tr, th, td,
article, aside, canvas, details, embed,
figure, figcaption, footer, header, hgroup,
main, menu, nav, output, ruby, section, summary,
time, mark, audio, video {
margin: 0;
padding: 0;
font-family: sans-serif;
border: 0;
font-size: 100%;
font: inherit;
}
/* HTML5 display-role reset for older browsers */
article, aside, details, figcaption, figure,
footer, header, hgroup, main, menu, nav, section {
display: block;
}
/* HTML5 hidden-attribute fix for newer browsers */
*[hidden] {
display: none;
}
body {
line-height: 1;
}
ol, ul {
list-style: none;
}
blockquote, q {
quotes: none;
}
blockquote:before, blockquote:after,
q:before, q:after {
content: '';
content: none;
}
table {
border-collapse: collapse;
border-spacing: 0;
}
pre{
overflow: hidden;
}
@font-face {
font-family: 'Segoe';
src: url('./static/font/SegoePro-Regular.ttf');
}
......@@ -4,24 +4,21 @@ import * as ReactDOM from 'react-dom';
import App from './App';
import { Router, Route, browserHistory, IndexRedirect } from 'react-router';
import registerServiceWorker from './registerServiceWorker';
import Accuracy from './components/Accuracy';
import Para from './components/Para';
import TrialStatus from './components/TrialStatus';
import Tensor from './components/Tensor';
import Control from './components/Control';
import Sessionpro from './components/Sessionpro';
import Overview from './components/Overview';
import TrialsDetail from './components/TrialsDetail';
// import TrialsDetail from './components/TrialsDetail';
import './index.css';
ReactDOM.render(
<Router history={browserHistory}>
<Route path="/" component={App}>
<IndexRedirect to="/oview" />
<Route path="/oview" component={Sessionpro} />
<Route path="/hyper" component={Para} />
<Route path="/trastaus" component={TrialStatus} />
<Route path="/oview" component={Overview} />
<Route path="/detail" component={TrialsDetail} />
<Route path="/tensor" component={Tensor} />
<Route path="/control" component={Control} />
<Route path="/all" component={Accuracy} />
</Route>
</Router>,
document.getElementById('root') as HTMLElement
......
......@@ -13,4 +13,4 @@ export const CONTROLTYPE = [
'TRIAL_CONCURRENCY',
'MAX_EXEC_DURATION'
];
export const overviewItem = 50;
export const overviewItem = 10;
import { AccurPoint } from './interface';
export const 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`;
}
};
// trial's duration, accurate to seconds for example 10min 30s
export const 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;
}
};
// ACCURACY point graph option format
export const getAccuracyData = (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
}]
};
};
\ 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