sequenceserver 3.1.0 → 3.1.1
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of sequenceserver might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/lib/sequenceserver/api_errors.rb +31 -1
- data/lib/sequenceserver/routes.rb +35 -5
- data/lib/sequenceserver/sequence.rb +35 -7
- data/lib/sequenceserver/server.rb +1 -1
- data/lib/sequenceserver/version.rb +1 -1
- data/public/404.html +1 -1
- data/public/css/app.min.css +1 -1
- data/public/js/download_fasta.js +1 -0
- data/public/js/form.js +1 -0
- data/public/js/sidebar.js +9 -0
- data/public/js/tests/form.spec.js +28 -0
- data/public/js/tests/search_query.spec.js +11 -0
- data/public/sequenceserver-report.min.js +2 -2
- data/public/sequenceserver-search.min.js +1 -1
- data/views/layout.erb +1 -0
- data/views/search_layout.erb +1 -0
- metadata +23 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b058e493103527b8d0120243180b748b256997416d9886c3d349539d0afe9420
|
4
|
+
data.tar.gz: 836645ba201b125b1f379b934b86186128b76717c5bd456c85caa71e5cdc9269
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 16e202385e0704918489da25ade9f938e3afe92a3298e338a2462188da049d9c780e80ba3cfe6de1c156196901d50570c845e030de71980151b2580ffd15a65f
|
7
|
+
data.tar.gz: a1033d77cb3feb609d0cf0b2f6af7dbfd558cca05027c4a6308d176f39c39b281d9dbf16b5de4d4d58620d00e372078a14103b35b456dc79b153d2d76c3c24e0
|
@@ -1,9 +1,10 @@
|
|
1
1
|
module SequenceServer
|
2
2
|
Error = Class.new(Sinatra::Error)
|
3
3
|
|
4
|
+
ValidationError = Class.new(Error)
|
4
5
|
# DatabaseUnreachableError is raised when the serialised Job object is
|
5
6
|
# refering to a database that is not present in the current filesystem.
|
6
|
-
class DatabaseUnreachableError <
|
7
|
+
class DatabaseUnreachableError < ValidationError
|
7
8
|
attr_reader :more_info
|
8
9
|
|
9
10
|
def initialize(more_info)
|
@@ -11,6 +12,10 @@ module SequenceServer
|
|
11
12
|
@more_info = more_info
|
12
13
|
end
|
13
14
|
|
15
|
+
def http_status
|
16
|
+
422
|
17
|
+
end
|
18
|
+
|
14
19
|
def title
|
15
20
|
'Sequence database unreachable'
|
16
21
|
end
|
@@ -22,6 +27,31 @@ module SequenceServer
|
|
22
27
|
end
|
23
28
|
end
|
24
29
|
|
30
|
+
# InvalidSequenceIdError is raised when the FASTA sequence ID provided by the
|
31
|
+
# frontend appears to be invalid. It is important to validate the sequence ID
|
32
|
+
# format for security reasons.
|
33
|
+
class InvalidSequenceIdError < ValidationError
|
34
|
+
attr_reader :more_info
|
35
|
+
|
36
|
+
def initialize(more_info)
|
37
|
+
super
|
38
|
+
@more_info = more_info
|
39
|
+
end
|
40
|
+
|
41
|
+
def http_status
|
42
|
+
422
|
43
|
+
end
|
44
|
+
|
45
|
+
def title
|
46
|
+
'Sequence ID invalid'
|
47
|
+
end
|
48
|
+
|
49
|
+
def message
|
50
|
+
"The action you're trying to perform is not possible because \
|
51
|
+
one of the FASTA ids seems to be invalid."
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
25
55
|
# API errors have an http status, title, message, and additional information
|
26
56
|
# like stacktrace or information from program output.
|
27
57
|
APIError = Class.new(Error)
|
@@ -9,6 +9,7 @@ require 'sequenceserver/blast/tasks'
|
|
9
9
|
require 'sequenceserver/report'
|
10
10
|
require 'sequenceserver/database'
|
11
11
|
require 'sequenceserver/sequence'
|
12
|
+
require 'rack/csrf'
|
12
13
|
|
13
14
|
module SequenceServer
|
14
15
|
# Controller.
|
@@ -58,6 +59,14 @@ module SequenceServer
|
|
58
59
|
frame_options = SequenceServer.config[:frame_options]
|
59
60
|
frame_options && { frame_options: frame_options }
|
60
61
|
}
|
62
|
+
|
63
|
+
use(
|
64
|
+
Rack::Session::Cookie,
|
65
|
+
key: 'rack.session.sequenceserver',
|
66
|
+
secret: ENV.fetch('SESSION_SECRET') { SecureRandom.alphanumeric(64) }
|
67
|
+
)
|
68
|
+
|
69
|
+
use Rack::Csrf, raise: true, skip: ['POST:/cloud_share']
|
61
70
|
end
|
62
71
|
|
63
72
|
unless ENV['SEQUENCE_SERVER_COMPRESS_RESPONSES'] == 'false'
|
@@ -147,15 +156,35 @@ module SequenceServer
|
|
147
156
|
# in identifiers) and retreival_databases (we don't allow whitespace in a
|
148
157
|
# database's name, so it's safe).
|
149
158
|
get '/get_sequence/' do
|
150
|
-
sequence_ids = params[:sequence_ids].split(',')
|
151
|
-
database_ids = params[:database_ids].split(',')
|
159
|
+
sequence_ids = params[:sequence_ids].to_s.split(',')
|
160
|
+
database_ids = params[:database_ids].to_s.split(',')
|
161
|
+
if sequence_ids.empty?
|
162
|
+
status 422
|
163
|
+
return { error: 'No sequence ids provided' }.to_json
|
164
|
+
end
|
165
|
+
|
166
|
+
if database_ids.empty?
|
167
|
+
status 422
|
168
|
+
return { error: 'No database ids provided' }.to_json
|
169
|
+
end
|
152
170
|
sequences = Sequence::Retriever.new(sequence_ids, database_ids)
|
153
171
|
sequences.to_json
|
154
172
|
end
|
155
173
|
|
156
174
|
post '/get_sequence' do
|
157
|
-
sequence_ids = params['sequence_ids'].split(',')
|
158
|
-
database_ids = params['database_ids'].split(',')
|
175
|
+
sequence_ids = params['sequence_ids'].to_s.split(',')
|
176
|
+
database_ids = params['database_ids'].to_s.split(',')
|
177
|
+
|
178
|
+
if sequence_ids.empty?
|
179
|
+
status 422
|
180
|
+
return 'No sequence ids provided'
|
181
|
+
end
|
182
|
+
|
183
|
+
if database_ids.empty?
|
184
|
+
status 422
|
185
|
+
return 'No database ids provided'
|
186
|
+
end
|
187
|
+
|
159
188
|
sequences = Sequence::Retriever.new(sequence_ids, database_ids, true)
|
160
189
|
send_file(sequences.file.path,
|
161
190
|
type: sequences.mime,
|
@@ -319,7 +348,8 @@ module SequenceServer
|
|
319
348
|
download_links: [
|
320
349
|
{ name: 'Standard Tabular Report', url: "download/#{jid}.std_tsv" },
|
321
350
|
{ name: 'Full Tabular Report', url: "/download/#{jid}.full_tsv" },
|
322
|
-
{ name: 'Results in XML', url: "/download/#{jid}.xml" }
|
351
|
+
{ name: 'Results in XML', url: "/download/#{jid}.xml" },
|
352
|
+
{ name: 'Pairwise', url: "/download/#{jid}.pairwise" },
|
323
353
|
]
|
324
354
|
}
|
325
355
|
end
|
@@ -180,7 +180,7 @@ module SequenceServer
|
|
180
180
|
@database_ids = Array database_ids
|
181
181
|
@in_file = in_file
|
182
182
|
|
183
|
-
validate && run
|
183
|
+
validate && create_entry_batch_file && run
|
184
184
|
end
|
185
185
|
|
186
186
|
attr_reader :sequence_ids, :database_ids, :in_file, :sequences
|
@@ -197,10 +197,9 @@ module SequenceServer
|
|
197
197
|
def run
|
198
198
|
command = "blastdbcmd -outfmt '%g %i %a %t %s'" \
|
199
199
|
" -db '#{database_names.join(' ')}'" \
|
200
|
-
" -
|
200
|
+
" -entry_batch '#{@batch_file.path}'"
|
201
201
|
|
202
202
|
out, = sys(command, path: config[:bin])
|
203
|
-
|
204
203
|
@sequences = out.each_line.map do |line|
|
205
204
|
# Stop codons in amino acid sequence databases show up as invalid
|
206
205
|
# UTF-8 characters in the output and cause the subsequent call to
|
@@ -208,6 +207,8 @@ module SequenceServer
|
|
208
207
|
line = line.encode('UTF-8', invalid: :replace, replace: 'X')
|
209
208
|
Sequence.new(*line.chomp.split(' '))
|
210
209
|
end
|
210
|
+
|
211
|
+
@batch_file.unlink
|
211
212
|
extend(IO) && write if in_file
|
212
213
|
end
|
213
214
|
|
@@ -221,11 +222,38 @@ module SequenceServer
|
|
221
222
|
|
222
223
|
def validate
|
223
224
|
ids = Database.ids
|
224
|
-
|
225
|
-
|
225
|
+
unless database_ids.is_a?(Array) &&
|
226
|
+
!database_ids.empty? &&
|
227
|
+
(ids & database_ids).length == database_ids.length
|
228
|
+
|
229
|
+
fail(
|
230
|
+
DatabaseUnreachableError,
|
231
|
+
"Database id should be one of: #{ids.join("\n")}"
|
232
|
+
)
|
233
|
+
end
|
234
|
+
|
235
|
+
valid_id_regex = /\A[a-zA-Z0-9-_.:*#|\[\]]+\z/
|
236
|
+
invalid_sequence_ids = sequence_ids.reject do |id|
|
237
|
+
id =~ valid_id_regex
|
238
|
+
end
|
226
239
|
|
227
|
-
|
228
|
-
|
240
|
+
unless invalid_sequence_ids.empty?
|
241
|
+
fail(
|
242
|
+
InvalidSequenceIdError,
|
243
|
+
"Invalid sequence id(s): #{invalid_sequence_ids.join(', ')}"
|
244
|
+
)
|
245
|
+
end
|
246
|
+
|
247
|
+
true
|
248
|
+
end
|
249
|
+
|
250
|
+
##
|
251
|
+
# Create a temporary file containing sequence ids to fetch.
|
252
|
+
def create_entry_batch_file
|
253
|
+
@batch_file = Tempfile.new("#{Time.now}_batch").tap do |f|
|
254
|
+
f.write(sequence_ids.join("\n"))
|
255
|
+
f.flush
|
256
|
+
end
|
229
257
|
end
|
230
258
|
|
231
259
|
# rubocop:disable Metrics/MethodLength
|
data/public/404.html
CHANGED
@@ -14,7 +14,7 @@
|
|
14
14
|
|
15
15
|
<body class="bg-light text-dark text-center">
|
16
16
|
|
17
|
-
<img src="
|
17
|
+
<img src="/sequenceserver_logo.webp" alt="SequenceServer Logo" class="mt-5 mb-3" style="max-width: 200px;">
|
18
18
|
|
19
19
|
<div class="container" style="margin-top: 10%;">
|
20
20
|
<h1 class="display-4">404 Not Found</h1>
|
data/public/css/app.min.css
CHANGED
@@ -1 +1 @@
|
|
1
|
-
/*! tailwindcss v3.4.3 | MIT License | https://tailwindcss.com*/*,:after,:before{box-sizing:border-box;border:0 solid #e5e7eb}:after,:before{--tw-content:""}:host,html{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:ui-sans-serif,system-ui,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,pre,samp{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-feature-settings:normal;font-variation-settings:normal;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:initial}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-feature-settings:inherit;font-variation-settings:inherit;font-size:100%;font-weight:inherit;line-height:inherit;letter-spacing:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}button,input:where([type=button]),input:where([type=reset]),input:where([type=submit]){-webkit-appearance:button;background-color:initial;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:initial}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dd,dl,figure,h1,h2,h3,h4,h5,h6,hr,p,pre{margin:0}fieldset{margin:0}fieldset,legend{padding:0}menu,ol,ul{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}[role=button],button{cursor:pointer}:disabled{cursor:default}audio,canvas,embed,iframe,img,object,svg,video{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]{display:none}*,::backdrop,:after,:before{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:#3b82f680;--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }.\!container{width:100%!important}.container{width:100%}@media (min-width:640px){.\!container{max-width:640px!important}.container{max-width:640px}}@media (min-width:768px){.\!container{max-width:768px!important}.container{max-width:768px}}@media (min-width:1024px){.\!container{max-width:1024px!important}.container{max-width:1024px}}@media (min-width:1280px){.\!container{max-width:1280px!important}.container{max-width:1280px}}@media (min-width:1536px){.\!container{max-width:1536px!important}.container{max-width:1536px}}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border-width:0}.visible{visibility:visible}.invisible{visibility:hidden}.collapse{visibility:collapse}.static{position:static}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.sticky{position:sticky}.inset-0{inset:0}.bottom-0{bottom:0}.bottom-12{bottom:3rem}.end-1{inset-inline-end:.25rem}.left-0{left:0}.left-1{left:.25rem}.right-0{right:0}.right-2{right:.5rem}.start-1{inset-inline-start:.25rem}.top-0{top:0}.top-2{top:.5rem}.z-10{z-index:10}.z-40{z-index:40}.z-50{z-index:50}.col-span-2{grid-column:span 2/span 2}.mx-1{margin-left:.25rem;margin-right:.25rem}.mx-auto{margin-left:auto;margin-right:auto}.my-1{margin-top:.25rem;margin-bottom:.25rem}.my-2{margin-top:.5rem;margin-bottom:.5rem}.my-4{margin-top:1rem;margin-bottom:1rem}.my-6{margin-top:1.5rem;margin-bottom:1.5rem}.-ml-8{margin-left:-2rem}.mb-2{margin-bottom:.5rem}.mb-3{margin-bottom:.75rem}.ml-1{margin-left:.25rem}.ml-2{margin-left:.5rem}.mr-1{margin-right:.25rem}.mr-2{margin-right:.5rem}.mt-2{margin-top:.5rem}.mt-3{margin-top:.75rem}.mt-5{margin-top:1.25rem}.\!block{display:block!important}.block{display:block}.inline-block{display:inline-block}.\!inline{display:inline!important}.inline{display:inline}.flex{display:flex}.inline-flex{display:inline-flex}.table{display:table}.table-caption{display:table-caption}.table-cell{display:table-cell}.grid{display:grid}.contents{display:contents}.list-item{display:list-item}.\!hidden{display:none!important}.hidden{display:none}.h-2{height:.5rem}.h-4{height:1rem}.h-6{height:1.5rem}.h-8{height:2rem}.h-full{height:100%}.max-h-8{max-height:2rem}.max-h-96{max-height:24rem}.min-h-screen{min-height:100vh}.w-3{width:.75rem}.w-4{width:1rem}.w-48{width:12rem}.w-6{width:1.5rem}.w-auto{width:auto}.w-full{width:100%}.max-w-7xl{max-width:80rem}.max-w-screen-xl{max-width:1280px}.flex-auto{flex:1 1 auto}.flex-none{flex:none}.shrink{flex-shrink:1}.flex-grow,.grow{flex-grow:1}.transform{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.cursor-pointer{cursor:pointer}.resize{resize:both}.list-inside{list-style-position:inside}.list-disc{list-style-type:disc}.flex-row{flex-direction:row}.flex-col{flex-direction:column}.items-start{align-items:flex-start}.items-end{align-items:flex-end}.items-center{align-items:center}.justify-end{justify-content:flex-end}.justify-center{justify-content:center}.gap-4{gap:1rem}.space-x-2>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-right:calc(.5rem*var(--tw-space-x-reverse));margin-left:calc(.5rem*(1 - var(--tw-space-x-reverse)))}.space-x-4>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-right:calc(1rem*var(--tw-space-x-reverse));margin-left:calc(1rem*(1 - var(--tw-space-x-reverse)))}.space-y-2>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.5rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.5rem*var(--tw-space-y-reverse))}.space-y-4>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(1rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1rem*var(--tw-space-y-reverse))}.divide-y>:not([hidden])~:not([hidden]){--tw-divide-y-reverse:0;border-top-width:calc(1px*(1 - var(--tw-divide-y-reverse)));border-bottom-width:calc(1px*var(--tw-divide-y-reverse))}.divide-gray-100>:not([hidden])~:not([hidden]){--tw-divide-opacity:1;border-color:rgb(243 244 246/var(--tw-divide-opacity))}.overflow-hidden{overflow:hidden}.overflow-x-auto{overflow-x:auto}.overflow-y-auto{overflow-y:auto}.overflow-y-scroll{overflow-y:scroll}.truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.rounded{border-radius:.25rem}.rounded-lg{border-radius:.5rem}.rounded-md{border-radius:.375rem}.rounded-l-lg{border-top-left-radius:.5rem;border-bottom-left-radius:.5rem}.rounded-r-md{border-top-right-radius:.375rem;border-bottom-right-radius:.375rem}.rounded-tr-lg{border-top-right-radius:.5rem}.border{border-width:1px}.border-b{border-bottom-width:1px}.border-t{border-top-width:1px}.border-blue-800{--tw-border-opacity:1;border-color:rgb(30 64 175/var(--tw-border-opacity))}.border-gray-300{--tw-border-opacity:1;border-color:rgb(209 213 219/var(--tw-border-opacity))}.border-red-400{--tw-border-opacity:1;border-color:rgb(248 113 113/var(--tw-border-opacity))}.border-seqblue{--tw-border-opacity:1;border-color:rgb(27 85 122/var(--tw-border-opacity))}.border-seqorange{--tw-border-opacity:1;border-color:rgb(199 79 19/var(--tw-border-opacity))}.border-transparent{border-color:#0000}.bg-blue-100{--tw-bg-opacity:1;background-color:rgb(219 234 254/var(--tw-bg-opacity))}.bg-blue-300{--tw-bg-opacity:1;background-color:rgb(147 197 253/var(--tw-bg-opacity))}.bg-gray-100{--tw-bg-opacity:1;background-color:rgb(243 244 246/var(--tw-bg-opacity))}.bg-gray-200{--tw-bg-opacity:1;background-color:rgb(229 231 235/var(--tw-bg-opacity))}.bg-gray-50{--tw-bg-opacity:1;background-color:rgb(249 250 251/var(--tw-bg-opacity))}.bg-gray-500{--tw-bg-opacity:1;background-color:rgb(107 114 128/var(--tw-bg-opacity))}.bg-red-100{--tw-bg-opacity:1;background-color:rgb(254 226 226/var(--tw-bg-opacity))}.bg-seqblue{--tw-bg-opacity:1;background-color:rgb(27 85 122/var(--tw-bg-opacity))}.bg-white{--tw-bg-opacity:1;background-color:rgb(255 255 255/var(--tw-bg-opacity))}.bg-yellow-100{--tw-bg-opacity:1;background-color:rgb(254 249 195/var(--tw-bg-opacity))}.bg-opacity-75{--tw-bg-opacity:0.75}.bg-gradient-to-t{background-image:linear-gradient(to top,var(--tw-gradient-stops))}.from-white\/90{--tw-gradient-from:#ffffffe6 var(--tw-gradient-from-position);--tw-gradient-to:#fff0 var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-from),var(--tw-gradient-to)}.to-gray-100\/90{--tw-gradient-to:#f3f4f6e6 var(--tw-gradient-to-position)}.fill-current{fill:currentColor}.p-1{padding:.25rem}.p-2{padding:.5rem}.p-4{padding:1rem}.px-1{padding-left:.25rem;padding-right:.25rem}.px-16{padding-left:4rem;padding-right:4rem}.px-2{padding-left:.5rem;padding-right:.5rem}.px-3{padding-left:.75rem;padding-right:.75rem}.px-4{padding-left:1rem;padding-right:1rem}.px-8{padding-left:2rem;padding-right:2rem}.py-1{padding-top:.25rem;padding-bottom:.25rem}.py-2{padding-top:.5rem;padding-bottom:.5rem}.py-3{padding-top:.75rem;padding-bottom:.75rem}.py-4{padding-top:1rem;padding-bottom:1rem}.py-6{padding-top:1.5rem;padding-bottom:1.5rem}.pb-20{padding-bottom:5rem}.pb-4{padding-bottom:1rem}.pr-2{padding-right:.5rem}.pt-2{padding-top:.5rem}.pt-4{padding-top:1rem}.pt-5{padding-top:1.25rem}.text-left{text-align:left}.text-center{text-align:center}.text-right{text-align:right}.align-bottom{vertical-align:bottom}.font-mono{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace}.text-2xl{font-size:1.5rem;line-height:2rem}.text-base{font-size:1rem;line-height:1.5rem}.text-lg{font-size:1.125rem;line-height:1.75rem}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xl{font-size:1.25rem;line-height:1.75rem}.font-bold{font-weight:700}.font-medium{font-weight:500}.uppercase{text-transform:uppercase}.lowercase{text-transform:lowercase}.capitalize{text-transform:capitalize}.italic{font-style:italic}.ordinal{--tw-ordinal:ordinal;font-variant-numeric:var(--tw-ordinal) var(--tw-slashed-zero) var(--tw-numeric-figure) var(--tw-numeric-spacing) var(--tw-numeric-fraction)}.leading-6{line-height:1.5rem}.text-gray-400{--tw-text-opacity:1;color:rgb(156 163 175/var(--tw-text-opacity))}.text-gray-600{--tw-text-opacity:1;color:rgb(75 85 99/var(--tw-text-opacity))}.text-gray-700{--tw-text-opacity:1;color:rgb(55 65 81/var(--tw-text-opacity))}.text-gray-800{--tw-text-opacity:1;color:rgb(31 41 55/var(--tw-text-opacity))}.text-gray-900{--tw-text-opacity:1;color:rgb(17 24 39/var(--tw-text-opacity))}.text-red-700{--tw-text-opacity:1;color:rgb(185 28 28/var(--tw-text-opacity))}.text-red-800{--tw-text-opacity:1;color:rgb(153 27 27/var(--tw-text-opacity))}.text-seqblue{--tw-text-opacity:1;color:rgb(27 85 122/var(--tw-text-opacity))}.text-white{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity))}.underline{-webkit-text-decoration-line:underline;text-decoration-line:underline}.\!shadow{--tw-shadow:0 1px 3px 0 #0000001a,0 1px 2px -1px #0000001a!important;--tw-shadow-colored:0 1px 3px 0 var(--tw-shadow-color),0 1px 2px -1px var(--tw-shadow-color)!important;box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)!important}.shadow{--tw-shadow:0 1px 3px 0 #0000001a,0 1px 2px -1px #0000001a;--tw-shadow-colored:0 1px 3px 0 var(--tw-shadow-color),0 1px 2px -1px var(--tw-shadow-color)}.shadow,.shadow-2xl{box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.shadow-2xl{--tw-shadow:0 25px 50px -12px #00000040;--tw-shadow-colored:0 25px 50px -12px var(--tw-shadow-color)}.shadow-lg{--tw-shadow:0 10px 15px -3px #0000001a,0 4px 6px -4px #0000001a;--tw-shadow-colored:0 10px 15px -3px var(--tw-shadow-color),0 4px 6px -4px var(--tw-shadow-color)}.shadow-lg,.shadow-sm{box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.shadow-sm{--tw-shadow:0 1px 2px 0 #0000000d;--tw-shadow-colored:0 1px 2px 0 var(--tw-shadow-color)}.shadow-xl{--tw-shadow:0 20px 25px -5px #0000001a,0 8px 10px -6px #0000001a;--tw-shadow-colored:0 20px 25px -5px var(--tw-shadow-color),0 8px 10px -6px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.outline-none{outline:2px solid #0000;outline-offset:2px}.outline{outline-style:solid}.ring{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(3px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000)}.blur{--tw-blur:blur(8px);filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.\!invert{--tw-invert:invert(100%)!important;filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)!important}.invert{--tw-invert:invert(100%);filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.\!filter{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)!important}.filter{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.\!transition{transition-property:color,background-color,border-color,fill,stroke,opacity,box-shadow,transform,filter,-webkit-text-decoration-color,-webkit-backdrop-filter!important;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter!important;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter,-webkit-text-decoration-color,-webkit-backdrop-filter!important;transition-timing-function:cubic-bezier(.4,0,.2,1)!important;transition-duration:.15s!important}.transition{transition-property:color,background-color,border-color,fill,stroke,opacity,box-shadow,transform,filter,-webkit-text-decoration-color,-webkit-backdrop-filter;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter,-webkit-text-decoration-color,-webkit-backdrop-filter;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-all{transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-opacity{transition-property:opacity;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.tooltip{position:absolute;z-index:1070;display:block;font-family:Helvetica Neue,Helvetica,Arial,sans-serif;font-style:normal;font-weight:400;line-height:1.42857143;line-break:auto;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;word-wrap:normal;white-space:normal;font-size:12px;filter:alpha(opacity=0);opacity:0}.tooltip.in{filter:alpha(opacity=90);opacity:.9}.tooltip.top{padding:5px 0;margin-top:-3px}.tooltip.right{padding:0 5px;margin-left:3px}.tooltip.bottom{padding:5px 0;margin-top:3px}.tooltip.left{padding:0 5px;margin-left:-3px}.tooltip.top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.top-left .tooltip-arrow{right:5px}.tooltip.top-left .tooltip-arrow,.tooltip.top-right .tooltip-arrow{bottom:0;margin-bottom:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.top-right .tooltip-arrow{left:5px}.tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-width:5px 5px 5px 0;border-right-color:#000}.tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-width:5px 0 5px 5px;border-left-color:#000}.tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-width:0 5px 5px;border-bottom-color:#000}.tooltip.bottom-left .tooltip-arrow{top:0;right:5px;margin-top:-5px;border-width:0 5px 5px;border-bottom-color:#000}.tooltip.bottom-right .tooltip-arrow{top:0;left:5px;margin-top:-5px;border-width:0 5px 5px;border-bottom-color:#000}.tooltip-inner{max-width:200px;padding:3px 8px;color:#fff;text-align:center;background-color:#000;border-radius:4px}.tooltip-arrow{position:absolute;width:0;height:0;border-color:#0000;border-style:solid}.hover\:bg-blue-400:hover{--tw-bg-opacity:1;background-color:rgb(96 165 250/var(--tw-bg-opacity))}.hover\:bg-gray-200:hover{--tw-bg-opacity:1;background-color:rgb(229 231 235/var(--tw-bg-opacity))}.hover\:bg-gray-300:hover{--tw-bg-opacity:1;background-color:rgb(209 213 219/var(--tw-bg-opacity))}.hover\:bg-red-600:hover{--tw-bg-opacity:1;background-color:rgb(220 38 38/var(--tw-bg-opacity))}.hover\:bg-seqorange:hover{--tw-bg-opacity:1;background-color:rgb(199 79 19/var(--tw-bg-opacity))}.hover\:bg-sky-400:hover{--tw-bg-opacity:1;background-color:rgb(56 189 248/var(--tw-bg-opacity))}.hover\:bg-sky-500:hover{--tw-bg-opacity:1;background-color:rgb(14 165 233/var(--tw-bg-opacity))}.hover\:bg-yellow-100:hover{--tw-bg-opacity:1;background-color:rgb(254 249 195/var(--tw-bg-opacity))}.hover\:font-bold:hover{font-weight:700}.hover\:text-white:hover{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity))}.focus\:outline-none:focus{outline:2px solid #0000;outline-offset:2px}.focus\:ring-1:focus{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color)}.focus\:ring-1:focus,.focus\:ring-2:focus{box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000)}.focus\:ring-2:focus{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color)}.focus\:ring-seqorange:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(199 79 19/var(--tw-ring-opacity))}.focus\:ring-offset-2:focus{--tw-ring-offset-width:2px}.group:hover .group-hover\:visible{visibility:visible}@media (min-width:640px){.sm\:my-8{margin-top:2rem;margin-bottom:2rem}.sm\:ml-3{margin-left:.75rem}.sm\:block{display:block}.sm\:inline-block{display:inline-block}.sm\:flex{display:flex}.sm\:h-screen{height:100vh}.sm\:w-auto{width:auto}.sm\:w-full{width:100%}.sm\:max-w-screen-md{max-width:768px}.sm\:flex-row-reverse{flex-direction:row-reverse}.sm\:items-center{align-items:center}.sm\:p-0{padding:0}.sm\:p-6{padding:1.5rem}.sm\:px-6{padding-left:1.5rem;padding-right:1.5rem}.sm\:pb-4{padding-bottom:1rem}.sm\:align-middle{vertical-align:middle}.sm\:text-sm{font-size:.875rem;line-height:1.25rem}}@media (min-width:768px){.md\:my-2{margin-top:.5rem;margin-bottom:.5rem}.md\:flex{display:flex}.md\:w-auto{width:auto}.md\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.md\:space-x-4>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-right:calc(1rem*var(--tw-space-x-reverse));margin-left:calc(1rem*(1 - var(--tw-space-x-reverse)))}}@media (min-width:1024px){.lg\:px-8{padding-left:2rem;padding-right:2rem}}
|
1
|
+
/*! tailwindcss v3.4.3 | MIT License | https://tailwindcss.com*/*,:after,:before{box-sizing:border-box;border:0 solid #e5e7eb}:after,:before{--tw-content:""}:host,html{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:ui-sans-serif,system-ui,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,pre,samp{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-feature-settings:normal;font-variation-settings:normal;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:initial}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-feature-settings:inherit;font-variation-settings:inherit;font-size:100%;font-weight:inherit;line-height:inherit;letter-spacing:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}button,input:where([type=button]),input:where([type=reset]),input:where([type=submit]){-webkit-appearance:button;background-color:initial;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:initial}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dd,dl,figure,h1,h2,h3,h4,h5,h6,hr,p,pre{margin:0}fieldset{margin:0}fieldset,legend{padding:0}menu,ol,ul{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}[role=button],button{cursor:pointer}:disabled{cursor:default}audio,canvas,embed,iframe,img,object,svg,video{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]{display:none}*,::backdrop,:after,:before{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:#3b82f680;--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }.\!container{width:100%!important}.container{width:100%}@media (min-width:640px){.\!container{max-width:640px!important}.container{max-width:640px}}@media (min-width:768px){.\!container{max-width:768px!important}.container{max-width:768px}}@media (min-width:1024px){.\!container{max-width:1024px!important}.container{max-width:1024px}}@media (min-width:1280px){.\!container{max-width:1280px!important}.container{max-width:1280px}}@media (min-width:1536px){.\!container{max-width:1536px!important}.container{max-width:1536px}}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border-width:0}.visible{visibility:visible}.invisible{visibility:hidden}.collapse{visibility:collapse}.static{position:static}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.sticky{position:sticky}.inset-0{inset:0}.bottom-0{bottom:0}.bottom-12{bottom:3rem}.end-1{inset-inline-end:.25rem}.left-0{left:0}.left-1{left:.25rem}.right-0{right:0}.right-2{right:.5rem}.start-1{inset-inline-start:.25rem}.top-0{top:0}.top-2{top:.5rem}.z-10{z-index:10}.z-40{z-index:40}.z-50{z-index:50}.col-span-2{grid-column:span 2/span 2}.mx-1{margin-left:.25rem;margin-right:.25rem}.mx-auto{margin-left:auto;margin-right:auto}.my-1{margin-top:.25rem;margin-bottom:.25rem}.my-2{margin-top:.5rem;margin-bottom:.5rem}.my-4{margin-top:1rem;margin-bottom:1rem}.my-6{margin-top:1.5rem;margin-bottom:1.5rem}.-mb-px{margin-bottom:-1px}.-ml-8{margin-left:-2rem}.mb-2{margin-bottom:.5rem}.mb-3{margin-bottom:.75rem}.mb-4{margin-bottom:1rem}.ml-1{margin-left:.25rem}.ml-2{margin-left:.5rem}.mr-1{margin-right:.25rem}.mr-2{margin-right:.5rem}.mt-2{margin-top:.5rem}.mt-3{margin-top:.75rem}.mt-5{margin-top:1.25rem}.\!block{display:block!important}.block{display:block}.inline-block{display:inline-block}.\!inline{display:inline!important}.inline{display:inline}.flex{display:flex}.inline-flex{display:inline-flex}.table{display:table}.table-caption{display:table-caption}.table-cell{display:table-cell}.grid{display:grid}.contents{display:contents}.list-item{display:list-item}.\!hidden{display:none!important}.hidden{display:none}.h-2{height:.5rem}.h-4{height:1rem}.h-6{height:1.5rem}.h-8{height:2rem}.h-full{height:100%}.max-h-8{max-height:2rem}.max-h-96{max-height:24rem}.min-h-screen{min-height:100vh}.w-3{width:.75rem}.w-4{width:1rem}.w-48{width:12rem}.w-6{width:1.5rem}.w-auto{width:auto}.w-full{width:100%}.max-w-7xl{max-width:80rem}.max-w-screen-xl{max-width:1280px}.flex-auto{flex:1 1 auto}.flex-none{flex:none}.shrink{flex-shrink:1}.shrink-0{flex-shrink:0}.flex-grow,.grow{flex-grow:1}.transform{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.cursor-help{cursor:help}.cursor-pointer{cursor:pointer}.resize{resize:both}.list-inside{list-style-position:inside}.list-disc{list-style-type:disc}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.flex-row{flex-direction:row}.flex-col{flex-direction:column}.items-start{align-items:flex-start}.items-end{align-items:flex-end}.items-center{align-items:center}.justify-end{justify-content:flex-end}.justify-center{justify-content:center}.gap-4{gap:1rem}.space-x-2>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-right:calc(.5rem*var(--tw-space-x-reverse));margin-left:calc(.5rem*(1 - var(--tw-space-x-reverse)))}.space-x-4>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-right:calc(1rem*var(--tw-space-x-reverse));margin-left:calc(1rem*(1 - var(--tw-space-x-reverse)))}.space-y-2>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.5rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.5rem*var(--tw-space-y-reverse))}.space-y-4>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(1rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1rem*var(--tw-space-y-reverse))}.divide-y>:not([hidden])~:not([hidden]){--tw-divide-y-reverse:0;border-top-width:calc(1px*(1 - var(--tw-divide-y-reverse)));border-bottom-width:calc(1px*var(--tw-divide-y-reverse))}.divide-gray-100>:not([hidden])~:not([hidden]){--tw-divide-opacity:1;border-color:rgb(243 244 246/var(--tw-divide-opacity))}.overflow-hidden{overflow:hidden}.overflow-x-auto{overflow-x:auto}.overflow-y-auto{overflow-y:auto}.overflow-y-scroll{overflow-y:scroll}.truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.rounded{border-radius:.25rem}.rounded-lg{border-radius:.5rem}.rounded-md{border-radius:.375rem}.rounded-l-lg{border-top-left-radius:.5rem;border-bottom-left-radius:.5rem}.rounded-r-md{border-top-right-radius:.375rem;border-bottom-right-radius:.375rem}.rounded-t{border-top-left-radius:.25rem;border-top-right-radius:.25rem}.rounded-tr-lg{border-top-right-radius:.5rem}.border{border-width:1px}.border-x{border-left-width:1px;border-right-width:1px}.border-b{border-bottom-width:1px}.border-t{border-top-width:1px}.border-blue-800{--tw-border-opacity:1;border-color:rgb(30 64 175/var(--tw-border-opacity))}.border-gray-300{--tw-border-opacity:1;border-color:rgb(209 213 219/var(--tw-border-opacity))}.border-red-400{--tw-border-opacity:1;border-color:rgb(248 113 113/var(--tw-border-opacity))}.border-seqblue{--tw-border-opacity:1;border-color:rgb(27 85 122/var(--tw-border-opacity))}.border-seqorange{--tw-border-opacity:1;border-color:rgb(199 79 19/var(--tw-border-opacity))}.border-transparent{border-color:#0000}.bg-blue-100{--tw-bg-opacity:1;background-color:rgb(219 234 254/var(--tw-bg-opacity))}.bg-blue-300{--tw-bg-opacity:1;background-color:rgb(147 197 253/var(--tw-bg-opacity))}.bg-gray-100{--tw-bg-opacity:1;background-color:rgb(243 244 246/var(--tw-bg-opacity))}.bg-gray-200{--tw-bg-opacity:1;background-color:rgb(229 231 235/var(--tw-bg-opacity))}.bg-gray-50{--tw-bg-opacity:1;background-color:rgb(249 250 251/var(--tw-bg-opacity))}.bg-gray-500{--tw-bg-opacity:1;background-color:rgb(107 114 128/var(--tw-bg-opacity))}.bg-red-100{--tw-bg-opacity:1;background-color:rgb(254 226 226/var(--tw-bg-opacity))}.bg-seqblue{--tw-bg-opacity:1;background-color:rgb(27 85 122/var(--tw-bg-opacity))}.bg-white{--tw-bg-opacity:1;background-color:rgb(255 255 255/var(--tw-bg-opacity))}.bg-yellow-100{--tw-bg-opacity:1;background-color:rgb(254 249 195/var(--tw-bg-opacity))}.bg-opacity-75{--tw-bg-opacity:0.75}.bg-gradient-to-t{background-image:linear-gradient(to top,var(--tw-gradient-stops))}.from-white\/90{--tw-gradient-from:#ffffffe6 var(--tw-gradient-from-position);--tw-gradient-to:#fff0 var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-from),var(--tw-gradient-to)}.to-gray-100\/90{--tw-gradient-to:#f3f4f6e6 var(--tw-gradient-to-position)}.fill-current{fill:currentColor}.p-1{padding:.25rem}.p-2{padding:.5rem}.p-4{padding:1rem}.px-1{padding-left:.25rem;padding-right:.25rem}.px-16{padding-left:4rem;padding-right:4rem}.px-2{padding-left:.5rem;padding-right:.5rem}.px-3{padding-left:.75rem;padding-right:.75rem}.px-4{padding-left:1rem;padding-right:1rem}.px-6{padding-left:1.5rem;padding-right:1.5rem}.px-8{padding-left:2rem;padding-right:2rem}.py-1{padding-top:.25rem;padding-bottom:.25rem}.py-2{padding-top:.5rem;padding-bottom:.5rem}.py-3{padding-top:.75rem;padding-bottom:.75rem}.py-4{padding-top:1rem;padding-bottom:1rem}.py-6{padding-top:1.5rem;padding-bottom:1.5rem}.pb-20{padding-bottom:5rem}.pb-4{padding-bottom:1rem}.pr-2{padding-right:.5rem}.pt-2{padding-top:.5rem}.pt-4{padding-top:1rem}.pt-5{padding-top:1.25rem}.text-left{text-align:left}.text-center{text-align:center}.text-right{text-align:right}.align-bottom{vertical-align:bottom}.font-mono{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace}.text-2xl{font-size:1.5rem;line-height:2rem}.text-base{font-size:1rem;line-height:1.5rem}.text-lg{font-size:1.125rem;line-height:1.75rem}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xl{font-size:1.25rem;line-height:1.75rem}.text-xs{font-size:.75rem;line-height:1rem}.font-bold{font-weight:700}.font-medium{font-weight:500}.font-thin{font-weight:100}.uppercase{text-transform:uppercase}.lowercase{text-transform:lowercase}.capitalize{text-transform:capitalize}.italic{font-style:italic}.ordinal{--tw-ordinal:ordinal;font-variant-numeric:var(--tw-ordinal) var(--tw-slashed-zero) var(--tw-numeric-figure) var(--tw-numeric-spacing) var(--tw-numeric-fraction)}.leading-6{line-height:1.5rem}.text-gray-400{--tw-text-opacity:1;color:rgb(156 163 175/var(--tw-text-opacity))}.text-gray-600{--tw-text-opacity:1;color:rgb(75 85 99/var(--tw-text-opacity))}.text-gray-700{--tw-text-opacity:1;color:rgb(55 65 81/var(--tw-text-opacity))}.text-gray-800{--tw-text-opacity:1;color:rgb(31 41 55/var(--tw-text-opacity))}.text-gray-900{--tw-text-opacity:1;color:rgb(17 24 39/var(--tw-text-opacity))}.text-red-700{--tw-text-opacity:1;color:rgb(185 28 28/var(--tw-text-opacity))}.text-red-800{--tw-text-opacity:1;color:rgb(153 27 27/var(--tw-text-opacity))}.text-seqblue{--tw-text-opacity:1;color:rgb(27 85 122/var(--tw-text-opacity))}.text-seqorange{--tw-text-opacity:1;color:rgb(199 79 19/var(--tw-text-opacity))}.text-white{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity))}.underline{-webkit-text-decoration-line:underline;text-decoration-line:underline}.\!shadow{--tw-shadow:0 1px 3px 0 #0000001a,0 1px 2px -1px #0000001a!important;--tw-shadow-colored:0 1px 3px 0 var(--tw-shadow-color),0 1px 2px -1px var(--tw-shadow-color)!important;box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)!important}.shadow{--tw-shadow:0 1px 3px 0 #0000001a,0 1px 2px -1px #0000001a;--tw-shadow-colored:0 1px 3px 0 var(--tw-shadow-color),0 1px 2px -1px var(--tw-shadow-color)}.shadow,.shadow-2xl{box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.shadow-2xl{--tw-shadow:0 25px 50px -12px #00000040;--tw-shadow-colored:0 25px 50px -12px var(--tw-shadow-color)}.shadow-lg{--tw-shadow:0 10px 15px -3px #0000001a,0 4px 6px -4px #0000001a;--tw-shadow-colored:0 10px 15px -3px var(--tw-shadow-color),0 4px 6px -4px var(--tw-shadow-color)}.shadow-lg,.shadow-sm{box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.shadow-sm{--tw-shadow:0 1px 2px 0 #0000000d;--tw-shadow-colored:0 1px 2px 0 var(--tw-shadow-color)}.shadow-xl{--tw-shadow:0 20px 25px -5px #0000001a,0 8px 10px -6px #0000001a;--tw-shadow-colored:0 20px 25px -5px var(--tw-shadow-color),0 8px 10px -6px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.outline-none{outline:2px solid #0000;outline-offset:2px}.outline{outline-style:solid}.ring{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(3px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000)}.blur{--tw-blur:blur(8px);filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.\!invert{--tw-invert:invert(100%)!important;filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)!important}.invert{--tw-invert:invert(100%);filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.\!filter{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)!important}.filter{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.\!transition{transition-property:color,background-color,border-color,fill,stroke,opacity,box-shadow,transform,filter,-webkit-text-decoration-color,-webkit-backdrop-filter!important;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter!important;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter,-webkit-text-decoration-color,-webkit-backdrop-filter!important;transition-timing-function:cubic-bezier(.4,0,.2,1)!important;transition-duration:.15s!important}.transition{transition-property:color,background-color,border-color,fill,stroke,opacity,box-shadow,transform,filter,-webkit-text-decoration-color,-webkit-backdrop-filter;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter,-webkit-text-decoration-color,-webkit-backdrop-filter;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-all{transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-opacity{transition-property:opacity;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.tooltip{position:absolute;z-index:1070;display:block;font-family:Helvetica Neue,Helvetica,Arial,sans-serif;font-style:normal;font-weight:400;line-height:1.42857143;line-break:auto;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;word-wrap:normal;white-space:normal;font-size:12px;filter:alpha(opacity=0);opacity:0}.tooltip.in{filter:alpha(opacity=90);opacity:.9}.tooltip.top{padding:5px 0;margin-top:-3px}.tooltip.right{padding:0 5px;margin-left:3px}.tooltip.bottom{padding:5px 0;margin-top:3px}.tooltip.left{padding:0 5px;margin-left:-3px}.tooltip.top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.top-left .tooltip-arrow{right:5px}.tooltip.top-left .tooltip-arrow,.tooltip.top-right .tooltip-arrow{bottom:0;margin-bottom:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.top-right .tooltip-arrow{left:5px}.tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-width:5px 5px 5px 0;border-right-color:#000}.tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-width:5px 0 5px 5px;border-left-color:#000}.tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-width:0 5px 5px;border-bottom-color:#000}.tooltip.bottom-left .tooltip-arrow{top:0;right:5px;margin-top:-5px;border-width:0 5px 5px;border-bottom-color:#000}.tooltip.bottom-right .tooltip-arrow{top:0;left:5px;margin-top:-5px;border-width:0 5px 5px;border-bottom-color:#000}.tooltip-inner{max-width:200px;padding:3px 8px;color:#fff;text-align:center;background-color:#000;border-radius:4px}.tooltip-arrow{position:absolute;width:0;height:0;border-color:#0000;border-style:solid}.hover\:bg-blue-400:hover{--tw-bg-opacity:1;background-color:rgb(96 165 250/var(--tw-bg-opacity))}.hover\:bg-gray-200:hover{--tw-bg-opacity:1;background-color:rgb(229 231 235/var(--tw-bg-opacity))}.hover\:bg-gray-300:hover{--tw-bg-opacity:1;background-color:rgb(209 213 219/var(--tw-bg-opacity))}.hover\:bg-red-600:hover{--tw-bg-opacity:1;background-color:rgb(220 38 38/var(--tw-bg-opacity))}.hover\:bg-seqorange:hover{--tw-bg-opacity:1;background-color:rgb(199 79 19/var(--tw-bg-opacity))}.hover\:bg-sky-400:hover{--tw-bg-opacity:1;background-color:rgb(56 189 248/var(--tw-bg-opacity))}.hover\:bg-sky-500:hover{--tw-bg-opacity:1;background-color:rgb(14 165 233/var(--tw-bg-opacity))}.hover\:bg-yellow-100:hover{--tw-bg-opacity:1;background-color:rgb(254 249 195/var(--tw-bg-opacity))}.hover\:font-bold:hover{font-weight:700}.hover\:text-white:hover{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity))}.focus\:outline-none:focus{outline:2px solid #0000;outline-offset:2px}.focus\:ring-1:focus{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color)}.focus\:ring-1:focus,.focus\:ring-2:focus{box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000)}.focus\:ring-2:focus{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color)}.focus\:ring-seqorange:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(199 79 19/var(--tw-ring-opacity))}.focus\:ring-offset-2:focus{--tw-ring-offset-width:2px}.group:hover .group-hover\:visible{visibility:visible}@media (min-width:640px){.sm\:my-8{margin-top:2rem;margin-bottom:2rem}.sm\:ml-3{margin-left:.75rem}.sm\:mt-0{margin-top:0}.sm\:block{display:block}.sm\:inline-block{display:inline-block}.sm\:flex{display:flex}.sm\:h-screen{height:100vh}.sm\:w-auto{width:auto}.sm\:w-full{width:100%}.sm\:max-w-screen-md{max-width:768px}.sm\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.sm\:flex-row-reverse{flex-direction:row-reverse}.sm\:items-center{align-items:center}.sm\:p-0{padding:0}.sm\:p-6{padding:1.5rem}.sm\:px-6{padding-left:1.5rem;padding-right:1.5rem}.sm\:pb-4{padding-bottom:1rem}.sm\:align-middle{vertical-align:middle}.sm\:text-sm{font-size:.875rem;line-height:1.25rem}}@media (min-width:768px){.md\:my-2{margin-top:.5rem;margin-bottom:.5rem}.md\:flex{display:flex}.md\:w-auto{width:auto}.md\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.md\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.md\:space-x-4>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-right:calc(1rem*var(--tw-space-x-reverse));margin-left:calc(1rem*(1 - var(--tw-space-x-reverse)))}.md\:divide-x>:not([hidden])~:not([hidden]){--tw-divide-x-reverse:0;border-right-width:calc(1px*var(--tw-divide-x-reverse));border-left-width:calc(1px*(1 - var(--tw-divide-x-reverse)))}.md\:divide-y-0>:not([hidden])~:not([hidden]){--tw-divide-y-reverse:0;border-top-width:calc(0px*(1 - var(--tw-divide-y-reverse)));border-bottom-width:calc(0px*var(--tw-divide-y-reverse))}.md\:pl-2{padding-left:.5rem}.md\:pt-0{padding-top:0}}@media (min-width:1024px){.lg\:px-8{padding-left:2rem;padding-right:2rem}}
|
data/public/js/download_fasta.js
CHANGED
@@ -7,6 +7,7 @@ export default function downloadFASTA(sequence_ids, database_ids) {
|
|
7
7
|
var form = $('<form/>').attr('method', 'post').attr('action', 'get_sequence');
|
8
8
|
addField('sequence_ids', sequence_ids);
|
9
9
|
addField('database_ids', database_ids);
|
10
|
+
addField('_csrf', document.querySelector('meta[name="_csrf"]').content);
|
10
11
|
form.appendTo('body').submit().remove();
|
11
12
|
|
12
13
|
function addField(name, val) {
|
data/public/js/form.js
CHANGED
@@ -203,6 +203,7 @@ export class Form extends Component {
|
|
203
203
|
</div>
|
204
204
|
|
205
205
|
<form id="blast" ref={this.formRef} onSubmit={this.handleFormSubmission}>
|
206
|
+
<input type="hidden" name="_csrf" value={document.querySelector('meta[name="_csrf"]').content} />
|
206
207
|
<div className="px-4">
|
207
208
|
<SearchQueryWidget ref="query" onSequenceTypeChanged={this.handleSequenceTypeChanged} onSequenceChanged={this.handleSequenceChanged}/>
|
208
209
|
|
data/public/js/sidebar.js
CHANGED
@@ -350,6 +350,15 @@ export default class extends Component {
|
|
350
350
|
</a>
|
351
351
|
</li>
|
352
352
|
}
|
353
|
+
{
|
354
|
+
!this.props.data.imported_xml && <li>
|
355
|
+
<a className="btn-link download" data-toggle="tooltip"
|
356
|
+
title="Results in pairwise format."
|
357
|
+
href={'download/' + this.props.data.search_id + '.pairwise'}>
|
358
|
+
Full Pairwise report
|
359
|
+
</a>
|
360
|
+
</li>
|
361
|
+
}
|
353
362
|
<DownloadLinks imported_xml={this.props.data.imported_xml} search_id={this.props.data.search_id} />
|
354
363
|
</ul>
|
355
364
|
</div>
|
@@ -13,6 +13,20 @@ export const setMockJSONResult = (result) => {
|
|
13
13
|
};
|
14
14
|
|
15
15
|
describe('ADVANCED PARAMETERS', () => {
|
16
|
+
let csrfMetaTag;
|
17
|
+
|
18
|
+
beforeEach(() => {
|
19
|
+
csrfMetaTag = document.createElement('meta');
|
20
|
+
csrfMetaTag.setAttribute('name', '_csrf');
|
21
|
+
csrfMetaTag.setAttribute('content', 'test-token');
|
22
|
+
document.head.appendChild(csrfMetaTag);
|
23
|
+
});
|
24
|
+
|
25
|
+
afterEach(() => {
|
26
|
+
// Remove the CSRF meta tag after each test to clean up
|
27
|
+
document.head.removeChild(csrfMetaTag);
|
28
|
+
});
|
29
|
+
|
16
30
|
const getInputElement = () => screen.getByRole('textbox', { name: '' });
|
17
31
|
test('should not render the link to advanced parameters modal if blast algorithm is unknown', () => {
|
18
32
|
setMockJSONResult(data);
|
@@ -37,6 +51,20 @@ describe('ADVANCED PARAMETERS', () => {
|
|
37
51
|
});
|
38
52
|
|
39
53
|
describe('query stats', () => {
|
54
|
+
let csrfMetaTag;
|
55
|
+
|
56
|
+
beforeEach(() => {
|
57
|
+
csrfMetaTag = document.createElement('meta');
|
58
|
+
csrfMetaTag.setAttribute('name', '_csrf');
|
59
|
+
csrfMetaTag.setAttribute('content', 'test-token');
|
60
|
+
document.head.appendChild(csrfMetaTag);
|
61
|
+
});
|
62
|
+
|
63
|
+
afterEach(() => {
|
64
|
+
// Remove the CSRF meta tag after each test to clean up
|
65
|
+
document.head.removeChild(csrfMetaTag);
|
66
|
+
});
|
67
|
+
|
40
68
|
const getInputElement = () => screen.getByRole('textbox', { name: '' });
|
41
69
|
|
42
70
|
test('should render the query stats modal when clicked', () => {
|
@@ -10,12 +10,23 @@ let container;
|
|
10
10
|
let inputEl;
|
11
11
|
|
12
12
|
describe('SEARCH COMPONENT', () => {
|
13
|
+
let csrfMetaTag;
|
14
|
+
|
13
15
|
beforeEach(() => {
|
16
|
+
csrfMetaTag = document.createElement('meta');
|
17
|
+
csrfMetaTag.setAttribute('name', '_csrf');
|
18
|
+
csrfMetaTag.setAttribute('content', 'test-token');
|
19
|
+
document.head.appendChild(csrfMetaTag);
|
14
20
|
container = render(<Form onSequenceTypeChanged={() => { }
|
15
21
|
} />).container;
|
16
22
|
inputEl = screen.getByRole('textbox', { name: '' });
|
17
23
|
});
|
18
24
|
|
25
|
+
afterEach(() => {
|
26
|
+
// Remove the CSRF meta tag after each test to clean up
|
27
|
+
document.head.removeChild(csrfMetaTag);
|
28
|
+
});
|
29
|
+
|
19
30
|
test('should render the search component textarea', () => {
|
20
31
|
expect(inputEl).toBeInTheDocument();
|
21
32
|
});
|
@@ -60,7 +60,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpac
|
|
60
60
|
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
|
61
61
|
|
62
62
|
"use strict";
|
63
|
-
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (/* binding */ downloadFASTA)\n/* harmony export */ });\n/* provided dependency */ var $ = __webpack_require__(/*! jquery */ \"./node_modules/jquery/dist/jquery.js\");\n/**\n * Dynamically create form and submit.\n *\n * Author: Filip Ter\n */\nfunction downloadFASTA(sequence_ids, database_ids) {\n var form = $('<form/>').attr('method', 'post').attr('action', 'get_sequence');\n addField('sequence_ids', sequence_ids);\n addField('database_ids', database_ids);\n form.appendTo('body').submit().remove();\n function addField(name, val) {\n form.append($('<input>').attr('type', 'hidden').attr('name', name).val(val));\n }\n}\n\n//# sourceURL=webpack://SequenceServer/./public/js/download_fasta.js?");
|
63
|
+
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (/* binding */ downloadFASTA)\n/* harmony export */ });\n/* provided dependency */ var $ = __webpack_require__(/*! jquery */ \"./node_modules/jquery/dist/jquery.js\");\n/**\n * Dynamically create form and submit.\n *\n * Author: Filip Ter\n */\nfunction downloadFASTA(sequence_ids, database_ids) {\n var form = $('<form/>').attr('method', 'post').attr('action', 'get_sequence');\n addField('sequence_ids', sequence_ids);\n addField('database_ids', database_ids);\n addField('_csrf', document.querySelector('meta[name=\"_csrf\"]').content);\n form.appendTo('body').submit().remove();\n function addField(name, val) {\n form.append($('<input>').attr('type', 'hidden').attr('name', name).val(val));\n }\n}\n\n//# sourceURL=webpack://SequenceServer/./public/js/download_fasta.js?");
|
64
64
|
|
65
65
|
/***/ }),
|
66
66
|
|
@@ -302,7 +302,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpac
|
|
302
302
|
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
|
303
303
|
|
304
304
|
"use strict";
|
305
|
-
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (/* binding */ _default)\n/* harmony export */ });\n/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ \"./node_modules/react/index.js\");\n/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);\n/* harmony import */ var underscore__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! underscore */ \"./node_modules/underscore/modules/index-all.js\");\n/* harmony import */ var _download_fasta__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./download_fasta */ \"./public/js/download_fasta.js\");\n/* harmony import */ var _mailto__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./mailto */ \"./public/js/mailto.js\");\n/* harmony import */ var _cloud_share_modal__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./cloud_share_modal */ \"./public/js/cloud_share_modal.js\");\n/* harmony import */ var download_links__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! download_links */ \"./public/js/null_plugins/download_links.js\");\n/* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! react/jsx-runtime */ \"./node_modules/react/jsx-runtime.js\");\n/* provided dependency */ var $ = __webpack_require__(/*! jquery */ \"./node_modules/jquery/dist/jquery.js\");\nfunction _typeof(obj) { \"@babel/helpers - typeof\"; return _typeof = \"function\" == typeof Symbol && \"symbol\" == typeof Symbol.iterator ? function (obj) { return typeof obj; } : function (obj) { return obj && \"function\" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? \"symbol\" : typeof obj; }, _typeof(obj); }\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\nfunction _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }\nfunction _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, \"prototype\", { writable: false }); return Constructor; }\nfunction _callSuper(_this, derived, args) {\n function isNativeReflectConstruct() {\n if (typeof Reflect === \"undefined\" || !Reflect.construct) return false;\n if (Reflect.construct.sham) return false;\n if (typeof Proxy === \"function\") return true;\n try {\n return !Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {}));\n } catch (e) {\n return false;\n }\n }\n derived = _getPrototypeOf(derived);\n return _possibleConstructorReturn(_this, isNativeReflectConstruct() ? Reflect.construct(derived, args || [], _getPrototypeOf(_this).constructor) : derived.apply(_this, args));\n}\nfunction _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === \"object\" || typeof call === \"function\")) { return call; } else if (call !== void 0) { throw new TypeError(\"Derived constructors may only return object or undefined\"); } return _assertThisInitialized(self); }\nfunction _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError(\"this hasn't been initialised - super() hasn't been called\"); } return self; }\nfunction _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }\nfunction _inherits(subClass, superClass) { if (typeof superClass !== \"function\" && superClass !== null) { throw new TypeError(\"Super expression must either be null or a function\"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); Object.defineProperty(subClass, \"prototype\", { writable: false }); if (superClass) _setPrototypeOf(subClass, superClass); }\nfunction _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }\n\n\n\n\n\n\n/**\n * checks whether code is being run by jest\n */\n// eslint-disable-next-line no-undef\n\nvar isTestMode = function isTestMode() {\n return ({}).JEST_WORKER_ID !== undefined || \"development\" === 'test';\n};\n/**\n * Renders links for downloading hit information in different formats.\n * Renders links for navigating to each query.\n */\nvar _default = /*#__PURE__*/function (_Component) {\n function _default(props) {\n var _this2;\n _classCallCheck(this, _default);\n _this2 = _callSuper(this, _default, [props]);\n _this2.downloadFastaOfAll = _this2.downloadFastaOfAll.bind(_this2);\n _this2.downloadFastaOfSelected = _this2.downloadFastaOfSelected.bind(_this2);\n _this2.topPanelJSX = _this2.topPanelJSX.bind(_this2);\n _this2.summaryString = _this2.summaryString.bind(_this2);\n _this2.indexJSX = _this2.indexJSX.bind(_this2);\n _this2.downloadsPanelJSX = _this2.downloadsPanelJSX.bind(_this2);\n _this2.handleQueryIndexChange = _this2.handleQueryIndexChange.bind(_this2);\n _this2.isElementInViewPort = _this2.isElementInViewPort.bind(_this2);\n _this2.setVisibleQueryIndex = _this2.setVisibleQueryIndex.bind(_this2);\n _this2.debounceScrolling = _this2.debounceScrolling.bind(_this2);\n _this2.scrollListener = _this2.scrollListener.bind(_this2);\n _this2.copyURL = _this2.copyURL.bind(_this2);\n _this2.shareCloudInit = _this2.shareCloudInit.bind(_this2);\n _this2.sharingPanelJSX = _this2.sharingPanelJSX.bind(_this2);\n _this2.timeout = null;\n _this2.queryElems = [];\n _this2.state = {\n queryIndex: 1\n };\n return _this2;\n }\n _inherits(_default, _Component);\n return _createClass(_default, [{\n key: \"componentDidMount\",\n value: function componentDidMount() {\n /**\n * Fixes tooltips in the sidebar, allows tooltip display on click\n */\n $(function () {\n $('.sidebar [data-toggle=\"tooltip\"]').tooltip({\n placement: 'right'\n });\n $('#copyURL').tooltip({\n title: 'Copied!',\n trigger: 'click',\n placement: 'right',\n delay: 0\n });\n });\n\n //keep track of the current queryIndex so it doesn't get lost on page reload\n var urlMatch = window.location.href.match(/#Query_(\\d+)/);\n if (urlMatch && urlMatch.length > 1) {\n var queryNumber = +urlMatch[1];\n var index = this.props.data.queries.findIndex(function (query) {\n return query.number === queryNumber;\n });\n this.setState({\n queryIndex: index + 1\n });\n }\n window.addEventListener('scroll', this.scrollListener);\n $('a[href^=\"#Query_\"]').on('click', this.animateAnchorElements);\n }\n }, {\n key: \"componentWillUnmount\",\n value: function componentWillUnmount() {\n window.removeEventListener('scroll', this.scrollListener);\n }\n }, {\n key: \"componentDidUpdate\",\n value: function componentDidUpdate(prevProps) {\n if (this.props.allQueriesLoaded && !prevProps.allQueriesLoaded) {\n /**\n * storing all query elements in this variable once they all become available so we don't have to fetch them all over again\n */\n this.queryElems = Array.from(document.querySelectorAll('.resultn'));\n }\n }\n\n /**\n * to avoid unnecessary computations, we debounce the scroll listener so it only fires after user has stopped scrolling for some milliseconds\n */\n }, {\n key: \"scrollListener\",\n value: function scrollListener() {\n this.debounceScrolling(this.setVisibleQueryIndex, 500);\n }\n }, {\n key: \"debounceScrolling\",\n value: function debounceScrolling(callback, timer) {\n if (this.timeout) {\n clearTimeout(this.timeout);\n }\n this.timeout = setTimeout(callback, timer);\n }\n\n /**\n * This method makes the page aware of what query is visible so that clicking previous / next button at any point\n * navigates to the proper query\n */\n }, {\n key: \"setVisibleQueryIndex\",\n value: function setVisibleQueryIndex() {\n var queryElems = this.queryElems.length ? this.queryElems : Array.from(document.querySelectorAll('.resultn'));\n var hits = Array.from(document.querySelectorAll('.hit[id^=Query_]'));\n // get the first visible element and marks it as the current query\n var topmostEl = queryElems.find(this.isElementInViewPort) || hits.find(this.isElementInViewPort);\n if (topmostEl) {\n var queryIndex = Number(topmostEl.id.match(/Query_(\\d+)/)[1]);\n var hash = \"#Query_\".concat(queryIndex);\n // if we can guarantee that the browser can handle change in url hash without the page jumping,\n // then we update the url hash after scroll. else, hash is only updated on click of next or prev button\n if (window.history.pushState) {\n window.history.pushState(null, null, hash);\n }\n this.setState({\n queryIndex: queryIndex\n });\n }\n }\n }, {\n key: \"animateAnchorElements\",\n value: function animateAnchorElements(e) {\n // allow normal behavior in test mode to prevent warnings or errors from jquery\n if (isTestMode()) return;\n e.preventDefault();\n $('html, body').animate({\n scrollTop: $(this.hash).offset().top\n }, 300);\n if (window.history.pushState) {\n window.history.pushState(null, null, this.hash);\n } else {\n window.location.hash = this.hash;\n }\n }\n }, {\n key: \"isElementInViewPort\",\n value: function isElementInViewPort(elem) {\n var _elem$getBoundingClie = elem.getBoundingClientRect(),\n top = _elem$getBoundingClie.top,\n left = _elem$getBoundingClie.left,\n right = _elem$getBoundingClie.right,\n bottom = _elem$getBoundingClie.bottom;\n return top >= 0 && left >= 0 && bottom <= (window.innerHeight || document.documentElement.clientHeight) && right <= (window.innerWidth || document.documentElement.clientWidth);\n }\n /**\n * Clear sessionStorage - useful to initiate a new search in the same tab.\n * Passing sessionStorage.clear directly as onclick callback didn't work\n * (on macOS Chrome).\n */\n }, {\n key: \"clearSession\",\n value: function clearSession() {\n sessionStorage.clear();\n }\n /**\n *\n * handle next and previous query button clicks\n */\n }, {\n key: \"handleQueryIndexChange\",\n value: function handleQueryIndexChange(nextQuery) {\n if (nextQuery < 1 || nextQuery > this.props.data.queries.length) return;\n var anchorEl = document.createElement('a');\n //indexing at [nextQuery - 1] because array is 0-indexed\n anchorEl.setAttribute('href', '#Query_' + this.props.data.queries[nextQuery - 1].number);\n anchorEl.setAttribute('hidden', true);\n document.body.appendChild(anchorEl);\n // add smooth scrolling animation with jquery\n $(anchorEl).on('click', this.animateAnchorElements);\n anchorEl.click();\n document.body.removeChild(anchorEl);\n this.setState({\n queryIndex: nextQuery\n });\n }\n /**\n * Event-handler for downloading fasta of all hits.\n */\n }, {\n key: \"downloadFastaOfAll\",\n value: function downloadFastaOfAll() {\n var sequence_ids = [];\n this.props.data.queries.forEach(function (query) {\n return query.hits.forEach(function (hit) {\n return sequence_ids.push(hit.id);\n });\n });\n var database_ids = this.props.data.querydb.map(function (querydb) {\n return querydb.id;\n });\n (0,_download_fasta__WEBPACK_IMPORTED_MODULE_2__[\"default\"])(sequence_ids, database_ids);\n return false;\n }\n\n /**\n * Handles downloading fasta of selected hits.\n */\n }, {\n key: \"downloadFastaOfSelected\",\n value: function downloadFastaOfSelected() {\n var sequence_ids = $('.hit-links :checkbox:checked').map(function () {\n return this.value;\n }).get();\n if (sequence_ids.length === 0) {\n return false;\n }\n var database_ids = underscore__WEBPACK_IMPORTED_MODULE_1__[\"default\"].map(this.props.data.querydb, underscore__WEBPACK_IMPORTED_MODULE_1__[\"default\"].iteratee('id'));\n (0,_download_fasta__WEBPACK_IMPORTED_MODULE_2__[\"default\"])(sequence_ids, database_ids);\n return false;\n }\n\n /**\n * Handles copying the URL into the user's clipboard. Modified from: https://stackoverflow.com/a/49618964/18117380\n * Hides the 'Copied!' tooltip after 3 seconds\n */\n }, {\n key: \"copyURL\",\n value: function copyURL() {\n var element = document.createElement('input');\n var url = window.location.href;\n document.body.appendChild(element);\n element.value = url;\n element.select();\n document.execCommand('copy');\n document.body.removeChild(element);\n setTimeout(function () {\n $('#copyURL')._tooltip('hide');\n }, 3000);\n }\n }, {\n key: \"shareCloudInit\",\n value: function shareCloudInit() {\n this.refs.cloudShareModal.show();\n }\n }, {\n key: \"topPanelJSX\",\n value: function topPanelJSX() {\n var path = location.pathname.split('/');\n // Get job id.\n var job_id = path.pop();\n // Deriving rootURL this way is required for subURI deployments\n // - we cannot just send to '/'.\n var rootURL = path.join('/');\n return /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxs)(\"div\", {\n className: \"sidebar-top-panel\",\n children: [/*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)(\"div\", {\n className: \"section-header-sidebar\",\n children: /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)(\"h4\", {\n children: this.summaryString()\n })\n }), this.props.data.queries.length > 12 && this.queryIndexButtons(), /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxs)(\"div\", {\n children: [/*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxs)(\"a\", {\n href: \"\".concat(rootURL, \"/?job_id=\").concat(job_id),\n children: [/*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)(\"i\", {\n className: \"fa fa-pencil\"\n }), \" Edit search\"]\n }), /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)(\"span\", {\n className: \"line\",\n children: \"|\"\n }), /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxs)(\"a\", {\n href: \"\".concat(rootURL, \"/\"),\n onClick: this.clearSession,\n children: [/*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)(\"i\", {\n className: \"fa fa-file-o\"\n }), \" New search\"]\n })]\n }), this.props.shouldShowIndex && this.indexJSX()]\n });\n }\n }, {\n key: \"summaryString\",\n value: function summaryString() {\n var program = this.props.data.program;\n var numqueries = this.props.data.queries.length;\n var numquerydb = this.props.data.querydb.length;\n return program.toUpperCase() + ': ' + numqueries + ' ' + (numqueries > 1 ? 'queries' : 'query') + ', ' + numquerydb + ' ' + (numquerydb > 1 ? 'databases' : 'database');\n }\n }, {\n key: \"queryIndexButtons\",\n value: function queryIndexButtons() {\n var _this3 = this;\n var buttonStyle = {\n outline: 'none',\n border: 'none',\n background: 'none'\n };\n var buttonClasses = 'btn-link nowrap-ellipsis hover-bold';\n var handlePreviousBtnClick = function handlePreviousBtnClick() {\n return _this3.handleQueryIndexChange(_this3.state.queryIndex - 1);\n };\n var handleNextBtnClick = function handleNextBtnClick() {\n return _this3.handleQueryIndexChange(_this3.state.queryIndex + 1);\n };\n\n // eslint-disable-next-line no-unused-vars\n var NavButton = function NavButton(_ref) {\n var text = _ref.text,\n onClick = _ref.onClick;\n return /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)(\"button\", {\n className: buttonClasses,\n onClick: onClick,\n style: buttonStyle,\n children: text\n });\n };\n return /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxs)(\"div\", {\n style: {\n display: 'flex',\n width: '100%',\n margin: '7px 0'\n },\n children: [this.state.queryIndex > 1 && /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)(NavButton, {\n text: \"Previous Query\",\n onClick: handlePreviousBtnClick\n }), this.state.queryIndex > 1 && this.state.queryIndex < this.props.data.queries.length && /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)(\"span\", {\n className: \"line\",\n children: \"|\"\n }), this.state.queryIndex < this.props.data.queries.length && /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)(NavButton, {\n onClick: handleNextBtnClick,\n text: \"Next Query\"\n })]\n });\n }\n }, {\n key: \"indexJSX\",\n value: function indexJSX() {\n return /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxs)(\"ul\", {\n className: \"nav hover-reset active-bold\",\n children: [\" \", underscore__WEBPACK_IMPORTED_MODULE_1__[\"default\"].map(this.props.data.queries, function (query) {\n return /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)(\"li\", {\n children: /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)(\"a\", {\n className: \"btn-link nowrap-ellipsis hover-bold\",\n title: 'Query= ' + query.id + ' ' + query.title,\n href: '#Query_' + query.number,\n children: 'Query= ' + query.id\n })\n }, 'Side_bar_' + query.id);\n })]\n });\n }\n }, {\n key: \"downloadsPanelJSX\",\n value: function downloadsPanelJSX() {\n return /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxs)(\"div\", {\n className: \"downloads\",\n children: [/*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)(\"div\", {\n className: \"section-header-sidebar\",\n children: /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)(\"h4\", {\n children: \"Download FASTA, XML, TSV\"\n })\n }), /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxs)(\"ul\", {\n className: \"nav\",\n children: [!(this.props.data.imported_xml || this.props.data.non_parse_seqids) && /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)(\"li\", {\n children: /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)(\"a\", {\n href: \"#\",\n className: \"btn-link download-fasta-of-all \".concat(!this.props.atLeastOneHit && 'disabled'),\n onClick: this.downloadFastaOfAll,\n children: \"FASTA of all hits\"\n })\n }), !(this.props.data.imported_xml || this.props.data.non_parse_seqids) && /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)(\"li\", {\n children: /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxs)(\"a\", {\n href: \"#\",\n className: \"btn-link download-fasta-of-selected disabled\",\n onClick: this.downloadFastaOfSelected,\n children: [\"FASTA of \", /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)(\"span\", {\n className: \"text-bold\"\n }), \" selected hit(s)\"]\n })\n }), /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)(\"li\", {\n children: /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)(\"a\", {\n href: \"#\",\n className: \"btn-link download-alignment-of-all \".concat(!this.props.atLeastOneHit && 'disabled'),\n children: \"Alignment of all hits\"\n })\n }), /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)(\"li\", {\n children: /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxs)(\"a\", {\n href: \"#\",\n className: \"btn-link download-alignment-of-selected disabled\",\n children: [\"Alignment of \", /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)(\"span\", {\n className: \"text-bold\"\n }), \" selected hit(s)\"]\n })\n }), !this.props.data.imported_xml && /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)(\"li\", {\n children: /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)(\"a\", {\n className: \"btn-link download\",\n \"data-toggle\": \"tooltip\",\n title: \"15 columns: query and subject ID; scientific name, alignment length, mismatches, gaps, identity, start and end coordinates, e value, bitscore, query coverage per subject and per HSP.\",\n href: 'download/' + this.props.data.search_id + '.std_tsv',\n children: \"Standard tabular report\"\n })\n }), !this.props.data.imported_xml && /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)(\"li\", {\n children: /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)(\"a\", {\n className: \"btn-link download\",\n \"data-toggle\": \"tooltip\",\n title: \"44 columns: query and subject ID, GI, accessions, and length; alignment details; taxonomy details of subject sequence(s) and query coverage per subject and per HSP.\",\n href: 'download/' + this.props.data.search_id + '.full_tsv',\n children: \"Full tabular report\"\n })\n }), !this.props.data.imported_xml && /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)(\"li\", {\n children: /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)(\"a\", {\n className: \"btn-link download\",\n \"data-toggle\": \"tooltip\",\n title: \"Results in XML format.\",\n href: 'download/' + this.props.data.search_id + '.xml',\n children: \"Full XML report\"\n })\n }), /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)(download_links__WEBPACK_IMPORTED_MODULE_5__[\"default\"], {\n imported_xml: this.props.data.imported_xml,\n search_id: this.props.data.search_id\n })]\n })]\n });\n }\n }, {\n key: \"sharingPanelJSX\",\n value: function sharingPanelJSX() {\n return /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxs)(\"div\", {\n className: \"sharing-panel\",\n children: [/*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)(\"div\", {\n className: \"section-header-sidebar\",\n children: /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)(\"h4\", {\n children: \"Share results\"\n })\n }), /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxs)(\"ul\", {\n className: \"nav\",\n children: [!this.props.cloudSharingEnabled && /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)(\"li\", {\n children: /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxs)(\"a\", {\n id: \"copyURL\",\n className: \"btn-link copy-URL cursor-pointer\",\n \"data-toggle\": \"tooltip\",\n onClick: this.copyURL,\n children: [/*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)(\"i\", {\n className: \"fa fa-copy\"\n }), \" Copy URL to clipboard\"]\n })\n }), !this.props.cloudSharingEnabled && /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)(\"li\", {\n children: /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxs)(\"a\", {\n id: \"sendEmail\",\n className: \"btn-link email-URL cursor-pointer\",\n \"data-toggle\": \"tooltip\",\n title: \"Send by email\",\n href: (0,_mailto__WEBPACK_IMPORTED_MODULE_3__[\"default\"])(this.props.data.querydb, this.props.data.program, this.props.data.queries.length, window.location.href),\n target: \"_blank\",\n rel: \"noopener noreferrer\",\n children: [/*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)(\"i\", {\n className: \"fa fa-envelope\"\n }), \" Send by email\"]\n })\n }), this.props.cloudSharingEnabled && /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)(\"li\", {\n children: /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxs)(\"button\", {\n className: \"btn-link cloud-Post cursor-pointer\",\n \"data-toggle\": \"tooltip\",\n title: \"Upload results to SequenceServer Cloud where it will become accessable to everyone who has a link.\",\n onClick: this.shareCloudInit,\n children: [/*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)(\"i\", {\n className: \"fa fa-cloud\"\n }), \" Share to cloud\"]\n })\n })]\n }), /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)(_cloud_share_modal__WEBPACK_IMPORTED_MODULE_4__[\"default\"], {\n ref: \"cloudShareModal\",\n querydb: this.props.data.querydb,\n program: this.props.data.program,\n queryLength: this.props.data.queries.length\n })]\n });\n }\n }, {\n key: \"render\",\n value: function render() {\n return /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxs)(\"div\", {\n className: \"sidebar\",\n children: [this.topPanelJSX(), this.downloadsPanelJSX(), this.sharingPanelJSX(), /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)(\"div\", {\n className: \"referral-panel\",\n children: /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxs)(\"div\", {\n className: \"section-header-sidebar\",\n children: [/*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)(\"h4\", {\n children: \"Recommend SequenceServer\"\n }), /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)(\"p\", {\n children: /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)(\"a\", {\n href: \"https://sequenceserver.com/referral-program\",\n target: \"_blank\",\n children: \"Earn up to $100 per signup\"\n })\n })]\n })\n })]\n });\n }\n }]);\n}(react__WEBPACK_IMPORTED_MODULE_0__.Component);\n\n\n//# sourceURL=webpack://SequenceServer/./public/js/sidebar.js?");
|
305
|
+
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (/* binding */ _default)\n/* harmony export */ });\n/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ \"./node_modules/react/index.js\");\n/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);\n/* harmony import */ var underscore__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! underscore */ \"./node_modules/underscore/modules/index-all.js\");\n/* harmony import */ var _download_fasta__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./download_fasta */ \"./public/js/download_fasta.js\");\n/* harmony import */ var _mailto__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./mailto */ \"./public/js/mailto.js\");\n/* harmony import */ var _cloud_share_modal__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./cloud_share_modal */ \"./public/js/cloud_share_modal.js\");\n/* harmony import */ var download_links__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! download_links */ \"./public/js/null_plugins/download_links.js\");\n/* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! react/jsx-runtime */ \"./node_modules/react/jsx-runtime.js\");\n/* provided dependency */ var $ = __webpack_require__(/*! jquery */ \"./node_modules/jquery/dist/jquery.js\");\nfunction _typeof(obj) { \"@babel/helpers - typeof\"; return _typeof = \"function\" == typeof Symbol && \"symbol\" == typeof Symbol.iterator ? function (obj) { return typeof obj; } : function (obj) { return obj && \"function\" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? \"symbol\" : typeof obj; }, _typeof(obj); }\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\nfunction _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }\nfunction _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, \"prototype\", { writable: false }); return Constructor; }\nfunction _callSuper(_this, derived, args) {\n function isNativeReflectConstruct() {\n if (typeof Reflect === \"undefined\" || !Reflect.construct) return false;\n if (Reflect.construct.sham) return false;\n if (typeof Proxy === \"function\") return true;\n try {\n return !Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {}));\n } catch (e) {\n return false;\n }\n }\n derived = _getPrototypeOf(derived);\n return _possibleConstructorReturn(_this, isNativeReflectConstruct() ? Reflect.construct(derived, args || [], _getPrototypeOf(_this).constructor) : derived.apply(_this, args));\n}\nfunction _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === \"object\" || typeof call === \"function\")) { return call; } else if (call !== void 0) { throw new TypeError(\"Derived constructors may only return object or undefined\"); } return _assertThisInitialized(self); }\nfunction _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError(\"this hasn't been initialised - super() hasn't been called\"); } return self; }\nfunction _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }\nfunction _inherits(subClass, superClass) { if (typeof superClass !== \"function\" && superClass !== null) { throw new TypeError(\"Super expression must either be null or a function\"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); Object.defineProperty(subClass, \"prototype\", { writable: false }); if (superClass) _setPrototypeOf(subClass, superClass); }\nfunction _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }\n\n\n\n\n\n\n/**\n * checks whether code is being run by jest\n */\n// eslint-disable-next-line no-undef\n\nvar isTestMode = function isTestMode() {\n return ({}).JEST_WORKER_ID !== undefined || \"development\" === 'test';\n};\n/**\n * Renders links for downloading hit information in different formats.\n * Renders links for navigating to each query.\n */\nvar _default = /*#__PURE__*/function (_Component) {\n function _default(props) {\n var _this2;\n _classCallCheck(this, _default);\n _this2 = _callSuper(this, _default, [props]);\n _this2.downloadFastaOfAll = _this2.downloadFastaOfAll.bind(_this2);\n _this2.downloadFastaOfSelected = _this2.downloadFastaOfSelected.bind(_this2);\n _this2.topPanelJSX = _this2.topPanelJSX.bind(_this2);\n _this2.summaryString = _this2.summaryString.bind(_this2);\n _this2.indexJSX = _this2.indexJSX.bind(_this2);\n _this2.downloadsPanelJSX = _this2.downloadsPanelJSX.bind(_this2);\n _this2.handleQueryIndexChange = _this2.handleQueryIndexChange.bind(_this2);\n _this2.isElementInViewPort = _this2.isElementInViewPort.bind(_this2);\n _this2.setVisibleQueryIndex = _this2.setVisibleQueryIndex.bind(_this2);\n _this2.debounceScrolling = _this2.debounceScrolling.bind(_this2);\n _this2.scrollListener = _this2.scrollListener.bind(_this2);\n _this2.copyURL = _this2.copyURL.bind(_this2);\n _this2.shareCloudInit = _this2.shareCloudInit.bind(_this2);\n _this2.sharingPanelJSX = _this2.sharingPanelJSX.bind(_this2);\n _this2.timeout = null;\n _this2.queryElems = [];\n _this2.state = {\n queryIndex: 1\n };\n return _this2;\n }\n _inherits(_default, _Component);\n return _createClass(_default, [{\n key: \"componentDidMount\",\n value: function componentDidMount() {\n /**\n * Fixes tooltips in the sidebar, allows tooltip display on click\n */\n $(function () {\n $('.sidebar [data-toggle=\"tooltip\"]').tooltip({\n placement: 'right'\n });\n $('#copyURL').tooltip({\n title: 'Copied!',\n trigger: 'click',\n placement: 'right',\n delay: 0\n });\n });\n\n //keep track of the current queryIndex so it doesn't get lost on page reload\n var urlMatch = window.location.href.match(/#Query_(\\d+)/);\n if (urlMatch && urlMatch.length > 1) {\n var queryNumber = +urlMatch[1];\n var index = this.props.data.queries.findIndex(function (query) {\n return query.number === queryNumber;\n });\n this.setState({\n queryIndex: index + 1\n });\n }\n window.addEventListener('scroll', this.scrollListener);\n $('a[href^=\"#Query_\"]').on('click', this.animateAnchorElements);\n }\n }, {\n key: \"componentWillUnmount\",\n value: function componentWillUnmount() {\n window.removeEventListener('scroll', this.scrollListener);\n }\n }, {\n key: \"componentDidUpdate\",\n value: function componentDidUpdate(prevProps) {\n if (this.props.allQueriesLoaded && !prevProps.allQueriesLoaded) {\n /**\n * storing all query elements in this variable once they all become available so we don't have to fetch them all over again\n */\n this.queryElems = Array.from(document.querySelectorAll('.resultn'));\n }\n }\n\n /**\n * to avoid unnecessary computations, we debounce the scroll listener so it only fires after user has stopped scrolling for some milliseconds\n */\n }, {\n key: \"scrollListener\",\n value: function scrollListener() {\n this.debounceScrolling(this.setVisibleQueryIndex, 500);\n }\n }, {\n key: \"debounceScrolling\",\n value: function debounceScrolling(callback, timer) {\n if (this.timeout) {\n clearTimeout(this.timeout);\n }\n this.timeout = setTimeout(callback, timer);\n }\n\n /**\n * This method makes the page aware of what query is visible so that clicking previous / next button at any point\n * navigates to the proper query\n */\n }, {\n key: \"setVisibleQueryIndex\",\n value: function setVisibleQueryIndex() {\n var queryElems = this.queryElems.length ? this.queryElems : Array.from(document.querySelectorAll('.resultn'));\n var hits = Array.from(document.querySelectorAll('.hit[id^=Query_]'));\n // get the first visible element and marks it as the current query\n var topmostEl = queryElems.find(this.isElementInViewPort) || hits.find(this.isElementInViewPort);\n if (topmostEl) {\n var queryIndex = Number(topmostEl.id.match(/Query_(\\d+)/)[1]);\n var hash = \"#Query_\".concat(queryIndex);\n // if we can guarantee that the browser can handle change in url hash without the page jumping,\n // then we update the url hash after scroll. else, hash is only updated on click of next or prev button\n if (window.history.pushState) {\n window.history.pushState(null, null, hash);\n }\n this.setState({\n queryIndex: queryIndex\n });\n }\n }\n }, {\n key: \"animateAnchorElements\",\n value: function animateAnchorElements(e) {\n // allow normal behavior in test mode to prevent warnings or errors from jquery\n if (isTestMode()) return;\n e.preventDefault();\n $('html, body').animate({\n scrollTop: $(this.hash).offset().top\n }, 300);\n if (window.history.pushState) {\n window.history.pushState(null, null, this.hash);\n } else {\n window.location.hash = this.hash;\n }\n }\n }, {\n key: \"isElementInViewPort\",\n value: function isElementInViewPort(elem) {\n var _elem$getBoundingClie = elem.getBoundingClientRect(),\n top = _elem$getBoundingClie.top,\n left = _elem$getBoundingClie.left,\n right = _elem$getBoundingClie.right,\n bottom = _elem$getBoundingClie.bottom;\n return top >= 0 && left >= 0 && bottom <= (window.innerHeight || document.documentElement.clientHeight) && right <= (window.innerWidth || document.documentElement.clientWidth);\n }\n /**\n * Clear sessionStorage - useful to initiate a new search in the same tab.\n * Passing sessionStorage.clear directly as onclick callback didn't work\n * (on macOS Chrome).\n */\n }, {\n key: \"clearSession\",\n value: function clearSession() {\n sessionStorage.clear();\n }\n /**\n *\n * handle next and previous query button clicks\n */\n }, {\n key: \"handleQueryIndexChange\",\n value: function handleQueryIndexChange(nextQuery) {\n if (nextQuery < 1 || nextQuery > this.props.data.queries.length) return;\n var anchorEl = document.createElement('a');\n //indexing at [nextQuery - 1] because array is 0-indexed\n anchorEl.setAttribute('href', '#Query_' + this.props.data.queries[nextQuery - 1].number);\n anchorEl.setAttribute('hidden', true);\n document.body.appendChild(anchorEl);\n // add smooth scrolling animation with jquery\n $(anchorEl).on('click', this.animateAnchorElements);\n anchorEl.click();\n document.body.removeChild(anchorEl);\n this.setState({\n queryIndex: nextQuery\n });\n }\n /**\n * Event-handler for downloading fasta of all hits.\n */\n }, {\n key: \"downloadFastaOfAll\",\n value: function downloadFastaOfAll() {\n var sequence_ids = [];\n this.props.data.queries.forEach(function (query) {\n return query.hits.forEach(function (hit) {\n return sequence_ids.push(hit.id);\n });\n });\n var database_ids = this.props.data.querydb.map(function (querydb) {\n return querydb.id;\n });\n (0,_download_fasta__WEBPACK_IMPORTED_MODULE_2__[\"default\"])(sequence_ids, database_ids);\n return false;\n }\n\n /**\n * Handles downloading fasta of selected hits.\n */\n }, {\n key: \"downloadFastaOfSelected\",\n value: function downloadFastaOfSelected() {\n var sequence_ids = $('.hit-links :checkbox:checked').map(function () {\n return this.value;\n }).get();\n if (sequence_ids.length === 0) {\n return false;\n }\n var database_ids = underscore__WEBPACK_IMPORTED_MODULE_1__[\"default\"].map(this.props.data.querydb, underscore__WEBPACK_IMPORTED_MODULE_1__[\"default\"].iteratee('id'));\n (0,_download_fasta__WEBPACK_IMPORTED_MODULE_2__[\"default\"])(sequence_ids, database_ids);\n return false;\n }\n\n /**\n * Handles copying the URL into the user's clipboard. Modified from: https://stackoverflow.com/a/49618964/18117380\n * Hides the 'Copied!' tooltip after 3 seconds\n */\n }, {\n key: \"copyURL\",\n value: function copyURL() {\n var element = document.createElement('input');\n var url = window.location.href;\n document.body.appendChild(element);\n element.value = url;\n element.select();\n document.execCommand('copy');\n document.body.removeChild(element);\n setTimeout(function () {\n $('#copyURL')._tooltip('hide');\n }, 3000);\n }\n }, {\n key: \"shareCloudInit\",\n value: function shareCloudInit() {\n this.refs.cloudShareModal.show();\n }\n }, {\n key: \"topPanelJSX\",\n value: function topPanelJSX() {\n var path = location.pathname.split('/');\n // Get job id.\n var job_id = path.pop();\n // Deriving rootURL this way is required for subURI deployments\n // - we cannot just send to '/'.\n var rootURL = path.join('/');\n return /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxs)(\"div\", {\n className: \"sidebar-top-panel\",\n children: [/*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)(\"div\", {\n className: \"section-header-sidebar\",\n children: /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)(\"h4\", {\n children: this.summaryString()\n })\n }), this.props.data.queries.length > 12 && this.queryIndexButtons(), /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxs)(\"div\", {\n children: [/*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxs)(\"a\", {\n href: \"\".concat(rootURL, \"/?job_id=\").concat(job_id),\n children: [/*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)(\"i\", {\n className: \"fa fa-pencil\"\n }), \" Edit search\"]\n }), /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)(\"span\", {\n className: \"line\",\n children: \"|\"\n }), /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxs)(\"a\", {\n href: \"\".concat(rootURL, \"/\"),\n onClick: this.clearSession,\n children: [/*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)(\"i\", {\n className: \"fa fa-file-o\"\n }), \" New search\"]\n })]\n }), this.props.shouldShowIndex && this.indexJSX()]\n });\n }\n }, {\n key: \"summaryString\",\n value: function summaryString() {\n var program = this.props.data.program;\n var numqueries = this.props.data.queries.length;\n var numquerydb = this.props.data.querydb.length;\n return program.toUpperCase() + ': ' + numqueries + ' ' + (numqueries > 1 ? 'queries' : 'query') + ', ' + numquerydb + ' ' + (numquerydb > 1 ? 'databases' : 'database');\n }\n }, {\n key: \"queryIndexButtons\",\n value: function queryIndexButtons() {\n var _this3 = this;\n var buttonStyle = {\n outline: 'none',\n border: 'none',\n background: 'none'\n };\n var buttonClasses = 'btn-link nowrap-ellipsis hover-bold';\n var handlePreviousBtnClick = function handlePreviousBtnClick() {\n return _this3.handleQueryIndexChange(_this3.state.queryIndex - 1);\n };\n var handleNextBtnClick = function handleNextBtnClick() {\n return _this3.handleQueryIndexChange(_this3.state.queryIndex + 1);\n };\n\n // eslint-disable-next-line no-unused-vars\n var NavButton = function NavButton(_ref) {\n var text = _ref.text,\n onClick = _ref.onClick;\n return /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)(\"button\", {\n className: buttonClasses,\n onClick: onClick,\n style: buttonStyle,\n children: text\n });\n };\n return /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxs)(\"div\", {\n style: {\n display: 'flex',\n width: '100%',\n margin: '7px 0'\n },\n children: [this.state.queryIndex > 1 && /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)(NavButton, {\n text: \"Previous Query\",\n onClick: handlePreviousBtnClick\n }), this.state.queryIndex > 1 && this.state.queryIndex < this.props.data.queries.length && /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)(\"span\", {\n className: \"line\",\n children: \"|\"\n }), this.state.queryIndex < this.props.data.queries.length && /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)(NavButton, {\n onClick: handleNextBtnClick,\n text: \"Next Query\"\n })]\n });\n }\n }, {\n key: \"indexJSX\",\n value: function indexJSX() {\n return /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxs)(\"ul\", {\n className: \"nav hover-reset active-bold\",\n children: [\" \", underscore__WEBPACK_IMPORTED_MODULE_1__[\"default\"].map(this.props.data.queries, function (query) {\n return /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)(\"li\", {\n children: /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)(\"a\", {\n className: \"btn-link nowrap-ellipsis hover-bold\",\n title: 'Query= ' + query.id + ' ' + query.title,\n href: '#Query_' + query.number,\n children: 'Query= ' + query.id\n })\n }, 'Side_bar_' + query.id);\n })]\n });\n }\n }, {\n key: \"downloadsPanelJSX\",\n value: function downloadsPanelJSX() {\n return /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxs)(\"div\", {\n className: \"downloads\",\n children: [/*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)(\"div\", {\n className: \"section-header-sidebar\",\n children: /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)(\"h4\", {\n children: \"Download FASTA, XML, TSV\"\n })\n }), /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxs)(\"ul\", {\n className: \"nav\",\n children: [!(this.props.data.imported_xml || this.props.data.non_parse_seqids) && /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)(\"li\", {\n children: /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)(\"a\", {\n href: \"#\",\n className: \"btn-link download-fasta-of-all \".concat(!this.props.atLeastOneHit && 'disabled'),\n onClick: this.downloadFastaOfAll,\n children: \"FASTA of all hits\"\n })\n }), !(this.props.data.imported_xml || this.props.data.non_parse_seqids) && /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)(\"li\", {\n children: /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxs)(\"a\", {\n href: \"#\",\n className: \"btn-link download-fasta-of-selected disabled\",\n onClick: this.downloadFastaOfSelected,\n children: [\"FASTA of \", /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)(\"span\", {\n className: \"text-bold\"\n }), \" selected hit(s)\"]\n })\n }), /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)(\"li\", {\n children: /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)(\"a\", {\n href: \"#\",\n className: \"btn-link download-alignment-of-all \".concat(!this.props.atLeastOneHit && 'disabled'),\n children: \"Alignment of all hits\"\n })\n }), /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)(\"li\", {\n children: /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxs)(\"a\", {\n href: \"#\",\n className: \"btn-link download-alignment-of-selected disabled\",\n children: [\"Alignment of \", /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)(\"span\", {\n className: \"text-bold\"\n }), \" selected hit(s)\"]\n })\n }), !this.props.data.imported_xml && /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)(\"li\", {\n children: /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)(\"a\", {\n className: \"btn-link download\",\n \"data-toggle\": \"tooltip\",\n title: \"15 columns: query and subject ID; scientific name, alignment length, mismatches, gaps, identity, start and end coordinates, e value, bitscore, query coverage per subject and per HSP.\",\n href: 'download/' + this.props.data.search_id + '.std_tsv',\n children: \"Standard tabular report\"\n })\n }), !this.props.data.imported_xml && /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)(\"li\", {\n children: /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)(\"a\", {\n className: \"btn-link download\",\n \"data-toggle\": \"tooltip\",\n title: \"44 columns: query and subject ID, GI, accessions, and length; alignment details; taxonomy details of subject sequence(s) and query coverage per subject and per HSP.\",\n href: 'download/' + this.props.data.search_id + '.full_tsv',\n children: \"Full tabular report\"\n })\n }), !this.props.data.imported_xml && /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)(\"li\", {\n children: /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)(\"a\", {\n className: \"btn-link download\",\n \"data-toggle\": \"tooltip\",\n title: \"Results in XML format.\",\n href: 'download/' + this.props.data.search_id + '.xml',\n children: \"Full XML report\"\n })\n }), !this.props.data.imported_xml && /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)(\"li\", {\n children: /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)(\"a\", {\n className: \"btn-link download\",\n \"data-toggle\": \"tooltip\",\n title: \"Results in pairwise format.\",\n href: 'download/' + this.props.data.search_id + '.pairwise',\n children: \"Full Pairwise report\"\n })\n }), /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)(download_links__WEBPACK_IMPORTED_MODULE_5__[\"default\"], {\n imported_xml: this.props.data.imported_xml,\n search_id: this.props.data.search_id\n })]\n })]\n });\n }\n }, {\n key: \"sharingPanelJSX\",\n value: function sharingPanelJSX() {\n return /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxs)(\"div\", {\n className: \"sharing-panel\",\n children: [/*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)(\"div\", {\n className: \"section-header-sidebar\",\n children: /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)(\"h4\", {\n children: \"Share results\"\n })\n }), /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxs)(\"ul\", {\n className: \"nav\",\n children: [!this.props.cloudSharingEnabled && /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)(\"li\", {\n children: /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxs)(\"a\", {\n id: \"copyURL\",\n className: \"btn-link copy-URL cursor-pointer\",\n \"data-toggle\": \"tooltip\",\n onClick: this.copyURL,\n children: [/*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)(\"i\", {\n className: \"fa fa-copy\"\n }), \" Copy URL to clipboard\"]\n })\n }), !this.props.cloudSharingEnabled && /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)(\"li\", {\n children: /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxs)(\"a\", {\n id: \"sendEmail\",\n className: \"btn-link email-URL cursor-pointer\",\n \"data-toggle\": \"tooltip\",\n title: \"Send by email\",\n href: (0,_mailto__WEBPACK_IMPORTED_MODULE_3__[\"default\"])(this.props.data.querydb, this.props.data.program, this.props.data.queries.length, window.location.href),\n target: \"_blank\",\n rel: \"noopener noreferrer\",\n children: [/*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)(\"i\", {\n className: \"fa fa-envelope\"\n }), \" Send by email\"]\n })\n }), this.props.cloudSharingEnabled && /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)(\"li\", {\n children: /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxs)(\"button\", {\n className: \"btn-link cloud-Post cursor-pointer\",\n \"data-toggle\": \"tooltip\",\n title: \"Upload results to SequenceServer Cloud where it will become accessable to everyone who has a link.\",\n onClick: this.shareCloudInit,\n children: [/*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)(\"i\", {\n className: \"fa fa-cloud\"\n }), \" Share to cloud\"]\n })\n })]\n }), /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)(_cloud_share_modal__WEBPACK_IMPORTED_MODULE_4__[\"default\"], {\n ref: \"cloudShareModal\",\n querydb: this.props.data.querydb,\n program: this.props.data.program,\n queryLength: this.props.data.queries.length\n })]\n });\n }\n }, {\n key: \"render\",\n value: function render() {\n return /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxs)(\"div\", {\n className: \"sidebar\",\n children: [this.topPanelJSX(), this.downloadsPanelJSX(), this.sharingPanelJSX(), /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)(\"div\", {\n className: \"referral-panel\",\n children: /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxs)(\"div\", {\n className: \"section-header-sidebar\",\n children: [/*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)(\"h4\", {\n children: \"Recommend SequenceServer\"\n }), /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)(\"p\", {\n children: /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)(\"a\", {\n href: \"https://sequenceserver.com/referral-program\",\n target: \"_blank\",\n children: \"Earn up to $100 per signup\"\n })\n })]\n })\n })]\n });\n }\n }]);\n}(react__WEBPACK_IMPORTED_MODULE_0__.Component);\n\n\n//# sourceURL=webpack://SequenceServer/./public/js/sidebar.js?");
|
306
306
|
|
307
307
|
/***/ }),
|
308
308
|
|
@@ -82,7 +82,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpac
|
|
82
82
|
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
|
83
83
|
|
84
84
|
"use strict";
|
85
|
-
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ Form: () => (/* binding */ Form)\n/* harmony export */ });\n/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ \"./node_modules/react/index.js\");\n/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);\n/* harmony import */ var _search_button__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./search_button */ \"./public/js/search_button.js\");\n/* harmony import */ var _query__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./query */ \"./public/js/query.js\");\n/* harmony import */ var _databases_tree__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./databases_tree */ \"./public/js/databases_tree.js\");\n/* harmony import */ var _databases__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./databases */ \"./public/js/databases.js\");\n/* harmony import */ var underscore__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! underscore */ \"./node_modules/underscore/modules/index-all.js\");\n/* harmony import */ var options__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! options */ \"./public/js/null_plugins/options.js\");\n/* harmony import */ var query_stats__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! query_stats */ \"./public/js/null_plugins/query_stats.js\");\n/* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! react/jsx-runtime */ \"./node_modules/react/jsx-runtime.js\");\n/* provided dependency */ var $ = __webpack_require__(/*! jquery */ \"./node_modules/jquery/dist/jquery.js\");\nfunction _typeof(obj) { \"@babel/helpers - typeof\"; return _typeof = \"function\" == typeof Symbol && \"symbol\" == typeof Symbol.iterator ? function (obj) { return typeof obj; } : function (obj) { return obj && \"function\" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? \"symbol\" : typeof obj; }, _typeof(obj); }\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\nfunction _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }\nfunction _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, \"prototype\", { writable: false }); return Constructor; }\nfunction _callSuper(_this, derived, args) {\n function isNativeReflectConstruct() {\n if (typeof Reflect === \"undefined\" || !Reflect.construct) return false;\n if (Reflect.construct.sham) return false;\n if (typeof Proxy === \"function\") return true;\n try {\n return !Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {}));\n } catch (e) {\n return false;\n }\n }\n derived = _getPrototypeOf(derived);\n return _possibleConstructorReturn(_this, isNativeReflectConstruct() ? Reflect.construct(derived, args || [], _getPrototypeOf(_this).constructor) : derived.apply(_this, args));\n}\nfunction _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === \"object\" || typeof call === \"function\")) { return call; } else if (call !== void 0) { throw new TypeError(\"Derived constructors may only return object or undefined\"); } return _assertThisInitialized(self); }\nfunction _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError(\"this hasn't been initialised - super() hasn't been called\"); } return self; }\nfunction _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }\nfunction _inherits(subClass, superClass) { if (typeof superClass !== \"function\" && superClass !== null) { throw new TypeError(\"Super expression must either be null or a function\"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); Object.defineProperty(subClass, \"prototype\", { writable: false }); if (superClass) _setPrototypeOf(subClass, superClass); }\nfunction _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }\n\n\n\n\n\n\n\n\n\n/**\n * Search form.\n *\n * Top level component that initialises and holds all other components, and\n * facilitates communication between them.\n */\n\nvar Form = /*#__PURE__*/function (_Component) {\n function Form(props) {\n var _this2;\n _classCallCheck(this, Form);\n _this2 = _callSuper(this, Form, [props]);\n _this2.state = {\n databases: [],\n preSelectedDbs: [],\n currentlySelectedDbs: [],\n preDefinedOpts: {},\n tree: {},\n residuesInQuerySequence: 0,\n blastMethod: ''\n };\n _this2.useTreeWidget = _this2.useTreeWidget.bind(_this2);\n _this2.determineBlastMethods = _this2.determineBlastMethods.bind(_this2);\n _this2.handleSequenceTypeChanged = _this2.handleSequenceTypeChanged.bind(_this2);\n _this2.handleSequenceChanged = _this2.handleSequenceChanged.bind(_this2);\n _this2.handleDatabaseTypeChanged = _this2.handleDatabaseTypeChanged.bind(_this2);\n _this2.handleDatabaseSelectionChanged = _this2.handleDatabaseSelectionChanged.bind(_this2);\n _this2.handleAlgoChanged = _this2.handleAlgoChanged.bind(_this2);\n _this2.handleFormSubmission = _this2.handleFormSubmission.bind(_this2);\n _this2.formRef = /*#__PURE__*/(0,react__WEBPACK_IMPORTED_MODULE_0__.createRef)();\n _this2.setButtonState = _this2.setButtonState.bind(_this2);\n return _this2;\n }\n _inherits(Form, _Component);\n return _createClass(Form, [{\n key: \"componentDidMount\",\n value: function componentDidMount() {\n /**\n * Fetch data to initialise the search interface from the server. These\n * include list of databases to search against, advanced options to\n * apply when an algorithm is selected, and a query sequence that\n * the user may want to search in the databases.\n */\n var search = location.search.split(/\\?|&/).filter(Boolean);\n var job_id = sessionStorage.getItem('job_id');\n if (job_id) {\n search.unshift(\"job_id=\".concat(job_id));\n }\n $.getJSON(\"searchdata.json?\".concat(search.join('&')), function (data) {\n /* Update form state (i.e., list of databases and predefined\n * advanced options.\n */\n this.setState({\n tree: data['tree'],\n databases: data['database'],\n preSelectedDbs: data['preSelectedDbs'],\n preDefinedOpts: data['options'],\n blastTaskMap: data['blastTaskMap']\n });\n\n /* Pre-populate the form with server sent query sequences\n * (if any).\n */\n if (data['query']) {\n this.refs.query.value(data['query']);\n }\n setTimeout(function () {\n $('.jstree_div').click();\n }, 1000);\n }.bind(this));\n\n /* Enable submitting form on Cmd+Enter */\n $(document).on('keydown', function (e) {\n var $button = $('#method');\n if (!$button.is(':disabled') && e.ctrlKey && e.key === 'Enter') {\n $button.trigger('click');\n }\n });\n\n // show overlay to create visual feedback on button click\n $('#method').on('click', function () {\n $('#overlay').css('display', 'block');\n });\n }\n }, {\n key: \"useTreeWidget\",\n value: function useTreeWidget() {\n return !underscore__WEBPACK_IMPORTED_MODULE_5__[\"default\"].isEmpty(this.state.tree);\n }\n }, {\n key: \"handleFormSubmission\",\n value: function handleFormSubmission(evt) {\n evt.preventDefault();\n var form = this.formRef.current;\n var formData = new FormData(form);\n formData.append('method', this.refs.button.state.methods[0]);\n fetch(window.location.href, {\n method: 'POST',\n body: formData\n }).then(function (res) {\n //remove overlay when form is submitted\n $('#overlay').css('display', 'none');\n // redirect\n if (res.redirected && res.url) {\n // setTimeout is needed here as a workaround because safari doesnt allow async calling of window.open\n // so setTimeout makes the method get called on the main thread.\n setTimeout(function () {\n window.open(res.url, $('#toggleNewTab').is(':checked') ? '_blank' : '_self');\n }, 0);\n }\n });\n }\n }, {\n key: \"determineBlastMethods\",\n value: function determineBlastMethods() {\n var database_type = this.databaseType;\n var sequence_type = this.sequenceType;\n if (this.refs.query.isEmpty()) {\n return [];\n }\n\n //database type is always known\n switch (database_type) {\n case 'protein':\n switch (sequence_type) {\n case undefined:\n return ['blastp', 'blastx'];\n case 'protein':\n return ['blastp'];\n case 'nucleotide':\n return ['blastx'];\n }\n break;\n case 'nucleotide':\n switch (sequence_type) {\n case undefined:\n return ['tblastn', 'blastn', 'tblastx'];\n case 'protein':\n return ['tblastn'];\n case 'nucleotide':\n return ['blastn', 'tblastx'];\n }\n break;\n }\n return [];\n }\n }, {\n key: \"handleSequenceChanged\",\n value: function handleSequenceChanged(residuesInQuerySequence) {\n if (residuesInQuerySequence !== this.state.residuesInQuerySequence) this.setState({\n residuesInQuerySequence: residuesInQuerySequence\n });\n }\n }, {\n key: \"handleSequenceTypeChanged\",\n value: function handleSequenceTypeChanged(type) {\n this.sequenceType = type;\n this.setButtonState();\n }\n }, {\n key: \"handleDatabaseTypeChanged\",\n value: function handleDatabaseTypeChanged(type) {\n this.databaseType = type;\n this.setButtonState();\n }\n }, {\n key: \"setButtonState\",\n value: function setButtonState() {\n this.refs.button.setState({\n hasQuery: !this.refs.query.isEmpty(),\n hasDatabases: !!this.databaseType,\n methods: this.determineBlastMethods()\n });\n }\n }, {\n key: \"handleDatabaseSelectionChanged\",\n value: function handleDatabaseSelectionChanged(selectedDbs) {\n if (!underscore__WEBPACK_IMPORTED_MODULE_5__[\"default\"].isEqual(selectedDbs, this.state.currentlySelectedDbs)) this.setState({\n currentlySelectedDbs: selectedDbs\n });\n }\n }, {\n key: \"handleAlgoChanged\",\n value: function handleAlgoChanged(algo) {\n if (algo in this.state.preDefinedOpts) {\n this.setState({\n blastMethod: algo\n });\n } else {\n this.setState({\n blastMethod: ''\n });\n }\n }\n }, {\n key: \"residuesInSelectedDbs\",\n value: function residuesInSelectedDbs() {\n return this.state.currentlySelectedDbs.reduce(function (sum, db) {\n return sum + parseInt(db.ncharacters, 10);\n }, 0);\n }\n }, {\n key: \"render\",\n value: function render() {\n return /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxs)(\"div\", {\n children: [/*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_8__.jsx)(\"div\", {\n id: \"overlay\",\n style: {\n position: 'absolute',\n top: 0,\n left: 0,\n width: '100vw',\n height: '100vw',\n background: 'rgba(0, 0, 0, 0.2)',\n display: 'none',\n zIndex: 99\n }\n }), /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxs)(\"div\", {\n className: \"fixed top-0 left-0 w-full max-h-8 px-8\",\n \"data-notifications\": true,\n id: \"notifications\",\n children: [/*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_8__.jsx)(FastqNotification, {}), /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_8__.jsx)(NucleotideNotification, {}), /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_8__.jsx)(ProteinNotification, {}), /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_8__.jsx)(MixedNotification, {})]\n }), /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxs)(\"form\", {\n id: \"blast\",\n ref: this.formRef,\n onSubmit: this.handleFormSubmission,\n children: [/*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxs)(\"div\", {\n className: \"px-4\",\n children: [/*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_8__.jsx)(_query__WEBPACK_IMPORTED_MODULE_2__.SearchQueryWidget, {\n ref: \"query\",\n onSequenceTypeChanged: this.handleSequenceTypeChanged,\n onSequenceChanged: this.handleSequenceChanged\n }), this.useTreeWidget() ? /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_8__.jsx)(_databases_tree__WEBPACK_IMPORTED_MODULE_3__[\"default\"], {\n ref: \"databases\",\n databases: this.state.databases,\n tree: this.state.tree,\n preSelectedDbs: this.state.preSelectedDbs,\n onDatabaseTypeChanged: this.handleDatabaseTypeChanged,\n onDatabaseSelectionChanged: this.handleDatabaseSelectionChanged\n }) : /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_8__.jsx)(_databases__WEBPACK_IMPORTED_MODULE_4__.Databases, {\n ref: \"databases\",\n databases: this.state.databases,\n preSelectedDbs: this.state.preSelectedDbs,\n onDatabaseTypeChanged: this.handleDatabaseTypeChanged,\n onDatabaseSelectionChanged: this.handleDatabaseSelectionChanged\n }), /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_8__.jsx)(options__WEBPACK_IMPORTED_MODULE_6__.Options, {\n blastMethod: this.state.blastMethod,\n predefinedOptions: this.state.preDefinedOpts[this.state.blastMethod] || {},\n blastTasks: (this.state.blastTaskMap || {})[this.state.blastMethod]\n })]\n }), /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_8__.jsx)(\"div\", {\n className: \"py-6\"\n }), \" \", /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxs)(\"div\", {\n className: \"pb-4 pt-2 px-4 sticky bottom-0 md:flex flex-row md:space-x-4 items-center justify-end bg-gradient-to-t to-gray-100/90 from-white/90\",\n children: [/*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_8__.jsx)(query_stats__WEBPACK_IMPORTED_MODULE_7__[\"default\"], {\n residuesInQuerySequence: this.state.residuesInQuerySequence,\n numberOfDatabasesSelected: this.state.currentlySelectedDbs.length,\n residuesInSelectedDbs: this.residuesInSelectedDbs(),\n currentBlastMethod: this.state.blastMethod\n }), /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxs)(\"label\", {\n className: \"block my-4 md:my-2\",\n children: [/*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_8__.jsx)(\"input\", {\n type: \"checkbox\",\n id: \"toggleNewTab\"\n }), \" Open results in new tab\"]\n }), /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_8__.jsx)(_search_button__WEBPACK_IMPORTED_MODULE_1__.SearchButton, {\n ref: \"button\",\n onAlgoChanged: this.handleAlgoChanged\n })]\n })]\n })]\n });\n }\n }]);\n}(react__WEBPACK_IMPORTED_MODULE_0__.Component);\nvar ProteinNotification = /*#__PURE__*/function (_Component2) {\n function ProteinNotification() {\n _classCallCheck(this, ProteinNotification);\n return _callSuper(this, ProteinNotification, arguments);\n }\n _inherits(ProteinNotification, _Component2);\n return _createClass(ProteinNotification, [{\n key: \"render\",\n value: function render() {\n return /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_8__.jsx)(\"div\", {\n \"data-role\": \"notification\",\n id: \"protein-sequence-notification\",\n style: {\n display: 'none'\n },\n children: /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_8__.jsx)(\"div\", {\n className: \"bg-blue-100 border rounded border-blue-800 px-4 py-2 my-2\",\n children: \"Detected: amino-acid sequence(s).\"\n })\n });\n }\n }]);\n}(react__WEBPACK_IMPORTED_MODULE_0__.Component);\nvar NucleotideNotification = /*#__PURE__*/function (_Component3) {\n function NucleotideNotification() {\n _classCallCheck(this, NucleotideNotification);\n return _callSuper(this, NucleotideNotification, arguments);\n }\n _inherits(NucleotideNotification, _Component3);\n return _createClass(NucleotideNotification, [{\n key: \"render\",\n value: function render() {\n return /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_8__.jsx)(\"div\", {\n \"data-role\": \"notification\",\n id: \"nucleotide-sequence-notification\",\n style: {\n display: 'none'\n },\n children: /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_8__.jsx)(\"div\", {\n className: \"bg-blue-100 border rounded border-blue-800 px-4 py-2 my-2\",\n children: \"Detected: nucleotide sequence(s).\"\n })\n });\n }\n }]);\n}(react__WEBPACK_IMPORTED_MODULE_0__.Component);\nvar FastqNotification = /*#__PURE__*/function (_Component4) {\n function FastqNotification() {\n _classCallCheck(this, FastqNotification);\n return _callSuper(this, FastqNotification, arguments);\n }\n _inherits(FastqNotification, _Component4);\n return _createClass(FastqNotification, [{\n key: \"render\",\n value: function render() {\n return /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_8__.jsx)(\"div\", {\n \"data-role\": \"notification\",\n id: \"fastq-sequence-notification\",\n style: {\n display: 'none'\n },\n children: /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_8__.jsx)(\"div\", {\n className: \"bg-blue-100 border rounded border-blue-800 px-4 py-2 my-2\",\n children: \"Detected FASTQ and automatically converted to FASTA.\"\n })\n });\n }\n }]);\n}(react__WEBPACK_IMPORTED_MODULE_0__.Component);\nvar MixedNotification = /*#__PURE__*/function (_Component5) {\n function MixedNotification() {\n _classCallCheck(this, MixedNotification);\n return _callSuper(this, MixedNotification, arguments);\n }\n _inherits(MixedNotification, _Component5);\n return _createClass(MixedNotification, [{\n key: \"render\",\n value: function render() {\n return /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_8__.jsx)(\"div\", {\n \"data-role\": \"notification\",\n id: \"mixed-sequence-notification\",\n style: {\n display: 'none'\n },\n children: /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_8__.jsx)(\"div\", {\n className: \"alert-danger col-md-10 col-md-offset-1\",\n children: \"Error: mixed nucleotide and amino-acid sequences detected.\"\n })\n });\n }\n }]);\n}(react__WEBPACK_IMPORTED_MODULE_0__.Component);\n\n//# sourceURL=webpack://SequenceServer/./public/js/form.js?");
|
85
|
+
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ Form: () => (/* binding */ Form)\n/* harmony export */ });\n/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ \"./node_modules/react/index.js\");\n/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);\n/* harmony import */ var _search_button__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./search_button */ \"./public/js/search_button.js\");\n/* harmony import */ var _query__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./query */ \"./public/js/query.js\");\n/* harmony import */ var _databases_tree__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./databases_tree */ \"./public/js/databases_tree.js\");\n/* harmony import */ var _databases__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./databases */ \"./public/js/databases.js\");\n/* harmony import */ var underscore__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! underscore */ \"./node_modules/underscore/modules/index-all.js\");\n/* harmony import */ var options__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! options */ \"./public/js/null_plugins/options.js\");\n/* harmony import */ var query_stats__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! query_stats */ \"./public/js/null_plugins/query_stats.js\");\n/* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! react/jsx-runtime */ \"./node_modules/react/jsx-runtime.js\");\n/* provided dependency */ var $ = __webpack_require__(/*! jquery */ \"./node_modules/jquery/dist/jquery.js\");\nfunction _typeof(obj) { \"@babel/helpers - typeof\"; return _typeof = \"function\" == typeof Symbol && \"symbol\" == typeof Symbol.iterator ? function (obj) { return typeof obj; } : function (obj) { return obj && \"function\" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? \"symbol\" : typeof obj; }, _typeof(obj); }\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\nfunction _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }\nfunction _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, \"prototype\", { writable: false }); return Constructor; }\nfunction _callSuper(_this, derived, args) {\n function isNativeReflectConstruct() {\n if (typeof Reflect === \"undefined\" || !Reflect.construct) return false;\n if (Reflect.construct.sham) return false;\n if (typeof Proxy === \"function\") return true;\n try {\n return !Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {}));\n } catch (e) {\n return false;\n }\n }\n derived = _getPrototypeOf(derived);\n return _possibleConstructorReturn(_this, isNativeReflectConstruct() ? Reflect.construct(derived, args || [], _getPrototypeOf(_this).constructor) : derived.apply(_this, args));\n}\nfunction _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === \"object\" || typeof call === \"function\")) { return call; } else if (call !== void 0) { throw new TypeError(\"Derived constructors may only return object or undefined\"); } return _assertThisInitialized(self); }\nfunction _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError(\"this hasn't been initialised - super() hasn't been called\"); } return self; }\nfunction _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }\nfunction _inherits(subClass, superClass) { if (typeof superClass !== \"function\" && superClass !== null) { throw new TypeError(\"Super expression must either be null or a function\"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); Object.defineProperty(subClass, \"prototype\", { writable: false }); if (superClass) _setPrototypeOf(subClass, superClass); }\nfunction _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }\n\n\n\n\n\n\n\n\n\n/**\n * Search form.\n *\n * Top level component that initialises and holds all other components, and\n * facilitates communication between them.\n */\n\nvar Form = /*#__PURE__*/function (_Component) {\n function Form(props) {\n var _this2;\n _classCallCheck(this, Form);\n _this2 = _callSuper(this, Form, [props]);\n _this2.state = {\n databases: [],\n preSelectedDbs: [],\n currentlySelectedDbs: [],\n preDefinedOpts: {},\n tree: {},\n residuesInQuerySequence: 0,\n blastMethod: ''\n };\n _this2.useTreeWidget = _this2.useTreeWidget.bind(_this2);\n _this2.determineBlastMethods = _this2.determineBlastMethods.bind(_this2);\n _this2.handleSequenceTypeChanged = _this2.handleSequenceTypeChanged.bind(_this2);\n _this2.handleSequenceChanged = _this2.handleSequenceChanged.bind(_this2);\n _this2.handleDatabaseTypeChanged = _this2.handleDatabaseTypeChanged.bind(_this2);\n _this2.handleDatabaseSelectionChanged = _this2.handleDatabaseSelectionChanged.bind(_this2);\n _this2.handleAlgoChanged = _this2.handleAlgoChanged.bind(_this2);\n _this2.handleFormSubmission = _this2.handleFormSubmission.bind(_this2);\n _this2.formRef = /*#__PURE__*/(0,react__WEBPACK_IMPORTED_MODULE_0__.createRef)();\n _this2.setButtonState = _this2.setButtonState.bind(_this2);\n return _this2;\n }\n _inherits(Form, _Component);\n return _createClass(Form, [{\n key: \"componentDidMount\",\n value: function componentDidMount() {\n /**\n * Fetch data to initialise the search interface from the server. These\n * include list of databases to search against, advanced options to\n * apply when an algorithm is selected, and a query sequence that\n * the user may want to search in the databases.\n */\n var search = location.search.split(/\\?|&/).filter(Boolean);\n var job_id = sessionStorage.getItem('job_id');\n if (job_id) {\n search.unshift(\"job_id=\".concat(job_id));\n }\n $.getJSON(\"searchdata.json?\".concat(search.join('&')), function (data) {\n /* Update form state (i.e., list of databases and predefined\n * advanced options.\n */\n this.setState({\n tree: data['tree'],\n databases: data['database'],\n preSelectedDbs: data['preSelectedDbs'],\n preDefinedOpts: data['options'],\n blastTaskMap: data['blastTaskMap']\n });\n\n /* Pre-populate the form with server sent query sequences\n * (if any).\n */\n if (data['query']) {\n this.refs.query.value(data['query']);\n }\n setTimeout(function () {\n $('.jstree_div').click();\n }, 1000);\n }.bind(this));\n\n /* Enable submitting form on Cmd+Enter */\n $(document).on('keydown', function (e) {\n var $button = $('#method');\n if (!$button.is(':disabled') && e.ctrlKey && e.key === 'Enter') {\n $button.trigger('click');\n }\n });\n\n // show overlay to create visual feedback on button click\n $('#method').on('click', function () {\n $('#overlay').css('display', 'block');\n });\n }\n }, {\n key: \"useTreeWidget\",\n value: function useTreeWidget() {\n return !underscore__WEBPACK_IMPORTED_MODULE_5__[\"default\"].isEmpty(this.state.tree);\n }\n }, {\n key: \"handleFormSubmission\",\n value: function handleFormSubmission(evt) {\n evt.preventDefault();\n var form = this.formRef.current;\n var formData = new FormData(form);\n formData.append('method', this.refs.button.state.methods[0]);\n fetch(window.location.href, {\n method: 'POST',\n body: formData\n }).then(function (res) {\n //remove overlay when form is submitted\n $('#overlay').css('display', 'none');\n // redirect\n if (res.redirected && res.url) {\n // setTimeout is needed here as a workaround because safari doesnt allow async calling of window.open\n // so setTimeout makes the method get called on the main thread.\n setTimeout(function () {\n window.open(res.url, $('#toggleNewTab').is(':checked') ? '_blank' : '_self');\n }, 0);\n }\n });\n }\n }, {\n key: \"determineBlastMethods\",\n value: function determineBlastMethods() {\n var database_type = this.databaseType;\n var sequence_type = this.sequenceType;\n if (this.refs.query.isEmpty()) {\n return [];\n }\n\n //database type is always known\n switch (database_type) {\n case 'protein':\n switch (sequence_type) {\n case undefined:\n return ['blastp', 'blastx'];\n case 'protein':\n return ['blastp'];\n case 'nucleotide':\n return ['blastx'];\n }\n break;\n case 'nucleotide':\n switch (sequence_type) {\n case undefined:\n return ['tblastn', 'blastn', 'tblastx'];\n case 'protein':\n return ['tblastn'];\n case 'nucleotide':\n return ['blastn', 'tblastx'];\n }\n break;\n }\n return [];\n }\n }, {\n key: \"handleSequenceChanged\",\n value: function handleSequenceChanged(residuesInQuerySequence) {\n if (residuesInQuerySequence !== this.state.residuesInQuerySequence) this.setState({\n residuesInQuerySequence: residuesInQuerySequence\n });\n }\n }, {\n key: \"handleSequenceTypeChanged\",\n value: function handleSequenceTypeChanged(type) {\n this.sequenceType = type;\n this.setButtonState();\n }\n }, {\n key: \"handleDatabaseTypeChanged\",\n value: function handleDatabaseTypeChanged(type) {\n this.databaseType = type;\n this.setButtonState();\n }\n }, {\n key: \"setButtonState\",\n value: function setButtonState() {\n this.refs.button.setState({\n hasQuery: !this.refs.query.isEmpty(),\n hasDatabases: !!this.databaseType,\n methods: this.determineBlastMethods()\n });\n }\n }, {\n key: \"handleDatabaseSelectionChanged\",\n value: function handleDatabaseSelectionChanged(selectedDbs) {\n if (!underscore__WEBPACK_IMPORTED_MODULE_5__[\"default\"].isEqual(selectedDbs, this.state.currentlySelectedDbs)) this.setState({\n currentlySelectedDbs: selectedDbs\n });\n }\n }, {\n key: \"handleAlgoChanged\",\n value: function handleAlgoChanged(algo) {\n if (algo in this.state.preDefinedOpts) {\n this.setState({\n blastMethod: algo\n });\n } else {\n this.setState({\n blastMethod: ''\n });\n }\n }\n }, {\n key: \"residuesInSelectedDbs\",\n value: function residuesInSelectedDbs() {\n return this.state.currentlySelectedDbs.reduce(function (sum, db) {\n return sum + parseInt(db.ncharacters, 10);\n }, 0);\n }\n }, {\n key: \"render\",\n value: function render() {\n return /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxs)(\"div\", {\n children: [/*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_8__.jsx)(\"div\", {\n id: \"overlay\",\n style: {\n position: 'absolute',\n top: 0,\n left: 0,\n width: '100vw',\n height: '100vw',\n background: 'rgba(0, 0, 0, 0.2)',\n display: 'none',\n zIndex: 99\n }\n }), /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxs)(\"div\", {\n className: \"fixed top-0 left-0 w-full max-h-8 px-8\",\n \"data-notifications\": true,\n id: \"notifications\",\n children: [/*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_8__.jsx)(FastqNotification, {}), /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_8__.jsx)(NucleotideNotification, {}), /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_8__.jsx)(ProteinNotification, {}), /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_8__.jsx)(MixedNotification, {})]\n }), /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxs)(\"form\", {\n id: \"blast\",\n ref: this.formRef,\n onSubmit: this.handleFormSubmission,\n children: [/*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_8__.jsx)(\"input\", {\n type: \"hidden\",\n name: \"_csrf\",\n value: document.querySelector('meta[name=\"_csrf\"]').content\n }), /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxs)(\"div\", {\n className: \"px-4\",\n children: [/*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_8__.jsx)(_query__WEBPACK_IMPORTED_MODULE_2__.SearchQueryWidget, {\n ref: \"query\",\n onSequenceTypeChanged: this.handleSequenceTypeChanged,\n onSequenceChanged: this.handleSequenceChanged\n }), this.useTreeWidget() ? /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_8__.jsx)(_databases_tree__WEBPACK_IMPORTED_MODULE_3__[\"default\"], {\n ref: \"databases\",\n databases: this.state.databases,\n tree: this.state.tree,\n preSelectedDbs: this.state.preSelectedDbs,\n onDatabaseTypeChanged: this.handleDatabaseTypeChanged,\n onDatabaseSelectionChanged: this.handleDatabaseSelectionChanged\n }) : /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_8__.jsx)(_databases__WEBPACK_IMPORTED_MODULE_4__.Databases, {\n ref: \"databases\",\n databases: this.state.databases,\n preSelectedDbs: this.state.preSelectedDbs,\n onDatabaseTypeChanged: this.handleDatabaseTypeChanged,\n onDatabaseSelectionChanged: this.handleDatabaseSelectionChanged\n }), /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_8__.jsx)(options__WEBPACK_IMPORTED_MODULE_6__.Options, {\n blastMethod: this.state.blastMethod,\n predefinedOptions: this.state.preDefinedOpts[this.state.blastMethod] || {},\n blastTasks: (this.state.blastTaskMap || {})[this.state.blastMethod]\n })]\n }), /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_8__.jsx)(\"div\", {\n className: \"py-6\"\n }), \" \", /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxs)(\"div\", {\n className: \"pb-4 pt-2 px-4 sticky bottom-0 md:flex flex-row md:space-x-4 items-center justify-end bg-gradient-to-t to-gray-100/90 from-white/90\",\n children: [/*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_8__.jsx)(query_stats__WEBPACK_IMPORTED_MODULE_7__[\"default\"], {\n residuesInQuerySequence: this.state.residuesInQuerySequence,\n numberOfDatabasesSelected: this.state.currentlySelectedDbs.length,\n residuesInSelectedDbs: this.residuesInSelectedDbs(),\n currentBlastMethod: this.state.blastMethod\n }), /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_8__.jsxs)(\"label\", {\n className: \"block my-4 md:my-2\",\n children: [/*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_8__.jsx)(\"input\", {\n type: \"checkbox\",\n id: \"toggleNewTab\"\n }), \" Open results in new tab\"]\n }), /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_8__.jsx)(_search_button__WEBPACK_IMPORTED_MODULE_1__.SearchButton, {\n ref: \"button\",\n onAlgoChanged: this.handleAlgoChanged\n })]\n })]\n })]\n });\n }\n }]);\n}(react__WEBPACK_IMPORTED_MODULE_0__.Component);\nvar ProteinNotification = /*#__PURE__*/function (_Component2) {\n function ProteinNotification() {\n _classCallCheck(this, ProteinNotification);\n return _callSuper(this, ProteinNotification, arguments);\n }\n _inherits(ProteinNotification, _Component2);\n return _createClass(ProteinNotification, [{\n key: \"render\",\n value: function render() {\n return /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_8__.jsx)(\"div\", {\n \"data-role\": \"notification\",\n id: \"protein-sequence-notification\",\n style: {\n display: 'none'\n },\n children: /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_8__.jsx)(\"div\", {\n className: \"bg-blue-100 border rounded border-blue-800 px-4 py-2 my-2\",\n children: \"Detected: amino-acid sequence(s).\"\n })\n });\n }\n }]);\n}(react__WEBPACK_IMPORTED_MODULE_0__.Component);\nvar NucleotideNotification = /*#__PURE__*/function (_Component3) {\n function NucleotideNotification() {\n _classCallCheck(this, NucleotideNotification);\n return _callSuper(this, NucleotideNotification, arguments);\n }\n _inherits(NucleotideNotification, _Component3);\n return _createClass(NucleotideNotification, [{\n key: \"render\",\n value: function render() {\n return /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_8__.jsx)(\"div\", {\n \"data-role\": \"notification\",\n id: \"nucleotide-sequence-notification\",\n style: {\n display: 'none'\n },\n children: /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_8__.jsx)(\"div\", {\n className: \"bg-blue-100 border rounded border-blue-800 px-4 py-2 my-2\",\n children: \"Detected: nucleotide sequence(s).\"\n })\n });\n }\n }]);\n}(react__WEBPACK_IMPORTED_MODULE_0__.Component);\nvar FastqNotification = /*#__PURE__*/function (_Component4) {\n function FastqNotification() {\n _classCallCheck(this, FastqNotification);\n return _callSuper(this, FastqNotification, arguments);\n }\n _inherits(FastqNotification, _Component4);\n return _createClass(FastqNotification, [{\n key: \"render\",\n value: function render() {\n return /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_8__.jsx)(\"div\", {\n \"data-role\": \"notification\",\n id: \"fastq-sequence-notification\",\n style: {\n display: 'none'\n },\n children: /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_8__.jsx)(\"div\", {\n className: \"bg-blue-100 border rounded border-blue-800 px-4 py-2 my-2\",\n children: \"Detected FASTQ and automatically converted to FASTA.\"\n })\n });\n }\n }]);\n}(react__WEBPACK_IMPORTED_MODULE_0__.Component);\nvar MixedNotification = /*#__PURE__*/function (_Component5) {\n function MixedNotification() {\n _classCallCheck(this, MixedNotification);\n return _callSuper(this, MixedNotification, arguments);\n }\n _inherits(MixedNotification, _Component5);\n return _createClass(MixedNotification, [{\n key: \"render\",\n value: function render() {\n return /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_8__.jsx)(\"div\", {\n \"data-role\": \"notification\",\n id: \"mixed-sequence-notification\",\n style: {\n display: 'none'\n },\n children: /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_8__.jsx)(\"div\", {\n className: \"alert-danger col-md-10 col-md-offset-1\",\n children: \"Error: mixed nucleotide and amino-acid sequences detected.\"\n })\n });\n }\n }]);\n}(react__WEBPACK_IMPORTED_MODULE_0__.Component);\n\n//# sourceURL=webpack://SequenceServer/./public/js/form.js?");
|
86
86
|
|
87
87
|
/***/ }),
|
88
88
|
|
data/views/layout.erb
CHANGED
@@ -9,6 +9,7 @@
|
|
9
9
|
<meta name="author" content="Pragmatic Genomics Ltd">
|
10
10
|
<meta name="description" content="Custom BLAST server provided by SequenceServer (https://sequenceserver.com)"/>
|
11
11
|
|
12
|
+
<%= Rack::Csrf.metatag(env) %>
|
12
13
|
<!-- CSS -->
|
13
14
|
<% if settings.production? || settings.test? %>
|
14
15
|
<link rel="stylesheet" media="screen,print" type="text/css" href="css/sequenceserver.min.css?ver=<%= SequenceServer::VERSION %>"/>
|
data/views/search_layout.erb
CHANGED
@@ -6,6 +6,7 @@
|
|
6
6
|
<meta name="author" content="Pragmatic Genomics Limited"/>
|
7
7
|
<meta charset="UTF-8">
|
8
8
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
9
|
+
<%= Rack::Csrf.metatag(env) %>
|
9
10
|
<link rel="stylesheet" media="screen,print" type="text/css" href="css/app.min.css"/>
|
10
11
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/css/all.min.css" integrity="sha512-SnH5WK+bZxgPHs44uWIX+LLJAJ9/2PkPKZ5QiAj6Ta86w+fsb2TkcmfRyVX3pBnMFcV7oQPJkl9QevSCWr3W6A==" crossorigin="anonymous" referrerpolicy="no-referrer" />
|
11
12
|
</head>
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sequenceserver
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.1.
|
4
|
+
version: 3.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Queen Mary University of London
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2024-
|
12
|
+
date: 2024-07-02 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: json_pure
|
@@ -51,6 +51,26 @@ dependencies:
|
|
51
51
|
- - ">="
|
52
52
|
- !ruby/object:Gem::Version
|
53
53
|
version: 2.1.1
|
54
|
+
- !ruby/object:Gem::Dependency
|
55
|
+
name: rack_csrf
|
56
|
+
requirement: !ruby/object:Gem::Requirement
|
57
|
+
requirements:
|
58
|
+
- - "~>"
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: '2.7'
|
61
|
+
- - ">="
|
62
|
+
- !ruby/object:Gem::Version
|
63
|
+
version: 2.7.0
|
64
|
+
type: :runtime
|
65
|
+
prerelease: false
|
66
|
+
version_requirements: !ruby/object:Gem::Requirement
|
67
|
+
requirements:
|
68
|
+
- - "~>"
|
69
|
+
- !ruby/object:Gem::Version
|
70
|
+
version: '2.7'
|
71
|
+
- - ">="
|
72
|
+
- !ruby/object:Gem::Version
|
73
|
+
version: 2.7.0
|
54
74
|
- !ruby/object:Gem::Dependency
|
55
75
|
name: rackup
|
56
76
|
requirement: !ruby/object:Gem::Requirement
|
@@ -3539,7 +3559,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
3539
3559
|
- !ruby/object:Gem::Version
|
3540
3560
|
version: '0'
|
3541
3561
|
requirements: []
|
3542
|
-
rubygems_version: 3.5.
|
3562
|
+
rubygems_version: 3.5.14
|
3543
3563
|
signing_key:
|
3544
3564
|
specification_version: 4
|
3545
3565
|
summary: BLAST search made easy!
|