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

Sanger feedback #4345

Closed
wants to merge 85 commits into from
Closed
Show file tree
Hide file tree
Changes from 10 commits
Commits
Show all changes
85 commits
Select commit Hold shift + click to select a range
b6ba007
Modal works nicely
Jan 15, 2024
a6e8256
Merge branch 'main' of https://github.com/Clinical-Genomics/scout int…
Jan 15, 2024
0bb5f1e
Remove unused code
Jan 15, 2024
e0004e6
Fixed form name
Jan 15, 2024
08e33df
Merge branch 'main' of https://github.com/Clinical-Genomics/scout int…
Jan 16, 2024
b961bdf
All works as it should
Jan 16, 2024
3c7e35b
Isort correctly one file
Jan 16, 2024
18930ae
Link rel noopener
Jan 16, 2024
e87050c
Updated changelog
Jan 16, 2024
e617a57
Fix potentia bug
Jan 16, 2024
1e4723c
Fix code style issues with Black
lint-action Jan 16, 2024
058730d
Fixed another couple of things
Jan 16, 2024
348dff0
Merge branch 'sanger_feedback' of https://github.com/Clinical-Genomic…
Jan 16, 2024
7be1509
Forgot to add a file
Jan 16, 2024
547f80b
Add new test for new adapter function
Jan 16, 2024
b596822
Add a test for cases.mark_validation
Jan 16, 2024
f924833
Merge branch 'main' into sanger_feedback
northwestwitch Jan 16, 2024
bc852b9
Added final test
Jan 16, 2024
710cd21
Merge branch 'sanger_feedback' of https://github.com/Clinical-Genomic…
Jan 16, 2024
a8616ae
Simplify logic
Jan 17, 2024
fb12630
Merge branch 'main' into sanger_feedback
northwestwitch Jan 17, 2024
10adb97
Merge branch 'main' into sanger_feedback
northwestwitch Jan 17, 2024
61e6743
Merge branch 'main' into sanger_feedback
northwestwitch Jan 19, 2024
9f683f5
Merge branch 'main' into sanger_feedback
dnil Jan 19, 2024
e574e96
Merge branch 'main' into sanger_feedback
northwestwitch Jan 19, 2024
18504f7
Merge branch 'main' into sanger_feedback
northwestwitch Jan 22, 2024
d0c9898
Merge branch 'main' into sanger_feedback
northwestwitch Jan 22, 2024
cb3a96b
Merge branch 'main' into sanger_feedback
dnil Jan 24, 2024
68601a4
Merge branch 'main' into sanger_feedback
northwestwitch Jan 24, 2024
ca41397
Merge branch 'main' into sanger_feedback
northwestwitch Jan 24, 2024
bfc3ad0
Merge branch 'main' into sanger_feedback
northwestwitch Jan 24, 2024
90f0918
Merge branch 'main' into sanger_feedback
dnil Jan 25, 2024
257c8ae
Merge branch 'main' into sanger_feedback
northwestwitch Jan 26, 2024
1ca0cc7
Merge branch 'main' into sanger_feedback
northwestwitch Jan 26, 2024
d154eca
Merge branch 'main' into sanger_feedback
northwestwitch Jan 29, 2024
2dd1674
Merge branch 'main' into sanger_feedback
northwestwitch Jan 30, 2024
610b7a9
Merge branch 'main' into sanger_feedback
northwestwitch Jan 30, 2024
266edf5
Merge branch 'main' into sanger_feedback
northwestwitch Jan 31, 2024
90b5695
Merge branch 'main' into sanger_feedback
dnil Jan 31, 2024
600bf99
Merge branch 'main' into sanger_feedback
northwestwitch Feb 1, 2024
37bcbd6
Merge branch 'main' into sanger_feedback
northwestwitch Feb 1, 2024
2895a3f
Merge branch 'main' into sanger_feedback
northwestwitch Feb 2, 2024
0903be4
Merge branch 'main' into sanger_feedback
northwestwitch Feb 2, 2024
c094d75
Merge branch 'main' into sanger_feedback
northwestwitch Feb 5, 2024
6f4f74d
Merge branch 'main' into sanger_feedback
northwestwitch Feb 7, 2024
b411247
Merge branch 'main' into sanger_feedback
northwestwitch Feb 7, 2024
a54805b
Merge branch 'main' into sanger_feedback
northwestwitch Feb 8, 2024
fe45880
Merge branch 'main' into sanger_feedback
northwestwitch Feb 8, 2024
cdf0380
Merge branch 'main' into sanger_feedback
dnil Feb 9, 2024
a6fb494
Merge branch 'main' into sanger_feedback
dnil Feb 9, 2024
a550c4c
Merge branch 'main' into sanger_feedback
dnil Feb 12, 2024
689d220
Merge branch 'main' into sanger_feedback
TereseBo Feb 15, 2024
15ad41f
Merge branch 'main' into sanger_feedback
northwestwitch Feb 16, 2024
bba4f91
Merge branch 'main' into sanger_feedback
northwestwitch Feb 19, 2024
b7ef51b
Merge branch 'main' into sanger_feedback
dnil Feb 19, 2024
69a3b51
Merge branch 'main' into sanger_feedback
northwestwitch Feb 19, 2024
7931a7d
Merge branch 'main' into sanger_feedback
northwestwitch Feb 19, 2024
ebd11f8
Merge branch 'main' into sanger_feedback
dnil Feb 19, 2024
591f61d
Merge branch 'main' into sanger_feedback
northwestwitch Feb 19, 2024
345f07e
Merge branch 'main' into sanger_feedback
dnil Feb 20, 2024
9c0a4a8
Merge branch 'main' into sanger_feedback
dnil Feb 20, 2024
fbc581c
Merge branch 'main' into sanger_feedback
dnil Feb 20, 2024
cebb0f7
Merge branch 'main' into sanger_feedback
dnil Feb 20, 2024
a1c63cd
Merge branch 'main' into sanger_feedback
northwestwitch Feb 20, 2024
8be3fea
Merge branch 'main' into sanger_feedback
TereseBo Feb 20, 2024
d180249
Merge branch 'main' into sanger_feedback
northwestwitch Feb 20, 2024
6dac315
Merge branch 'main' into sanger_feedback
dnil Feb 21, 2024
2f03a64
Merge branch 'main' into sanger_feedback
dnil Feb 21, 2024
dab23fd
Merge branch 'main' into sanger_feedback
northwestwitch Feb 27, 2024
22cdd1b
Merge branch 'main' into sanger_feedback
northwestwitch Feb 27, 2024
81fab78
Merge branch 'main' into sanger_feedback
northwestwitch Feb 28, 2024
c4f1736
Merge branch 'main' into sanger_feedback
northwestwitch Feb 28, 2024
8db399c
Merge branch 'main' into sanger_feedback
dnil Feb 29, 2024
177b025
Merge branch 'main' into sanger_feedback
TereseBo Mar 1, 2024
4d049aa
Merge branch 'main' into sanger_feedback
TereseBo Mar 4, 2024
bbd58be
Merge branch 'main' into sanger_feedback
TereseBo Mar 4, 2024
2bee21c
Merge branch 'main' into sanger_feedback
dnil Mar 4, 2024
a0d68b6
Merge branch 'main' into sanger_feedback
northwestwitch Mar 5, 2024
a8d3cce
Merge branch 'main' into sanger_feedback
northwestwitch Mar 5, 2024
84c1dda
Merge branch 'main' into sanger_feedback
dnil Mar 5, 2024
3cac301
Merge branch 'main' into sanger_feedback
northwestwitch Mar 5, 2024
9e4d891
Merge branch 'main' into sanger_feedback
northwestwitch Mar 7, 2024
23fec9e
Merge branch 'main' into sanger_feedback
dnil Mar 7, 2024
a22585d
Merge branch 'main' into sanger_feedback
dnil Mar 8, 2024
987ad80
Merge branch 'main' into sanger_feedback
TereseBo Mar 11, 2024
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ About changelog [here](https://keepachangelog.com/en/1.0.0/)
## [unreleased]
### Added
- Pydantic validation of image paths provided in case load config file
- Sanger recipient may send an alert to the user which ordered the verification when a variant is flagged as true positive
### Changed
- Revel score, Revel rank score and SpliceAI values are also displayed in Causatives and Validated variants tables
- Remove unused functions and tests
Expand Down
14 changes: 14 additions & 0 deletions scout/adapter/mongo/user.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# -*- coding: utf-8 -*-
import logging
from typing import Optional

import pymongo
from pymongo.errors import DuplicateKeyError
Expand Down Expand Up @@ -100,3 +101,16 @@ def delete_user(self, email):
LOG.info("Deleting user %s", email)
result = self.user_collection.delete_one({"email": email})
return result

def update_users_verified_positives(
self, user_id: str, variant_info: dict, add: bool = True
) -> Optional[dict]:
"""Update the list of links to the variants for which the user has ordered verification and turned out to be true positives."""
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
"""Update the list of links to the variants for which the user has ordered verification and turned out to be true positives."""
"""Update the list of links to the variants for which the user has ordered verification and has then changed status."""

A False positive would very possibly trigger some action as well, depending on the institutes workflow..

if add:
return self.user_collection.find_one_and_update(
{"_id": user_id}, {"$addToSet": {"validated_positive_variants": variant_info}}
)
else:
return self.user_collection.find_one_and_update(
{"_id": user_id}, {"$pull": {"validated_positive_variants": variant_info}}
)
18 changes: 17 additions & 1 deletion scout/adapter/mongo/variant_events.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import logging
from collections import Counter
from typing import Any, Dict, List
from typing import Dict, List, Optional

import pymongo

Expand Down Expand Up @@ -214,6 +214,22 @@ def sanger_ordered(
sanger_ordered = [item for item in results]
return sanger_ordered

def sanger_ordered_by(self, institute_id: str, case_id: str, variant_id: str) -> Optional[str]:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

"""retrieve the id of a user which ordered the Sanger verification of a variant."""

query = {
"verb": "sanger",
"institute": institute_id,
"case": case_id,
"variant_id": variant_id,
}
projection = {"_id": 0, "user_id": 1}
result: dict = self.event_collection.find_one(
query, projection, sort=[("created_at", pymongo.DESCENDING)]
)
if result:
return result["user_id"]

def validated(
self, institute_id: str = None, user_id: str = None, case_id: str = None
) -> List[Dict[str, List]]:
Expand Down
12 changes: 12 additions & 0 deletions scout/server/blueprints/cases/templates/cases/case.html
Original file line number Diff line number Diff line change
Expand Up @@ -704,5 +704,17 @@ <h5 class="modal-title" id="exampleModalLabel">Edit synopsis</h5>
$('[data-bs-toggle=sidebar-collapse]').click(function() {
SidebarCollapse();
});

// Allows a Sanger recipient to notify the user who ordered a Sanger verification that it was a true positive
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, I'm missing the gain from checking for the user in Sanger recipients? If they are posed to set the validation status, they got the info somehow, didn't they? The Sanger recipient can conveniently be a function email box at the hospital, to which several lab users have access.

function validate_action(validated_option) {
if (validated_option != "True positive"){
document.getElementById('validation_form').submit();
}
const sanger_recipients = {{ institute.sanger_recipients | tojson }};
if ( sanger_recipients.includes("{{current_user.email}}") ){
var myModal = new bootstrap.Modal(document.getElementById('validationModal'))
myModal.show();
}
}
</script>
{% endblock %}
49 changes: 38 additions & 11 deletions scout/server/blueprints/cases/templates/cases/utils.html
Original file line number Diff line number Diff line change
Expand Up @@ -553,17 +553,7 @@ <h6>No pinned variants</h6>
</div>
</div>
<div class="col-5">
<form action="{{ url_for('cases.mark_validation',
institute_id=variant.institute,
case_name=case.display_name,
variant_id=variant._id) }}"
method="POST" accept-charset="utf-8">
<select class="form-control form-control-sm" onchange="this.form.submit()" name="type">
{% for type in ('Not validated', 'True positive', 'False positive') %}
<option value="{{ type }}" {% if type == variant.validation %}selected{% endif %}>{{ type }}</option>
{% endfor %}
</select>
</form>
{{ validation_macro(variant, case) }}
</div>
<div class="col-2">
{{ remove_form(url_for('cases.pin_variant',
Expand All @@ -583,6 +573,43 @@ <h6>No pinned variants</h6>
</div>
{% endmacro %}


{% macro validation_macro(variant, case) %}
<form action="{{ url_for('cases.mark_validation', institute_id=variant.institute, case_name=case.display_name, variant_id=variant._id) }}" method="POST" accept-charset="utf-8" id="validation_form">
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pre-existing code

<select class="form-control form-control-sm" onchange="validate_action(this.value);" name="type">
{% for type in ('Not validated', 'True positive', 'False positive') %}
<option value="{{ type }}" {% if type == variant.validation %}selected{% endif %}>{{ type }}</option>
{% endfor %}
</select>
</form>

<div class="modal fade" tabindex="-1" id="validationModal">
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

New code

<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Positive validation notification</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<form action="{{ url_for('cases.mark_validation', institute_id=variant.institute, case_name=case.display_name, variant_id=variant._id) }}" method="POST" accept-charset="utf-8">
<input type="hidden" name="type" value="True positive"/>
<div class="modal-body">
<p>The variant is being marked as a true positive.</p>
<input class="form-check-input" type="checkbox" value="yes" name="notify_user" id="notify_user" checked>
<label class="form-check-label" for="notify_user">
Notify user which ordered verification
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Notify user which ordered verification
Notify user who ordered verification

Unless it's one of those function email boxes at work of course! 😉

</label>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Dismiss</button>
<button type="submit" class="btn btn-primary">Save changes</button>
</div>
</form>
</div>
</div>
</div>
{% endmacro %}


{% macro matching_causatives(other_causatives, institute, case, default=False) %}
<div data-bs-toggle='tooltip' class="panel-heading" title="If there are any variants in this case
that have been marked as causative in another case for this insitute. {% if default %}Variants in default panels for the case only.{% endif %}">
Expand Down
14 changes: 14 additions & 0 deletions scout/server/blueprints/cases/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -675,6 +675,20 @@ def mark_validation(institute_id, case_name, variant_id):
variant_id=variant_id,
)
store.validate(institute_obj, case_obj, user_obj, link, variant_obj, validate_type)
if request.form.get("notify_user"):
sanger_by: str = store.sanger_ordered_by(
institute_id=institute_id, case_id=case_obj["_id"], variant_id=variant_obj["variant_id"]
)
if sanger_by:
variant_info: dict = {
"subject": variant_obj["display_name"],
"link": link,
"case_name": case_name,
}
store.update_users_verified_positives(
user_id=sanger_by, variant_info=variant_info, add=True
)

return redirect(request.referrer or link)


Expand Down
2 changes: 2 additions & 0 deletions scout/server/blueprints/institutes/controllers.py
Original file line number Diff line number Diff line change
Expand Up @@ -480,6 +480,8 @@ def cases(store, request, institute_id):
data["status_ncases"] = store.nr_cases_by_status(institute_id=institute_id)
data["nr_cases"] = sum(data["status_ncases"].values())
data["sanger_unevaluated"] = get_sanger_unevaluated(store, institute_id, current_user.email)
user_obj: dict = store.user(email=current_user.email)
data["sanger_positives"] = user_obj.get("validated_positive_variants",[])

case_groups = {status: [] for status in CASE_STATUSES}
nr_cases = 0
Expand Down
18 changes: 18 additions & 0 deletions scout/server/blueprints/institutes/templates/overview/cases.html
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,24 @@ <h5 class="modal-title" id="sangerModalLabel">Sanger validations to evaluate:</h
</div>
</div>
{% endif %}

<!-- Eventual variants the user has ordered verification for and turned out to be true positives -->
{% if sanger_positives %}
<form action="{{url_for('overview.dismiss_positive_verified_alert')}}" method="POST">
<div class="row mt-3">
<div class="alert alert-primary">
The following variants were verified as true positives:&nbsp;
{% for variant in sanger_positives %}
<a target="_blank" rel="noopener" href="{{variant.link}}">{{variant.case_name}}/{{variant.subject}}</a>
<button class="btn btn-link btn-sm" name="variant_link" value="{{variant.link}}" type="submit"><i class="fa fa-remove text-dark""></i></button>
&emsp;&emsp;
{% endfor %}
</div>
</div>
</form>
{% endif %}


<div>
{% set ordered_statuses = ['prioritized', 'inactive', 'active', 'archived', 'solved', 'ignored'] -%}
{% for status in ordered_statuses %}
Expand Down
14 changes: 14 additions & 0 deletions scout/server/blueprints/institutes/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -248,3 +248,17 @@ def institute_users(institute_id):
return redirect(request.referrer)
data = controllers.institute(store, institute_id)
return render_template("/overview/users.html", panel=2, **data)


@blueprint.route("/overview/dismiss_positive_verified_alert", methods=["POST"])
def dismiss_positive_verified_alert():
"""Removes the alert for a user to go check a variant that was verified as a true positive."""
variant_link_to_remove = request.form.get("variant_link")
users_verified_positives: list = current_user.validated_positive_variants or []
for variant_info in users_verified_positives:
if variant_info["link"] == variant_link_to_remove:
store.update_users_verified_positives(
user_id=current_user._id, variant_info=variant_info, add=False
)
break
return redirect(request.referrer)
Loading