Commit 8e1e1c03 authored by Lijiao's avatar Lijiao Committed by fishyds
Browse files

[WebUI] Show version and support download logfile (#485)

* [WebUI]Show version and support download logfile

* Update download style
parent 9ff1f9d4
...@@ -9,19 +9,19 @@ ...@@ -9,19 +9,19 @@
left: 0; left: 0;
top: 0; top: 0;
width: 100%; width: 100%;
height: 80px; height: 56px;
background: #0071BC; background: #0071BC;
border-right: 1px solid #ccc; border-right: 1px solid #ccc;
z-index: 1000; z-index: 1000;
} }
.headerCon{ .headerCon{
min-width: 600px min-width: 1024px;
} }
.content{ .content{
width: 86%; width: 86%;
min-width: 1024px; min-width: 1024px;
margin: 0 auto; margin: 0 auto;
margin-top: 90px; margin-top: 74px;
margin-bottom: 30px; margin-bottom: 30px;
} }
......
...@@ -8,10 +8,11 @@ class App extends React.Component<{}, {}> { ...@@ -8,10 +8,11 @@ class App extends React.Component<{}, {}> {
return ( return (
<Row className="nni"> <Row className="nni">
<Row className="header"> <Row className="header">
<Col span={2} /> <Col span={1} />
<Col className="headerCon" span={22}> <Col className="headerCon" span={22}>
<SlideBar /> <SlideBar />
</Col> </Col>
<Col span={1}/>
</Row> </Row>
<Row className="content"> <Row className="content">
{this.props.children} {this.props.children}
......
import * as React from 'react'; import * as React from 'react';
import axios from 'axios'; import axios from 'axios';
import { Row, Col, Button } from 'antd'; import { Row, Col } from 'antd';
import { MANAGER_IP } from '../static/const'; import { MANAGER_IP } from '../static/const';
import { import {
Experiment, TableObj, Experiment, TableObj,
...@@ -30,10 +30,12 @@ interface OverviewState { ...@@ -30,10 +30,12 @@ interface OverviewState {
option: object; option: object;
noData: string; noData: string;
accuracyData: object; accuracyData: object;
bestAccuracy: string; bestAccuracy: number;
accNodata: string; accNodata: string;
trialNumber: TrialNumber; trialNumber: TrialNumber;
downBool: boolean; isTop10: boolean;
titleMaxbgcolor: string;
titleMinbgcolor?: string;
} }
class Overview extends React.Component<{}, OverviewState> { class Overview extends React.Component<{}, OverviewState> {
...@@ -76,7 +78,7 @@ class Overview extends React.Component<{}, OverviewState> { ...@@ -76,7 +78,7 @@ class Overview extends React.Component<{}, OverviewState> {
// accuracy // accuracy
accuracyData: {}, accuracyData: {},
accNodata: '', accNodata: '',
bestAccuracy: '', bestAccuracy: 0,
trialNumber: { trialNumber: {
succTrial: 0, succTrial: 0,
failTrial: 0, failTrial: 0,
...@@ -86,7 +88,8 @@ class Overview extends React.Component<{}, OverviewState> { ...@@ -86,7 +88,8 @@ class Overview extends React.Component<{}, OverviewState> {
unknowTrial: 0, unknowTrial: 0,
totalCurrentTrial: 0 totalCurrentTrial: 0
}, },
downBool: false isTop10: true,
titleMaxbgcolor: '#999'
}; };
} }
...@@ -244,18 +247,37 @@ class Overview extends React.Component<{}, OverviewState> { ...@@ -244,18 +247,37 @@ class Overview extends React.Component<{}, OverviewState> {
default: default:
} }
}); });
topTableData.sort((a: TableObj, b: TableObj) => { // choose top10 or lowest10
if (a.acc && b.acc) { const { isTop10 } = this.state;
return b.acc - a.acc; if (isTop10 === true) {
} else { topTableData.sort((a: TableObj, b: TableObj) => {
return NaN; if (a.acc && b.acc) {
} return b.acc - a.acc;
}); } else {
return NaN;
}
});
} else {
topTableData.sort((a: TableObj, b: TableObj) => {
if (a.acc && b.acc) {
return a.acc - b.acc;
} else {
return NaN;
}
});
}
topTableData.length = Math.min(10, topTableData.length); topTableData.length = Math.min(10, topTableData.length);
let bestDefaultMetric = 0;
if (topTableData[0] !== undefined) {
if (topTableData[0].acc !== undefined) {
bestDefaultMetric = topTableData[0].acc;
}
}
if (this._isMounted) { if (this._isMounted) {
this.setState({ this.setState({
tableData: topTableData, tableData: topTableData,
trialNumber: profile trialNumber: profile,
bestAccuracy: bestDefaultMetric
}); });
} }
this.checkStatus(); this.checkStatus();
...@@ -265,64 +287,6 @@ class Overview extends React.Component<{}, OverviewState> { ...@@ -265,64 +287,6 @@ class Overview extends React.Component<{}, OverviewState> {
}); });
} }
downExperimentContent = () => {
this.setState(() => ({
downBool: true
}));
axios
.all([
axios.get(`${MANAGER_IP}/experiment`),
axios.get(`${MANAGER_IP}/trial-jobs`),
axios.get(`${MANAGER_IP}/metric-data`)
])
.then(axios.spread((res, res1, res2) => {
if (res.status === 200 && res1.status === 200 && res2.status === 200) {
if (res.data.params.searchSpace) {
res.data.params.searchSpace = JSON.parse(res.data.params.searchSpace);
}
const isEdge = navigator.userAgent.indexOf('Edge') !== -1 ? true : false;
const interResultList = res2.data;
const contentOfExperiment = JSON.stringify(res.data, null, 2);
let trialMessagesArr = res1.data;
Object.keys(trialMessagesArr).map(item => {
// transform hyperparameters as object to show elegantly
trialMessagesArr[item].hyperParameters = JSON.parse(trialMessagesArr[item].hyperParameters);
const trialId = trialMessagesArr[item].id;
// add intermediate result message
trialMessagesArr[item].intermediate = [];
Object.keys(interResultList).map(key => {
const interId = interResultList[key].trialJobId;
if (trialId === interId) {
trialMessagesArr[item].intermediate.push(interResultList[key]);
}
});
});
const trialMessages = JSON.stringify(trialMessagesArr, null, 2);
const aTag = document.createElement('a');
const file = new Blob([contentOfExperiment, trialMessages], { type: 'application/json' });
aTag.download = 'experiment.json';
aTag.href = URL.createObjectURL(file);
aTag.click();
if (!isEdge) {
URL.revokeObjectURL(aTag.href);
}
if (navigator.userAgent.indexOf('Firefox') > -1) {
const downTag = document.createElement('a');
downTag.addEventListener('click', function () {
downTag.download = 'experiment.json';
downTag.href = URL.createObjectURL(file);
});
let eventMouse = document.createEvent('MouseEvents');
eventMouse.initEvent('click', false, false);
downTag.dispatchEvent(eventMouse);
}
this.setState(() => ({
downBool: false
}));
}
}));
}
// trial accuracy graph Default Metric // trial accuracy graph Default Metric
drawPointGraph = () => { drawPointGraph = () => {
...@@ -342,7 +306,6 @@ class Overview extends React.Component<{}, OverviewState> { ...@@ -342,7 +306,6 @@ class Overview extends React.Component<{}, OverviewState> {
accarr.push(items.acc); accarr.push(items.acc);
indexarr.push(items.sequenceId); indexarr.push(items.sequenceId);
}); });
const bestAccnum = Math.max(...accarr);
const accOption = { const accOption = {
tooltip: { tooltip: {
trigger: 'item' trigger: 'item'
...@@ -355,6 +318,7 @@ class Overview extends React.Component<{}, OverviewState> { ...@@ -355,6 +318,7 @@ class Overview extends React.Component<{}, OverviewState> {
yAxis: { yAxis: {
name: 'Default Metric', name: 'Default Metric',
type: 'value', type: 'value',
scale: true,
data: accarr data: accarr
}, },
series: [{ series: [{
...@@ -370,13 +334,25 @@ class Overview extends React.Component<{}, OverviewState> { ...@@ -370,13 +334,25 @@ class Overview extends React.Component<{}, OverviewState> {
}); });
} else { } else {
this.setState({ this.setState({
accNodata: '', accNodata: ''
bestAccuracy: bestAccnum.toFixed(6)
}); });
} }
}); });
} }
clickMaxTop = (event: React.SyntheticEvent<EventTarget>) => {
event.stopPropagation();
// #999 panel active bgcolor; #b3b3b3 as usual
this.setState(() => ({ isTop10: true, titleMaxbgcolor: '#999', titleMinbgcolor: '#b3b3b3' }));
this.showTrials();
}
clickMinTop = (event: React.SyntheticEvent<EventTarget>) => {
event.stopPropagation();
this.setState(() => ({ isTop10: false, titleMaxbgcolor: '#b3b3b3', titleMinbgcolor: '#999' }));
this.showTrials();
}
isOffInterval = () => { isOffInterval = () => {
const { status } = this.state; const { status } = this.state;
switch (status) { switch (status) {
...@@ -407,36 +383,16 @@ class Overview extends React.Component<{}, OverviewState> { ...@@ -407,36 +383,16 @@ class Overview extends React.Component<{}, OverviewState> {
render() { render() {
const { const {
trialProfile, trialProfile, searchSpace, tableData, accuracyData,
searchSpace, accNodata, status, errorStr, trialNumber, bestAccuracy,
tableData, titleMaxbgcolor, titleMinbgcolor
accuracyData,
accNodata,
status,
errorStr,
trialNumber,
bestAccuracy,
downBool
} = this.state; } = this.state;
return ( return (
<div className="overview"> <div className="overview">
{/* status and experiment block */} {/* status and experiment block */}
<Row> <Row>
<Row className="exbgcolor"> <Title1 text="Experiment" icon="11.png" />
<Col span={4}><Title1 text="Experiment" icon="11.png" /></Col>
<Col span={4}>
<Button
type="primary"
className="changeBtu download"
onClick={this.downExperimentContent}
disabled={downBool}
>
<span>Download</span>
<img src={require('../static/img/icon/download.png')} alt="icon" />
</Button>
</Col>
</Row>
<BasicInfo trialProfile={trialProfile} status={status} /> <BasicInfo trialProfile={trialProfile} status={status} />
</Row> </Row>
<Row className="overMessage"> <Row className="overMessage">
...@@ -472,8 +428,26 @@ class Overview extends React.Component<{}, OverviewState> { ...@@ -472,8 +428,26 @@ class Overview extends React.Component<{}, OverviewState> {
</Col> </Col>
</Row> </Row>
<Row className="overGraph"> <Row className="overGraph">
<Row className="top10bg">
<Col span={4} className="top10Title">
<Title1 text="Top10 Trials" icon="7.png" />
</Col>
<Col
span={2}
className="title"
onClick={this.clickMaxTop}
>
<Title1 text="Maximal" icon="max.png" bgcolor={titleMaxbgcolor} />
</Col>
<Col
span={2}
className="title minTitle"
onClick={this.clickMinTop}
>
<Title1 text="Minimal" icon="min.png" bgcolor={titleMinbgcolor} />
</Col>
</Row>
<Col span={8} className="overviewBoder"> <Col span={8} className="overviewBoder">
<Title1 text="Optimization Progress" icon="3.png" />
<Row className="accuracy"> <Row className="accuracy">
<Accuracy <Accuracy
accuracyData={accuracyData} accuracyData={accuracyData}
...@@ -483,7 +457,6 @@ class Overview extends React.Component<{}, OverviewState> { ...@@ -483,7 +457,6 @@ class Overview extends React.Component<{}, OverviewState> {
</Row> </Row>
</Col> </Col>
<Col span={16} id="succeTable"> <Col span={16} id="succeTable">
<Title1 text="Top10 Trials" icon="7.png" />
<SuccessTable tableSource={tableData} /> <SuccessTable tableSource={tableData} />
</Col> </Col>
</Row> </Row>
......
import * as React from 'react'; import * as React from 'react';
import { Link } from 'react-router'; import { Link } from 'react-router';
import axios from 'axios';
import { DOWNLOAD_IP } from '../static/const';
import { Row, Col, Menu, Dropdown, Icon } from 'antd';
import { MANAGER_IP } from '../static/const';
import '../static/style/slideBar.scss'; import '../static/style/slideBar.scss';
import '../static/style/button.scss';
class SlideBar extends React.Component<{}, {}> { interface SliderState {
version: string;
menuVisible: boolean;
}
interface EventPer {
key: string;
}
class SlideBar extends React.Component<{}, SliderState> {
public _isMounted = false;
constructor(props: {}) {
super(props);
this.state = {
version: '',
menuVisible: false
};
}
downExperimentContent = () => {
axios
.all([
axios.get(`${MANAGER_IP}/experiment`),
axios.get(`${MANAGER_IP}/trial-jobs`),
axios.get(`${MANAGER_IP}/metric-data`)
])
.then(axios.spread((res, res1, res2) => {
if (res.status === 200 && res1.status === 200 && res2.status === 200) {
if (res.data.params.searchSpace) {
res.data.params.searchSpace = JSON.parse(res.data.params.searchSpace);
}
const isEdge = navigator.userAgent.indexOf('Edge') !== -1 ? true : false;
const interResultList = res2.data;
const contentOfExperiment = JSON.stringify(res.data, null, 2);
let trialMessagesArr = res1.data;
Object.keys(trialMessagesArr).map(item => {
// transform hyperparameters as object to show elegantly
trialMessagesArr[item].hyperParameters = JSON.parse(trialMessagesArr[item].hyperParameters);
const trialId = trialMessagesArr[item].id;
// add intermediate result message
trialMessagesArr[item].intermediate = [];
Object.keys(interResultList).map(key => {
const interId = interResultList[key].trialJobId;
if (trialId === interId) {
trialMessagesArr[item].intermediate.push(interResultList[key]);
}
});
});
const trialMessages = JSON.stringify(trialMessagesArr, null, 2);
const aTag = document.createElement('a');
const file = new Blob([contentOfExperiment, trialMessages], { type: 'application/json' });
aTag.download = 'experiment.json';
aTag.href = URL.createObjectURL(file);
aTag.click();
if (!isEdge) {
URL.revokeObjectURL(aTag.href);
}
if (navigator.userAgent.indexOf('Firefox') > -1) {
const downTag = document.createElement('a');
downTag.addEventListener('click', function () {
downTag.download = 'experiment.json';
downTag.href = URL.createObjectURL(file);
});
let eventMouse = document.createEvent('MouseEvents');
eventMouse.initEvent('click', false, false);
downTag.dispatchEvent(eventMouse);
}
}
}));
}
downnnimanagerLog = () => {
axios(`${DOWNLOAD_IP}/nnimanager.log`, {
method: 'GET'
})
.then(res => {
if (res.status === 200) {
const nniLogfile = res.data;
const aTag = document.createElement('a');
const isEdge = navigator.userAgent.indexOf('Edge') !== -1 ? true : false;
const file = new Blob([nniLogfile], { type: 'application/json' });
aTag.download = 'nnimanagerLog.json';
aTag.href = URL.createObjectURL(file);
aTag.click();
if (!isEdge) {
URL.revokeObjectURL(aTag.href);
}
if (navigator.userAgent.indexOf('Firefox') > -1) {
const downTag = document.createElement('a');
downTag.addEventListener('click', function () {
downTag.download = 'nnimanagerLog.json';
downTag.href = URL.createObjectURL(file);
});
let eventMouse = document.createEvent('MouseEvents');
eventMouse.initEvent('click', false, false);
downTag.dispatchEvent(eventMouse);
}
}
});
}
downDispatcherlog = () => {
axios(`${DOWNLOAD_IP}/dispatcher.log`, {
method: 'GET'
})
.then(res => {
if (res.status === 200) {
const dispatchLogfile = res.data;
const aTag = document.createElement('a');
const isEdge = navigator.userAgent.indexOf('Edge') !== -1 ? true : false;
const file = new Blob([dispatchLogfile], { type: 'application/json' });
aTag.download = 'dispatcherLog.json';
aTag.href = URL.createObjectURL(file);
aTag.click();
if (!isEdge) {
URL.revokeObjectURL(aTag.href);
}
if (navigator.userAgent.indexOf('Firefox') > -1) {
const downTag = document.createElement('a');
downTag.addEventListener('click', function () {
downTag.download = 'dispatcherLog.json';
downTag.href = URL.createObjectURL(file);
});
let eventMouse = document.createEvent('MouseEvents');
eventMouse.initEvent('click', false, false);
downTag.dispatchEvent(eventMouse);
}
}
});
}
getNNIversion = () => {
axios(`${MANAGER_IP}/version`, {
method: 'GET'
})
.then(res => {
if (res.status === 200 && this._isMounted) {
this.setState({ version: res.data });
}
});
}
handleMenuClick = (e: EventPer) => {
if (this._isMounted) { this.setState({ menuVisible: false }); }
// download experiment related content
switch (e.key) {
case '1':
this.downExperimentContent();
break;
case '2':
this.downnnimanagerLog();
break;
case '3':
this.downDispatcherlog();
break;
default:
}
}
handleVisibleChange = (flag: boolean) => {
this.setState({ menuVisible: flag });
}
componentDidMount() {
this._isMounted = true;
this.getNNIversion();
}
componentWillUnmount() {
this._isMounted = false;
}
render() { render() {
const { version, menuVisible } = this.state;
const menu = (
<Menu onClick={this.handleMenuClick}>
<Menu.Item key="1">Experiment Parameters</Menu.Item>
<Menu.Item key="2">NNImanager Logfile</Menu.Item>
<Menu.Item key="3">Dispatcher Logfile</Menu.Item>
</Menu>
);
return ( return (
<ul className="nav"> <Row className="nav">
<li className="logo"> <Col span={8}>
<Link to={'/oview'}> <ul className="link">
<img src={require('../static/img/logo.png')} style={{ width: 156 }} alt="NNI logo" /> <li className="logo">
</Link> <Link to={'/oview'}>
</li> <img src={require('../static/img/logo2.png')} style={{ width: 88 }} alt="NNI logo" />
<li className="tab"> </Link>
<Link to={'/oview'} activeClassName="high"> </li>
Overview <li className="tab firstTab">
<Link to={'/oview'} activeClassName="high">
Overview
</Link> </Link>
</li> </li>
<li className="tab"> <li className="tab">
<Link to={'/detail'} activeClassName="high"> <Link to={'/detail'} activeClassName="high">
Trials Detail Trials Detail
</Link> </Link>
</li> </li>
</ul> </ul>
</Col>
<Col span={16} className="feedback">
<Dropdown
className="dropdown"
overlay={menu}
onVisibleChange={this.handleVisibleChange}
visible={menuVisible}
>
<a className="ant-dropdown-link" href="#">
Download <Icon type="down" />
</a>
</Dropdown>
<a href="https://github.com/Microsoft/nni/issues/new" target="_blank">
<img
src={require('../static/img/icon/issue.png')}
alt="NNI github issue"
/>
FeedBack
</a>
<span className="version">Version: {version}</span>
</Col>
</Row>
); );
} }
} }
......
...@@ -14,14 +14,10 @@ class BasicInfo extends React.Component<BasicInfoProps, {}> { ...@@ -14,14 +14,10 @@ class BasicInfo extends React.Component<BasicInfoProps, {}> {
constructor(props: BasicInfoProps) { constructor(props: BasicInfoProps) {
super(props); super(props);
} }
render() { render() {
const { trialProfile, const { trialProfile } = this.props;
// status
} = this.props;
return ( return (
<Row className="main"> <Row className="main">
<Col span={8} className="padItem basic"> <Col span={8} className="padItem basic">
......
...@@ -17,7 +17,7 @@ import '../../static/style/probar.scss'; ...@@ -17,7 +17,7 @@ import '../../static/style/probar.scss';
interface ProgressProps { interface ProgressProps {
trialProfile: Experiment; trialProfile: Experiment;
trialNumber: TrialNumber; trialNumber: TrialNumber;
bestAccuracy: string; bestAccuracy: number;
status: string; status: string;
errors: string; errors: string;
updateFile: Function; updateFile: Function;
...@@ -26,64 +26,67 @@ interface ProgressProps { ...@@ -26,64 +26,67 @@ interface ProgressProps {
interface ProgressState { interface ProgressState {
btnName: string; btnName: string;
isEnable: boolean; isEnable: boolean;
userInputVal?: string; // get user input userInputVal: string; // get user input
cancelSty: string; cancelSty: string;
} }
class Progressed extends React.Component<ProgressProps, ProgressState> { class Progressed extends React.Component<ProgressProps, ProgressState> {
public conInput: HTMLInputElement | null; public conInput: HTMLInputElement | null;
public _isMounted = false;
constructor(props: ProgressProps) { constructor(props: ProgressProps) {
super(props); super(props);
this.state = { this.state = {
btnName: 'Edit', btnName: 'Edit',
isEnable: true, isEnable: true,
userInputVal: this.props.trialProfile.runConcurren.toString(),
cancelSty: 'none' cancelSty: 'none'
}; };
} }
editTrialConcurrency = () => { editTrialConcurrency = () => {
const { btnName } = this.state; const { btnName } = this.state;
if (btnName === 'Edit') { if (this._isMounted) {
this.setState(() => ({ if (btnName === 'Edit') {
isEnable: false, this.setState(() => ({
btnName: 'Save', isEnable: false,
cancelSty: 'inline-block' btnName: 'Save',
})); cancelSty: 'inline-block'
} else { }));
axios(`${MANAGER_IP}/experiment`, { } else {
method: 'GET' axios(`${MANAGER_IP}/experiment`, {
}) method: 'GET'
.then(rese => { })
if (rese.status === 200) { .then(rese => {
const { userInputVal } = this.state; if (rese.status === 200) {
const experimentFile = rese.data; const { userInputVal } = this.state;
const trialConcurrency = experimentFile.params.trialConcurrency; const experimentFile = rese.data;
if (userInputVal !== undefined) { const trialConcurrency = experimentFile.params.trialConcurrency;
if (userInputVal === trialConcurrency.toString() || userInputVal === '') { if (userInputVal !== undefined) {
message.info( if (userInputVal === trialConcurrency.toString() || userInputVal === '0') {
`trialConcurrency's value is ${trialConcurrency}, you did not modify it`, 2); message.info(
} else { `trialConcurrency's value is ${trialConcurrency}, you did not modify it`, 2);
experimentFile.params.trialConcurrency = parseInt(userInputVal, 10); } else {
// rest api, modify trial concurrency value experimentFile.params.trialConcurrency = parseInt(userInputVal, 10);
axios(`${MANAGER_IP}/experiment`, { // rest api, modify trial concurrency value
method: 'PUT', axios(`${MANAGER_IP}/experiment`, {
headers: { method: 'PUT',
'Content-Type': 'application/json;charset=utf-8' headers: {
}, 'Content-Type': 'application/json;charset=utf-8'
data: experimentFile, },
params: { data: experimentFile,
update_type: CONTROLTYPE[1] params: {
} update_type: CONTROLTYPE[1]
}).then(res => { }
if (res.status === 200) { }).then(res => {
message.success(`Update ${CONTROLTYPE[1].toLocaleLowerCase()} successfully`); if (res.status === 200) {
// rerender trial profile message message.success(`Update ${CONTROLTYPE[1].toLocaleLowerCase()}
const { updateFile } = this.props; successfully`);
updateFile(); // rerender trial profile message
} const { updateFile } = this.props;
}) updateFile();
}
})
.catch(error => { .catch(error => {
if (error.response.status === 500) { if (error.response.status === 500) {
if (error.response.data.error) { if (error.response.data.error) {
...@@ -93,27 +96,30 @@ class Progressed extends React.Component<ProgressProps, ProgressState> { ...@@ -93,27 +96,30 @@ class Progressed extends React.Component<ProgressProps, ProgressState> {
} }
} }
}); });
// btn -> edit // btn -> edit
this.setState(() => ({ this.setState(() => ({
btnName: 'Edit', btnName: 'Edit',
isEnable: true, isEnable: true,
cancelSty: 'none' cancelSty: 'none'
})); }));
}
} }
} }
} });
}); }
} }
} }
cancelFunction = () => { cancelFunction = () => {
const { trialProfile } = this.props; const { trialProfile } = this.props;
this.setState( if (this._isMounted) {
() => ({ this.setState(
btnName: 'Edit', () => ({
isEnable: true, btnName: 'Edit',
cancelSty: 'none', isEnable: true,
})); cancelSty: 'none',
}));
}
if (this.conInput !== null) { if (this.conInput !== null) {
this.conInput.value = trialProfile.runConcurren.toString(); this.conInput.value = trialProfile.runConcurren.toString();
} }
...@@ -141,6 +147,14 @@ class Progressed extends React.Component<ProgressProps, ProgressState> { ...@@ -141,6 +147,14 @@ class Progressed extends React.Component<ProgressProps, ProgressState> {
} }
} }
componentDidMount() {
this._isMounted = true;
}
componentWillUnmount() {
this._isMounted = false;
}
render() { render() {
const { trialProfile, trialNumber, bestAccuracy, status, errors } = this.props; const { trialProfile, trialNumber, bestAccuracy, status, errors } = this.props;
const { isEnable, btnName, cancelSty } = this.state; const { isEnable, btnName, cancelSty } = this.state;
...@@ -164,51 +178,54 @@ class Progressed extends React.Component<ProgressProps, ProgressState> { ...@@ -164,51 +178,54 @@ class Progressed extends React.Component<ProgressProps, ProgressState> {
} }
return ( return (
<Row className="progress" id="barBack"> <Row className="progress" id="barBack">
<Row className="basic"> <Row className="basic lineBasic">
<p>Status</p> <Col span={12}>
<div className="status"> <p>Status</p>
<span className={status}>{status}</span> <div className="status">
{ <span className={status}>{status}</span>
status === 'ERROR' {
? status === 'ERROR'
<Popover ?
placement="rightTop" <Popover
content={errorContent} placement="rightTop"
title="Error" content={errorContent}
trigger="hover" title="Error"
> trigger="hover"
<span className="errorBtn">i</span> >
</Popover> <span className="errorBtn">i</span>
: </Popover>
<span /> :
} <span />
}
</div> </div>
</Row> </Col>
{/* modify concurrency */} <Col span={12}>
<Row className="inputBox"> {/* modify concurrency */}
<span className="title">Concurrency:</span> <p>Concurrency</p>
<input <Row className="inputBox">
type="number" <input
disabled={isEnable} type="number"
onChange={this.getUserTrialConcurrency} disabled={isEnable}
className="concurrencyInput" onChange={this.getUserTrialConcurrency}
ref={(input) => this.conInput = input} className="concurrencyInput"
/> ref={(input) => this.conInput = input}
<Button />
type="primary" <Button
className="tableButton editStyle" type="primary"
onClick={this.editTrialConcurrency} className="tableButton editStyle"
>{btnName} onClick={this.editTrialConcurrency}
</Button> >{btnName}
<Button </Button>
type="primary" <Button
onClick={this.cancelFunction} type="primary"
style={{ display: cancelSty, marginLeft: 1 }} onClick={this.cancelFunction}
className="tableButton editStyle" style={{ display: cancelSty, marginLeft: 1 }}
> className="tableButton editStyle"
Cancel >
</Button> Cancel
</Button>
</Row>
</Col>
</Row> </Row>
<ProgressBar <ProgressBar
who="Duration" who="Duration"
......
...@@ -19,7 +19,7 @@ class SearchSpace extends React.Component<SearchspaceProps, {}> { ...@@ -19,7 +19,7 @@ class SearchSpace extends React.Component<SearchspaceProps, {}> {
<div className="searchSpace"> <div className="searchSpace">
<MonacoEditor <MonacoEditor
width="100%" width="100%"
height="398" height="380"
language="json" language="json"
theme="vs-light" theme="vs-light"
value={JSON.stringify(searchSpace, null, 2)} value={JSON.stringify(searchSpace, null, 2)}
......
...@@ -3,6 +3,7 @@ import * as React from 'react'; ...@@ -3,6 +3,7 @@ import * as React from 'react';
interface Title1Props { interface Title1Props {
text: string; text: string;
icon: string; icon: string;
bgcolor?: string;
} }
class Title1 extends React.Component<Title1Props, {}> { class Title1 extends React.Component<Title1Props, {}> {
...@@ -12,10 +13,10 @@ class Title1 extends React.Component<Title1Props, {}> { ...@@ -12,10 +13,10 @@ class Title1 extends React.Component<Title1Props, {}> {
} }
render() { render() {
const { text, icon } = this.props; const { text, icon, bgcolor } = this.props;
return ( return (
<div> <div>
<div className="panelTitle"> <div className="panelTitle" style={{backgroundColor: bgcolor}}>
<img src={require(`../../static/img/icon/${icon}`)} alt="icon" /> <img src={require(`../../static/img/icon/${icon}`)} alt="icon" />
<span>{text}</span> <span>{text}</span>
</div> </div>
......
...@@ -29,7 +29,7 @@ class TrialInfo extends React.Component<TrialInfoProps, {}> { ...@@ -29,7 +29,7 @@ class TrialInfo extends React.Component<TrialInfoProps, {}> {
<div className="profile"> <div className="profile">
<MonacoEditor <MonacoEditor
width="100%" width="100%"
height="396" height="380"
language="json" language="json"
theme="vs-light" theme="vs-light"
value={JSON.stringify(showProInfo[0], null, 2)} value={JSON.stringify(showProInfo[0], null, 2)}
......
export const MANAGER_IP = `/api/v1/nni`; export const MANAGER_IP = `/api/v1/nni`;
export const DOWNLOAD_IP = `/logs`;
export const trialJobStatus = [ export const trialJobStatus = [
'UNKNOWN', 'UNKNOWN',
'WAITING', 'WAITING',
......
/* new style */ /* new style */
.overMessage{ .overMessage{
height: 456px; height: 430px;
} }
.overGraph{ .overGraph{
height: 362px; height: 362px;
...@@ -27,7 +27,6 @@ ...@@ -27,7 +27,6 @@
} }
.searchSpace{ .searchSpace{
height: 386px;
line-height: 22px; line-height: 22px;
font-size: 14px; font-size: 14px;
padding: 15px 0; padding: 15px 0;
...@@ -50,28 +49,3 @@ ...@@ -50,28 +49,3 @@
} }
} }
.exbgcolor {
background: #b3b3b3;
.download{
height: 30px;
border: 1px solid #fff;
border-radius: 0;
margin-top: 4px;
background-color: #0071BC;
span{
font-family: 'Segoe';
font-size: 14px;
}
img{
height: 14px;
margin-left: 10px;
margin-top: -6px;
}
}
}
.exbgcolor .download:hover{
border: 1px solid #fff;
}
\ No newline at end of file
$titleBgcolor: #b3b3b3;
.overview .overviewBoder{ .overview .overviewBoder{
height: 100%; height: 100%;
border-right: 2px solid white; border-right: 2px solid white;
} }
.panelTitle{ .panelTitle{
display: block;
width: 100%; width: 100%;
height: 38px; height: 38px;
background: #b3b3b3; background: $titleBgcolor;
img{ img{
height: 22px; height: 22px;
...@@ -23,4 +23,26 @@ ...@@ -23,4 +23,26 @@
color: #333; color: #333;
line-height: 38px; line-height: 38px;
} }
} }
\ No newline at end of file
.top10bg{
background-color: $titleBgcolor;
.top10Title{
width: 160px;
}
.title{
width: 135px;
border-left: 2px solid #fff;
}
.minTitle{
border-right: 2px solid #fff;
}
.title:hover{
cursor: pointer;
}
}
#barBack{ #barBack{
/* status: 'INITIALIZED' | 'EXPERIMENT_RUNNING' | 'ERROR' | 'STOPPING' | 'STOPPED' | 'DONE' */ /* status: 'INITIALIZED' | 'RUNNING' | 'ERROR' | 'STOPPING' | 'STOPPED' | 'DONE' */
.EXPERIMENT_RUNNING, .STOPPING, .INITIALIZED{ .RUNNING, .STOPPING, .INITIALIZED{
/* specific status color */ /* specific status color */
color: #0071bc; color: #0071bc;
.ant-progress-bg { .ant-progress-bg {
......
.progress{ .progress{
margin: 15px 20px; margin: 15px 17px;
.status{ .status{
color: #0573bc; color: #0573bc;
font-size: 20px; font-size: 20px;
font-weight: bold; font-weight: bold;
margin-top: 5px;
} }
.probar{ .probar{
...@@ -71,24 +72,21 @@ ...@@ -71,24 +72,21 @@
} }
*/ */
.inputBox{ .inputBox{
height: 30px; height: 26px;
margin-top: 8px;
border-bottom: 1px solid #ccc;
padding-bottom: 44px;
.title{
font-size: 14px;
margin-right: 10px;
}
.concurrencyInput{ .concurrencyInput{
width: 25%; width: 25%;
height: 32px; height: 26px;
padding-left: 8px;
outline: none; outline: none;
border: 1px solid #ccc; border: 1px solid #ccc;
} }
.editStyle{ .editStyle{
height: 32px; height: 26px;
padding: 0 9px;
} }
} }
.lineBasic{
padding-bottom: 14px;
border-bottom: 1px solid #ccc;
}
$barHeight: 56px;
.nav{ .nav{
list-style: none; list-style: none;
width: 100%; width: 94%;
height: 80px; height: $barHeight;
li{ margin: 0 auto;
float: left; .tab{
margin-right: 40px;
font-family: 'Segoe'; font-family: 'Segoe';
line-height: $barHeight;
a{ a{
display: block;
padding: 0 10px;
font-size: 18px; font-size: 18px;
color: #b8c7ce; color: #b8c7ce;
text-decoration: none; text-decoration: none;
} }
} }
.firstTab{
margin: 0 32px;
}
.logo{ .logo{
height: 80px; margin-top: 2px;
line-height: 80px; max-width: 128px;
} }
.tab{ }
position: relative;
top: 36px;
line-height: 30px;
.tab a:hover, .tab a.high{
color: white;
border-bottom: 1px solid #fff;
}
.feedback{
text-align: right;
line-height: $barHeight;
font-size: 16px;
color: #fff;
a{
color: #fff;
text-decoration: none;
margin-left: 10px;
}
img{
width: 24px;
margin-right: 8px;
} }
.last{ .version{
margin-right: 0; margin-left: 16px;
} }
} }
.nav li a:hover, .nav a.high{ .link li{
color: white; float: left;
border-bottom: 1px solid white; }
.dropdown{
margin-right: 10px;
} }
\ 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