From 120cd11d58b51b6f1a60e378300c2ccf29fd4710 Mon Sep 17 00:00:00 2001
From: Lijiao <15910218274@163.com>
Date: Fri, 13 Mar 2020 02:35:44 +0000
Subject: [PATCH 1/5] add warning message when final data illegal

---
 src/webui/scripts/start.js          |  2 +-
 src/webui/src/App.scss              |  5 +++
 src/webui/src/App.tsx               | 49 ++++++++++++++++++++++++-----
 src/webui/src/static/const.ts       |  2 +-
 src/webui/src/static/model/trial.ts |  2 +-
 5 files changed, 49 insertions(+), 11 deletions(-)

diff --git a/src/webui/scripts/start.js b/src/webui/scripts/start.js
index e6236bd6a2..49a489a484 100644
--- a/src/webui/scripts/start.js
+++ b/src/webui/scripts/start.js
@@ -41,7 +41,7 @@ if (!checkRequiredFiles([paths.appHtml, paths.appIndexJs])) {
 }
 
 // Tools like Cloud9 rely on this.
-const DEFAULT_PORT = parseInt(process.env.PORT, 10) || 3000;
+const DEFAULT_PORT = parseInt(process.env.PORT, 10) || 9000;
 const HOST = process.env.HOST || '0.0.0.0';
 
 if (process.env.HOST) {
diff --git a/src/webui/src/App.scss b/src/webui/src/App.scss
index c6e8fcebfa..fdd51cde0c 100644
--- a/src/webui/src/App.scss
+++ b/src/webui/src/App.scss
@@ -43,3 +43,8 @@
     color: #333;
   }
 }
+
+.warning{
+  padding-bottom: 15px;
+  background-color: #f2f2f2;
+}
diff --git a/src/webui/src/App.tsx b/src/webui/src/App.tsx
index e10e4bd664..a91fcface9 100644
--- a/src/webui/src/App.tsx
+++ b/src/webui/src/App.tsx
@@ -3,6 +3,7 @@ import { Stack } from 'office-ui-fabric-react';
 import { COLUMN } from './static/const';
 import { EXPERIMENT, TRIALS } from './static/datamodel';
 import NavCon from './components/NavCon';
+import MessageInfo from './components/Modals/MessageInfo';
 import './App.scss';
 
 interface AppState {
@@ -11,6 +12,8 @@ interface AppState {
     experimentUpdateBroadcast: number;
     trialsUpdateBroadcast: number;
     metricGraphMode: 'max' | 'min'; // tuner's optimize_mode filed
+    isilLegalFinal: boolean;
+    expWarningMessage: string;
 }
 
 class App extends React.Component<{}, AppState> {
@@ -23,7 +26,9 @@ class App extends React.Component<{}, AppState> {
             columnList: COLUMN,
             experimentUpdateBroadcast: 0,
             trialsUpdateBroadcast: 0,
-            metricGraphMode: 'max'
+            metricGraphMode: 'max',
+            isilLegalFinal: false,
+            expWarningMessage: ''
         };
     }
 
@@ -33,6 +38,30 @@ class App extends React.Component<{}, AppState> {
         this.setState(state => ({ trialsUpdateBroadcast: state.trialsUpdateBroadcast + 1 }));
         this.timerId = window.setTimeout(this.refresh, this.state.interval * 1000);
         this.setState({ metricGraphMode: (EXPERIMENT.optimizeMode === 'minimize' ? 'min' : 'max') });
+        // final result is legal
+        // 选一条succeed trial,查看final result格式是否支持
+        // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
+        window.setInterval(this.test, this.state.interval * 1000);
+        
+    }
+
+    test = () => {
+        console.info('例行检查'); // eslint-disable-line
+        for(let i = 0; this.state.isilLegalFinal === false; i++){
+            if(TRIALS.succeededTrials()[0] !== undefined && TRIALS.succeededTrials()[0].final !== undefined){
+                const oneSucceedTrial = JSON.parse(TRIALS.succeededTrials()[0].final!.data);
+                if (typeof oneSucceedTrial === 'number' || oneSucceedTrial.hasOwnProperty('default')) {
+                    return;
+                } else {
+                    console.info('数据不合常理'); // eslint-disable-line
+                    // 非法
+                    this.setState(() => ({
+                        isilLegalFinal: true,
+                        expWarningMessage: 'WebUI support final result as number and dictornary includes default keys, your experiment final result is illegal, please check your data.'
+                    }));
+                }
+            }
+        }
     }
 
     changeInterval = (interval: number): void => {
@@ -54,18 +83,19 @@ class App extends React.Component<{}, AppState> {
     }
 
     render(): React.ReactNode {
-        const { interval, columnList, experimentUpdateBroadcast, trialsUpdateBroadcast, metricGraphMode } = this.state;
+        const { interval, columnList, experimentUpdateBroadcast, trialsUpdateBroadcast,
+        metricGraphMode, isilLegalFinal, expWarningMessage } = this.state;
         if (experimentUpdateBroadcast === 0 || trialsUpdateBroadcast === 0) {
             return null;  // TODO: render a loading page
         }
         const reactPropsChildren = React.Children.map(this.props.children, child =>
             React.cloneElement(
                 child as React.ReactElement<any>, {
-                    interval,
-                    columnList, changeColumn: this.changeColumn,
-                    experimentUpdateBroadcast,
-                    trialsUpdateBroadcast,
-                    metricGraphMode, changeMetricGraphMode: this.changeMetricGraphMode
+                interval,
+                columnList, changeColumn: this.changeColumn,
+                experimentUpdateBroadcast,
+                trialsUpdateBroadcast,
+                metricGraphMode, changeMetricGraphMode: this.changeMetricGraphMode
             })
         );
 
@@ -73,11 +103,14 @@ class App extends React.Component<{}, AppState> {
             <Stack className="nni" style={{ minHeight: window.innerHeight }}>
                 <div className="header">
                     <div className="headerCon">
-                        <NavCon changeInterval={this.changeInterval} refreshFunction={this.lastRefresh}/>
+                        <NavCon changeInterval={this.changeInterval} refreshFunction={this.lastRefresh} />
                     </div>
                 </div>
                 <Stack className="contentBox">
                     <Stack className="content">
+                        {isilLegalFinal && <div className="warning">
+                            <MessageInfo info={expWarningMessage} typeInfo="warning" />
+                        </div>}
                         {reactPropsChildren}
                     </Stack>
                 </Stack>
diff --git a/src/webui/src/static/const.ts b/src/webui/src/static/const.ts
index a950fe1d80..c58eb8fe80 100644
--- a/src/webui/src/static/const.ts
+++ b/src/webui/src/static/const.ts
@@ -2,7 +2,7 @@
 const METRIC_GROUP_UPDATE_THRESHOLD = 100;
 const METRIC_GROUP_UPDATE_SIZE = 20;
 
-const MANAGER_IP = `/api/v1/nni`;
+const MANAGER_IP = `http://13.77.78.63:8080/api/v1/nni`;
 const DOWNLOAD_IP = `/logs`;
 const WEBUIDOC = 'https://nni.readthedocs.io/en/latest/Tutorial/WebUI.html';
 const trialJobStatus = [
diff --git a/src/webui/src/static/model/trial.ts b/src/webui/src/static/model/trial.ts
index 60d45ed50b..49f6a95142 100644
--- a/src/webui/src/static/model/trial.ts
+++ b/src/webui/src/static/model/trial.ts
@@ -5,7 +5,7 @@ class Trial implements TableObj {
     private metricsInitialized: boolean = false;
     private infoField: TrialJobInfo | undefined;
     private intermediates: (MetricDataRecord | undefined)[] = [ ];
-    private final: MetricDataRecord | undefined;
+    public final: MetricDataRecord | undefined;
     private finalAcc: number | undefined;
 
     constructor(info?: TrialJobInfo, metrics?: MetricDataRecord[]) {

From 57d663eed51ffb7cd4b8376cfe6aa7f49b0ec83a Mon Sep 17 00:00:00 2001
From: Lijiao <15910218274@163.com>
Date: Fri, 13 Mar 2020 02:37:02 +0000
Subject: [PATCH 2/5] update

---
 src/webui/src/App.tsx | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/src/webui/src/App.tsx b/src/webui/src/App.tsx
index a91fcface9..aa41569ff6 100644
--- a/src/webui/src/App.tsx
+++ b/src/webui/src/App.tsx
@@ -18,6 +18,7 @@ interface AppState {
 
 class App extends React.Component<{}, AppState> {
     private timerId!: number | null;
+    private dataFormatimer!: number | null;
 
     constructor(props: {}) {
         super(props);
@@ -41,7 +42,7 @@ class App extends React.Component<{}, AppState> {
         // final result is legal
         // 选一条succeed trial,查看final result格式是否支持
         // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-        window.setInterval(this.test, this.state.interval * 1000);
+        this.dataFormatimer = window.setInterval(this.test, this.state.interval * 1000);
         
     }
 
@@ -59,6 +60,7 @@ class App extends React.Component<{}, AppState> {
                         isilLegalFinal: true,
                         expWarningMessage: 'WebUI support final result as number and dictornary includes default keys, your experiment final result is illegal, please check your data.'
                     }));
+                    window.clearInterval(this.dataFormatimer);
                 }
             }
         }

From 36354beb0dfd3ce86c431e1a74922a2d33a821b9 Mon Sep 17 00:00:00 2001
From: Lijiao <15910218274@163.com>
Date: Fri, 13 Mar 2020 08:26:53 +0000
Subject: [PATCH 3/5] update

---
 src/webui/src/App.tsx         | 5 +++--
 src/webui/src/static/const.ts | 2 +-
 2 files changed, 4 insertions(+), 3 deletions(-)

diff --git a/src/webui/src/App.tsx b/src/webui/src/App.tsx
index aa41569ff6..027091b736 100644
--- a/src/webui/src/App.tsx
+++ b/src/webui/src/App.tsx
@@ -18,7 +18,7 @@ interface AppState {
 
 class App extends React.Component<{}, AppState> {
     private timerId!: number | null;
-    private dataFormatimer!: number | null;
+    private dataFormatimer!: number;
 
     constructor(props: {}) {
         super(props);
@@ -43,7 +43,6 @@ class App extends React.Component<{}, AppState> {
         // 选一条succeed trial,查看final result格式是否支持
         // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
         this.dataFormatimer = window.setInterval(this.test, this.state.interval * 1000);
-        
     }
 
     test = () => {
@@ -51,6 +50,8 @@ class App extends React.Component<{}, AppState> {
         for(let i = 0; this.state.isilLegalFinal === false; i++){
             if(TRIALS.succeededTrials()[0] !== undefined && TRIALS.succeededTrials()[0].final !== undefined){
                 const oneSucceedTrial = JSON.parse(TRIALS.succeededTrials()[0].final!.data);
+                console.info(oneSucceedTrial); // eslint-disable-line
+                console.info(typeof oneSucceedTrial); // eslint-disable-line
                 if (typeof oneSucceedTrial === 'number' || oneSucceedTrial.hasOwnProperty('default')) {
                     return;
                 } else {
diff --git a/src/webui/src/static/const.ts b/src/webui/src/static/const.ts
index c58eb8fe80..a675dde452 100644
--- a/src/webui/src/static/const.ts
+++ b/src/webui/src/static/const.ts
@@ -2,7 +2,7 @@
 const METRIC_GROUP_UPDATE_THRESHOLD = 100;
 const METRIC_GROUP_UPDATE_SIZE = 20;
 
-const MANAGER_IP = `http://13.77.78.63:8080/api/v1/nni`;
+const MANAGER_IP = `http://13.77.78.63:8282/api/v1/nni`;
 const DOWNLOAD_IP = `/logs`;
 const WEBUIDOC = 'https://nni.readthedocs.io/en/latest/Tutorial/WebUI.html';
 const trialJobStatus = [

From 9331b1e5dfcde365c19021a67a2599bbc69ec25e Mon Sep 17 00:00:00 2001
From: Lijiao <15910218274@163.com>
Date: Wed, 18 Mar 2020 02:32:38 +0000
Subject: [PATCH 4/5] update

---
 src/webui/scripts/start.js    |  2 +-
 src/webui/src/App.tsx         | 22 +++++++++++-----------
 src/webui/src/static/const.ts |  2 +-
 3 files changed, 13 insertions(+), 13 deletions(-)

diff --git a/src/webui/scripts/start.js b/src/webui/scripts/start.js
index 49a489a484..e6236bd6a2 100644
--- a/src/webui/scripts/start.js
+++ b/src/webui/scripts/start.js
@@ -41,7 +41,7 @@ if (!checkRequiredFiles([paths.appHtml, paths.appIndexJs])) {
 }
 
 // Tools like Cloud9 rely on this.
-const DEFAULT_PORT = parseInt(process.env.PORT, 10) || 9000;
+const DEFAULT_PORT = parseInt(process.env.PORT, 10) || 3000;
 const HOST = process.env.HOST || '0.0.0.0';
 
 if (process.env.HOST) {
diff --git a/src/webui/src/App.tsx b/src/webui/src/App.tsx
index 027091b736..7adb8239f1 100644
--- a/src/webui/src/App.tsx
+++ b/src/webui/src/App.tsx
@@ -40,33 +40,33 @@ class App extends React.Component<{}, AppState> {
         this.timerId = window.setTimeout(this.refresh, this.state.interval * 1000);
         this.setState({ metricGraphMode: (EXPERIMENT.optimizeMode === 'minimize' ? 'min' : 'max') });
         // final result is legal
-        // 选一条succeed trial,查看final result格式是否支持
+        // get a succeed trial,see final result data's format
         // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-        this.dataFormatimer = window.setInterval(this.test, this.state.interval * 1000);
+        this.dataFormatimer = window.setInterval(this.getFinalDataFormat, this.state.interval * 1000);
     }
 
-    test = () => {
-        console.info('例行检查'); // eslint-disable-line
+    getFinalDataFormat = (): void => {
         for(let i = 0; this.state.isilLegalFinal === false; i++){
             if(TRIALS.succeededTrials()[0] !== undefined && TRIALS.succeededTrials()[0].final !== undefined){
-                const oneSucceedTrial = JSON.parse(TRIALS.succeededTrials()[0].final!.data);
-                console.info(oneSucceedTrial); // eslint-disable-line
-                console.info(typeof oneSucceedTrial); // eslint-disable-line
+                // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
+                const oneSucceedTrial = JSON.parse(JSON.parse(TRIALS.succeededTrials()[0].final!.data));
                 if (typeof oneSucceedTrial === 'number' || oneSucceedTrial.hasOwnProperty('default')) {
-                    return;
+                    window.clearInterval(this.dataFormatimer);
+                    break;
                 } else {
-                    console.info('数据不合常理'); // eslint-disable-line
-                    // 非法
+                    // illegal final data
                     this.setState(() => ({
                         isilLegalFinal: true,
                         expWarningMessage: 'WebUI support final result as number and dictornary includes default keys, your experiment final result is illegal, please check your data.'
                     }));
                     window.clearInterval(this.dataFormatimer);
                 }
+            } else {
+                break;
             }
         }
     }
-
+    
     changeInterval = (interval: number): void => {
         this.setState({ interval });
         if (this.timerId === null && interval !== 0) {
diff --git a/src/webui/src/static/const.ts b/src/webui/src/static/const.ts
index a675dde452..a950fe1d80 100644
--- a/src/webui/src/static/const.ts
+++ b/src/webui/src/static/const.ts
@@ -2,7 +2,7 @@
 const METRIC_GROUP_UPDATE_THRESHOLD = 100;
 const METRIC_GROUP_UPDATE_SIZE = 20;
 
-const MANAGER_IP = `http://13.77.78.63:8282/api/v1/nni`;
+const MANAGER_IP = `/api/v1/nni`;
 const DOWNLOAD_IP = `/logs`;
 const WEBUIDOC = 'https://nni.readthedocs.io/en/latest/Tutorial/WebUI.html';
 const trialJobStatus = [

From 673c7f5f9a0bb38e75019d64e6f650feb105151c Mon Sep 17 00:00:00 2001
From: Lijiao <15910218274@163.com>
Date: Thu, 19 Mar 2020 09:29:22 +0000
Subject: [PATCH 5/5] fix comments

---
 src/webui/src/App.tsx | 23 ++++++++++++-----------
 1 file changed, 12 insertions(+), 11 deletions(-)

diff --git a/src/webui/src/App.tsx b/src/webui/src/App.tsx
index 7adb8239f1..3778c675af 100644
--- a/src/webui/src/App.tsx
+++ b/src/webui/src/App.tsx
@@ -12,7 +12,7 @@ interface AppState {
     experimentUpdateBroadcast: number;
     trialsUpdateBroadcast: number;
     metricGraphMode: 'max' | 'min'; // tuner's optimize_mode filed
-    isilLegalFinal: boolean;
+    isillegalFinal: boolean;
     expWarningMessage: string;
 }
 
@@ -28,7 +28,7 @@ class App extends React.Component<{}, AppState> {
             experimentUpdateBroadcast: 0,
             trialsUpdateBroadcast: 0,
             metricGraphMode: 'max',
-            isilLegalFinal: false,
+            isillegalFinal: false,
             expWarningMessage: ''
         };
     }
@@ -46,7 +46,7 @@ class App extends React.Component<{}, AppState> {
     }
 
     getFinalDataFormat = (): void => {
-        for(let i = 0; this.state.isilLegalFinal === false; i++){
+        for(let i = 0; this.state.isillegalFinal === false; i++){
             if(TRIALS.succeededTrials()[0] !== undefined && TRIALS.succeededTrials()[0].final !== undefined){
                 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
                 const oneSucceedTrial = JSON.parse(JSON.parse(TRIALS.succeededTrials()[0].final!.data));
@@ -56,7 +56,7 @@ class App extends React.Component<{}, AppState> {
                 } else {
                     // illegal final data
                     this.setState(() => ({
-                        isilLegalFinal: true,
+                        isillegalFinal: true,
                         expWarningMessage: 'WebUI support final result as number and dictornary includes default keys, your experiment final result is illegal, please check your data.'
                     }));
                     window.clearInterval(this.dataFormatimer);
@@ -87,18 +87,19 @@ class App extends React.Component<{}, AppState> {
 
     render(): React.ReactNode {
         const { interval, columnList, experimentUpdateBroadcast, trialsUpdateBroadcast,
-        metricGraphMode, isilLegalFinal, expWarningMessage } = this.state;
+            metricGraphMode, isillegalFinal, expWarningMessage 
+        } = this.state;
         if (experimentUpdateBroadcast === 0 || trialsUpdateBroadcast === 0) {
             return null;  // TODO: render a loading page
         }
         const reactPropsChildren = React.Children.map(this.props.children, child =>
             React.cloneElement(
                 child as React.ReactElement<any>, {
-                interval,
-                columnList, changeColumn: this.changeColumn,
-                experimentUpdateBroadcast,
-                trialsUpdateBroadcast,
-                metricGraphMode, changeMetricGraphMode: this.changeMetricGraphMode
+                    interval,
+                    columnList, changeColumn: this.changeColumn,
+                    experimentUpdateBroadcast,
+                    trialsUpdateBroadcast,
+                    metricGraphMode, changeMetricGraphMode: this.changeMetricGraphMode
             })
         );
 
@@ -111,7 +112,7 @@ class App extends React.Component<{}, AppState> {
                 </div>
                 <Stack className="contentBox">
                     <Stack className="content">
-                        {isilLegalFinal && <div className="warning">
+                        {isillegalFinal && <div className="warning">
                             <MessageInfo info={expWarningMessage} typeInfo="warning" />
                         </div>}
                         {reactPropsChildren}