frontend/app/ProxyHealthDetail/ProxyHealthDetail.jsx (214 lines of code) (raw):

import React from 'react'; import axios from 'axios'; import TimestampFormatter from "../common/TimestampFormatter"; import TimestampDiffComponent from "../common/TimestampDiffComponent.jsx"; import ByCollectionChart from "./ByCollectionChart.jsx"; import GeneralOverviewChart from "./GeneralOverviewChart.jsx"; import InfoTable from "./InfoTable"; import AdminContainer from "../admin/AdminContainer"; import { Button, CircularProgress, Divider, Grid, Paper, Snackbar, Tooltip, Typography, withStyles } from "@material-ui/core"; import MuiAlert from "@material-ui/lab/Alert"; import {proxyHealthStyles} from "./ProxyHealthStyles"; import {Helmet} from "react-helmet"; import {formatError} from "../common/ErrorViewComponent"; class ProxyHealthDetail extends React.Component { constructor(props) { super(props); this.state = { loading: false, showingAlert: false, lastError: null, collectionSummary: [], mostRecentRun: null, previousRuns: [], tableData: [], selectedCollection: null, tableStart: 0, tablePageSize: 100, tableMaxSize: 2500, triggerInProgress: false }; this.closeAlert = this.closeAlert.bind(this); this.collectionSelectedCb = this.collectionSelectedCb.bind(this); this.triggerSelectedCollectionFix = this.triggerSelectedCollectionFix.bind(this); } collectionSelectedCb(selected) { console.log("selected collection " + selected); this.setState({selectedCollection: selected}, ()=>this.reloadTableData()); } loadData() { return new Promise((resolve, reject)=> { const loadingFuture = [ axios.get("/api/proxyhealth/mostrecent"), axios.get("/api/proxyhealth/problemitems/collectionlist") ]; this.setState({loading: true, lastError: null}, () => { axios.all(loadingFuture).then(responseList => { this.setState({ loading: false, lastError: null, collectionSummary: responseList[1].data.entries, mostRecentRun: responseList[0].data.entry }, ()=>resolve()) }).catch(err => { console.error(err); this.setState({ loading: false, lastError: err, showingAlert: true }, ()=>reject(err)) }) }) }); } static filePathSplitter = /^(.*)\/([^\/]+)$/; /** * splits a filepath into filename/pathname components * @param filePath */ splitPath(filePath){ const parts = ProxyHealthDetail.filePathSplitter.exec(filePath); if(parts && parts.length>1){ return [parts[1], parts[2]]; } else { return [filePath, ""]; } } convertVerifyResultFor(resultList, requiredType) { const matches = resultList.filter(entry=>entry.proxyType===requiredType); if(matches.length>0){ return { wantProxy: matches[0].wantProxy, haveProxy: matches[0].haveProxy, known: true } } else { return { known: false, wantProxy: false, haveProxy: false } } } /** * takes a problem item entry from the server and converts it to a form that the table wants */ convertToTableData(incomingData){ return incomingData.map(entry=>{ const pathParts = this.splitPath(entry.filePath); return { id: entry.fileId, fileId: entry.fileId, collection: entry.collection, esRecordSays: entry.esRecordSays, filePath: pathParts[0], fileName: pathParts[1], thumbnailResult: this.convertVerifyResultFor(entry.verifyResults, "THUMBNAIL"), videoResult: this.convertVerifyResultFor(entry.verifyResults, "VIDEO"), audioResult: this.convertVerifyResultFor(entry.verifyResults, "AUDIO") } }) } /** * get another page of data from the server and put it into the table. "Recurses" until there are state.tableMaxSize rows available. */ loadMoreTableData() { const uri = "/api/proxyhealth/problemitems?size=" + this.state.tablePageSize + "&start=" + this.state.tableStart; const finalUri = this.state.selectedCollection ? uri + "&collection=" + this.state.selectedCollection : uri; this.setState({loading: true, lastError:null}, ()=>axios.get(finalUri).then(response=>{ this.setState({ loading: false, lastError: null, tableData: this.state.tableData.concat(this.convertToTableData(response.data.entries)) },()=>{ if(this.state.tableData.length<this.state.tableMaxSize) this.loadMoreTableData(); }); }).catch(err=>{ console.error(err); this.setState({loading: false, lastError: err, showingAlert: true}); })) } /** * blank out current table data and load from the start */ reloadTableData() { this.setState({tableData:[], tableStart: 0}, ()=>this.loadMoreTableData()); } componentDidMount() { this.loadData().then(()=>this.reloadTableData()); } triggerSelectedCollectionFix(){ this.setState({triggerInProgress: true}, ()=>axios.post("/api/proxyhealth/triggerproblems/" + this.state.selectedCollection) .then(response=>{ this.setState({triggerInProgress: false}) }).catch(err=>{ console.error(err); this.setState({triggerInProgress: false, lastError: err, showingAlert: true}); })) } closeAlert() { this.setState({showingAlert: false}) } render() { return <AdminContainer {...this.props}> <Helmet> <title>Proxy Health - ArchiveHunter</title> </Helmet> <Snackbar open={this.state.showingAlert} onClose={this.closeAlert} autoHideDuration={8000}> { this.state.lastError ? <MuiAlert severity="error" onClose={this.closeAlert}>{formatError(this.state.lastError)}</MuiAlert> : null } </Snackbar> <Grid container className={this.props.classes.chartsBar} spacing={3} justify="space-between"> <Grid item className={this.props.classes.chartContainer}> <Typography variant="h5">Proxy Health</Typography> {this.state.mostRecentRun ? <Paper elevation={0}> <Typography>Last check:</Typography> <ul> <li> <Typography> was at <TimestampFormatter relative={false} value={this.state.mostRecentRun.scanStart} formatString="hh:mm:ss a [on] MMMM Do YYYY"/> </Typography> </li> <li> <Typography> completed <TimestampDiffComponent startTime={this.state.mostRecentRun.scanStart} endTime={this.state.mostRecentRun.scanFinish}/> </Typography> </li> </ul> { this.state.selectedCollection ? <Tooltip title={"Re-run proxies for " + this.state.selectedCollection ? this.state.selectedCollection : "(none)"}> <Button onClick={this.triggerSelectedCollectionFix} disabled={this.state.triggerInProgress}>Re-create</Button> </Tooltip> : null } </Paper> : <div><CircularProgress/><Typography>Loading...</Typography></div> } </Grid> <Grid item className={this.props.classes.chartContainer}> <GeneralOverviewChart recentCountData={this.state.mostRecentRun}/> </Grid> <Grid item className={this.props.classes.chartContainer} > <ByCollectionChart facetData={this.state.collectionSummary} dataSeriesClicked={this.collectionSelectedCb}/> </Grid> </Grid> <Divider className={this.props.classes.chartDivider}/> <InfoTable tableData={this.state.tableData}/> </AdminContainer> } } export default withStyles(proxyHealthStyles)(ProxyHealthDetail);