Commit 88b75065 authored by Lijiao's avatar Lijiao Committed by chicm-ms
Browse files

[Fixed issue#1230] Refactor webui nav (#1319)


* update margin

* modify tablet

* final version
parent 5445bf4b
...@@ -103,7 +103,7 @@ class ExperimentDrawer extends React.Component<ExpDrawerProps, ExpDrawerState> { ...@@ -103,7 +103,7 @@ class ExperimentDrawer extends React.Component<ExpDrawerProps, ExpDrawerState> {
height={heights} height={heights}
> >
<div className="card-container log-tab-body" style={{ height: heights }}> <div className="card-container log-tab-body" style={{ height: heights }}>
<Tabs type="card"> <Tabs type="card" style={{ height: heights + 19 }}>
<TabPane tab="Experiment Parameters" key="Experiment"> <TabPane tab="Experiment Parameters" key="Experiment">
<div className="just-for-log"> <div className="just-for-log">
<MonacoEditor <MonacoEditor
...@@ -115,7 +115,7 @@ class ExperimentDrawer extends React.Component<ExpDrawerProps, ExpDrawerState> { ...@@ -115,7 +115,7 @@ class ExperimentDrawer extends React.Component<ExpDrawerProps, ExpDrawerState> {
/> />
</div> </div>
<Row className="buttons"> <Row className="buttons">
<Col span={12}> <Col span={12} className="download">
<Button <Button
type="primary" type="primary"
onClick={this.downExperimentParameters} onClick={this.downExperimentParameters}
......
...@@ -145,7 +145,7 @@ class LogDrawer extends React.Component<LogDrawerProps, LogDrawerState> { ...@@ -145,7 +145,7 @@ class LogDrawer extends React.Component<LogDrawerProps, LogDrawerState> {
// className="logDrawer" // className="logDrawer"
> >
<div className="card-container log-tab-body" style={{ height: heights }}> <div className="card-container log-tab-body" style={{ height: heights }}>
<Tabs type="card" defaultActiveKey={activeTab}> <Tabs type="card" defaultActiveKey={activeTab} style={{ height: heights + 19 }}>
{/* <Tabs type="card" onTabClick={this.selectwhichLog} defaultActiveKey={activeTab}> */} {/* <Tabs type="card" onTabClick={this.selectwhichLog} defaultActiveKey={activeTab}> */}
{/* <TabPane tab="Dispatcher Log" key="dispatcher"> */} {/* <TabPane tab="Dispatcher Log" key="dispatcher"> */}
<TabPane tab={this.dispatcherHTML()} key="dispatcher"> <TabPane tab={this.dispatcherHTML()} key="dispatcher">
...@@ -153,7 +153,7 @@ class LogDrawer extends React.Component<LogDrawerProps, LogDrawerState> { ...@@ -153,7 +153,7 @@ class LogDrawer extends React.Component<LogDrawerProps, LogDrawerState> {
<MonacoHTML content={dispatcherLogStr} loading={isLoadispatcher} /> <MonacoHTML content={dispatcherLogStr} loading={isLoadispatcher} />
</div> </div>
<Row className="buttons"> <Row className="buttons">
<Col span={12}> <Col span={12} className="download">
<Button <Button
type="primary" type="primary"
onClick={this.downloadDispatcher} onClick={this.downloadDispatcher}
......
...@@ -3,9 +3,12 @@ import { Link } from 'react-router'; ...@@ -3,9 +3,12 @@ import { Link } from 'react-router';
import axios from 'axios'; import axios from 'axios';
import { MANAGER_IP } from '../static/const'; import { MANAGER_IP } from '../static/const';
import MediaQuery from 'react-responsive'; import MediaQuery from 'react-responsive';
import { Row, Col, Menu, Dropdown, Icon, Select, Button } from 'antd'; import { Row, Col, Menu, Dropdown, Icon, Select, Button, Form } from 'antd';
import { FormComponentProps } from 'antd/lib/form';
import { OVERVIEWTABS, DETAILTABS, NNILOGO } from './stateless-component/NNItabs';
const { SubMenu } = Menu; const { SubMenu } = Menu;
const { Option } = Select; const { Option } = Select;
const FormItem = Form.Item;
import LogDrawer from './Modal/LogDrawer'; import LogDrawer from './Modal/LogDrawer';
import ExperimentDrawer from './Modal/ExperimentDrawer'; import ExperimentDrawer from './Modal/ExperimentDrawer';
import '../static/style/slideBar.scss'; import '../static/style/slideBar.scss';
...@@ -21,7 +24,7 @@ interface SliderState { ...@@ -21,7 +24,7 @@ interface SliderState {
activeKey: string; activeKey: string;
} }
interface SliderProps { interface SliderProps extends FormComponentProps {
changeInterval: (value: number) => void; changeInterval: (value: number) => void;
changeFresh: (value: string) => void; changeFresh: (value: string) => void;
} }
...@@ -122,9 +125,8 @@ class SlideBar extends React.Component<SliderProps, SliderState> { ...@@ -122,9 +125,8 @@ class SlideBar extends React.Component<SliderProps, SliderState> {
const { version } = this.state; const { version } = this.state;
const feedBackLink = `https://github.com/Microsoft/nni/issues/new?labels=${version}`; const feedBackLink = `https://github.com/Microsoft/nni/issues/new?labels=${version}`;
return ( return (
<Menu onClick={this.handleMenuClick} className="menuModal"> <Menu onClick={this.handleMenuClick} className="menu-list" style={{ width: 216 }}>
<Menu.Item key="overview"><Link to={'/oview'}>Overview</Link></Menu.Item> {/* <Menu onClick={this.handleMenuClick} className="menu-list" style={{width: window.innerWidth}}> */}
<Menu.Item key="detail"><Link to={'/detail'}>Trials detail</Link></Menu.Item>
<Menu.Item key="feedback"> <Menu.Item key="feedback">
<a href={feedBackLink} target="_blank">Feedback</a> <a href={feedBackLink} target="_blank">Feedback</a>
</Menu.Item> </Menu.Item>
...@@ -146,10 +148,46 @@ class SlideBar extends React.Component<SliderProps, SliderState> { ...@@ -146,10 +148,46 @@ class SlideBar extends React.Component<SliderProps, SliderState> {
); );
} }
mobileTabs = () => {
return (
// <Menu className="menuModal" style={{width: 880, position: 'fixed', left: 0, top: 56}}>
<Menu className="menuModal" style={{ padding: '0 10px' }}>
<Menu.Item key="overview"><Link to={'/oview'}>Overview</Link></Menu.Item>
<Menu.Item key="detail"><Link to={'/detail'}>Trials detail</Link></Menu.Item>
</Menu>
);
}
refreshInterval = () => {
const {
form: { getFieldDecorator },
// form: { getFieldDecorator, getFieldValue },
} = this.props;
return (
<Form>
<FormItem style={{ marginBottom: 0 }}>
{getFieldDecorator('interval', {
initialValue: 'Refresh every 10s',
})(
<Select onSelect={this.getInterval}>
<Option value="close">Disable Auto Refresh</Option>
<Option value="10">Refresh every 10s</Option>
<Option value="20">Refresh every 20s</Option>
<Option value="30">Refresh every 30s</Option>
<Option value="60">Refresh every 1min</Option>
</Select>,
)}
</FormItem>
</Form>
);
}
select = () => { select = () => {
const { isdisabledFresh } = this.state; const { isdisabledFresh } = this.state;
return ( return (
<div className="interval"> <div className="interval">
{this.refreshInterval()}
<Button <Button
className="fresh" className="fresh"
onClick={this.fresh} onClick={this.fresh}
...@@ -158,16 +196,6 @@ class SlideBar extends React.Component<SliderProps, SliderState> { ...@@ -158,16 +196,6 @@ class SlideBar extends React.Component<SliderProps, SliderState> {
> >
<Icon type="sync" /><span>Refresh</span> <Icon type="sync" /><span>Refresh</span>
</Button> </Button>
<Select
onSelect={this.getInterval}
defaultValue="Refresh every 10s"
>
<Option value="close">Disable Auto Refresh</Option>
<Option value="10">Refresh every 10s</Option>
<Option value="20">Refresh every 20s</Option>
<Option value="30">Refresh every 30s</Option>
<Option value="60">Refresh every 1min</Option>
</Select>
</div> </div>
); );
} }
...@@ -184,59 +212,19 @@ class SlideBar extends React.Component<SliderProps, SliderState> { ...@@ -184,59 +212,19 @@ class SlideBar extends React.Component<SliderProps, SliderState> {
} }
} }
// close log drawer (nnimanager.dispatcher) desktopHTML = () => {
closeLogDrawer = () => { const { version, menuVisible } = this.state;
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();
}
componentWillUnmount() {
this._isMounted = false;
}
render() {
const { version, menuVisible, isvisibleLogDrawer, activeKey, isvisibleExperimentDrawer } = this.state;
const feed = `https://github.com/Microsoft/nni/issues/new?labels=${version}`; const feed = `https://github.com/Microsoft/nni/issues/new?labels=${version}`;
return ( return (
<Row>
<Row>
<Col span={18}>
<MediaQuery query="(min-width: 1299px)">
<Row className="nav"> <Row className="nav">
<ul className="link"> <Col span={8}>
<li className="logo"> <span className="desktop-logo">{NNILOGO}</span>
<Link to={'/oview'}> <span className="left-right-margin">{OVERVIEWTABS}</span>
<img <span>{DETAILTABS}</span>
src={require('../static/img/logo2.png')} </Col>
style={{ width: 88 }} <Col span={16} className="desktop-right">
alt="NNI logo" <span>{this.select()}</span>
/> <span>
</Link>
</li>
<li className="tab firstTab">
<Link to={'/oview'} activeClassName="high">
Overview
</Link>
</li>
<li className="tab">
<Link to={'/detail'} activeClassName="high">
Trials detail
</Link>
</li>
<li className="feedback">
<Dropdown <Dropdown
className="dropdown" className="dropdown"
overlay={this.menu()} overlay={this.menu()}
...@@ -245,9 +233,19 @@ class SlideBar extends React.Component<SliderProps, SliderState> { ...@@ -245,9 +233,19 @@ class SlideBar extends React.Component<SliderProps, SliderState> {
trigger={['click']} trigger={['click']}
> >
<a className="ant-dropdown-link" href="#"> <a className="ant-dropdown-link" href="#">
Download <Icon type="down" /> <Icon type="download" className="down-icon" />
<span>Download</span>
{
menuVisible
?
<Icon type="up" className="margin-icon"/>
:
<Icon type="down" className="margin-icon"/>
}
</a> </a>
</Dropdown> </Dropdown>
</span>
<span className="feedback">
<a href={feed} target="_blank"> <a href={feed} target="_blank">
<img <img
src={require('../static/img/icon/issue.png')} src={require('../static/img/icon/issue.png')}
...@@ -255,34 +253,104 @@ class SlideBar extends React.Component<SliderProps, SliderState> { ...@@ -255,34 +253,104 @@ class SlideBar extends React.Component<SliderProps, SliderState> {
/> />
Feedback Feedback
</a> </a>
</span>
<span className="version">Version: {version}</span> <span className="version">Version: {version}</span>
</li>
</ul>
</Row>
</MediaQuery>
</Col> </Col>
<Col span={18}> </Row>
<MediaQuery query="(max-width: 1299px)"> );
<Row className="little"> }
<Col span={1} className="menu">
tabeltHTML = () => {
return (
<Row className="nav">
<Col className="tabelt-left" span={14}>
<span>
<Dropdown overlay={this.navigationBar()} trigger={['click']}> <Dropdown overlay={this.navigationBar()} trigger={['click']}>
<Icon type="unordered-list" className="more" /> <Icon type="unordered-list" className="more" />
</Dropdown> </Dropdown>
</span>
<span className="left-right-margin tabelt-img">{NNILOGO}</span>
<span>{OVERVIEWTABS}</span>
<span className="left-margin">{DETAILTABS}</span>
</Col> </Col>
<Col span={14} className="logo"> <Col className="tabelt-right" span={10}>
<Link to={'/oview'}> {this.select()}
</Col>
</Row>
);
}
mobileHTML = () => {
const { isdisabledFresh } = this.state;
return (
<Row className="nav">
<Col className="left" span={8}>
<span>
<Dropdown className="more-mobile" overlay={this.navigationBar()} trigger={['click']}>
<Icon type="unordered-list" className="more" />
</Dropdown>
</span>
<span>
<Dropdown overlay={this.mobileTabs()} trigger={['click']}>
<a className="ant-dropdown-link" href="#">
<span>NNI <Icon type="down" /></span>
</a>
</Dropdown>
</span>
</Col>
<Col className="center" span={8}>
<img <img
src={require('../static/img/logo2.png')} src={require('../static/img/logo2.png')}
style={{ width: 80 }}
alt="NNI logo" alt="NNI logo"
/> />
</Link>
</Col> </Col>
</Row> {/* the class interval have other style ! */}
</MediaQuery> <Col className="right interval" span={8}>
<Button
className="fresh"
onClick={this.fresh}
type="ghost"
disabled={isdisabledFresh}
>
<Icon type="sync" /><span>Refresh</span>
</Button>
</Col> </Col>
<Col span={3}> {this.select()} </Col>
</Row> </Row>
);
}
// 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();
}
componentWillUnmount() {
this._isMounted = false;
}
render() {
const mobile = (<MediaQuery maxWidth={884}>{this.mobileHTML()}</MediaQuery>);
const tablet = (<MediaQuery minWidth={885} maxWidth={1241}>{this.tabeltHTML()}</MediaQuery>);
const desktop = (<MediaQuery minWidth={1242}>{this.desktopHTML()}</MediaQuery>);
const { isvisibleLogDrawer, activeKey, isvisibleExperimentDrawer } = this.state;
return (
<div>
{mobile}
{tablet}
{desktop}
{/* the drawer for dispatcher & nnimanager log message */} {/* the drawer for dispatcher & nnimanager log message */}
<LogDrawer <LogDrawer
isVisble={isvisibleLogDrawer} isVisble={isvisibleLogDrawer}
...@@ -293,9 +361,9 @@ class SlideBar extends React.Component<SliderProps, SliderState> { ...@@ -293,9 +361,9 @@ class SlideBar extends React.Component<SliderProps, SliderState> {
isVisble={isvisibleExperimentDrawer} isVisble={isvisibleExperimentDrawer}
closeExpDrawer={this.closeExpDrawer} closeExpDrawer={this.closeExpDrawer}
/> />
</Row> </div>
); );
} }
} }
export default SlideBar; export default Form.create<FormComponentProps>()(SlideBar);
\ No newline at end of file \ No newline at end of file
import * as React from 'react'; import * as React from 'react';
import { import { Row, Col, Popover, Button, message } from 'antd';
Row, Col, Popover, Button, message
} from 'antd';
import axios from 'axios'; import axios from 'axios';
import { MANAGER_IP, CONTROLTYPE } from '../../static/const'; import { MANAGER_IP, CONTROLTYPE } from '../../static/const';
import { Experiment, TrialNumber } from '../../static/interface'; import { Experiment, TrialNumber } from '../../static/interface';
......
import * as React from 'react';
import { Link } from 'react-router';
const OVERVIEWTABS = (
<Link to={'/oview'} activeClassName="high-light" className="common-tabs">
Overview
</Link>
);
const DETAILTABS = (
<Link to={'/detail'} activeClassName="high-light" className="common-tabs">
Trials detail
</Link>
);
const NNILOGO = (
<Link to={'/oview'}>
<img
src={require('../../static/img/logo2.png')}
alt="NNI logo"
style={{height: 40}}
/>
</Link>
);
export { OVERVIEWTABS, DETAILTABS, NNILOGO };
\ No newline at end of file
...@@ -49,4 +49,3 @@ table { ...@@ -49,4 +49,3 @@ table {
border-collapse: collapse; border-collapse: collapse;
border-spacing: 0; border-spacing: 0;
} }
...@@ -26,7 +26,7 @@ ...@@ -26,7 +26,7 @@
} }
.buttons{ .buttons{
margin-top: 15px; margin-top: 11px;
.close{ .close{
text-align: right; text-align: right;
} }
......
...@@ -3,54 +3,6 @@ $barHeight: 56px; ...@@ -3,54 +3,6 @@ $barHeight: 56px;
$drowBgColor: #f2f2f2; $drowBgColor: #f2f2f2;
/* drowdown and select hover bgcolor */ /* drowdown and select hover bgcolor */
$drowHoverBgColor: #e2e2e2; $drowHoverBgColor: #e2e2e2;
.nav{
list-style: none;
width: 95%;
height: $barHeight;
margin: 0 auto;
position: relative;
.tab{
line-height: $barHeight;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
a{
font-size: 18px;
color: #b8c7ce;
text-decoration: none;
}
}
.firstTab{
margin: 0 20px;
}
.logo{
margin-top: 2px;
max-width: 128px;
}
}
.tab a:hover, .tab a.high{
color: white;
border-bottom: 1px solid #fff;
}
.feedback{
position: fixed;
right: 26%;
line-height: $barHeight;
font-size: 16px;
color: #fff;
a{
color: #fff;
text-decoration: none;
margin-left: 10px;
}
img{
width: 20px;
margin-right: 8px;
}
.version{
margin-left: 16px;
}
}
/* refresh button */ /* refresh button */
.fresh{ .fresh{
...@@ -63,20 +15,25 @@ $drowHoverBgColor: #e2e2e2; ...@@ -63,20 +15,25 @@ $drowHoverBgColor: #e2e2e2;
color: #fff; color: #fff;
} }
.link li{
float: left;
}
.dropdown{ .dropdown{
margin-right: 10px;
/* make dropdown content box position in blue bar bottom */ /* make dropdown content box position in blue bar bottom */
padding-bottom: 14px; padding-bottom: 14px;
.down-icon{
font-size: 20px !important;
padding-right: 2px;
}
} }
.interval{ .interval{
position: fixed; display: inline-block;
right: 6%;
top: 12px;
font-size: 16px; font-size: 16px;
color: #fff; color: #fff;
.ant-form{
display: inline-block;
}
form .ant-select{
width: 166px;
}
.ant-select-selection{ .ant-select-selection{
background-color: transparent; background-color: transparent;
border: none; border: none;
...@@ -87,10 +44,19 @@ $drowHoverBgColor: #e2e2e2; ...@@ -87,10 +44,19 @@ $drowHoverBgColor: #e2e2e2;
.ant-select-arrow{ .ant-select-arrow{
color: #fff; color: #fff;
} }
.fresh{
margin-right: 10px;
}
.ant-btn-ghost{
padding: 0 10px;
}
.ant-btn-ghost[disabled]{ .ant-btn-ghost[disabled]{
background-color: transparent; background-color: #005b98;
color: #fff; color: #fff;
} }
} }
/* set select bgcolor */ /* set select bgcolor */
.ant-select-dropdown-menu{ .ant-select-dropdown-menu{
...@@ -126,26 +92,141 @@ $drowHoverBgColor: #e2e2e2; ...@@ -126,26 +92,141 @@ $drowHoverBgColor: #e2e2e2;
} }
} }
.menu-list{
position: relative;
top: 13px;
}
.ant-dropdown{
.menuModal{
position: relative;
top: 12px;
}
}
.ant-select-selection-selected-value{
font-size: 16px;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
}
.ant-dropdown-menu-submenu-title{
font-size: 16px;
}
.ant-dropdown-menu-item:hover, .ant-dropdown-menu-submenu-title:hover{
background-color: transparent;
}
.nav{
width: 95%;
height: $barHeight;
margin: 0 auto;
line-height: $barHeight;
/* nav style*/ /* mobile start*/
.little{ .left{
width: 90%; text-align: left;
.menu{ /* more menu */
margin-left: 33px; font-size: 18px;
.more{
color: #fff; color: #fff;
font-size: 24px; a, a:visited{
margin-top: 16px; color: #fff;
text-decoration: none;
} }
.more:hover{ .more-mobile{
margin-right: 10%;
font-size: 22px;
position: relative;
top: 1px;
}
.more-mobile:hover{
cursor: pointer; cursor: pointer;
} }
} }
.logo{ .center{
text-align: center;
img{
height: 38px;
}
}
.right{
text-align: right; text-align: right;
button{
margin-top: 12px;
}
} }
/* mobile end */
/* tabelt mode */
.tabelt-left{
height: $barHeight;
.tabelt-img img{
position: relative;
top: -5px;
}
}
.tabelt-right{
text-align: right;
}
/* desktop mode */
.desktop-logo{
position: relative;
top: -3px;
}
.desktop-right{
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
text-align: right;
line-height: $barHeight;
font-size: 16px;
color: #fff;
a{
color: #fff;
text-decoration: none;
}
img{
width: 20px;
margin-right: 8px;
}
.feedback{
font-size: 16px;
margin: 0 20px;
}
.version{
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
font-size: 16px;
}
.margin-icon{
margin-left: 8px;
}
}
}
/* public style in nav in threee mode*/
.more{
color: #fff;
font-size: 24px;
}
.more:hover{
cursor: pointer;
} }
.menuModal{ /* overview and detail tabs common style */
width: 198px; a.common-tabs{
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
font-size: 16px;
color: #b8c7ce;
text-decoration: none;
}
.common-tabs:visited, .high-light:hover{
color: #fff;
text-decoration: none;
}
.common-tabs:hover, .high-light{
color: #fff;
border-bottom: 1px solid #fff;
}
.left-right-margin{
margin-left: 20px;
margin-right: 20px;
}
.left-margin{
margin-left: 20px;
} }
\ 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