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

Fix autocomplete studies #47

Merged
merged 16 commits into from
Nov 25, 2024
Merged
Show file tree
Hide file tree
Changes from 15 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions idr_gallery/static/idr_gallery/css/search_form_styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,12 @@
position: relative;
background-color: #ddd;
}
.studyThumb img:hover {
border: solid 3px #64a3e1;
}
.studyThumb .selected img {
border: solid 5px #64a3e1;
}
.imgLinks {
position: absolute;
background: transparent;
Expand Down
29 changes: 17 additions & 12 deletions idr_gallery/static/idr_gallery/omero_search_form.js
Original file line number Diff line number Diff line change
Expand Up @@ -168,14 +168,15 @@ async function getAutoCompleteResults(key, query, knownKeys, operator) {
let kvp_url = `${SEARCH_ENGINE_URL}resources/all/searchvalues/?` + params;
let urls = [kvp_url];

// We always check for Names...
// Need to load data from 2 end-points
let names_url = `${SEARCH_ENGINE_URL}resources/all/names/?value=${query}`;
// NB: Don't show auto-complete for Description yet - issues with 'equals' search
// if (key == "Any" || key == "description") {
// names_url += `&use_description=true`;
// }
urls.push(names_url);
// We check for Names if "Any"
if (key == "Any") {
let names_url = `${SEARCH_ENGINE_URL}resources/all/names/?value=${query}`;
// NB: Don't show auto-complete for Description yet - issues with 'equals' search
// if (key == "Any" || key == "description") {
// names_url += `&use_description=true`;
// }
urls.push(names_url);
}

const promises = urls.map((p) => fetch(p).then((rsp) => rsp.json()));
const responses = await Promise.all(promises);
Expand Down Expand Up @@ -783,6 +784,7 @@ class OmeroSearchForm {
submitSearch() {
console.log("Submit search...");
let query = this.getCurrentQuery();
console.log(JSON.stringify(query));
if (!this.validateQuery(query)) {
console.log("Form not valid");
return;
Expand Down Expand Up @@ -855,12 +857,15 @@ class OmeroSearchForm {
return `<li class="studyRow" data-name="${studyName}">
<div class="studyColumns">
<div class="caret"><i class="fa fa-caret-right"></i></div>
<div class="studyId">
<a href="${BASE_URL}webclient/?show=${objType}-${objId}" target="_blank">${studyId}</a></div>
<div class="studyId">${studyId}</div>
<div class="count">${count}</div>
<div class="studyName" title="${title}">${title}</div>
</div>
<div class="studyImages">
<div style="margin-left: 20px">
Images from study: <a href="${BASE_URL}webclient/?show=${objType}-${objId}" target="_blank" title="Open Study in webclient showing ALL images">
${studyName}</a>
</div>
<ul></ul>
<div class="studyImagesSpinner">
${SPINNER_SVG}
Expand Down Expand Up @@ -938,8 +943,8 @@ class OmeroSearchForm {
.map((img) => {
// Each thumbnail links to image viewer. Hover menu links to viewer (eye) and webclient (i)
return `<li class="studyThumb">
<a target="_blank" href="${BASE_URL}webclient/img_detail/${img.id}">
<img title="${img.name}" src="${BASE_URL}webclient/render_thumbnail/${img.id}/" loading="lazy" />
<a class="thumblink" data-image_id="${img.id}" data-image_name="${img.name}" target="_blank" href="${BASE_URL}webclient/img_detail/${img.id}">
<img data-image_id="${img.id}" data-image_name="${img.name}" title="${img.name}" src="${BASE_URL}webclient/render_thumbnail/${img.id}/" loading="lazy" />
</a>
<ul class="imgLinks">
<li title="Browse image metadata">
Expand Down
223 changes: 220 additions & 3 deletions idr_gallery/templates/idr_gallery/search.html
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,6 @@
max-height: 45px;
max-width: 45px;
}
table td {
white-space: nowrap;
}
.filterMessage {
font-size: 120%;
}
Expand All @@ -58,6 +55,108 @@
border-radius: 10px;
margin: 5px;
}

.close {
position: absolute;
right: 5px;
top: 5px;
z-index: 100;
font-size: 2rem;
padding: 2px 9px;
}
.scrollable {
position: absolute;
inset: 0;
overflow: auto;
height: 100%;
z-index: 0;
padding: 5px;
}
#kvp_popover {
margin: auto;
position: fixed;
margin-right: 15px;
margin-bottom: 15px;
width: 400px;
height: 65%;
overflow: auto;
box-shadow: 5px 4px 10px -5px #737373;
border: solid 1px black;
border-radius: 10px;
}
#kvp_popover_content {
color: hsl(210, 10%, 30%);
font-size: 12px;
background-color: hsl(220,20%,95%);
display: flex;
flex-direction: column;
z-index: 0;
}
#kvp_popover_content h2 {
font-size: 16px;
color: hsl(210, 10%, 30%);
inset: 0;
flex: auto 0 0;
margin: 10px;
}
#kvp_popover_content th h2 {
font-size: 15px;
margin: 0;
}
#kvp_popover_content a {
font-weight: normal;
}
#popover_links a {
font-weight: normal;
display: inline-block;
border: solid #ccc 1px;
padding: 5px;
border-radius: 10px;
background: rgba(256, 256, 256, 0.5);
}
#kvp_popover_content i.fas {
margin: 0 10px;
}
#popover_links {
flex: auto 0 0;
margin: 0 10px 10px 10px;
}
#popover_kvp {
flex: auto 1 1;
overflow: auto;
}

@media (max-width: 800px) {
#mypopover {
width: 100%;
}
}
.map_ann tbody tr {
background: hsl(220,20%,95%);
border: solid #ddd 1px;
}
.map_ann td, .map_ann th {
padding: 2px;
background-color: hsl(220,20%,95%);
width: 50%;
max-width: 100px;
overflow-wrap: break-word;
overflow: hidden;
}
.map_ann {
padding: 5px;
margin: 5px;
}
.map_ann table {
margin: 0;
}
.favion img {
border: 1px solid hsl(210, 8%, 65%);
box-shadow: 0 1px 0 rgba(255, 255, 255, 0.5);
vertical-align: middle;
width: 15px;
height: 15px;
}
</style>

<link rel="stylesheet" href="{% static 'idr_gallery/css/search_form_styles.css' %}?_={{VERSION}}" />
Expand Down Expand Up @@ -105,6 +204,15 @@

</div>

<div id="kvp_popover" popover>
<button class="close" popovertarget="kvp_popover">&times;</button>
<div id="kvp_popover_content" class="scrollable">
<h2 id="popover_imagename">Image Name</h2>
<div id="popover_links"></div>
<div id="popover_kvp"></div>
</div>
</div>

<script>
// Various global constants from omero config set...
var FILTER_KEYS = {{ filter_keys|safe }};
Expand Down Expand Up @@ -181,6 +289,115 @@
searchFromUrl();
});

$(".resultsList").on("click", "a.thumblink", function(event){
event.preventDefault();
document.getElementById("popover_kvp").innerHTML = `<div style='padding:10px'>Loading Attributes...</div>`;
document.getElementById("kvp_popover").showPopover();
let $thumb = $(event.target);
$(".studyThumb a").removeClass("selected");
$thumb.parents(".studyThumb").find("a").addClass("selected");

let image_id = event.target.dataset.image_id;
let image_name = event.target.dataset.image_name;
document.getElementById("popover_imagename").innerHTML = image_name;
let linkshtml = `
<div><a target="_blank" href="${BASE_URL}webclient/?show=image-${image_id}">
Browse image metadata<i class="fas fa-info"></i></a>
<a target="_blank" href="${BASE_URL}webclient/img_detail/${image_id}">
Open Image in Viewer<i class="fas fa-eye"></i></a></div>`
document.getElementById("popover_links").innerHTML = linkshtml;

let url = `${BASE_URL}webclient/api/annotations/?type=map&image=${image_id}`;
fetch(url)
.then(response => response.json())
.then(data => {
var experimenters = [];
if (data.experimenters.length > 0) {
// manipulate data...
// make an object of eid: experimenter
experimenters = data.experimenters.reduce(function(prev, exp){
prev[exp.id + ""] = exp;
return prev;
}, {});
}

var populate_experimenter = function(ann) {
if (data.experimenters.length > 0) {
ann.owner = experimenters[ann.owner.id];
}
if (ann.link && ann.link.owner) {
ann.link.owner = experimenters[ann.link.owner.id];
// AddedBy IDs for filtering
ann.addedBy = [ann.link.owner.id];
}
return ann;
};

// Populate experimenters within anns
var anns = data.annotations.map(populate_experimenter);

// Replace namespace with label
var ns2menu = {};
Object.entries(MAPR_CONFIG).forEach(([key, obj]) => {
ns2menu[obj.ns] = obj.label;
});

// Combine e.g. "Gene Identifier" and following "Gene Identifier URL" into one
anns = anns.map((ann, i) => {
ann.values = ann.values.map((kv, idx) => {
if (ann.values[idx + 1] && ann.values[idx + 1][0] === kv[0] + " URL") {
let url = ann.values[idx + 1][1];
// Add URL to kvp
kv = [...kv, url];
}
return kv;
});
ann.values = ann.values.filter((kv, idx) => {
// if the previous kvp have URL, skip this one
return !(idx > 0 && ann.values[idx - 1][2]);
});
return ann;
});

// Update html...
let html = anns.map(ann => {
return `
<div class="map_ann">
<table>
<thead>
<tr title="${ann.ns}">
<th colspan="2"><h2>${ns2menu[ann.ns] || ann.ns}</h2></th>
</tr>
</thead>
<tbody>
${ann.values.map(v => {
return `<tr>
<td>${v[0]}</td>
<td>
<a title="Search for images with ${v[0]}: ${v[1]}" href="/search/?key=${encodeURIComponent(v[0])}&value=${encodeURIComponent(v[1])}&operator=equals&resource=image">
${v[1]}
</a>
${v[2] ? `<span class='favicon'><a href="${v[2]}" target="_blank">
<img src="/mapr/favicon/?u=${v[2]}">
</a></span>` : ""}
</td>
</tr>`
}).join("")}
</tbody>
</table>
</div>`
});

document.getElementById("popover_kvp").innerHTML = html.join("\n");
});
});

// load mapr config at the start...
window.MAPR_CONFIG = {};
let maprConigUrl = `${BASE_URL}mapr/api/config/`;
fetch(maprConigUrl).then(response => response.json())
.then(data => {window.MAPR_CONFIG = data;});


window.onpopstate = (event) => {
console.log(`onpopstate location: ${document.location}, state: ${JSON.stringify(event.state)}`)
Expand Down
Loading