aboutsummaryrefslogtreecommitdiff
path: root/bh20simplewebuploader
diff options
context:
space:
mode:
Diffstat (limited to 'bh20simplewebuploader')
-rw-r--r--bh20simplewebuploader/__init__.py0
-rw-r--r--bh20simplewebuploader/main.py127
-rw-r--r--bh20simplewebuploader/static/main.css269
-rw-r--r--bh20simplewebuploader/static/main.js47
-rw-r--r--bh20simplewebuploader/templates/form.html325
5 files changed, 531 insertions, 237 deletions
diff --git a/bh20simplewebuploader/__init__.py b/bh20simplewebuploader/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/bh20simplewebuploader/__init__.py
diff --git a/bh20simplewebuploader/main.py b/bh20simplewebuploader/main.py
index e88eb4c..126b8dd 100644
--- a/bh20simplewebuploader/main.py
+++ b/bh20simplewebuploader/main.py
@@ -8,7 +8,7 @@ import re
import string
import yaml
import pkg_resources
-from flask import Flask, request, redirect, send_file, send_from_directory, render_template
+from flask import Flask, request, redirect, send_file, send_from_directory, render_template, jsonify
import os.path
import requests
@@ -197,6 +197,14 @@ def generate_form(schema, options):
record['type'] = 'number'
# Choose a reasonable precision for the control
record['step'] = '0.0001'
+
+ ### This is to fix the homepage for the moment ## needs more love though
+ # implementation of the [] stuff instead of just text fields
+ ## ToDo - implement lists
+ elif field_type == 'string[]':
+ record['type'] = 'text'
+ elif field_type == 'float[]':
+ record['type'] = 'text'
else:
raise NotImplementedError('Unimplemented field type {} in {} in metadata schema'.format(field_type, type_name))
yield record
@@ -358,7 +366,8 @@ def getAllaccessions():
payload = {'query': query, 'format': 'json'}
r = requests.get(baseURL, params=payload)
result = r.json()['results']['bindings']
- return str(result)
+ return jsonify([{'uri': x['fasta']['value'],
+ 'value': x['value']['value']} for x in result])
# parameter must be encoded e.g. http://arvados.org/keep:6e6276698ed8b0e6cd21f523e4f91179+123/sequence.fasta must become
@@ -368,26 +377,69 @@ def getDetailsForSeq():
seq_id = request.args.get('seq')
query="""SELECT DISTINCT ?key ?value WHERE {<placeholder> ?x [?key ?value]}"""
query=query.replace("placeholder", seq_id)
- print(query)
+ payload = {'query': query, 'format': 'json'}
+ r = requests.get(baseURL, params=payload)
+ result = r.json()['results']['bindings']
+ return jsonify([{'uri': x['key']['value'],
+ 'value': x['value']['value']} for x in result])
+
+
+@app.route('/api/getSEQCountbytech', methods=['GET'])
+def getSEQCountbytech():
+ query="""SELECT ?tech ?tech_label (count(?fasta) as ?fastaCount) WHERE
+ {?fasta ?x [<http://purl.obolibrary.org/obo/OBI_0600047> ?tech]
+ BIND (concat(?tech,"_label") as ?tech_label)}
+ GROUP BY ?tech ?tech_label ORDER BY DESC (?fastaCount)
+ """
+ payload = {'query': query, 'format': 'json'}
+ r = requests.get(baseURL, params=payload)
+ result = r.json()['results']['bindings']
+ return jsonify([{'Fasta Count': x['fastaCount']['value'],
+ 'tech': x['tech']['value'],
+ 'Label': x['tech_label']['value']} for x in result])
+
+## Is this one really necessary or should we just use getSEQCountbytech instead?
+@app.route('/api/getAvailableTech', methods=['GET'])
+def getAvailableTech():
+ query="""SELECT distinct ?tech ?tech_label WHERE
+ {?fasta ?x [<http://purl.obolibrary.org/obo/OBI_0600047> ?tech]
+ BIND (concat(?tech,"_label") as ?tech_label)
+ } """
payload = {'query': query, 'format': 'json'}
r = requests.get(baseURL, params=payload)
result = r.json()['results']['bindings']
return str(result)
+## List all Sequences/submissions by a given tech, as example e.g. http://purl.obolibrary.org/obo/OBI_0000759
+## Has to be encoded again so should be --> http%3A%2F%2Fpurl.obolibrary.org%2Fobo%2FOBI_0000759
@app.route('/api/getSEQbytech', methods=['GET'])
def getSEQbytech():
- query="""SELECT ?specimen_source ?specimen_source_label (count(?fasta) as ?fastaCount) WHERE
- {?fasta ?x [<http://purl.obolibrary.org/obo/OBI_0600047> ?specimen_source]
- BIND (concat(?specimen_source,"_label") as ?specimen_source_label)}
- GROUP BY ?specimen_source ?specimen_source_label ORDER BY DESC (?fastaCount)
+ query="""SELECT ?fasta WHERE
+ {?fasta ?x [<http://purl.obolibrary.org/obo/OBI_0600047> <placeholder>] }
"""
+ tech = request.args.get('tech')
+ query=query.replace("placeholder", tech)
payload = {'query': query, 'format': 'json'}
r = requests.get(baseURL, params=payload)
result = r.json()['results']['bindings']
return str(result)
+
+## Example location, encoded http%3A%2F%2Fwww.wikidata.org%2Fentity%2FQ1223
@app.route('/api/getSEQbyLocation', methods=['GET'])
def getSEQbyLocation():
+ query="""SELECT ?fasta WHERE {?fasta ?x[ <http://purl.obolibrary.org/obo/GAZ_00000448> <placeholder>]}"""
+ location=request.args.get('location')
+ query=query.replace("placeholder", location)
+ print(query)
+ payload = {'query': query, 'format': 'json'}
+ r = requests.get(baseURL, params=payload)
+ result = r.json()['results']['bindings']
+ return str(result)
+
+
+@app.route('/api/getSEQCountbyLocation', methods=['GET'])
+def getSEQCountbyLocation():
query="""SELECT ?geoLocation ?geoLocation_label (count(?fasta) as ?fastaCount) WHERE
{?fasta ?x [<http://purl.obolibrary.org/obo/GAZ_00000448> ?geoLocation]
BIND (concat(?geoLocation,"_label") as ?geoLocation_label)}
@@ -396,10 +448,13 @@ def getSEQbyLocation():
payload = {'query': query, 'format': 'json'}
r = requests.get(baseURL, params=payload)
result = r.json()['results']['bindings']
- return str(result)
+ return jsonify([{'Fasta Count': x['fastaCount']['value'],
+ 'GeoLocation': x['geoLocation']['value'],
+ 'GeoLocation Label': x['geoLocation_label']['value']} for x in result])
-@app.route('/api/getSEQbySpecimenSource', methods=['GET'])
-def getSEQbySpecimenSource():
+
+@app.route('/api/getSEQCountbySpecimenSource', methods=['GET'])
+def getSEQCountbySpecimenSource():
query="""SELECT ?specimen_source ?specimen_source_label (count(?fasta) as ?fastaCount) WHERE
{?fasta ?x [<http://purl.obolibrary.org/obo/OBI_0001479> ?specimen_source]
BIND (concat(?specimen_source,"_label") as ?specimen_source_label)}
@@ -409,11 +464,27 @@ def getSEQbySpecimenSource():
payload = {'query': query, 'format': 'json'}
r = requests.get(baseURL, params=payload)
result = r.json()['results']['bindings']
+ return jsonify([{'Fasta Count': x['fastaCount']['value'],
+ 'Specimen Source': x['specimen_source']['value'],
+ 'Label': x['specimen_source_label']['value']} for x in result])
+
+# Example specimen http%3A%2F%2Fpurl.obolibrary.org%2Fobo%2FNCIT_C155831
+@app.route('/api/getSEQbySpecimenSource', methods=['GET'])
+def getSEQBySpecimenSource():
+ query="""SELECT ?fasta ?specimen_source ?specimen_source_label WHERE
+ {?fasta ?x [<http://purl.obolibrary.org/obo/OBI_0001479> <placeholder>]
+ BIND (concat(?specimen_source,"_label") as ?specimen_source_label)}
+ """
+ specimen=request.args.get('specimen')
+ query = query.replace("placeholder", specimen)
+ payload = {'query': query, 'format': 'json'}
+ r = requests.get(baseURL, params=payload)
+ result = r.json()['results']['bindings']
return str(result)
#No data for this atm
-@app.route('/api/getSEQbyHostHealthStatus', methods=['GET'])
-def getSEQbyHostHealthStatus():
+@app.route('/api/getSEQCountbyHostHealthStatus', methods=['GET'])
+def getSEQCountbyHostHealthStatus():
query="""SELECT ?health_status ?health_status_label (count(?fasta) as ?fastaCount) WHERE
{?fasta ?x [<http://purl.obolibrary.org/obo/NCIT_C25688> ?health_status]
BIND (concat(?health_status,"_label") as ?health_status_label)}
@@ -423,4 +494,36 @@ def getSEQbyHostHealthStatus():
payload = {'query': query, 'format': 'json'}
r = requests.get(baseURL, params=payload)
result = r.json()['results']['bindings']
+ return str(result)
+
+@app.route('/api/getSEQbyLocationAndTech', methods=['GET'])
+def getSEQbyLocationAndTech():
+ query="""SELECT ?fasta WHERE { ?fasta ?x [
+ <http://purl.obolibrary.org/obo/GAZ_00000448> <placeholderLoc>; <http://purl.obolibrary.org/obo/OBI_0600047> <placeholderTech> ]}"""
+ location=request.args.get('location')
+ tech=request.args.get('tech')
+ query=query.replace("placeholderLoc", location)
+ query = query.replace("placeholderTech", tech)
+ print(query)
+ payload = {'query': query, 'format': 'json'}
+ r = requests.get(baseURL, params=payload)
+ result = r.json()['results']['bindings']
+ return str(result)
+
+
+# Example Location http%3A%2F%2Fwww.wikidata.org%2Fentity%2FQ1223
+# Example specimen http%3A%2F%2Fpurl.obolibrary.org%2Fobo%2FNCIT_C155831
+@app.route('/api/getSEQbyLocationAndSpecimenSource', methods=['GET'])
+def getSEQbyLocationAndSpecimenSource():
+ query="""SELECT ?fasta WHERE { ?fasta ?x [
+ <http://purl.obolibrary.org/obo/GAZ_00000448> <placeholderLoc>; <http://purl.obolibrary.org/obo/OBI_0001479> <placeholderSpecimen> ]}
+ """
+ location = request.args.get('location')
+ specimen = request.args.get('specimen')
+ query = query.replace("placeholderLoc", location)
+ query = query.replace("placeholderSpecimen", specimen)
+ print(query)
+ payload = {'query': query, 'format': 'json'}
+ r = requests.get(baseURL, params=payload)
+ result = r.json()['results']['bindings']
return str(result) \ No newline at end of file
diff --git a/bh20simplewebuploader/static/main.css b/bh20simplewebuploader/static/main.css
new file mode 100644
index 0000000..57e29ef
--- /dev/null
+++ b/bh20simplewebuploader/static/main.css
@@ -0,0 +1,269 @@
+hr {
+ margin: auto 0;
+}
+
+body {
+ color: #101010;
+ background-color: #F5FFFF;
+ margin: 0;
+}
+
+h1, h2, h3, h4 {
+ font-family: 'Inter', sans-serif;
+ color: #0ED1CD;
+}
+
+h1 {
+ text-align: center;
+}
+
+.intro {
+ color: #505050;
+ font-weight: 300;
+}
+
+.header {
+ background-color: white;
+ margin: 0 auto;
+ padding: 20px;
+ text-align: center;
+ height: 150px;
+}
+
+h2 > svg {
+ position: relative;
+ top: 8px;
+}
+
+.logo {
+ float: right;
+}
+
+p, form, .about, .footer {
+ font-family: 'Inter', sans-serif;
+ line-height: 1.5;
+}
+
+form h4 {
+ text-transform: 'uppercase';
+}
+
+.intro, form, .search {
+ padding: 20px;
+}
+
+.intro {
+ background-color: inherit;
+ margin: 0 auto;
+ padding: 20px;
+}
+
+.about {
+ background-color: #B2F8F8;
+ margin: 30px auto;
+ padding: 20px;
+ width: 95%;
+ border-radius: 20px;
+}
+
+.button {
+ border-radius: 5px;
+ background: #0ED1CD;
+ margin: 0.3em auto;
+ padding: 0.4em;
+}
+
+.footer {
+ background: #058280;;
+ margin: 0 auto;
+ color: #fff;
+}
+
+.footer a {
+ color: #fff;
+}
+
+span.dropt {border-bottom: thin dotted; background: #ffeedd;}
+span.dropt:hover {text-decoration: none; background: #ffffff; z-index: 6; }
+
+.grid-container {
+ display: grid;
+ grid-template-columns: repeat(4, 1fr);
+ grid-template-rows: auto;
+ row-gap:5px;
+ grid-template-areas:
+ "a a b b"
+ "a a c c"
+ "a a d d"
+ "e e e e"
+ "f f f f";
+ grid-auto-flow: column;
+}
+
+.about {
+ display: grid;
+ grid-template-columns: repeat(2, 1fr);
+ grid-auto-flow: row;
+}
+
+.about h1 {
+ text-align: left;
+}
+
+.about p {
+ font-weight: 300;
+ color: #505050;
+}
+
+.intro {
+ grid-area: a;
+}
+
+.fasta-file-select {
+ padding: 1em;
+ grid-area: b;
+}
+
+a {
+ color: #40DBD8;
+ font-weight: 700;
+}
+
+.fasta-file-select label, .metadata label {
+ font-weight: 600;
+}
+
+.metadata {
+ padding: 1em;
+ grid-area: c;
+}
+.metadata_upload_form {
+ padding: 1em;
+ grid-area: c;
+}
+
+#metadata_upload_form_spot {
+ grid-area: d;
+}
+
+#metadata_fill_form_spot {
+ grid-area: e;
+}
+
+#metadata_fill_form {
+ column-count: 4;
+ margin-top: 0.5em;
+ column-width: 250px;
+}
+
+pre code {
+ background-color: #eee;
+ display: flex;
+ width: max-content;
+ margin: 0 auto;
+ overflow-y: scroll;
+ max-height: 300px;
+ padding: 10px;
+ border: solid 1px black;
+}
+
+.record {
+ display: flex;
+ flex-direction: column;
+ border: solid 1px #808080;
+ padding: 1em;
+ background: #F8F8F8;
+ margin-bottom: 1em;
+ -webkit-column-break-inside: avoid; /* Chrome, Safari, Opera */
+ page-break-inside: avoid; /* Firefox */
+ break-inside: avoid;
+}
+
+.record label {
+ font-size: small;
+ margin-top: 10px;
+}
+
+.search-section {
+ display: flex;
+ justify-content: space-between;
+}
+
+.search-section .filter-options {
+ display: flex;
+ flex-direction: column;
+ width: max-content;
+ padding: 20px;
+}
+
+.search-section p {
+ margin: 0;
+}
+
+.submit {
+ grid-area: f;
+ width: 17em;
+ justify-self: center;
+}
+
+footer {
+ display: block;
+ width: 100%;
+}
+
+.sponsors {
+ width: inherit;
+ display: flex;
+ flex-direction: row;
+ flex-wrap: wrap;
+ justify-content: space-evenly;
+ align-content: space-evenly;
+}
+
+.sponsors a {
+ flex-grow: 4;
+ height: 200px;
+ margin: 10px;
+ background: white;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+}
+.sponsors img {
+ width: 100%;
+}
+.metadata input#metadata_upload:checked ~ #metadata_upload_form_spot {
+ display: block;
+}
+
+.metadata input#metadata_upload ~ #metadata_upload_form_spot {
+ display: none;
+}
+
+.loader {
+ display: block;
+ border: 5px solid #f3f3f3; /* Light grey */
+ border-top: 5px solid #3498db; /* Blue */
+ border-radius: 50%;
+ width: 20px;
+ height: 20px;
+ margin-right: auto;
+ margin-left: auto;
+ animation: spin 1.5s linear infinite;
+}
+
+.invisible {
+ display: none;
+}
+
+@keyframes spin {
+ 0% { transform: rotate(0deg); }
+ 100% { transform: rotate(360deg); }
+}
+
+@media only screen and (max-device-width: 480px) {
+ .grid-container {
+ display: flex;
+ flex-direction: column;
+ }
+}
diff --git a/bh20simplewebuploader/static/main.js b/bh20simplewebuploader/static/main.js
new file mode 100644
index 0000000..96199a0
--- /dev/null
+++ b/bh20simplewebuploader/static/main.js
@@ -0,0 +1,47 @@
+function fetchAPI(apiEndPoint) {
+ fetch(scriptRoot + apiEndPoint)
+ .then(response => {
+ return response.json();
+ })
+ .then(data => {
+ document.getElementById("json").textContent = JSON.stringify(data, undefined, 2);
+ document.getElementById("results").classList.remove("invisible");
+ document.getElementById("loader").classList.add("invisible");
+ });
+ document.getElementById("results").classList.add("invisible");
+ document.getElementById("loader").classList.remove("invisible");
+
+}
+
+let search = () => {
+ let m = document.getElementById('search-input').value;
+ fetchAPI(scriptRoot + "/api/getDetailsForSeq?seq=" + encodeURIComponent(m));
+}
+
+let fetchSEQBySpecimen = () => {
+ fetchAPI("/api/getSEQCountbySpecimenSource");
+}
+
+let fetchSEQByLocation = () => {
+ fetchAPI("/api/getSEQCountbyLocation");
+}
+
+let fetchSEQByTech = () => {
+ fetchAPI("/api/getSEQCountbytech");
+}
+
+let fetchAllaccessions = () => {
+ fetchAPI("/api/getAllaccessions");
+};
+
+/**
+ * Show form if checked
+ */
+let fillFormSpot = document.getElementById('metadata_fill_form_spot');
+function displayForm() {
+ if (document.getElementById('metadata_form').checked) {
+ fillFormSpot.classList.remove("invisible");
+ return;
+ }
+ fillFormSpot.classList.add("invisible");
+}
diff --git a/bh20simplewebuploader/templates/form.html b/bh20simplewebuploader/templates/form.html
index 02ae84d..ffd4158 100644
--- a/bh20simplewebuploader/templates/form.html
+++ b/bh20simplewebuploader/templates/form.html
@@ -1,152 +1,9 @@
<!DOCTYPE html>
<html>
- <style>
- hr {
- margin: auto 0;
- }
-
- body {
- color: #101010;
- background-color: #F9EDE1;
- }
-
- h1, h2, h3, h4 {
- font-family: 'Roboto Slab', serif;
- color: darkblue;
- }
-
- h1 {
- text-align: center;
- }
-
- p {
- color: #505050;
- font-style: italic;
- }
- .header {
- background-color: white;
- margin: 0 auto;
- padding: 20px;
- text-align: center;
- height: 150px;
- }
-
- .logo {
- float: right;
- }
-
- p, form, .about, .footer {
- font-family: 'Raleway', sans-serif;
- line-height: 1.5;
- }
-
- form h4 {
- text-transform: 'uppercase';
- }
-
- .intro, form {
- padding: 20px;
- }
-
- .intro {
- background-color: lightgrey;
- margin: 0 auto;
- padding: 20px;
- }
-
- .about {
- background-color: lightgrey;
- margin: 0 auto;
- padding: 20px;
- }
- .footer {
- background-color: white;
- margin: 0 auto;
- }
-
- span.dropt {border-bottom: thin dotted; background: #ffeedd;}
- span.dropt:hover {text-decoration: none; background: #ffffff; z-index: 6; }
-
- .grid-container {
- display: grid;
- grid-template-columns: repeat(4, 1fr);
- grid-template-rows: auto;
- row-gap:5px;
- grid-template-areas:
- "a a b b"
- "a a c c"
- "a a d d"
- "e e e e"
- "f f f f";
- grid-auto-flow: column;
- }
-
- .intro {
- grid-area: a;
- }
-
- .fasta-file-select {
- padding: 1em;
- grid-area: b;
- }
-
- .metadata {
- padding: 1em;
- grid-area: c;
- }
- .metadata_upload_form {
- padding: 1em;
- grid-area: c;
- }
-
- #metadata_upload_form_spot {
- grid-area: d;
- }
-
- #metadata_fill_form_spot {
- grid-area: e;
- }
-
- #metadata_fill_form {
- column-count: 4;
- margin-top: 0.5em;
- column-width: 250px;
- }
-
- .record {
- display: flex;
- flex-direction: column;
- border: solid 1px #808080;
- padding: 1em;
- background: #F8F8F8;
- margin-bottom: 1em;
- -webkit-column-break-inside: avoid; /* Chrome, Safari, Opera */
- page-break-inside: avoid; /* Firefox */
- break-inside: avoid;
- }
-
- .record label {
- font-size: small;
- margin-top: 10px;
- }
-
- .submit {
- grid-area: f;
- width: 17em;
- justify-self: center;
- }
-
- @media only screen and (max-device-width: 480px) {
- .grid-container {
- display: flex;
- flex-direction: column;
- }
- }
- </style>
-
<head>
<meta charset="UTF-8">
- <link href="https://fonts.googleapis.com/css2?family=Raleway:wght@500&family=Roboto+Slab&display=swap" rel="stylesheet">
+ <link href="https://fonts.googleapis.com/css2?family=Inter:wght@100;200;300;400;500;600;700;800;900&display=swap" rel="stylesheet">
+ <link href="/static/main.css" rel="stylesheet" type="text/css">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Web uploader for Public SARS-CoV-2 Sequence Resource</title>
</head>
@@ -158,28 +15,67 @@
<small>Disabled until we got everything wired up</small>
</section>
- <hr>
+
+ <section class="search-section">
+ <div class="filter-options" action="#">
+ <p>[Demo] Display content sequences by: </p>
+
+ <div>
+ <button class="button" onclick="fetchSEQBySpecimen()">Specimen Source</button>
+ <button class="button" onclick="fetchSEQByLocation()">Location</button>
+ <button class="button" onclick="fetchSEQByTech()">Tech</button>
+ <button class="button" onclick="fetchAllaccessions()">Allaccessions</button>
+ </div>
+
+ </div>
+
+ <div class="search">
+ <input id="search-input" id="global-search" type="search" placeholder="FASTA uri" required>
+ <button class="button search-button" type="submit" onclick="search()">
+ <span class="icon ion-search">
+ <span class="sr-only">Search</span>
+ </span>
+ </button>
+ </div>
+ </section>
+
+ <div id="loader" class="loader invisible"></div>
+
+ <section id="results" class="invisible">
+ <pre><code id="json"></code></pre>
+ </section>
<section>
<form action="/submit" method="POST" enctype="multipart/form-data" id="main_form" class="grid-container">
- <p class="intro">
- Upload your SARS-CoV-2 sequence (FASTA or FASTQ formats) with metadata (JSONLD) to the <a href="https://workbench.lugli.arvadosapi.com/collections/lugli-4zz18-z513nlpqm03hpca">public sequence resource</a>. The upload will trigger a
- recompute with all available sequences into a Pangenome
- available for
- <a href="https://workbench.lugli.arvadosapi.com/collections/lugli-4zz18-z513nlpqm03hpca">download</a>!
- Your uploaded sequence will automatically be processed
- and incorporated into the public pangenome with
- metadata using worklows from the High Performance Open Biology Lab defined <a href="https://github.com/hpobio-lab/viral-analysis/tree/master/cwl/pangenome-generate">here</a>. All data is published under
- a <a href="https://creativecommons.org/licenses/by/4.0/">Creative
- Commons 4.0 attribution license</a> (CC-BY-4.0). You
- can take the published (GFA/RDF/FASTA) data and store it in
- a triple store for further processing. We also plan to
- combine identifiers with clinical data stored securely at <a href="https://redcap-covid19.elixir-luxembourg.org/redcap/">REDCap</a>.
- A free command line version of the uploader can be
- installed from <a href="https://github.com/arvados/bh20-seq-resource">source</a>.
- </p>
+ <div class="intro">
+ <p>
+ Upload your SARS-CoV-2 sequence (FASTA or FASTQ formats) with metadata (JSONLD) to the <a href="https://workbench.lugli.arvadosapi.com/collections/lugli-4zz18-z513nlpqm03hpca">public sequence resource</a>. The upload will trigger a
+ recompute with all available sequences into a Pangenome
+ available for
+ <a href="https://workbench.lugli.arvadosapi.com/collections/lugli-4zz18-z513nlpqm03hpca">download</a>!
+ </p>
+ <p>
+ Your uploaded sequence will automatically be processed
+ and incorporated into the public pangenome with
+ metadata using worklows from the High Performance Open Biology Lab defined <a href="https://github.com/hpobio-lab/viral-analysis/tree/master/cwl/pangenome-generate">here</a>. All data is published under
+ a <a href="https://creativecommons.org/licenses/by/4.0/">Creative
+ Commons 4.0 attribution license</a> (CC-BY-4.0). You
+ can take the published (GFA/RDF/FASTA) data and store it in
+ a triple store for further processing. We also plan to
+ combine identifiers with clinical data stored securely at <a href="https://redcap-covid19.elixir-luxembourg.org/redcap/">REDCap</a>.
+ A free command line version of the uploader can be
+ installed from <a href="https://github.com/arvados/bh20-seq-resource">source</a>.
+ </p>
+
+ </div>
<div class="fasta-file-select">
+ <h2><svg class="bi bi-cloud-upload" width="1.2em" height="1.2em" viewBox="0 0 16 16" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
+ <path d="M4.887 6.2l-.964-.165A2.5 2.5 0 103.5 11H6v1H3.5a3.5 3.5 0 11.59-6.95 5.002 5.002 0 119.804 1.98A2.501 2.501 0 0113.5 12H10v-1h3.5a1.5 1.5 0 00.237-2.981L12.7 7.854l.216-1.028a4 4 0 10-7.843-1.587l-.185.96z"/>
+ <path fill-rule="evenodd" d="M5 8.854a.5.5 0 00.707 0L8 6.56l2.293 2.293A.5.5 0 1011 8.146L8.354 5.5a.5.5 0 00-.708 0L5 8.146a.5.5 0 000 .708z" clip-rule="evenodd"/>
+ <path fill-rule="evenodd" d="M8 6a.5.5 0 01.5.5v8a.5.5 0 01-1 0v-8A.5.5 0 018 6z" clip-rule="evenodd"/>
+ </svg> Upload SARS-CoV-2 Sequence</h2>
+
<label for="fasta">Select FASTA file of assembled genome (max 50K), or FASTQ of reads (<span class="dropt" title="For a larger fastq file you'll need to use a CLI uploader">max 150MB<span style="width:500px;"></span></span>) : </label>
<br>
<input type="file" id="fasta" name="fasta" accept=".fa,.fasta,.fna,.fq" required>
@@ -189,16 +85,16 @@
</div>
<div class="metadata">
- <label>Select metadata submission method:</label>
- <br>
- <input type="radio" id="metadata_form" name="metadata_type" value="fill" onchange="setMode()" checked required>
- <label for="metadata_form">Fill in metadata manually</label>
- <input type="radio" id="metadata_upload" name="metadata_type" value="upload" onchange="setMode()" required>
- <label for="metadata_upload">Upload metadata file</label>
- <br>
- <small>Make sure the metadata has submitter attribution details.</small>
+ <label>Select metadata submission method:</label>
+ <br>
+ <input type="radio" id="metadata_form" name="metadata_type" value="fill" checked onchange="displayForm()" required>
+ <label for="metadata_form">Fill in metadata manually</label>
+ <input type="radio" id="metadata_upload" name="metadata_type" value="upload" onchange="displayForm()" required>
+ <label for="metadata_upload">Upload metadata file</label>
+ <br>
+ <small>Make sure the metadata has submitter attribution details.</small>
- <div id="metadata_upload_form_spot">
+ <div id="metadata_upload_form_spot">
<div id="metadata_upload_form">
<br>
<label for="metadata">Select JSON or YAML metadata file following <a href="https://github.com/arvados/bh20-seq-resource/blob/master/bh20sequploader/bh20seq-schema.yml" target="_blank">this schema</a> and <a href="https://github.com/arvados/bh20-seq-resource/blob/master/example/metadata.yaml" target="_blank">example</a> (max 50K):</label>
@@ -206,9 +102,9 @@
<input type="file" id="metadata" name="metadata" accept=".json,.yml,.yaml" required>
<br>
</div>
- </div>
- </div>
+ </div>
+ </div>
<div id="metadata_fill_form_spot">
<div id="metadata_fill_form">
{% for record in fields %}
@@ -246,40 +142,44 @@
{% endif %}
{% endfor %}
</div>
+
</div>
<input class="submit" type="submit" value="Add to Pangenome">
</form>
</section>
-<hr>
<br>
<div class="about">
- <h3>ABOUT</h3>
- <p>
- This a public repository created at the COVID-19 BioHackathon
- that has a low barrier to entry for uploading sequence data using
- best practices. I.e., data is published with a creative commons
- 4.0 (CC-4.0) license with metadata using state-of-the art
- standards and, perhaps most importantly, providing standardized
- workflows that get triggered on upload, so that results are
- immediately available in standardized data formats. The repository
- will be maintained and expanded for the duration of the
- pandemic. To contribute data simply upload it! To contribute code
- and/or workflows see
- the <a href="https://github.com/arvados/bh20-seq-resource">project
- repository</a>. For more information see the <a href="https://github.com/arvados/bh20-seq-resource/blob/master/paper/paper.md">paper</a> (WIP).
- </p>
- <br>
+ <div>
+ <h1>ABOUT</h1>
+ <p>
+ This a public repository created at the COVID-19 BioHackathon
+ that has a low barrier to entry for uploading sequence data using
+ best practices. I.e., data is published with a creative commons
+ 4.0 (CC-4.0) license with metadata using state-of-the art
+ standards and, perhaps most importantly, providing standardized
+ workflows that get triggered on upload, so that results are
+ immediately available in standardized data formats. The repository
+ will be maintained and expanded for the duration of the
+ pandemic. To contribute data simply upload it! To contribute code
+ and/or workflows see
+ the <a href="https://github.com/arvados/bh20-seq-resource">project
+ repository</a>. For more information see the <a href="https://github.com/arvados/bh20-seq-resource/blob/master/paper/paper.md">paper</a> (WIP).
+ </p>
+
+ </div>
+ <div class="sponsors">
+ <a href="https://arvados.org/"><img src="static/image/arvados-logo.png"></a>
+ <a href="https://www.commonwl.org/"><img src="static/image/CWL-Logo-Header.png"></a>
+
+ <a href="https://github.com/virtual-biohackathons/covid-19-bh20">
+ <img src="static/image/covid19biohackathon.png"></a>
+ </div>
</div>
-
- <hr>
<div class="footer">
- <a href="https://arvados.org/"><img src="static/image/arvados-logo.png" align="top"></a>
- <a href="https://www.commonwl.org/"><img src="static/image/CWL-Logo-Header.png" height="70"></a>
+ <!-- Sponsors -->
- <a href="https://github.com/virtual-biohackathons/covid-19-bh20">
- <img src="static/image/covid19biohackathon.png" align="right" height="70"></a>
<center>
<small><a href="https://github.com/arvados/bh20-seq-resource">Source code</a> &middot; Powered by <a href="https://www.commonwl.org/">Common Workflow Language</a> &amp; <a href="https://arvados.org/">Arvados</a>; Made for <a href="https://github.com/virtual-biohackathons/covid-19-bh20">COVID-19-BH20</a>
@@ -289,35 +189,10 @@
</div>
- <script type="text/javascript">
- let uploadForm = document.getElementById('metadata_upload_form')
- let uploadFormSpot = document.getElementById('metadata_upload_form_spot')
- let fillForm = document.getElementById('metadata_fill_form')
- let fillFormSpot = document.getElementById('metadata_fill_form_spot')
-
- function setUploadMode() {
- // Make the upload form the one in use
- uploadFormSpot.appendChild(uploadForm)
- fillFormSpot.removeChild(fillForm)
- }
-
- function setFillMode() {
- // Make the fillable form the one in use
- uploadFormSpot.removeChild(uploadForm)
- fillFormSpot.appendChild(fillForm)
- }
-
- function setMode() {
- // Pick mode based on radio
- if (document.getElementById('metadata_upload').checked) {
- setUploadMode()
- } else {
- setFillMode()
- }
- }
+<script type="text/javascript">
+ let scriptRoot = {{ request.script_root|tojson|safe }};
+</script>
- // Start in mode appropriate to selected form item
- setMode()
- </script>
+<script type="text/javascript" src="/static/main.js"></script>
</body>
</html>