forked from PGScatalog/PGS_Catalog
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request PGScatalog#395 from fyvon/feature/client_validator
Feature/Pyodide metadata and scores validators
- Loading branch information
Showing
26 changed files
with
708 additions
and
10 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,4 +4,6 @@ | |
app.yaml | ||
pgs-catalog-cred.json | ||
.idea | ||
.vscode | ||
.vscode | ||
*.min.js | ||
*.min.css |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
from django.contrib import admin | ||
|
||
# Register your models here. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
from django.apps import AppConfig | ||
|
||
|
||
class ValidatorConfig(AppConfig): | ||
default_auto_field = 'django.db.models.BigAutoField' | ||
name = 'validator' |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
from django.db import models | ||
|
||
# Create your models here. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,123 @@ | ||
const pyworker = await import((on_gae)?'./py-worker.min.js':'./py-worker.js'); | ||
const asyncRun = pyworker.asyncRun; | ||
|
||
const validate_metadata = await fetch(new URL('../python/bin/validation_metadata.py', import.meta.url, null)).then(response => response.text()); | ||
let dirHandle; | ||
|
||
|
||
async function validateFile() { | ||
const fileInput = document.getElementById('myfile'); | ||
const file = fileInput.files[0]; | ||
|
||
if (file) { | ||
const spinner = document.getElementById('pgs_loading'); | ||
spinner.style.visibility = "visible"; | ||
|
||
const reader = new FileReader(); | ||
reader.onload = async function(event) { | ||
const fileContent = new Uint8Array(event.target.result); | ||
let context = { | ||
file_content: fileContent, | ||
file_name: file.name, | ||
dirHandle: dirHandle | ||
} | ||
const { results, error } = await asyncRun(validate_metadata, context); | ||
if(results){ | ||
console.log(results); | ||
spinner.style.visibility = "hidden"; | ||
showResults(results); | ||
} | ||
if(error){ | ||
console.error(error); | ||
spinner.style.visibility = "hidden"; | ||
showSystemError(error); | ||
} | ||
}; | ||
reader.readAsArrayBuffer(file); | ||
} | ||
} | ||
|
||
function report_items_2_html(reports_list) { | ||
let report = '<ul>'; | ||
$.each(reports_list, function(index, report_item){ | ||
let lines = '' | ||
if (report_item.lines) { | ||
let lines_label = (report_item.lines.length > 1) ? 'Lines' : 'Line'; | ||
lines = lines_label+": "+report_item.lines.join(',')+ ' → '; | ||
} | ||
let message = report_item.message; | ||
// Value highlighting | ||
message = message.replace(/"(.+?)"/g, "\"<b>$1</b>\""); | ||
// Leading space | ||
message = message.replace(/"<b>\s+/g, "\"<b><span class=\"pgs_color_red\">_</span>"); | ||
// Trailing space | ||
message = message.replace(/\s+<\/b>"/g, "<span class=\"pgs_color_red\">_</span></b>\""); | ||
// Column highlighting | ||
message = message.replace(/'(.+?)'/g, "\'<span class=\"pgs_color_1\">$1</span>\'"); | ||
report += "<li>"+lines+message+"</li>"; | ||
}); | ||
report += '</ul>'; | ||
return report; | ||
} | ||
|
||
function makeReportTable(data_spreadsheet_items, items_header){ | ||
let table_html = '<table class="table table-bordered" style="width:auto"><thead class="thead-light">'+ | ||
'<tr><th>Spreadsheet</th><th>'+items_header+'</th></tr>'+ | ||
'</thead><tbody>'; | ||
$.each(data_spreadsheet_items, function(spreadsheet, reports_list){ | ||
table_html += "<tr><td><b>"+spreadsheet+"</b></td><td>"; | ||
table_html += report_items_2_html(reports_list); | ||
table_html += '</td></tr>'; | ||
}); | ||
table_html += '</tbody></table>'; | ||
return table_html; | ||
} | ||
|
||
function showResults(results){ | ||
let data = JSON.parse(results); | ||
let status_style = (data.status === 'failed') ? '<i class="fa fa-times-circle pgs_color_red" style="font-size:18px"></i> Failed' : '<i class="fa fa-check-circle pgs_color_green" style="font-size:18px"></i> Passed'; | ||
let status_html = '<table class="table table-bordered table_pgs_h mb-4"><tbody>'+ | ||
' <tr><td>File validation</td><td>'+status_style+'</td></tr>'+ | ||
'</tbody></table>'; | ||
$('#check_status').html(status_html); | ||
// Error messages | ||
if (data.error) { | ||
let report = '<h5 class="mt-4"><i class="fa fa-times-circle pgs_color_red"></i> Error report</h5>' | ||
+ makeReportTable(data.error, 'Error message(s)'); | ||
$('#report_error').html(report); | ||
} else { | ||
$('#report_error').html(''); | ||
} | ||
// Warning messages | ||
if (data.warning) { | ||
let report = '<h5 class="mt-4"><i class="fa fa-exclamation-triangle pgs_color_amber"></i> Warning report</h5>' | ||
+ makeReportTable(data.warning, 'Warning message(s)'); | ||
$('#report_warning').html(report); | ||
} else { | ||
$('#report_warning').html(''); | ||
} | ||
// Other messages | ||
if (data.messages){ | ||
let report = ''; | ||
$.each(data.messages, function (index, message){ | ||
report = report + '<div class="alert alert-danger alert-dismissible">'+message+'</div>'+"\n"; | ||
}) | ||
$('#report_messages').html(report); | ||
} | ||
} | ||
|
||
function showSystemError(errors){ | ||
let status_html = '<div><b>File validation:</b> <i class="fa fa-times-circle-o pgs_color_red"></i> Failed</div>'; | ||
$('#check_status').html(status_html); | ||
let error_msg = (errors && errors !== '') ? errors : 'Internal error'; | ||
let error_html = '<div class="clearfix">'+ | ||
' <div class="mt-3 float_left pgs_note pgs_note_2">'+ | ||
' <div><b>Error:</b> '+error_msg+'</div>'+ | ||
' </div>'+ | ||
'</div>'; | ||
$('#report_error').html(error_html); | ||
} | ||
|
||
document.querySelector('#upload_btn').addEventListener('click', async () => { | ||
await validateFile(); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
// Adapted from https://github.com/EBISPOT/gwas-sumstats-tools-ssf-morph | ||
// This script is setting up a way to run Python scripts asynchronously in a web worker. It sends the Python script to the worker and sets up a callback to handle the result when the worker has finished executing the script. | ||
const pyodideWorker = new Worker(new URL((on_gae) ? "webworker.min.js" : "webworker.js", import.meta.url, null)); | ||
|
||
const callbacks = {}; | ||
|
||
pyodideWorker.onmessage = (event) => { | ||
const { id, ...data } = event.data; | ||
const onSuccess = callbacks[id]; | ||
delete callbacks[id]; | ||
onSuccess(data); | ||
}; | ||
//This id is incremented each time the function is invoked and is kept within the safe integer limit. | ||
|
||
|
||
const asyncRun = (() => { | ||
let id = 0; // identify a Promise | ||
return (script, context) => { | ||
// the id could be generated more carefully | ||
id = (id + 1) % Number.MAX_SAFE_INTEGER; | ||
return new Promise((onSuccess) => { | ||
callbacks[id] = onSuccess; | ||
pyodideWorker.postMessage({ | ||
...context, | ||
python: script, | ||
id, | ||
}); | ||
}); | ||
}; | ||
})(); | ||
|
||
export { asyncRun }; |
Oops, something went wrong.