frontend/app/searchnbrowse/ResultsPanel.tsx (126 lines of code) (raw):

import React, {ErrorInfo} from "react"; import PropTypes from "prop-types"; import EntrySummaryLi from "./EntrySummaryLi"; import DetailsPanel from "./DetailsPanel.jsx"; import { withStyles } from "@material-ui/core/styles"; import SearchComponentContext from "./SearchComponentContext"; import {createStyles} from "@material-ui/core"; import {WithStyles} from "@material-ui/styles"; const styles = createStyles({ container: { marginLeft: "auto", marginRight: "auto", overflow: "hidden", width: "90vw", marginTop: "2em", height: "80vh", display: "grid", borderStyle: "dashed", paddingBottom: "1em", gridTemplateColumns: "50% 50%", gridTemplateRows: "3.4em auto", }, titleRow: { gridColumnStart: 1, gridColumnEnd: 3, gridRowStart: 1, gridRowEnd: 2, borderBottomStyle: "dashed", borderBottomWidth: "thin", padding: "0.5em", }, subPanel: { overflowX: "hidden", overflowY: "auto", }, leftPanel: { borderRightStyle: "dashed", borderRightWidth: "thin", gridColumnStart: 1, gridColumnEnd: 2, gridRowStart: 2, gridRowEnd: 3, }, rightPanel: { gridColumnStart: 2, gridColumnEnd: 3, gridRowStart: 2, gridRowEnd: 3, }, }); interface ResultsPanelProps extends WithStyles<typeof styles>{ entries: FileEntry[]; previewRequestedCb: (oid:string)=>void; projectClicked?: (projectId:string)=>void; } interface ResultsPanelState { selectedEntry?: FileEntry; internalError?: string; classes?: any; } class ResultsPanel extends React.Component<ResultsPanelProps, ResultsPanelState> { static propTypes = { entries: PropTypes.array.isRequired, previewRequestedCb: PropTypes.func.isRequired, projectClicked: PropTypes.func, }; constructor(props:ResultsPanelProps) { super(props); this.state = { selectedEntry: undefined, internalError: undefined, }; this.entryClicked = this.entryClicked.bind(this); } static getDerivedStateFromError(err:Error) { return { internalError: err.toString(), }; } componentDidCatch(error:Error, errorInfo:ErrorInfo) { console.error("The following error occurred in ResultsPanel:"); console.error(error, errorInfo); } entrySummary() { return "Found " + this.props.entries.length + " files"; } entryClicked(selectedEntry:FileEntry) { this.setState({ selectedEntry: selectedEntry }); } render() { if (this.state.internalError) { return ( <div className="results-panel"> <div className="results-subpanel-wide"> <p className="error"> The results panel failed: {this.state.internalError} </p> <p className="error">Please reload the page</p> </div> </div> ); } return ( <div className={this.props.classes.container}> <div className={this.props.classes.titleRow}> <span className="centered large">{this.entrySummary()}</span> </div> <div className={`${this.props.classes.subPanel} ${this.props.classes.leftPanel}`} > <ul className="silent-list"> {this.props.entries.map((entry) => ( <EntrySummaryLi entry={entry} entryClickedCb={this.entryClicked} /> ))} </ul> </div> <DetailsPanel className={`${this.props.classes.subPanel} ${this.props.classes.rightPanel}`} entry={this.state.selectedEntry} previewRequestedCb={this.props.previewRequestedCb} projectClicked={this.props.projectClicked} /> </div> ); } } ResultsPanel.contextType = SearchComponentContext; export default withStyles(styles)(ResultsPanel);