Skip to content

Commit

Permalink
Merge b287d63 into a36d01d
Browse files Browse the repository at this point in the history
  • Loading branch information
holtgrewe committed Feb 9, 2022
2 parents a36d01d + b287d63 commit 14a82bd
Show file tree
Hide file tree
Showing 13 changed files with 171 additions and 45 deletions.
2 changes: 2 additions & 0 deletions HISTORY.rst
Expand Up @@ -94,6 +94,8 @@ Full Change List
- Adding REST API versioning to (#333)
- Adding more postgres versions to CI (#337)
- Make migrations compatible with Postgres 14 (#338)
- DgvSvs and DgvGoldStandardSvs are two different data sources now
- Adding deep linking into case details tab (#344)

-------
v0.23.9
Expand Down
3 changes: 2 additions & 1 deletion importer/management/commands/import_tables.py
Expand Up @@ -63,7 +63,8 @@
"clinvar": (Clinvar,),
"dbSNP": (Dbsnp,),
"dbVar": (DbVarSv,),
"DGV": (DgvGoldStandardSvs, DgvSvs),
"DgvGoldStandardSvs": (DgvGoldStandardSvs,),
"DgvSvs": (DgvSvs,),
"ensembl_genes": (GeneInterval,),
"ensembl_regulatory": (EnsemblRegulatoryFeature,),
"ensembltogenesymbol": (EnsemblToGeneSymbol,),
Expand Down
2 changes: 1 addition & 1 deletion utility/install_chrome.sh
Expand Up @@ -5,7 +5,7 @@ echo "Installing Chrome + Driver for UI Testing"
echo "***********************************************"

# Version
CHROME_DRIVER_VERSION=96.0.4664.35
CHROME_DRIVER_VERSION=98.0.4758.80

# Install dependencies
sudo apt-get update
Expand Down
2 changes: 1 addition & 1 deletion utility/install_chrome_gitlab.sh
Expand Up @@ -5,7 +5,7 @@ echo "Installing Chrome + Driver for UI Testing"
echo "***********************************************"

# Version
CHROME_DRIVER_VERSION=96.0.4664.35
CHROME_DRIVER_VERSION=98.0.4758.80

# Install dependencies
apt-get -y install unzip libgconf-2-4 xvfb gtk2-engines-pixbuf
Expand Down
24 changes: 24 additions & 0 deletions varfish/static/css/project.css
Expand Up @@ -46,3 +46,27 @@
.fa-md {
font-size:0.8em;
}

.img-light-gray {
filter: invert(100%) sepia(0%) saturate(966%) hue-rotate(245deg) brightness(85%) contrast(83%);
}

.img-gray {
filter: invert(54%) sepia(0%) saturate(0%) hue-rotate(321deg) brightness(95%) contrast(89%);
}

.img-dark-gray {
filter: invert(23%) sepia(44%) saturate(0%) hue-rotate(190deg) brightness(61%) contrast(84%);
}

.img-red {
filter: invert(21%) sepia(61%) saturate(2501%) hue-rotate(341deg) brightness(94%) contrast(122%);
}

.img-gold {
filter: invert(57%) sepia(91%) saturate(1599%) hue-rotate(9deg) brightness(96%) contrast(101%);
}

.img-green {
filter: invert(51%) sepia(42%) saturate(6815%) hue-rotate(80deg) brightness(95%) contrast(95%);
}
50 changes: 33 additions & 17 deletions varfish/static/js/flags_comments.js
Expand Up @@ -296,28 +296,44 @@ function clickMultiVariantBookmark() {
}).done(function(data) {
if (data["message"] === "OK") {
$.each(rowIds, function(i, e) {
var iconBookmark = $(e).find(".variant-bookmark")
var iconComment = $(e).find(".variant-comment")
var d = data["flags"]
// update filter results
if (filter_or_case_details === "filter") {
var iconBookmark = $(e).find(".variant-bookmark")
var iconComment = $(e).find(".variant-comment")

if (d["flag_bookmarked"] || d["flag_for_validation"] || d["flag_candidate"] || d["flag_final_causative"]) {
iconBookmark.attr("src", "/icons/fa-solid/bookmark.svg");
} else {
iconBookmark.attr("src", "/icons/fa-regular/bookmark.svg");
}

if (d["flag_bookmarked"] || d["flag_for_validation"] || d["flag_candidate"] || d["flag_final_causative"]) {
iconBookmark.attr("src", "/icons/fa-solid/bookmark.svg");
} else {
iconBookmark.attr("src", "/icons/fa-regular/bookmark.svg");
}

if (data["comment"]) {
iconComment.attr("src", "/icons/fa-solid/comment.svg");
}
if (data["comment"]) {
iconComment.attr("src", "/icons/fa-solid/comment.svg");
}

$(e).removeClass("variant-row-positive variant-row-uncertain variant-row-negative variant-row-empty variant-row-wip");
$(e).addClass("variant-row-" + summarizeFlags(d));
if (structural_or_small === "small") {
let dtrow = dt.row($(e));
if (dtrow.child() && dtrow.child().length) {
loadVariantDetails(dtrow, cell);
$(e).removeClass("variant-row-positive variant-row-uncertain variant-row-negative variant-row-empty variant-row-wip");
$(e).addClass("variant-row-" + summarizeFlags(d));
if (structural_or_small === "small") {
let dtrow = dt.row($(e));
if (dtrow.child() && dtrow.child().length) {
loadVariantDetails(dtrow, cell);
}
}
}
else { // case_details
// update case detail page
var flags = ["bookmarked", "for_validation", "candidate", "final_causative", "disease_association", "segregates", "doesnt_segregate"]
$.each(flags, function (flag) {
if (d["flag_" + flag]) {
$(e + "-flag-" + flag).addClass("img-dark-gray")
$(e + "-flag-" + flag).removeClass("img-light-gray")
} else {
$(e + "-flag-" + flag).removeClass("img-dark-gray")
$(e + "-flag-" + flag).addClass("img-light-gray")
}
})
}
});
}
}).fail(function(xhr) {
Expand Down
5 changes: 4 additions & 1 deletion variants/queries.py
Expand Up @@ -1849,7 +1849,10 @@ def chunks(lst, n=50):
return AnnotatedSmallVariants(
small_variants=list(SmallVariant.objects.filter(id__in=small_var_ids)),
small_variant_flags=list(SmallVariantFlags.objects.filter(id__in=flags_ids)),
small_variant_comments=list(SmallVariantComment.objects.filter(id__in=comments_ids)),
# for some reason, ordering in the model has no effect.
small_variant_comments=list(
SmallVariantComment.objects.filter(id__in=comments_ids).order_by("date_created")
),
acmg_criteria_rating=list(AcmgCriteriaRating.objects.filter(id__in=ratings_ids)),
)

Expand Down
71 changes: 52 additions & 19 deletions variants/templates/variants/case/detail_annotation.html
Expand Up @@ -14,6 +14,16 @@ <h4>

<div class="float-right">
<div class="dropdown">
<button type="button" id="multiVarButton" class="btn btn-outline-secondary dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<i class="iconify" data-icon="fluent:bookmark-multiple-16-filled"></i> Multi-Variant Options
</button>
<div class="dropdown-menu dropdown-menu-left" style="z-index: 1031;">
<a class="dropdown-item" id="multivar-bookmark-comment" data-toggle="modal" data-target="#multiVarBookmarkCommentModal">
<i class="iconify" data-icon="fluent:bookmark-multiple-16-filled"></i> Flag & Comment
</a>
</div>
</div>
<div class="dropdown pl-2">
<button class="btn btn-secondary dropdown-toggle" type="button" data-toggle="dropdown">
<i class="iconify" data-icon="fa-solid:cloud-download-alt"></i>
Download
Expand All @@ -32,9 +42,10 @@ <h4>
</div>
</h4>
</div>
<table class="table table-striped table-hover">
<table class="table table-striped table-hover table-sm" style="width: 100%">
<thead>
<tr>
<th rowspan="2"></th>
<th style="width: 200px;" rowspan="2" class="text-center align-text-top"><div class="sodar-overflow-container sodar-overflow-hover">Variant</div></th>
<th style="width: 80px;" rowspan="2" class="text-center align-text-top"><div class="sodar-overflow-container sodar-overflow-hover">Gene(s) / Effect(s)</div></th>
<th rowspan="2" class="text-center align-text-top">ACMG Rating</th>
Expand All @@ -44,44 +55,49 @@ <h4>
</tr>
<tr>
<th class="text-center">Generic</th>
<th class="text-center">Visual</th>
<th class="text-center">Molecular</th>
<th class="text-center">Validation</th>
<th class="text-center">Phenotype</th>
<th class="text-center">Summary</th>
<th class="text-center" data-toggle="tooltip" data-title="Visual">Vis.</th>
<th class="text-center" data-toggle="tooltip" data-title="Molecular">Mol.</th>
<th class="text-center" data-toggle="tooltip" data-title="Validation">Val.</th>
<th class="text-center" data-toggle="tooltip" data-title="Phenotype">Phe.</th>
<th class="text-center" data-toggle="tooltip" data-title="Summary">Sum.</th>
</tr>
</thead>
<tbody>
{% for data in commentsflags.values %}
<tr id="flags-{{ var_id }}">
<td class="text-nowrap">
<div class="sodar-overflow-container sodar-overflow-hover" style="max-width: 200px;">
<tr id="flags-{{ data.variants.0|smallvar_description }}">
<td>
<input type="checkbox" value="{{ data.variants.0|smallvar_description }}" class="multivar-selector" data-case="{{ case.sodar_uuid }}">
</td>
<td style="max-width: 100px;">
<div class="sodar-overflow-container sodar-overflow-hover">
{{ data.variants.0.human_readable }}
</div>
</td>
<td>
<td style="max-width: 100px;">
<div class="sodar-overflow-container sodar-overflow-hover">
{% for variant in data.variants %}
{{ gene_id_to_symbol|keyvalue:variant.refseq_gene_id }}:{{ variant.refseq_hgvs_p|default:variant.refseq_hgvs_c|default:"-" }}{% if not forloop.last %},{% endif %}
{% endfor %}
</div>
</td>
<td class="text-center">
{% if data.acmg_rating %}
<span class="{{ data.acmg_rating|acmg_badge_class2 }}">
{{ data.acmg_rating|acmg_classification2 }}
</span>
{% else %}
<p class="text-muted font-italic">No ACMG rating.</p>
<p class="text-muted font-italic">None</p>
{% endif %}
</td>
{% if data.flags %}
<td class="text-center">
<i class="iconify {% if not data.flags.flag_bookmarked %}text-muted" style="opacity: 0.3{% endif %}" data-icon="fa-solid:star"></i>
<i class="iconify {% if not data.flags.flag_for_validation %}text-muted" style="opacity: 0.3{% endif %}" data-icon="fa-solid:flask"></i>
<i class="iconify {% if not data.flags.flag_candidate %}text-muted" style="opacity: 0.3{% endif %}" data-icon="fa-solid:heart"></i>
<i class="iconify {% if not data.flags.flag_final_causative %}text-muted" style="opacity: 0.3{% endif %}" data-icon="fa-solid:flag-checkered"></i>
<i class="iconify {% if not data.flags.flag_no_disease_association %}text-muted" style="opacity: 0.3{% endif %}" data-icon="cli:link-broken"></i>
<i class="iconify {% if not data.flags.flag_segregates %}text-muted" style="opacity: 0.3{% endif %}" data-icon="fa-solid:thumbs-up"></i>
<i class="iconify {% if not data.flags.flag_doesnt_segregate %}text-muted" style="opacity: 0.3{% endif %}" data-icon="fa-solid:thumbs-down"></i>
<img id="{{ case.sodar_uuid }}-{{ data.variants.0|smallvar_description }}-flag_bookmarked" class="img-{% if data.flags.flag_bookmarked %}dark{% else %}light{% endif %}-gray" src="/icons/fa-solid/star.svg" />
<img id="{{ case.sodar_uuid }}-{{ data.variants.0|smallvar_description }}-flag_for_validation" class="img-{% if data.flags.flag_for_validation %}dark{% else %}light{% endif %}-gray" src="/icons/fa-solid/flask.svg" />
<img id="{{ case.sodar_uuid }}-{{ data.variants.0|smallvar_description }}-flag_candidate" class="img-{% if data.flags.flag_candidate %}dark{% else %}light{% endif %}-gray" src="/icons/fa-solid/heart.svg" />
<img id="{{ case.sodar_uuid }}-{{ data.variants.0|smallvar_description }}-flag_final_causative" class="img-{% if data.flags.flag_final_causative %}dark{% else %}light{% endif %}-gray" src="/icons/fa-solid/flag-checkered.svg" />
<img id="{{ case.sodar_uuid }}-{{ data.variants.0|smallvar_description }}-flag_disease_association" class="img-{% if data.flags.flag_no_disease_association %}dark{% else %}light{% endif %}-gray" src="/icons/cil/link-broken.svg" />
<img id="{{ case.sodar_uuid }}-{{ data.variants.0|smallvar_description }}-flag_segregates" class="img-{% if data.flags.flag_segregates %}dark{% else %}light{% endif %}-gray" src="/icons/fa-solid/thumbs-up.svg" />
<img id="{{ case.sodar_uuid }}-{{ data.variants.0|smallvar_description }}-flag_doesnt_segregate" class="img-{% if data.flags.flag_doesnt_segregate %}dark{% else %}light{% endif %}-gray" src="/icons/fa-solid/thumbs-down.svg" />
</td>
<td class="text-center">
<i class="iconify {{ data.flags.flag_visual|flag_value_to_color }}" data-icon="{{ data.flags.flag_visual|flag_value_to_fa }}"></i>
Expand All @@ -107,7 +123,6 @@ <h4>
data-url-submit="{% url 'variants:small-variant-comment-api' project=project.sodar_uuid case=object.sodar_uuid %}"
data-url-delete="{% url 'variants:small-variant-comment-delete-api' project=project.sodar_uuid case=object.sodar_uuid %}">
{% for comment in data.comments %}
{{ comment }}
<li class="list-group-item list-item" id="comment-{{ comment.sodar_uuid }}" data-sodar-uuid="{{ comment.sodar_uuid }}">
<div id="display-comment-{{ comment.sodar_uuid }}">
<span class="small text-muted">
Expand Down Expand Up @@ -175,6 +190,24 @@ <h4>
</tbody>
</table>
</div>

{# Multi-var bookmark and comment modal #}
<div class="modal fade" id="multiVarBookmarkCommentModal" aria-hidden="true">
<div class="modal-dialog" style="width: 434px" role="document">
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title">Multi-Variant Comments &amp; Flags</h4>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<div class="container-fluid" id="multiVarBookmarkCommentModalContent">
</div>
</div>
</div>
</div>
</div>
</div>

{% if svs_enabled %}
Expand Down
33 changes: 33 additions & 0 deletions variants/templates/variants/case_detail.html
Expand Up @@ -133,6 +133,32 @@ <h2 class="sodar-pr-content-title">
{% block javascript %}
{{ block.super }}
<script type="text/javascript">

// Properly open tabs.
$(document).ready(() => {
let url = location.href.replace(/\/$/, "");

if (location.hash) {
const hash = url.split("#");
$('#case-tab a[href="#'+hash[1]+'"]').tab("show");
history.replaceState(null, null, url);
setTimeout(() => {
$(window).scrollTop(0);
}, 400);
}

$('a[data-toggle="tab"]').on("click", function() {
let newUrl;
const hash = $(this).attr("href");
if(hash == "#home") {
newUrl = url.split("#")[0];
} else {
newUrl = url.split("#")[0] + hash;
}
history.replaceState(null, null, newUrl);
});
});

// Load data after the page has loaded
$(function() {
axios.get("/variants/{{ object.project.sodar_uuid }}/case/api-qc/{{ object.sodar_uuid }}/")
Expand All @@ -150,7 +176,13 @@ <h2 class="sodar-pr-content-title">
</script>
<script type="text/javascript" src="{% static 'js/qc_plots.js' %}"></script>
<script type="text/javascript" src="{% static 'js/helpers.js' %}"></script>
<script type="text/javascript">
var structural_or_small = "small";
var multi_variant_flags_comment_url = "{% url 'variants:multi-small-variant-flags-comment-api' project=project.sodar_uuid %}";
var filter_or_case_details = "case_details";
</script>
<script type="text/javascript" src="{% static 'js/variant_comments.js' %}"></script>
<script type="text/javascript" src="{% static 'js/flags_comments.js' %}"></script>
<script type="text/javascript">
$(document).ready(function() {
$("#comment-button-submit").on("click", commentSubmit);
Expand All @@ -163,4 +195,5 @@ <h2 class="sodar-pr-content-title">
updateCaseCommentsCount();
});
</script>
{% include "variants/_multi_variant_flag_form_tpl.html" %}
{% endblock %}
4 changes: 2 additions & 2 deletions variants/templates/variants/filter_result/row.html
Expand Up @@ -33,8 +33,8 @@
{% if not training_mode %}
<td style="width: 0px" class="bookmark pl-0 pr-0 text-nowrap">
<a style="text-decoration: none" class="variant-bookmark-comment-group" data-variant="{{ entry|smallvar_description }}" data-project="{{ project.sodar_uuid }}" data-case="{{ entry.case_uuid }}">
<img class="variant-bookmark" style="filter: invert(54%) sepia(0%) saturate(0%) hue-rotate(321deg) brightness(95%) contrast(89%);" src="/icons/fa-{% if entry.flag_count %}solid{% else %}regular{% endif %}/bookmark.svg" />
<img class="variant-comment" style="filter: invert(54%) sepia(0%) saturate(0%) hue-rotate(321deg) brightness(95%) contrast(89%);;" src="/icons/fa-{% if entry.comment_count %}solid{% else %}regular{% endif %}/comment.svg" />
<img class="variant-bookmark img-gray" src="/icons/fa-{% if entry.flag_count %}solid{% else %}regular{% endif %}/bookmark.svg" />
<img class="variant-comment img-gray" src="/icons/fa-{% if entry.comment_count %}solid{% else %}regular{% endif %}/comment.svg" />
</a>
<span class="{{ entry|acmg_badge_class }} variant-acmg" style="width: 22px; display: inline-block"
data-variant="{{ entry|smallvar_description }}" data-project="{{ project.sodar_uuid }}" data-case="{{ entry.case_uuid }}">
Expand Down
1 change: 1 addition & 0 deletions variants/templates/variants/scripts.html
Expand Up @@ -4,6 +4,7 @@
/* This script has the purpose of dynamically rendering the django template variables that we require in JavaScript.
*/
var structural_or_small = "small";
var filter_or_case_details = "filter";
var variant_flags_url = "{% url 'variants:small-variant-flags-api' project=project.sodar_uuid case="--abcef--" %}";
var variant_comment_url = "{% url 'variants:small-variant-comment-api' project=project.sodar_uuid case="--abcef--" %}";
var multi_variant_flags_comment_url = "{% url 'variants:multi-small-variant-flags-comment-api' project=project.sodar_uuid %}";
Expand Down
13 changes: 13 additions & 0 deletions variants/templatetags/variants_tags.py
Expand Up @@ -215,11 +215,24 @@ def flag_value_to_fa(value):
}


FLAG_VALUE_TO_IMG_COLOR = {
"positive": "img-red",
"uncertain": "img-gold",
"negative": "img-green",
"empty": "img-gray",
}


@register.filter
def flag_value_to_color(value):
return FLAG_VALUE_TO_COLOR.get(value, "")


@register.filter
def flag_value_to_img_color(value):
return FLAG_VALUE_TO_IMG_COLOR.get(value, "")


CASE_STATUS_TO_COLOR = {
"initial": "secondary",
"active": "info",
Expand Down
6 changes: 3 additions & 3 deletions variants/tests/test_ui.py
Expand Up @@ -713,7 +713,7 @@ def test_variant_filter_case_multi_bookmark_one_variant(self):
WebDriverWait(self.selenium, self.wait_time).until(
wait_for_element_endswith_value(
selectors[0].find_element_by_xpath(
"../following-sibling::td[contains(@class, 'bookmark')]/a/img[@class='variant-bookmark']"
"../following-sibling::td[contains(@class, 'bookmark')]/a/img[contains(@class, 'variant-bookmark')]"
),
"src",
"/icons/fa-solid/bookmark.svg",
Expand All @@ -723,7 +723,7 @@ def test_variant_filter_case_multi_bookmark_one_variant(self):
WebDriverWait(self.selenium, self.wait_time).until(
wait_for_element_endswith_value(
selectors[1].find_element_by_xpath(
"../following-sibling::td[contains(@class, 'bookmark')]/a/img[@class='variant-bookmark']"
"../following-sibling::td[contains(@class, 'bookmark')]/a/img[contains(@class, 'variant-bookmark')]"
),
"src",
"/icons/fa-solid/bookmark.svg",
Expand All @@ -733,7 +733,7 @@ def test_variant_filter_case_multi_bookmark_one_variant(self):
self.assertTrue(
selectors[2]
.find_element_by_xpath(
"../following-sibling::td[contains(@class, 'bookmark')]/a/img[@class='variant-bookmark']"
"../following-sibling::td[contains(@class, 'bookmark')]/a/img[contains(@class, 'variant-bookmark')]"
)
.get_attribute("src")
.endswith("/icons/fa-regular/bookmark.svg")
Expand Down

0 comments on commit 14a82bd

Please sign in to comment.