import React from "react" ; import ReactDOM from "react-dom" ; import ReactDOMServer from "react-dom/server" ; import { Menu, MenuList, MenuButton, MenuItem } from "@reach/menu-button" ; import "@reach/menu-button/styles.css" ; import { ToastContainer, toast } from "react-toastify" ; import "react-toastify/dist/ReactToastify.min.css" ; import SearchForm from "./SearchForm" ; import { SearchResults } from "./SearchResults" ; import { PublisherSearchResult } from "./PublisherSearchResult" ; import { PublicationSearchResult } from "./PublicationSearchResult" ; import { ArticleSearchResult } from "./ArticleSearchResult" ; import { DbReport } from "./DbReport"; import ModalForm from "./ModalForm"; import AskDialog from "./AskDialog" ; import { DataCache } from "./DataCache" ; import { PreviewableImage } from "./PreviewableImage" ; import { makeSmartBulletList, isLink } from "./utils.js" ; import { APP_NAME } from "./constants.js" ; import "./App.css" ; const axios = require( "axios" ) ; const queryString = require( "query-string" ) ; window.$ = window.jQuery = require( "jquery" ) ; export let gAppRef = null ; // -------------------------------------------------------------------- export class App extends React.Component { constructor( props ) { // initialize the App super( props ) ; this.state = { searchResults: [], searchSeqNo: 0, showDbReport: false, modalForm: null, askDialog: null, startupTasks: [ "dummy" ], // FUDGE! We need at least one startup task. } ; gAppRef = this ; this.setWindowTitle( null ) ; // initialize the data cache this.dataCache = new DataCache() ; // initialize this.args = queryString.parse( window.location.search ) ; this._storeMsgs = this.isTestMode() && this.args.store_msgs ; this._disableSearchResultHighlighting = this.isTestMode() && this.args.no_sr_hilite ; this._disableConstraints = this.isTestMode() && this.args.disable_constraints ; this._disableConfirmDiscardChanges = this.isTestMode() && this.args.disable_confirm_discard_changes ; this._fakeUploads = this.isTestMode() && this.args.fake_uploads ; // initialize this._searchFormRef = React.createRef() ; this._searchResultsRef = React.createRef() ; this._modalFormRef = React.createRef() ; this._setFocusTo = null ; // figure out the base URL of the Flask backend server // NOTE: We allow the caller to do this since the test suite will usually spin up // it's own Flask server, but talks to an existing React server, so we need some way // for pytest to change which Flask server the React frontend code should tak to. this._flaskBaseUrl = this.isTestMode() ? this.args._flask : null ; if ( ! this._flaskBaseUrl ) { // NOTE: We used to use process.env.REACT_APP_FLASK_URL here, but this means that the client // needs to have access to the Flask backend server. We now proxy all backend requests via // "/api/..." endpoints, which we handle ourself (by setupProxy.js for the dev environment, // and nginx proxying for production), so the client only needs access to the React front-end. // This also has the nice side-effect of removing CORS issues :-/ this._flaskBaseUrl = "/api" ; } // NOTE: Managing publisher/publication/article images is a bit tricky, since they are accessed via a URL // such as "/articles/images/123", so if the user uploads a new image, the browser has no way of knowing // that it can't use what's in its cache and must get a new one. We can add something to the URL to force // a reload (e.g. "?foo=" + Math.random()), but this forces the image to be reloaded *every* time, which is // pretty inefficient. // Instead, we track a unique cache-busting value for each image URL, and change it when necessary. this._flaskImageUrlVersions = {} ; } render() { let content ; if ( this.state.startupTasks.length > 0 ) { // we are still starting up content =
Loading...
; } else { // generate the menu const menu = ( this._showPublishers(true) } > Show publishers. Show publishers this._showTechniqueArticles(true) } > Show technique articles. Show technique this._showTipsArticles(true) } > Show tip articles. Show tips
New publisher. New publisher New publication. New publication New article. New article
this._showDbReport(true) } > Database report. DB report
) ; // generate the main content content = (
{menu} { this.state.showDbReport ? : }
) ; } return (
{content} { this.state.modalForm !== null && } { this.state.askDialog !== null && } { this._storeMsgs &&