sequenceserver 3.0 → 3.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of sequenceserver might be problematic. Click here for more details.
- checksums.yaml +4 -4
 - data/bin/sequenceserver +2 -2
 - data/lib/sequenceserver/api_errors.rb +1 -1
 - data/lib/sequenceserver/blast/job.rb +20 -3
 - data/lib/sequenceserver/blast/report.rb +74 -86
 - data/lib/sequenceserver/blast/tasks.rb +38 -0
 - data/lib/sequenceserver/config.rb +54 -20
 - data/lib/sequenceserver/makeblastdb.rb +16 -2
 - data/lib/sequenceserver/report.rb +0 -6
 - data/lib/sequenceserver/routes.rb +32 -21
 - data/lib/sequenceserver/version.rb +1 -1
 - data/lib/sequenceserver.rb +1 -1
 - data/public/css/app.css +121 -0
 - data/public/css/app.min.css +1 -0
 - data/public/css/sequenceserver.css +0 -148
 - data/public/css/sequenceserver.min.css +3 -3
 - data/public/js/circos.js +2 -2
 - data/public/js/collapse_preferences.js +37 -0
 - data/public/js/databases.js +65 -37
 - data/public/js/databases_tree.js +2 -1
 - data/public/js/dnd.js +37 -50
 - data/public/js/form.js +78 -50
 - data/public/js/grapher.js +23 -37
 - data/public/js/hits_overview.js +2 -2
 - data/public/js/kablammo.js +2 -2
 - data/public/js/length_distribution.js +3 -3
 - data/public/js/null_plugins/grapher/histogram.js +25 -0
 - data/public/js/null_plugins/options.js +3 -0
 - data/public/js/null_plugins/query_stats.js +11 -0
 - data/public/js/null_plugins/report_plugins.js +6 -1
 - data/public/js/null_plugins/search_header_plugin.js +4 -0
 - data/public/js/options.js +161 -56
 - data/public/js/query.js +85 -59
 - data/public/js/report.js +1 -1
 - data/public/js/search.js +2 -0
 - data/public/js/search_button.js +67 -56
 - data/public/js/sidebar.js +1 -1
 - data/public/js/tests/database.spec.js +5 -5
 - data/public/js/tests/{advanced_parameters.spec.js → form.spec.js} +35 -1
 - data/public/js/tests/mock_data/databases.json +5 -5
 - data/public/js/tests/mocks/circos.js +6 -0
 - data/public/js/tests/report.spec.js +4 -3
 - data/public/js/tests/search_query.spec.js +5 -6
 - data/public/sequenceserver-report.min.js +45 -23
 - data/public/sequenceserver-search.min.js +57 -13
 - data/public/sequenceserver_logo.webp +0 -0
 - data/views/blastn_options.erb +66 -66
 - data/views/blastp_options.erb +59 -59
 - data/views/blastx_options.erb +68 -68
 - data/views/layout.erb +60 -3
 - data/views/search.erb +33 -38
 - data/views/search_layout.erb +152 -0
 - data/views/tblastn_options.erb +57 -57
 - data/views/tblastx_options.erb +64 -64
 - metadata +31 -22
 - data/lib/sequenceserver/makeblastdb-modified-with-cache.rb +0 -345
 - data/public/SequenceServer_logo.png +0 -0
 
    
        data/public/js/query.js
    CHANGED
    
    | 
         @@ -5,6 +5,7 @@ import HitsOverview from './hits_overview'; 
     | 
|
| 
       5 
5 
     | 
    
         
             
            import LengthDistribution from './length_distribution'; // length distribution of hits
         
     | 
| 
       6 
6 
     | 
    
         
             
            import Utils from './utils';
         
     | 
| 
       7 
7 
     | 
    
         
             
            import { fastqToFasta } from './fastq_to_fasta';
         
     | 
| 
      
 8 
     | 
    
         
            +
            import CollapsePreferences from './collapse_preferences';
         
     | 
| 
       8 
9 
     | 
    
         | 
| 
       9 
10 
     | 
    
         
             
            /**
         
     | 
| 
       10 
11 
     | 
    
         
             
             * Query component displays query defline, graphical overview, length
         
     | 
| 
         @@ -59,7 +60,7 @@ export class ReportQuery extends Component { 
     | 
|
| 
       59 
60 
     | 
    
         
             
                hitsListJSX() {
         
     | 
| 
       60 
61 
     | 
    
         
             
                    return <div className="section-content">
         
     | 
| 
       61 
62 
     | 
    
         
             
                        <HitsOverview key={'GO_' + this.props.query.number} query={this.props.query} program={this.props.program} collapsed={this.props.veryBig} />
         
     | 
| 
       62 
     | 
    
         
            -
                        <LengthDistribution key={'LD_' + this.props.query.id} query={this.props.query} algorithm={this.props.program}  
     | 
| 
      
 63 
     | 
    
         
            +
                        <LengthDistribution key={'LD_' + this.props.query.id} query={this.props.query} algorithm={this.props.program} />
         
     | 
| 
       63 
64 
     | 
    
         
             
                        <HitsTable key={'HT_' + this.props.query.number} query={this.props.query} imported_xml={this.props.imported_xml} />
         
     | 
| 
       64 
65 
     | 
    
         
             
                    </div>;
         
     | 
| 
       65 
66 
     | 
    
         
             
                }
         
     | 
| 
         @@ -107,8 +108,8 @@ export class SearchQueryWidget extends Component { 
     | 
|
| 
       107 
108 
     | 
    
         
             
                    this.preProcessSequence = this.preProcessSequence.bind(this);
         
     | 
| 
       108 
109 
     | 
    
         
             
                    this.notify = this.notify.bind(this);
         
     | 
| 
       109 
110 
     | 
    
         | 
| 
       110 
     | 
    
         
            -
                    this.textareaRef = createRef()
         
     | 
| 
       111 
     | 
    
         
            -
                    this.controlsRef = createRef()
         
     | 
| 
      
 111 
     | 
    
         
            +
                    this.textareaRef = createRef();
         
     | 
| 
      
 112 
     | 
    
         
            +
                    this.controlsRef = createRef();
         
     | 
| 
       112 
113 
     | 
    
         
             
                }
         
     | 
| 
       113 
114 
     | 
    
         | 
| 
       114 
115 
     | 
    
         | 
| 
         @@ -116,13 +117,14 @@ export class SearchQueryWidget extends Component { 
     | 
|
| 
       116 
117 
     | 
    
         | 
| 
       117 
118 
     | 
    
         
             
                componentDidMount() {
         
     | 
| 
       118 
119 
     | 
    
         
             
                    $('body').click(function () {
         
     | 
| 
       119 
     | 
    
         
            -
                        $(' 
     | 
| 
      
 120 
     | 
    
         
            +
                        $('[data-notifications] [data-role=notification].active').hide('drop', { direction: 'up' }).removeClass('active');
         
     | 
| 
       120 
121 
     | 
    
         
             
                    });
         
     | 
| 
       121 
122 
     | 
    
         
             
                }
         
     | 
| 
       122 
123 
     | 
    
         | 
| 
       123 
124 
     | 
    
         
             
                componentDidUpdate() {
         
     | 
| 
       124 
125 
     | 
    
         
             
                    this.hideShowButton();
         
     | 
| 
       125 
126 
     | 
    
         
             
                    this.preProcessSequence();
         
     | 
| 
      
 127 
     | 
    
         
            +
                    this.props.onSequenceChanged(this.residuesCount());
         
     | 
| 
       126 
128 
     | 
    
         | 
| 
       127 
129 
     | 
    
         
             
                    var type = this.type();
         
     | 
| 
       128 
130 
     | 
    
         
             
                    if (!type || type !== this._type) {
         
     | 
| 
         @@ -155,6 +157,19 @@ export class SearchQueryWidget extends Component { 
     | 
|
| 
       155 
157 
     | 
    
         
             
                    }
         
     | 
| 
       156 
158 
     | 
    
         
             
                }
         
     | 
| 
       157 
159 
     | 
    
         | 
| 
      
 160 
     | 
    
         
            +
                residuesCount() {
         
     | 
| 
      
 161 
     | 
    
         
            +
                    const sequence = this.value();
         
     | 
| 
      
 162 
     | 
    
         
            +
                    const lines = sequence.split('\n');
         
     | 
| 
      
 163 
     | 
    
         
            +
                    const residuesCount = lines.reduce((count, line) => {
         
     | 
| 
      
 164 
     | 
    
         
            +
                        if (!line.startsWith('>')) {
         
     | 
| 
      
 165 
     | 
    
         
            +
                            return count + line.length;
         
     | 
| 
      
 166 
     | 
    
         
            +
                        }
         
     | 
| 
      
 167 
     | 
    
         
            +
                        return count;
         
     | 
| 
      
 168 
     | 
    
         
            +
                    }, 0);
         
     | 
| 
      
 169 
     | 
    
         
            +
             
     | 
| 
      
 170 
     | 
    
         
            +
                    return residuesCount;
         
     | 
| 
      
 171 
     | 
    
         
            +
                }
         
     | 
| 
      
 172 
     | 
    
         
            +
             
     | 
| 
       158 
173 
     | 
    
         
             
                /**
         
     | 
| 
       159 
174 
     | 
    
         
             
                 * Clears textarea. Returns `this`.
         
     | 
| 
       160 
175 
     | 
    
         
             
                 *
         
     | 
| 
         @@ -311,13 +326,13 @@ export class SearchQueryWidget extends Component { 
     | 
|
| 
       311 
326 
     | 
    
         
             
                notify(type) {
         
     | 
| 
       312 
327 
     | 
    
         
             
                    this.indicateNormal();
         
     | 
| 
       313 
328 
     | 
    
         
             
                    clearTimeout(this.notification_timeout);
         
     | 
| 
       314 
     | 
    
         
            -
                    // $(' 
     | 
| 
      
 329 
     | 
    
         
            +
                    // $('[data-notifications] [data-role=notification].active').hide().removeClass('active');
         
     | 
| 
       315 
330 
     | 
    
         | 
| 
       316 
331 
     | 
    
         
             
                    if (type) {
         
     | 
| 
       317 
332 
     | 
    
         
             
                        $('#' + type + '-sequence-notification').show('drop', { direction: 'up' }).addClass('active');
         
     | 
| 
       318 
333 
     | 
    
         | 
| 
       319 
334 
     | 
    
         
             
                        this.notification_timeout = setTimeout(function () {
         
     | 
| 
       320 
     | 
    
         
            -
                            $(' 
     | 
| 
      
 335 
     | 
    
         
            +
                            $('[data-notifications] [data-role=notification].active').hide('drop', { direction: 'up' }).removeClass('active');
         
     | 
| 
       321 
336 
     | 
    
         
             
                        }, 5000);
         
     | 
| 
       322 
337 
     | 
    
         | 
| 
       323 
338 
     | 
    
         
             
                        if (type === 'mixed') {
         
     | 
| 
         @@ -328,14 +343,15 @@ export class SearchQueryWidget extends Component { 
     | 
|
| 
       328 
343 
     | 
    
         | 
| 
       329 
344 
     | 
    
         
             
                render() {
         
     | 
| 
       330 
345 
     | 
    
         
             
                    return (
         
     | 
| 
       331 
     | 
    
         
            -
                        <div
         
     | 
| 
       332 
     | 
    
         
            -
                            className="col-md-12">
         
     | 
| 
      
 346 
     | 
    
         
            +
                        <div className="relative">
         
     | 
| 
       333 
347 
     | 
    
         
             
                            <div
         
     | 
| 
       334 
348 
     | 
    
         
             
                                className="sequence">
         
     | 
| 
       335 
349 
     | 
    
         
             
                                <textarea
         
     | 
| 
       336 
350 
     | 
    
         
             
                                    id="sequence" ref={this.textareaRef}
         
     | 
| 
       337 
     | 
    
         
            -
                                    className=" 
     | 
| 
      
 351 
     | 
    
         
            +
                                    className="block w-full p-4 text-gray-900 border border-gray-300 rounded-l-lg rounded-tr-lg bg-gray-50 text-base text-monospace"
         
     | 
| 
       338 
352 
     | 
    
         
             
                                    name="sequence" value={this.state.value}
         
     | 
| 
      
 353 
     | 
    
         
            +
                                    rows="6"
         
     | 
| 
      
 354 
     | 
    
         
            +
                                    required="required"
         
     | 
| 
       339 
355 
     | 
    
         
             
                                    placeholder="Paste query sequence(s) or drag file
         
     | 
| 
       340 
356 
     | 
    
         
             
                                    containing query sequence(s) in FASTA format here ..."
         
     | 
| 
       341 
357 
     | 
    
         
             
                                    spellCheck="false" autoFocus
         
     | 
| 
         @@ -343,16 +359,16 @@ export class SearchQueryWidget extends Component { 
     | 
|
| 
       343 
359 
     | 
    
         
             
                                </textarea>
         
     | 
| 
       344 
360 
     | 
    
         
             
                            </div>
         
     | 
| 
       345 
361 
     | 
    
         
             
                            <div
         
     | 
| 
       346 
     | 
    
         
            -
                                className="hidden"
         
     | 
| 
       347 
     | 
    
         
            -
                                style={{ position: 'absolute', top: '4px', right: '19px' }}
         
     | 
| 
      
 362 
     | 
    
         
            +
                                className="hidden absolute top-2 right-2"
         
     | 
| 
       348 
363 
     | 
    
         
             
                                ref={this.controlsRef}>
         
     | 
| 
       349 
364 
     | 
    
         
             
                                <button
         
     | 
| 
       350 
365 
     | 
    
         
             
                                    type="button"
         
     | 
| 
       351 
     | 
    
         
            -
                                    className=" 
     | 
| 
      
 366 
     | 
    
         
            +
                                    className="border border-gray-300 rounded bg-white hover:bg-gray-200" id="btn-sequence-clear"
         
     | 
| 
       352 
367 
     | 
    
         
             
                                    title="Clear query sequence(s)."
         
     | 
| 
       353 
368 
     | 
    
         
             
                                    onClick={this.clear}>
         
     | 
| 
       354 
369 
     | 
    
         
             
                                    <span id="sequence-file"></span>
         
     | 
| 
       355 
     | 
    
         
            -
                                    <i className="fa fa-times"></i>
         
     | 
| 
      
 370 
     | 
    
         
            +
                                    <i className="fa fa-times w-6 h-6 p-1"></i>
         
     | 
| 
      
 371 
     | 
    
         
            +
                                    <span className="sr-only">Clear query sequence(s).</span>
         
     | 
| 
       356 
372 
     | 
    
         
             
                                </button>
         
     | 
| 
       357 
373 
     | 
    
         
             
                            </div>
         
     | 
| 
       358 
374 
     | 
    
         
             
                        </div>
         
     | 
| 
         @@ -368,8 +384,14 @@ export class SearchQueryWidget extends Component { 
     | 
|
| 
       368 
384 
     | 
    
         
             
            class HitsTable extends Component {
         
     | 
| 
       369 
385 
     | 
    
         
             
                constructor(props) {
         
     | 
| 
       370 
386 
     | 
    
         
             
                    super(props);
         
     | 
| 
      
 387 
     | 
    
         
            +
                    this.name = 'Hit sequences producing significant alignments';
         
     | 
| 
      
 388 
     | 
    
         
            +
                    this.collapsePreferences = new CollapsePreferences(this);
         
     | 
| 
      
 389 
     | 
    
         
            +
                    this.state = {
         
     | 
| 
      
 390 
     | 
    
         
            +
                        collapsed: this.collapsePreferences.preferenceStoredAsCollapsed()
         
     | 
| 
      
 391 
     | 
    
         
            +
                    };
         
     | 
| 
       371 
392 
     | 
    
         
             
                }
         
     | 
| 
       372 
     | 
    
         
            -
             
     | 
| 
      
 393 
     | 
    
         
            +
             
     | 
| 
      
 394 
     | 
    
         
            +
                tableJSX() {
         
     | 
| 
       373 
395 
     | 
    
         
             
                    var hasName = _.every(this.props.query.hits, function (hit) {
         
     | 
| 
       374 
396 
     | 
    
         
             
                        return hit.sciname !== '';
         
     | 
| 
       375 
397 
     | 
    
         
             
                    });
         
     | 
| 
         @@ -385,54 +407,58 @@ class HitsTable extends Component { 
     | 
|
| 
       385 
407 
     | 
    
         
             
                    // column.
         
     | 
| 
       386 
408 
     | 
    
         
             
                    if (this.props.imported_xml) seqwidth += 15;
         
     | 
| 
       387 
409 
     | 
    
         | 
| 
      
 410 
     | 
    
         
            +
                    return <table
         
     | 
| 
      
 411 
     | 
    
         
            +
                        className="table table-hover table-condensed tabular-view ">
         
     | 
| 
      
 412 
     | 
    
         
            +
                        <thead>
         
     | 
| 
      
 413 
     | 
    
         
            +
                            <tr>
         
     | 
| 
      
 414 
     | 
    
         
            +
                                <th className="text-left">#</th>
         
     | 
| 
      
 415 
     | 
    
         
            +
                                <th width={`${seqwidth}%`}>Similar sequences</th>
         
     | 
| 
      
 416 
     | 
    
         
            +
                                {hasName && <th width="15%" className="text-left">Species</th>}
         
     | 
| 
      
 417 
     | 
    
         
            +
                                {!this.props.imported_xml && <th width="15%" className="text-right">Query coverage (%)</th>}
         
     | 
| 
      
 418 
     | 
    
         
            +
                                <th width="10%" className="text-right">Total score</th>
         
     | 
| 
      
 419 
     | 
    
         
            +
                                <th width="10%" className="text-right">E value</th>
         
     | 
| 
      
 420 
     | 
    
         
            +
                                <th width="10%" className="text-right">Identity (%)</th>
         
     | 
| 
      
 421 
     | 
    
         
            +
                            </tr>
         
     | 
| 
      
 422 
     | 
    
         
            +
                        </thead>
         
     | 
| 
      
 423 
     | 
    
         
            +
                        <tbody>
         
     | 
| 
      
 424 
     | 
    
         
            +
                            {
         
     | 
| 
      
 425 
     | 
    
         
            +
                                _.map(this.props.query.hits, _.bind(function (hit) {
         
     | 
| 
      
 426 
     | 
    
         
            +
                                    return (
         
     | 
| 
      
 427 
     | 
    
         
            +
                                        <tr key={hit.number}>
         
     | 
| 
      
 428 
     | 
    
         
            +
                                            <td className="text-left">{hit.number + '.'}</td>
         
     | 
| 
      
 429 
     | 
    
         
            +
                                            <td className="nowrap-ellipsis"
         
     | 
| 
      
 430 
     | 
    
         
            +
                                                title={`${hit.id} ${hit.title}`}
         
     | 
| 
      
 431 
     | 
    
         
            +
                                                data-toggle="tooltip" data-placement="left">
         
     | 
| 
      
 432 
     | 
    
         
            +
                                                <a href={'#Query_' + this.props.query.number + '_hit_' + hit.number}
         
     | 
| 
      
 433 
     | 
    
         
            +
                                                    className="btn-link">{hit.id} {hit.title}</a>
         
     | 
| 
      
 434 
     | 
    
         
            +
                                            </td>
         
     | 
| 
      
 435 
     | 
    
         
            +
                                            {hasName &&
         
     | 
| 
      
 436 
     | 
    
         
            +
                                                <td className="nowrap-ellipsis" title={hit.sciname}
         
     | 
| 
      
 437 
     | 
    
         
            +
                                                    data-toggle="tooltip" data-placement="top">
         
     | 
| 
      
 438 
     | 
    
         
            +
                                                    {hit.sciname}
         
     | 
| 
      
 439 
     | 
    
         
            +
                                                </td>
         
     | 
| 
      
 440 
     | 
    
         
            +
                                            }
         
     | 
| 
      
 441 
     | 
    
         
            +
                                            {!this.props.imported_xml && <td className="text-right">{hit.qcovs}</td>}
         
     | 
| 
      
 442 
     | 
    
         
            +
                                            <td className="text-right">{hit.total_score}</td>
         
     | 
| 
      
 443 
     | 
    
         
            +
                                            <td className="text-right">{Utils.inExponential(hit.hsps[0].evalue)}</td>
         
     | 
| 
      
 444 
     | 
    
         
            +
                                            <td className="text-right">{Utils.inPercentage(hit.hsps[0].identity, hit.hsps[0].length)}</td>
         
     | 
| 
      
 445 
     | 
    
         
            +
                                        </tr>
         
     | 
| 
      
 446 
     | 
    
         
            +
                                    );
         
     | 
| 
      
 447 
     | 
    
         
            +
                                }, this))
         
     | 
| 
      
 448 
     | 
    
         
            +
                            }
         
     | 
| 
      
 449 
     | 
    
         
            +
                        </tbody>
         
     | 
| 
      
 450 
     | 
    
         
            +
                    </table>;
         
     | 
| 
      
 451 
     | 
    
         
            +
                }
         
     | 
| 
      
 452 
     | 
    
         
            +
             
     | 
| 
      
 453 
     | 
    
         
            +
                render() {
         
     | 
| 
       388 
454 
     | 
    
         
             
                    return (
         
     | 
| 
       389 
455 
     | 
    
         
             
                        <div className="table-hit-overview">
         
     | 
| 
       390 
     | 
    
         
            -
                            <h4 className="caption"  
     | 
| 
       391 
     | 
    
         
            -
                                 
     | 
| 
       392 
     | 
    
         
            -
                                <span> 
     | 
| 
      
 456 
     | 
    
         
            +
                            <h4 className="caption" onClick={() => this.collapsePreferences.toggleCollapse()}>
         
     | 
| 
      
 457 
     | 
    
         
            +
                                {this.collapsePreferences.renderCollapseIcon()}
         
     | 
| 
      
 458 
     | 
    
         
            +
                                <span> {this.name}</span>
         
     | 
| 
       393 
459 
     | 
    
         
             
                            </h4>
         
     | 
| 
       394 
     | 
    
         
            -
                            <div  
     | 
| 
       395 
     | 
    
         
            -
                                 
     | 
| 
       396 
     | 
    
         
            -
                                    className="table table-hover table-condensed tabular-view ">
         
     | 
| 
       397 
     | 
    
         
            -
                                    <thead>
         
     | 
| 
       398 
     | 
    
         
            -
                                        <tr>
         
     | 
| 
       399 
     | 
    
         
            -
                                            <th className="text-left">#</th>
         
     | 
| 
       400 
     | 
    
         
            -
                                            <th width={`${seqwidth}%`}>Similar sequences</th>
         
     | 
| 
       401 
     | 
    
         
            -
                                            {hasName && <th width="15%" className="text-left">Species</th>}
         
     | 
| 
       402 
     | 
    
         
            -
                                            {!this.props.imported_xml && <th width="15%" className="text-right">Query coverage (%)</th>}
         
     | 
| 
       403 
     | 
    
         
            -
                                            <th width="10%" className="text-right">Total score</th>
         
     | 
| 
       404 
     | 
    
         
            -
                                            <th width="10%" className="text-right">E value</th>
         
     | 
| 
       405 
     | 
    
         
            -
                                            <th width="10%" className="text-right">Identity (%)</th>
         
     | 
| 
       406 
     | 
    
         
            -
                                        </tr>
         
     | 
| 
       407 
     | 
    
         
            -
                                    </thead>
         
     | 
| 
       408 
     | 
    
         
            -
                                    <tbody>
         
     | 
| 
       409 
     | 
    
         
            -
                                        {
         
     | 
| 
       410 
     | 
    
         
            -
                                            _.map(this.props.query.hits, _.bind(function (hit) {
         
     | 
| 
       411 
     | 
    
         
            -
                                                return (
         
     | 
| 
       412 
     | 
    
         
            -
                                                    <tr key={hit.number}>
         
     | 
| 
       413 
     | 
    
         
            -
                                                        <td className="text-left">{hit.number + '.'}</td>
         
     | 
| 
       414 
     | 
    
         
            -
                                                        <td className="nowrap-ellipsis"
         
     | 
| 
       415 
     | 
    
         
            -
                                                            title={`${hit.id} ${hit.title}`}
         
     | 
| 
       416 
     | 
    
         
            -
                                                            data-toggle="tooltip" data-placement="left">
         
     | 
| 
       417 
     | 
    
         
            -
                                                            <a href={'#Query_' + this.props.query.number + '_hit_' + hit.number}
         
     | 
| 
       418 
     | 
    
         
            -
                                                                className="btn-link">{hit.id} {hit.title}</a>
         
     | 
| 
       419 
     | 
    
         
            -
                                                        </td>
         
     | 
| 
       420 
     | 
    
         
            -
                                                        {hasName &&
         
     | 
| 
       421 
     | 
    
         
            -
                                                            <td className="nowrap-ellipsis" title={hit.sciname}
         
     | 
| 
       422 
     | 
    
         
            -
                                                                data-toggle="tooltip" data-placement="top">
         
     | 
| 
       423 
     | 
    
         
            -
                                                                {hit.sciname}
         
     | 
| 
       424 
     | 
    
         
            -
                                                            </td>
         
     | 
| 
       425 
     | 
    
         
            -
                                                        }
         
     | 
| 
       426 
     | 
    
         
            -
                                                        {!this.props.imported_xml && <td className="text-right">{hit.qcovs}</td>}
         
     | 
| 
       427 
     | 
    
         
            -
                                                        <td className="text-right">{hit.total_score}</td>
         
     | 
| 
       428 
     | 
    
         
            -
                                                        <td className="text-right">{Utils.inExponential(hit.hsps[0].evalue)}</td>
         
     | 
| 
       429 
     | 
    
         
            -
                                                        <td className="text-right">{Utils.inPercentage(hit.hsps[0].identity, hit.hsps[0].length)}</td>
         
     | 
| 
       430 
     | 
    
         
            -
                                                    </tr>
         
     | 
| 
       431 
     | 
    
         
            -
                                                );
         
     | 
| 
       432 
     | 
    
         
            -
                                            }, this))
         
     | 
| 
       433 
     | 
    
         
            -
                                        }
         
     | 
| 
       434 
     | 
    
         
            -
                                    </tbody>
         
     | 
| 
       435 
     | 
    
         
            -
                                </table>
         
     | 
| 
      
 460 
     | 
    
         
            +
                            <div id={'Query_' + this.props.query.number + 'HT_' + this.props.query.number}>
         
     | 
| 
      
 461 
     | 
    
         
            +
                                {!this.state.collapsed && this.tableJSX()}
         
     | 
| 
       436 
462 
     | 
    
         
             
                            </div>
         
     | 
| 
       437 
463 
     | 
    
         
             
                        </div>
         
     | 
| 
       438 
464 
     | 
    
         
             
                    );
         
     | 
    
        data/public/js/report.js
    CHANGED
    
    | 
         @@ -300,6 +300,7 @@ class Report extends Component { 
     | 
|
| 
       300 
300 
     | 
    
         
             
                            <div className="col-md-9">
         
     | 
| 
       301 
301 
     | 
    
         
             
                                {this.overviewJSX()}
         
     | 
| 
       302 
302 
     | 
    
         
             
                                {this.circosJSX()}
         
     | 
| 
      
 303 
     | 
    
         
            +
                                {this.plugins.generateStats()}
         
     | 
| 
       303 
304 
     | 
    
         
             
                                {this.state.results}
         
     | 
| 
       304 
305 
     | 
    
         
             
                            </div>
         
     | 
| 
       305 
306 
     | 
    
         
             
                        </div>
         
     | 
| 
         @@ -386,7 +387,6 @@ class Report extends Component { 
     | 
|
| 
       386 
387 
     | 
    
         
             
                        <Circos
         
     | 
| 
       387 
388 
     | 
    
         
             
                            queries={this.state.queries}
         
     | 
| 
       388 
389 
     | 
    
         
             
                            program={this.state.program}
         
     | 
| 
       389 
     | 
    
         
            -
                            collapsed="true"
         
     | 
| 
       390 
390 
     | 
    
         
             
                        />
         
     | 
| 
       391 
391 
     | 
    
         
             
                    ) : (
         
     | 
| 
       392 
392 
     | 
    
         
             
                        <span></span>
         
     | 
    
        data/public/js/search.js
    CHANGED
    
    | 
         @@ -3,6 +3,7 @@ import React, { Component } from "react"; 
     | 
|
| 
       3 
3 
     | 
    
         
             
            import { createRoot } from "react-dom/client";
         
     | 
| 
       4 
4 
     | 
    
         
             
            import { DnD } from "./dnd";
         
     | 
| 
       5 
5 
     | 
    
         
             
            import { Form } from "./form";
         
     | 
| 
      
 6 
     | 
    
         
            +
            import { SearchHeaderPlugin } from "search_header_plugin";
         
     | 
| 
       6 
7 
     | 
    
         | 
| 
       7 
8 
     | 
    
         
             
            /**
         
     | 
| 
       8 
9 
     | 
    
         
             
             * Clear sessionStorage on reload.
         
     | 
| 
         @@ -19,6 +20,7 @@ class Page extends Component { 
     | 
|
| 
       19 
20 
     | 
    
         
             
              render() {
         
     | 
| 
       20 
21 
     | 
    
         
             
                return (
         
     | 
| 
       21 
22 
     | 
    
         
             
                  <div>
         
     | 
| 
      
 23 
     | 
    
         
            +
                    <SearchHeaderPlugin />
         
     | 
| 
       22 
24 
     | 
    
         
             
                    <DnD ref="dnd" />
         
     | 
| 
       23 
25 
     | 
    
         
             
                    <Form ref="form" />
         
     | 
| 
       24 
26 
     | 
    
         
             
                  </div>
         
     | 
    
        data/public/js/search_button.js
    CHANGED
    
    | 
         @@ -12,6 +12,7 @@ export class SearchButton extends Component { 
     | 
|
| 
       12 
12 
     | 
    
         
             
                        methods: [],
         
     | 
| 
       13 
13 
     | 
    
         
             
                        hasQuery: false,
         
     | 
| 
       14 
14 
     | 
    
         
             
                        hasDatabases: false,
         
     | 
| 
      
 15 
     | 
    
         
            +
                        dropdownVisible: false,
         
     | 
| 
       15 
16 
     | 
    
         
             
                    };
         
     | 
| 
       16 
17 
     | 
    
         
             
                    this.inputGroup = this.inputGroup.bind(this);
         
     | 
| 
       17 
18 
     | 
    
         
             
                    this.submitButton = this.submitButton.bind(this);
         
     | 
| 
         @@ -28,15 +29,17 @@ export class SearchButton extends Component { 
     | 
|
| 
       28 
29 
     | 
    
         
             
                }
         
     | 
| 
       29 
30 
     | 
    
         | 
| 
       30 
31 
     | 
    
         
             
                shouldComponentUpdate(props, state) {
         
     | 
| 
       31 
     | 
    
         
            -
                    return !_.isEqual(state.methods, this.state.methods);
         
     | 
| 
      
 32 
     | 
    
         
            +
                    return !_.isEqual(state.methods, this.state.methods) || state.dropdownVisible !== this.state.dropdownVisible;
         
     | 
| 
       32 
33 
     | 
    
         
             
                }
         
     | 
| 
       33 
34 
     | 
    
         | 
| 
       34 
     | 
    
         
            -
                componentDidUpdate() {
         
     | 
| 
       35 
     | 
    
         
            -
                    if (this.state.methods 
     | 
| 
       36 
     | 
    
         
            -
                        this. 
     | 
| 
       37 
     | 
    
         
            -
             
     | 
| 
       38 
     | 
    
         
            -
             
     | 
| 
       39 
     | 
    
         
            -
                         
     | 
| 
      
 35 
     | 
    
         
            +
                componentDidUpdate(_prevProps, prevState) {
         
     | 
| 
      
 36 
     | 
    
         
            +
                    if (!_.isEqual(prevState.methods, this.state.methods)) {
         
     | 
| 
      
 37 
     | 
    
         
            +
                        if (this.state.methods.length > 0) {
         
     | 
| 
      
 38 
     | 
    
         
            +
                            this.inputGroup().wiggle();
         
     | 
| 
      
 39 
     | 
    
         
            +
                            this.props.onAlgoChanged(this.state.methods[0]);
         
     | 
| 
      
 40 
     | 
    
         
            +
                        } else {
         
     | 
| 
      
 41 
     | 
    
         
            +
                            this.props.onAlgoChanged('');
         
     | 
| 
      
 42 
     | 
    
         
            +
                        }
         
     | 
| 
       40 
43 
     | 
    
         
             
                    }
         
     | 
| 
       41 
44 
     | 
    
         
             
                }
         
     | 
| 
       42 
45 
     | 
    
         
             
                // Internal helpers. //
         
     | 
| 
         @@ -110,6 +113,7 @@ export class SearchButton extends Component { 
     | 
|
| 
       110 
113 
     | 
    
         
             
                    methods.unshift(method);
         
     | 
| 
       111 
114 
     | 
    
         
             
                    this.setState({
         
     | 
| 
       112 
115 
     | 
    
         
             
                        methods: methods,
         
     | 
| 
      
 116 
     | 
    
         
            +
                        dropdownVisible: false,
         
     | 
| 
       113 
117 
     | 
    
         
             
                    });
         
     | 
| 
       114 
118 
     | 
    
         
             
                }
         
     | 
| 
       115 
119 
     | 
    
         | 
| 
         @@ -131,64 +135,71 @@ export class SearchButton extends Component { 
     | 
|
| 
       131 
135 
     | 
    
         
             
                        });
         
     | 
| 
       132 
136 
     | 
    
         
             
                }
         
     | 
| 
       133 
137 
     | 
    
         | 
| 
      
 138 
     | 
    
         
            +
                toggleDropdownVisibility = () => {
         
     | 
| 
      
 139 
     | 
    
         
            +
                    this.setState(prevState => ({
         
     | 
| 
      
 140 
     | 
    
         
            +
                        dropdownVisible: !prevState.dropdownVisible
         
     | 
| 
      
 141 
     | 
    
         
            +
                    }));
         
     | 
| 
      
 142 
     | 
    
         
            +
                }
         
     | 
| 
      
 143 
     | 
    
         
            +
             
     | 
| 
       134 
144 
     | 
    
         
             
                render() {
         
     | 
| 
       135 
145 
     | 
    
         
             
                    var methods = this.state.methods;
         
     | 
| 
       136 
146 
     | 
    
         
             
                    var method = methods[0];
         
     | 
| 
       137 
147 
     | 
    
         
             
                    var multi = methods.length > 1;
         
     | 
| 
       138 
148 
     | 
    
         | 
| 
       139 
149 
     | 
    
         
             
                    return (
         
     | 
| 
       140 
     | 
    
         
            -
                        <div 
     | 
| 
       141 
     | 
    
         
            -
                             
     | 
| 
       142 
     | 
    
         
            -
             
     | 
| 
       143 
     | 
    
         
            -
             
     | 
| 
       144 
     | 
    
         
            -
             
     | 
| 
       145 
     | 
    
         
            -
             
     | 
| 
       146 
     | 
    
         
            -
             
     | 
| 
       147 
     | 
    
         
            -
             
     | 
| 
       148 
     | 
    
         
            -
             
     | 
| 
      
 150 
     | 
    
         
            +
                        <div
         
     | 
| 
      
 151 
     | 
    
         
            +
                            // className={multi ? 'flex' : 'flex'}
         
     | 
| 
      
 152 
     | 
    
         
            +
                            className="my-4 md:my-2 flex justify-end w-full md:w-auto relative"
         
     | 
| 
      
 153 
     | 
    
         
            +
                            id="methods"
         
     | 
| 
      
 154 
     | 
    
         
            +
                            ref={this.inputGroupRef}
         
     | 
| 
      
 155 
     | 
    
         
            +
                            onMouseOver={this.showTooltip}
         
     | 
| 
      
 156 
     | 
    
         
            +
                            onMouseOut={this.hideTooltip}
         
     | 
| 
      
 157 
     | 
    
         
            +
                        >
         
     | 
| 
      
 158 
     | 
    
         
            +
                            <button
         
     | 
| 
      
 159 
     | 
    
         
            +
                                type="submit"
         
     | 
| 
      
 160 
     | 
    
         
            +
                                className="uppercase w-full md:w-auto flex text-xl justify-center py-2 px-16 border border-transparent rounded-md shadow-sm text-white bg-seqblue hover:bg-seqorange focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-seqorange"
         
     | 
| 
      
 161 
     | 
    
         
            +
                                id="method"
         
     | 
| 
      
 162 
     | 
    
         
            +
                                ref={this.submitButtonRef}
         
     | 
| 
      
 163 
     | 
    
         
            +
                                name="method"
         
     | 
| 
      
 164 
     | 
    
         
            +
                                value={method}
         
     | 
| 
      
 165 
     | 
    
         
            +
                                disabled={!method}
         
     | 
| 
      
 166 
     | 
    
         
            +
                            >
         
     | 
| 
      
 167 
     | 
    
         
            +
                                {this.decorate(method || 'blast')}
         
     | 
| 
      
 168 
     | 
    
         
            +
                            </button>
         
     | 
| 
      
 169 
     | 
    
         
            +
             
     | 
| 
      
 170 
     | 
    
         
            +
                            {multi && (
         
     | 
| 
      
 171 
     | 
    
         
            +
                                <div className="ui--multi-dropdown">
         
     | 
| 
      
 172 
     | 
    
         
            +
                                    <button
         
     | 
| 
      
 173 
     | 
    
         
            +
                                        className="text-xl bg-seqblue rounded-r-md text-white p-2 border border-seqblue hover:bg-seqorange focus:outline-none focus:ring-1 focus:ring-seqorange -ml-8"
         
     | 
| 
      
 174 
     | 
    
         
            +
                                        type="button"
         
     | 
| 
      
 175 
     | 
    
         
            +
                                        onClick={this.toggleDropdownVisibility}
         
     | 
| 
       149 
176 
     | 
    
         
             
                                    >
         
     | 
| 
       150 
     | 
    
         
            -
                                        < 
     | 
| 
       151 
     | 
    
         
            -
             
     | 
| 
       152 
     | 
    
         
            -
             
     | 
| 
       153 
     | 
    
         
            -
             
     | 
| 
       154 
     | 
    
         
            -
             
     | 
| 
       155 
     | 
    
         
            -
             
     | 
| 
       156 
     | 
    
         
            -
             
     | 
| 
       157 
     | 
    
         
            -
                                             
     | 
| 
       158 
     | 
    
         
            -
             
     | 
| 
       159 
     | 
    
         
            -
             
     | 
| 
       160 
     | 
    
         
            -
             
     | 
| 
       161 
     | 
    
         
            -
             
     | 
| 
       162 
     | 
    
         
            -
             
     | 
| 
       163 
     | 
    
         
            -
             
     | 
| 
       164 
     | 
    
         
            -
             
     | 
| 
       165 
     | 
    
         
            -
             
     | 
| 
       166 
     | 
    
         
            -
             
     | 
| 
       167 
     | 
    
         
            -
             
     | 
| 
       168 
     | 
    
         
            -
             
     | 
| 
       169 
     | 
    
         
            -
             
     | 
| 
       170 
     | 
    
         
            -
             
     | 
| 
       171 
     | 
    
         
            -
             
     | 
| 
       172 
     | 
    
         
            -
             
     | 
| 
       173 
     | 
    
         
            -
                                                            return (
         
     | 
| 
       174 
     | 
    
         
            -
                                                                <li
         
     | 
| 
       175 
     | 
    
         
            -
                                                                    key={method}
         
     | 
| 
       176 
     | 
    
         
            -
                                                                    className="text-uppercase"
         
     | 
| 
       177 
     | 
    
         
            -
                                                                    onClick={_.bind(function () {
         
     | 
| 
       178 
     | 
    
         
            -
                                                                        this.changeAlgorithm(method);
         
     | 
| 
       179 
     | 
    
         
            -
                                                                    }, this)}
         
     | 
| 
       180 
     | 
    
         
            -
                                                                >
         
     | 
| 
       181 
     | 
    
         
            -
                                                                    {method}
         
     | 
| 
       182 
     | 
    
         
            -
                                                                </li>
         
     | 
| 
       183 
     | 
    
         
            -
                                                            );
         
     | 
| 
       184 
     | 
    
         
            -
                                                        }, this)
         
     | 
| 
       185 
     | 
    
         
            -
                                                    )}
         
     | 
| 
       186 
     | 
    
         
            -
                                                </ul>
         
     | 
| 
       187 
     | 
    
         
            -
                                            </div>
         
     | 
| 
       188 
     | 
    
         
            -
                                        )}
         
     | 
| 
      
 177 
     | 
    
         
            +
                                        <i className="fas fa-caret-down w-6 h-6 fill-current"></i>
         
     | 
| 
      
 178 
     | 
    
         
            +
                                        <span className="sr-only">Other methods</span>
         
     | 
| 
      
 179 
     | 
    
         
            +
                                    </button>
         
     | 
| 
      
 180 
     | 
    
         
            +
             
     | 
| 
      
 181 
     | 
    
         
            +
                                    <div id="dropdown"
         
     | 
| 
      
 182 
     | 
    
         
            +
                                        className={`z-10 my-2 uppercase bg-blue-300 divide-y divide-gray-100 rounded-lg shadow absolute left-0 bottom-12 w-full text-xl text-center ${this.state.dropdownVisible ? '' : 'hidden'}`}>
         
     | 
| 
      
 183 
     | 
    
         
            +
                                        <ul className="text-gray-700" aria-labelledby="dropdownDefaultButton">
         
     | 
| 
      
 184 
     | 
    
         
            +
                                            {_.map(
         
     | 
| 
      
 185 
     | 
    
         
            +
                                                methods.slice(1),
         
     | 
| 
      
 186 
     | 
    
         
            +
                                                _.bind(function (method) {
         
     | 
| 
      
 187 
     | 
    
         
            +
                                                    return (
         
     | 
| 
      
 188 
     | 
    
         
            +
                                                        <li
         
     | 
| 
      
 189 
     | 
    
         
            +
                                                            key={method}
         
     | 
| 
      
 190 
     | 
    
         
            +
                                                            onClick={_.bind(function () {
         
     | 
| 
      
 191 
     | 
    
         
            +
                                                                this.changeAlgorithm(method);
         
     | 
| 
      
 192 
     | 
    
         
            +
                                                            }, this)}
         
     | 
| 
      
 193 
     | 
    
         
            +
                                                        >
         
     | 
| 
      
 194 
     | 
    
         
            +
                                                            <a href="#" className="block px-4 py-2 hover:bg-blue-400 rounded-lg">{method}</a>
         
     | 
| 
      
 195 
     | 
    
         
            +
                                                        </li>
         
     | 
| 
      
 196 
     | 
    
         
            +
                                                    );
         
     | 
| 
      
 197 
     | 
    
         
            +
                                                }, this)
         
     | 
| 
      
 198 
     | 
    
         
            +
                                            )}
         
     | 
| 
      
 199 
     | 
    
         
            +
                                        </ul>
         
     | 
| 
       189 
200 
     | 
    
         
             
                                    </div>
         
     | 
| 
       190 
201 
     | 
    
         
             
                                </div>
         
     | 
| 
       191 
     | 
    
         
            -
                             
     | 
| 
      
 202 
     | 
    
         
            +
                            )}
         
     | 
| 
       192 
203 
     | 
    
         
             
                        </div>
         
     | 
| 
       193 
204 
     | 
    
         
             
                    );
         
     | 
| 
       194 
205 
     | 
    
         
             
                }
         
     | 
    
        data/public/js/sidebar.js
    CHANGED
    
    
| 
         @@ -1,6 +1,6 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            /* eslint-disable no-unused-vars */
         
     | 
| 
       2 
2 
     | 
    
         
             
            /* eslint-disable no-undef */
         
     | 
| 
       3 
     | 
    
         
            -
            import { render, screen, fireEvent 
     | 
| 
      
 3 
     | 
    
         
            +
            import { render, screen, fireEvent } from '@testing-library/react';
         
     | 
| 
       4 
4 
     | 
    
         
             
            import { Databases } from '../databases';
         
     | 
| 
       5 
5 
     | 
    
         
             
            import data from './mock_data/databases.json';
         
     | 
| 
       6 
6 
     | 
    
         | 
| 
         @@ -21,13 +21,13 @@ describe('DATABASES COMPONENT', () => { 
     | 
|
| 
       21 
21 
     | 
    
         
             
                });
         
     | 
| 
       22 
22 
     | 
    
         | 
| 
       23 
23 
     | 
    
         
             
                test('clicking select all on a database should select all its children', () => {
         
     | 
| 
       24 
     | 
    
         
            -
                    const { container } = render(<Databases databases={data.database} onDatabaseTypeChanged={() => { }} />);
         
     | 
| 
       25 
     | 
    
         
            -
             
     | 
| 
      
 24 
     | 
    
         
            +
                    const { container } = render(<Databases databases={data.database} onDatabaseTypeChanged={() => { }} onDatabaseSelectionChanged={() => { }} />);
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
       26 
26 
     | 
    
         
             
                    // select all nucleotide databases
         
     | 
| 
       27 
27 
     | 
    
         
             
                    const nucleotideSelectAllBtn = screen.getByRole('heading', { name: /nucleotide databases/i }).parentElement.querySelector('button');
         
     | 
| 
       28 
28 
     | 
    
         
             
                    fireEvent.click(nucleotideSelectAllBtn);
         
     | 
| 
       29 
29 
     | 
    
         
             
                    const nucleotideCheckboxes = container.querySelector('.databases.nucleotide').querySelectorAll('input[type=checkbox]');
         
     | 
| 
       30 
     | 
    
         
            -
             
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
       31 
31 
     | 
    
         
             
                    // all nucleotide databases should be checked
         
     | 
| 
       32 
32 
     | 
    
         
             
                    nucleotideCheckboxes.forEach((checkbox) => {
         
     | 
| 
       33 
33 
     | 
    
         
             
                        expect(checkbox).toBeChecked();
         
     | 
| 
         @@ -45,7 +45,7 @@ describe('DATABASES COMPONENT', () => { 
     | 
|
| 
       45 
45 
     | 
    
         | 
| 
       46 
46 
     | 
    
         
             
                test('checking any item of a database type should disable other database type', () => {
         
     | 
| 
       47 
47 
     | 
    
         
             
                    const mockFunction = jest.fn(() => { });
         
     | 
| 
       48 
     | 
    
         
            -
                    const { container } = render(<Databases databases={data.database} onDatabaseTypeChanged={mockFunction} />);
         
     | 
| 
      
 48 
     | 
    
         
            +
                    const { container } = render(<Databases databases={data.database} onDatabaseTypeChanged={mockFunction} onDatabaseSelectionChanged={mockFunction}/>);
         
     | 
| 
       49 
49 
     | 
    
         | 
| 
       50 
50 
     | 
    
         
             
                    //select a proteinn database
         
     | 
| 
       51 
51 
     | 
    
         
             
                    fireEvent.click(screen.getByRole('checkbox', { name: /2020-11 Swiss-Prot insecta/i }));
         
     | 
| 
         @@ -11,6 +11,7 @@ import '@testing-library/react/dont-cleanup-after-each'; 
     | 
|
| 
       11 
11 
     | 
    
         
             
            export const setMockJSONResult = (result) => {
         
     | 
| 
       12 
12 
     | 
    
         
             
                global.$.getJSON = (_, cb) => cb(result);
         
     | 
| 
       13 
13 
     | 
    
         
             
            };
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
       14 
15 
     | 
    
         
             
            describe('ADVANCED PARAMETERS', () => {
         
     | 
| 
       15 
16 
     | 
    
         
             
                const getInputElement = () => screen.getByRole('textbox', { name: '' });
         
     | 
| 
       16 
17 
     | 
    
         
             
                test('should not render the link to advanced parameters modal if blast algorithm is unknown', () => {
         
     | 
| 
         @@ -24,7 +25,7 @@ describe('ADVANCED PARAMETERS', () => { 
     | 
|
| 
       24 
25 
     | 
    
         
             
                    setMockJSONResult(data);
         
     | 
| 
       25 
26 
     | 
    
         
             
                    const {container } =render(<Form onSequenceTypeChanged={() => { }
         
     | 
| 
       26 
27 
     | 
    
         
             
                    } />);
         
     | 
| 
       27 
     | 
    
         
            -
             
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
       28 
29 
     | 
    
         
             
                    const inputEl = getInputElement();
         
     | 
| 
       29 
30 
     | 
    
         
             
                    // populate search and select dbs to determine blast algorithm
         
     | 
| 
       30 
31 
     | 
    
         
             
                    fireEvent.change(inputEl, { target: { value: AMINO_ACID_SEQUENCE } });
         
     | 
| 
         @@ -34,3 +35,36 @@ describe('ADVANCED PARAMETERS', () => { 
     | 
|
| 
       34 
35 
     | 
    
         
             
                    expect(modalButton).not.toBeNull();
         
     | 
| 
       35 
36 
     | 
    
         
             
                });
         
     | 
| 
       36 
37 
     | 
    
         
             
            });
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
      
 39 
     | 
    
         
            +
            describe('query stats', () => {
         
     | 
| 
      
 40 
     | 
    
         
            +
                const getInputElement = () => screen.getByRole('textbox', { name: '' });
         
     | 
| 
      
 41 
     | 
    
         
            +
             
     | 
| 
      
 42 
     | 
    
         
            +
                test('should render the query stats modal when clicked', () => {
         
     | 
| 
      
 43 
     | 
    
         
            +
                    const logSpy = jest.spyOn(global.console, 'log');
         
     | 
| 
      
 44 
     | 
    
         
            +
             
     | 
| 
      
 45 
     | 
    
         
            +
                    setMockJSONResult(data);
         
     | 
| 
      
 46 
     | 
    
         
            +
                    render(<Form onSequenceTypeChanged={() => { }} />);
         
     | 
| 
      
 47 
     | 
    
         
            +
             
     | 
| 
      
 48 
     | 
    
         
            +
                    expect(logSpy).toHaveBeenCalledTimes(1);
         
     | 
| 
      
 49 
     | 
    
         
            +
             
     | 
| 
      
 50 
     | 
    
         
            +
                    const inputEl = getInputElement();
         
     | 
| 
      
 51 
     | 
    
         
            +
                    // populate search and select dbs to determine blast algorithm
         
     | 
| 
      
 52 
     | 
    
         
            +
                    fireEvent.change(inputEl, { target: { value: AMINO_ACID_SEQUENCE } });
         
     | 
| 
      
 53 
     | 
    
         
            +
             
     | 
| 
      
 54 
     | 
    
         
            +
                    expect(logSpy).toHaveBeenCalledTimes(2);
         
     | 
| 
      
 55 
     | 
    
         
            +
             
     | 
| 
      
 56 
     | 
    
         
            +
                    const proteinSelectAllBtn = screen.getByRole('heading', { name: /protein databases/i }).parentElement.querySelector('button');
         
     | 
| 
      
 57 
     | 
    
         
            +
                    fireEvent.click(proteinSelectAllBtn);
         
     | 
| 
      
 58 
     | 
    
         
            +
             
     | 
| 
      
 59 
     | 
    
         
            +
                    expect(logSpy).toHaveBeenCalledTimes(4);
         
     | 
| 
      
 60 
     | 
    
         
            +
                    expect(logSpy).toHaveBeenCalledWith(
         
     | 
| 
      
 61 
     | 
    
         
            +
                      'Query stats:',
         
     | 
| 
      
 62 
     | 
    
         
            +
                      {
         
     | 
| 
      
 63 
     | 
    
         
            +
                        residuesInQuerySequence: 385,
         
     | 
| 
      
 64 
     | 
    
         
            +
                        numberOfDatabasesSelected: 4,
         
     | 
| 
      
 65 
     | 
    
         
            +
                        residuesInSelectedDbs: 4343318,
         
     | 
| 
      
 66 
     | 
    
         
            +
                        currentBlastMethod: 'blastp'
         
     | 
| 
      
 67 
     | 
    
         
            +
                      }
         
     | 
| 
      
 68 
     | 
    
         
            +
                    );
         
     | 
| 
      
 69 
     | 
    
         
            +
                });
         
     | 
| 
      
 70 
     | 
    
         
            +
            });
         
     | 
| 
         @@ -82,10 +82,10 @@ 
     | 
|
| 
       82 
82 
     | 
    
         
             
                }
         
     | 
| 
       83 
83 
     | 
    
         
             
              ],
         
     | 
| 
       84 
84 
     | 
    
         
             
              "options": {
         
     | 
| 
       85 
     | 
    
         
            -
                "blastn": { "default": ["-task blastn", "-evalue 1e-5"] },
         
     | 
| 
       86 
     | 
    
         
            -
                "blastp": { "default": ["-evalue 1e-5"] },
         
     | 
| 
       87 
     | 
    
         
            -
                "blastx": { "default": ["-evalue 1e-5"] },
         
     | 
| 
       88 
     | 
    
         
            -
                "tblastx": { "default": ["-evalue 1e-5"] },
         
     | 
| 
       89 
     | 
    
         
            -
                "tblastn": { "default": ["-evalue 1e-5"] }
         
     | 
| 
      
 85 
     | 
    
         
            +
                "blastn": { "default": { "attributes": ["-task blastn", "-evalue 1e-5"] }},
         
     | 
| 
      
 86 
     | 
    
         
            +
                "blastp": { "default": { "attributes": ["-evalue 1e-5"] }},
         
     | 
| 
      
 87 
     | 
    
         
            +
                "blastx": { "default": { "attributes": ["-evalue 1e-5"] }},
         
     | 
| 
      
 88 
     | 
    
         
            +
                "tblastx": { "default": { "attributes": ["-evalue 1e-5"] }},
         
     | 
| 
      
 89 
     | 
    
         
            +
                "tblastn": { "default": { "attributes": ["-evalue 1e-5"] }}
         
     | 
| 
       90 
90 
     | 
    
         
             
              }
         
     | 
| 
       91 
91 
     | 
    
         
             
            }
         
     | 
| 
         @@ -44,6 +44,7 @@ describe('REPORT PAGE', () => { 
     | 
|
| 
       44 
44 
     | 
    
         
             
                    render(<Report showErrorModal={showErrorModal} />);
         
     | 
| 
       45 
45 
     | 
    
         
             
                    expect(showErrorModal).toHaveBeenCalledTimes(1);
         
     | 
| 
       46 
46 
     | 
    
         
             
                });
         
     | 
| 
      
 47 
     | 
    
         
            +
             
     | 
| 
       47 
48 
     | 
    
         
             
                it('it should render the report page correctly if there\'s a response provided', () => {
         
     | 
| 
       48 
49 
     | 
    
         
             
                    setMockJSONResult({ status: 200, responseJSON: shortResponseJSON });
         
     | 
| 
       49 
50 
     | 
    
         
             
                    const { container } = render(<Report getCharacterWidth={jest.fn()} />);
         
     | 
| 
         @@ -119,7 +120,7 @@ describe('REPORT PAGE', () => { 
     | 
|
| 
       119 
120 
     | 
    
         
             
                            it('link for downloading alignment of specific number of selected hits should be disabled on initial load', () => {
         
     | 
| 
       120 
121 
     | 
    
         
             
                                const alignment_download_link = container.querySelector('.download-alignment-of-selected');
         
     | 
| 
       121 
122 
     | 
    
         
             
                                expect(alignment_download_link.classList.contains('disabled')).toBeTruthy();
         
     | 
| 
       122 
     | 
    
         
            -
             
     | 
| 
      
 123 
     | 
    
         
            +
             
     | 
| 
       123 
124 
     | 
    
         
             
                            });
         
     | 
| 
       124 
125 
     | 
    
         
             
                            it('should generate a blob url and filename for downloading alignment of specific number of selected hits', () => {
         
     | 
| 
       125 
126 
     | 
    
         
             
                                const alignment_download_link = container.querySelector('.download-alignment-of-selected');
         
     | 
| 
         @@ -132,7 +133,7 @@ describe('REPORT PAGE', () => { 
     | 
|
| 
       132 
133 
     | 
    
         
             
                                expect(alignment_download_link.download).toEqual(file_name);
         
     | 
| 
       133 
134 
     | 
    
         
             
                            });
         
     | 
| 
       134 
135 
     | 
    
         
             
                        });
         
     | 
| 
       135 
     | 
    
         
            -
             
     | 
| 
      
 136 
     | 
    
         
            +
             
     | 
| 
       136 
137 
     | 
    
         
             
                        describe('FASTA DOWNLOAD', () => {
         
     | 
| 
       137 
138 
     | 
    
         
             
                            let fasta_download_link;
         
     | 
| 
       138 
139 
     | 
    
         
             
                            beforeEach(() => {
         
     | 
| 
         @@ -141,7 +142,7 @@ describe('REPORT PAGE', () => { 
     | 
|
| 
       141 
142 
     | 
    
         
             
                            it('link for downloading fasta of selected number of hits should be disabled on initial load', () => {
         
     | 
| 
       142 
143 
     | 
    
         
             
                                expect(fasta_download_link.classList.contains('disabled')).toBeTruthy();
         
     | 
| 
       143 
144 
     | 
    
         
             
                            });
         
     | 
| 
       144 
     | 
    
         
            -
             
     | 
| 
      
 145 
     | 
    
         
            +
             
     | 
| 
       145 
146 
     | 
    
         
             
                            it('link for downloading fasta of specific number of selected hits should be active after selection', () => {
         
     | 
| 
       146 
147 
     | 
    
         
             
                                const checkboxes = container.querySelectorAll('.hit-links input[type="checkbox"]');
         
     | 
| 
       147 
148 
     | 
    
         
             
                                // SELECT 5 CHECKBOXES
         
     | 
| 
         @@ -1,7 +1,6 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            /* eslint-disable no-unused-vars */
         
     | 
| 
       2 
2 
     | 
    
         
             
            /* eslint-disable no-undef */
         
     | 
| 
       3 
3 
     | 
    
         
             
            import { render, screen, fireEvent } from '@testing-library/react';
         
     | 
| 
       4 
     | 
    
         
            -
            import { SearchQueryWidget } from '../query';
         
     | 
| 
       5 
4 
     | 
    
         
             
            import { Form } from '../form';
         
     | 
| 
       6 
5 
     | 
    
         
             
            import { AMINO_ACID_SEQUENCE, NUCLEOTIDE_SEQUENCE, FASTQ_SEQUENCE, FASTA_OF_FASTQ_SEQUENCE } from './mock_data/sequences';
         
     | 
| 
       7 
6 
     | 
    
         
             
            import '@testing-library/jest-dom/extend-expect';
         
     | 
| 
         @@ -18,7 +17,7 @@ describe('SEARCH COMPONENT', () => { 
     | 
|
| 
       18 
17 
     | 
    
         
             
                });
         
     | 
| 
       19 
18 
     | 
    
         | 
| 
       20 
19 
     | 
    
         
             
                test('should render the search component textarea', () => {
         
     | 
| 
       21 
     | 
    
         
            -
                    expect(inputEl). 
     | 
| 
      
 20 
     | 
    
         
            +
                    expect(inputEl).toBeInTheDocument();
         
     | 
| 
       22 
21 
     | 
    
         
             
                });
         
     | 
| 
       23 
22 
     | 
    
         | 
| 
       24 
23 
     | 
    
         
             
                test('clear button should only become visible if textarea is not empty', () => {
         
     | 
| 
         @@ -33,7 +32,7 @@ describe('SEARCH COMPONENT', () => { 
     | 
|
| 
       33 
32 
     | 
    
         
             
                test('should correctly detect the amino-acid sequence type and show notification', () => {
         
     | 
| 
       34 
33 
     | 
    
         
             
                    // populate search
         
     | 
| 
       35 
34 
     | 
    
         
             
                    fireEvent.change(inputEl, { target: { value: AMINO_ACID_SEQUENCE } });
         
     | 
| 
       36 
     | 
    
         
            -
                    const activeNotification = container.querySelector(' 
     | 
| 
      
 35 
     | 
    
         
            +
                    const activeNotification = container.querySelector('[data-role=notification].active');
         
     | 
| 
       37 
36 
     | 
    
         
             
                    expect(activeNotification.id).toBe('protein-sequence-notification');
         
     | 
| 
       38 
37 
     | 
    
         
             
                    const alertWrapper = activeNotification.children[0];
         
     | 
| 
       39 
38 
     | 
    
         
             
                    expect(alertWrapper).toHaveTextContent('Detected: amino-acid sequence(s).');
         
     | 
| 
         @@ -42,7 +41,7 @@ describe('SEARCH COMPONENT', () => { 
     | 
|
| 
       42 
41 
     | 
    
         
             
                test('should correctly detect the nucleotide sequence type and show notification', () => {
         
     | 
| 
       43 
42 
     | 
    
         
             
                    // populate search
         
     | 
| 
       44 
43 
     | 
    
         
             
                    fireEvent.change(inputEl, { target: { value: NUCLEOTIDE_SEQUENCE } });
         
     | 
| 
       45 
     | 
    
         
            -
                    const activeNotification = container.querySelector(' 
     | 
| 
      
 44 
     | 
    
         
            +
                    const activeNotification = container.querySelector('[data-role=notification].active');
         
     | 
| 
       46 
45 
     | 
    
         
             
                    const alertWrapper = activeNotification.children[0];
         
     | 
| 
       47 
46 
     | 
    
         
             
                    expect(activeNotification.id).toBe('nucleotide-sequence-notification');
         
     | 
| 
       48 
47 
     | 
    
         
             
                    expect(alertWrapper).toHaveTextContent('Detected: nucleotide sequence(s).');
         
     | 
| 
         @@ -50,7 +49,7 @@ describe('SEARCH COMPONENT', () => { 
     | 
|
| 
       50 
49 
     | 
    
         | 
| 
       51 
50 
     | 
    
         
             
                test('should correctly detect the mixed sequences and show error notification', () => {
         
     | 
| 
       52 
51 
     | 
    
         
             
                    fireEvent.change(inputEl, { target: { value: `${NUCLEOTIDE_SEQUENCE}${AMINO_ACID_SEQUENCE}` } });
         
     | 
| 
       53 
     | 
    
         
            -
                    const activeNotification = container.querySelector(' 
     | 
| 
      
 52 
     | 
    
         
            +
                    const activeNotification = container.querySelector('[data-role=notification].active');
         
     | 
| 
       54 
53 
     | 
    
         
             
                    expect(activeNotification.id).toBe('mixed-sequence-notification');
         
     | 
| 
       55 
54 
     | 
    
         
             
                    const alertWrapper = activeNotification.children[0];
         
     | 
| 
       56 
55 
     | 
    
         
             
                    expect(alertWrapper).toHaveTextContent('Error: mixed nucleotide and amino-acid sequences detected.');
         
     | 
| 
         @@ -58,7 +57,7 @@ describe('SEARCH COMPONENT', () => { 
     | 
|
| 
       58 
57 
     | 
    
         | 
| 
       59 
58 
     | 
    
         
             
                test('should correctly detect FASTQ and convert it to FASTA', () => {
         
     | 
| 
       60 
59 
     | 
    
         
             
                    fireEvent.change(inputEl, { target: { value: FASTQ_SEQUENCE } });
         
     | 
| 
       61 
     | 
    
         
            -
                    const activeNotification = container.querySelector(' 
     | 
| 
      
 60 
     | 
    
         
            +
                    const activeNotification = container.querySelector('[data-role=notification].active');
         
     | 
| 
       62 
61 
     | 
    
         
             
                    const alertWrapper = activeNotification.children[0];
         
     | 
| 
       63 
62 
     | 
    
         
             
                    expect(activeNotification.id).toBe('fastq-sequence-notification');
         
     | 
| 
       64 
63 
     | 
    
         
             
                    expect(alertWrapper).toHaveTextContent('Detected FASTQ and automatically converted to FASTA.');
         
     |