Unverified Commit f322548f authored by chicm-ms's avatar chicm-ms Committed by GitHub
Browse files

Merge pull request #30 from microsoft/master

pull code
parents cb361b34 797f0e2c
......@@ -17,11 +17,13 @@
NNI (Neural Network Intelligence) is a toolkit to help users run automated machine learning (AutoML) experiments.
The tool dispatches and runs trial jobs generated by tuning algorithms to search the best neural architecture and/or hyper-parameters in different environments like local machine, remote servers and cloud.
### **NNI [v0.9](https://github.com/Microsoft/nni/releases) has been released! &nbsp;<a href="#nni-released-reminder"><img width="48" src="docs/img/release_icon.png"></a>**
<p align="center">
<a href="#nni-has-been-released"><img src="docs/img/overview.svg" /></a>
</p>
<div>
<table>
<tbody>
<tr align="center" valign="bottom">
......@@ -56,27 +58,27 @@ The tool dispatches and runs trial jobs generated by tuning algorithms to search
<a href="docs/en_US/Tuner/BuiltinTuner.md">Tuner</a>
<br />
<ul>
<b style="margin-left:-20px"><font size=4 color=#800000>General Tuner</font></b>
<li><a href="docs/en_US/Tuner/BuiltinTuner.md#Random"><font size=2.9>Random Search</font></a></li>
<li><a href="docs/en_US/Tuner/BuiltinTuner.md#Evolution"><font size=2.9>Naïve Evolution</font></a></li>
<b><font size=4 color=#800000 style="margin-left:-20px">Tuner for HPO</font></b>
<li><a href="docs/en_US/Tuner/BuiltinTuner.md#TPE"><font size=2.9>TPE</font></a></li>
<li><a href="docs/en_US/Tuner/BuiltinTuner.md#Anneal"><font size=2.9>Anneal</font></a></li>
<li><a href="docs/en_US/Tuner/BuiltinTuner.md#SMAC"><font size=2.9>SMAC</font></a></li>
<li><a href="docs/en_US/Tuner/BuiltinTuner.md#Batch"><font size=2.9>Batch</font></a></li>
<li><a href="docs/en_US/Tuner/BuiltinTuner.md#GridSearch"><font size=2.9>Grid Search</font></a></li>
<li><a href="docs/en_US/Tuner/BuiltinTuner.md#Hyperband"><font size=2.9>Hyperband</font></a></li>
<li><a href="docs/en_US/Tuner/BuiltinTuner.md#MetisTuner"><font size=2.9>Metis Tuner</font></a></li>
<li><a href="docs/en_US/Tuner/BuiltinTuner.md#BOHB"><font size=2.9>BOHB</font></a></li>
<li><a href="docs/en_US/Tuner/BuiltinTuner.md#GPTuner"><font size=2.9>GP Tuner</font></a></li>
<b style="margin-left:-20px"><font size=4 color=#800000 style="margin-left:-20px">Tuner for NAS</font></b>
<li><a href="docs/en_US/Tuner/BuiltinTuner.md#NetworkMorphism"><font size=2.9>Network Morphism</font></a></li>
<li><a href="examples/tuners/enas_nni/README.md"><font size=2.9>ENAS</font></a></li>
<b style="margin-left:-20px">General Tuner</b>
<li><a href="docs/en_US/Tuner/BuiltinTuner.md#Random">Random Search</a></li>
<li><a href="docs/en_US/Tuner/BuiltinTuner.md#Evolution">Naïve Evolution</a></li>
<b style="margin-left:-20px">Tuner for HPO</b>
<li><a href="docs/en_US/Tuner/BuiltinTuner.md#TPE">TPE</a></li>
<li><a href="docs/en_US/Tuner/BuiltinTuner.md#Anneal">Anneal</a></li>
<li><a href="docs/en_US/Tuner/BuiltinTuner.md#SMAC">SMAC</a></li>
<li><a href="docs/en_US/Tuner/BuiltinTuner.md#Batch">Batch</a></li>
<li><a href="docs/en_US/Tuner/BuiltinTuner.md#GridSearch">Grid Search</a></li>
<li><a href="docs/en_US/Tuner/BuiltinTuner.md#Hyperband">Hyperband</a></li>
<li><a href="docs/en_US/Tuner/BuiltinTuner.md#MetisTuner">Metis Tuner</a></li>
<li><a href="docs/en_US/Tuner/BuiltinTuner.md#BOHB">BOHB</a></li>
<li><a href="docs/en_US/Tuner/BuiltinTuner.md#GPTuner">GP Tuner</a></li>
<b style="margin-left:-20px">Tuner for NAS</b>
<li><a href="docs/en_US/Tuner/BuiltinTuner.md#NetworkMorphism">Network Morphism</a></li>
<li><a href="examples/tuners/enas_nni/README.md">ENAS</a></li>
</ul>
<a href="docs/en_US/Assessor/BuiltinAssessor.md">Assessor</a>
<ul>
<li><a href="docs/en_US/Assessor/BuiltinAssessor.md#Medianstop"><font size=2.9>Median Stop</font></a></li>
<li><a href="docs/en_US/Assessor/BuiltinAssessor.md#Curvefitting"><font size=2.9>Curve Fitting</font></a></li>
<li><a href="docs/en_US/Assessor/BuiltinAssessor.md#Medianstop">Median Stop</a></li>
<li><a href="docs/en_US/Assessor/BuiltinAssessor.md#Curvefitting">Curve Fitting</a></li>
</ul>
</td>
<td>
......@@ -91,52 +93,10 @@ The tool dispatches and runs trial jobs generated by tuning algorithms to search
</ul>
</td>
</tr>
<tr align="center" valign="bottom">
<td style="border-top:#FF0000 solid 0px;">
<b>References</b>
<img src="docs/img/bar.png"/>
</td>
<td style="border-top:#FF0000 solid 0px;">
<b>References</b>
<img src="docs/img/bar.png"/>
</td>
<td style="border-top:#FF0000 solid 0px;">
<b>References</b>
<img src="docs/img/bar.png"/>
</td>
</tr>
<tr valign="top">
<td style="border-top:#FF0000 solid 0px;">
<ul>
<li><a href="docs/en_US/sdk_reference.rst">Python API</a></li>
<li><a href="docs/en_US/Tutorial/AnnotationSpec.md">NNI Annotation</a></li>
<li><a href="docs/en_US/TrialExample/Trials.md#nni-python-annotation">Annotation tutorial</a></li>
</ul>
</td>
<td style="border-top:#FF0000 solid 0px;">
<ul>
<li><a href="docs/en_US/tuners.rst">Try different tuners</a></li>
<li><a href="docs/en_US/assessors.rst">Try different assessors</a></li>
<li><a href="docs/en_US/Tuner/CustomizeTuner.md">Implement a customized tuner</a></li>
<li><a href="docs/en_US/Tuner/CustomizeAdvisor.md">Implement a customized advisor</a></li>
<li><a href="docs/en_US/Assessor/CustomizeAssessor.md">Implement a customized assessor </a></li>
<li><a href="docs/en_US/CommunitySharings/HpoComparision.md">HPO Comparison</a></li>
<li><a href="docs/en_US/CommunitySharings/NasComparision.md">NAS Comparison</a></li>
<li><a href="docs/en_US/CommunitySharings/RecommendersSvd.md">Automatically tuning SVD on NNI</a></li>
</ul>
</td>
<td style="border-top:#FF0000 solid 0px;">
<ul>
<li><a href="docs/en_US/TrainingService/HowToImplementTrainingService.md">Implement TrainingService in NNI</a></li>
<li><a href="docs/en_US/TrainingService/LocalMode.md">Run an experiment on local</a></li>
<li><a href="docs/en_US/TrainingService/KubeflowMode.md">Run an experiment on Kubeflow</a></li>
<li><a href="docs/en_US/TrainingService/PaiMode.md">Run an experiment on OpenPAI?</a></li>
<li><a href="docs/en_US/TrainingService/RemoteMachineMode.md">Run an experiment on multiple machines?</a></li>
</ul>
</td>
</tbody>
</table>
</div>
## **Who should consider using NNI**
......@@ -291,17 +251,18 @@ Maybe you want to read:
* [Config an experiment](docs/en_US/Tutorial/ExperimentConfig.md)
* [How to use annotation](docs/en_US/TrialExample/Trials.md#nni-python-annotation)
## **Tutorials**
* [Run an experiment on OpenPAI?](docs/en_US/PaiMode.md)
* [Run an experiment on Kubeflow?](docs/en_US/KubeflowMode.md)
* [Run an experiment on local (with multiple GPUs)?](docs/en_US/LocalMode.md)
* [Run an experiment on multiple machines?](docs/en_US/RemoteMachineMode.md)
* [Try different tuners](docs/en_US/tuners.rst)
* [Try different assessors](docs/en_US/assessors.rst)
* [Run an experiment on OpenPAI](docs/en_US/TrainingService/PaiMode.md)
* [Run an experiment on Kubeflow](docs/en_US/TrainingService/KubeflowMode.md)
* [Run an experiment on local (with multiple GPUs)](docs/en_US/TrainingService/LocalMode.md)
* [Run an experiment on multiple machines](docs/en_US/TrainingService/RemoteMachineMode.md)
* [Try different tuners](docs/en_US/Tuner/BuiltinTuner.md)
* [Try different assessors](docs/en_US/Assessor/BuiltinAssessor.md)
* [Implement a customized tuner](docs/en_US/Tuner/CustomizeTuner.md)
* [Implement a customized assessor](docs/en_US/CustomizeAssessor.md)
* [Use Genetic Algorithm to find good model architectures for Reading Comprehension task](examples/trials/ga_squad/README.md)
* [Implement a customized assessor](docs/en_US/Assessor/CustomizeAssessor.md)
* [Use Genetic Algorithm to find good model architectures for Reading Comprehension task](docs/en_US/TrialExample/SquadEvolutionExamples.md)
## **Contribute**
This project welcomes contributions and there are many ways in which you can participate in the project, for example:
......
configspace @ f389e1d0
Subproject commit f389e1d0a72564f7f1fd4d86039e5f393a45a058
This file is placed here by pip to indicate the source was put
here by pip.
Once this package is successfully installed this source code will be
deleted (unless you remove this file).
ConfigSpace==0.4.7
statsmodels==0.9.0
\ No newline at end of file
statsmodels==0.10.0
\ No newline at end of file
.nni{
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
color: #212121;
font-size: 14px;
background: #f2f2f2;
......
import * as React from 'react';
import axios from 'axios';
import { downFile } from '../../static/function';
import { Drawer, Tabs, Row, Col, Button } from 'antd';
import { MANAGER_IP, DRAWEROPTION } from '../../static/const';
import MonacoEditor from 'react-monaco-editor';
const { TabPane } = Tabs;
import '../../static/style/logDrawer.scss';
interface ExpDrawerProps {
isVisble: boolean;
closeExpDrawer: () => void;
}
interface ExpDrawerState {
experiment: string;
}
class ExperimentDrawer extends React.Component<ExpDrawerProps, ExpDrawerState> {
public _isCompareMount: boolean;
constructor(props: ExpDrawerProps) {
super(props);
this.state = {
experiment: ''
};
}
getExperimentContent = () => {
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);
}
let trialMessagesArr = res1.data;
const interResultList = res2.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 result = {
experimentParameters: res.data,
trialMessage: trialMessagesArr
};
if (this._isCompareMount === true) {
this.setState(() => ({ experiment: JSON.stringify(result, null, 4) }));
}
}
}));
}
downExperimentParameters = () => {
const { experiment } = this.state;
downFile(experiment, 'experiment.json');
}
componentDidMount() {
this._isCompareMount = true;
this.getExperimentContent();
}
componentWillReceiveProps(nextProps: ExpDrawerProps) {
const { isVisble } = nextProps;
if (isVisble === true) {
this.getExperimentContent();
}
}
componentWillUnmount() {
this._isCompareMount = false;
}
render() {
const { isVisble, closeExpDrawer } = this.props;
const { experiment } = this.state;
const heights: number = window.innerHeight - 48;
return (
<Row className="logDrawer">
<Drawer
// title="Log Message"
placement="right"
closable={false}
destroyOnClose={true}
onClose={closeExpDrawer}
visible={isVisble}
width="54%"
height={heights}
>
<div className="card-container log-tab-body" style={{ height: heights }}>
<Tabs type="card">
<TabPane tab="Experiment Parameters" key="Experiment">
<div className="just-for-log">
<MonacoEditor
width="100%"
height={heights * 0.9}
language="json"
value={experiment}
options={DRAWEROPTION}
/>
</div>
<Row className="buttons">
<Col span={12}>
<Button
type="primary"
onClick={this.downExperimentParameters}
>
Download
</Button>
</Col>
<Col span={12} className="close">
<Button
type="default"
onClick={closeExpDrawer}
>
Close
</Button>
</Col>
</Row>
</TabPane>
</Tabs>
</div>
</Drawer>
</Row>
);
}
}
export default ExperimentDrawer;
import * as React from 'react';
import axios from 'axios';
import { Drawer, Tabs, Row, Col, Button, Icon } from 'antd';
import { DOWNLOAD_IP } from '../../static/const';
import { downFile } from '../../static/function';
const { TabPane } = Tabs;
import MonacoHTML from '../public-child/MonacoEditor';
import '../../static/style/logDrawer.scss';
interface LogDrawerProps {
isVisble: boolean;
closeDrawer: () => void;
activeTab?: string;
}
interface LogDrawerState {
nniManagerLogStr: string;
dispatcherLogStr: string;
isLoading: boolean;
isLoadispatcher: boolean;
}
class LogDrawer extends React.Component<LogDrawerProps, LogDrawerState> {
public _isLogDrawer: boolean;
constructor(props: LogDrawerProps) {
super(props);
this.state = {
nniManagerLogStr: 'nnimanager',
dispatcherLogStr: 'dispatcher',
isLoading: false,
isLoadispatcher: false
};
}
getNNImanagerLogmessage = () => {
if (this._isLogDrawer === true) {
this.setState({ isLoading: true }, () => {
axios(`${DOWNLOAD_IP}/nnimanager.log`, {
method: 'GET'
})
.then(res => {
if (res.status === 200) {
setTimeout(() => { this.setNNImanager(res.data); }, 300);
}
});
});
}
}
setDispatcher = (value: string) => {
if (this._isLogDrawer === true) {
this.setState(() => ({ isLoadispatcher: false, dispatcherLogStr: value }));
}
}
setNNImanager = (val: string) => {
if (this._isLogDrawer === true) {
this.setState(() => ({ isLoading: false, nniManagerLogStr: val }));
}
}
getdispatcherLogmessage = () => {
if (this._isLogDrawer === true) {
this.setState({ isLoadispatcher: true }, () => {
axios(`${DOWNLOAD_IP}/dispatcher.log`, {
method: 'GET'
})
.then(res => {
if (res.status === 200) {
setTimeout(() => { this.setDispatcher(res.data); }, 300);
}
});
});
}
}
downloadNNImanager = () => {
const { nniManagerLogStr } = this.state;
downFile(nniManagerLogStr, 'nnimanager.log');
}
downloadDispatcher = () => {
const { dispatcherLogStr } = this.state;
downFile(dispatcherLogStr, 'dispatcher.log');
}
dispatcherHTML = () => {
return (
<div>
<span>Dispatcher Log</span>
<span className="refresh" onClick={this.getdispatcherLogmessage}>
<Icon type="sync" />
</span>
</div>
);
}
nnimanagerHTML = () => {
return (
<div>
<span>NNImanager Log</span>
<span className="refresh" onClick={this.getNNImanagerLogmessage}><Icon type="sync" /></span>
</div>
);
}
componentDidMount() {
this._isLogDrawer = true;
this.getNNImanagerLogmessage();
this.getdispatcherLogmessage();
}
componentWillReceiveProps(nextProps: LogDrawerProps) {
const { isVisble, activeTab } = nextProps;
if (isVisble === true) {
if (activeTab === 'nnimanager') {
this.getNNImanagerLogmessage();
}
if (activeTab === 'dispatcher') {
this.getdispatcherLogmessage();
}
}
}
componentWillUnmount() {
this._isLogDrawer = false;
}
render() {
const { isVisble, closeDrawer, activeTab } = this.props;
const { nniManagerLogStr, dispatcherLogStr, isLoadispatcher, isLoading } = this.state;
const heights: number = window.innerHeight - 48; // padding top and bottom
return (
<Row>
<Drawer
placement="right"
closable={false}
destroyOnClose={true}
onClose={closeDrawer}
visible={isVisble}
width="76%"
height={heights}
// className="logDrawer"
>
<div className="card-container log-tab-body" style={{ height: heights }}>
<Tabs type="card" defaultActiveKey={activeTab}>
{/* <Tabs type="card" onTabClick={this.selectwhichLog} defaultActiveKey={activeTab}> */}
{/* <TabPane tab="Dispatcher Log" key="dispatcher"> */}
<TabPane tab={this.dispatcherHTML()} key="dispatcher">
<div>
<MonacoHTML content={dispatcherLogStr} loading={isLoadispatcher} />
</div>
<Row className="buttons">
<Col span={12}>
<Button
type="primary"
onClick={this.downloadDispatcher}
>
Download
</Button>
</Col>
<Col span={12} className="close">
<Button
type="default"
onClick={closeDrawer}
>
Close
</Button>
</Col>
</Row>
</TabPane>
<TabPane tab={this.nnimanagerHTML()} key="nnimanager">
{/* <TabPane tab="NNImanager Log" key="nnimanager"> */}
<div>
<MonacoHTML content={nniManagerLogStr} loading={isLoading} />
</div>
<Row className="buttons">
<Col span={12} className="download">
<Button
type="primary"
onClick={this.downloadNNImanager}
>
Download
</Button>
</Col>
<Col span={12} className="close">
<Button
type="default"
onClick={closeDrawer}
>
Close
</Button>
</Col>
</Row>
</TabPane>
</Tabs>
</div>
</Drawer>
</Row>
);
}
}
export default LogDrawer;
......@@ -3,10 +3,11 @@ import { Link } from 'react-router';
import axios from 'axios';
import { MANAGER_IP } from '../static/const';
import MediaQuery from 'react-responsive';
import { DOWNLOAD_IP } from '../static/const';
import { Row, Col, Menu, Dropdown, Icon, Select, Button } from 'antd';
const { SubMenu } = Menu;
const { Option } = Select;
import LogDrawer from './Modal/LogDrawer';
import ExperimentDrawer from './Modal/ExperimentDrawer';
import '../static/style/slideBar.scss';
import '../static/style/button.scss';
......@@ -15,6 +16,9 @@ interface SliderState {
menuVisible: boolean;
navBarVisible: boolean;
isdisabledFresh: boolean;
isvisibleLogDrawer: boolean;
isvisibleExperimentDrawer: boolean;
activeKey: string;
}
interface SliderProps {
......@@ -38,124 +42,13 @@ class SlideBar extends React.Component<SliderProps, SliderState> {
version: '',
menuVisible: false,
navBarVisible: false,
isdisabledFresh: false
isdisabledFresh: false,
isvisibleLogDrawer: false, // download button (nnimanager·dispatcher) click -> drawer
isvisibleExperimentDrawer: false,
activeKey: 'dispatcher'
};
}
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;
let trialMessagesArr = res1.data;
const interResultList = res2.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 result = {
experimentParameters: res.data,
trialMessage: trialMessagesArr
};
const aTag = document.createElement('a');
const file = new Blob([JSON.stringify(result, null, 4)], { 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.log';
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.log';
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.log';
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.log';
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'
......@@ -170,17 +63,23 @@ class SlideBar extends React.Component<SliderProps, SliderState> {
handleMenuClick = (e: EventPer) => {
if (this._isMounted) { this.setState({ menuVisible: false }); }
switch (e.key) {
// download experiment related content
// to see & download experiment parameters
case '1':
this.downExperimentContent();
if (this._isMounted === true) {
this.setState(() => ({ isvisibleExperimentDrawer: true }));
}
break;
// download nnimanager log file
// to see & download nnimanager log
case '2':
this.downnnimanagerLog();
if (this._isMounted === true) {
this.setState(() => ({ activeKey: 'nnimanager', isvisibleLogDrawer: true }));
}
break;
// download dispatcher log file
// to see & download dispatcher log
case '3':
this.downDispatcherlog();
if (this._isMounted === true) {
this.setState(() => ({ isvisibleLogDrawer: true, activeKey: 'dispatcher' }));
}
break;
case 'close':
case '10':
......@@ -285,6 +184,20 @@ class SlideBar extends React.Component<SliderProps, SliderState> {
}
}
// close log drawer (nnimanager.dispatcher)
closeLogDrawer = () => {
if (this._isMounted === true) {
this.setState(() => ({ isvisibleLogDrawer: false, activeKey: '' }));
}
}
// close download experiment parameters drawer
closeExpDrawer = () => {
if (this._isMounted === true) {
this.setState(() => ({ isvisibleExperimentDrawer: false }));
}
}
componentDidMount() {
this._isMounted = true;
this.getNNIversion();
......@@ -295,9 +208,10 @@ class SlideBar extends React.Component<SliderProps, SliderState> {
}
render() {
const { version, menuVisible } = this.state;
const { version, menuVisible, isvisibleLogDrawer, activeKey, isvisibleExperimentDrawer } = this.state;
const feed = `https://github.com/Microsoft/nni/issues/new?labels=${version}`;
return (
<Row>
<Row>
<Col span={18}>
<MediaQuery query="(min-width: 1299px)">
......@@ -369,6 +283,17 @@ class SlideBar extends React.Component<SliderProps, SliderState> {
</Col>
<Col span={3}> {this.select()} </Col>
</Row>
{/* the drawer for dispatcher & nnimanager log message */}
<LogDrawer
isVisble={isvisibleLogDrawer}
closeDrawer={this.closeLogDrawer}
activeTab={activeKey}
/>
<ExperimentDrawer
isVisble={isvisibleExperimentDrawer}
closeExpDrawer={this.closeExpDrawer}
/>
</Row>
);
}
}
......
......@@ -7,6 +7,7 @@ import { MANAGER_IP, CONTROLTYPE } from '../../static/const';
import { Experiment, TrialNumber } from '../../static/interface';
import { convertTime } from '../../static/function';
import ProgressBar from './ProgressItem';
import LogDrawer from '../Modal/LogDrawer';
import '../../static/style/progress.scss';
import '../../static/style/probar.scss';
......@@ -24,6 +25,7 @@ interface ProgressState {
isEnable: boolean;
userInputVal: string; // get user input
cancelSty: string;
isShowLogDrawer: boolean;
}
class Progressed extends React.Component<ProgressProps, ProgressState> {
......@@ -36,7 +38,8 @@ class Progressed extends React.Component<ProgressProps, ProgressState> {
btnName: 'Edit',
isEnable: true,
userInputVal: this.props.trialProfile.runConcurren.toString(),
cancelSty: 'none'
cancelSty: 'none',
isShowLogDrawer: false
};
}
......@@ -139,6 +142,18 @@ class Progressed extends React.Component<ProgressProps, ProgressState> {
}
}
isShowDrawer = () => {
if (this._isMounted === true) {
this.setState(() => ({ isShowLogDrawer: true }));
}
}
closeDrawer = () => {
if (this._isMounted === true) {
this.setState(() => ({ isShowLogDrawer: false }));
}
}
componentWillReceiveProps() {
const { trialProfile } = this.props;
if (this.conInput !== null) {
......@@ -156,7 +171,7 @@ class Progressed extends React.Component<ProgressProps, ProgressState> {
render() {
const { trialProfile, trialNumber, bestAccuracy, status, errors } = this.props;
const { isEnable, btnName, cancelSty } = this.state;
const { isEnable, btnName, cancelSty, isShowLogDrawer } = this.state;
const bar2 = trialNumber.totalCurrentTrial - trialNumber.waitTrial - trialNumber.unknowTrial;
const bar2Percent = (bar2 / trialProfile.MaxTrialNum) * 100;
const percent = (trialProfile.execDuration / trialProfile.maxDuration) * 100;
......@@ -173,6 +188,7 @@ class Progressed extends React.Component<ProgressProps, ProgressState> {
errorContent = (
<div className="errors">
{errors}
<div><a href="#" onClick={this.isShowDrawer}>Learn about</a></div>
</div>
);
}
......@@ -282,8 +298,13 @@ class Progressed extends React.Component<ProgressProps, ProgressState> {
<div>{trialNumber.failTrial}</div>
</Row>
</Col>
</Row>
{/* learn about click -> default active key is dispatcher. */}
<LogDrawer
isVisble={isShowLogDrawer}
closeDrawer={this.closeDrawer}
activeTab="dispatcher"
/>
</Row>
);
}
......
import * as React from 'react';
import { Spin } from 'antd';
import { DRAWEROPTION } from '../../static/const';
import MonacoEditor from 'react-monaco-editor';
interface MonacoEditorProps {
content: string;
loading: boolean;
}
class MonacoHTML extends React.Component<MonacoEditorProps, {}> {
public _isMonacoMount: boolean;
constructor(props: MonacoEditorProps) {
super(props);
}
componentDidMount() {
this._isMonacoMount = true;
}
componentWillUnmount() {
this._isMonacoMount = false;
}
render() {
const { content, loading } = this.props;
const heights: number = window.innerHeight - 48;
return (
<div className="just-for-log">
<Spin
// tip="Loading..."
style={{ width: '100%', height: heights * 0.9 }}
spinning={loading}
>
<MonacoEditor
width="100%"
height={heights * 0.9}
language="json"
value={content}
options={DRAWEROPTION}
/>
</Spin>
</div>
);
}
}
export default MonacoHTML;
......@@ -19,6 +19,11 @@ const MONACO = {
readOnly: true,
automaticLayout: true
};
const DRAWEROPTION = {
minimap: { enabled: false },
readOnly: true,
automaticLayout: true
};
const COLUMN_INDEX = [
{
name: 'Trial No.',
......@@ -52,5 +57,5 @@ const COLUMN_INDEX = [
const COLUMN = ['Trial No.', 'ID', 'Duration', 'Status', 'Default', 'Operation', 'Intermediate result'];
export {
MANAGER_IP, DOWNLOAD_IP, trialJobStatus,
CONTROLTYPE, MONACO, COLUMN, COLUMN_INDEX
CONTROLTYPE, MONACO, COLUMN, COLUMN_INDEX, DRAWEROPTION
};
......@@ -138,7 +138,29 @@ const filterDuration = (item: TableObj) => {
return item.status !== 'WAITING';
};
const downFile = (content: string, fileName: string) => {
const aTag = document.createElement('a');
const isEdge = navigator.userAgent.indexOf('Edge') !== -1 ? true : false;
const file = new Blob([content], { type: 'application/json' });
aTag.download = fileName;
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 = fileName;
downTag.href = URL.createObjectURL(file);
});
let eventMouse = document.createEvent('MouseEvents');
eventMouse.initEvent('click', false, false);
downTag.dispatchEvent(eventMouse);
}
};
export {
convertTime, convertDuration, getFinalResult, getFinal,
convertTime, convertDuration, getFinalResult, getFinal, downFile,
intermediateGraphOption, killJob, filterByStatus, filterDuration
};
$btnBgcolor: #0071bc;
Button.tableButton{
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
background: $btnBgcolor;
border-color: $btnBgcolor;
height: 26px;
......
......@@ -12,7 +12,7 @@
.column{
max-width: 124px;
padding-left: 18px;
font-weight: 700;
font-weight: 600;
}
.value{
max-width: 152px;
......@@ -20,6 +20,6 @@
text-align: left;
}
.idList{
font-weight: 700;
font-weight: 600;
}
}
......@@ -55,7 +55,7 @@ div.addtitle{
font-size: 20px;
}
.line{
font-weight: bold;
font-weight: 600;
color: rgb(60,141,188);
padding-right: 20px;
}
......
.card-container > .ant-tabs-card > .ant-tabs-content {
margin-top: -16px;
}
.card-container > .ant-tabs-card > .ant-tabs-content > .ant-tabs-tabpane {
background: #fff;
padding: 16px;
}
.card-container > .ant-tabs-card > .ant-tabs-bar {
border-color: #fff;
}
.card-container > .ant-tabs-card > .ant-tabs-bar .ant-tabs-tab {
border-color: transparent;
background: transparent;
}
.card-container > .ant-tabs-card > .ant-tabs-bar .ant-tabs-tab-active {
border-color: #fff;
background: #fff;
}
.logContainer{
height: 100%;
}
.buttons{
margin-top: 15px;
.close{
text-align: right;
}
}
/*
.logDrawer{
width: 100%;
.ant-drawer-body{
box-sizing: border-box;
-webkit-box-sizing: border-box;
}
}
*/
.ant-drawer-body{
background: #333;
}
.card-container > .ant-tabs-card > .ant-tabs-bar{
border: none;
}
.card-container > .ant-tabs-card > .ant-tabs-content > .ant-tabs-tabpane{
background-color: #333;
}
.close{
Button, Button:active, Button:hover{
background-color: #212121;
color: #fff;
border: none;
}
}
.download{
Button, Button:active, Button:hover{
background-color: #2772be;
color: #fff;
border: none;
}
}
.log-tab-body > .ant-tabs-card > .ant-tabs-bar .ant-tabs-tab-active{
background-color: #1e1e1e;
color: #fff;
border: none;
}
.log-tab-body .ant-tabs-nav .ant-tabs-tab:hover, .log-tab-body .ant-tabs-nav .ant-tabs-tab{
color: #fff;
border: none;
}
.ant-tabs.ant-tabs-card>.ant-tabs-bar .ant-tabs-tab{
border: none;
}
.log-tab-body{
.refresh{
margin-left: 10px;
display: none;
}
.ant-tabs-tab-active{
.refresh{
transition: 0.3s;
display: inline-block;
}
.refresh:hover{
transform: scale(1.2);
}
}
}
.just-for-log{
.monaco-editor{
.line-numbers{
color: #fff;
}
.current-line ~ .line-numbers{
color: #FFFAF0;
}
}
.view-lines{
background-color: #1e1e1e;
.mtk1{
color: #fff;
}
}
.margin-view-overlays{
background-color: #1e1e1e;
}
}
......@@ -22,7 +22,7 @@ $bgColor: #f2f2f2;
}
.ant-tabs-nav .ant-tabs-tab-active{
color: $color;
font-weight: 500;
font-weight: 600;
background: #dedede;
border-left: 3px solid ;
}
......
......@@ -5,6 +5,7 @@ $titleBgcolor: #b3b3b3;
}
.panelTitle{
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
width: 100%;
height: 38px;
background: $titleBgcolor;
......@@ -17,8 +18,7 @@ $titleBgcolor: #b3b3b3;
span{
font-size: 18px;
font-weight: bold;
font-family: 'Segoe';
font-weight: 600;
color: #333;
line-height: 38px;
margin-left: 14px;
......
......@@ -4,7 +4,7 @@
.status{
color: #0573bc;
font-size: 20px;
font-weight: bold;
font-weight: 600;
margin-top: 5px;
}
......@@ -46,7 +46,7 @@
.basic{
line-height: 24px;
font-family: 'Segoe';
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
p{
font-size: 14px;
color: #212121;
......
......@@ -10,8 +10,8 @@ $drowHoverBgColor: #e2e2e2;
margin: 0 auto;
position: relative;
.tab{
font-family: 'Segoe';
line-height: $barHeight;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
a{
font-size: 18px;
color: #b8c7ce;
......
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