diff --git a/src/webui/src/App.css b/src/webui/src/App.css index d506354555..bc9b69e810 100644 --- a/src/webui/src/App.css +++ b/src/webui/src/App.css @@ -17,12 +17,17 @@ .headerCon{ min-width: 1024px; } +.contentBox{ + width: 100%; + background: #f2f2f2; +} .content{ width: 86%; min-width: 1024px; margin: 0 auto; margin-top: 74px; margin-bottom: 30px; + background: #fff; } diff --git a/src/webui/src/App.tsx b/src/webui/src/App.tsx index 23c3b70252..a013a9d258 100644 --- a/src/webui/src/App.tsx +++ b/src/webui/src/App.tsx @@ -6,16 +6,18 @@ import SlideBar from './components/SlideBar'; class App extends React.Component<{}, {}> { render() { return ( - + - + - + - + + {this.props.children} + ); diff --git a/src/webui/src/components/Overview.tsx b/src/webui/src/components/Overview.tsx index 7a0ed8cadb..ed1dad927d 100644 --- a/src/webui/src/components/Overview.tsx +++ b/src/webui/src/components/Overview.tsx @@ -215,6 +215,7 @@ class Overview extends React.Component<{}, OverviewState> { case 'USER_CANCELED': case 'SYS_CANCELED': + case 'EARLY_STOPPED': profile.stopTrial += 1; break; case 'SUCCEEDED': @@ -461,7 +462,10 @@ class Overview extends React.Component<{}, OverviewState> { - + diff --git a/src/webui/src/components/TrialsDetail.tsx b/src/webui/src/components/TrialsDetail.tsx index 0b614104df..a9590c7c22 100644 --- a/src/webui/src/components/TrialsDetail.tsx +++ b/src/webui/src/components/TrialsDetail.tsx @@ -21,6 +21,7 @@ interface TrialDetailState { isHasSearch: boolean; experimentStatus: string; entriesTable: number; + experimentPlatform: string; } class TrialsDetail extends React.Component<{}, TrialDetailState> { @@ -43,6 +44,7 @@ class TrialsDetail extends React.Component<{}, TrialDetailState> { experimentStatus: '', entriesTable: 20, isHasSearch: false, + experimentPlatform: '' }; } // trial accuracy graph @@ -370,6 +372,26 @@ class TrialsDetail extends React.Component<{}, TrialDetailState> { alert('TableList component was not properly initialized.'); } + checkExperimentPlatform = () => { + axios(`${MANAGER_IP}/experiment`, { + method: 'GET' + }) + .then(res => { + if (res.status === 200) { + const trainingPlatform = res.data.params.trainingServicePlatform !== undefined + ? + res.data.params.trainingServicePlatform + : + ''; + if (this._isMounted) { + this.setState({ + experimentPlatform: trainingPlatform + }); + } + } + }); + } + componentDidMount() { this._isMounted = true; @@ -377,6 +399,7 @@ class TrialsDetail extends React.Component<{}, TrialDetailState> { this.drawPointGraph(); this.interTableList = window.setInterval(this.drawTableList, 10000); this.interAccuracy = window.setInterval(this.drawPointGraph, 10000); + this.checkExperimentPlatform(); } componentWillUnmount() { @@ -386,7 +409,10 @@ class TrialsDetail extends React.Component<{}, TrialDetailState> { } render() { - const { accSource, accNodata, tableListSource, entriesTable, searchResultSource, isHasSearch } = this.state; + const { accSource, accNodata, tableListSource, + entriesTable, searchResultSource, isHasSearch, + experimentPlatform + } = this.state; const titleOfacc = ( ); @@ -463,6 +489,7 @@ class TrialsDetail extends React.Component<{}, TrialDetailState> { updateList={this.drawTableList} searchResult={searchResultSource} isHasSearch={isHasSearch} + platform={experimentPlatform} ref={(tabList) => this.tableList = tabList} /> diff --git a/src/webui/src/components/logPath/PaiTrialChild.tsx b/src/webui/src/components/logPath/PaiTrialChild.tsx new file mode 100644 index 0000000000..588599a6b6 --- /dev/null +++ b/src/webui/src/components/logPath/PaiTrialChild.tsx @@ -0,0 +1,55 @@ +import * as React from 'react'; +import { Row, Button } from 'antd'; +import { DOWNLOAD_IP } from '../../static/const'; + +interface PaiTrialChildProps { + logString: string; + id: string; + showLogModal: Function; + isdisLogbtn?: boolean; +} + +class PaiTrialChild extends React.Component { + + constructor(props: PaiTrialChildProps) { + super(props); + + } + + render() { + const { logString, id, showLogModal, isdisLogbtn } = this.props; + return ( +
+ { + logString === '' + ? +
+ : + + + + trial stdout + + + + + + + } +
+ ); + } +} + +export default PaiTrialChild; diff --git a/src/webui/src/components/logPath/PaiTrialLog.tsx b/src/webui/src/components/logPath/PaiTrialLog.tsx new file mode 100644 index 0000000000..42cf5f6774 --- /dev/null +++ b/src/webui/src/components/logPath/PaiTrialLog.tsx @@ -0,0 +1,72 @@ +import * as React from 'react'; +import { Row, Button } from 'antd'; +import { DOWNLOAD_IP } from '../../static/const'; +import PaiTrialChild from './PaiTrialChild'; + +interface PaitrialLogProps { + logStr: string; + id: string; + showLogModal: Function; + trialStatus?: string; + isdisLogbutton?: boolean; +} + +class PaitrialLog extends React.Component { + + constructor(props: PaitrialLogProps) { + super(props); + + } + + render() { + const { logStr, id, showLogModal, + isdisLogbutton + } = this.props; + const isTwopath = logStr.indexOf(',') !== -1 + ? + true + : + false; + return ( +
+
+ { + isTwopath + ? + + + + trial stdout + + hdfsLog + + + + + + : + + } +
+
+ ); + } +} + +export default PaitrialLog; diff --git a/src/webui/src/components/logPath/TrialLog.tsx b/src/webui/src/components/logPath/TrialLog.tsx new file mode 100644 index 0000000000..b2da64bf72 --- /dev/null +++ b/src/webui/src/components/logPath/TrialLog.tsx @@ -0,0 +1,30 @@ +import * as React from 'react'; +import LogPathChild from './LogPathChild'; + +interface TrialLogProps { + logStr: string; + id: string; +} + +class TrialLog extends React.Component { + + constructor(props: TrialLogProps) { + super(props); + + } + + render() { + const { logStr } = this.props; + + return ( +
+ +
+ ); + } +} + +export default TrialLog; diff --git a/src/webui/src/components/overview/Progress.tsx b/src/webui/src/components/overview/Progress.tsx index a0858403da..0e102dc50f 100644 --- a/src/webui/src/components/overview/Progress.tsx +++ b/src/webui/src/components/overview/Progress.tsx @@ -1,10 +1,6 @@ import * as React from 'react'; import { - Row, - Col, - Popover, - Button, - message + Row, Col, Popover, Button, message } from 'antd'; import axios from 'axios'; import { MANAGER_IP, CONTROLTYPE } from '../../static/const'; @@ -92,7 +88,8 @@ class Progressed extends React.Component { if (error.response.data.error) { message.error(error.response.data.error); } else { - message.error(`Update ${CONTROLTYPE[1].toLocaleLowerCase()} failed`); + message.error( + `Update ${CONTROLTYPE[1].toLocaleLowerCase()} failed`); } } }); @@ -179,29 +176,47 @@ class Progressed extends React.Component { return ( - -

Status

-
- {status} - { - status === 'ERROR' - ? - - i - - : - - } -
+

Status

+
+ {status} + { + status === 'ERROR' + ? + + i + + : + + } +
+
+ + + + +

best metric

+
{bestAccuracy.toFixed(6)}
- + {/* modify concurrency */} -

Concurrency

+

concurrency

{
- - - -

best metric

-
{bestAccuracy}
-
diff --git a/src/webui/src/components/overview/SuccessTable.tsx b/src/webui/src/components/overview/SuccessTable.tsx index 500e55b051..ba0ecc201d 100644 --- a/src/webui/src/components/overview/SuccessTable.tsx +++ b/src/webui/src/components/overview/SuccessTable.tsx @@ -1,24 +1,90 @@ import * as React from 'react'; +import axios from 'axios'; import JSONTree from 'react-json-tree'; -import { Table } from 'antd'; +import { Row, Modal, Input, Table, Tabs } from 'antd'; +const TabPane = Tabs.TabPane; +const { TextArea } = Input; +import { DOWNLOAD_IP } from '../../static/const'; import { TableObj } from '../../static/interface'; import { convertDuration } from '../../static/function'; +import PaiTrialLog from '../logPath/PaiTrialLog'; +import TrialLog from '../logPath/TrialLog'; import '../../static/style/tableStatus.css'; -import LogPath from '../logPath/LogPath'; +import '../../static/style/tableList.scss'; interface SuccessTableProps { tableSource: Array; + trainingPlatform: string; } -class SuccessTable extends React.Component { +interface SuccessTableState { + isShowLogModal: boolean; + logContent: string; +} + +class SuccessTable extends React.Component { + + public _isMounted = false; constructor(props: SuccessTableProps) { super(props); + this.state = { + isShowLogModal: false, + logContent: '' + }; + + } + + showLogModalOverview = (id: string) => { + axios(`${DOWNLOAD_IP}/trial_${id}.log`, { + method: 'GET' + }) + .then(res => { + if (res.status === 200) { + if (this._isMounted) { + this.setState(() => ({ + logContent: res.data + })); + } + } + }) + .catch(error => { + if (error.response.status === 500) { + if (this._isMounted) { + this.setState(() => ({ + logContent: 'failed to get log message' + })); + } + } + }); + if (this._isMounted) { + this.setState({ + isShowLogModal: true + }); + } + } + + hideLogModalOverview = () => { + if (this._isMounted) { + this.setState({ + isShowLogModal: false, + logContent: '' // close modal, delete data + }); + } + } + + componentDidMount() { + this._isMounted = true; + } + + componentWillUnmount() { + this._isMounted = false; } render() { - const { tableSource } = this.props; + const { tableSource, trainingPlatform } = this.props; + const { isShowLogModal, logContent } = this.state; let bgColor = ''; const columns = [{ @@ -114,22 +180,40 @@ class SuccessTable extends React.Component { 'This trial\'s logPath are not available.'; return (
-                    {
-                        isHasParameters
-                            ?
-                             true}  // default expandNode
-                                getItemString={() => ()}  // remove the {} items
-                                data={openRowDataSource}
-                            />
-                            :
-                            
- Error: - 'This trial's parameters are not available.' -
- } - + + + + { + isHasParameters + ? + true} // default expandNode + getItemString={() => ()} // remove the {} items + data={openRowDataSource} + /> + : +
+ Error: + 'This trial's parameters are not available.' +
+ } +
+ + { + trainingPlatform === 'pai' || trainingPlatform === 'kubeflow' + ? + + : + + } + +
+
); }; @@ -142,6 +226,23 @@ class SuccessTable extends React.Component { className="commonTableStyle" pagination={false} /> + {/* trial log modal */} + +
+