From c9b2c17f40b2536f7b1001df8feadde98722faee Mon Sep 17 00:00:00 2001
From: Mattia Mancini <mancini@astron.nl>
Date: Mon, 12 Nov 2018 14:08:40 +0000
Subject: [PATCH] OSB-31: add test type selection on the landing page

---
 .gitattributes                                |   1 +
 .../maintenancedb_view/package.json           | 103 ++++++++++--------
 .../src/components/MultiSelectDropdown.js     |  78 +++++++++++++
 .../src/pages/DetailsPage.js                  |   7 --
 .../src/pages/LandingPage.js                  |  33 +++++-
 .../src/redux/actions/mainFiltersActions.js   |   6 +
 .../src/redux/reducers/mainFilters.js         |  11 +-
 .../src/themes/lofar-styles.css               |   9 ++
 .../src/themes/lofar-styles.scss              |  14 +++
 .../maintenancedb_view/src/themes/lofar.css   |   9 ++
 10 files changed, 212 insertions(+), 59 deletions(-)
 create mode 100644 LCU/Maintenance/MDB_WebView/maintenancedb_view/src/components/MultiSelectDropdown.js

diff --git a/.gitattributes b/.gitattributes
index 9c6fdcfbe4b..8eec57f0d0b 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -1852,6 +1852,7 @@ LCU/Maintenance/MDB_WebView/maintenancedb_view/src/api_configuration.js -text
 LCU/Maintenance/MDB_WebView/maintenancedb_view/src/components/LatestObservations.css -text
 LCU/Maintenance/MDB_WebView/maintenancedb_view/src/components/LatestObservations.js -text
 LCU/Maintenance/MDB_WebView/maintenancedb_view/src/components/LatestObservations.scss -text
+LCU/Maintenance/MDB_WebView/maintenancedb_view/src/components/MultiSelectDropdown.js -text
 LCU/Maintenance/MDB_WebView/maintenancedb_view/src/components/StationAutoComplete.css -text
 LCU/Maintenance/MDB_WebView/maintenancedb_view/src/components/StationAutoComplete.js -text
 LCU/Maintenance/MDB_WebView/maintenancedb_view/src/components/StationAutoComplete.scss -text
diff --git a/LCU/Maintenance/MDB_WebView/maintenancedb_view/package.json b/LCU/Maintenance/MDB_WebView/maintenancedb_view/package.json
index 9d29380d039..6006dda0eb4 100644
--- a/LCU/Maintenance/MDB_WebView/maintenancedb_view/package.json
+++ b/LCU/Maintenance/MDB_WebView/maintenancedb_view/package.json
@@ -1,48 +1,59 @@
 {
-	"name": "maintenancedb_view",
-	"version": "0.1.0",
-	"description": "WebPage meant to display the content of the maintenance db in the web browser,",
-	"proxy": "http://lofarmonitortest.control.lofar",
-	"scripts": {
-		"flow": "flow",
-		"build-css": "node-sass-chokidar src/ -o src/",
-		"watch-css": "npm run build-css && node-sass-chokidar src/ -o src/ --watch --recursive",
-		"start-js": "react-scripts start",
-		"build-js": "react-scripts build",
-		"start": "npm run -p watch-css & npm run start-js",
-		"build": "npm run build-css && npm run build-js",
-		"test": "react-scripts test --env=jsdom",
-		"eject": "react-scripts eject",
-		"deploy": "npm run build"
-	},
-	"dependencies": {
-		"ajv": "^6.5.4",
-		"axios": "^0.18.0",
-		"bootstrap": "^4.1.3",
-		"connected-react-router": "^4.5.0",
-		"moment": "^2.22.2",
-		"node-sass-chokidar": "^1.3.3",
-		"query-string": "^6.2.0",
-		"react": "^16.4.2",
-		"react-autosuggest": "^9.4.2",
-		"react-datepicker": "^1.7.0",
-		"react-dom": "^16.4.2",
-		"react-grid-layout": "^0.16.6",
-		"react-icons": "^3.2.2",
-		"react-redux": "^5.0.7",
-		"react-router": "^4.3.1",
-		"react-router-dom": "^4.3.1",
-		"react-scripts": "1.1.4",
-		"react-sticky": "^6.0.3",
-		"react-table": "^6.8.6",
-		"react-table-container": "^2.0.1",
-		"react-vega-lite": "^2.0.2",
-		"reactstrap": "^6.3.1",
-		"redux": "^4.0.1",
-		"redux-thunk": "^2.3.0",
-		"vega": "^4.3.0",
-		"vega-lite": "^2.6.0",
-		"vega-tooltip": "^0.13.0"
-	},
-	"private": true
+  "name": "maintenancedb_view",
+  "version": "0.1.0",
+  "description": "WebPage meant to display the content of the maintenance db in the web browser,",
+  "proxy": "http://lofarmonitortest.control.lofar",
+  "scripts": {
+    "flow": "flow",
+    "build-css": "node-sass-chokidar src/ -o src/",
+    "watch-css": "npm run build-css && node-sass-chokidar src/ -o src/ --watch --recursive",
+    "start-js": "react-scripts start",
+    "build-js": "react-scripts build",
+    "start": "npm run -p watch-css & npm run start-js",
+    "build": "npm run build-css && npm run build-js",
+    "test": "react-scripts test --env=jsdom",
+    "eject": "react-scripts eject",
+    "deploy": "npm run build"
+  },
+  "dependencies": {
+    "ajv": "^6.5.4",
+    "axios": "^0.18.0",
+    "bootstrap": "^4.1.3",
+    "bootstrap-select": "^1.13.3",
+    "connected-react-router": "^4.5.0",
+    "jquery": "^3.3.1",
+    "moment": "^2.22.2",
+    "node-sass-chokidar": "^1.3.3",
+    "query-string": "^6.2.0",
+    "react": "^16.4.2",
+    "react-autosuggest": "^9.4.2",
+    "react-datepicker": "^1.7.0",
+    "react-dom": "^16.4.2",
+    "react-grid-layout": "^0.16.6",
+    "react-icons": "^3.2.2",
+    "react-redux": "^5.0.7",
+    "react-router": "^4.3.1",
+    "react-router-dom": "^4.3.1",
+    "react-select": "^2.1.1",
+    "react-sticky": "^6.0.3",
+    "react-table": "^6.8.6",
+    "react-table-container": "^2.0.1",
+    "react-vega-lite": "^2.0.2",
+    "reactstrap": "^6.3.1",
+    "redux": "^4.0.1",
+    "redux-thunk": "^2.3.0",
+    "vega": "^4.3.0",
+    "vega-lite": "^2.6.0",
+    "vega-tooltip": "^0.13.0"
+  },
+  "devDependencies": {
+    "react-scripts": "latest"
+  },
+  "private": true,
+  "browserslist": [
+    ">0.2%",
+    "not dead",
+    "not ie <= 11",
+    "not op_mini all"
+  ]
 }
diff --git a/LCU/Maintenance/MDB_WebView/maintenancedb_view/src/components/MultiSelectDropdown.js b/LCU/Maintenance/MDB_WebView/maintenancedb_view/src/components/MultiSelectDropdown.js
new file mode 100644
index 00000000000..2dee653169f
--- /dev/null
+++ b/LCU/Maintenance/MDB_WebView/maintenancedb_view/src/components/MultiSelectDropdown.js
@@ -0,0 +1,78 @@
+import React, {Component} from 'react';
+import { IoMdCheckmark as IsSelectIcon } from 'react-icons/io';
+import { Dropdown, DropdownToggle, DropdownMenu, DropdownItem } from 'reactstrap'
+
+class SelectableOption extends Component {
+
+    selectedItem = () => {this.props.onSelectedItem(this.props.value)}
+
+    render(){
+        const selectMark = this.props.isSelected ? <IsSelectIcon style={{float: "right", marginTop:".2em"}}/> : undefined
+        const jsx = (
+            <DropdownItem onClick={this.selectedItem}>
+                <span>{this.props.children}</span>
+                {selectMark}
+            </DropdownItem>
+        )
+        return jsx
+    }
+}
+
+export class MultiSelectDropdown extends Component{
+    constructor(props){
+        super(props)
+
+        this.state = {
+            isOpen: false,
+            selectedItems: {}
+        }
+    }
+    // Toggle the dropdown state
+    toggle = () => this.setState({isOpen:!this.state.isOpen})
+
+    itemSelected = (e) => {
+        const newSelectedItems = this.state.selectedItems
+        newSelectedItems[e] = !newSelectedItems[e]
+        this.setState({selectedItems: newSelectedItems})
+        this.props.onSelectionChange(this.getSelectedItemsList())
+    }
+
+    getSelectedItemsList () {
+        return Object.keys(this.state.selectedItems).filter(item => this.state.selectedItems[item])
+    }
+
+    renderLabel(){
+        const selectedItemsList = this.getSelectedItemsList()
+        if(selectedItemsList.length === 0 ){
+            return this.props.placeHolder;
+        }else if(selectedItemsList.length === 1){
+            return selectedItemsList[0]
+        }else {
+            return `${selectedItemsList[0]}, ...`
+        }
+    }
+
+    isItemSelected = (e) => {
+        if(this.state.selectedItems.hasOwnProperty(e))
+            return this.state.selectedItems[e]
+        return false
+    }
+
+
+    render(){
+        const options = this.props.options.map((item, key) => <SelectableOption key={key} value={item.value} isSelected={this.isItemSelected(item.value)} onSelectedItem={this.itemSelected}>{item.label}</SelectableOption>)
+        const jsx = (
+            <Dropdown  isOpen={this.state.isOpen} toggle={this.toggle} className={this.props.className}>
+                <DropdownToggle caret>
+                    {this.renderLabel()}
+                </DropdownToggle>
+                <DropdownMenu style={{width:'max-content'}}>
+                    {options}
+                </DropdownMenu>
+            </Dropdown>
+        )
+        return jsx;
+    }
+}
+
+export default MultiSelectDropdown
diff --git a/LCU/Maintenance/MDB_WebView/maintenancedb_view/src/pages/DetailsPage.js b/LCU/Maintenance/MDB_WebView/maintenancedb_view/src/pages/DetailsPage.js
index d7f531f9224..047689ab7e1 100644
--- a/LCU/Maintenance/MDB_WebView/maintenancedb_view/src/pages/DetailsPage.js
+++ b/LCU/Maintenance/MDB_WebView/maintenancedb_view/src/pages/DetailsPage.js
@@ -1,21 +1,14 @@
 import React, { Component } from 'react';
 import Header from '../components/header.js'
 
-var data = [
-  'cs001': 2,
-  'cs002': 2,
-  'cs003': 2,
-]
 class DetailsPage extends Component {
 
   render() {
-    var list = data.map((item) => <div>{item}</div>);
 
     return (
       <div>
         <Header active_page={this.props.location} />
         <div>Details Overview!</div>
-        <div>{list}</div>
       </div>
     );
   }
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 e734a71cab5..9785ecb51e8 100644
--- a/LCU/Maintenance/MDB_WebView/maintenancedb_view/src/pages/LandingPage.js
+++ b/LCU/Maintenance/MDB_WebView/maintenancedb_view/src/pages/LandingPage.js
@@ -8,19 +8,22 @@ import StationStatistics from '../components/StationStatistics.js';
 
 import {Responsive, WidthProvider} from 'react-grid-layout';
 import {Button, ButtonGroup, Form} from 'reactstrap';
+
 import * as moment from 'moment';
 import {connect} from "react-redux";
 import { setNewLayout } from "../redux/actions/landingPageActions";
-import { setPeriod, setStationGroup, setErrorsOnly } from "../redux/actions/mainFiltersActions";
+import { setPeriod, setStationGroup, setErrorsOnly, setErrorTypes } from "../redux/actions/mainFiltersActions";
 import { composeQueryString } from '../utils/utils.js';
 import { createGridPanel } from '../utils/grid.js';
 
+import MultiSelectDropdown from '../components/MultiSelectDropdown.js'
 import 'react-grid-layout/css/styles.css';
 import 'react-resizable/css/styles.css';
 import '../themes/lofar-styles.css';
 
 const ResponsiveGridLayout = WidthProvider(Responsive);
 
+
 /**
  * Class to display a secondary header for selecting data filters.
  * The state is managed by the LandingPage class.
@@ -40,7 +43,14 @@ class ToolBarC extends Component {
         this.props.setPeriod(i);
     }
 
+    onSelectionErrorTypes(errorTypes) {
+        this.props.setErrorTypes(errorTypes)
+    }
+
     render() {
+
+        let errorTypes = this.props.errorTypes.map(item => ({value:item, label:item}))
+
         return (<div className="toolbar-top">
             <Form inline>
                 <label htmlFor="selected-group">Station group&nbsp;&nbsp;</label>
@@ -65,6 +75,13 @@ class ToolBarC extends Component {
                     <Button color="info" onClick={() => this.onPeriodClick(21)} active={this.props.period === 21}>3 wk</Button>
                     <Button color="info" onClick={() => this.onPeriodClick(28)} active={this.props.period === 28}>4 wk</Button>
                 </ButtonGroup>
+                &nbsp;&nbsp;&nbsp;
+                <label>Error type&nbsp;&nbsp;</label>
+                <MultiSelectDropdown
+                    className="form-input"
+                    placeHolder="All"
+                    options={errorTypes}
+                    onSelectionChange={(e)=> this.onSelectionErrorTypes(e)}/>
             </Form>
         </div>);
     }
@@ -72,14 +89,16 @@ class ToolBarC extends Component {
 
 const mapStateToPropsToolBar = state => {
     return {
-        ...state.mainFilters
+        ...state.mainFilters,
+        ...state.appInitData
     };
 };
 
 const mapDispatchToPropsToolBar = {
     setStationGroup,
     setErrorsOnly,
-    setPeriod
+    setPeriod,
+    setErrorTypes,
 };
 
 const ToolBar = connect(mapStateToPropsToolBar, mapDispatchToPropsToolBar)(ToolBarC);
@@ -95,7 +114,8 @@ class LandingPageC extends Component {
             station_group: this.props.selectedStationGroup,
             errors_only: this.props.errorsOnly,
             n_station_tests: 4,
-            n_rtsm: 4
+            n_rtsm: 4,
+            error_types: this.props.errorTypes
         });
 
         return `${url}?${parametersString}`;
@@ -110,7 +130,8 @@ class LandingPageC extends Component {
             lookback_time: this.props.period,
             // ---- Optional parameters
             station_group: this.props.selectedStationGroup,
-            errors_only: this.props.errorsOnly
+            errors_only: this.props.errorsOnly,
+            error_types: this.props.errorTypes
         });
 
         return `${url}?${parametersString}`;
@@ -126,6 +147,7 @@ class LandingPageC extends Component {
         // ---- Optional parameters
         parameters.station_group = this.props.selectedStationGroup
         parameters.errors_only = this.props.errorsOnly
+        parameters.error_types = this.props.errorTypes
         const parametersString = composeQueryString(parameters)
 
         return `${url}&${parametersString}`;
@@ -150,6 +172,7 @@ class LandingPageC extends Component {
         parameters.errors_only = this.props.errorsOnly
         parameters.station_group = this.props.selectedStationGroup
         parameters.test_type = test_type
+        parameters.error_types = this.props.errorTypes
         const parametersString = composeQueryString(parameters)
 
         return `${url}&${parametersString}`;
diff --git a/LCU/Maintenance/MDB_WebView/maintenancedb_view/src/redux/actions/mainFiltersActions.js b/LCU/Maintenance/MDB_WebView/maintenancedb_view/src/redux/actions/mainFiltersActions.js
index adc9a53a187..c6bdd70742f 100644
--- a/LCU/Maintenance/MDB_WebView/maintenancedb_view/src/redux/actions/mainFiltersActions.js
+++ b/LCU/Maintenance/MDB_WebView/maintenancedb_view/src/redux/actions/mainFiltersActions.js
@@ -5,6 +5,7 @@ export const SET_ERRORS_ONLY = "SET_ERRORS_ONLY";
 export const SET_PERIOD = "SET_PERIOD";
 export const SET_DATE_RANGE = "SET_DATE_RANGE";
 export const SET_TEST_TYPE = "SET_TEST_TYPE";
+export const SET_ERROR_TYPES = "SET_ERROR_TYPES";
 
 export const setStationGroup = stationGroup => ({
   type: SET_STATION_GROUP,
@@ -35,3 +36,8 @@ export const setTestType = type => ({
   type: SET_TEST_TYPE,
   payload: { type }
 });
+
+export const setErrorTypes = type_list => ({
+    type: SET_ERROR_TYPES,
+    payload: { type_list }
+});
diff --git a/LCU/Maintenance/MDB_WebView/maintenancedb_view/src/redux/reducers/mainFilters.js b/LCU/Maintenance/MDB_WebView/maintenancedb_view/src/redux/reducers/mainFilters.js
index 7d9bdb9f0a7..97134b276e3 100644
--- a/LCU/Maintenance/MDB_WebView/maintenancedb_view/src/redux/reducers/mainFilters.js
+++ b/LCU/Maintenance/MDB_WebView/maintenancedb_view/src/redux/reducers/mainFilters.js
@@ -10,7 +10,8 @@ const initialState = {
     errorsOnly: false,
     period: 7,             // days
     startDate: moment().subtract(7, 'days'),
-    endDate: moment()
+    endDate: moment(),
+    errorTypes: []
 };
 
 
@@ -71,6 +72,14 @@ export default function(state = initialState, action) {
                 testType: type
             };
         }
+        case a.SET_ERROR_TYPES: {
+            const { type_list }  = action.payload;
+
+            return {
+                ...state,
+                errorTypes: type_list
+            }
+        }
         default:
             return state;
     }
diff --git a/LCU/Maintenance/MDB_WebView/maintenancedb_view/src/themes/lofar-styles.css b/LCU/Maintenance/MDB_WebView/maintenancedb_view/src/themes/lofar-styles.css
index 5362252bddc..8299bf97e06 100644
--- a/LCU/Maintenance/MDB_WebView/maintenancedb_view/src/themes/lofar-styles.css
+++ b/LCU/Maintenance/MDB_WebView/maintenancedb_view/src/themes/lofar-styles.css
@@ -101,3 +101,12 @@
   background-color: white !important;
   color: black !important;
   border: 1px solid #8d8d8d; }
+
+.react-select-container {
+  min-width: 20rem; }
+
+.form-input button {
+  font-size: .8rem;
+  background-color: white !important;
+  color: black !important;
+  border: none; }
diff --git a/LCU/Maintenance/MDB_WebView/maintenancedb_view/src/themes/lofar-styles.scss b/LCU/Maintenance/MDB_WebView/maintenancedb_view/src/themes/lofar-styles.scss
index 6e91e5fa74f..ca65f46782d 100644
--- a/LCU/Maintenance/MDB_WebView/maintenancedb_view/src/themes/lofar-styles.scss
+++ b/LCU/Maintenance/MDB_WebView/maintenancedb_view/src/themes/lofar-styles.scss
@@ -115,3 +115,17 @@ $griditem-color: $secondary-dark;
     border: 1px solid $secondary-dark;
 
 }
+.react-select-container{
+    min-width: 20rem;
+}
+
+.form-input {
+
+}
+
+.form-input button{
+    font-size: .8rem;
+    background-color: white !important;
+    color: black !important;
+    border: none;
+}
diff --git a/LCU/Maintenance/MDB_WebView/maintenancedb_view/src/themes/lofar.css b/LCU/Maintenance/MDB_WebView/maintenancedb_view/src/themes/lofar.css
index b5616d6e3a1..255b22d2bc9 100644
--- a/LCU/Maintenance/MDB_WebView/maintenancedb_view/src/themes/lofar.css
+++ b/LCU/Maintenance/MDB_WebView/maintenancedb_view/src/themes/lofar.css
@@ -6420,3 +6420,12 @@ a.text-dark:hover, a.text-dark:focus {
   background-color: white !important;
   color: black !important;
   border: 1px solid #8d8d8d; }
+
+.react-select-container {
+  min-width: 20rem; }
+
+.form-input button {
+  font-size: .8rem;
+  background-color: white !important;
+  color: black !important;
+  border: none; }
-- 
GitLab