From 03eb0a8bf1e48b38ed17656d6056605be12ab749 Mon Sep 17 00:00:00 2001
From: rbokhorst <rbokhorst@astron.nl>
Date: Thu, 18 Oct 2018 08:06:00 +0000
Subject: [PATCH] OSB-29: summary panel stuff

---
 .../src/components/StationTestSummary.css     |  40 +----
 .../src/components/StationTestSummary.js      | 147 +++++++++++-------
 .../src/pages/LandingPage.js                  |  13 +-
 .../src/testdata/station_test_summary.js      |  17 +-
 .../src/utils/autoLoader.js                   |   8 +-
 .../maintenancedb_view/src/utils/utils.js     |   9 +-
 6 files changed, 116 insertions(+), 118 deletions(-)

diff --git a/LCU/Maintenance/MDB_WebView/maintenancedb_view/src/components/StationTestSummary.css b/LCU/Maintenance/MDB_WebView/maintenancedb_view/src/components/StationTestSummary.css
index 938763dba19..36a9d440f28 100644
--- a/LCU/Maintenance/MDB_WebView/maintenancedb_view/src/components/StationTestSummary.css
+++ b/LCU/Maintenance/MDB_WebView/maintenancedb_view/src/components/StationTestSummary.css
@@ -1,36 +1,6 @@
-.card {
-    margin-top: 1em;
-    box-shadow: 0 .1em .2em .2em grey;
-}
-.content {
-    text-align: center;
-    vertical-align: bottom;
-}
-.content-title {
-    background-color: lightgrey;
-}
-
-.tableheader {
-    font-weight: bold;
-}
-
-.detailsbutton {
-    background-color: lightgrey !important;
-    color: black !important;
-    font-weight: bold;
-}
-
-.danger,
-.no_error {
-    color: rgb(218, 242, 244);
-}
-
-.danger {
-    background-color: rgb(210, 7, 7) !important;
-    border-color: rgb(210, 7, 7) !important;
-}
-
-.no_error {
-    background-color: rgb(90, 180, 0) !important;
-    border-color: rgb(90, 180, 0) !important;
+.stsToolbar {
+    position: absolute;
+    right: 0.5rem;
+    top: 0.1rem;
+    display: inline-block;
 }
diff --git a/LCU/Maintenance/MDB_WebView/maintenancedb_view/src/components/StationTestSummary.js b/LCU/Maintenance/MDB_WebView/maintenancedb_view/src/components/StationTestSummary.js
index f32174cafca..81ef837e9f9 100644
--- a/LCU/Maintenance/MDB_WebView/maintenancedb_view/src/components/StationTestSummary.js
+++ b/LCU/Maintenance/MDB_WebView/maintenancedb_view/src/components/StationTestSummary.js
@@ -1,8 +1,9 @@
 import React, { Component } from 'react';
 import { Table, Popover, PopoverHeader, PopoverBody, Button, ButtonGroup } from 'reactstrap';
-import { unique_id } from '../utils/utils.js'
+import { unique_id, capitalize } from '../utils/utils.js'
 import AutoLoadWrapper from '../utils/autoLoader.js'
 import axios from 'axios';
+//import stdata from '../testdata/station_test_summary.js'
 
 import './StationTestSummary.css'
 
@@ -55,58 +56,37 @@ class StationTestBadge extends Component {
 }
 
 
-/**
- * RTSMBadge; class to render one RTSM badge in the SORow.
- */
-class RTSMBadge extends Component {
-
-    getClass() {
-        let total = this.props.data.total_component_errors;
-        let color = total>10 ? "so-serious" :
-                    total>5 ? "so-alarming" :
-                    total>0 ? "so-warning" : "so-good";
-        return "so-pill " + color;
-    }
-
-    render () {
-        let data = this.props.data;
-        return <div className="so-rtsmbadge">{ data.observation_id }<span className={ this.getClass() }>{ data.total_component_errors }</span></div>;
-    }
-}
-
-
 /**
  * SORow; Class to render the row for a station in the StationOverview.
  */
 class STSRow extends Component {
 
-    renderStationName() {
-        return this.props.data.station_name;
-    }
-
     renderStartDate() {
         return this.props.date;
     }
 
-    renderStationTests() {
-        let data = this.props.data;
-        return data.station_tests.map( (testData) => <StationTestBadge station={data.station_name} data={ testData } /> );
-    }
-
-    renderRTSM() {
-        if (! this.props.data.rtsm || this.props.data.rtsm.length === 0) {
-            return "No RTSM data found"
-        }
-        return this.props.data.rtsm.map( (testData) => <RTSMBadge data={ testData } /> );
+    renderStartTime() {
+        let arr = this.props.data.start_datetime.match(/T(.*):..Z/);
+        return arr[1];
     }
 
     render() {
+        let props = this.props,
+            component = props.component,
+            errors = props.data.component_error_summary[component] || {},
+            cols = [];
+
+        props.errorTypes.forEach((type) => {
+            cols.push(<td key={unique_id()}>{ errors[type] }</td>);
+        });
+
         return (
             <tr>
                 <th scope="row">{ this.renderStartDate() }</th>
-                <td>{ this.renderStationName() }</td>
-                <td></td>
-                <td></td>
+                <td>{ props.time }</td>
+                <td>{ props.station }</td>
+                <td>{ component }</td>
+                { cols }
             </tr>
         );
     }
@@ -121,7 +101,7 @@ class ToolBar extends Component {
 
     render() {
         return (
-            <div style={{position: "absolute", right: 0, display: "inline-block"}}>
+            <div className="stsToolbar">
                 { this.props.allErrorTypes
                     ? <Button color="info" size="xs" onClick={() => this.onErrorsOnlyClick()} active>All types</Button>
                     : <Button color="info" size="xs" onClick={() => this.onErrorsOnlyClick()} outline>All types</Button>
@@ -139,16 +119,55 @@ class StationTestSummaryC extends Component {
 
     static errorTypesURL = '/api/view/ctrl_list_component_error_types';
 
+    activeErrorTypes = [];  // Result of filtering state.errorTypes
+
     state = {
-        allErrorTypes: false,  // true: error types shown, even when there are no errors for that type
-        errorTypes: []
+        allErrorTypes: false, // true: error types shown, even when there are no errors for that type
+        errorTypes: []        // Result of API call
     };
 
     /* Handle changes of selected filters in the ToolBar */
     onToolbarChange(key, value) {
-      let obj = {};
-      obj[key] = value;
-      this.setState(obj);
+        let obj = {};
+        obj[key] = value;
+        this.setState(obj);
+    }
+
+
+    filterErrorTypes() {
+        let typesFound = {},
+            retTypes = [];
+
+        if (this.state.errorTypes.length === 0 || this.props.data.length === 0){
+            return [];
+        }
+
+        // Create index object for all error types in the data
+        this.props.data.forEach( (stationData) => {
+            let esummary = stationData.component_error_summary;
+            let key;
+            for(key in esummary){
+                let errors = Object.keys(esummary[key]);
+                errors.forEach((e) => typesFound[e] = 1);
+            }
+        });
+
+        // Loop over all error types and check which ones are present in the data
+        this.state.errorTypes.forEach((t) => {
+            if (typesFound[t]) {
+                retTypes.push(t);
+            }
+        })
+
+        return retTypes;
+    }
+
+    setActiveErrorTypes() {
+        if (this.state.allErrorTypes) {
+            this.activeErrorTypes = this.state.errorTypes;
+        } else {
+            this.activeErrorTypes = this.filterErrorTypes();
+        }
     }
 
     fetchErrorTypes() {
@@ -160,6 +179,8 @@ class StationTestSummaryC extends Component {
         })
         .catch(error => {
             console.log(error);
+            // Try again in 30s
+            setTimeout(() => this.fetchErrorTypes(), 30000);
         });
     }
 
@@ -171,20 +192,34 @@ class StationTestSummaryC extends Component {
         let rows = [],
             prevDate = null;
 
-        this.props.data.map( (stationData) => {
-            let key = unique_id();
+        this.props.data.forEach( (stationData) => {
             let date = (stationData.date != prevDate ? stationData.date : "");
-            rows.push(<STSRow key={key} date={date} data={stationData} />)
+            let components = Object.keys(stationData.component_error_summary).sort();
+            let station = stationData.station_name;
+            let time = (stationData.start_datetime.match(/T(.*):..Z/))[1];
+
+            components.forEach( (component) => {
+                rows.push(<STSRow key={ unique_id() } date={date} time={time} component={component} station={station} data={stationData} errorTypes={this.activeErrorTypes}/>)
+                date = station = time = "";
+            });
+            if (components.length === 0) {
+                rows.push(<STSRow key={ unique_id() } date={date} time={time} component={"-"} station={station} data={stationData} errorTypes={this.activeErrorTypes}/>)
+            }
             prevDate = stationData.date;
         });
+
         return rows;
     }
 
     renderTableHeaders() {
-        return this.state.errorTypes.map((err) => <th>{err}</th>);
+        return this.activeErrorTypes.map((err) => <th key={unique_id()}>{capitalize(err)}</th>);
     }
 
     render() {
+        console.log("render stationTestSummary");
+
+        this.setActiveErrorTypes();
+
         return (
             <React.Fragment>
                 <h5 className="react-grid-item-header">
@@ -192,14 +227,15 @@ class StationTestSummaryC extends Component {
                     <ToolBar onChange={(key,value) => this.onToolbarChange(key,value) } allErrorTypes={this.state.allErrorTypes} />
                 </h5>
                 <div className="react-grid-item-body">
-                    <Table size="sm" className="so-table">
+                    <Table bordered hover size="sm" className="so-table">
                         <thead>
-                          <tr>
-                            <th>Date</th>
-                            <th>Station</th>
-                            <th>Component</th>
-                            {this.renderTableHeaders()}
-                          </tr>
+                            <tr>
+                              <th>Date</th>
+                              <th>Time</th>
+                              <th>Station</th>
+                              <th>Comp.</th>
+                              {this.renderTableHeaders()}
+                            </tr>
                         </thead>
                         <tbody>
                             { this.getTableRows() }
@@ -212,6 +248,7 @@ class StationTestSummaryC extends Component {
 
 }
 
+
 /* Add some magic; use the AutoLoadWrapper to create a HOC that handles the
    auto-loading of the data for StationOverviewC.
  */
diff --git a/LCU/Maintenance/MDB_WebView/maintenancedb_view/src/pages/LandingPage.js b/LCU/Maintenance/MDB_WebView/maintenancedb_view/src/pages/LandingPage.js
index 66595b03e01..919d5f09721 100644
--- a/LCU/Maintenance/MDB_WebView/maintenancedb_view/src/pages/LandingPage.js
+++ b/LCU/Maintenance/MDB_WebView/maintenancedb_view/src/pages/LandingPage.js
@@ -11,9 +11,7 @@ import 'react-resizable/css/styles.css';
 import '../themes/lofar-styles.css';
 
 // Testing
-import station_overview_data from '../testdata/station_overview.js'
 import latest_obs_data from '../testdata/latest_observations.js'
-import station_details_data from '../testdata/station_details.js'
 
 const ResponsiveGridLayout = WidthProvider(Responsive);
 
@@ -72,13 +70,14 @@ class ToolBar extends Component {
                         <option value="C">Core stations</option>
                         <option value="R">Remote stations</option>
                         <option value="I">ILT stations</option>
-                    </select>&nbsp;
+                    </select>
+                    &nbsp;
                     { this.props.errorsOnly
-                        ? <Button color="info" size="md" onClick={()=>this.onErrorsOnlyClick()} active>Errors only</Button>
-                        : <Button color="info" size="md" onClick={()=>this.onErrorsOnlyClick()} outline>Errors only</Button>
+                        ? <Button color="info" size="sm" onClick={()=>this.onErrorsOnlyClick()} active>Errors only</Button>
+                        : <Button color="info" size="sm" onClick={()=>this.onErrorsOnlyClick()} outline>Errors only</Button>
                     }
                     &nbsp;
-                    <ButtonGroup  size="xs">
+                    <ButtonGroup  size="sm">
                         period:
                         <Button color="info" onClick={() => this.onPeriodClick(7)} active={this.props.period === 7}>1 wk</Button>
                         <Button color="info" onClick={() => this.onPeriodClick(14)} active={this.props.period === 14}>2 wk</Button>
@@ -153,7 +152,7 @@ class LandingPage extends Component {
                 })}
                 {createGridPanel({
                     key: "bl", renderHeader: false,
-                    body: <StationTestSummary url={this.getStationTestSummaryURL()} reloadInterval="6000"/>
+                    body: <StationTestSummary url={this.getStationTestSummaryURL()}/>
                 })}
                 {createGridPanel({ key: "br", renderHeader: true, title: "Statistics" })}
             </ResponsiveGridLayout>
diff --git a/LCU/Maintenance/MDB_WebView/maintenancedb_view/src/testdata/station_test_summary.js b/LCU/Maintenance/MDB_WebView/maintenancedb_view/src/testdata/station_test_summary.js
index 61164101f78..aedbde378a3 100644
--- a/LCU/Maintenance/MDB_WebView/maintenancedb_view/src/testdata/station_test_summary.js
+++ b/LCU/Maintenance/MDB_WebView/maintenancedb_view/src/testdata/station_test_summary.js
@@ -1,4 +1,4 @@
-const data = [
+const stdata = [
     {
         "station_name": "CS002C",
         "total_component_errors": 18,
@@ -31,19 +31,6 @@ const data = [
         "end_datetime": "2018-10-11T00:52:24Z",
         "checks": "RV SPU RBC SH1 F1 D1 O1 SP1 NS1=60 S1 SH3 F3 D3 O3 SP3 NS3=60 S3 M5 O5 SN5 SP5 NS5=60 E7 TV TBC TM",
         "component_error_summary": {
-            "HBA": {
-                "HIGH_NOISE": 4,
-                "MODEM": 2,
-                "OSCILLATION": 1,
-                "C_SUMMATOR": 1
-            },
-            "LBL": {
-                "LOW_NOISE": 1,
-                "RF_FAIL": 1
-            },
-            "TBB": {
-                "TEMPERATURE": 1
-            }
         }
     }, {
         "station_name": "CS005C",
@@ -812,4 +799,4 @@ const data = [
     }
 ];
 
-export default data;
+export default stdata;
diff --git a/LCU/Maintenance/MDB_WebView/maintenancedb_view/src/utils/autoLoader.js b/LCU/Maintenance/MDB_WebView/maintenancedb_view/src/utils/autoLoader.js
index 3071cc310d6..7bf4512d95a 100644
--- a/LCU/Maintenance/MDB_WebView/maintenancedb_view/src/utils/autoLoader.js
+++ b/LCU/Maintenance/MDB_WebView/maintenancedb_view/src/utils/autoLoader.js
@@ -1,4 +1,4 @@
-import React, { Component } from 'react';
+import React from 'react';
 import axios from 'axios';
 
 
@@ -25,7 +25,7 @@ function AutoLoadWrapper(WrappedComponent) {
     /* Called when props changed, before the render phase */
     static getDerivedStateFromProps(props, state) {
         // Store prevUrl in state so we can compare when props change.
-        if (props.url != state.prevUrl) {
+        if (props.url !== state.prevUrl) {
             console.log('getDerived; ');
             return {
                 isLoading: true,
@@ -47,7 +47,7 @@ function AutoLoadWrapper(WrappedComponent) {
         }
 
         // Create cancellation token
-        if (typeof this._source != typeof undefined) {
+        if (typeof this._source !== typeof undefined) {
             this._source.cancel('Operation canceled due to new request.')
         }
         this._source = axios.CancelToken.source();
@@ -84,7 +84,7 @@ function AutoLoadWrapper(WrappedComponent) {
     }
 
     componentDidUpdate(prevProps, prevState) {
-        if (prevProps.url != this.props.url) {
+        if (prevProps.url !== this.props.url) {
             console.log('props changed: ' + prevProps.url+ ' '+this.props.url);
             this.fetchData();
         }
diff --git a/LCU/Maintenance/MDB_WebView/maintenancedb_view/src/utils/utils.js b/LCU/Maintenance/MDB_WebView/maintenancedb_view/src/utils/utils.js
index d8412b90dd9..f6080b07b67 100644
--- a/LCU/Maintenance/MDB_WebView/maintenancedb_view/src/utils/utils.js
+++ b/LCU/Maintenance/MDB_WebView/maintenancedb_view/src/utils/utils.js
@@ -1,9 +1,14 @@
 let lastId = 0;
 
-function unique_id(prefix='id_') { 
+function unique_id(prefix='id_') {
     lastId++;
     return `${prefix}${lastId}`;
 }
 
 
-export { unique_id };
+function capitalize(s) {
+  if (typeof s !== 'string') return ''
+  return s.charAt(0).toUpperCase() + s.slice(1).toLowerCase()
+}
+
+export { unique_id, capitalize };
-- 
GitLab