sequenceserver 2.0.0.beta4 → 2.0.0.rc5
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.
- checksums.yaml +5 -5
- data/.dockerignore +1 -0
- data/.travis.yml +7 -4
- data/AppImage/sequenceserver.sh +5 -0
- data/Dockerfile +14 -12
- data/bin/sequenceserver +37 -28
- data/lib/sequenceserver.rb +35 -7
- data/lib/sequenceserver/blast/job.rb +18 -25
- data/lib/sequenceserver/blast/report.rb +68 -34
- data/lib/sequenceserver/config.rb +1 -1
- data/lib/sequenceserver/database.rb +0 -129
- data/lib/sequenceserver/makeblastdb.rb +243 -0
- data/lib/sequenceserver/routes.rb +28 -2
- data/lib/sequenceserver/version.rb +1 -1
- data/public/SequenceServer_logo.png +0 -0
- data/public/css/grapher.css +8 -15
- data/public/css/sequenceserver.css +119 -55
- data/public/css/sequenceserver.min.css +3 -3
- data/public/js/circos.js +1 -1
- data/public/js/download_fasta.js +17 -0
- data/public/js/grapher.js +7 -9
- data/public/js/hit.js +217 -0
- data/public/js/hits_overview.js +12 -13
- data/public/js/hsp.js +104 -84
- data/public/js/{sequenceserver.js → jquery_world.js} +1 -18
- data/public/js/kablammo.js +337 -334
- data/public/js/length_distribution.js +1 -1
- data/public/js/query.js +147 -0
- data/public/js/report.js +216 -836
- data/public/js/search.js +194 -192
- data/public/js/sequence_modal.js +167 -0
- data/public/js/sidebar.js +210 -0
- data/public/js/utils.js +2 -19
- data/public/js/visualisation_helpers.js +2 -2
- data/public/sequenceserver-report.min.js +19 -19
- data/public/sequenceserver-search.min.js +11 -11
- data/public/vendor/github/twbs/bootstrap@3.3.5/js/bootstrap.js +2 -2
- data/spec/blast_versions/blast_2.2.30/import_spec_capybara_local_2.2.30.rb +15 -15
- data/spec/blast_versions/blast_2.2.31/import_spec_capybara_local_2.2.31.rb +15 -15
- data/spec/blast_versions/blast_2.3.0/import_spec_capybara_local_2.3.0.rb +15 -15
- data/spec/blast_versions/blast_2.4.0/import_spec_capybara_local_2.4.0.rb +15 -15
- data/spec/blast_versions/blast_2.5.0/import_spec_capybara_local_2.5.0.rb +15 -15
- data/spec/blast_versions/blast_2.6.0/import_spec_capybara_local_2.6.0.rb +15 -15
- data/spec/blast_versions/blast_2.7.1/import_spec_capybara_local_2.7.1.rb +15 -15
- data/spec/blast_versions/blast_2.8.1/import_spec_capybara_local_2.8.1.rb +15 -15
- data/spec/blast_versions/blast_2.9.0/import_spec_capybara_local_2.9.0.rb +15 -15
- data/spec/blast_versions/diamond_0.9.24/import_spec_capybara_local_0.9.24.rb +6 -6
- data/spec/capybara_spec.rb +14 -3
- data/spec/database/sample/genome/Solenopsis_invicta/Solenopsis_invicta_gnG_subset.fasta.ndb +0 -0
- data/spec/database/sample/genome/Solenopsis_invicta/Solenopsis_invicta_gnG_subset.fasta.nhr +0 -0
- data/spec/database/sample/genome/Solenopsis_invicta/Solenopsis_invicta_gnG_subset.fasta.nin +0 -0
- data/spec/database/sample/genome/Solenopsis_invicta/Solenopsis_invicta_gnG_subset.fasta.nos +0 -0
- data/spec/database/sample/genome/Solenopsis_invicta/Solenopsis_invicta_gnG_subset.fasta.not +0 -0
- data/spec/database/sample/genome/Solenopsis_invicta/Solenopsis_invicta_gnG_subset.fasta.ntf +0 -0
- data/spec/database/sample/genome/Solenopsis_invicta/Solenopsis_invicta_gnG_subset.fasta.nto +0 -0
- data/spec/database/sample/proteins/Solenopsis_invicta/Sinvicta2-2-3.prot.subset.fasta.pdb +0 -0
- data/spec/database/sample/proteins/Solenopsis_invicta/Sinvicta2-2-3.prot.subset.fasta.phr +0 -0
- data/spec/database/sample/proteins/Solenopsis_invicta/Sinvicta2-2-3.prot.subset.fasta.pin +0 -0
- data/spec/database/sample/proteins/Solenopsis_invicta/Sinvicta2-2-3.prot.subset.fasta.pos +0 -0
- data/spec/database/sample/proteins/Solenopsis_invicta/Sinvicta2-2-3.prot.subset.fasta.pot +0 -0
- data/spec/database/sample/proteins/Solenopsis_invicta/Sinvicta2-2-3.prot.subset.fasta.ptf +0 -0
- data/spec/database/sample/proteins/Solenopsis_invicta/Sinvicta2-2-3.prot.subset.fasta.pto +0 -0
- data/spec/database/sample/proteins/uniprot/2018-04-Swiss-Prot_insecta.fasta.pdb +0 -0
- data/spec/database/sample/proteins/uniprot/2018-04-Swiss-Prot_insecta.fasta.phr +0 -0
- data/spec/database/sample/proteins/uniprot/2018-04-Swiss-Prot_insecta.fasta.pin +0 -0
- data/spec/database/sample/proteins/uniprot/2018-04-Swiss-Prot_insecta.fasta.pos +0 -0
- data/spec/database/sample/proteins/uniprot/2018-04-Swiss-Prot_insecta.fasta.pot +0 -0
- data/spec/database/sample/proteins/uniprot/2018-04-Swiss-Prot_insecta.fasta.ptf +0 -0
- data/spec/database/sample/proteins/uniprot/2018-04-Swiss-Prot_insecta.fasta.pto +0 -0
- data/spec/database/sample/transcripts/Solenopsis_invicta/Sinvicta2-2-3.cdna.subset.fasta.ndb +0 -0
- data/spec/database/sample/transcripts/Solenopsis_invicta/Sinvicta2-2-3.cdna.subset.fasta.nhr +0 -0
- data/spec/database/sample/transcripts/Solenopsis_invicta/Sinvicta2-2-3.cdna.subset.fasta.nin +0 -0
- data/spec/database/sample/transcripts/Solenopsis_invicta/Sinvicta2-2-3.cdna.subset.fasta.nos +0 -0
- data/spec/database/sample/transcripts/Solenopsis_invicta/Sinvicta2-2-3.cdna.subset.fasta.not +0 -0
- data/spec/database/sample/transcripts/Solenopsis_invicta/Sinvicta2-2-3.cdna.subset.fasta.nsq +0 -0
- data/spec/database/sample/transcripts/Solenopsis_invicta/Sinvicta2-2-3.cdna.subset.fasta.ntf +0 -0
- data/spec/database/sample/transcripts/Solenopsis_invicta/Sinvicta2-2-3.cdna.subset.fasta.nto +0 -0
- data/spec/database/v4/genome/Solenopsis_invicta/Solenopsis_invicta_gnG_subset.fasta.nhd +8 -0
- data/spec/database/v4/genome/Solenopsis_invicta/Solenopsis_invicta_gnG_subset.fasta.nhi +0 -0
- data/spec/database/v4/genome/Solenopsis_invicta/Solenopsis_invicta_gnG_subset.fasta.nhr +0 -0
- data/spec/database/v4/genome/Solenopsis_invicta/Solenopsis_invicta_gnG_subset.fasta.nin +0 -0
- data/spec/database/v4/genome/Solenopsis_invicta/Solenopsis_invicta_gnG_subset.fasta.nog +0 -0
- data/spec/database/{sample → v4}/genome/Solenopsis_invicta/Solenopsis_invicta_gnG_subset.fasta.nsd +0 -0
- data/spec/database/{sample → v4}/genome/Solenopsis_invicta/Solenopsis_invicta_gnG_subset.fasta.nsi +0 -0
- data/spec/database/v4/genome/Solenopsis_invicta/Solenopsis_invicta_gnG_subset.fasta.nsq +0 -0
- data/spec/database/v4/genome/Solenopsis_invicta/Solenopsis_invicta_gnG_subset.txt +8 -0
- data/spec/database/v4/links.rb +23 -0
- data/spec/database/v4/proteins/Solenopsis_invicta/Sinvicta2-2-3.prot.subset.fasta +6449 -0
- data/spec/database/v4/proteins/Solenopsis_invicta/Sinvicta2-2-3.prot.subset.fasta.phd +1189 -0
- data/spec/database/v4/proteins/Solenopsis_invicta/Sinvicta2-2-3.prot.subset.fasta.phi +0 -0
- data/spec/database/v4/proteins/Solenopsis_invicta/Sinvicta2-2-3.prot.subset.fasta.phr +0 -0
- data/spec/database/v4/proteins/Solenopsis_invicta/Sinvicta2-2-3.prot.subset.fasta.pin +0 -0
- data/spec/database/v4/proteins/Solenopsis_invicta/Sinvicta2-2-3.prot.subset.fasta.pog +0 -0
- data/spec/database/{sample → v4}/proteins/Solenopsis_invicta/Sinvicta2-2-3.prot.subset.fasta.psd +0 -0
- data/spec/database/{sample → v4}/proteins/Solenopsis_invicta/Sinvicta2-2-3.prot.subset.fasta.psi +0 -0
- data/spec/database/v4/proteins/Solenopsis_invicta/Sinvicta2-2-3.prot.subset.fasta.psq +0 -0
- data/spec/database/v4/proteins/uniprot/2018-04-Swiss-Prot_insecta.fasta.phd +9140 -0
- data/spec/database/v4/proteins/uniprot/2018-04-Swiss-Prot_insecta.fasta.phi +0 -0
- data/spec/database/v4/proteins/uniprot/2018-04-Swiss-Prot_insecta.fasta.phr +0 -0
- data/spec/database/v4/proteins/uniprot/2018-04-Swiss-Prot_insecta.fasta.pin +0 -0
- data/spec/database/v4/proteins/uniprot/2018-04-Swiss-Prot_insecta.fasta.pog +0 -0
- data/spec/database/{sample → v4}/proteins/uniprot/2018-04-Swiss-Prot_insecta.fasta.psd +0 -0
- data/spec/database/{sample → v4}/proteins/uniprot/2018-04-Swiss-Prot_insecta.fasta.psi +0 -0
- data/spec/database/v4/proteins/uniprot/2018-04-Swiss-Prot_insecta.fasta.psq +0 -0
- data/spec/database/v4/proteins/uniprot/URL +1 -0
- data/spec/database/v4/si_uniprot_idmap.yml +14180 -0
- data/spec/database/v4/transcripts/Solenopsis_invicta/Sinvicta2-2-3.cdna.subset.fasta +5486 -0
- data/spec/database/v4/transcripts/Solenopsis_invicta/Sinvicta2-2-3.cdna.subset.fasta.nhd +473 -0
- data/spec/database/v4/transcripts/Solenopsis_invicta/Sinvicta2-2-3.cdna.subset.fasta.nhi +0 -0
- data/spec/database/v4/transcripts/Solenopsis_invicta/Sinvicta2-2-3.cdna.subset.fasta.nhr +0 -0
- data/spec/database/v4/transcripts/Solenopsis_invicta/Sinvicta2-2-3.cdna.subset.fasta.nin +0 -0
- data/spec/database/v4/transcripts/Solenopsis_invicta/Sinvicta2-2-3.cdna.subset.fasta.nog +0 -0
- data/spec/database/{sample → v4}/transcripts/Solenopsis_invicta/Sinvicta2-2-3.cdna.subset.fasta.nsd +0 -0
- data/spec/database/{sample → v4}/transcripts/Solenopsis_invicta/Sinvicta2-2-3.cdna.subset.fasta.nsi +0 -0
- data/spec/database/v4/transcripts/Solenopsis_invicta/Sinvicta2-2-3.cdna.subset.fasta.nsq +0 -0
- data/spec/database_spec.rb +0 -76
- data/spec/makeblastdb_spec.rb +121 -0
- data/views/layout.erb +5 -1
- metadata +75 -15
data/public/js/search.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import
|
|
2
|
-
import _ from 'underscore';
|
|
1
|
+
import './jquery_world';
|
|
3
2
|
import React from 'react';
|
|
3
|
+
import _ from 'underscore';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Load necessary polyfills.
|
|
@@ -20,7 +20,7 @@ var Page = React.createClass({
|
|
|
20
20
|
componentDidMount: function () {
|
|
21
21
|
this.refs.dnd.setState({
|
|
22
22
|
query: this.refs.form.refs.query
|
|
23
|
-
})
|
|
23
|
+
});
|
|
24
24
|
}
|
|
25
25
|
});
|
|
26
26
|
|
|
@@ -31,14 +31,14 @@ var DnD = React.createClass({
|
|
|
31
31
|
getInitialState: function () {
|
|
32
32
|
return {
|
|
33
33
|
query: null
|
|
34
|
-
}
|
|
34
|
+
};
|
|
35
35
|
},
|
|
36
36
|
|
|
37
37
|
render: function () {
|
|
38
38
|
return (
|
|
39
39
|
<div
|
|
40
40
|
className="dnd-overlay"
|
|
41
|
-
style={{display:
|
|
41
|
+
style={{display: 'none'}}>
|
|
42
42
|
<div
|
|
43
43
|
className="container dnd-overlay-container">
|
|
44
44
|
<div
|
|
@@ -47,15 +47,15 @@ var DnD = React.createClass({
|
|
|
47
47
|
className="col-md-offset-2 col-md-10">
|
|
48
48
|
<p
|
|
49
49
|
className="dnd-overlay-drop"
|
|
50
|
-
style={{display:
|
|
50
|
+
style={{display: 'none'}}>
|
|
51
51
|
<i className="fa fa-2x fa-file-o"></i>
|
|
52
52
|
Drop query sequence file here
|
|
53
53
|
</p>
|
|
54
54
|
<p
|
|
55
55
|
className="dnd-overlay-overwrite"
|
|
56
|
-
style={{display:
|
|
56
|
+
style={{display: 'none'}}>
|
|
57
57
|
<i className="fa fa-2x fa-file-o"></i>
|
|
58
|
-
<span style={{color:
|
|
58
|
+
<span style={{color: 'red'}}>Overwrite</span> query sequence file
|
|
59
59
|
</p>
|
|
60
60
|
|
|
61
61
|
<div
|
|
@@ -63,7 +63,7 @@ var DnD = React.createClass({
|
|
|
63
63
|
<div
|
|
64
64
|
className="dnd-error row"
|
|
65
65
|
id="dnd-multi-notification"
|
|
66
|
-
style={{display:
|
|
66
|
+
style={{display: 'none'}}>
|
|
67
67
|
<div
|
|
68
68
|
className="col-md-6 col-md-offset-3">
|
|
69
69
|
One file at a time please.
|
|
@@ -73,7 +73,7 @@ var DnD = React.createClass({
|
|
|
73
73
|
<div
|
|
74
74
|
className="dnd-error row"
|
|
75
75
|
id="dnd-large-file-notification"
|
|
76
|
-
style={{display:
|
|
76
|
+
style={{display: 'none'}}>
|
|
77
77
|
<div
|
|
78
78
|
className="col-md-6 col-md-offset-3">
|
|
79
79
|
Too big a file. Can only do less than 10 MB. >_<
|
|
@@ -83,7 +83,7 @@ var DnD = React.createClass({
|
|
|
83
83
|
<div
|
|
84
84
|
className="dnd-error row"
|
|
85
85
|
id="dnd-format-notification"
|
|
86
|
-
style={{display:
|
|
86
|
+
style={{display: 'none'}}>
|
|
87
87
|
<div
|
|
88
88
|
className="col-md-6 col-md-offset-3">
|
|
89
89
|
Only FASTA files please.
|
|
@@ -99,6 +99,7 @@ var DnD = React.createClass({
|
|
|
99
99
|
|
|
100
100
|
componentDidMount: function () {
|
|
101
101
|
var self = this;
|
|
102
|
+
var FASTA_FORMAT = /^>/;
|
|
102
103
|
|
|
103
104
|
$(document).ready(function(){
|
|
104
105
|
var tgtMarker = $('.dnd-overlay');
|
|
@@ -110,80 +111,80 @@ var DnD = React.createClass({
|
|
|
110
111
|
};
|
|
111
112
|
|
|
112
113
|
$(document)
|
|
113
|
-
|
|
114
|
+
.on('dragenter', function (evt) {
|
|
114
115
|
// Do not activate DnD if a modal is active.
|
|
115
|
-
|
|
116
|
+
if ($.modalActive()) return;
|
|
116
117
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
118
|
+
// Based on http://stackoverflow.com/a/8494918/1205465.
|
|
119
|
+
// Contrary to what the above link says, the snippet below can't
|
|
120
|
+
// distinguish directories from files. We handle that on drop.
|
|
121
|
+
var dt = evt.originalEvent.dataTransfer;
|
|
122
|
+
var isFile = dt.types && ((dt.types.indexOf && // Chrome and Safari
|
|
122
123
|
dt.types.indexOf('Files') != -1) ||
|
|
123
124
|
(dt.types.contains && // Firefox
|
|
124
125
|
dt.types.contains('application/x-moz-file')));
|
|
125
126
|
|
|
126
|
-
|
|
127
|
+
if (!isFile) { return; }
|
|
127
128
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
129
|
+
$('.dnd-error').hide();
|
|
130
|
+
tgtMarker.stop(true, true);
|
|
131
|
+
tgtMarker.show();
|
|
132
|
+
dt.effectAllowed = 'copy';
|
|
133
|
+
if (self.state.query.isEmpty()) {
|
|
134
|
+
$('.dnd-overlay-overwrite').hide();
|
|
135
|
+
$('.dnd-overlay-drop').show('drop', {direction: 'down'}, 'fast');
|
|
136
|
+
}
|
|
137
|
+
else {
|
|
138
|
+
$('.dnd-overlay-drop').hide();
|
|
139
|
+
$('.dnd-overlay-overwrite').show('drop', {direction: 'down'}, 'fast');
|
|
140
|
+
}
|
|
141
|
+
})
|
|
142
|
+
.on('dragleave', '.dnd-overlay', function (evt) {
|
|
143
|
+
tgtMarker.hide();
|
|
137
144
|
$('.dnd-overlay-drop').hide();
|
|
138
|
-
$('.dnd-overlay-overwrite').
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
var files = evt.originalEvent.dataTransfer.files;
|
|
158
|
-
if (files.length > 1) {
|
|
159
|
-
dndError('dnd-multi');
|
|
160
|
-
return;
|
|
161
|
-
}
|
|
145
|
+
$('.dnd-overlay-overwrite').hide();
|
|
146
|
+
})
|
|
147
|
+
.on('dragover', '.dnd-overlay', function (evt) {
|
|
148
|
+
evt.originalEvent.dataTransfer.dropEffect = 'copy';
|
|
149
|
+
evt.preventDefault();
|
|
150
|
+
})
|
|
151
|
+
.on('drop', '.dnd-overlay', function (evt) {
|
|
152
|
+
evt.preventDefault();
|
|
153
|
+
evt.stopPropagation();
|
|
154
|
+
|
|
155
|
+
var indicator = $('#sequence-file');
|
|
156
|
+
self.state.query.focus();
|
|
157
|
+
|
|
158
|
+
var files = evt.originalEvent.dataTransfer.files;
|
|
159
|
+
if (files.length > 1) {
|
|
160
|
+
dndError('dnd-multi');
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
162
163
|
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
164
|
+
var file = files[0];
|
|
165
|
+
if (file.size > 10 * 1048576) {
|
|
166
|
+
dndError('dnd-large-file');
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
168
169
|
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
170
|
+
var reader = new FileReader();
|
|
171
|
+
reader.onload = function (e) {
|
|
172
|
+
var content = e.target.result;
|
|
173
|
+
if (FASTA_FORMAT.test(content)) {
|
|
174
|
+
indicator.text(file.name + ' ');
|
|
175
|
+
self.state.query.value(content);
|
|
176
|
+
tgtMarker.hide();
|
|
177
|
+
} else {
|
|
177
178
|
// apparently not FASTA
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
179
|
+
dndError('dnd-format');
|
|
180
|
+
}
|
|
181
|
+
};
|
|
182
|
+
reader.onerror = function (e) {
|
|
182
183
|
// Couldn't read. Means dropped stuff wasn't FASTA file.
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
184
|
+
dndError('dnd-format');
|
|
185
|
+
};
|
|
186
|
+
reader.readAsText(file);
|
|
187
|
+
});
|
|
187
188
|
});
|
|
188
189
|
}
|
|
189
190
|
});
|
|
@@ -203,32 +204,39 @@ var Form = React.createClass({
|
|
|
203
204
|
componentDidMount: function () {
|
|
204
205
|
/* Fetch data to initialise the search interface from the server. These
|
|
205
206
|
* include list of databases to search against, advanced options to
|
|
206
|
-
* apply when an algorithm is selected, and a query
|
|
207
|
+
* apply when an algorithm is selected, and a query sequence that
|
|
207
208
|
* the user may want to search in the databases.
|
|
208
209
|
*/
|
|
209
|
-
|
|
210
|
+
var search = location.search.split(/\?|&/).filter(Boolean);
|
|
211
|
+
var job_id = sessionStorage.getItem('job_id');
|
|
212
|
+
if (job_id) {
|
|
213
|
+
search.unshift(`job_id=${job_id}`);
|
|
214
|
+
}
|
|
215
|
+
$.getJSON(`searchdata.json?${search.join('&')}`, function(data) {
|
|
210
216
|
/* Update form state (i.e., list of databases and predefined
|
|
211
217
|
* advanced options.
|
|
212
218
|
*/
|
|
213
219
|
this.setState({
|
|
214
|
-
databases: data[
|
|
220
|
+
databases: data['database'],
|
|
221
|
+
preSelectedDbs: data['preSelectedDbs'],
|
|
222
|
+
preDefinedOpts: data['options']
|
|
215
223
|
});
|
|
216
224
|
|
|
217
225
|
/* Pre-populate the form with server sent query sequences
|
|
218
226
|
* (if any).
|
|
219
227
|
*/
|
|
220
|
-
if (data[
|
|
221
|
-
this.refs.query.value(data[
|
|
228
|
+
if (data['query']) {
|
|
229
|
+
this.refs.query.value(data['query']);
|
|
222
230
|
}
|
|
223
231
|
}.bind(this));
|
|
224
232
|
|
|
225
233
|
/* Enable submitting form on Cmd+Enter */
|
|
226
|
-
|
|
227
|
-
|
|
234
|
+
$(document).bind('keydown', _.bind(function (e) {
|
|
235
|
+
if (e.ctrlKey && e.keyCode === 13 &&
|
|
228
236
|
!$('#method').is(':disabled')) {
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
237
|
+
$(this.getDOMNode()).trigger('submit');
|
|
238
|
+
}
|
|
239
|
+
}, this));
|
|
232
240
|
},
|
|
233
241
|
|
|
234
242
|
determineBlastMethod: function () {
|
|
@@ -241,26 +249,26 @@ var Form = React.createClass({
|
|
|
241
249
|
|
|
242
250
|
//database type is always known
|
|
243
251
|
switch (database_type) {
|
|
252
|
+
case 'protein':
|
|
253
|
+
switch (sequence_type) {
|
|
254
|
+
case undefined:
|
|
255
|
+
return ['blastp', 'blastx'];
|
|
244
256
|
case 'protein':
|
|
245
|
-
|
|
246
|
-
case undefined:
|
|
247
|
-
return ['blastp', 'blastx'];
|
|
248
|
-
case 'protein':
|
|
249
|
-
return ['blastp'];
|
|
250
|
-
case 'nucleotide':
|
|
251
|
-
return ['blastx'];
|
|
252
|
-
}
|
|
253
|
-
break;
|
|
257
|
+
return ['blastp'];
|
|
254
258
|
case 'nucleotide':
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
259
|
+
return ['blastx'];
|
|
260
|
+
}
|
|
261
|
+
break;
|
|
262
|
+
case 'nucleotide':
|
|
263
|
+
switch (sequence_type) {
|
|
264
|
+
case undefined:
|
|
265
|
+
return ['tblastn', 'blastn', 'tblastx'];
|
|
266
|
+
case 'protein':
|
|
267
|
+
return ['tblastn'];
|
|
268
|
+
case 'nucleotide':
|
|
269
|
+
return ['blastn', 'tblastx'];
|
|
270
|
+
}
|
|
271
|
+
break;
|
|
264
272
|
}
|
|
265
273
|
|
|
266
274
|
return [];
|
|
@@ -285,35 +293,32 @@ var Form = React.createClass({
|
|
|
285
293
|
},
|
|
286
294
|
|
|
287
295
|
handleAlgoChanged: function (algo) {
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
+
if (this.state.preDefinedOpts.hasOwnProperty(algo)) {
|
|
297
|
+
this.refs.opts.setState({
|
|
298
|
+
preOpts: this.state.preDefinedOpts[algo].join(' ')
|
|
299
|
+
});
|
|
300
|
+
}
|
|
301
|
+
else {
|
|
302
|
+
this.refs.opts.setState({preOpts: ''});
|
|
303
|
+
}
|
|
296
304
|
},
|
|
297
305
|
|
|
298
306
|
render: function () {
|
|
299
307
|
return (
|
|
300
|
-
<div
|
|
301
|
-
className="
|
|
302
|
-
|
|
303
|
-
id="blast" method="post" className="form-horizontal">
|
|
304
|
-
<div
|
|
305
|
-
className="form-group query-container">
|
|
308
|
+
<div className="container">
|
|
309
|
+
<form id="blast" method="post" className="form-horizontal">
|
|
310
|
+
<div className="form-group query-container">
|
|
306
311
|
<Query ref="query" onSequenceTypeChanged={this.handleSequenceTypeChanged}/>
|
|
307
312
|
</div>
|
|
308
|
-
<div
|
|
309
|
-
className="notifications" id="notifications">
|
|
313
|
+
<div className="notifications" id="notifications">
|
|
310
314
|
<NucleotideNotification/>
|
|
311
315
|
<ProteinNotification/>
|
|
312
316
|
<MixedNotification/>
|
|
313
317
|
</div>
|
|
314
|
-
<Databases ref="databases"
|
|
315
|
-
|
|
316
|
-
|
|
318
|
+
<Databases ref="databases" databases={this.state.databases}
|
|
319
|
+
preSelectedDbs={this.state.preSelectedDbs}
|
|
320
|
+
onDatabaseTypeChanged={this.handleDatabaseTypeChanaged} />
|
|
321
|
+
<div className="form-group">
|
|
317
322
|
<Options ref="opts"/>
|
|
318
323
|
<SearchButton ref="button" onAlgoChanged={this.handleAlgoChanged}/>
|
|
319
324
|
</div>
|
|
@@ -346,7 +351,7 @@ var Query = React.createClass({
|
|
|
346
351
|
else {
|
|
347
352
|
this.setState({
|
|
348
353
|
value: val
|
|
349
|
-
})
|
|
354
|
+
});
|
|
350
355
|
return this;
|
|
351
356
|
}
|
|
352
357
|
},
|
|
@@ -451,12 +456,12 @@ var Query = React.createClass({
|
|
|
451
456
|
if (!tmp) { continue; }
|
|
452
457
|
|
|
453
458
|
if (!type) {
|
|
454
|
-
|
|
455
|
-
|
|
459
|
+
// successfully guessed the type of atleast one sequence
|
|
460
|
+
type = tmp;
|
|
456
461
|
}
|
|
457
462
|
else if (tmp !== type) {
|
|
458
|
-
|
|
459
|
-
|
|
463
|
+
// user has mixed different type of sequences
|
|
464
|
+
return 'mixed';
|
|
460
465
|
}
|
|
461
466
|
}
|
|
462
467
|
|
|
@@ -511,7 +516,7 @@ var Query = React.createClass({
|
|
|
511
516
|
// Lifecycle methods. //
|
|
512
517
|
|
|
513
518
|
getInitialState: function () {
|
|
514
|
-
var input_sequence = $(
|
|
519
|
+
var input_sequence = $('input#input_sequence').val() || '';
|
|
515
520
|
return {
|
|
516
521
|
value: input_sequence
|
|
517
522
|
};
|
|
@@ -619,21 +624,16 @@ var MixedNotification = React.createClass({
|
|
|
619
624
|
|
|
620
625
|
var Databases = React.createClass({
|
|
621
626
|
getInitialState: function () {
|
|
622
|
-
return {
|
|
623
|
-
type: '',
|
|
624
|
-
databases: []
|
|
625
|
-
}
|
|
627
|
+
return { type: '' };
|
|
626
628
|
},
|
|
627
629
|
|
|
628
630
|
databases: function (category) {
|
|
629
|
-
|
|
630
|
-
|
|
631
|
+
var databases = this.props.databases;
|
|
632
|
+
if (category) {
|
|
633
|
+
databases = _.select(databases, database => database.type === category);
|
|
631
634
|
}
|
|
632
635
|
|
|
633
|
-
return _.
|
|
634
|
-
function (database) {
|
|
635
|
-
return database.type === category;
|
|
636
|
-
});
|
|
636
|
+
return _.sortBy(databases, 'title');
|
|
637
637
|
},
|
|
638
638
|
|
|
639
639
|
nselected: function () {
|
|
@@ -642,7 +642,7 @@ var Databases = React.createClass({
|
|
|
642
642
|
|
|
643
643
|
categories: function () {
|
|
644
644
|
return _.uniq(_.map(this.props.databases,
|
|
645
|
-
|
|
645
|
+
_.iteratee('type'))).sort();
|
|
646
646
|
},
|
|
647
647
|
|
|
648
648
|
handleClick: function (database) {
|
|
@@ -652,12 +652,12 @@ var Databases = React.createClass({
|
|
|
652
652
|
|
|
653
653
|
handleToggle: function (toggleState, type) {
|
|
654
654
|
switch (toggleState) {
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
655
|
+
case '[Select all]':
|
|
656
|
+
$(`.${type} .database input:not(:checked)`).click();
|
|
657
|
+
break;
|
|
658
|
+
case '[Deselect all]':
|
|
659
|
+
$(`.${type} .database input:checked`).click();
|
|
660
|
+
break;
|
|
661
661
|
}
|
|
662
662
|
},
|
|
663
663
|
|
|
@@ -672,13 +672,13 @@ var Databases = React.createClass({
|
|
|
672
672
|
renderDatabases: function (category) {
|
|
673
673
|
// Panel name and column width.
|
|
674
674
|
var panelTitle = category[0].toUpperCase() +
|
|
675
|
-
category.substring(1).toLowerCase() +
|
|
675
|
+
category.substring(1).toLowerCase() + ' databases';
|
|
676
676
|
var columnClass = this.categories().length === 1 ? 'col-md-12' :
|
|
677
677
|
'col-md-6';
|
|
678
678
|
|
|
679
679
|
// Toggle button.
|
|
680
680
|
var toggleState = '[Select all]';
|
|
681
|
-
var toggleClass = 'btn
|
|
681
|
+
var toggleClass = 'btn-link';
|
|
682
682
|
var toggleShown = this.databases(category).length > 1 ;
|
|
683
683
|
var toggleDisabled = this.state.type && this.state.type !== category;
|
|
684
684
|
if (toggleShown && toggleDisabled) toggleClass += ' disabled';
|
|
@@ -689,20 +689,20 @@ var Databases = React.createClass({
|
|
|
689
689
|
|
|
690
690
|
// JSX.
|
|
691
691
|
return (
|
|
692
|
-
<div className={columnClass} key={
|
|
692
|
+
<div className={columnClass} key={'DB_'+category}>
|
|
693
693
|
<div className="panel panel-default">
|
|
694
694
|
<div className="panel-heading">
|
|
695
|
-
<h4 style={{display:
|
|
695
|
+
<h4 style={{display: 'inline'}}>{panelTitle}</h4>
|
|
696
696
|
<button type="button" className={toggleClass} disabled={toggleDisabled}
|
|
697
|
-
onClick={ function () { this.handleToggle(toggleState, category) }.bind(this) }>
|
|
697
|
+
onClick={ function () { this.handleToggle(toggleState, category); }.bind(this) }>
|
|
698
698
|
{toggleState}
|
|
699
699
|
</button>
|
|
700
700
|
</div>
|
|
701
|
-
<ul className={
|
|
701
|
+
<ul className={'list-group databases ' + category}>
|
|
702
702
|
{
|
|
703
703
|
_.map(this.databases(category), _.bind(function (database,index) {
|
|
704
704
|
return (
|
|
705
|
-
<li className="list-group-item" key={
|
|
705
|
+
<li className="list-group-item" key={'DB_'+category+index}>
|
|
706
706
|
{ this.renderDatabase(database) }
|
|
707
707
|
</li>
|
|
708
708
|
);
|
|
@@ -724,18 +724,18 @@ var Databases = React.createClass({
|
|
|
724
724
|
type="checkbox" name="databases[]" value={database.id}
|
|
725
725
|
data-type={database.type} disabled={disabled}
|
|
726
726
|
onChange=
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
{
|
|
727
|
+
{
|
|
728
|
+
_.bind(function () {
|
|
729
|
+
this.handleClick(database);
|
|
730
|
+
}, this)
|
|
731
|
+
}/>
|
|
732
|
+
{' ' + (database.title || database.name)}
|
|
733
733
|
</label>
|
|
734
734
|
);
|
|
735
735
|
},
|
|
736
736
|
|
|
737
737
|
//shouldComponentUpdate: function (props, state) {
|
|
738
|
-
|
|
738
|
+
//return !(state.type && state.type === this.state.type);
|
|
739
739
|
//},
|
|
740
740
|
|
|
741
741
|
componentDidUpdate: function () {
|
|
@@ -744,47 +744,49 @@ var Databases = React.createClass({
|
|
|
744
744
|
this.handleClick(this.databases()[0]);
|
|
745
745
|
}
|
|
746
746
|
|
|
747
|
+
if (this.props.preSelectedDbs) {
|
|
748
|
+
var selectors = this.props.preSelectedDbs.map(db => `input[value=${db.id}]`);
|
|
749
|
+
$(...selectors).prop('checked',true);
|
|
750
|
+
setTimeout(() => {
|
|
751
|
+
this.handleClick(this.props.preSelectedDbs[0]);
|
|
752
|
+
this.props.preSelectedDbs = null;
|
|
753
|
+
});
|
|
754
|
+
}
|
|
747
755
|
this.props.onDatabaseTypeChanged(this.state.type);
|
|
748
756
|
}
|
|
749
757
|
});
|
|
750
758
|
|
|
759
|
+
// Component for the advanced params input field.
|
|
751
760
|
var Options = React.createClass({
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
preOpts: evt.target.value
|
|
756
|
-
});
|
|
761
|
+
// State of this component is the advanced params text.
|
|
762
|
+
getInitialState: function () {
|
|
763
|
+
return { preOpts: '' };
|
|
757
764
|
},
|
|
758
765
|
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
766
|
+
updateBox: function (evt) {
|
|
767
|
+
this.setState({
|
|
768
|
+
preOpts: evt.target.value
|
|
769
|
+
});
|
|
763
770
|
},
|
|
764
771
|
|
|
765
772
|
render: function () {
|
|
773
|
+
var classNames = 'form-control';
|
|
774
|
+
if (this.state.preOpts.trim()) {
|
|
775
|
+
classNames += ' yellow-background';
|
|
776
|
+
}
|
|
766
777
|
return (
|
|
767
|
-
<div
|
|
768
|
-
className="
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
className="col-md-12">
|
|
773
|
-
<div
|
|
774
|
-
className="input-group">
|
|
775
|
-
<label
|
|
776
|
-
className="control-label"
|
|
777
|
-
htmlFor="advanced">
|
|
778
|
+
<div className="col-md-8">
|
|
779
|
+
<div className="form-group">
|
|
780
|
+
<div className="col-md-12">
|
|
781
|
+
<div className="input-group">
|
|
782
|
+
<label className="control-label" htmlFor="advanced">
|
|
778
783
|
Advanced parameters:
|
|
779
784
|
</label>
|
|
780
|
-
<input
|
|
781
|
-
|
|
782
|
-
className="form-control" name="advanced" id="advanced"
|
|
783
|
-
title="View, and enter advanced parameters."
|
|
785
|
+
<input type="text" className={classNames} onChange={this.updateBox}
|
|
786
|
+
id="advanced" name="advanced" value={this.state.preOpts}
|
|
784
787
|
placeholder="eg: -evalue 1.0e-5 -num_alignments 100"
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
/>
|
|
788
|
+
title="View, and enter advanced parameters."
|
|
789
|
+
/>
|
|
788
790
|
<div
|
|
789
791
|
className="input-group-addon cursor-pointer"
|
|
790
792
|
data-toggle="modal" data-target="#help">
|
|
@@ -827,23 +829,23 @@ var SearchButton = React.createClass({
|
|
|
827
829
|
trigger: 'manual',
|
|
828
830
|
title: _.bind(function () {
|
|
829
831
|
if (!this.state.hasQuery && !this.state.hasDatabases) {
|
|
830
|
-
return
|
|
832
|
+
return 'You must enter a query sequence and select one or more databases above before you can run a search!';
|
|
831
833
|
}
|
|
832
834
|
else if (this.state.hasQuery && !this.state.hasDatabases) {
|
|
833
|
-
return
|
|
835
|
+
return 'You must select one or more databases above before you can run a search!';
|
|
834
836
|
}
|
|
835
837
|
else if (!this.state.hasQuery && this.state.hasDatabases) {
|
|
836
|
-
return
|
|
838
|
+
return 'You must enter a query sequence above before you can run a search!';
|
|
837
839
|
}
|
|
838
840
|
}, this)
|
|
839
841
|
});
|
|
840
842
|
|
|
841
843
|
this.submitButton().tooltip({
|
|
842
844
|
title: _.bind(function () {
|
|
843
|
-
var title =
|
|
845
|
+
var title = 'Click to BLAST or press Ctrl+Enter.';
|
|
844
846
|
if (this.state.methods.length > 1) {
|
|
845
|
-
title +=
|
|
846
|
-
|
|
847
|
+
title += ' Click dropdown button on the right for other' +
|
|
848
|
+
' BLAST algorithms that can be used.';
|
|
847
849
|
}
|
|
848
850
|
return title;
|
|
849
851
|
}, this)
|
|
@@ -902,7 +904,7 @@ var SearchButton = React.createClass({
|
|
|
902
904
|
methods: [],
|
|
903
905
|
hasQuery: false,
|
|
904
906
|
hasDatabases: false
|
|
905
|
-
}
|
|
907
|
+
};
|
|
906
908
|
},
|
|
907
909
|
|
|
908
910
|
render: function () {
|
|
@@ -970,7 +972,7 @@ var SearchButton = React.createClass({
|
|
|
970
972
|
this.props.onAlgoChanged(this.state.methods[0]);
|
|
971
973
|
}
|
|
972
974
|
else {
|
|
973
|
-
this.props.onAlgoChanged(
|
|
975
|
+
this.props.onAlgoChanged('');
|
|
974
976
|
}
|
|
975
977
|
}
|
|
976
978
|
});
|