diff --git a/LCU/Maintenance/MDB_WebView/maintenancedb_view/package.json b/LCU/Maintenance/MDB_WebView/maintenancedb_view/package.json index 4cb434341b3a3a16fc76df4f7600c9de4ae9b986..9d29380d0396fd1c1427e2d102c4b06eb32daef3 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://localhost:8080", + "proxy": "http://lofarmonitortest.control.lofar", "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 index 1c03d704d19cadcdc107f84a1e7a512c6a7fa14a..952368d0354343f292e5093fbdff1bde2f2262e5 100644 --- a/LCU/Maintenance/MDB_WebView/maintenancedb_view/src/components/StationTestChildView.js +++ b/LCU/Maintenance/MDB_WebView/maintenancedb_view/src/components/StationTestChildView.js @@ -2,9 +2,10 @@ import React, { Component } from 'react'; import {connect} from "react-redux"; -import {setChildPanelData} from '../redux/actions/stationOverviewPageActions' +import {unpinChildPanelData} from '../redux/actions/stationOverviewPageActions' import { + Button, Table, Badge, Tooltip, @@ -14,7 +15,7 @@ import { TabContent, Nav } from 'reactstrap'; -import { IoMdArrowDropdown as DropDownIcon} from 'react-icons/io'; +import { IoMdCloseCircleOutline as CloseIcon} from 'react-icons/io'; import { unique_id } from '../utils/utils.js' @@ -27,98 +28,71 @@ import ReactTableContainer from "react-table-container"; import moment from 'moment'; import classnames from 'classnames'; +import './StationTestChildView.css'; -class StationTestChildViewC extends Component { - - render(){ - if (this.props.data === null) { - return <i>Hover mouse over an error</i>; - } +class StationTestChildViewC extends Component { - let renderedErrorsPerPolarization = []; - let errorDetails = []; - - 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> - ) - }) - } + unpinPanel = () => { + this.props.unpinChildPanelData(); + } + render() { + let rows; - let rows = []; + // default value when data is null + rows = <tr><td><i>Hover the mouse over an error to view the details. Right-click on the error to pin it on this panel.</i></td></tr>; - for (let polarization of ['X', 'Y']){ - let d = this.props.data[polarization]; - let p = polarization; + if (this.props.data !== null) { + rows = []; - let err_types = Object.keys(d); + for (let polarization of ['X', 'Y']){ + let d = this.props.data[polarization]; + let p = polarization; - d.forEach((item, key) => { + let err_types = Object.keys(d); - let err_details = Object.keys(item.details).map((parameter, key) =>{ - const parameter_value = item.details[parameter] - const rendered_parameter = parameter === 'percentage'? parameter_value.toFixed(2) + '%' : parameter_value + d.forEach((item, key) => { - return (<li key={key}>{parameter}: {rendered_parameter}</li>) - }); + let err_details = Object.keys(item.details).map((parameter, key) =>{ + const parameter_value = item.details[parameter] + const rendered_parameter = parameter === 'percentage'? parameter_value.toFixed(2) + '%' : parameter_value + if (parameter !== 'url') { + return (<li key={key}>{parameter}: {rendered_parameter}</li>) + } + }); - if (err_details.length === 0) { - err_details = <li><em>see element error</em></li>; - } + if (err_details.length === 0) { + err_details = <li><em>see element error</em></li>; + } - rows.push( - <tr key={p}> - <th scope="row">{p}</th> - <td key={key}> - <Badge className='error-type-badge'>{item.error_type}</Badge> - </td> - <td> - <ul style={{listStyleType: 'none'}}> - { err_details } - </ul> - </td> - </tr> - ); + rows.push( + <tr key={p}> + <th scope="row">{p} - <Badge className='error-type-badge'>{item.error_type}</Badge></th> + <td> + <ul style={{listStyleType: 'none'}}> + { err_details } + </ul> + </td> + </tr> + ); - p = ""; - }); + p = ""; + }); + } + } + let unpinButton = ""; + if (this.props.isPinned) { + unpinButton = <Button title="Click to unpin the error details" color="info" size="xs" style={{float:'right'}} onClick={this.unpinPanel}> + <CloseIcon/> unpin + </Button> } return <div> - <h5>Errors details</h5> + <div className="stcv-header">Errors details {unpinButton}</div> <Table size='sm'> <tbody> {rows} @@ -136,6 +110,8 @@ const StationTestChildView = connect(state => { return { ...state.station_page.child_panel, }; +}, { + unpinChildPanelData })(StationTestChildViewC); 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 9b6152cfd90b706217f12f6c401dc2017fbcbc9d..e7691b30d61f5dd54a69b7409fbee9d30c066b1f 100644 --- a/LCU/Maintenance/MDB_WebView/maintenancedb_view/src/components/StationTestView.js +++ b/LCU/Maintenance/MDB_WebView/maintenancedb_view/src/components/StationTestView.js @@ -74,27 +74,38 @@ class GenericStatusC extends Component { } onMouseOver = () => { - if (this.props.errors_per_polarization) { - this.props.setChildPanelData(this.props.errors_per_polarization); - } + this.props.setChildPanelData(this.props.errors_per_polarization); } onMouseOut = () => { - if (this.props.errors_per_polarization) { - this.props.setChildPanelData(null); - } + this.props.setChildPanelData(null); + } + + // left-click with mouse + onClick = () => { + console.log('click (TODO, switch to tiles page)'); + } + + // right-click with mouse + onContextMenu = (e) => { + e.preventDefault(); + this.props.setChildPanelData(this.props.errors_per_polarization, true); } render(){ let jsx = ""; - if (this.props.errors_per_polarization) { - jsx = <td className={this.getClass()} onMouseOver={this.onMouseOver} onMouseOut={this.onMouseOut}> + if (this.props.n_errors > 0) { + jsx = <td className={this.getClass()} + onContextMenu={this.onContextMenu} + onClick={this.onClick} + onMouseOver={this.onMouseOver} + onMouseOut={this.onMouseOut}> {this.props.n_errors} </td> } else { - jsx = <td className={this.getClass()}> + jsx = <td className={this.getClass()} onClick={this.onClick}> {this.props.n_errors === 0 ? ' ' : this.props.n_errors} </td> } @@ -108,46 +119,20 @@ const GenericStatus = connect(null, { })(GenericStatusC); -class StationSummaryLine extends Component { +/** + * TestLine: renders a table row with the results of one station test or RTSM run. + */ +class TestLine extends Component { + formatDate(date){ const result = moment(date).format('DD-MM-YYYY HH:mm'); return result } - renderHeader(){ - const date = this.formatDate(this.props.data.end_date); - - const jsx = ( - <td>{this.props.test_type} {date}</td> - ) - return jsx - } - - renderHBA(){ - const jsx = this.renderHeader() - return <tr>{jsx}{this.renderComponentErrors()}</tr> - } - - renderLBH(){ - const jsx = this.renderHeader() - return <tr>{jsx}{this.renderComponentErrors()}</tr> - } - - renderLBL(){ - const jsx = this.renderHeader() - return <tr>{jsx}{this.renderComponentErrors()}</tr> - } - - renderGeneric(){ - const jsx = this.renderHeader() - return <tr>{jsx}{this.renderComponentErrors()}</tr> - } - renderComponentErrors(){ const component_errors = this.props.data.component_errors; - const component_type = this.props.component_type - const rendered_component_errors = this.props.ordered_component_ids.map((item, key) => - { + const component_type = this.props.component_type; + const rendered_component_errors = this.props.ordered_component_ids.map((item, key) => { let component_errors_count = 0 const errorsPerPolarization = {X:[], Y:[]} for(let polarization of ['X', 'Y']){ @@ -159,7 +144,6 @@ class StationSummaryLine extends Component { } if (component_errors_count > 0){ - return <GenericStatus key={key} component_id={item} errors_per_polarization={errorsPerPolarization} n_errors={component_errors_count} status = 'error' /> } else{ @@ -170,16 +154,12 @@ class StationSummaryLine extends Component { } render (){ - switch (this.props.component_type) { - case 'HBA': - return this.renderHBA(); - case 'LBH': - return this.renderLBH(); - case 'LBL': - return this.renderLBL(); - default: - return this.renderGeneric(); - } + const date = this.formatDate(this.props.data.end_date); + + return <tr> + <td>{this.props.test_type} {date}</td> + {this.renderComponentErrors()} + </tr> } } @@ -191,7 +171,7 @@ class RTSMSummaryLine extends Component { } 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}/>) + return (<TestLine 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){ @@ -223,6 +203,7 @@ class RTSMSummaryLine extends Component { Object.keys(summary).forEach(item => summary[item] /= n_tests/50. ) return summary } + renderDateRange(data){ const lastTest = data[0] const firstTest = data[data.length - 1] @@ -241,7 +222,9 @@ class RTSMSummaryLine extends Component { } toggleDisplaySingleTests = (e) => { - this.setState({displaySingleTests:!this.state.displaySingleTests}) + this.setState({ + displaySingleTests:!this.state.displaySingleTests + }); } render(){ @@ -264,7 +247,8 @@ class RTSMSummaryLine extends Component { RT {this.renderDateRange(this.props.data)} <DropDownIcon className={"line-header-dropdownbutton " + dropdownAdditionStyles} color="black" /> </td> - {summaryLine}</tr> + {summaryLine} + </tr> {all_rtsm} </React.Fragment> ) @@ -274,6 +258,14 @@ class RTSMSummaryLine extends Component { } } +/** + * ComponentClass; renders a table of station tests and rtsm data for a component (HBA, RSP, LBH, etc.) + * + * Props: + * station_type: C, R or I + * type: component type + * data: Data for this component + */ class ComponentClass extends Component { computeComponentIDList(componentType){ @@ -298,11 +290,11 @@ class ComponentClass extends Component { return jsx } - renderTestLine(key, data, component_id_list){ - return (<StationSummaryLine key={key} ordered_component_ids={component_id_list} test_type="ST" component_type={this.props.type} station_type={this.props.station_type} data={data}/>) + renderStationTestLine(key, data, component_id_list){ + return (<TestLine key={key} ordered_component_ids={component_id_list} test_type="ST" component_type={this.props.type} station_type={this.props.station_type} data={data}/>) } - renderTestSummaryLine(key, data, component_id_list){ + renderRTSMSummaryLine(key, data, component_id_list){ return (<RTSMSummaryLine key={key} ordered_component_ids={component_id_list} component_type={this.props.type} station_type={this.props.station_type} data={data}/>) } @@ -311,29 +303,28 @@ class ComponentClass extends Component { const rows = [] var tmp_rtsm_set = [] - for(let i=0; i<data.length - 1; i++){ + for (let i=0; i<data.length - 1; i++){ const next_item = data[i + 1] const current_item = data[i] - if(current_item.test_type === 'R' ){ + if (current_item.test_type === 'R' ){ tmp_rtsm_set.push(current_item) } - if(current_item.test_type === 'R' && next_item.test_type === 'S'){ - rows.push(this.renderTestSummaryLine(rows.length, tmp_rtsm_set, component_id_list)) + if (current_item.test_type === 'R' && next_item.test_type === 'S'){ + rows.push(this.renderRTSMSummaryLine(rows.length, tmp_rtsm_set, component_id_list)) tmp_rtsm_set = [] - }else if(current_item.test_type === 'S'){ - rows.push(this.renderTestLine(rows.length, current_item, component_id_list)); + } else if (current_item.test_type === 'S'){ + rows.push(this.renderStationTestLine(rows.length, current_item, component_id_list)); } } const lastTest = data[data.length - 1] - if(lastTest.test_type === 'R'){ + if (lastTest.test_type === 'R'){ tmp_rtsm_set.push(lastTest) - }else{ - rows.push(this.renderTestLine(rows.length, lastTest, component_id_list)); + } else { + rows.push(this.renderStationTestLine(rows.length, lastTest, component_id_list)); } if (tmp_rtsm_set.length > 0) { - rows.push(<RTSMSummaryLine key={rows.length} data={tmp_rtsm_set} component_type={this.props.type} ordered_component_ids={component_id_list}/>); - + rows.push(this.renderRTSMSummaryLine(rows.length, tmp_rtsm_set, component_id_list)) tmp_rtsm_set = [] } return rows @@ -405,7 +396,7 @@ class StationTestViewC extends Component { 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]}/> + <ComponentClass key={componentType} station_type={stationType} type={componentType} data={this.props.data[componentType]}/> </TabPane> ); 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 c45bff4342e38d84598290adbc2bfb558f2e70f3..76a59002d7c8af963a721fce93fb0e01bf769f09 100644 --- a/LCU/Maintenance/MDB_WebView/maintenancedb_view/src/pages/StationOverviewPage.js +++ b/LCU/Maintenance/MDB_WebView/maintenancedb_view/src/pages/StationOverviewPage.js @@ -184,16 +184,14 @@ class StationOverviewPageC extends Component { <Header active_page={this.props.location} /> <ToolBar/> {this.renderErrorIfParameterMissing()} - - - <Container fluid={true} style={{padding: '10px'}}> - <Row> - <Col md="8"><StationTestView url={this.getStationSummaryURL()} /></Col> - <Col md="4"><StationTestChildView /></Col> - </Row> - </Container> - - + { this.isParameterMissing() ? "" : + <Container fluid={true} style={{padding: '10px'}}> + <Row> + <Col md="8"><StationTestView url={this.getStationSummaryURL()} /></Col> + <Col md="4"><StationTestChildView /></Col> + </Row> + </Container> + } </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 index 2f4543088edaf9a9f97a21049d2e21547bcb1946..b9ed3425850e0273bfc6012993be1ba327df5c61 100644 --- a/LCU/Maintenance/MDB_WebView/maintenancedb_view/src/redux/actions/stationOverviewPageActions.js +++ b/LCU/Maintenance/MDB_WebView/maintenancedb_view/src/redux/actions/stationOverviewPageActions.js @@ -1,7 +1,12 @@ export const SET_CHILD_PANEL_DATA = "SET_CHILD_PANEL_DATA"; +export const UNPIN_CHILD_PANEL_DATA = "UNPIN_CHILD_PANEL_DATA"; - -export const setChildPanelData = data => ({ +export const setChildPanelData = (data, pin = false) => ({ type: SET_CHILD_PANEL_DATA, - payload: { data } + payload: { data, pin } +}); + +export const unpinChildPanelData = () => ({ + type: UNPIN_CHILD_PANEL_DATA, + payload: null }); 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 164a44b19b19964d5ea29950bcd98d99be566c3f..8e83e2a45aeb689bd51bf9b960fbc4eb7914a698 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,6 @@ import { - SET_CHILD_PANEL_DATA + SET_CHILD_PANEL_DATA, + UNPIN_CHILD_PANEL_DATA } from '../actions/stationOverviewPageActions.js' @@ -7,7 +8,8 @@ const initialState = { // Child panel showing data on mouse hover child_panel: { - data: null + data: null, + isPinned: false }, layout: { @@ -59,10 +61,23 @@ const initialState = { export default function(state = initialState, action) { switch (action.type) { case SET_CHILD_PANEL_DATA: + if (state.child_panel.isPinned && ! action.payload.pin) { + return state; + } return { ...state, child_panel: { - data: action.payload.data + data: action.payload.data, + isPinned: action.payload.pin + } + }; + + case UNPIN_CHILD_PANEL_DATA: + return { + ...state, + child_panel: { + data: null, + isPinned: false } };