diff --git a/.gitattributes b/.gitattributes index 57001489031cf553df53ce053af101bbf462493e..9c6fdcfbe4bdc7b05fcea8dcca990ea78c63d9fd 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1862,6 +1862,7 @@ LCU/Maintenance/MDB_WebView/maintenancedb_view/src/components/StationOverview.cs LCU/Maintenance/MDB_WebView/maintenancedb_view/src/components/StationOverview.js -text LCU/Maintenance/MDB_WebView/maintenancedb_view/src/components/StationOverview.scss -text LCU/Maintenance/MDB_WebView/maintenancedb_view/src/components/StationStatistics.js -text +LCU/Maintenance/MDB_WebView/maintenancedb_view/src/components/StationTestChildView.js -text LCU/Maintenance/MDB_WebView/maintenancedb_view/src/components/StationTestDetails.js -text LCU/Maintenance/MDB_WebView/maintenancedb_view/src/components/StationTestSummary.css -text LCU/Maintenance/MDB_WebView/maintenancedb_view/src/components/StationTestSummary.js -text @@ -1885,6 +1886,7 @@ LCU/Maintenance/MDB_WebView/maintenancedb_view/src/pages/TilesPage.js -text LCU/Maintenance/MDB_WebView/maintenancedb_view/src/redux/actions/appInitDataActions.js -text LCU/Maintenance/MDB_WebView/maintenancedb_view/src/redux/actions/landingPageActions.js -text LCU/Maintenance/MDB_WebView/maintenancedb_view/src/redux/actions/mainFiltersActions.js -text +LCU/Maintenance/MDB_WebView/maintenancedb_view/src/redux/actions/stationOverviewPageActions.js -text LCU/Maintenance/MDB_WebView/maintenancedb_view/src/redux/reducers/appInitDataReducers.js -text LCU/Maintenance/MDB_WebView/maintenancedb_view/src/redux/reducers/index.js -text LCU/Maintenance/MDB_WebView/maintenancedb_view/src/redux/reducers/landingPageReducers.js -text diff --git a/LCU/Maintenance/MDB_WebView/maintenancedb_view/package.json b/LCU/Maintenance/MDB_WebView/maintenancedb_view/package.json index 9d29380d0396fd1c1427e2d102c4b06eb32daef3..4cb434341b3a3a16fc76df4f7600c9de4ae9b986 100644 --- a/LCU/Maintenance/MDB_WebView/maintenancedb_view/package.json +++ b/LCU/Maintenance/MDB_WebView/maintenancedb_view/package.json @@ -2,7 +2,7 @@ "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", + "proxy": "http://localhost:8080", "scripts": { "flow": "flow", "build-css": "node-sass-chokidar src/ -o src/", diff --git a/LCU/Maintenance/MDB_WebView/maintenancedb_view/src/components/StationTestChildView.js b/LCU/Maintenance/MDB_WebView/maintenancedb_view/src/components/StationTestChildView.js new file mode 100644 index 0000000000000000000000000000000000000000..4e3ce25c2b940bc01800efe7caed8920447abd30 --- /dev/null +++ b/LCU/Maintenance/MDB_WebView/maintenancedb_view/src/components/StationTestChildView.js @@ -0,0 +1,99 @@ +import React, { + Component +} from 'react'; +import {connect} from "react-redux"; +import {setChildPanelData} from '../redux/actions/stationOverviewPageActions' + +import { + Table, + Badge, + Tooltip, + NavItem, + NavLink, + TabPane, + TabContent, + Nav +} from 'reactstrap'; +import { IoMdArrowDropdown as DropDownIcon} from 'react-icons/io'; +import { + unique_id +} from '../utils/utils.js' +import AutoLoadWrapper from '../utils/autoLoader.js' +import './StationOverview.css' +import './StationTestView.css' +import * as LOFARDefinitions from '../utils/LOFARDefinitions' +import '../themes/lofar-styles.css' +import ReactTableContainer from "react-table-container"; +import moment from 'moment'; +import classnames from 'classnames'; + + + +class StationTestChildViewC extends Component { + + render(){ + let renderedErrorsPerPolarization = []; + let errorDetails = []; + + if(this.props.data !== null){ + for(let polarization of ['X', 'Y']){ + renderedErrorsPerPolarization.push( + <tr key={polarization}><th scope="row">{polarization}</th> + {this.props.data[polarization].map((item, key) => + <td key={key}><Badge className='error-type-badge'>{item.error_type}</Badge></td>)} + </tr> + ) + this.props.data[polarization].forEach((item, key) => { + + let renderDetails = <em>see element error</em> + if(Object.keys(item.details).length> 0){ + renderDetails = ( + <ul style={{listStyleType: 'none'}}> + {Object.keys(item.details).map((parameter, key) =>{ + const parameter_value = item.details[parameter] + const rendered_parameter = parameter === 'percentage'? parameter_value.toFixed(2) + '%' : parameter_value + + return (<li key={key}>{parameter}: {rendered_parameter}</li>) + }) + } + </ul>) + } + errorDetails.push( + <React.Fragment key={key + polarization}> + <div><em>{polarization} - {item.error_type}</em></div> + {renderDetails} + </React.Fragment> + ) + }) + } + } + + + const jsx = ( + <div> + <h5>Errors details</h5> + <Table size='sm'> + <tbody> + {renderedErrorsPerPolarization} + </tbody> + </Table> + {errorDetails} + </div> + ) + return jsx + + } +} + + +/* Add some magic; use the AutoLoadWrapper to create a HOC that handles the + auto-loading of the data for StationOverviewC. + */ +const StationTestChildView = connect(state => { + return { + ...state.station_page.child_panel, + }; +})(StationTestChildViewC); + + +export default StationTestChildView; diff --git a/LCU/Maintenance/MDB_WebView/maintenancedb_view/src/components/StationTestView.js b/LCU/Maintenance/MDB_WebView/maintenancedb_view/src/components/StationTestView.js index ad9c037b16ebfb7011135bcdad2fe5656f12f1a0..4c659fc5766f2b7d4b269ef55eafc347df1a02ad 100644 --- a/LCU/Maintenance/MDB_WebView/maintenancedb_view/src/components/StationTestView.js +++ b/LCU/Maintenance/MDB_WebView/maintenancedb_view/src/components/StationTestView.js @@ -2,6 +2,8 @@ import React, { Component } from 'react'; import {connect} from "react-redux"; +import {setChildPanelData} from '../redux/actions/stationOverviewPageActions' + import { Table, Badge, @@ -56,20 +58,9 @@ function RCUIDFromAntennaNumberPolarization(antennaNumber, polarization, compone return {id:antennaNumber} } } -class GenericStatus extends Component { - constructor (props) { - super(props) - this.toggleTooltip = this.toggleTooltip.bind(this) - this.state = {isTooltipOpen: false} - this.id = unique_id() - } - toggleTooltip () { - if(this.state.isTooltipOpen){ - } - this.setState({isTooltipOpen: !this.state.isTooltipOpen}) - } +class GenericStatusC extends Component { getClass(){ switch(this.props.status){ @@ -81,76 +72,42 @@ class GenericStatus extends Component { return 'so-stationtestbadge so-undefined' } } - renderTooltip() { - let renderedErrorsPerPolarization = [] - - let errorDetails = [] - if(this.props.errors_per_polarization !== undefined){ - for(let polarization of ['X', 'Y']){ - renderedErrorsPerPolarization.push( - <tr key={polarization}><th scope="row">{polarization}</th> - {this.props.errors_per_polarization[polarization].map((item, key) => - <td key={key}><Badge className='error-type-badge'>{item.error_type}</Badge></td>)} - </tr> - ) - this.props.errors_per_polarization[polarization].forEach((item, key) => { - - let renderDetails = <em>see element error</em> - if(Object.keys(item.details).length> 0){ - renderDetails = ( - <ul style={{listStyleType: 'none'}}> - {Object.keys(item.details).map((parameter, key) =>{ - const parameter_value = item.details[parameter] - const rendered_parameter = parameter === 'percentage'? parameter_value.toFixed(2) + '%' : parameter_value - - return (<li key={key}>{parameter}: {rendered_parameter}</li>) - }) - } - </ul>) - } - errorDetails.push( - <React.Fragment key={key + polarization}> - <div><em>{polarization} - {item.error_type}</em></div> - {renderDetails} - </React.Fragment> - ) - }) - } + onMouseOver = () => { + if (this.props.errors_per_polarization) { + this.props.setChildPanelData(this.props.errors_per_polarization); } + } - - const jsx = ( - <Tooltip isOpen={this.state.isTooltipOpen} - target={this.id} - className = {'tooltip'} - placement='auto' toggle={this.toggleTooltip}> - <h5>Errors details</h5> - <Table size='sm'> - <tbody> - {renderedErrorsPerPolarization} - </tbody> - </Table> - {errorDetails} - </Tooltip> - ) - return jsx + onMouseOut = () => { + if (this.props.errors_per_polarization) { + this.props.setChildPanelData(null); + } } + render(){ - let Tooltip= undefined - if(this.props.errors_per_polarization) { - Tooltip = this.renderTooltip() + let jsx = ""; + + if (this.props.errors_per_polarization) { + jsx = <td className='component-status' onMouseOver={this.onMouseOver} onMouseOut={this.onMouseOut}> + <div className={this.getClass()}>{this.props.n_errors}</div> + </td> } - const jsx = ( - <td id={this.id} className='component-status'> - <div className={this.getClass()}>{this.props.n_errors}</div> - {Tooltip} - </td> - ) + else { + jsx = <td className='component-status'> + <div className={this.getClass()}>{this.props.n_errors}</div> + </td> + } + return jsx; } } +const GenericStatus = connect(null, { + setChildPanelData +})(GenericStatusC); + + class StationSummaryLine extends Component { formatDate(date){ const result = moment(date).format('DD-MM-YYYY HH:mm'); @@ -227,17 +184,20 @@ class StationSummaryLine extends Component { } class RTSMSummaryLine extends Component { + constructor(props){ super(props); this.state = {displaySingleTests: false} } + renderTestLine(key, data, component_id_list){ return (<StationSummaryLine className="collapse open" key={key} ordered_component_ids={component_id_list} test_type="RT" component_type={this.props.component_type} station_type={this.props.station_type} data={data}/>) } + renderTestSummaryLine(data, component_id_list){ const result = component_id_list.map((item, key) => { if(data[item] > 0){ - return (<td key={key} className={'rtsm-summary-badge'}>{data[item].toFixed(1) + '%'} </td> ); + return (<td key={key} className={'rtsm-summary-badge'}>{data[item].toFixed(0) + '%'} </td> ); }else{ return (<GenericStatus key={key} status={'ok'} n_errors={data[item].toFixed(0)} />); } @@ -428,10 +388,10 @@ class StationTestViewC extends Component { } isActiveClass = (componentType) => { - const className = this.state.activeTab === componentType ? 'active' : 'unactive' return className } + render() { const stationType = LOFARDefinitions.stationTypeFromName(this.props.selectedStation); @@ -441,10 +401,12 @@ class StationTestViewC extends Component { onClick={() => this.toggle(componentType)}>{componentType}</NavLink> </NavItem>) ); + const componentListTabs = Object.keys(this.props.data).map((componentType, key) => - <TabPane key={key} tabId={componentType}> - <ComponentClass key={key} station_type={stationType} type={componentType} data={this.props.data[componentType]}/> - </TabPane>); + <TabPane key={key} tabId={componentType}> + <ComponentClass key={key} station_type={stationType} type={componentType} data={this.props.data[componentType]}/> + </TabPane> + ); return ( <div> diff --git a/LCU/Maintenance/MDB_WebView/maintenancedb_view/src/pages/StationOverviewPage.js b/LCU/Maintenance/MDB_WebView/maintenancedb_view/src/pages/StationOverviewPage.js index 0ac5d765cf4c49b352ba7049a741dc963449cf4b..129f77e773d470c7ef49a7804066f9c543b2b13f 100644 --- a/LCU/Maintenance/MDB_WebView/maintenancedb_view/src/pages/StationOverviewPage.js +++ b/LCU/Maintenance/MDB_WebView/maintenancedb_view/src/pages/StationOverviewPage.js @@ -1,5 +1,6 @@ import React, { Component } from 'react'; import {connect} from "react-redux"; +import {Responsive, WidthProvider} from 'react-grid-layout'; import {Alert, Button, ButtonGroup} from 'reactstrap'; import { setDateRange, setTestType, setStation } from "../redux/actions/mainFiltersActions"; import DatePicker from 'react-datepicker'; @@ -8,6 +9,8 @@ import moment from 'moment'; import Header from '../components/header.js' import StationAutoComplete from '../components/StationAutoComplete'; import StationTestView from '../components/StationTestView'; +import StationTestChildView from '../components/StationTestChildView'; +import { createGridPanel } from '../utils/grid.js'; import { composeQueryString } from '../utils/utils.js'; @@ -18,6 +21,9 @@ import { push } from 'connected-react-router'; import { store } from "../redux/store.js"; +const ResponsiveGridLayout = WidthProvider(Responsive); + + /** * Class to display a secondary header for selecting data filters. * The state is managed by the LandingPage class. @@ -139,6 +145,7 @@ const mapDispatchToPropsToolBar = { const ToolBar = connect(mapStateToPropsToolBar, mapDispatchToPropsToolBar)(ToolBarC); class StationOverviewPageC extends Component { + getStationSummaryURL(){ const parameters = {}; @@ -163,7 +170,8 @@ class StationOverviewPageC extends Component { renderErrorIfParameterMissing(){ if (this.isParameterMissing()){ - return <Alert color="warning">Please select a station</Alert> + // The 10px is the margin that ResponsiveGridLayout uses + return <Alert style={{margin: '10px'}} color="warning">Please select a station</Alert> }else { return "" } @@ -176,7 +184,24 @@ class StationOverviewPageC extends Component { <Header active_page={this.props.location} /> <ToolBar/> {this.renderErrorIfParameterMissing()} - <StationTestView url={this.getStationSummaryURL()}/> + + <ResponsiveGridLayout className="layout" layouts={this.props.layout.panels} measureBeforeMount={true} + breakpoints={this.props.layout.breakpoints} cols={this.props.layout.cols} + onResizeStop={this.props.setNewLayout}> + {createGridPanel({ + key: "ul", + renderHeader: false, + title: "Station overview", + body: <StationTestView url={this.getStationSummaryURL()}/> + })} + {createGridPanel({ + key: "ur", + renderHeader: false, + title: "Latest observations", + body: <StationTestChildView /> + })} + </ResponsiveGridLayout> + </React.Fragment> ); } diff --git a/LCU/Maintenance/MDB_WebView/maintenancedb_view/src/redux/actions/stationOverviewPageActions.js b/LCU/Maintenance/MDB_WebView/maintenancedb_view/src/redux/actions/stationOverviewPageActions.js new file mode 100644 index 0000000000000000000000000000000000000000..2f4543088edaf9a9f97a21049d2e21547bcb1946 --- /dev/null +++ b/LCU/Maintenance/MDB_WebView/maintenancedb_view/src/redux/actions/stationOverviewPageActions.js @@ -0,0 +1,7 @@ +export const SET_CHILD_PANEL_DATA = "SET_CHILD_PANEL_DATA"; + + +export const setChildPanelData = data => ({ + type: SET_CHILD_PANEL_DATA, + payload: { data } +}); diff --git a/LCU/Maintenance/MDB_WebView/maintenancedb_view/src/redux/reducers/stationOverviewPageReducers.js b/LCU/Maintenance/MDB_WebView/maintenancedb_view/src/redux/reducers/stationOverviewPageReducers.js index 94633eaaf31b845fd0572cff4110274256b0920d..164a44b19b19964d5ea29950bcd98d99be566c3f 100644 --- a/LCU/Maintenance/MDB_WebView/maintenancedb_view/src/redux/reducers/stationOverviewPageReducers.js +++ b/LCU/Maintenance/MDB_WebView/maintenancedb_view/src/redux/reducers/stationOverviewPageReducers.js @@ -1,5 +1,15 @@ +import { + SET_CHILD_PANEL_DATA +} from '../actions/stationOverviewPageActions.js' + const initialState = { + + // Child panel showing data on mouse hover + child_panel: { + data: null + }, + layout: { breakpoints: { md: 996, @@ -48,6 +58,14 @@ const initialState = { export default function(state = initialState, action) { switch (action.type) { + case SET_CHILD_PANEL_DATA: + return { + ...state, + child_panel: { + data: action.payload.data + } + }; + default: return state; }