diff --git a/src/webui/src/components/Modals/ExperimentDrawer.tsx b/src/webui/src/components/Modals/ExperimentPanel.tsx similarity index 56% rename from src/webui/src/components/Modals/ExperimentDrawer.tsx rename to src/webui/src/components/Modals/ExperimentPanel.tsx index 142af89f59..cbc674ec9a 100644 --- a/src/webui/src/components/Modals/ExperimentDrawer.tsx +++ b/src/webui/src/components/Modals/ExperimentPanel.tsx @@ -1,17 +1,16 @@ import * as React from 'react'; -import axios from 'axios'; import { downFile } from '../../static/function'; import { Stack, PrimaryButton, DefaultButton, Panel, StackItem, Pivot, PivotItem } from 'office-ui-fabric-react'; -import { MANAGER_IP, DRAWEROPTION } from '../../static/const'; +import { DRAWEROPTION } from '../../static/const'; +import { EXPERIMENT, TRIALS } from '../../static/datamodel'; import MonacoEditor from 'react-monaco-editor'; import '../../static/style/logDrawer.scss'; -import { TrialManager } from '../../static/model/trialmanager'; interface ExpDrawerProps { - isVisble: boolean; closeExpDrawer: () => void; + experimentProfile: object; } interface ExpDrawerState { @@ -21,7 +20,9 @@ interface ExpDrawerState { class ExperimentDrawer extends React.Component { - public _isCompareMount!: boolean; + public _isExperimentMount!: boolean; + private refreshId!: number | undefined; + constructor(props: ExpDrawerProps) { super(props); @@ -32,42 +33,40 @@ class ExperimentDrawer extends React.Component { } getExperimentContent = (): void => { - axios - .all([ - axios.get(`${MANAGER_IP}/experiment`), - axios.get(`${MANAGER_IP}/trial-jobs`), - axios.get(`${MANAGER_IP}/metric-data`) - ]) - .then(axios.spread((resExperiment, resTrialJobs, resMetricData) => { - if (resExperiment.status === 200 && resTrialJobs.status === 200 && resMetricData.status === 200) { - if (resExperiment.data.params.searchSpace) { - resExperiment.data.params.searchSpace = JSON.parse(resExperiment.data.params.searchSpace); - } - const trialMessagesArr = TrialManager.expandJobsToTrials(resTrialJobs.data); - const interResultList = resMetricData.data; - Object.keys(trialMessagesArr).map(item => { - // not deal with trial's hyperParameters - const trialId = trialMessagesArr[item].id; - // add intermediate result message - trialMessagesArr[item].intermediate = []; - Object.keys(interResultList).map(key => { - const interId = `${interResultList[key].trialJobId}-${interResultList[key].parameterId}`; - if (trialId === interId) { - trialMessagesArr[item].intermediate.push(interResultList[key]); - } - }); - }); - const result = { - experimentParameters: resExperiment.data, - trialMessage: trialMessagesArr - }; - if (this._isCompareMount === true) { - this.setState({ experiment: JSON.stringify(result, null, 4) }); - } + const experimentData = JSON.parse(JSON.stringify(this.props.experimentProfile)); + if (experimentData.params.searchSpace) { + experimentData.params.searchSpace = JSON.parse(experimentData.params.searchSpace); + } + const trialMessagesArr = TRIALS.getTrialJobList(); + const interResultList = TRIALS.getMetricsList(); + Object.keys(trialMessagesArr).map(item => { + // not deal with trial's hyperParameters + const trialId = trialMessagesArr[item].jobId; + // add intermediate result message + trialMessagesArr[item].intermediate = []; + Object.keys(interResultList).map(key => { + const interId = interResultList[key].trialJobId; + if (trialId === interId) { + trialMessagesArr[item].intermediate.push(interResultList[key]); } - })); - } + }); + }); + const result = { + experimentParameters: experimentData, + trialMessage: trialMessagesArr + }; + if (this._isExperimentMount === true) { + this.setState({ experiment: JSON.stringify(result, null, 4) }); + } + if (['DONE', 'ERROR', 'STOPPED'].includes(EXPERIMENT.status)) { + if(this.refreshId !== null || this.refreshId !== undefined){ + window.clearInterval(this.refreshId); + } + } + + } + downExperimentParameters = (): void => { const { experiment } = this.state; downFile(experiment, 'experiment.json'); @@ -78,31 +77,28 @@ class ExperimentDrawer extends React.Component { } componentDidMount(): void { - this._isCompareMount = true; + this._isExperimentMount = true; this.getExperimentContent(); + this.refreshId = window.setInterval(this.getExperimentContent, 10000); window.addEventListener('resize', this.onWindowResize); } - componentWillReceiveProps(nextProps: ExpDrawerProps): void { - const { isVisble } = nextProps; - if (isVisble === true) { - this.getExperimentContent(); - } - } - componentWillUnmount(): void { - this._isCompareMount = false; + this._isExperimentMount = false; + window.clearTimeout(this.refreshId); window.removeEventListener('resize', this.onWindowResize); } render(): React.ReactNode { - const { isVisble, closeExpDrawer } = this.props; + const { closeExpDrawer } = this.props; const { experiment, expDrawerHeight } = this.state; return ( diff --git a/src/webui/src/components/Modals/LogDrawer.tsx b/src/webui/src/components/Modals/LogPanel.tsx similarity index 98% rename from src/webui/src/components/Modals/LogDrawer.tsx rename to src/webui/src/components/Modals/LogPanel.tsx index a54b0f4c25..97a408fe9d 100644 --- a/src/webui/src/components/Modals/LogDrawer.tsx +++ b/src/webui/src/components/Modals/LogPanel.tsx @@ -92,6 +92,8 @@ class LogDrawer extends React.Component { isOpen={true} hasCloseButton={false} isFooterAtBottom={true} + isLightDismiss={true} + onLightDismissClick={closeDrawer} >
{ openDocs = (): void => { window.open(WEBUIDOC); } - + openGithubNNI = (): void => { - const {version} = this.state; + const { version } = this.state; const nniLink = `https://github.com/Microsoft/nni/tree/${version}`; window.open(nniLink); } @@ -178,8 +179,8 @@ class NavCon extends React.Component { {/* the drawer for dispatcher & nnimanager log message */} - {isvisibleLogDrawer && } - + {isvisibleLogDrawer && } + {isvisibleExperimentDrawer && } ); } diff --git a/src/webui/src/components/overview/Progress.tsx b/src/webui/src/components/overview/Progress.tsx index c63e23827c..c21e9e8921 100644 --- a/src/webui/src/components/overview/Progress.tsx +++ b/src/webui/src/components/overview/Progress.tsx @@ -9,7 +9,7 @@ import { EXPERIMENT, TRIALS } from '../../static/datamodel'; import { convertTime } from '../../static/function'; import ConcurrencyInput from './NumInput'; import ProgressBar from './ProgressItem'; -import LogDrawer from '../Modals/LogDrawer'; +import LogDrawer from '../Modals/LogPanel'; import MessageInfo from '../Modals/MessageInfo'; import { infoIcon } from "../Buttons/Icon"; import '../../static/style/progress.scss'; diff --git a/src/webui/src/static/model/trialmanager.ts b/src/webui/src/static/model/trialmanager.ts index bc613e1ba1..b860cfa042 100644 --- a/src/webui/src/static/model/trialmanager.ts +++ b/src/webui/src/static/model/trialmanager.ts @@ -48,6 +48,16 @@ class TrialManager { private latestMetricdataErrorMessage: string = ''; // metric-data-latest error message private isMetricdataRangeError: boolean = false; // metric-data-range api error filed private metricdataRangeErrorMessage: string = ''; // metric-data-latest error message + private metricsList: Array = []; + private trialJobList: Array = []; + + public getMetricsList(): Array { + return this.metricsList; + } + + public getTrialJobList(): Array { + return this.trialJobList; + } public async init(): Promise { while (!this.infoInitialized || !this.metricInitialized) { @@ -230,6 +240,7 @@ class TrialManager { requestAxios(`${MANAGER_IP}/trial-jobs`) .then(data => { const newTrials = TrialManager.expandJobsToTrials(data as any); + this.trialJobList = newTrials; for (const trialInfo of newTrials as TrialJobInfo[]) { if (this.trials.has(trialInfo.id)) { // eslint-disable-next-line @typescript-eslint/no-non-null-assertion @@ -265,7 +276,10 @@ class TrialManager { private async updateAllMetrics(): Promise { return requestAxios(`${MANAGER_IP}/metric-data`) - .then(data => this.doUpdateMetrics(data as any, false)) + .then(data => { + this.metricsList = data; + return this.doUpdateMetrics(data as any, false); + }) .catch(error => { this.isMetricdataError = true; this.MetricdataErrorMessage = `${error.message}`;