Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add an Export page #566

Merged
merged 9 commits into from
Sep 10, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
41 changes: 41 additions & 0 deletions apps/port/export.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<!DOCTYPE html>
<html>
<head>
<script src="../../core/Store.js"></script>
<title>Export Results [caMicroscope]</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-iYQeCzEYFbKjA/T2uDLTpkwGzCiq6soy8tYaI1GyVh/UjpbCx/TYkiZhlZB6+fzT" crossorigin="anonymous">
<style>
body{
padding:20px;
}
#output{
padding: 20px;
}
span{
display:inline-block;
}
.form-check-input{
padding:5px !important;
}
</style>
</head>
<body>

<h1>Export Results</h1>
<div class="form">
<label for="slide_id">Slide Ids (exact matches, comma delimited):</label>
<input type="text" id="slide_id" name="slide_id"><br>

<button id="populate_btn" onclick="populateList()" type="button">Get List of Results</button>

</div>
<br><br>
<h3>Select Results</h3>
<div id="output"></div>
<button id="convert_btn" onclick="downloadResults()" type="button">Download Selected Results</button>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.1/dist/js/bootstrap.bundle.min.js" integrity="sha384-u1OknCvxWvY5kfmNBILK2hRnQC3Pr17a+RTT6rIHI7NnikvbZlHgTPOOmMi466C8" crossorigin="anonymous"></script>
<script src="//code.jquery.com/jquery.min.js"></script>
<script src="./tree_table.js"></script>
<script src="./export.js"></script>
</body>
</html>
156 changes: 156 additions & 0 deletions apps/port/export.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
const store = new Store('../../data/');

async function populateList() {
// clear any previous
document.getElementById('output').innerHTML = '';
console.log('populating list...');
nameField = 'name';
// get slide and associated result information
let slides = [];
let results = {};
let slideList = document.getElementById('slide_id').value;
slideList = slideList.replace(/\s+/g, '');
slideList = slideList.split(',');
for (let id of slideList) {
let slide = await store.getSlide(id);
slide = slide[0];
if (slide && slide['_id']) {
let s = {'id': slide['_id']['$oid'], 'name': slide['name'], 'type': 'slide', 'raw': slide};
console.log(s);
slides.push(s);
// get associated result types
r = [];
for (let a of await store.findMarkTypes(slide['_id']['$oid'], 'computer')) {
r.push({'id': a['_id']['analysis']['execution_id'], 'name': a['_id']['analysis']['name'], 'type': 'computer mark'});
}
for (let a of await store.findMarkTypes(slide['_id']['$oid'], 'human')) {
r.push({'id': a['_id']['analysis']['execution_id'], 'name': a['_id']['analysis']['name'], 'type': 'human mark'});
}
// todo -- is this right for heatmapType results?
for (let a of await store.findHeatmapType(slide['_id']['$oid'])) {
r.push({'id': a['provenance']['analysis']['execution_id'],
'name': a['provenance']['analysis']['execution_id'], 'type': 'heatmap'});
}
results[slide['_id']['$oid']] = r;
}
}

let headers = ['name', 'id', 'type'];
let t = document.createElement('table');
t.id = 'tree-table';
t.classList.add('table', 'table-hover', 'table-bordered');
// add headers
let table = document.createElement('tbody');
let headerTr = document.createElement('tr');
for (let z of headers) {
let th = document.createElement('th');
th.innerText = z || '?';
headerTr.appendChild(th);
}
// add select header special
let selectTh = document.createElement('th');
selectTh.innerText = 'Select';
headerTr.appendChild(selectTh);
table.append(headerTr);
// populate results
for (let x of slides) {
let parent = document.createElement('tr');
parent.setAttribute('data-id', x.id);
parent.setAttribute('data-parent', 0);
parent.setAttribute('data-level', 1);
for (let z of headers) {
let d = document.createElement('td');
d.innerText = x[z] || '?';
if (z==nameField) {
d.setAttribute('data-column', 'name');
}
parent.appendChild(d);
}
// add special checkbox
parentCheck = document.createElement('input');
parentCheck.classList.add('form-check-input');
parentCheck.type = 'checkbox';
parentCheck.indeterminate = true; // cool!
// TODO -- finish this. you'd want to add logic that sets this checkbox to true, false or indeterminate
// depending on children selection. also select/deselect all children on change of this.
// parent.appendChild(parentCheck);
table.appendChild(parent);
for (let y of results[x.id]) {
console.log(x.raw);
let child = document.createElement('tr');
child.setAttribute('data-id', x.id+'-'+y.id);
child.setAttribute('data-parent', x.id);
child.setAttribute('data-level', 2);
for (let z of headers) {
let d = document.createElement('td');
d.innerText = y[z] || '?';
if (z==nameField) {
d.setAttribute('data-column', 'name');
}
child.appendChild(d);
}
// special checkbox
childCheck = document.createElement('input');
childCheck.type = 'checkbox';
childCheck.classList.add('form-check-input');
childCheck.classList.add('result');
childCheck.setAttribute('data-target', x.id);
childCheck.setAttribute('data-self', y.id);
childCheck.setAttribute('data-slideInfo', JSON.stringify(x.raw));
childCheck.setAttribute('data-type', y.type);
childCheck.checked = true;
child.appendChild(childCheck);
table.appendChild(child);
}
}
t.appendChild(table);
document.getElementById('output').appendChild(t);
makeTreeTable('tree-table');
}

async function downloadResults() {
let checks = document.querySelectorAll('.result:checked');
let marks = [];
let heatmaps = [];
for (let c of checks) {
console.log(c.dataset);
let parentSlide = JSON.parse(checks[0].dataset.slideinfo);
if (c.dataset.type == 'human mark' || c.dataset.type == 'human mark') {
let mark = await store.getMarkByIds([c.dataset.self], c.dataset.target);
for (m of mark) {
m.provenance.image = parentSlide;
marks.push(m);
}
console.log(mark);
} else if (c.dataset.type == 'heatmap' ) {
let hm = await store.getHeatmap(c.dataset.parent, c.dataset.target);
for (h of hm) {
h.provenance.image = parentSlide;
heatmaps.push(h);
}
}
}
console.log(marks, heatmaps);
if (marks.length) {
var element = document.createElement('a');
element.setAttribute('href', 'data:application/json;charset=utf-8,' + encodeURIComponent(JSON.stringify(marks)));
element.setAttribute('download', 'camic_export_marks.json');
element.style.display = 'none';
document.body.appendChild(element);
element.click();
document.body.removeChild(element);
}
if (heatmaps.length) {
var element = document.createElement('a');
element.setAttribute('href', 'data:application/json;charset=utf-8,' + encodeURIComponent(JSON.stringify(heatmaps)));
element.setAttribute('download', 'camic_export_heatmaps.json');
element.style.display = 'none';
document.body.appendChild(element);
element.click();
document.body.removeChild(element);
}
// tell the user that data is missing
if (!heatmaps.length && !marks.length) {
alert('No data selected for download.');
}
}
2 changes: 1 addition & 1 deletion apps/port/index.html → apps/port/import.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<html>
<head>
<script src="../../core/Store.js"></script>
<script src="./port.js"></script>
<script src="./import.js"></script>
<script src="./xml2geo.js"></script>
<link rel="stylesheet" href="./style.css">
<title>Import and Export [caMicroscope]</title>
Expand Down
File renamed without changes.
64 changes: 64 additions & 0 deletions apps/port/tree_table.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
function makeTreeTable(id) {
var
$table = $('#' + id);
var rows = $table.find('tr');

rows.each(function(index, row) {
var
$row = $(row);
var level = $row.data('level');
var id = $row.data('id');
var $columnName = $row.find('td[data-column="name"]');
var children = $table.find('tr[data-parent="' + id + '"]');

if (children.length) {
var expander = $columnName.prepend('' +
'<span class="treegrid-expander glyphicon glyphicon-chevron-right">&#9660;</span>' +
'');

children.hide();

expander.on('click', function(e) {
var $target = $(e.target);
if ($target.hasClass('glyphicon-chevron-right')) {
$target
.removeClass('glyphicon-chevron-right')
.addClass('glyphicon-chevron-down');

children.show();
} else {
$target
.removeClass('glyphicon-chevron-down')
.addClass('glyphicon-chevron-right');

reverseHide($table, $row);
}
});
}

$columnName.prepend('' +
'<span class="treegrid-indent" style="width:' + 25 * level + 'px"></span>' +
'');
});

// Reverse hide all elements
reverseHide = function(table, element) {
var
$element = $(element);
var id = $element.data('id');
var children = table.find('tr[data-parent="' + id + '"]');

if (children.length) {
children.each(function(i, e) {
reverseHide(table, e);
});

$element
.find('.glyphicon-chevron-down')
.removeClass('glyphicon-chevron-down')
.addClass('glyphicon-chevron-right');

children.hide();
}
};
}
13 changes: 8 additions & 5 deletions apps/table.html
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,9 @@
<li class="nav-item link">
<a class="nav-link" href="./dev-workbench/workbench.html"> <i class="fas fa-pencil-ruler"></i> Workbench</a>
</li>
<li class="nav-item link">
<a class="nav-link" href="./port/export.html"> <i class="fas fa-solid fa-file-export"></i> Export</a>
</li>
<li class="nav-item link" style="font-family: sans-serif;">
<a class="nav-link" href="./signup/signup.html"> <i class="fas fa-user-plus"></i> Signup</a>
</li>
Expand Down Expand Up @@ -136,7 +139,7 @@ <h1 class="h1">caMicroscope</h1>
onclick="(()=>{location.reload();return false;})()"> <i class="fas fa-sync-alt"></i>
Reload</button>
</div>
<div>
<div>
<div id="slideUploadButton" class="btn-group float-right pl-md-2 pt-2">
<button type="button" class="btn btn-primary " data-bs-toggle="modal"
data-bs-target="#upload-dialog" onclick="hidePostButton(); hideCheckButton(); resetUploadForm();" > <i class="fas fa-upload"></i> Upload</button>
Expand All @@ -149,12 +152,12 @@ <h1 class="h1">caMicroscope</h1>
</div>
</div>
</div>


</div>
</div>
</div>



<div class="modal fade" id="upload-dialog" tabindex="-1" role="dialog"
Expand Down Expand Up @@ -285,7 +288,7 @@ <h5 class="modal-title" id="slideNameChangeModalLabel">Slide name change confirm
</div>
</div>
</div>
<!-- popup -->
<!-- popup -->
<div id="popup-container"></div>
</div>

Expand All @@ -295,7 +298,7 @@ <h5 class="modal-title" id="slideNameChangeModalLabel">Slide name change confirm
<footer class="text-center text-white bg-dark p-3">
<p class="p">Copyright © 2021 caMicroscope</p>
</footer>

<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0/dist/js/bootstrap.bundle.min.js" integrity="sha384-p34f1UUtsS3wqzfto5wAAmdvj+osOnFyQFpp4Ua3gs/ZVWx6oOypYoCJhGGScy+8" crossorigin="anonymous"></script>
<script src="./table.js"></script>
</body>
Expand Down