Unverified Commit e2d8cc1b authored by Lijiaoa's avatar Lijiaoa Committed by GitHub
Browse files

[webui] format code by eslint and prettier (#2744)



* update

* format as prettier

* fix error

* add stylelint for scss css file

* add arrow-parens rule

* update

* fix lint

* fix conflict
Co-authored-by: default avatarLijiao <15910218274@163.com>
Co-authored-by: default avatarLijiao <Lijiaoa@outlook.com>
Co-authored-by: default avatarLijiao <1425861283@qq.com>
parent 4668fc08
/build/**
/scripts/**
/src/serviceWorker.ts
\ No newline at end of file
......@@ -9,22 +9,29 @@
"sourceType": "module"
},
"plugins": [
"@typescript-eslint"
"@typescript-eslint",
"eslint-plugin-prettier"
],
"extends": [
"eslint:recommended",
"plugin:react/recommended",
"plugin:@typescript-eslint/eslint-recommended",
"plugin:@typescript-eslint/recommended"
"plugin:@typescript-eslint/recommended",
"prettier/react",
"prettier"
],
"rules": {
"prettier/prettier": 2,
"@typescript-eslint/no-explicit-any": 0,
"@typescript-eslint/no-namespace": 0,
"@typescript-eslint/consistent-type-assertions": 0,
"@typescript-eslint/no-inferrable-types": 0,
"@typescript-eslint/no-use-before-define": [2, "nofunc"],
"no-inner-declarations": 0,
"@typescript-eslint/no-var-requires": 0,
"arrow-parens": [2, "as-needed"],
"no-inner-declarations": 0,
"no-empty": 2,
"no-multiple-empty-lines": [2, { "max": 1 }],
"react/display-name": 0
},
"settings": {
......
{
"extends": "stylelint-config-standard",
"ignoreFiles": [
"build/**"
],
"rules": {
"at-rule-empty-line-before": null,
"indentation": 4,
"no-descending-specificity": null
}
}
\ No newline at end of file
{
"name": "nni-webui",
"version": "0.1.0",
"private": true,
"license": "MIT",
"dependencies": {
"axios": "^0.19.0",
"babel-eslint": "10.0.1",
......@@ -75,15 +75,20 @@
"@typescript-eslint/parser": "^2.11.0",
"concurrently": "^5.2.0",
"eslint": "^5.16.0",
"eslint-config-prettier": "^6.1.0",
"eslint-config-react-app": "^4.0.0",
"eslint-loader": "2.1.2",
"eslint-plugin-flowtype": "2.50.1",
"eslint-plugin-import": "2.16.0",
"eslint-plugin-jsx-a11y": "6.2.1",
"eslint-plugin-prettier": "^3.1.0",
"eslint-plugin-react": "7.12.4",
"eslint-plugin-react-hooks": "^1.5.0",
"express": "^4.17.1",
"npx": "^10.2.0",
"prettier": "^1.18.2",
"stylelint": "^13.7.0",
"stylelint-config-standard": "^20.0.0",
"typescript": "^3.8.0"
},
"proxy": "http://localhost:12138",
......@@ -92,6 +97,7 @@
"build": "node --max-old-space-size=3072 scripts/build.js",
"test": "node --max-old-space-size=3072 scripts/test.js",
"eslint": "npx eslint ./ --ext .tsx,.ts",
"stylelint": "npx stylelint **/*{.css,.scss}",
"mock": "node scripts/server.js",
"dev": "concurrently \"yarn mock\" \"yarn start\""
},
......
module.exports = {
printWidth: 120,
semi: true,
tabWidth: 4,
trailingComma: 'none',
arrowParens: 'avoid',
bracketSpacing: true,
singleQuote: true,
eslintIntegration: true,
jsxSingleQuote: true,
endOfline: 'lf'
};
.nni{
.nni {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
color: #212121;
font-size: 14px;
background: #f2f2f2;
}
.header{
.header {
position: fixed;
left: 0;
top: 0;
width: 100%;
height: 56px;
background: #0071BC;
background: #0071bc;
border-right: 1px solid #ccc;
z-index: 1000;
}
.headerCon{
.headerCon {
width: 90%;
margin: 0 auto;
}
.contentBox{
.contentBox {
width: 100%;
}
.content{
.content {
width: 89%;
min-width: 1024px;
margin: 0 auto;
......@@ -33,31 +33,31 @@
margin-bottom: 30px;
}
.bottomDiv{
.bottomDiv {
margin-bottom: 10px;
}
.bgNNI{
.bgNNI {
background-color: #fff;
}
.borderRight{
.borderRight {
margin-right: 10px;
}
/* office-fabric-ui */
.ms-Pivot-linkContent{
.ms-Pivot-linkContent {
height: 44px;
}
.ms-Callout-main{
p{
.ms-Callout-main {
p {
font-weight: 500;
color: #333;
}
}
.warning{
.warning {
padding-bottom: 15px;
background-color: #f2f2f2;
}
......@@ -28,7 +28,7 @@ export const AppContext = React.createContext({
// eslint-disable-next-line @typescript-eslint/no-empty-function, @typescript-eslint/no-unused-vars
changeColumn: (val: string[]) => {},
// eslint-disable-next-line @typescript-eslint/no-empty-function, @typescript-eslint/no-unused-vars
changeMetricGraphMode: ( val: 'max' | 'min') => {},
changeMetricGraphMode: (val: 'max' | 'min') => {},
// eslint-disable-next-line @typescript-eslint/no-empty-function, @typescript-eslint/no-unused-vars
changeEntries: (val: string) => {}
});
......@@ -57,7 +57,7 @@ class App extends React.Component<{}, AppState> {
this.setState(state => ({
experimentUpdateBroadcast: state.experimentUpdateBroadcast + 1,
trialsUpdateBroadcast: state.trialsUpdateBroadcast + 1,
metricGraphMode: (EXPERIMENT.optimizeMode === 'minimize' ? 'min' : 'max')
metricGraphMode: EXPERIMENT.optimizeMode === 'minimize' ? 'min' : 'max'
}));
this.timerId = window.setTimeout(this.refresh, this.state.interval * 100);
// final result is legal
......@@ -78,7 +78,8 @@ class App extends React.Component<{}, AppState> {
// illegal final data
this.setState(() => ({
isillegalFinal: true,
expWarningMessage: 'WebUI support final result as number and dictornary includes default keys, your experiment final result is illegal, please check your data.'
expWarningMessage:
'WebUI support final result as number and dictornary includes default keys, your experiment final result is illegal, please check your data.'
}));
window.clearInterval(this.dataFormatimer);
}
......@@ -86,10 +87,9 @@ class App extends React.Component<{}, AppState> {
break;
}
}
}
};
changeInterval = (interval: number): void => {
window.clearTimeout(this.timerId);
if (interval === 0) {
return;
......@@ -100,22 +100,21 @@ class App extends React.Component<{}, AppState> {
this.firstLoad = true;
this.refresh();
});
}
};
// TODO: use local storage
changeColumn = (columnList: string[]): void => {
this.setState({ columnList: columnList });
}
};
changeMetricGraphMode = (val: 'max' | 'min'): void => {
this.setState({ metricGraphMode: val });
}
};
// overview best trial module
changeEntries = (entries: string): void => {
this.setState({ bestTrialEntries: entries });
}
};
shouldComponentUpdate(nextProps: any, nextState: AppState): boolean {
if (!(nextState.isUpdate || nextState.isUpdate === undefined)) {
......@@ -126,8 +125,15 @@ class App extends React.Component<{}, AppState> {
}
render(): React.ReactNode {
const { interval, columnList, experimentUpdateBroadcast, trialsUpdateBroadcast,
metricGraphMode, isillegalFinal, expWarningMessage, bestTrialEntries
const {
interval,
columnList,
experimentUpdateBroadcast,
trialsUpdateBroadcast,
metricGraphMode,
isillegalFinal,
expWarningMessage,
bestTrialEntries
} = this.state;
if (experimentUpdateBroadcast === 0 || trialsUpdateBroadcast === 0) {
return null; // TODO: render a loading page
......@@ -141,28 +147,30 @@ class App extends React.Component<{}, AppState> {
{ errorWhere: TRIALS.metricDataRangeError(), errorMessage: TRIALS.metricDataRangeErrorMessage() }
];
return (
<Stack className="nni" style={{ minHeight: window.innerHeight }}>
<div className="header">
<div className="headerCon">
<Stack className='nni' style={{ minHeight: window.innerHeight }}>
<div className='header'>
<div className='headerCon'>
<NavCon changeInterval={this.changeInterval} refreshFunction={this.lastRefresh} />
</div>
</div>
<Stack className="contentBox">
<Stack className="content">
<Stack className='contentBox'>
<Stack className='content'>
{/* if api has error field, show error message */}
{
errorList.map((item, key) => {
return (
item.errorWhere && <div key={key} className="warning">
<MessageInfo info={item.errorMessage} typeInfo="error" />
{errorList.map(
(item, key) =>
item.errorWhere && (
<div key={key} className='warning'>
<MessageInfo info={item.errorMessage} typeInfo='error' />
</div>
);
})
}
{isillegalFinal && <div className="warning">
<MessageInfo info={expWarningMessage} typeInfo="warning" />
</div>}
<AppContext.Provider value={{
)
)}
{isillegalFinal && (
<div className='warning'>
<MessageInfo info={expWarningMessage} typeInfo='warning' />
</div>
)}
<AppContext.Provider
value={{
interval,
columnList,
changeColumn: this.changeColumn,
......@@ -172,7 +180,8 @@ class App extends React.Component<{}, AppState> {
changeMetricGraphMode: this.changeMetricGraphMode,
bestTrialEntries,
changeEntries: this.changeEntries
}}>
}}
>
{this.props.children}
</AppContext.Provider>
</Stack>
......@@ -192,7 +201,6 @@ class App extends React.Component<{}, AppState> {
if (trialsUpdated) {
this.setState(state => ({ trialsUpdateBroadcast: state.trialsUpdateBroadcast + 1 }));
}
} else {
this.firstLoad = false;
}
......@@ -205,13 +213,15 @@ class App extends React.Component<{}, AppState> {
}
this.timerId = window.setTimeout(this.refresh, this.state.interval * 1000);
}
};
public async lastRefresh(): Promise<void> {
await EXPERIMENT.update();
await TRIALS.update(true);
this.setState(state => ({ experimentUpdateBroadcast: state.experimentUpdateBroadcast + 1, trialsUpdateBroadcast: state.trialsUpdateBroadcast + 1 }));
this.setState(state => ({
experimentUpdateBroadcast: state.experimentUpdateBroadcast + 1,
trialsUpdateBroadcast: state.trialsUpdateBroadcast + 1
}));
}
}
......
......@@ -2,15 +2,17 @@ import * as React from 'react';
import axios from 'axios';
import { WEBUIDOC, MANAGER_IP } from '../static/const';
import {
Stack, initializeIcons, StackItem, CommandBarButton,
IContextualMenuProps, IStackTokens, IStackStyles
Stack,
initializeIcons,
StackItem,
CommandBarButton,
IContextualMenuProps,
IStackTokens,
IStackStyles
} from '@fluentui/react';
import LogPanel from './modals/LogPanel';
import ExperimentPanel from './modals/ExperimentPanel';
import {
downLoadIcon, infoIconAbout,
timeIcon, disableUpdates, requency, closeTimer
} from './buttons/Icon';
import { downLoadIcon, infoIconAbout, timeIcon, disableUpdates, requency, closeTimer } from './buttons/Icon';
import { OVERVIEWTABS, DETAILTABS, NNILOGO } from './stateless-component/NNItabs';
import { EXPERIMENT } from '../static/datamodel';
import '../static/style/nav/nav.scss';
......@@ -22,7 +24,10 @@ const stackTokens: IStackTokens = {
};
const stackStyle: IStackStyles = {
root: {
minWidth: 400, height: 56, display: 'flex', verticalAlign: 'center'
minWidth: 400,
height: 56,
display: 'flex',
verticalAlign: 'center'
}
};
......@@ -43,7 +48,6 @@ interface NavProps {
}
class NavCon extends React.Component<NavProps, NavState> {
constructor(props: NavProps) {
super(props);
this.state = {
......@@ -61,49 +65,48 @@ class NavCon extends React.Component<NavProps, NavState> {
// to see & download experiment parameters
showExpcontent = (): void => {
this.setState({ isvisibleExperimentDrawer: true });
}
};
// to see & download dispatcher | nnimanager log
showDispatcherLog = (): void => {
this.setState({ isvisibleLogDrawer: true });
}
};
// close log drawer (nnimanager.dispatcher)
closeLogDrawer = (): void => {
this.setState({ isvisibleLogDrawer: false });
}
};
// close download experiment parameters drawer
closeExpDrawer = (): void => {
this.setState({ isvisibleExperimentDrawer: false });
}
};
getNNIversion = (): void => {
axios(`${MANAGER_IP}/version`, {
method: 'GET'
})
.then(res => {
}).then(res => {
if (res.status === 200) {
this.setState({ version: res.data });
}
});
}
};
openGithub = (): void => {
const { version } = this.state;
const feed = `https://github.com/Microsoft/nni/issues/new?labels=${version}`;
window.open(feed);
}
};
openDocs = (): void => {
window.open(WEBUIDOC);
}
};
openGithubNNI = (): void => {
const { version } = this.state;
const nniLink = `https://github.com/Microsoft/nni/tree/${version}`;
window.open(nniLink);
}
};
getInterval = (num: number): void => {
this.props.changeInterval(num); // notice parent component
......@@ -111,15 +114,14 @@ class NavCon extends React.Component<NavProps, NavState> {
refreshFrequency: num === 0 ? '' : num,
refreshText: num === 0 ? 'Disable auto' : 'Auto refresh'
}));
}
};
componentDidMount(): void {
this.getNNIversion();
}
render(): React.ReactNode {
const { isvisibleLogDrawer, isvisibleExperimentDrawer, version,
refreshText, refreshFrequency } = this.state;
const { isvisibleLogDrawer, isvisibleExperimentDrawer, version, refreshText, refreshFrequency } = this.state;
const aboutProps: IContextualMenuProps = {
items: [
{
......@@ -143,14 +145,14 @@ class NavCon extends React.Component<NavProps, NavState> {
]
};
return (
<Stack horizontal className="nav">
<Stack horizontal className='nav'>
<StackItem grow={30} styles={{ root: { minWidth: 300, display: 'flex', verticalAlign: 'center' } }}>
<span className="desktop-logo">{NNILOGO}</span>
<span className="left-right-margin">{OVERVIEWTABS}</span>
<span className='desktop-logo'>{NNILOGO}</span>
<span className='left-right-margin'>{OVERVIEWTABS}</span>
<span>{DETAILTABS}</span>
</StackItem>
<StackItem grow={70} className="navOptions">
<Stack horizontal horizontalAlign="end" tokens={stackTokens} styles={stackStyle}>
<StackItem grow={70} className='navOptions'>
<Stack horizontal horizontalAlign='end' tokens={stackTokens} styles={stackStyle}>
{/* refresh button danyi*/}
{/* TODO: fix bug */}
{/* <CommandBarButton
......@@ -158,29 +160,23 @@ class NavCon extends React.Component<NavProps, NavState> {
text="Refresh"
onClick={this.props.refreshFunction}
/> */}
<div className="nav-refresh">
<div className='nav-refresh'>
<CommandBarButton
iconProps={refreshFrequency === '' ? disableUpdates : timeIcon}
text={refreshText}
menuProps={this.refreshProps}
/>
<div className="nav-refresh-num">{refreshFrequency}</div>
<div className='nav-refresh-num'>{refreshFrequency}</div>
</div>
<CommandBarButton
iconProps={downLoadIcon}
text="Download"
menuProps={this.menuProps}
/>
<CommandBarButton
iconProps={infoIconAbout}
text="About"
menuProps={aboutProps}
/>
<CommandBarButton iconProps={downLoadIcon} text='Download' menuProps={this.menuProps} />
<CommandBarButton iconProps={infoIconAbout} text='About' menuProps={aboutProps} />
</Stack>
</StackItem>
{/* the drawer for dispatcher & nnimanager log message */}
{isvisibleLogDrawer && <LogPanel closeDrawer={this.closeLogDrawer} />}
{isvisibleExperimentDrawer && <ExperimentPanel closeExpDrawer={this.closeExpDrawer} experimentProfile={EXPERIMENT.profile} />}
{isvisibleExperimentDrawer && (
<ExperimentPanel closeExpDrawer={this.closeExpDrawer} experimentProfile={EXPERIMENT.profile} />
)}
</Stack>
);
}
......@@ -236,8 +232,7 @@ class NavCon extends React.Component<NavProps, NavState> {
text: 'Refresh every 1min',
iconProps: requency,
onClick: this.getInterval.bind(this, 60)
},
}
]
};
}
......
......@@ -2,7 +2,7 @@ import * as React from 'react';
import { Stack, IStackTokens, Dropdown } from '@fluentui/react';
import { EXPERIMENT, TRIALS } from '../static/datamodel';
import { Trial } from '../static/model/trial';
import { AppContext } from "../App";
import { AppContext } from '../App';
import { Title1 } from './overview/Title1';
import SuccessTable from './overview/SuccessTable';
import Progressed from './overview/Progress';
......@@ -14,7 +14,7 @@ import '../static/style/overview.scss';
import '../static/style/logPath.scss';
const stackTokens: IStackTokens = {
childrenGap: 30,
childrenGap: 30
};
const entriesOption = [
......@@ -50,25 +50,24 @@ class Overview extends React.Component<{}, OverviewState> {
// #999 panel active bgcolor; #b3b3b3 as usual
const { changeMetricGraphMode } = this.context;
changeMetricGraphMode('max');
}
};
clickMinTop = (event: React.SyntheticEvent<EventTarget>): void => {
event.stopPropagation();
const { changeMetricGraphMode } = this.context;
changeMetricGraphMode('min');
}
};
changeConcurrency = (val: number): void => {
this.setState({ trialConcurrency: val });
}
};
// updateEntries = (event: React.FormEvent<HTMLDivElement>, item: IDropdownOption | undefined): void => {
updateEntries = (event: React.FormEvent<HTMLDivElement>, item: any): void => {
if (item !== undefined) {
this.context.changeEntries(item.key);
}
}
};
render(): React.ReactNode {
const { trialConcurrency } = this.state;
......@@ -81,22 +80,22 @@ class Overview extends React.Component<{}, OverviewState> {
<AppContext.Consumer>
{(value): React.ReactNode => {
const { experimentUpdateBroadcast, metricGraphMode, bestTrialEntries } = value;
const titleMaxbgcolor = (metricGraphMode === 'max' ? '#333' : '#b3b3b3');
const titleMinbgcolor = (metricGraphMode === 'min' ? '#333' : '#b3b3b3');
const titleMaxbgcolor = metricGraphMode === 'max' ? '#333' : '#b3b3b3';
const titleMinbgcolor = metricGraphMode === 'min' ? '#333' : '#b3b3b3';
return (
<div className="overview">
<div className='overview'>
{/* status and experiment block */}
<Stack className="bottomDiv bgNNI">
<TitleContext.Provider value={{ text: "Experiment", icon: "11.png", fontColor: '' }}>
<Stack className='bottomDiv bgNNI'>
<TitleContext.Provider value={{ text: 'Experiment', icon: '11.png', fontColor: '' }}>
<Title1 />
</TitleContext.Provider>
<BasicInfo />
</Stack>
<Stack horizontal className="overMessage bottomDiv">
<Stack horizontal className='overMessage bottomDiv'>
{/* status block */}
<Stack.Item grow className="prograph bgNNI borderRight">
<TitleContext.Provider value={{ text: "Status", icon: "5.png", fontColor: '' }}>
<Stack.Item grow className='prograph bgNNI borderRight'>
<TitleContext.Provider value={{ text: 'Status', icon: '5.png', fontColor: '' }}>
<Title1 />
</TitleContext.Provider>
<Progressed
......@@ -107,21 +106,27 @@ class Overview extends React.Component<{}, OverviewState> {
/>
</Stack.Item>
{/* experiment parameters search space tuner assessor... */}
<Stack.Item grow styles={{ root: { width: 450 } }} className="overviewBoder borderRight bgNNI">
<TitleContext.Provider value={{ text: "Search space", icon: "10.png", fontColor: '' }}>
<Stack.Item
grow
styles={{ root: { width: 450 } }}
className='overviewBoder borderRight bgNNI'
>
<TitleContext.Provider
value={{ text: 'Search space', icon: '10.png', fontColor: '' }}
>
<Title1 />
</TitleContext.Provider>
<Stack className="experiment">
<Stack className='experiment'>
<SearchSpace searchSpace={EXPERIMENT.searchSpace} />
</Stack>
</Stack.Item>
<Stack.Item grow styles={{ root: { width: 450 } }} className="bgNNI">
<TitleContext.Provider value={{ text: "Config", icon: "4.png", fontColor: '' }}>
<Stack.Item grow styles={{ root: { width: 450 } }} className='bgNNI'>
<TitleContext.Provider value={{ text: 'Config', icon: '4.png', fontColor: '' }}>
<Title1 />
</TitleContext.Provider>
<Stack className="experiment">
<Stack className='experiment'>
{/* the scroll bar all the trial profile in the searchSpace div*/}
<div className="experiment searchSpace">
<div className='experiment searchSpace'>
<TrialInfo
experimentUpdateBroadcast={experimentUpdateBroadcast}
concurrency={trialConcurrency}
......@@ -132,20 +137,26 @@ class Overview extends React.Component<{}, OverviewState> {
</Stack>
<Stack style={{ backgroundColor: '#fff' }}>
<Stack horizontal className="top10bg" style={{ position: 'relative', height: 42 }}>
<div
className="title"
onClick={this.clickMaxTop}
<Stack horizontal className='top10bg' style={{ position: 'relative', height: 42 }}>
<div className='title' onClick={this.clickMaxTop}>
<TitleContext.Provider
value={{
text: 'Top maximal trials',
icon: 'max.png',
fontColor: titleMaxbgcolor
}}
>
<TitleContext.Provider value={{ text: "Top maximal trials", icon: "max.png", fontColor: titleMaxbgcolor }}>
<Title1 />
</TitleContext.Provider>
</div>
<div
className="title minTitle"
onClick={this.clickMinTop}
<div className='title minTitle' onClick={this.clickMinTop}>
<TitleContext.Provider
value={{
text: 'Top minimal trials',
icon: 'min.png',
fontColor: titleMinbgcolor
}}
>
<TitleContext.Provider value={{ text: "Top minimal trials", icon: "min.png", fontColor: titleMinbgcolor }}>
<Title1 />
</TitleContext.Provider>
</div>
......@@ -172,9 +183,8 @@ class Overview extends React.Component<{}, OverviewState> {
</Stack>
</Stack>
</div>
)
}
}
);
}}
</AppContext.Consumer>
);
}
......@@ -214,11 +224,13 @@ class Overview extends React.Component<{}, OverviewState> {
scale: true,
data: ySequence
},
series: [{
series: [
{
symbolSize: 6,
type: 'scatter',
data: ySequence
}]
}
]
};
}
}
......
import * as React from 'react';
import {
Stack, StackItem, Pivot, PivotItem, Dropdown, IDropdownOption, DefaultButton
} from '@fluentui/react';
import { Stack, StackItem, Pivot, PivotItem, Dropdown, IDropdownOption, DefaultButton } from '@fluentui/react';
import { EXPERIMENT, TRIALS } from '../static/datamodel';
import { Trial } from '../static/model/trial';
import { AppContext } from "../App";
import { AppContext } from '../App';
import { tableListIcon } from './buttons/Icon';
import DefaultPoint from './trial-detail/DefaultMetricPoint';
import Duration from './trial-detail/Duration';
......@@ -18,7 +16,7 @@ const searchOptions = [
{ key: 'id', text: 'Id' },
{ key: 'Trial No.', text: 'Trial No.' },
{ key: 'status', text: 'Status' },
{ key: 'parameters', text: 'Parameters' },
{ key: 'parameters', text: 'Parameters' }
];
interface TrialDetailState {
......@@ -74,17 +72,17 @@ class TrialsDetail extends React.Component<{}, TrialDetailState> {
alert(`Unexpected search filter ${this.state.searchType}`);
}
this.setState({ searchFilter: filter });
}
};
handleTablePageSizeSelect = (event: React.FormEvent<HTMLDivElement>, item: IDropdownOption | undefined): void => {
if (item !== undefined) {
this.setState({ tablePageSize: item.text === 'all' ? -1 : parseInt(item.text, 10) });
}
}
};
handleWhichTabs = (item: any): void => {
this.setState({ whichChart: item.props.headerText });
}
};
updateSearchFilterType = (event: React.FormEvent<HTMLDivElement>, item: IDropdownOption | undefined): void => {
// clear input value and re-render table
......@@ -94,7 +92,7 @@ class TrialsDetail extends React.Component<{}, TrialDetailState> {
}
this.setState(() => ({ searchType: item.key.toString() }));
}
}
};
render(): React.ReactNode {
const { tablePageSize, whichChart, searchType } = this.state;
......@@ -103,22 +101,24 @@ class TrialsDetail extends React.Component<{}, TrialDetailState> {
return (
<AppContext.Consumer>
{(value): React.ReactNode =>
{(value): React.ReactNode => (
<React.Fragment>
<div className="trial" id="tabsty">
<Pivot defaultSelectedKey={"0"} className="detial-title" onLinkClick={this.handleWhichTabs} selectedKey={whichChart}>
<div className='trial' id='tabsty'>
<Pivot
defaultSelectedKey={'0'}
className='detial-title'
onLinkClick={this.handleWhichTabs}
selectedKey={whichChart}
>
{/* <PivotItem tab={this.titleOfacc} key="1"> doesn't work*/}
<PivotItem headerText="Default metric" itemIcon="HomeGroup" key="Default metric">
<Stack className="graph">
<DefaultPoint
trialIds={trialIds}
visible={whichChart === 'Default metric'}
/>
<PivotItem headerText='Default metric' itemIcon='HomeGroup' key='Default metric'>
<Stack className='graph'>
<DefaultPoint trialIds={trialIds} visible={whichChart === 'Default metric'} />
</Stack>
</PivotItem>
{/* <PivotItem tab={this.titleOfhyper} key="2"> */}
<PivotItem headerText="Hyper-parameter" itemIcon="Equalizer" key="Hyper-parameter">
<Stack className="graph">
<PivotItem headerText='Hyper-parameter' itemIcon='Equalizer' key='Hyper-parameter'>
<Stack className='graph'>
<Para
trials={source}
searchSpace={EXPERIMENT.searchSpaceNew}
......@@ -127,11 +127,15 @@ class TrialsDetail extends React.Component<{}, TrialDetailState> {
</Stack>
</PivotItem>
{/* <PivotItem tab={this.titleOfDuration} key="3"> */}
<PivotItem headerText="Duration" itemIcon="BarChartHorizontal" key="Duration">
<PivotItem headerText='Duration' itemIcon='BarChartHorizontal' key='Duration'>
<Duration source={source} whichChart={whichChart} />
</PivotItem>
{/* <PivotItem tab={this.titleOfIntermediate} key="4"> */}
<PivotItem headerText="Intermediate result" itemIcon="StackedLineChart" key="Intermediate result">
<PivotItem
headerText='Intermediate result'
itemIcon='StackedLineChart'
key='Intermediate result'
>
{/* *why this graph has small footprint? */}
<Intermediate source={source} whichChart={whichChart} />
</PivotItem>
......@@ -139,25 +143,33 @@ class TrialsDetail extends React.Component<{}, TrialDetailState> {
</div>
{/* trial table list */}
<div style={{ backgroundColor: '#fff' }}>
<Stack horizontal className="panelTitle" style={{ marginTop: 10 }}>
<Stack horizontal className='panelTitle' style={{ marginTop: 10 }}>
<span style={{ marginRight: 12 }}>{tableListIcon}</span>
<span>Trial jobs</span>
</Stack>
<Stack horizontal className="allList">
<Stack horizontal className='allList'>
<StackItem grow={50}>
<DefaultButton
text="Compare"
className="allList-compare"
text='Compare'
className='allList-compare'
// use child-component tableList's function, the function is in child-component.
onClick={(): void => { if (this.tableList) { this.tableList.compareBtn(); } }}
onClick={(): void => {
if (this.tableList) {
this.tableList.compareBtn();
}
}}
/>
</StackItem>
<StackItem grow={50}>
<Stack horizontal horizontalAlign="end" className="allList">
<Stack horizontal horizontalAlign='end' className='allList'>
<DefaultButton
className="allList-button-gap"
text="Add column"
onClick={(): void => { if (this.tableList) { this.tableList.addColumn(); } }}
className='allList-button-gap'
text='Add column'
onClick={(): void => {
if (this.tableList) {
this.tableList.addColumn();
}
}}
/>
<Dropdown
selectedKey={searchType}
......@@ -166,12 +178,12 @@ class TrialsDetail extends React.Component<{}, TrialDetailState> {
styles={{ root: { width: 150 } }}
/>
<input
type="text"
className="allList-search-input"
type='text'
className='allList-search-input'
placeholder={`Search by ${this.state.searchType}`}
onChange={this.searchTrial}
style={{ width: 230 }}
ref={(text): any => (this.searchInput) = text}
ref={(text): any => (this.searchInput = text)}
/>
</Stack>
</StackItem>
......@@ -183,11 +195,11 @@ class TrialsDetail extends React.Component<{}, TrialDetailState> {
changeColumn={value.changeColumn}
trialsUpdateBroadcast={this.context.trialsUpdateBroadcast}
// TODO: change any to specific type
ref={(tabList): any => this.tableList = tabList}
ref={(tabList): any => (this.tableList = tabList)}
/>
</div>
</React.Fragment>
}
)}
</AppContext.Consumer>
);
}
......
......@@ -17,7 +17,19 @@ const requency = { iconName: 'Timer' };
const closeTimer = { iconName: 'Blocked2' };
const LineChart = <Icon iconName='LineChart' />;
export { infoIcon, warining, errorBadge, completed, blocked,
infoIconAbout, copy, tableListIcon, downLoadIcon, timeIcon,
disableUpdates, requency, closeTimer, LineChart
export {
infoIcon,
warining,
errorBadge,
completed,
blocked,
infoIconAbout,
copy,
tableListIcon,
downLoadIcon,
timeIcon,
disableUpdates,
requency,
closeTimer,
LineChart
};
......@@ -21,17 +21,23 @@ interface CheckBoxItems {
onChange: () => void;
}
class ChangeColumnComponent extends React.Component<ChangeColumnProps, ChangeColumnState> {
constructor(props: ChangeColumnProps) {
super(props);
this.state = { userSelectColumnList: this.props.selectedColumn, originSelectColumnList: this.props.selectedColumn };
this.state = {
userSelectColumnList: this.props.selectedColumn,
originSelectColumnList: this.props.selectedColumn
};
}
makeChangeHandler = (label: string): any => {
return (ev: any, checked: boolean): void => this.onCheckboxChange(ev, label, checked);
}
};
onCheckboxChange = (ev: React.FormEvent<HTMLElement | HTMLInputElement> | undefined, label: string, val?: boolean, ): void => {
onCheckboxChange = (
ev: React.FormEvent<HTMLElement | HTMLInputElement> | undefined,
label: string,
val?: boolean
): void => {
const source: string[] = JSON.parse(JSON.stringify(this.state.userSelectColumnList));
if (val === true) {
if (!source.includes(label)) {
......@@ -41,7 +47,7 @@ class ChangeColumnComponent extends React.Component<ChangeColumnProps, ChangeCol
} else {
if (source.includes(label)) {
// remove from source
const result = source.filter((item) => item !== label);
const result = source.filter(item => item !== label);
this.setState(() => ({ userSelectColumnList: result }));
}
}
......@@ -88,11 +94,11 @@ class ChangeColumnComponent extends React.Component<ChangeColumnProps, ChangeCol
}
this.props.changeColumn(sortColumn);
this.hideDialog(); // hide dialog
}
};
hideDialog = (): void => {
this.props.hideShowColumnDialog();
}
};
// user exit dialog
cancelOption = (): void => {
......@@ -101,7 +107,7 @@ class ChangeColumnComponent extends React.Component<ChangeColumnProps, ChangeCol
this.setState({ userSelectColumnList: originSelectColumnList }, () => {
this.hideDialog();
});
}
};
render(): React.ReactNode {
const { showColumn, isHideDialog } = this.props;
......@@ -129,14 +135,14 @@ class ChangeColumnComponent extends React.Component<ChangeColumnProps, ChangeCol
styles: { main: { maxWidth: 450 } }
}}
>
<div className="columns-height">
<div className='columns-height'>
{renderOptions.map(item => {
return <Checkbox key={item.label} {...item} styles={{ root: { marginBottom: 8 } }} />
return <Checkbox key={item.label} {...item} styles={{ root: { marginBottom: 8 } }} />;
})}
</div>
<DialogFooter>
<PrimaryButton text="Save" onClick={this.saveUserSelectColumn} />
<DefaultButton text="Cancel" onClick={this.cancelOption} />
<PrimaryButton text='Save' onClick={this.saveUserSelectColumn} />
<DefaultButton text='Cancel' onClick={this.cancelOption} />
</DialogFooter>
</Dialog>
</div>
......
......@@ -20,7 +20,6 @@ interface CompareProps {
}
class Compare extends React.Component<CompareProps, {}> {
public _isCompareMount!: boolean;
constructor(props: CompareProps) {
super(props);
......@@ -41,7 +40,9 @@ class Compare extends React.Component<CompareProps, {}> {
idsList.push(element.id);
});
// find max intermediate number
trialIntermediate.sort((a, b) => { return (b.data.length - a.data.length); });
trialIntermediate.sort((a, b) => {
return b.data.length - a.data.length;
});
const legend: string[] = [];
// max length
const length = trialIntermediate[0] !== undefined ? trialIntermediate[0].data.length : 0;
......@@ -56,27 +57,35 @@ class Compare extends React.Component<CompareProps, {}> {
tooltip: {
trigger: 'item',
enterable: true,
position: function (point: number[], data: TooltipForIntermediate): number[] {
position: function(point: number[], data: TooltipForIntermediate): number[] {
if (data.dataIndex < length / 2) {
return [point[0], 80];
} else {
return [point[0] - 300, 80];
}
},
formatter: function (data: TooltipForIntermediate): React.ReactNode {
formatter: function(data: TooltipForIntermediate): React.ReactNode {
const trialId = data.seriesName;
let obj = {};
const temp = trialIntermediate.find(key => key.name === trialId);
if (temp !== undefined) {
obj = temp.hyperPara;
}
return '<div class="tooldetailAccuracy">' +
'<div>Trial ID: ' + trialId + '</div>' +
'<div>Intermediate: ' + data.data + '</div>' +
return (
'<div class="tooldetailAccuracy">' +
'<div>Trial ID: ' +
trialId +
'</div>' +
'<div>Intermediate: ' +
data.data +
'</div>' +
'<div>Parameters: ' +
'<pre>' + JSON.stringify(obj, null, 4) + '</pre>' +
'<pre>' +
JSON.stringify(obj, null, 4) +
'</pre>' +
'</div>' +
'</div>';
'</div>'
);
}
},
grid: {
......@@ -110,8 +119,7 @@ class Compare extends React.Component<CompareProps, {}> {
notMerge={true} // update now
/>
);
}
};
// render table column ---
initColumn = (): React.ReactNode => {
......@@ -134,8 +142,7 @@ class Compare extends React.Component<CompareProps, {}> {
});
let isComplexSearchSpace;
if (parameterList.length > 0) {
isComplexSearchSpace = (typeof parameterList[0][parameterKeys[0]] === 'object')
? true : false;
isComplexSearchSpace = typeof parameterList[0][parameterKeys[0]] === 'object' ? true : false;
}
const width = this.getWebUIWidth();
let scrollClass;
......@@ -150,70 +157,59 @@ class Compare extends React.Component<CompareProps, {}> {
<table className={`compare-modal-table ${scrollClass}`}>
<tbody>
<tr>
<td className="column">Id</td>
{Object.keys(idList).map(key => {
return (
<td className="value idList" key={key}>{idList[key]}</td>
);
})}
<td className='column'>Id</td>
{Object.keys(idList).map(key => (
<td className='value idList' key={key}>
{idList[key]}
</td>
))}
</tr>
<tr>
<td className="column">Trial No.</td>
{Object.keys(sequenceIdList).map(key => {
return (
<td className="value idList" key={key}>{sequenceIdList[key]}</td>
);
})}
<td className='column'>Trial No.</td>
{Object.keys(sequenceIdList).map(key => (
<td className='value idList' key={key}>
{sequenceIdList[key]}
</td>
))}
</tr>
<tr>
<td className="column">Default metric</td>
{Object.keys(compareStacks).map(index => {
const temp = compareStacks[index];
return (
<td className="value" key={index}>
<IntermediateVal trialId={temp.id} />
<td className='column'>Default metric</td>
{Object.keys(compareStacks).map(index => (
<td className='value' key={index}>
<IntermediateVal trialId={compareStacks[index].id} />
</td>
);
})}
))}
</tr>
<tr>
<td className="column">duration</td>
{Object.keys(durationList).map(index => {
return (
<td className="value" key={index}>{durationList[index]}</td>
);
})}
<td className='column'>duration</td>
{Object.keys(durationList).map(index => (
<td className='value' key={index}>
{durationList[index]}
</td>
))}
</tr>
{
isComplexSearchSpace
?
null
:
Object.keys(parameterKeys).map(index => {
return (
{isComplexSearchSpace
? null
: Object.keys(parameterKeys).map(index => (
<tr key={index}>
<td className="column" key={index}>{parameterKeys[index]}</td>
{
Object.keys(parameterList).map(key => {
return (
<td key={key} className="value">
<td className='column' key={index}>
{parameterKeys[index]}
</td>
{Object.keys(parameterList).map(key => (
<td key={key} className='value'>
{parameterList[key][parameterKeys[index]]}
</td>
);
})
}
))}
</tr>
);
})
}
))}
</tbody>
</table>
);
}
};
getWebUIWidth = (): number => {
return window.innerWidth;
}
};
componentDidMount(): void {
this._isCompareMount = true;
......@@ -230,7 +226,7 @@ class Compare extends React.Component<CompareProps, {}> {
<Modal
isOpen={true}
containerClassName={contentStyles.container}
className="compare-modal"
className='compare-modal'
allowTouchBodyScroll={true}
dragOptions={dragOptions}
>
......@@ -240,13 +236,13 @@ class Compare extends React.Component<CompareProps, {}> {
<IconButton
styles={iconButtonStyles}
iconProps={{ iconName: 'Cancel' }}
ariaLabel="Close popup modal"
ariaLabel='Close popup modal'
onClick={cancelFunc}
/>
</div>
<Stack className="compare-modal-intermediate">
<Stack className='compare-modal-intermediate'>
{this.intermediate()}
<Stack className="compare-yAxis"># Intermediate result</Stack>
<Stack className='compare-yAxis'># Intermediate result</Stack>
</Stack>
<Stack>{this.initColumn()}</Stack>
</div>
......
......@@ -25,7 +25,6 @@ interface CustomizeState {
}
class Customize extends React.Component<CustomizeProps, CustomizeState> {
constructor(props: CustomizeProps) {
super(props);
this.state = {
......@@ -36,17 +35,15 @@ class Customize extends React.Component<CustomizeProps, CustomizeState> {
copyTrialParameter: {},
customParameters: {},
customID: NaN,
changeMap: new Map
changeMap: new Map()
};
}
getFinalVal = (event: React.ChangeEvent<HTMLInputElement>): void => {
const { name, value } = event.target;
const { changeMap } = this.state;
this.setState({ changeMap: changeMap.set(name, value) });
}
};
// [submit click] user add a new trial [submit a trial]
addNewTrial = (): void => {
......@@ -54,7 +51,7 @@ class Customize extends React.Component<CustomizeProps, CustomizeState> {
// get user edited hyperParameter, ps: will change data type if you modify the input val
const customized = JSON.parse(JSON.stringify(copyTrialParameter));
// changeMap: user changed keys: values
changeMap.forEach(function (value, key) {
changeMap.forEach(function(value, key) {
customized[key] = value;
});
......@@ -72,14 +69,17 @@ class Customize extends React.Component<CustomizeProps, CustomizeState> {
return;
}
if (searchSpace[item]._type === 'choice') {
if (searchSpace[item]._value.find((val: string | number) =>
val === customized[item]) === undefined) {
if (
searchSpace[item]._value.find((val: string | number) => val === customized[item]) === undefined
) {
parametersIllegal = true;
return;
}
} else {
if (customized[item] < searchSpace[item]._value[0]
|| customized[item] > searchSpace[item]._value[1]) {
if (
customized[item] < searchSpace[item]._value[0] ||
customized[item] > searchSpace[item]._value[1]
) {
parametersIllegal = true;
return;
}
......@@ -93,18 +93,17 @@ class Customize extends React.Component<CustomizeProps, CustomizeState> {
// submit a customized job
this.submitCustomize(customized);
}
}
};
warningConfirm = (): void => {
this.setState(() => ({ isShowWarning: false }));
const { customParameters } = this.state;
this.submitCustomize(customParameters);
}
};
warningCancel = (): void => {
this.setState(() => ({ isShowWarning: false }));
}
};
submitCustomize = (customized: Record<string, any>): void => {
// delete `tag` key
......@@ -129,19 +128,19 @@ class Customize extends React.Component<CustomizeProps, CustomizeState> {
.catch(() => {
this.setState(() => ({ isShowSubmitFailed: true }));
});
}
};
closeSucceedHint = (): void => {
// also close customized trial modal
this.setState(() => ({ isShowSubmitSucceed: false, changeMap: new Map() }));
this.props.closeCustomizeModal();
}
};
closeFailedHint = (): void => {
// also close customized trial modal
this.setState(() => ({ isShowSubmitFailed: false, changeMap: new Map() }));
this.props.closeCustomizeModal();
}
};
componentDidMount(): void {
const { copyTrialId } = this.props;
......@@ -164,8 +163,9 @@ class Customize extends React.Component<CustomizeProps, CustomizeState> {
render(): React.ReactNode {
const { closeCustomizeModal, visible } = this.props;
const { isShowSubmitSucceed, isShowSubmitFailed, isShowWarning, customID, copyTrialParameter } = this.state;
const warning = 'The parameters you set are not in our search space, this may cause the tuner to crash, Are'
+ ' you sure you want to continue submitting?';
const warning =
'The parameters you set are not in our search space, this may cause the tuner to crash, Are' +
' you sure you want to continue submitting?';
return (
<Stack>
<Dialog
......@@ -180,23 +180,22 @@ class Customize extends React.Component<CustomizeProps, CustomizeState> {
styles: { main: { maxWidth: 450 } }
}}
>
<form className="hyper-box">
{
Object.keys(copyTrialParameter).map(item => (
<Stack horizontal key={item} className="hyper-form">
<StackItem styles={{ root: { minWidth: 100 } }} className="title">{item}</StackItem>
<StackItem className="inputs">
<form className='hyper-box'>
{Object.keys(copyTrialParameter).map(item => (
<Stack horizontal key={item} className='hyper-form'>
<StackItem styles={{ root: { minWidth: 100 } }} className='title'>
{item}
</StackItem>
<StackItem className='inputs'>
<input
type="text"
type='text'
name={item}
defaultValue={copyTrialParameter[item]}
onChange={this.getFinalVal}
/>
</StackItem>
</Stack>
)
)
}
))}
{/* disable [tag] because we havn't support */}
{/* <Stack key="tag" horizontal className="hyper-form tag-input">
<StackItem grow={9} className="title">Tag</StackItem>
......@@ -206,8 +205,8 @@ class Customize extends React.Component<CustomizeProps, CustomizeState> {
</Stack> */}
</form>
<DialogFooter>
<PrimaryButton text="Submit" onClick={this.addNewTrial} />
<DefaultButton text="Cancel" onClick={closeCustomizeModal} />
<PrimaryButton text='Submit' onClick={this.addNewTrial} />
<DefaultButton text='Cancel' onClick={closeCustomizeModal} />
</DialogFooter>
</Dialog>
......@@ -217,17 +216,22 @@ class Customize extends React.Component<CustomizeProps, CustomizeState> {
onDismiss={this.closeSucceedHint}
dialogContentProps={{
type: DialogType.normal,
title: <div className="icon-color">{completed}<b>Submit successfully</b></div>,
title: (
<div className='icon-color'>
{completed}
<b>Submit successfully</b>
</div>
),
closeButtonAriaLabel: 'Close',
subText: `You can find your customized trial by Trial No.${customID}`
}}
modalProps={{
isBlocking: false,
styles: { main: { minWidth: 500 } },
styles: { main: { minWidth: 500 } }
}}
>
<DialogFooter>
<PrimaryButton onClick={this.closeSucceedHint} text="OK" />
<PrimaryButton onClick={this.closeSucceedHint} text='OK' />
</DialogFooter>
</Dialog>
......@@ -236,17 +240,17 @@ class Customize extends React.Component<CustomizeProps, CustomizeState> {
onDismiss={this.closeSucceedHint}
dialogContentProps={{
type: DialogType.normal,
title: <div className="icon-error">{errorBadge}Submit Failed</div>,
title: <div className='icon-error'>{errorBadge}Submit Failed</div>,
closeButtonAriaLabel: 'Close',
subText: 'Unknown error.'
}}
modalProps={{
isBlocking: false,
styles: { main: { minWidth: 500 } },
styles: { main: { minWidth: 500 } }
}}
>
<DialogFooter>
<PrimaryButton onClick={this.closeFailedHint} text="OK" />
<PrimaryButton onClick={this.closeFailedHint} text='OK' />
</DialogFooter>
</Dialog>
......@@ -256,22 +260,21 @@ class Customize extends React.Component<CustomizeProps, CustomizeState> {
onDismiss={this.closeSucceedHint}
dialogContentProps={{
type: DialogType.normal,
title: <div className="icon-error">{warining}Warning</div>,
title: <div className='icon-error'>{warining}Warning</div>,
closeButtonAriaLabel: 'Close',
subText: `${warning}`
}}
modalProps={{
isBlocking: false,
styles: { main: { minWidth: 500 } },
styles: { main: { minWidth: 500 } }
}}
>
<DialogFooter>
<PrimaryButton onClick={this.warningConfirm} text="Confirm" />
<DefaultButton onClick={this.warningCancel} text="Cancel" />
<PrimaryButton onClick={this.warningConfirm} text='Confirm' />
<DefaultButton onClick={this.warningCancel} text='Cancel' />
</DialogFooter>
</Dialog>
</Stack>
);
}
}
......
import * as React from 'react';
import { downFile } from '../../static/function';
import {
Stack, PrimaryButton, DefaultButton, Panel, StackItem, Pivot, PivotItem
} from '@fluentui/react';
import { Stack, PrimaryButton, DefaultButton, Panel, StackItem, Pivot, PivotItem } from '@fluentui/react';
import { DRAWEROPTION } from '../../static/const';
import { EXPERIMENT, TRIALS } from '../../static/datamodel';
import MonacoEditor from 'react-monaco-editor';
......@@ -19,7 +17,6 @@ interface ExpDrawerState {
}
class ExperimentDrawer extends React.Component<ExpDrawerProps, ExpDrawerState> {
public _isExperimentMount!: boolean;
private refreshId!: number | undefined;
......@@ -60,21 +57,20 @@ class ExperimentDrawer extends React.Component<ExpDrawerProps, ExpDrawerState> {
}
if (['DONE', 'ERROR', 'STOPPED'].includes(EXPERIMENT.status)) {
if(this.refreshId !== null || this.refreshId !== undefined){
if (this.refreshId !== null || this.refreshId !== undefined) {
window.clearInterval(this.refreshId);
}
}
}
};
downExperimentParameters = (): void => {
const { experiment } = this.state;
downFile(experiment, 'experiment.json');
}
};
onWindowResize = (): void => {
this.setState(() => ({ expDrawerHeight: window.innerHeight }));
}
};
componentDidMount(): void {
this._isExperimentMount = true;
......@@ -93,7 +89,7 @@ class ExperimentDrawer extends React.Component<ExpDrawerProps, ExpDrawerState> {
const { closeExpDrawer } = this.props;
const { experiment, expDrawerHeight } = this.state;
return (
<Stack className="logDrawer">
<Stack className='logDrawer'>
<Panel
isOpen={true}
hasCloseButton={false}
......@@ -101,30 +97,24 @@ class ExperimentDrawer extends React.Component<ExpDrawerProps, ExpDrawerState> {
onLightDismissClick={closeExpDrawer}
styles={{ root: { height: expDrawerHeight, paddingTop: 15 } }}
>
<Pivot style={{ minHeight: 190 }} className="log-tab-body">
<PivotItem headerText="Experiment parameters">
<div className="just-for-log">
<Pivot style={{ minHeight: 190 }} className='log-tab-body'>
<PivotItem headerText='Experiment parameters'>
<div className='just-for-log'>
<MonacoEditor
width="100%"
width='100%'
// 92 + marginTop[16]
height={expDrawerHeight - 108}
language="json"
language='json'
value={experiment}
options={DRAWEROPTION}
/>
</div>
<Stack horizontal className="buttons">
<StackItem grow={50} className="download">
<PrimaryButton
text="Download"
onClick={this.downExperimentParameters}
/>
<Stack horizontal className='buttons'>
<StackItem grow={50} className='download'>
<PrimaryButton text='Download' onClick={this.downExperimentParameters} />
</StackItem>
<StackItem grow={50} className="close">
<DefaultButton
text="Close"
onClick={closeExpDrawer}
/>
<StackItem grow={50} className='close'>
<DefaultButton text='Close' onClick={closeExpDrawer} />
</StackItem>
</Stack>
</PivotItem>
......
import * as React from 'react';
import {
Stack, FocusTrapCallout, DefaultButton,
Stack,
FocusTrapCallout,
DefaultButton,
FocusZone,
PrimaryButton, getTheme, mergeStyleSets, FontWeights
PrimaryButton,
getTheme,
mergeStyleSets,
FontWeights
} from '@fluentui/react';
import { killJob } from '../../static/function';
import { blocked } from '../buttons/Icon';
......@@ -63,7 +68,6 @@ interface KillJobProps {
}
class KillJob extends React.Component<KillJobProps, KillJobState> {
private menuButtonElement!: HTMLElement | null;
constructor(props: KillJobProps) {
super(props);
......@@ -72,20 +76,20 @@ class KillJob extends React.Component<KillJobProps, KillJobState> {
onDismiss = (): void => {
this.setState(() => ({ isCalloutVisible: false }));
}
};
onKill = (): void => {
this.setState({ isCalloutVisible: false }, () => {
const { trial } = this.props;
killJob(trial.key, trial.id, trial.status);
});
}
};
openPromot = (event: React.SyntheticEvent<EventTarget>): void => {
event.preventDefault();
event.stopPropagation();
this.setState({ isCalloutVisible: true });
}
};
render(): React.ReactNode {
const { isCalloutVisible } = this.state;
......@@ -93,12 +97,14 @@ class KillJob extends React.Component<KillJobProps, KillJobState> {
return (
<div>
<div className={styles.buttonArea} ref={(menuButton): any => (this.menuButtonElement = menuButton)}>
<PrimaryButton className="detail-button-operation" onClick={this.openPromot} title="kill">{blocked}</PrimaryButton>
<PrimaryButton className='detail-button-operation' onClick={this.openPromot} title='kill'>
{blocked}
</PrimaryButton>
</div>
{isCalloutVisible ? (
<div>
<FocusTrapCallout
role="alertdialog"
role='alertdialog'
className={styles.callout}
gapSpace={0}
target={this.menuButtonElement}
......
import * as React from 'react';
import axios from 'axios';
import {
Stack, StackItem, Panel, PrimaryButton, DefaultButton,
Pivot, PivotItem
} from '@fluentui/react';
import { Stack, StackItem, Panel, PrimaryButton, DefaultButton, Pivot, PivotItem } from '@fluentui/react';
import { infoIcon } from '../buttons/Icon';
import { DOWNLOAD_IP } from '../../static/const';
import { downFile } from '../../static/function';
......@@ -40,44 +37,42 @@ class LogDrawer extends React.Component<LogDrawerProps, LogDrawerState> {
if (this.state.nniManagerLogStr !== null) {
downFile(this.state.nniManagerLogStr, 'nnimanager.log');
}
}
};
downloadDispatcher = (): void => {
if (this.state.dispatcherLogStr !== null) {
downFile(this.state.dispatcherLogStr, 'dispatcher.log');
}
}
};
dispatcherHTML = (): React.ReactNode => {
return (
dispatcherHTML = (): React.ReactNode => (
<div>
<span>Dispatcher log</span>
<span className="refresh" onClick={this.manualRefresh}>
<span className='refresh' onClick={this.manualRefresh}>
{infoIcon}
</span>
</div>
);
}
nnimanagerHTML = (): React.ReactNode => {
return (
nnimanagerHTML = (): React.ReactNode => (
<div>
<span>NNImanager log</span>
<span className="refresh" onClick={this.manualRefresh}>{infoIcon}</span>
<span className='refresh' onClick={this.manualRefresh}>
{infoIcon}
</span>
</div>
);
}
setLogDrawerHeight = (): void => {
this.setState(() => ({ logDrawerHeight: window.innerHeight - 48 }));
}
};
async componentDidMount(): Promise<void> {
this.refresh();
window.addEventListener('resize', this.setLogDrawerHeight);
}
componentWillUnmount(): void{
componentWillUnmount(): void {
window.clearTimeout(this.timerId);
window.removeEventListener('resize', this.setLogDrawerHeight);
}
......@@ -95,41 +90,38 @@ class LogDrawer extends React.Component<LogDrawerProps, LogDrawerState> {
isLightDismiss={true}
onLightDismissClick={closeDrawer}
>
<div className="log-tab-body">
<Pivot
selectedKey={activeTab}
style={{ minHeight: 190, paddingTop: '16px' }}
>
<div className='log-tab-body'>
<Pivot selectedKey={activeTab} style={{ minHeight: 190, paddingTop: '16px' }}>
{/* <PivotItem headerText={this.dispatcherHTML()} key="dispatcher" onLinkClick> */}
<PivotItem headerText="Dispatcher log" key="dispatcher">
<PivotItem headerText='Dispatcher log' key='dispatcher'>
<MonacoHTML
content={dispatcherLogStr || 'Loading...'}
loading={isLoading}
// paddingTop[16] + tab[44] + button[32]
height={logDrawerHeight - 92}
/>
<Stack horizontal className="buttons">
<StackItem grow={12} className="download">
<PrimaryButton text="Download" onClick={this.downloadDispatcher} />
<Stack horizontal className='buttons'>
<StackItem grow={12} className='download'>
<PrimaryButton text='Download' onClick={this.downloadDispatcher} />
</StackItem>
<StackItem grow={12} className="close">
<DefaultButton text="Close" onClick={closeDrawer} />
<StackItem grow={12} className='close'>
<DefaultButton text='Close' onClick={closeDrawer} />
</StackItem>
</Stack>
</PivotItem>
<PivotItem headerText="NNIManager log" key="nnimanager">
<PivotItem headerText='NNIManager log' key='nnimanager'>
{/* <TabPane tab="NNImanager Log" key="nnimanager"> */}
<MonacoHTML
content={nniManagerLogStr || 'Loading...'}
loading={isLoading}
height={logDrawerHeight - 92}
/>
<Stack horizontal className="buttons">
<StackItem grow={12} className="download">
<PrimaryButton text="Download" onClick={this.downloadNNImanager} />
<Stack horizontal className='buttons'>
<StackItem grow={12} className='download'>
<PrimaryButton text='Download' onClick={this.downloadNNImanager} />
</StackItem>
<StackItem grow={12} className="close">
<DefaultButton text="Close" onClick={closeDrawer} />
<StackItem grow={12} className='close'>
<DefaultButton text='Close' onClick={closeDrawer} />
</StackItem>
</Stack>
</PivotItem>
......@@ -158,12 +150,12 @@ class LogDrawer extends React.Component<LogDrawerProps, LogDrawerState> {
this.setState({ isLoading: false });
this.timerId = window.setTimeout(this.refresh, 10000);
});
}
};
private manualRefresh = (): void => {
this.setState({ isLoading: true });
this.refresh();
}
};
}
export default LogDrawer;
......@@ -8,7 +8,6 @@ interface MessageInfoProps {
}
class MessageInfo extends React.Component<MessageInfoProps, {}> {
constructor(props: MessageInfoProps) {
super(props);
}
......@@ -16,11 +15,7 @@ class MessageInfo extends React.Component<MessageInfoProps, {}> {
render(): React.ReactNode {
const { info, typeInfo, className } = this.props;
return (
<MessageBar
messageBarType={MessageBarType[typeInfo]}
isMultiline={true}
className={className}
>
<MessageBar messageBarType={MessageBarType[typeInfo]} isMultiline={true} className={className}>
{info}
</MessageBar>
);
......
/* resubmit confirm modal style */
.resubmit{
.title{
.resubmit {
.title {
font-size: 16px;
color: #000;
.color-warn, .color-error{
.color-warn,
.color-error {
color: red;
}
i{
i {
margin-right: 10px;
}
}
.hint{
.hint {
padding: 15px 0;
color: #333;
margin-left: 30px;
}
.color-succ{
.color-succ {
color: green;
}
}
.hyper-box{
.hyper-box {
padding: 16px 18px 16px 16px;
}
.hyper-form{
.hyper-form {
margin-bottom: 10px;
.title{
.title {
font-size: 14px;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
line-height: 40px;
}
.inputs{
.inputs {
height: 32px;
}
input{
input {
padding-left: 5px;
height: 32px;
}
}
.tag-input{
.tag-input {
margin-top: 25px;
}
/* submit & cancel buttons style*/
.modal-button{
/* submit & cancel buttons style */
.modal-button {
text-align: right;
height: 28px;
/* cancel button style*/
.cancelSty{
/* cancel button style */
.cancelSty {
width: 80px;
background-color: #dadada;
border: none;
color: #333;
}
.cancelSty:hover, .cancelSty:active, .cancelSty:focus{
.cancelSty:hover,
.cancelSty:active,
.cancelSty:focus {
background-color: #dadada;
}
.distance{
.distance {
margin-right: 8px;
}
}
.center{
.center {
text-align: center;
}
.icon-color{
i{
.icon-color {
i {
color: green;
}
}
.icon-error{
i{
.icon-error {
i {
color: red;
}
}
.icon-color, .icon-error{
i{
.icon-color,
.icon-error {
i {
margin-right: 10px;
position: relative;
top: 5px;
}
}
.ms-Dialog-subText{
.ms-Dialog-subText {
color: #333;
}
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