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 </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> + + <label>Error type </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