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

[webui] update the layout of overview page (#3123)


Co-authored-by: default avatarLijiao <Lijiaoa@outlook.com>
parent 580ce0a3
......@@ -47,6 +47,7 @@
"react-monaco-editor": "^0.32.1",
"react-paginate": "^6.3.2",
"react-pagination": "^1.0.0",
"react-responsive": "^8.1.1",
"react-router": "^5.2.0",
"react-router-dom": "^5.2.0",
"react-table": "^7.0.0-rc.15",
......
......@@ -18,6 +18,7 @@
.headerCon {
width: 90%;
max-width: 1490px;
margin: 0 auto;
}
......@@ -29,9 +30,10 @@
width: 87%;
margin: 0 auto;
min-width: 1200px;
max-width: 1490px;
/* nav bar: 56 + marginTop: 18 */
margin-top: 74px;
/* nav bar: 56 + marginTop: 24 */
margin-top: 80px;
margin-bottom: 30px;
}
......
......@@ -157,7 +157,7 @@ class NavCon extends React.Component<NavProps, NavState> {
</div>
<CommandBarButton
iconProps={{ iconName: 'ShowResults' }}
text='Experiment summary'
text='Summary'
onClick={this.showExpcontent}
/>
<CommandBarButton iconProps={infoIconAbout} text='About' menuProps={aboutProps} />
......
......@@ -174,12 +174,10 @@ class Overview extends React.Component<{}, OverviewState> {
/>
</div>
</div>
<div className='overviewCommand1'>
<Command1 />
</div>
<div className='overviewCommand2'>
<Stack className='overviewCommand' horizontal>
<Command2 />
</div>
<Command1 />
</Stack>
</div>
</div>
);
......
......@@ -39,7 +39,7 @@ class ExperimentSummaryPanel extends React.Component<ExpDrawerProps, ExpDrawerSt
const interResultList = TRIALS.getMetricsList();
Object.keys(trialMessagesArr).map(item => {
// not deal with trial's hyperParameters
const trialId = trialMessagesArr[item].jobId;
const trialId = trialMessagesArr[item].trialJobId;
// add intermediate result message
trialMessagesArr[item].intermediate = [];
Object.keys(interResultList).map(key => {
......@@ -94,7 +94,7 @@ class ExperimentSummaryPanel extends React.Component<ExpDrawerProps, ExpDrawerSt
return (
<Panel isOpen={true} hasCloseButton={false} isLightDismiss={true} onLightDismissClick={closeExpDrawer}>
<div className='panel'>
<div className='panelName'>Experiment summary</div>
<div className='panelName'>Summary</div>
<MonacoEditor
width='100%'
height={monacoEditorHeight}
......
import React from 'react';
import { EXPERIMENT } from '../../../static/datamodel';
import { rightEidtParam } from '../count/commonStyle';
import '../../../static/style/overview/command.scss';
export const Command1 = (): any => {
......@@ -33,7 +34,7 @@ export const Command1 = (): any => {
}
return (
<div className='basic'>
<div className='basic' style={rightEidtParam}>
<div>
<p className='command'>Training platform</p>
<div className='nowrap'>{EXPERIMENT.profile.params.trainingServicePlatform}</div>
......
import React from 'react';
import { TooltipHost, DirectionalHint } from '@fluentui/react';
import { EXPERIMENT } from '../../../static/datamodel';
import { leftProgress } from '../count/commonStyle';
import { TOOLTIP_BACKGROUND_COLOR } from '../../../static/const';
import '../../../static/style/overview/command.scss';
......@@ -21,7 +22,7 @@ export const Command2 = (): any => {
}
}
return (
<div className='basic'>
<div className='basic' style={leftProgress}>
<p className='command'>Log directory</p>
<div className='nowrap'>
<TooltipHost
......
......@@ -168,7 +168,7 @@ export const EditExperimentParam = (): any => {
return (
<React.Fragment>
<div className={`${editClassName} editparam`}>
<span>{value.title}</span>
<div className='title'>{value.title}</div>
<input
className={`${value.field} editparam-Input`}
ref={DurationInputRef}
......
......@@ -6,7 +6,7 @@ import { convertDuration, convertTimeAsUnit } from '../../../static/function';
import { EditExperimentParam } from './EditExperimentParam';
import { ExpDurationContext } from './ExpDurationContext';
import { EditExpeParamContext } from './context';
import { leftProgress, durationItem2, progressHeight } from './commonStyle';
import { leftProgress, rightEidtParam, progressHeight } from './commonStyle';
import '../../../static/style/overview/count.scss';
export const ExpDuration = (): any => (
......@@ -46,7 +46,7 @@ export const ExpDuration = (): any => (
<span>{`${maxExecDurationStr} ${maxDurationUnit}`}</span>
</div>
</div>
<div style={durationItem2}>
<div style={rightEidtParam}>
<EditExpeParamContext.Provider
value={{
editType: CONTROLTYPE[0],
......
......@@ -5,7 +5,7 @@ import { CONTROLTYPE, TOOLTIP_BACKGROUND_COLOR, MAX_TRIAL_NUMBERS } from '../../
import { EditExperimentParam } from './EditExperimentParam';
import { EditExpeParamContext } from './context';
import { ExpDurationContext } from './ExpDurationContext';
import { leftProgress, trialCountItem2, progressHeight } from './commonStyle';
import { leftProgress, rightEidtParam, progressHeight } from './commonStyle';
export const TrialCount = (): any => {
const count = TRIALS.countStatus();
......@@ -22,7 +22,7 @@ export const TrialCount = (): any => {
const { updateOverviewPage } = value;
return (
<React.Fragment>
<Stack horizontal horizontalAlign='space-between' className='ExpDuration'>
<Stack horizontal className='ExpDuration'>
<div style={leftProgress}>
<TooltipHost
content={`${bar2.toString()} trials`}
......@@ -49,7 +49,36 @@ export const TrialCount = (): any => {
<span>{maxTrialNum}</span>
</div>
</div>
<div style={trialCountItem2}>
</Stack>
<Stack horizontal className='marginTop'>
<div style={leftProgress}>
<Stack horizontal className='status-count' gap={60}>
<div>
<span>Running</span>
<p>{count.get('RUNNING')}</p>
</div>
<div>
<span>Succeeded</span>
<p>{count.get('SUCCEEDED')}</p>
</div>
<div>
<span>Stopped</span>
<p>{stoppedCount}</p>
</div>
</Stack>
<Stack horizontal className='status-count marginTop' gap={80}>
<div>
<span>Failed</span>
<p>{count.get('FAILED')}</p>
</div>
<div>
<span>Waiting</span>
<p>{count.get('WAITING')}</p>
</div>
</Stack>
</div>
<div style={rightEidtParam}>
<EditExpeParamContext.Provider
value={{
title: MAX_TRIAL_NUMBERS,
......@@ -65,42 +94,22 @@ export const TrialCount = (): any => {
<EditExperimentParam />
</div>
</EditExpeParamContext.Provider>
<EditExpeParamContext.Provider
value={{
title: 'Concurrency',
field: 'trialConcurrency',
editType: CONTROLTYPE[2],
// maxExecDuration: EXPERIMENT.profile.params.maxExecDuration,
maxExecDuration: '',
maxTrialNum: EXPERIMENT.profile.params.maxTrialNum,
trialConcurrency: EXPERIMENT.profile.params.trialConcurrency,
updateOverviewPage
}}
>
<EditExperimentParam />
</EditExpeParamContext.Provider>
</div>
</Stack>
<Stack horizontal horizontalAlign='space-between' className='trialStatus'>
<div className='basic'>
<p>Running</p>
<div>{count.get('RUNNING')}</div>
</div>
<div className='basic'>
<p>Succeeded</p>
<div>{count.get('SUCCEEDED')}</div>
</div>
<div className='basic'>
<p>Stopped</p>
<div>{stoppedCount}</div>
</div>
<div className='basic'>
<p>Failed</p>
<div>{count.get('FAILED')}</div>
</div>
<div className='basic'>
<p>Waiting</p>
<div>{count.get('WAITING')}</div>
<div className='concurrency'>
<EditExpeParamContext.Provider
value={{
title: 'Concurrency',
field: 'trialConcurrency',
editType: CONTROLTYPE[2],
// maxExecDuration: EXPERIMENT.profile.params.maxExecDuration,
maxExecDuration: '',
maxTrialNum: EXPERIMENT.profile.params.maxTrialNum,
trialConcurrency: EXPERIMENT.profile.params.trialConcurrency,
updateOverviewPage
}}
>
<EditExperimentParam />
</EditExpeParamContext.Provider>
</div>
</div>
</Stack>
</React.Fragment>
......
const leftProgress: React.CSSProperties = {
width: '33%',
position: 'relative',
top: 6
width: '60%',
position: 'relative'
};
const durationItem2: React.CSSProperties = {
width: '51.5%',
paddingLeft: '15%'
const rightEidtParam: React.CSSProperties = {
paddingLeft: '9%',
boxSizing: 'border-box'
};
const trialCountItem2: React.CSSProperties = {
width: '51.5%'
};
const progressHeight = 8;
export { leftProgress, durationItem2, trialCountItem2, progressHeight };
export { leftProgress, rightEidtParam, progressHeight };
......@@ -23,11 +23,11 @@ export const ReBasicInfo = (): any => {
return (
<div>
<Stack horizontal horizontalAlign='space-between' className='mess'>
<Stack horizontal horizontalAlign='space-between' className='marginTop'>
<div className='basic'>
<p>Name</p>
<div className='nowrap'>{EXPERIMENT.profile.params.experimentName}</div>
<p className='margin'>ID</p>
<p className='marginTop'>ID</p>
<div className='nowrap'>{EXPERIMENT.profile.id}</div>
</div>
<div className='basic'>
......@@ -76,7 +76,7 @@ export const ReBasicInfo = (): any => {
<BestMetricContext.Consumer>
{(value): React.ReactNode => (
<Stack className='bestMetric'>
<p className='margin'>Best metric</p>
<p className='marginTop'>Best metric</p>
<div className={EXPERIMENT.status}>
{isNaN(value.bestAccuracy) ? 'N/A' : value.bestAccuracy.toFixed(6)}
</div>
......@@ -87,7 +87,7 @@ export const ReBasicInfo = (): any => {
<div className='basic'>
<p>Start time</p>
<div className='nowrap'>{formatTimestamp(EXPERIMENT.profile.startTime)}</div>
<p className='margin'>End time</p>
<p className='marginTop'>End time</p>
<div className='nowrap'>{formatTimestamp(EXPERIMENT.profile.endTime)}</div>
</div>
</Stack>
......
......@@ -145,7 +145,7 @@ class SuccessTable extends React.Component<SuccessTableProps, SuccessTableState>
key: 'id',
fieldName: 'id',
minWidth: 60,
maxWidth: 118,
maxWidth: 90,
isResizable: true,
className: 'tableHead leftTitle',
data: 'string',
......@@ -155,8 +155,8 @@ class SuccessTable extends React.Component<SuccessTableProps, SuccessTableState>
{
name: 'Duration',
key: 'duration',
minWidth: 85,
maxWidth: 166,
minWidth: 80,
maxWidth: 120,
isResizable: true,
fieldName: 'duration',
data: 'number',
......@@ -170,8 +170,8 @@ class SuccessTable extends React.Component<SuccessTableProps, SuccessTableState>
{
name: 'Status',
key: 'status',
minWidth: 98,
maxWidth: 160,
minWidth: 88,
maxWidth: 120,
isResizable: true,
fieldName: 'status',
onRender: (item: any): React.ReactNode => (
......
import React, { useState, useCallback } from 'react';
import { Stack } from '@fluentui/react';
import { Stack, DefaultButton, Icon } from '@fluentui/react';
import MediaQuery from 'react-responsive';
import TrialConfigPanel from './TrialConfigPanel';
import LogPanel from '../modals/LogPanel';
import IconButtonTemplate from './IconButtonTemplet';
......@@ -28,9 +29,31 @@ export const SlideNavBtns = (): any => {
// right side nav buttons
<React.Fragment>
<Stack className='config'>
<IconButtonTemplate icon='DocumentSearch' btuName='Search space' event={showSearchSpacePanel} />
<IconButtonTemplate icon='Archive' btuName='Config' event={showTrialConfigpPanel} />
<IconButtonTemplate icon='FilePDB' btuName='Log files' event={showLogPanel} />
<MediaQuery maxWidth={1799}>
<IconButtonTemplate icon='DocumentSearch' btuName='Search space' event={showSearchSpacePanel} />
<IconButtonTemplate icon='Archive' btuName='Config' event={showTrialConfigpPanel} />
<IconButtonTemplate icon='FilePDB' btuName='Log files' event={showLogPanel} />
</MediaQuery>
<MediaQuery minWidth={1798}>
<div className='container'>
<DefaultButton onClick={showSearchSpacePanel} className='maxScrBtn'>
<Icon iconName='DocumentSearch' />
<span className='margin'>Search space</span>
</DefaultButton>
</div>
<div className='container'>
<DefaultButton onClick={showTrialConfigpPanel} className='maxScrBtn configBtn'>
<Icon iconName='Archive' />
<span className='margin'>Config</span>
</DefaultButton>
</div>
<div className='container'>
<DefaultButton onClick={showLogPanel} className='maxScrBtn logBtn'>
<Icon iconName='FilePDB' />
<span className='margin'>Log files</span>
</DefaultButton>
</div>
</MediaQuery>
</Stack>
{isShowConfigPanel && <TrialConfigPanel panelName={panelName} hideConfigPanel={hideConfigPanel} />}
{/* the panel for dispatcher & nnimanager log message */}
......
......@@ -171,6 +171,7 @@ class TrialManager {
let updated = false;
requestAxios(`${MANAGER_IP}/trial-jobs`)
.then(data => {
this.trialJobList = data;
for (const trialInfo of data as TrialJobInfo[]) {
if (this.trials.has(trialInfo.trialJobId)) {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
......
......@@ -8,7 +8,7 @@
.basic {
.lineMargin {
margin-top: 20px;
margin-top: 24px;
font-weight: normal;
}
}
$seriesIconMargin: 10px;
$margin: 24px;
.marginTop {
margin-top: $margin;
}
.ExpDuration {
margin-top: 20px;
margin-top: $margin;
.maxTrialNum {
margin-bottom: 10px;
}
.maxTrialNum {
margin-bottom: 10px;
}
}
.exp-progress {
margin-top: 16px;
margin-top: 9px;
.bold {
font-weight: 500;
}
.bold {
font-weight: 500;
}
.joiner {
padding: 0 3px;
}
}
.joiner {
padding: 0 3px;
}
.status-count {
span {
font-size: 14px;
color: #8f8f8f;
}
p {
font-size: 16px;
font-weight: 500;
color: #484848;
}
}
.maxTrialNum {
.editparam {
position: relative;
top: -7px;
}
.editparam {
position: relative;
top: -7px;
}
}
.noEditDuration {
position: relative;
top: -7px;
position: relative;
top: -7px;
}
.editDuration {
position: relative;
top: -17px;
position: relative;
top: -4px;
}
.concurrency {
.editparam {
margin-top: 5px;
}
}
.editparam {
&-Input {
width: 42px;
height: 32px;
padding-right: 5px;
text-align: right;
outline: none;
border: none;
border-bottom: 1px solid #ccc;
}
.maxExecDuration {
width: 36px;
}
&-dropdown {
width: 65px;
display: inline-block;
position: relative;
top: 13px;
left: 4px;
margin-right: 3px;
.ms-Dropdown-title {
padding-right: 0;
}
}
&-Input {
width: 42px;
height: 32px;
padding-right: 5px;
text-align: right;
outline: none;
border: none;
border-bottom: 1px solid #ccc;
}
.maxExecDuration {
width: 36px;
}
&-dropdown {
width: 65px;
display: inline-block;
position: relative;
top: 13px;
left: 4px;
margin-right: 3px;
.ms-Dropdown-title {
padding-right: 0;
}
}
}
.series {
position: relative;
top: 5px;
position: relative;
top: 5px;
i {
font-size: 20px;
font-weight: 700;
}
i {
font-size: 20px;
font-weight: 700;
}
.confirm {
margin: 0 $seriesIconMargin;
.confirm {
margin: 0 $seriesIconMargin;
i {
color: green;
}
}
i {
color: green;
}
}
}
.cancel i {
color: red;
font-size: 16px;
color: red;
font-size: 16px;
}
.edit i {
margin-left: 4px;
margin-left: 4px;
}
.overview input:disabled {
background: transparent;
border: none;
background: transparent;
border: none;
}
.info {
position: absolute;
z-index: 999;
left: 0;
}
.mess {
margin-top: 20px;
.basic p {
margin-top: 0;
}
p.margin {
margin-top: 20px;
}
}
.trialStatus {
margin-top: 8px;
position: absolute;
z-index: 999;
left: 0;
}
$boxPadding: 20px;
$boxPadding: 24px;
$boxBorderRadius: 5px;
$boxGapPadding: 10px;
.wrapper {
display: grid;
grid-template-columns: repeat(8, 1fr);
grid-auto-rows: 93px;
> div {
background: #fff;
padding: $boxPadding;
border-radius: $boxBorderRadius;
box-sizing: border-box;
}
.duration,
.trialCount {
grid-column: 1 / 5;
background: #fff;
padding: $boxPadding;
border-radius: $boxBorderRadius;
box-sizing: border-box;
margin-top: $boxGapPadding;
/* for alert message tooltip position */
position: relative;
}
.duration {
grid-row: 3 / 5;
height: 138px;
}
.trialCount {
grid-row: 4 / 6;
margin-top: 65px;
height: 239px;
}
.overviewCommand1,
.overviewCommand2 {
grid-row-start: 8;
margin-top: -59px;
margin-right: $boxGapPadding;
border-radius: 0;
}
.overviewCommand1 {
grid-column: 1 / 5;
border-radius: $boxBorderRadius 0 0 $boxBorderRadius;
}
.overviewCommand2 {
grid-column: 2 / 5;
margin-right: $boxGapPadding;
padding-left: 30px;
border-radius: 0 $boxBorderRadius $boxBorderRadius 0;
}
display: grid;
grid-template-columns: repeat(8, 1fr);
grid-auto-rows: 102px;
> div {
background: #fff;
padding: $boxPadding;
border-radius: $boxBorderRadius;
box-sizing: border-box;
}
.duration,
.trialCount {
grid-column: 1 / 5;
background: #fff;
padding: $boxPadding;
border-radius: $boxBorderRadius;
box-sizing: border-box;
margin-top: $boxGapPadding;
/* for alert message tooltip position */
position: relative;
}
.duration {
grid-row: 3 / 5;
height: 158px;
}
.trialCount {
grid-row: 5 / 8;
margin-top: -26px;
height: 273px;
}
.overviewCommand {
grid-column: 1 / 5;
grid-row-start: 8;
margin-top: -50px;
height: 158px;
margin-right: $boxGapPadding;
border-radius: $boxBorderRadius;
}
}
.overviewBasicInfo {
grid-column: 1 / 5;
grid-row: 1 / 3;
z-index: 2;
grid-column: 1 / 5;
grid-row: 1 / 3;
z-index: 2;
}
.overviewBasicInfo,
.duration,
.trialCount {
margin-right: $boxGapPadding;
margin-right: $boxGapPadding;
}
.basic {
line-height: 21px;
font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif;
p {
font-size: 14px;
color: #8f8f8f;
margin-top: 20px;
span {
color: #484848;
}
}
div {
font-size: 16px;
font-weight: 500;
color: #484848;
}
.nowrap {
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
line-height: 21px;
font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif;
p {
color: #8f8f8f;
font-size: 14px;
font-weight: normal;
span {
color: #484848;
}
}
div {
font-size: 16px;
font-weight: 500;
color: #484848;
}
.nowrap {
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
}
.overviewBestMetric {
grid-column: 5 / 9;
grid-row: 1 / 9;
max-height: 736px;
overflow: hidden;
.topTrialTitle {
width: 72%;
}
.active {
background: #d2d0ce;
}
.max {
margin-left: 7px;
}
.mincenter {
margin: 0 13px 0 $boxGapPadding;
}
.chooseEntry {
margin-right: $boxGapPadding;
line-height: 30px;
}
grid-column: 5 / 9;
grid-row: 1 / 10;
max-height: 822px;
overflow: hidden;
.topTrialTitle {
width: 72%;
}
.active {
background: #d2d0ce;
}
.max {
margin-left: 7px;
}
.mincenter {
margin: 0 13px 0 $boxGapPadding;
}
.chooseEntry {
margin-right: $boxGapPadding;
line-height: 30px;
}
}
.overviewCommand1,
.overviewCommand2 {
grid-row: 7 / 9;
height: 144px;
overflow: hidden;
margin-top: $boxGapPadding;
grid-row: 7 / 9;
height: 144px;
overflow: hidden;
margin-top: $boxGapPadding;
}
.overviewChart {
margin-top: 20px;
margin-top: 20px;
}
.defaultMetricContainer {
position: relative;
position: relative;
.showMess {
position: absolute;
top: 42%;
left: 48%;
}
.showMess {
position: absolute;
top: 42%;
left: 48%;
}
}
$buttonBorderRadius: 23px;
.config {
position: fixed;
right: 0;
z-index: 1000;
.ms-Button--default {
padding: 0 8px;
margin-bottom: 12px;
border: none;
box-shadow: 0 3px 3px rgba(0, 0, 0, 0.08);
border-radius: $buttonBorderRadius 0 0 $buttonBorderRadius;
font-size: 12px;
text-align: left;
.ms-Button-label {
font-weight: normal;
}
}
position: fixed;
right: 0;
z-index: 1000;
.integralBtn {
display: none;
}
.ms-Button--default {
padding: 0 8px;
margin-bottom: 12px;
border: none;
box-shadow: 0 3px 3px rgba(0, 0, 0, 0.08);
border-radius: $buttonBorderRadius 0 0 $buttonBorderRadius;
font-size: 12px;
text-align: left;
.ms-Button-label {
font-weight: normal;
}
}
.integralBtn {
display: none;
}
.margin {
margin-left: 10px;
}
.margin {
margin-left: 10px;
}
}
.container {
text-align: right;
text-align: right;
.icon {
min-width: 50px;
.icon {
min-width: 50px;
i {
font-size: 16px;
}
}
i {
font-size: 16px;
}
}
&:hover {
.icon {
display: none;
}
.integralBtn {
display: block;
color: #fff;
border: 1px solid blue;
background-color: #0071bc;
i {
font-size: 14px;
}
}
.maxScrBtn {
width: 150px;
&:hover {
color: #fff;
border: 1px solid blue;
background-color: #0071bc;
}
}
.configBtn i{
margin-left: -40px;
}
.logBtn i {
margin-left: -25px;
}
&:hover {
.icon {
display: none;
}
.integralBtn {
display: block;
color: #fff;
border: 1px solid blue;
background-color: #0071bc;
i {
font-size: 14px;
}
}
}
}
.ms-Fabric {
.ms-Panel-commands {
margin: 0;
}
.ms-Panel-commands {
margin: 0;
}
}
$tableHeight: 381px;
$tableHeight: 432px;
.scrollPanel {
height: $tableHeight;
......
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