Commit f437107d authored by Lijiao's avatar Lijiao Committed by fishyds
Browse files

[WebUI] Fix issue#458 about final result as dict (#563)

* [WebUI] Fix issue#458 about final result as dict

* Fix comments

* fix bug
parent 95d19478
......@@ -209,6 +209,10 @@ class Overview extends React.Component<{}, OverviewState> {
profile.failTrial += 1;
break;
case 'RUNNING':
profile.runTrial += 1;
break;
case 'USER_CANCELED':
case 'SYS_CANCELED':
profile.stopTrial += 1;
......
import * as React from 'react';
import axios from 'axios';
import { MANAGER_IP } from '../static/const';
import { Row, Col, Tabs, Input, Select } from 'antd';
import { Row, Col, Tabs, Input, Select, Button } from 'antd';
const Option = Select.Option;
import { TableObj, Parameters, DetailAccurPoint, TooltipForAccuracy } from '../static/interface';
import { getFinalResult } from '../static/function';
import { TableObjFianl, Parameters, DetailAccurPoint, TooltipForAccuracy } from '../static/interface';
import { getFinalResult, getFinal } from '../static/function';
import Accuracy from './overview/Accuracy';
import Duration from './trial-detail/Duration';
import Title1 from './overview/Title1';
......@@ -16,8 +16,8 @@ import '../static/style/trialsDetail.scss';
interface TrialDetailState {
accSource: object;
accNodata: string;
tableListSource: Array<TableObj>;
searchResultSource: Array<TableObj>;
tableListSource: Array<TableObjFianl>;
searchResultSource: Array<TableObjFianl>;
isHasSearch: boolean;
experimentStatus: string;
entriesTable: number;
......@@ -30,6 +30,8 @@ class TrialsDetail extends React.Component<{}, TrialDetailState> {
public interTableList = 1;
public interAllTableList = 2;
public tableList: TableList | null;
constructor(props: {}) {
super(props);
......@@ -40,7 +42,7 @@ class TrialsDetail extends React.Component<{}, TrialDetailState> {
searchResultSource: [],
experimentStatus: '',
entriesTable: 20,
isHasSearch: false
isHasSearch: false,
};
}
// trial accuracy graph
......@@ -132,7 +134,7 @@ class TrialsDetail extends React.Component<{}, TrialDetailState> {
.then(res => {
if (res.status === 200) {
const trialJobs = res.data;
const trialTable: Array<TableObj> = [];
const trialTable: Array<TableObjFianl> = [];
Object.keys(trialJobs).map(item => {
// only succeeded trials have finalMetricData
let desc: Parameters = {
......@@ -167,7 +169,7 @@ class TrialsDetail extends React.Component<{}, TrialDetailState> {
if (trialJobs[item].logPath !== undefined) {
desc.logPath = trialJobs[item].logPath;
}
const acc = getFinalResult(trialJobs[item].finalMetricData);
const acc = getFinal(trialJobs[item].finalMetricData);
trialTable.push({
key: trialTable.length,
sequenceId: trialJobs[item].sequenceId,
......@@ -185,7 +187,7 @@ class TrialsDetail extends React.Component<{}, TrialDetailState> {
Object.keys(searchResultSource).map(index => {
temp.push(searchResultSource[index].id);
});
const searchResultList: Array<TableObj> = [];
const searchResultList: Array<TableObjFianl> = [];
for (let i = 0; i < temp.length; i++) {
Object.keys(trialTable).map(key => {
const item = trialTable[key];
......@@ -217,7 +219,7 @@ class TrialsDetail extends React.Component<{}, TrialDetailState> {
.then(res => {
if (res.status === 200) {
const trialJobs = res.data;
const trialTable: Array<TableObj> = [];
const trialTable: Array<TableObjFianl> = [];
Object.keys(trialJobs).map(item => {
// only succeeded trials have finalMetricData
let desc: Parameters = {
......@@ -252,7 +254,7 @@ class TrialsDetail extends React.Component<{}, TrialDetailState> {
if (trialJobs[item].logPath !== undefined) {
desc.logPath = trialJobs[item].logPath;
}
const acc = getFinalResult(trialJobs[item].finalMetricData);
const acc = getFinal(trialJobs[item].finalMetricData);
trialTable.push({
key: trialTable.length,
sequenceId: trialJobs[item].sequenceId,
......@@ -308,7 +310,7 @@ class TrialsDetail extends React.Component<{}, TrialDetailState> {
} else {
window.clearInterval(this.interAllTableList);
const { tableListSource } = this.state;
const searchResultList: Array<TableObj> = [];
const searchResultList: Array<TableObjFianl> = [];
Object.keys(tableListSource).map(key => {
const item = tableListSource[key];
if (item.sequenceId.toString() === targetValue || item.id.includes(targetValue)) {
......@@ -364,6 +366,10 @@ class TrialsDetail extends React.Component<{}, TrialDetailState> {
}
}
test = () => {
alert('TableList component was not properly initialized.');
}
componentDidMount() {
this._isMounted = true;
......@@ -429,6 +435,17 @@ class TrialsDetail extends React.Component<{}, TrialDetailState> {
<span>entries</span>
</Col>
<Col span={12} className="right">
<Row>
<Col span={12}>
<Button
type="primary"
className="tableButton editStyle"
onClick={this.tableList ? this.tableList.addColumn : this.test}
>
AddColumn
</Button>
</Col>
<Col span={12}>
{/* <span>Search:</span> */}
<Input
type="text"
......@@ -438,12 +455,15 @@ class TrialsDetail extends React.Component<{}, TrialDetailState> {
/>
</Col>
</Row>
</Col>
</Row>
<TableList
entries={entriesTable}
tableSource={tableListSource}
updateList={this.drawTableList}
searchResult={searchResultSource}
isHasSearch={isHasSearch}
ref={(tabList) => this.tableList = tabList}
/>
</div>
);
......
......@@ -242,45 +242,45 @@ class Progressed extends React.Component<ProgressProps, ProgressState> {
maxString={`MaxTrialNumber: ${trialProfile.MaxTrialNum}`}
/>
<Row className="basic colorOfbasic mess">
<p>Best Default Metric</p>
<p>best metric</p>
<div>{bestAccuracy}</div>
</Row>
<Row className="mess">
<Col span={8}>
<Row className="basic colorOfbasic">
<p>Time Spent</p>
<p>spent</p>
<div>{convertTime(trialProfile.execDuration)}</div>
</Row>
</Col>
<Col span={9}>
<Row className="basic colorOfbasic">
<p>Remaining Time</p>
<p>remaining</p>
<div>{remaining}</div>
</Row>
</Col>
<Col span={7}>
<Row className="basic colorOfbasic">
<p>MaxDuration</p>
<div>{convertTime(trialProfile.maxDuration)}</div>
<p>running</p>
<div>{trialNumber.runTrial}</div>
</Row>
</Col>
</Row>
<Row className="mess">
<Col span={8}>
<Row className="basic colorOfbasic">
<p>Succeed Trial</p>
<p>succeed</p>
<div>{trialNumber.succTrial}</div>
</Row>
</Col>
<Col span={9}>
<Row className="basic">
<p>Stopped Trial</p>
<p>stopped</p>
<div>{trialNumber.stopTrial}</div>
</Row>
</Col>
<Col span={7}>
<Row className="basic">
<p>Failed Trial</p>
<p>failed</p>
<div>{trialNumber.failTrial}</div>
</Row>
</Col>
......
......@@ -2,11 +2,13 @@ import * as React from 'react';
import axios from 'axios';
import JSONTree from 'react-json-tree';
import ReactEcharts from 'echarts-for-react';
import { Row, Table, Button, Popconfirm, Modal, message } from 'antd';
import { MANAGER_IP, trialJobStatus } from '../../static/const';
import { Row, Table, Button, Popconfirm, Modal, message, Checkbox } from 'antd';
const CheckboxGroup = Checkbox.Group;
import { MANAGER_IP, trialJobStatus, COLUMN, COLUMN_INDEX } from '../../static/const';
import { convertDuration } from '../../static/function';
import { TableObj, TrialJob } from '../../static/interface';
import { TableObjFianl, TrialJob } from '../../static/interface';
import LogPath from '../logPath/LogPath';
import '../../static/style/search.scss';
require('../../static/style/tableStatus.css');
require('../../static/style/logPath.scss');
require('../../static/style/search.scss');
......@@ -22,8 +24,8 @@ echarts.registerTheme('my_theme', {
interface TableListProps {
entries: number;
tableSource: Array<TableObj>;
searchResult: Array<TableObj>;
tableSource: Array<TableObjFianl>;
searchResult: Array<TableObjFianl>;
updateList: Function;
isHasSearch: boolean;
}
......@@ -31,6 +33,14 @@ interface TableListProps {
interface TableListState {
intermediateOption: object;
modalVisible: boolean;
isObjFinal: boolean;
isShowColumn: boolean;
columnSelected: Array<string>; // user select columnKeys
}
interface ColumnIndex {
name: string;
index: number;
}
class TableList extends React.Component<TableListProps, TableListState> {
......@@ -41,7 +51,10 @@ class TableList extends React.Component<TableListProps, TableListState> {
this.state = {
intermediateOption: {},
modalVisible: false
modalVisible: false,
isObjFinal: false,
isShowColumn: false,
columnSelected: COLUMN,
};
}
......@@ -79,6 +92,14 @@ class TableList extends React.Component<TableListProps, TableListState> {
}
}
hideShowColumnModal = () => {
if (this._isMounted) {
this.setState({
isShowColumn: false
});
}
}
intermediateGraphOption = (intermediateArr: number[], id: string) => {
const sequence: number[] = [];
const lengthInter = intermediateArr.length;
......@@ -143,6 +164,67 @@ class TableList extends React.Component<TableListProps, TableListState> {
});
}
// click add column btn, just show the modal of addcolumn
addColumn = () => {
// show user select check button
if (this._isMounted) {
this.setState({
isShowColumn: true
});
}
}
// checkbox for coloumn
selectedColumn = (checkedValues: Array<string>) => {
let count = 6;
const want: Array<object> = [];
const finalKeys: Array<string> = [];
const wantResult: Array<string> = [];
Object.keys(checkedValues).map(m => {
switch (checkedValues[m]) {
case 'Trial No':
case 'id':
case 'duration':
case 'status':
case 'Operation':
case 'Default':
case 'Intermediate Result':
break;
default:
finalKeys.push(checkedValues[m]);
}
});
Object.keys(finalKeys).map(n => {
want.push({
name: finalKeys[n],
index: count++
});
});
Object.keys(checkedValues).map(item => {
const temp = checkedValues[item];
Object.keys(COLUMN_INDEX).map(key => {
const index = COLUMN_INDEX[key];
if (index.name === temp) {
want.push(index);
}
});
});
want.sort((a: ColumnIndex, b: ColumnIndex) => {
return a.index - b.index;
});
Object.keys(want).map(i => {
wantResult.push(want[i].name);
});
if (this._isMounted) {
this.setState(() => ({ columnSelected: wantResult }));
}
}
componentDidMount() {
this._isMounted = true;
}
......@@ -154,7 +236,27 @@ class TableList extends React.Component<TableListProps, TableListState> {
render() {
const { entries, tableSource, searchResult, isHasSearch } = this.props;
const { intermediateOption, modalVisible } = this.state;
const { intermediateOption, modalVisible, isShowColumn, columnSelected,
} = this.state;
let showTitle = COLUMN;
if (tableSource.length >= 1) {
const temp = tableSource[0].acc;
if (temp !== undefined && typeof temp === 'object') {
if (this._isMounted) {
// concat default column and finalkeys
const item = Object.keys(temp);
const want: Array<string> = [];
Object.keys(item).map(key => {
if (item[key] !== 'default') {
want.push(item[key]);
}
});
showTitle = COLUMN.concat(want);
}
}
}
let bgColor = '';
const trialJob: Array<TrialJob> = [];
trialJobStatus.map(item => {
......@@ -163,35 +265,47 @@ class TableList extends React.Component<TableListProps, TableListState> {
value: item
});
});
const columns = [{
const showColumn: Array<object> = [];
Object.keys(columnSelected).map(key => {
const item = columnSelected[key];
switch (item) {
case 'Trial No':
showColumn.push({
title: 'Trial No.',
dataIndex: 'sequenceId',
key: 'sequenceId',
width: 120,
className: 'tableHead',
sorter: (a: TableObj, b: TableObj) => (a.sequenceId as number) - (b.sequenceId as number)
}, {
sorter:
(a: TableObjFianl, b: TableObjFianl) =>
(a.sequenceId as number) - (b.sequenceId as number)
});
break;
case 'id':
showColumn.push({
title: 'Id',
dataIndex: 'id',
key: 'id',
width: 60,
className: 'tableHead idtitle',
// the sort of string
sorter: (a: TableObj, b: TableObj): number => a.id.localeCompare(b.id),
render: (text: string, record: TableObj) => {
sorter: (a: TableObjFianl, b: TableObjFianl): number => a.id.localeCompare(b.id),
render: (text: string, record: TableObjFianl) => {
return (
<div>{record.id}</div>
);
}
}, {
});
break;
case 'duration':
showColumn.push({
title: 'Duration',
dataIndex: 'duration',
key: 'duration',
width: 140,
// the sort of number
sorter: (a: TableObj, b: TableObj) => (a.duration as number) - (b.duration as number),
render: (text: string, record: TableObj) => {
sorter: (a: TableObjFianl, b: TableObjFianl) => (a.duration as number) - (b.duration as number),
render: (text: string, record: TableObjFianl) => {
let duration;
if (record.duration !== undefined && record.duration > 0) {
duration = convertDuration(record.duration);
......@@ -202,29 +316,44 @@ class TableList extends React.Component<TableListProps, TableListState> {
<div className="durationsty"><div>{duration}</div></div>
);
},
}, {
});
break;
case 'status':
showColumn.push({
title: 'Status',
dataIndex: 'status',
key: 'status',
width: 150,
className: 'tableStatus',
render: (text: string, record: TableObj) => {
render: (text: string, record: TableObjFianl) => {
bgColor = record.status;
return (
<span className={`${bgColor} commonStyle`}>{record.status}</span>
);
},
filters: trialJob,
onFilter: (value: string, record: TableObj) => record.status.indexOf(value) === 0,
sorter: (a: TableObj, b: TableObj): number => a.status.localeCompare(b.status)
}, {
onFilter: (value: string, record: TableObjFianl) => record.status.indexOf(value) === 0,
sorter: (a: TableObjFianl, b: TableObjFianl): number => a.status.localeCompare(b.status)
});
break;
case 'Default':
showColumn.push({
title: 'Default Metric',
dataIndex: 'acc',
key: 'acc',
width: 200,
sorter: (a: TableObj, b: TableObj) => (a.acc as number) - (b.acc as number),
render: (text: string, record: TableObj) => {
const accuracy = record.acc;
sorter: (a: TableObjFianl, b: TableObjFianl) => {
if (a.acc !== undefined && b.acc !== undefined) {
return JSON.parse(a.acc.default) - JSON.parse(b.acc.default);
} else {
return NaN;
}
},
render: (text: string, record: TableObjFianl) => {
let accuracy;
if (record.acc !== undefined) {
accuracy = record.acc.default;
}
let wei = 0;
if (accuracy) {
if (accuracy.toString().indexOf('.') !== -1) {
......@@ -234,25 +363,28 @@ class TableList extends React.Component<TableListProps, TableListState> {
return (
<div>
{
record.acc
record.acc && record.acc.default
?
wei > 6
?
record.acc.toFixed(6)
JSON.parse(record.acc.default).toFixed(6)
:
record.acc
record.acc.default
:
'--'
}
</div>
);
}
}, {
});
break;
case 'Operation':
showColumn.push({
title: 'Operation',
dataIndex: 'operation',
key: 'operation',
width: 90,
render: (text: string, record: TableObj) => {
render: (text: string, record: TableObjFianl) => {
let trialStatus = record.status;
let flagKill = false;
if (trialStatus === 'RUNNING') {
......@@ -283,12 +415,16 @@ class TableList extends React.Component<TableListProps, TableListState> {
)
);
},
}, {
});
break;
case 'Intermediate Result':
showColumn.push({
title: 'Intermediate Result',
dataIndex: 'intermediate',
key: 'intermediate',
width: '16%',
render: (text: string, record: TableObj) => {
render: (text: string, record: TableObjFianl) => {
return (
<Button
type="primary"
......@@ -299,10 +435,32 @@ class TableList extends React.Component<TableListProps, TableListState> {
</Button>
);
},
});
break;
default:
showColumn.push({
title: item,
dataIndex: item,
key: item,
width: 150,
render: (text: string, record: TableObjFianl) => {
return (
<div>
{
record.acc
?
record.acc[item]
:
'--'
}
</div>
);
}
];
});
}
});
const openRow = (record: TableObj) => {
const openRow = (record: TableObjFianl) => {
let isHasParameters = true;
if (record.description.parameters.error) {
isHasParameters = false;
......@@ -341,12 +499,13 @@ class TableList extends React.Component<TableListProps, TableListState> {
<Row className="tableList">
<div id="tableList">
<Table
columns={columns}
columns={showColumn}
expandedRowRender={openRow}
dataSource={isHasSearch ? searchResult : tableSource}
className="commonTableStyle"
pagination={{ pageSize: entries }}
/>
{/* Intermediate Result Modal */}
<Modal
title="Intermediate Result"
visible={modalVisible}
......@@ -365,6 +524,22 @@ class TableList extends React.Component<TableListProps, TableListState> {
/>
</Modal>
</div>
{/* Add Column Modal */}
<Modal
title="Table Title"
visible={isShowColumn}
onCancel={this.hideShowColumnModal}
footer={null}
destroyOnClose={true}
width="40%"
>
<CheckboxGroup
options={showTitle}
defaultValue={columnSelected}
onChange={this.selectedColumn}
className="titleColumn"
/>
</Modal>
</Row>
);
}
......
export const MANAGER_IP = `/api/v1/nni`;
export const DOWNLOAD_IP = `/logs`;
export const trialJobStatus = [
const MANAGER_IP = `/api/v1/nni`;
const DOWNLOAD_IP = `/logs`;
const trialJobStatus = [
'UNKNOWN',
'WAITING',
'RUNNING',
......@@ -10,12 +10,47 @@ export const trialJobStatus = [
'SYS_CANCELED',
'EARLY_STOPPED'
];
export const CONTROLTYPE = [
const CONTROLTYPE = [
'SEARCH_SPACE',
'TRIAL_CONCURRENCY',
'MAX_EXEC_DURATION'
];
export const MONACO = {
const MONACO = {
readOnly: true,
automaticLayout: true
};
const COLUMN_INDEX = [
{
name: 'Trial No',
index: 1
},
{
name: 'id',
index: 2
},
{
name: 'duration',
index: 3
},
{
name: 'status',
index: 4
},
{
name: 'Default',
index: 5
},
{
name: 'Operation',
index: 10000
},
{
name: 'Intermediate Result',
index: 10001
}
];
const COLUMN = ['Trial No', 'id', 'duration', 'status', 'Default', 'Operation', 'Intermediate Result'];
export {
MANAGER_IP, DOWNLOAD_IP, trialJobStatus,
CONTROLTYPE, MONACO, COLUMN, COLUMN_INDEX
};
import { FinalResult } from './interface';
import { FinalResult, FinalType } from './interface';
const convertTime = (num: number) => {
if (num % 3600 === 0) {
......@@ -28,6 +28,7 @@ const convertDuration = (num: number) => {
};
// get final result value
// draw Accuracy point graph
const getFinalResult = (final: FinalResult) => {
let acc;
let showDefault = 0;
......@@ -46,6 +47,21 @@ const getFinalResult = (final: FinalResult) => {
}
};
// get final result value // acc obj
const getFinal = (final: FinalResult) => {
let showDefault: FinalType;
if (final) {
showDefault = JSON.parse(final[0].data);
if (typeof showDefault === 'number') {
showDefault = { default: showDefault };
}
return showDefault;
} else {
return undefined;
}
};
export {
convertTime, convertDuration, getFinalResult
convertTime, convertDuration, getFinalResult,
getFinal
};
// draw accuracy graph data interface
interface TableObj {
key: number;
sequenceId: number;
id: string;
duration: number;
status: string;
acc?: number;
acc?: number; // draw accuracy graph
description: Parameters;
color?: string;
}
interface TableObjFianl {
key: number;
sequenceId: number;
id: string;
duration: number;
status: string;
acc?: FinalType;
description: Parameters;
color?: string;
}
interface FinalType {
default: string;
}
interface ErrorParameter {
error?: string;
}
interface Parameters {
parameters: ErrorParameter;
logPath?: string;
......@@ -93,5 +111,6 @@ export {
TableObj, Parameters, Experiment,
AccurPoint, TrialNumber, TrialJob,
DetailAccurPoint, TooltipForAccuracy,
ParaObj, VisualMapValue, Dimobj, FinalResult
ParaObj, VisualMapValue, Dimobj, FinalResult,
TableObjFianl, FinalType
};
/* some buttons about trial-detail table */
.allList{
width: 96%;
margin: 0 auto;
......@@ -17,4 +18,17 @@
}
}
.titleColumn{
.ant-checkbox-group-item{
display: block;
}
}
.applyfooter{
/* apply button style */
.apply{
text-align: right;
}
}
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