public/js/report.js in sequenceserver-2.2.0 vs public/js/report.js in sequenceserver-3.0

- old
+ new

@@ -6,19 +6,18 @@ import Circos from './circos'; import { ReportQuery } from './query'; import Hit from './hit'; import HSP from './hsp'; import AlignmentExporter from './alignment_exporter'; +import ReportPlugins from 'report_plugins'; - - - /** * Renders entire report. * * Composed of Query and Sidebar components. */ + class Report extends Component { constructor(props) { super(props); // Properties below are internal state used to render results in small // slices (see updateState). @@ -45,19 +44,25 @@ cloud_sharing_enabled: false, }; this.prepareAlignmentOfSelectedHits = this.prepareAlignmentOfSelectedHits.bind(this); this.prepareAlignmentOfAllHits = this.prepareAlignmentOfAllHits.bind(this); this.setStateFromJSON = this.setStateFromJSON.bind(this); + this.plugins = new ReportPlugins(this); } + /** * Fetch results. */ fetchResults() { + const path = location.pathname + '.json' + location.search; + this.pollPeriodically(path, this.setStateFromJSON, this.props.showErrorModal); + } + + pollPeriodically(path, callback, errCallback) { var intervals = [200, 400, 800, 1200, 2000, 3000, 5000]; - var component = this; function poll() { - $.getJSON(location.pathname + '.json' + location.search).complete(function (jqXHR) { + $.getJSON(path).complete(function (jqXHR) { switch (jqXHR.status) { case 202: var interval; if (intervals.length === 1) { interval = intervals[0]; @@ -65,16 +70,16 @@ interval = intervals.shift(); } setTimeout(poll, interval); break; case 200: - component.setStateFromJSON(jqXHR.responseJSON); + callback(jqXHR.responseJSON); break; - case 404: case 400: + case 422: case 500: - component.props.showErrorModal(jqXHR.responseJSON); + errCallback(jqXHR.responseJSON); break; } }); } @@ -91,17 +96,19 @@ this.setState({user_warning: responseJSON.user_warning, download_links: responseJSON.download_links}); } else { this.setState(responseJSON, this.prepareAlignmentOfAllHits); } } + /** * Called as soon as the page has loaded and the user sees the loading spinner. * We use this opportunity to setup services that make use of delegated events * bound to the window, document, or body. */ componentDidMount() { this.fetchResults(); + this.plugins.init(); // This sets up an event handler which enables users to select text from // hit header without collapsing the hit. this.preventCollapseOnSelection(); this.toggleTable(); } @@ -110,11 +117,11 @@ * Called for the first time after as BLAST results have been retrieved from * the server and added to this.state by fetchResults. Only summary overview * and circos would have been rendered at this point. At this stage we kick * start iteratively adding 1 HSP to the page every 25 milli-seconds. */ - componentDidUpdate() { + componentDidUpdate(prevProps, prevState) { // Log to console how long the last update take? // console.log((Date.now() - this.lastTimeStamp) / 1000); // Lock sidebar in its position on the first update. if (this.nextQuery == 0 && this.nextHit == 0 && this.nextHSP == 0) { @@ -128,36 +135,41 @@ // to user interactions. setTimeout(() => this.updateState(), 25); } else { this.componentFinishedUpdating(); } + + this.plugins.componentDidUpdate(prevProps, prevState); } /** * Push next slice of results to React for rendering. */ updateState() { var results = []; var numHSPsProcessed = 0; while (this.nextQuery < this.state.queries.length) { var query = this.state.queries[this.nextQuery]; + // We may see a query multiple times during rendering because only - // 3 hsps or are rendered in each cycle, but we want to create the + // 3 hsps are rendered in each cycle, but we want to create the // corresponding Query component only the first time we see it. if (this.nextHit == 0 && this.nextHSP == 0) { results.push( <ReportQuery - key={'Query_' + query.number} + key={'Query_' + query.id} query={query} program={this.state.program} querydb={this.state.querydb} showQueryCrumbs={this.state.queries.length > 1} non_parse_seqids={this.state.non_parse_seqids} imported_xml={this.state.imported_xml} veryBig={this.state.veryBig} /> ); + + results.push(...this.plugins.queryResults(query)); } while (this.nextHit < query.hits.length) { var hit = query.hits[this.nextHit]; // We may see a hit multiple times during rendering because only @@ -188,15 +200,15 @@ var hsp = hit.hsps[this.nextHSP++]; results.push( <HSP key={ 'Query_' + - query.number + - '_Hit_' + - hit.number + - '_HSP_' + - hsp.number + query.number + + '_Hit_' + + hit.number + + '_HSP_' + + hsp.number } query={query} hit={hit} hsp={hsp} algorithm={this.state.program} @@ -259,10 +271,13 @@ database(s). The page will update automatically when BLAST is done. <br /> <br /> You can bookmark the page and come back to it later or share the link with someone. + <br /> + <br /> + { process.env.targetEnv === 'cloud' && <b>If the job takes more than 10 minutes to complete, we will send you an email upon completion.</b> } </p> </div> </div> ); } @@ -449,11 +464,11 @@ /* Handling the fa icon when Hit Table is collapsed */ toggleTable() { $('body').on( 'mousedown', - '.resultn > .section-content > .table-hit-overview > .caption', + '.resultn .caption[data-toggle="collapse"]', function (event) { var $this = $(this); $this.on('mouseup mousemove', function handler(event) { $this.find('i').toggleClass('fa-minus-square-o fa-plus-square-o'); $this.off('mouseup mousemove', handler); @@ -507,9 +522,10 @@ $('.download-fasta-of-selected').enable(); $('.download-alignment-of-selected').enable(); } else { $hit.removeClass('glow'); $hit.next('.hsp').removeClass('glow'); + $('.download-fasta-of-selected').attr('href', '#').removeAttr('download'); } var $a = $('.download-fasta-of-selected'); var $b = $('.download-alignment-of-selected');