From b48f2d6079740c446b59d8f70c115213046c4732 Mon Sep 17 00:00:00 2001 From: BonfaceKilz Date: Fri, 24 Apr 2020 14:18:21 +0300 Subject: Update .gitignore file --- .gitignore | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/.gitignore b/.gitignore index 8e8c01b..5707130 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,18 @@ *.py~ + +# Distribution / packaging build/ +__pycache__/ +eggs/ +.eggs/ +*.egg-info/ +*.egg + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ \ No newline at end of file -- cgit v1.2.3 From 73d36d4b91cd0ac7b2112f20eb7d88acd981827a Mon Sep 17 00:00:00 2001 From: BonfaceKilz Date: Fri, 24 Apr 2020 14:18:48 +0300 Subject: Make package data accessible from `setup.py` Based off: https://stackoverflow.com/a/39024947/3668255 --- bh20simplewebuploader/__init__.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 bh20simplewebuploader/__init__.py diff --git a/bh20simplewebuploader/__init__.py b/bh20simplewebuploader/__init__.py new file mode 100644 index 0000000..e69de29 -- cgit v1.2.3 From 8e8df40378244daf71edb8d3a469d7cbe59ddcdc Mon Sep 17 00:00:00 2001 From: BonfaceKilz Date: Sat, 25 Apr 2020 19:28:52 +0300 Subject: Wrap extra flags to cater for non-bash terminals `pip install -e .[web]` does not work on zsh. Wrapping `.web` in quotes makes the command in all terminals --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b0b22ff..8b78ebd 100644 --- a/README.md +++ b/README.md @@ -166,7 +166,7 @@ To run it locally: ``` virtualenv --python python3 venv . venv/bin/activate -pip install -e .[web] +pip install -e ".[web]" env FLASK_APP=bh20simplewebuploader/main.py flask run ``` -- cgit v1.2.3 From 8ea8f7c2ed50bb089df26ae497e9d274c04705c8 Mon Sep 17 00:00:00 2001 From: BonfaceKilz Date: Sat, 25 Apr 2020 19:34:55 +0300 Subject: Put CSS code into it's own separate CSS file --- bh20simplewebuploader/static/main.css | 155 ++++++++++++++++++++++++++++++ bh20simplewebuploader/templates/form.html | 145 +--------------------------- 2 files changed, 156 insertions(+), 144 deletions(-) create mode 100644 bh20simplewebuploader/static/main.css diff --git a/bh20simplewebuploader/static/main.css b/bh20simplewebuploader/static/main.css new file mode 100644 index 0000000..30b1d04 --- /dev/null +++ b/bh20simplewebuploader/static/main.css @@ -0,0 +1,155 @@ +hr { + margin: auto 0; +} + +body { + color: #101010; + background-color: #F9EDE1; + margin: 0; +} + +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; +} + +footer { + display: block; + width: 100%; +} + +.sponsors { + width: inherit; + display: flex; + flex-direction: row; + flex-wrap: wrap; + justify-content: space-around; +} + +@media only screen and (max-device-width: 480px) { + .grid-container { + display: flex; + flex-direction: column; + } +} diff --git a/bh20simplewebuploader/templates/form.html b/bh20simplewebuploader/templates/form.html index 02ae84d..f24af0e 100644 --- a/bh20simplewebuploader/templates/form.html +++ b/bh20simplewebuploader/templates/form.html @@ -1,152 +1,9 @@ - - + Web uploader for Public SARS-CoV-2 Sequence Resource -- cgit v1.2.3 From 414a8028638039d4113e099455c0a7f929ff0b68 Mon Sep 17 00:00:00 2001 From: BonfaceKilz Date: Sat, 25 Apr 2020 19:35:54 +0300 Subject: Reposition sponsor logo at the bottom --- bh20simplewebuploader/templates/form.html | 79 ++++++++++++++++++------------- 1 file changed, 46 insertions(+), 33 deletions(-) diff --git a/bh20simplewebuploader/templates/form.html b/bh20simplewebuploader/templates/form.html index f24af0e..9c272a0 100644 --- a/bh20simplewebuploader/templates/form.html +++ b/bh20simplewebuploader/templates/form.html @@ -132,11 +132,14 @@
- + -- cgit v1.2.3 From 686958488357f7dab385c2a62405a49b2cb15dfa Mon Sep 17 00:00:00 2001 From: BonfaceKilz Date: Sat, 25 Apr 2020 19:40:56 +0300 Subject: Put JS code in its own JS file --- bh20simplewebuploader/static/main.js | 37 +++++++++++++++++++++++++++++ bh20simplewebuploader/templates/form.html | 39 ++----------------------------- 2 files changed, 39 insertions(+), 37 deletions(-) create mode 100644 bh20simplewebuploader/static/main.js diff --git a/bh20simplewebuploader/static/main.js b/bh20simplewebuploader/static/main.js new file mode 100644 index 0000000..ab810cd --- /dev/null +++ b/bh20simplewebuploader/static/main.js @@ -0,0 +1,37 @@ +let r = new XMLHttpRequest(); +let test; +r.open("GET", scriptRoot + "/api/getAllaccessions", true); +r.onreadystatechange = function () { + if (r.readyState != 4 || r.status != 200) return; + test = r.responseText; + console.log(JSON.parse(test)); +}; +r.send(); +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() + } +} + +// Start in mode appropriate to selected form item +setMode() diff --git a/bh20simplewebuploader/templates/form.html b/bh20simplewebuploader/templates/form.html index 9c272a0..7b1fd98 100644 --- a/bh20simplewebuploader/templates/form.html +++ b/bh20simplewebuploader/templates/form.html @@ -151,43 +151,8 @@ + + -- cgit v1.2.3 From ab1896d6be95875ce767124ac160b095cacb9883 Mon Sep 17 00:00:00 2001 From: BonfaceKilz Date: Sat, 25 Apr 2020 22:52:54 +0300 Subject: Remove unnecessary JS --- bh20simplewebuploader/static/main.css | 11 +++++++ bh20simplewebuploader/static/main.js | 50 +++++++++++-------------------- bh20simplewebuploader/templates/form.html | 25 ++++++++-------- 3 files changed, 41 insertions(+), 45 deletions(-) diff --git a/bh20simplewebuploader/static/main.css b/bh20simplewebuploader/static/main.css index 30b1d04..609ae19 100644 --- a/bh20simplewebuploader/static/main.css +++ b/bh20simplewebuploader/static/main.css @@ -147,6 +147,17 @@ footer { justify-content: space-around; } +.metadata input#metadata_upload:checked ~ #metadata_upload_form_spot { + display: block; +} + +.metadata input#metadata_upload ~ #metadata_upload_form_spot { + display: none; +} + +.invisible { + display: none; +} @media only screen and (max-device-width: 480px) { .grid-container { display: flex; diff --git a/bh20simplewebuploader/static/main.js b/bh20simplewebuploader/static/main.js index ab810cd..e8d4776 100644 --- a/bh20simplewebuploader/static/main.js +++ b/bh20simplewebuploader/static/main.js @@ -1,37 +1,21 @@ -let r = new XMLHttpRequest(); -let test; -r.open("GET", scriptRoot + "/api/getAllaccessions", true); -r.onreadystatechange = function () { - if (r.readyState != 4 || r.status != 200) return; - test = r.responseText; - console.log(JSON.parse(test)); -}; -r.send(); -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') +fetch(scriptRoot + "/api/getAllaccessions") + .then(response => { + return response.json(); + }) + .then(data => { + console.log('test'); + console.log(data); + }) -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() +/** + * Show form if checked + */ +let fillFormSpot = document.getElementById('metadata_fill_form_spot'); +function displayForm() { + if (document.getElementById('metadata_form').checked) { + fillFormSpot.classList.remove("invisible"); } else { - setFillMode() + fillFormSpot.classList.add("invisible"); + console.log("visible"); } } - -// Start in mode appropriate to selected form item -setMode() diff --git a/bh20simplewebuploader/templates/form.html b/bh20simplewebuploader/templates/form.html index 7b1fd98..ea3caab 100644 --- a/bh20simplewebuploader/templates/form.html +++ b/bh20simplewebuploader/templates/form.html @@ -46,16 +46,16 @@
- -
- - - - -
- Make sure the metadata has submitter attribution details. - -
+ +
+ + + + +
+ Make sure the metadata has submitter attribution details. + +

@@ -63,9 +63,9 @@
-
-
+
+
{% for record in fields %} @@ -103,6 +103,7 @@ {% endif %} {% endfor %}
+
-- cgit v1.2.3 From e158d57813b3cfe494b47d3a865200ecddd11c4d Mon Sep 17 00:00:00 2001 From: BonfaceKilz Date: Sun, 26 Apr 2020 03:43:38 +0300 Subject: Add basic structure for interacting with the API --- bh20simplewebuploader/static/main.css | 26 ++++++++++++++++++++++++++ bh20simplewebuploader/templates/form.html | 22 +++++++++++++++++++++- 2 files changed, 47 insertions(+), 1 deletion(-) diff --git a/bh20simplewebuploader/static/main.css b/bh20simplewebuploader/static/main.css index 609ae19..94d38bf 100644 --- a/bh20simplewebuploader/static/main.css +++ b/bh20simplewebuploader/static/main.css @@ -57,6 +57,15 @@ form h4 { margin: 0 auto; padding: 20px; } + +.button { + width: 6em; + border-radius: 5px; + background: #0ED1CD; + margin: 0.3em auto; + padding: 0.4em; +} + .footer { background-color: white; margin: 0 auto; @@ -128,6 +137,22 @@ span.dropt:hover {text-decoration: none; background: #ffffff; z-index: 6; } 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; @@ -158,6 +183,7 @@ footer { .invisible { display: none; } + @media only screen and (max-device-width: 480px) { .grid-container { display: flex; diff --git a/bh20simplewebuploader/templates/form.html b/bh20simplewebuploader/templates/form.html index ea3caab..e01b846 100644 --- a/bh20simplewebuploader/templates/form.html +++ b/bh20simplewebuploader/templates/form.html @@ -15,7 +15,27 @@ Disabled until we got everything wired up -
+ +
+
+

[Demo] Display content sequences by:

+ + + +
+ + +
+ +
+
-- cgit v1.2.3 From 5565338df4c172df2c140bfc1380262c3fb02aed Mon Sep 17 00:00:00 2001 From: BonfaceKilz Date: Sun, 26 Apr 2020 05:25:35 +0300 Subject: Jsonify response and pick the values --- bh20simplewebuploader/main.py | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/bh20simplewebuploader/main.py b/bh20simplewebuploader/main.py index e88eb4c..53a4cda 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 @@ -358,7 +358,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,11 +369,12 @@ def getDetailsForSeq(): seq_id = request.args.get('seq') query="""SELECT DISTINCT ?key ?value WHERE { ?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 str(result) + return jsonify([{'uri': x['key']['value'], + 'value': x['value']['value']} for x in result]) + @app.route('/api/getSEQbytech', methods=['GET']) def getSEQbytech(): @@ -384,7 +386,9 @@ def getSEQbytech(): 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'], + 'Specimen Source': x['specimen_source']['value'], + 'Label': x['specimen_source_label']['value']} for x in result]) @app.route('/api/getSEQbyLocation', methods=['GET']) def getSEQbyLocation(): @@ -396,7 +400,10 @@ 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(): @@ -409,7 +416,9 @@ def getSEQbySpecimenSource(): 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'], + 'Specimen Source': x['specimen_source']['value'], + 'Label': x['specimen_source_label']['value']} for x in result]) #No data for this atm @app.route('/api/getSEQbyHostHealthStatus', methods=['GET']) @@ -423,4 +432,4 @@ def getSEQbyHostHealthStatus(): 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 + return str(result) -- cgit v1.2.3 From 87628425bd83d3d142fbf9383ef727047cd8f9d1 Mon Sep 17 00:00:00 2001 From: BonfaceKilz Date: Sun, 26 Apr 2020 05:26:18 +0300 Subject: Display the output of the queries as prettified JSON for now --- bh20simplewebuploader/static/main.css | 31 ++++++++++++++++++-- bh20simplewebuploader/static/main.js | 48 ++++++++++++++++++++++++------- bh20simplewebuploader/templates/form.html | 18 ++++++++---- 3 files changed, 79 insertions(+), 18 deletions(-) diff --git a/bh20simplewebuploader/static/main.css b/bh20simplewebuploader/static/main.css index 94d38bf..20003f9 100644 --- a/bh20simplewebuploader/static/main.css +++ b/bh20simplewebuploader/static/main.css @@ -42,7 +42,7 @@ form h4 { text-transform: 'uppercase'; } -.intro, form { +.intro, form, .search { padding: 20px; } @@ -59,7 +59,6 @@ form h4 { } .button { - width: 6em; border-radius: 5px; background: #0ED1CD; margin: 0.3em auto; @@ -120,6 +119,17 @@ span.dropt:hover {text-decoration: none; background: #ffffff; z-index: 6; } 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; @@ -180,10 +190,27 @@ footer { 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; diff --git a/bh20simplewebuploader/static/main.js b/bh20simplewebuploader/static/main.js index e8d4776..0f79fdf 100644 --- a/bh20simplewebuploader/static/main.js +++ b/bh20simplewebuploader/static/main.js @@ -1,11 +1,38 @@ -fetch(scriptRoot + "/api/getAllaccessions") - .then(response => { - return response.json(); - }) - .then(data => { - console.log('test'); - console.log(data); - }) +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/getSEQbySpecimenSource"); +} + +let fetchSEQByLocation = () => { + fetchAPI("/api/getSEQbyLocation"); +} + +let fetchSEQByTech = () => { + fetchAPI("/api/getSEQbytech"); +} + +let fetchAllaccessions = () => { + fetchAPI("/api/getAllaccessions"); +}; /** * Show form if checked @@ -14,8 +41,7 @@ let fillFormSpot = document.getElementById('metadata_fill_form_spot'); function displayForm() { if (document.getElementById('metadata_form').checked) { fillFormSpot.classList.remove("invisible"); - } else { - fillFormSpot.classList.add("invisible"); - console.log("visible"); + return; } + fillFormSpot.classList.add("invisible"); } diff --git a/bh20simplewebuploader/templates/form.html b/bh20simplewebuploader/templates/form.html index e01b846..5d1e1b1 100644 --- a/bh20simplewebuploader/templates/form.html +++ b/bh20simplewebuploader/templates/form.html @@ -20,21 +20,29 @@

[Demo] Display content sequences by:

- - +
+ + + + +
+
- +
-
+ + +
-- cgit v1.2.3 From 3af1eb2aea430d0b421d7bf0c6e966badfec87d3 Mon Sep 17 00:00:00 2001 From: BonfaceKilz Date: Sun, 26 Apr 2020 06:52:54 +0300 Subject: Update styles to match suggested mockup Ref: https://xd.adobe.com/view/fa2b4841-e463-432e-7465-e96b4ed200ff-8c1a/screen/b84fcf66-9580-4ae2-b37d-7ee15401d627/Pangenome-Browser-Manual-Metadata-Host --- bh20simplewebuploader/static/main.css | 72 +++++++++++++++++++---- bh20simplewebuploader/templates/form.html | 95 +++++++++++++++++-------------- 2 files changed, 114 insertions(+), 53 deletions(-) diff --git a/bh20simplewebuploader/static/main.css b/bh20simplewebuploader/static/main.css index 20003f9..57e29ef 100644 --- a/bh20simplewebuploader/static/main.css +++ b/bh20simplewebuploader/static/main.css @@ -4,23 +4,24 @@ hr { body { color: #101010; - background-color: #F9EDE1; + background-color: #F5FFFF; margin: 0; } h1, h2, h3, h4 { - font-family: 'Roboto Slab', serif; - color: darkblue; + font-family: 'Inter', sans-serif; + color: #0ED1CD; } h1 { text-align: center; } -p { +.intro { color: #505050; - font-style: italic; + font-weight: 300; } + .header { background-color: white; margin: 0 auto; @@ -29,12 +30,17 @@ p { height: 150px; } +h2 > svg { + position: relative; + top: 8px; +} + .logo { float: right; } p, form, .about, .footer { - font-family: 'Raleway', sans-serif; + font-family: 'Inter', sans-serif; line-height: 1.5; } @@ -47,15 +53,17 @@ form h4 { } .intro { - background-color: lightgrey; + background-color: inherit; margin: 0 auto; padding: 20px; } .about { - background-color: lightgrey; - margin: 0 auto; + background-color: #B2F8F8; + margin: 30px auto; padding: 20px; + width: 95%; + border-radius: 20px; } .button { @@ -66,8 +74,13 @@ form h4 { } .footer { - background-color: white; + background: #058280;; margin: 0 auto; + color: #fff; +} + +.footer a { + color: #fff; } span.dropt {border-bottom: thin dotted; background: #ffeedd;} @@ -87,6 +100,21 @@ span.dropt:hover {text-decoration: none; background: #ffffff; z-index: 6; } 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; } @@ -96,6 +124,15 @@ span.dropt:hover {text-decoration: none; background: #ffffff; z-index: 6; } grid-area: b; } +a { + color: #40DBD8; + font-weight: 700; +} + +.fasta-file-select label, .metadata label { + font-weight: 600; +} + .metadata { padding: 1em; grid-area: c; @@ -179,9 +216,22 @@ footer { display: flex; flex-direction: row; flex-wrap: wrap; - justify-content: space-around; + 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; } diff --git a/bh20simplewebuploader/templates/form.html b/bh20simplewebuploader/templates/form.html index 5d1e1b1..ffd4158 100644 --- a/bh20simplewebuploader/templates/form.html +++ b/bh20simplewebuploader/templates/form.html @@ -2,7 +2,7 @@ - + Web uploader for Public SARS-CoV-2 Sequence Resource @@ -47,24 +47,35 @@
-

- Upload your SARS-CoV-2 sequence (FASTA or FASTQ formats) with metadata (JSONLD) to the public sequence resource. The upload will trigger a - recompute with all available sequences into a Pangenome - available for - download! - 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 here. All data is published under - a Creative - Commons 4.0 attribution license (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 REDCap. - A free command line version of the uploader can be - installed from source. -

+
+

+ Upload your SARS-CoV-2 sequence (FASTA or FASTQ formats) with metadata (JSONLD) to the public sequence resource. The upload will trigger a + recompute with all available sequences into a Pangenome + available for + download! +

+

+ 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 here. All data is published under + a Creative + Commons 4.0 attribution license (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 REDCap. + A free command line version of the uploader can be + installed from source. +

+ +
+

+ + + + Upload SARS-CoV-2 Sequence

+
@@ -138,37 +149,37 @@
-

-

ABOUT

-

- 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 project - repository. For more information see the paper (WIP). -

-
-
+
+

ABOUT

+

+ 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 project + repository. For more information see the paper (WIP). +

-
+
+
+ + + + + +
+ +
{% for record in fields %} @@ -103,6 +103,7 @@ {% endif %} {% endfor %}
+
-- cgit v1.2.3 From 13bcf6fcc911ffa717a86e368b190322b8065d3d Mon Sep 17 00:00:00 2001 From: BonfaceKilz Date: Sun, 26 Apr 2020 03:43:38 +0300 Subject: Add basic structure for interacting with the API --- bh20simplewebuploader/static/main.css | 26 ++++++++++++++++++++++++++ bh20simplewebuploader/templates/form.html | 22 +++++++++++++++++++++- 2 files changed, 47 insertions(+), 1 deletion(-) diff --git a/bh20simplewebuploader/static/main.css b/bh20simplewebuploader/static/main.css index 609ae19..94d38bf 100644 --- a/bh20simplewebuploader/static/main.css +++ b/bh20simplewebuploader/static/main.css @@ -57,6 +57,15 @@ form h4 { margin: 0 auto; padding: 20px; } + +.button { + width: 6em; + border-radius: 5px; + background: #0ED1CD; + margin: 0.3em auto; + padding: 0.4em; +} + .footer { background-color: white; margin: 0 auto; @@ -128,6 +137,22 @@ span.dropt:hover {text-decoration: none; background: #ffffff; z-index: 6; } 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; @@ -158,6 +183,7 @@ footer { .invisible { display: none; } + @media only screen and (max-device-width: 480px) { .grid-container { display: flex; diff --git a/bh20simplewebuploader/templates/form.html b/bh20simplewebuploader/templates/form.html index ea3caab..e01b846 100644 --- a/bh20simplewebuploader/templates/form.html +++ b/bh20simplewebuploader/templates/form.html @@ -15,7 +15,27 @@ Disabled until we got everything wired up
-
+ +
+
+

[Demo] Display content sequences by:

+ + + +
+ + +
+ +
+
-- cgit v1.2.3 From 72f9b2c96b2be87f028737957c3ab22be1ccea69 Mon Sep 17 00:00:00 2001 From: BonfaceKilz Date: Sun, 26 Apr 2020 05:25:35 +0300 Subject: Jsonify response and pick the values --- bh20simplewebuploader/main.py | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/bh20simplewebuploader/main.py b/bh20simplewebuploader/main.py index e88eb4c..53a4cda 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 @@ -358,7 +358,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,11 +369,12 @@ def getDetailsForSeq(): seq_id = request.args.get('seq') query="""SELECT DISTINCT ?key ?value WHERE { ?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 str(result) + return jsonify([{'uri': x['key']['value'], + 'value': x['value']['value']} for x in result]) + @app.route('/api/getSEQbytech', methods=['GET']) def getSEQbytech(): @@ -384,7 +386,9 @@ def getSEQbytech(): 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'], + 'Specimen Source': x['specimen_source']['value'], + 'Label': x['specimen_source_label']['value']} for x in result]) @app.route('/api/getSEQbyLocation', methods=['GET']) def getSEQbyLocation(): @@ -396,7 +400,10 @@ 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(): @@ -409,7 +416,9 @@ def getSEQbySpecimenSource(): 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'], + 'Specimen Source': x['specimen_source']['value'], + 'Label': x['specimen_source_label']['value']} for x in result]) #No data for this atm @app.route('/api/getSEQbyHostHealthStatus', methods=['GET']) @@ -423,4 +432,4 @@ def getSEQbyHostHealthStatus(): 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 + return str(result) -- cgit v1.2.3 From ad10d632b9ffb4433b696df374e77d9e932403d0 Mon Sep 17 00:00:00 2001 From: BonfaceKilz Date: Sun, 26 Apr 2020 05:26:18 +0300 Subject: Display the output of the queries as prettified JSON for now --- bh20simplewebuploader/static/main.css | 31 ++++++++++++++++++-- bh20simplewebuploader/static/main.js | 48 ++++++++++++++++++++++++------- bh20simplewebuploader/templates/form.html | 18 ++++++++---- 3 files changed, 79 insertions(+), 18 deletions(-) diff --git a/bh20simplewebuploader/static/main.css b/bh20simplewebuploader/static/main.css index 94d38bf..20003f9 100644 --- a/bh20simplewebuploader/static/main.css +++ b/bh20simplewebuploader/static/main.css @@ -42,7 +42,7 @@ form h4 { text-transform: 'uppercase'; } -.intro, form { +.intro, form, .search { padding: 20px; } @@ -59,7 +59,6 @@ form h4 { } .button { - width: 6em; border-radius: 5px; background: #0ED1CD; margin: 0.3em auto; @@ -120,6 +119,17 @@ span.dropt:hover {text-decoration: none; background: #ffffff; z-index: 6; } 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; @@ -180,10 +190,27 @@ footer { 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; diff --git a/bh20simplewebuploader/static/main.js b/bh20simplewebuploader/static/main.js index e8d4776..0f79fdf 100644 --- a/bh20simplewebuploader/static/main.js +++ b/bh20simplewebuploader/static/main.js @@ -1,11 +1,38 @@ -fetch(scriptRoot + "/api/getAllaccessions") - .then(response => { - return response.json(); - }) - .then(data => { - console.log('test'); - console.log(data); - }) +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/getSEQbySpecimenSource"); +} + +let fetchSEQByLocation = () => { + fetchAPI("/api/getSEQbyLocation"); +} + +let fetchSEQByTech = () => { + fetchAPI("/api/getSEQbytech"); +} + +let fetchAllaccessions = () => { + fetchAPI("/api/getAllaccessions"); +}; /** * Show form if checked @@ -14,8 +41,7 @@ let fillFormSpot = document.getElementById('metadata_fill_form_spot'); function displayForm() { if (document.getElementById('metadata_form').checked) { fillFormSpot.classList.remove("invisible"); - } else { - fillFormSpot.classList.add("invisible"); - console.log("visible"); + return; } + fillFormSpot.classList.add("invisible"); } diff --git a/bh20simplewebuploader/templates/form.html b/bh20simplewebuploader/templates/form.html index e01b846..5d1e1b1 100644 --- a/bh20simplewebuploader/templates/form.html +++ b/bh20simplewebuploader/templates/form.html @@ -20,21 +20,29 @@

[Demo] Display content sequences by:

- - +
+ + + + +
+
- +
-
+ + +
-- cgit v1.2.3 From 3416265c7431ebcc962f39781aa9fc60243bda3a Mon Sep 17 00:00:00 2001 From: BonfaceKilz Date: Sun, 26 Apr 2020 06:52:54 +0300 Subject: Update styles to match suggested mockup Ref: https://xd.adobe.com/view/fa2b4841-e463-432e-7465-e96b4ed200ff-8c1a/screen/b84fcf66-9580-4ae2-b37d-7ee15401d627/Pangenome-Browser-Manual-Metadata-Host --- bh20simplewebuploader/static/main.css | 72 +++++++++++++++++++---- bh20simplewebuploader/templates/form.html | 95 +++++++++++++++++-------------- 2 files changed, 114 insertions(+), 53 deletions(-) diff --git a/bh20simplewebuploader/static/main.css b/bh20simplewebuploader/static/main.css index 20003f9..57e29ef 100644 --- a/bh20simplewebuploader/static/main.css +++ b/bh20simplewebuploader/static/main.css @@ -4,23 +4,24 @@ hr { body { color: #101010; - background-color: #F9EDE1; + background-color: #F5FFFF; margin: 0; } h1, h2, h3, h4 { - font-family: 'Roboto Slab', serif; - color: darkblue; + font-family: 'Inter', sans-serif; + color: #0ED1CD; } h1 { text-align: center; } -p { +.intro { color: #505050; - font-style: italic; + font-weight: 300; } + .header { background-color: white; margin: 0 auto; @@ -29,12 +30,17 @@ p { height: 150px; } +h2 > svg { + position: relative; + top: 8px; +} + .logo { float: right; } p, form, .about, .footer { - font-family: 'Raleway', sans-serif; + font-family: 'Inter', sans-serif; line-height: 1.5; } @@ -47,15 +53,17 @@ form h4 { } .intro { - background-color: lightgrey; + background-color: inherit; margin: 0 auto; padding: 20px; } .about { - background-color: lightgrey; - margin: 0 auto; + background-color: #B2F8F8; + margin: 30px auto; padding: 20px; + width: 95%; + border-radius: 20px; } .button { @@ -66,8 +74,13 @@ form h4 { } .footer { - background-color: white; + background: #058280;; margin: 0 auto; + color: #fff; +} + +.footer a { + color: #fff; } span.dropt {border-bottom: thin dotted; background: #ffeedd;} @@ -87,6 +100,21 @@ span.dropt:hover {text-decoration: none; background: #ffffff; z-index: 6; } 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; } @@ -96,6 +124,15 @@ span.dropt:hover {text-decoration: none; background: #ffffff; z-index: 6; } grid-area: b; } +a { + color: #40DBD8; + font-weight: 700; +} + +.fasta-file-select label, .metadata label { + font-weight: 600; +} + .metadata { padding: 1em; grid-area: c; @@ -179,9 +216,22 @@ footer { display: flex; flex-direction: row; flex-wrap: wrap; - justify-content: space-around; + 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; } diff --git a/bh20simplewebuploader/templates/form.html b/bh20simplewebuploader/templates/form.html index 5d1e1b1..ffd4158 100644 --- a/bh20simplewebuploader/templates/form.html +++ b/bh20simplewebuploader/templates/form.html @@ -2,7 +2,7 @@ - + Web uploader for Public SARS-CoV-2 Sequence Resource @@ -47,24 +47,35 @@
-

- Upload your SARS-CoV-2 sequence (FASTA or FASTQ formats) with metadata (JSONLD) to the public sequence resource. The upload will trigger a - recompute with all available sequences into a Pangenome - available for - download! - 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 here. All data is published under - a Creative - Commons 4.0 attribution license (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 REDCap. - A free command line version of the uploader can be - installed from source. -

+
+

+ Upload your SARS-CoV-2 sequence (FASTA or FASTQ formats) with metadata (JSONLD) to the public sequence resource. The upload will trigger a + recompute with all available sequences into a Pangenome + available for + download! +

+

+ 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 here. All data is published under + a Creative + Commons 4.0 attribution license (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 REDCap. + A free command line version of the uploader can be + installed from source. +

+ +
+

+ + + + Upload SARS-CoV-2 Sequence

+
@@ -138,37 +149,37 @@
-

-

ABOUT

-

- 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 project - repository. For more information see the paper (WIP). -

-
-
+
+

ABOUT

+

+ 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 project + repository. For more information see the paper (WIP). +

-
+
+
+ + + + + +
+