Skip to content
This repository has been archived by the owner on Sep 18, 2024. It is now read-only.

Commit

Permalink
Multiple Experiments Management UX (#3127)
Browse files Browse the repository at this point in the history
* first update

* add click event

* add manager exp nav

* first demo, fix some comments

* use api to dev

* refactor code

* fix lint

* fix test met issue and adjust column width

* add /experiments-info  error status

* no declare platform list, get this from api result filter

* fix compare tooltip issue

* fix tooltip location

* fix some comments

* delete datestring

* fix clickable style and clickable column ID rather than name

Co-authored-by: Lijiao <Lijiaoa@outlook.com>
  • Loading branch information
Lijiaoa and Lijiao authored Dec 14, 2020
1 parent af19888 commit 683c458
Show file tree
Hide file tree
Showing 35 changed files with 2,265 additions and 1,467 deletions.
2 changes: 2 additions & 0 deletions ts/webui/src/App.scss
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

.headerCon {
width: 90%;
min-width: 1200px;
max-width: 1490px;
margin: 0 auto;
}
Expand All @@ -28,6 +29,7 @@

.content {
width: 87%;
min-height: calc(100vh - 56);
margin: 0 auto;
min-width: 1200px;
max-width: 1490px;
Expand Down
127 changes: 58 additions & 69 deletions ts/webui/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import * as React from 'react';
import { Stack } from '@fluentui/react';
import { COLUMN } from './static/const';
import { EXPERIMENT, TRIALS } from './static/datamodel';
import { isManagerExperimentPage } from './static/function';
import NavCon from './components/NavCon';
import MessageInfo from './components/modals/MessageInfo';
import { SlideNavBtns } from './components/slideNav/SlideNavBtns';
Expand Down Expand Up @@ -29,15 +30,15 @@ export const AppContext = React.createContext({
metricGraphMode: 'max',
bestTrialEntries: '10',
maxDurationUnit: 'm',
// 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') => {},
// eslint-disable-next-line @typescript-eslint/no-empty-function, @typescript-eslint/no-unused-vars
changeMaxDurationUnit: (val: string) => {},
// eslint-disable-next-line @typescript-eslint/no-empty-function, @typescript-eslint/no-unused-vars
changeEntries: (val: string) => {},
// eslint-disable-next-line @typescript-eslint/no-empty-function, @typescript-eslint/no-unused-vars
// eslint-disable-next-line @typescript-eslint/no-empty-function
changeColumn: (_val: string[]): void => {},
// eslint-disable-next-line @typescript-eslint/no-empty-function
changeMetricGraphMode: (_val: 'max' | 'min'): void => {},
// eslint-disable-next-line @typescript-eslint/no-empty-function
changeMaxDurationUnit: (_val: string): void => {},
// eslint-disable-next-line @typescript-eslint/no-empty-function
changeEntries: (_val: string): void => {},
// eslint-disable-next-line @typescript-eslint/no-empty-function
updateOverviewPage: () => {}
});

Expand Down Expand Up @@ -139,69 +140,57 @@ class App extends React.Component<{}, AppState> {
{ errorWhere: TRIALS.latestMetricDataError(), errorMessage: TRIALS.getLatestMetricDataErrorMessage() },
{ errorWhere: TRIALS.metricDataRangeError(), errorMessage: TRIALS.metricDataRangeErrorMessage() }
];

return (
<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'>
{/* search space & config */}
<AppContext.Provider
value={{
interval,
columnList,
changeColumn: this.changeColumn,
experimentUpdateBroadcast,
trialsUpdateBroadcast,
metricGraphMode,
maxDurationUnit,
changeMaxDurationUnit: this.changeMaxDurationUnit,
changeMetricGraphMode: this.changeMetricGraphMode,
bestTrialEntries,
changeEntries: this.changeEntries,
updateOverviewPage: this.updateOverviewPage
}}
>
<SlideNavBtns />
</AppContext.Provider>
{/* if api has error field, show error message */}
{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' />
<React.Fragment>
{isManagerExperimentPage() ? null : (
<Stack className='nni' style={{ minHeight: window.innerHeight }}>
<div className='header'>
<div className='headerCon'>
<NavCon changeInterval={this.changeInterval} refreshFunction={this.lastRefresh} />
</div>
)}
<AppContext.Provider
value={{
interval,
columnList,
changeColumn: this.changeColumn,
experimentUpdateBroadcast,
trialsUpdateBroadcast,
metricGraphMode,
maxDurationUnit,
changeMaxDurationUnit: this.changeMaxDurationUnit,
changeMetricGraphMode: this.changeMetricGraphMode,
bestTrialEntries,
changeEntries: this.changeEntries,
updateOverviewPage: this.updateOverviewPage
}}
>
{this.props.children}
</AppContext.Provider>
</div>
<Stack className='contentBox'>
<Stack className='content'>
{/* search space & config */}
<SlideNavBtns />
{/* if api has error field, show error message */}
{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={{
interval,
columnList,
changeColumn: this.changeColumn,
experimentUpdateBroadcast,
trialsUpdateBroadcast,
metricGraphMode,
maxDurationUnit,
changeMaxDurationUnit: this.changeMaxDurationUnit,
changeMetricGraphMode: this.changeMetricGraphMode,
bestTrialEntries,
changeEntries: this.changeEntries,
updateOverviewPage: this.updateOverviewPage
}}
>
{this.props.children}
</AppContext.Provider>
</Stack>
</Stack>
</Stack>
</Stack>
</Stack>
)}
</React.Fragment>
);
}

Expand Down
101 changes: 45 additions & 56 deletions ts/webui/src/components/NavCon.tsx
Original file line number Diff line number Diff line change
@@ -1,35 +1,16 @@
import * as React from 'react';
import axios from 'axios';
import { WEBUIDOC, MANAGER_IP } from '../static/const';
import {
Stack,
initializeIcons,
StackItem,
CommandBarButton,
IContextualMenuProps,
IStackTokens,
IStackStyles
} from '@fluentui/react';
import { Stack, StackItem, CommandBarButton, IContextualMenuProps } from '@fluentui/react';
import { Link } from 'react-router-dom';
import { infoIconAbout, timeIcon, disableUpdates, requency, closeTimer, ChevronRightMed } from './buttons/Icon';
import ExperimentSummaryPanel from './modals/ExperimentSummaryPanel';
import { infoIconAbout, timeIcon, disableUpdates, requency, closeTimer } from './buttons/Icon';
import { OVERVIEWTABS, DETAILTABS, NNILOGO } from './stateless-component/NNItabs';
import { EXPERIMENT } from '../static/datamodel';
import { stackTokens, stackStyle } from './NavConst';
import '../static/style/nav/nav.scss';
import '../static/style/icon.scss';

initializeIcons();
const stackTokens: IStackTokens = {
childrenGap: 15
};
const stackStyle: IStackStyles = {
root: {
minWidth: 400,
height: 56,
display: 'flex',
verticalAlign: 'center'
}
};

interface NavState {
version: string;
menuVisible: boolean;
Expand Down Expand Up @@ -133,42 +114,50 @@ class NavCon extends React.Component<NavProps, NavState> {
};
return (
<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>{DETAILTABS}</span>
</StackItem>
<StackItem grow={70} className='navOptions'>
<Stack horizontal horizontalAlign='end' tokens={stackTokens} styles={stackStyle}>
{/* refresh button danyi*/}
{/* TODO: fix bug */}
{/* <CommandBarButton
iconProps={{ iconName: 'sync' }}
text="Refresh"
onClick={this.props.refreshFunction}
/> */}
<div className='nav-refresh'>
<React.Fragment>
<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>{DETAILTABS}</span>
</StackItem>
<StackItem grow={70} className='navOptions'>
<Stack horizontal horizontalAlign='end' tokens={stackTokens} styles={stackStyle}>
{/* refresh button danyi*/}
{/* TODO: fix bug */}
{/* <CommandBarButton
iconProps={{ iconName: 'sync' }}
text="Refresh"
onClick={this.props.refreshFunction}
/> */}
<div className='nav-refresh'>
<CommandBarButton
iconProps={refreshFrequency === '' ? disableUpdates : timeIcon}
text={refreshText}
menuProps={this.refreshProps}
/>
<div className='nav-refresh-num'>{refreshFrequency}</div>
</div>
<CommandBarButton
iconProps={refreshFrequency === '' ? disableUpdates : timeIcon}
text={refreshText}
menuProps={this.refreshProps}
iconProps={{ iconName: 'ShowResults' }}
text='Experiment summary'
onClick={this.showExpcontent}
/>
<div className='nav-refresh-num'>{refreshFrequency}</div>
</div>
<CommandBarButton
iconProps={{ iconName: 'ShowResults' }}
text='Summary'
onClick={this.showExpcontent}
<CommandBarButton iconProps={infoIconAbout} text='About' menuProps={aboutProps} />
<Link to='/experiment' className='experiment'>
<div className='expNavTitle'>
<span>All experiment</span>
{ChevronRightMed}
</div>
</Link>
</Stack>
</StackItem>
{isvisibleExperimentDrawer && (
<ExperimentSummaryPanel
closeExpDrawer={this.closeExpDrawer}
experimentProfile={EXPERIMENT.profile}
/>
<CommandBarButton iconProps={infoIconAbout} text='About' menuProps={aboutProps} />
</Stack>
</StackItem>
{isvisibleExperimentDrawer && (
<ExperimentSummaryPanel
closeExpDrawer={this.closeExpDrawer}
experimentProfile={EXPERIMENT.profile}
/>
)}
)}
</React.Fragment>
</Stack>
);
}
Expand Down
15 changes: 15 additions & 0 deletions ts/webui/src/components/NavConst.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { IStackTokens, IStackStyles } from '@fluentui/react';

const stackTokens: IStackTokens = {
childrenGap: 15
};
const stackStyle: IStackStyles = {
root: {
minWidth: 400,
height: 56,
display: 'flex',
verticalAlign: 'center'
}
};

export { stackTokens, stackStyle };
4 changes: 2 additions & 2 deletions ts/webui/src/components/Overview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { AppContext } from '../App';
import { Title } from './overview/Title';
import SuccessTable from './overview/table/SuccessTable';
import Accuracy from './overview/Accuracy';
import { ReBasicInfo } from './overview/experiment/BasicInfo';
import { BasicInfo } from './overview/params/BasicInfo';
import { ExpDuration } from './overview/count/ExpDuration';
import { ExpDurationContext } from './overview/count/ExpDurationContext';
import { TrialCount } from './overview/count/TrialCount';
Expand Down Expand Up @@ -86,7 +86,7 @@ class Overview extends React.Component<{}, OverviewState> {
<Title />
</TitleContext.Provider>
<BestMetricContext.Provider value={{ bestAccuracy: bestAccuracy }}>
<ReBasicInfo />
<BasicInfo />
</BestMetricContext.Provider>
</div>
{/* duration & trial numbers */}
Expand Down
8 changes: 7 additions & 1 deletion ts/webui/src/components/buttons/Icon.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ const LineChart = <Icon iconName='LineChart' />;
const Edit = <Icon iconName='Edit' />;
const CheckMark = <Icon iconName='CheckMark' />;
const Cancel = <Icon iconName='Cancel' />;
const ReplyAll = { iconName: 'ReplyAll' };
const RevToggleKey = { iconName: 'RevToggleKey' };
const ChevronRightMed = <Icon iconName='ChevronRightMed' />;

export {
infoIcon,
Expand All @@ -37,5 +40,8 @@ export {
LineChart,
Edit,
CheckMark,
Cancel
Cancel,
ReplyAll,
RevToggleKey,
ChevronRightMed
};
Loading

0 comments on commit 683c458

Please sign in to comment.