frontend/app/ProjectValidationView.jsx (251 lines of code) (raw):

import React from "react"; import axios from "axios"; import GeneralListComponent from "./GeneralListComponent.jsx"; import ProjectTypeView from "./EntryViews/ProjectTypeView.jsx"; import WorkingGroupEntryView from "./EntryViews/WorkingGroupEntryView.jsx"; import CommissionEntryView from "./EntryViews/CommissionEntryView.jsx"; import { Link } from "react-router-dom"; import ErrorViewComponent from "./common/ErrorViewComponent.jsx"; import { Helmet } from "react-helmet"; import EnhancedTable from "./MaterialUITable"; import { Button } from "@material-ui/core"; import { openProject } from "./ProjectEntryList/helpers"; class ProjectValidationView extends React.Component { constructor(props) { super(props); this.state = { loading: false, totalProjectCount: 0, problemProjects: [], lastError: null, hasRun: false, }; this.columns = [ { header: "Id", key: "id", defaultSorting: "desc", dataProps: { className: "align-right" }, headerProps: { className: "dashboardheader" }, }, GeneralListComponent.standardColumn("Title", "title"), { header: "Pluto project", key: "vidispineId", render: this.getPlutoLink, headerProps: { className: "dashboardheader" }, }, { header: "Project type", key: "projectTypeId", render: (typeId) => <ProjectTypeView entryId={typeId} />, headerProps: { className: "dashboardheader" }, }, GeneralListComponent.dateTimeColumn("Created", "created"), GeneralListComponent.standardColumn("Owner", "user"), { header: "Working group", key: "workingGroupId", render: (typeId) => <WorkingGroupEntryView entryId={typeId} />, headerProps: { className: "dashboardheader" }, }, { header: "Commission", key: "commissionId", render: (typeId) => <CommissionEntryView entryId={typeId} />, headerProps: { className: "dashboardheader" }, }, this.actionIcons(), { header: "", key: "id", headerProps: { className: "dashboardheader" }, render: (projid) => ( <Button variant="contained" onClick={() => openProject(projid)}> Open project </Button> ), }, ]; this.style = { backgroundColor: "#eee", border: "1px solid black", borderCollapse: "collapse", }; this.iconStyle = { color: "#aaa", paddingLeft: "5px", paddingRight: "5px", }; this.runValidation = this.runValidation.bind(this); } breakdownPathComponents() { return this.props.location.pathname.split("/"); } /* this method supplies the edit and delete icons. Can't be static as <Link> relies on the object context to access * history. */ actionIcons() { const componentName = this.breakdownPathComponents()[1]; return { header: "", key: "id", render: (id) => ( <span className="icons" style={{ display: this.state.isAdmin ? "inherit" : "none" }} > <Link to={"/" + componentName + "/" + id}> <img className="smallicon" src="/assets/images/edit.png" /> </Link> <Link to={"/" + componentName + "/" + id + "/delete"}> <img className="smallicon" src="/assets/images/delete.png" /> </Link> </span> ), }; } getFilterComponent() { return <p />; } runValidation() { this.setState({ loading: true }, () => axios .post("/api/project/validate") .then((result) => { this.setState({ loading: false, hasRun: true, totalProjectCount: result.data.totalProjectsCount, problemProjects: result.data.failedProjectsList, }); }) .catch((err) => { console.error(err); this.setState({ loading: false, hasRun: true, lastError: err }); }) ); } itemLimitWarning() { if (this.state.maximumItemsLoaded) return ( <p className="warning-text"> <i className="fa-info fa" style={{ marginRight: "0.5em", color: "orange" }} /> Maximum of {GeneralListComponent.ITEM_LIMIT} items have been loaded. Use filters to narrow this down. </p> ); else return <p style={{ margin: 0 }} />; } showRunning() { if (this.state.loading) { return ( <p className="warning-text"> <img src="/assets/images/uploading.svg" className="smallicon" style={{ display: this.state.loading ? "inline" : "none", verticalAlign: "middle", marginRight: "1em", }} /> Searching for unlinked projects... </p> ); } else { return <p />; } } showResult() { if (!this.state.loading && !this.state.hasRun) { return ( <p style={{ marginLeft: "1em" }}> <i className="fa fa-3x fa-info-circle validation-status-text" style={{ color: "blue", verticalAlign: "middle" }} /> This function checks that all of the projects in the database exist at their correct filesystem location. <br /> Click "Run Validation" to perform the scan. </p> ); } if (!this.state.loading && this.state.hasRun) { if (this.state.totalProjectCount === 0) { return ( <p> <i className="fa fa-3x fa-exclamation-triangle validation-status-text" style={{ color: "orange", verticalAlign: "middle" }} /> Hmmm, there were no projects found to scan. </p> ); } if (this.state.problemProjects.length === 0) { return ( <p> <i className="fa fa-3x fa-smile-o validation-status-text" style={{ color: "#f9e100", verticalAlign: "middle" }} /> Hooray, no unlinked projects found! {this.state.totalProjectCount}{" "} projects checked successfully </p> ); } else { return ( <p> <i className="fa fa-3x fa-exclamation-triangle validation-status-text" style={{ color: "orange", verticalAlign: "middle" }} /> {this.state.problemProjects.length} projects were not found on their correct storage locations (scanned {this.state.totalProjectCount}{" "} projects in total) <br /> Affected projects are shown in the table below. </p> ); } } } showError() { if (!this.state.loading && this.state.lastError) { return <ErrorViewComponent error={this.state.lastError} />; } } render() { return ( <div> <Helmet> <title>Core Admin</title> </Helmet> <span className="list-title"> <h2 className="list-title">Validate Projects</h2> </span> {this.getFilterComponent()} {this.itemLimitWarning()} {this.showRunning()} {this.showError()} <span className="banner-control"> <button id="newElementButton" onClick={this.runValidation}> Run validation </button> </span> {this.showResult()} {this.state.problemProjects.length > 0 ? ( <EnhancedTable columnData={this.columns} tableData={this.state.problemProjects} /> ) : null} </div> ); } } export default ProjectValidationView;