scout-browser 4.79.1__py3-none-any.whl → 4.81__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. scout/__version__.py +1 -1
  2. scout/adapter/mongo/variant.py +2 -2
  3. scout/constants/__init__.py +3 -0
  4. scout/constants/clinvar.py +3 -0
  5. scout/constants/indexes.py +14 -12
  6. scout/constants/variants_export.py +11 -0
  7. scout/models/case/case_loading_models.py +45 -23
  8. scout/models/clinvar.py +1 -0
  9. scout/parse/variant/variant.py +27 -23
  10. scout/server/blueprints/api/views.py +12 -0
  11. scout/server/blueprints/cases/controllers.py +72 -6
  12. scout/server/blueprints/cases/templates/cases/case.html +1 -22
  13. scout/server/blueprints/cases/templates/cases/case_bionano.html +2 -0
  14. scout/server/blueprints/cases/templates/cases/case_report.html +135 -129
  15. scout/server/blueprints/cases/templates/cases/case_sma.html +2 -0
  16. scout/server/blueprints/cases/templates/cases/collapsible_actionbar.html +12 -2
  17. scout/server/blueprints/cases/templates/cases/gene_panel.html +45 -22
  18. scout/server/blueprints/cases/templates/cases/utils.html +52 -14
  19. scout/server/blueprints/cases/views.py +22 -0
  20. scout/server/blueprints/clinvar/controllers.py +2 -0
  21. scout/server/blueprints/clinvar/form.py +5 -0
  22. scout/server/blueprints/clinvar/templates/clinvar/multistep_add_variant.html +30 -5
  23. scout/server/blueprints/diagnoses/templates/diagnoses/diagnoses.html +1 -1
  24. scout/server/blueprints/institutes/static/select2_darktheme.css +62 -0
  25. scout/server/blueprints/institutes/templates/overview/institute_settings.html +1 -1
  26. scout/server/blueprints/panels/templates/panels/panel.html +15 -1
  27. scout/server/blueprints/panels/templates/panels/panel_pdf_case_hits.html +2 -2
  28. scout/server/blueprints/panels/templates/panels/panel_pdf_simple.html +3 -3
  29. scout/server/blueprints/panels/views.py +5 -1
  30. scout/server/blueprints/variant/controllers.py +5 -2
  31. scout/server/blueprints/variant/templates/variant/variant_details.html +32 -20
  32. scout/server/blueprints/variants/controllers.py +179 -93
  33. scout/server/blueprints/variants/templates/variants/components.html +5 -4
  34. scout/server/blueprints/variants/templates/variants/fusion-variants.html +1 -1
  35. scout/server/blueprints/variants/views.py +30 -15
  36. scout/server/config.py +3 -0
  37. scout/server/templates/report_base.html +3 -3
  38. scout/server/templates/utils.html +68 -38
  39. scout/server/utils.py +25 -3
  40. {scout_browser-4.79.1.dist-info → scout_browser-4.81.dist-info}/METADATA +1 -1
  41. {scout_browser-4.79.1.dist-info → scout_browser-4.81.dist-info}/RECORD +45 -45
  42. scout/server/blueprints/cases/templates/cases/clinvar.html +0 -48
  43. {scout_browser-4.79.1.dist-info → scout_browser-4.81.dist-info}/LICENSE +0 -0
  44. {scout_browser-4.79.1.dist-info → scout_browser-4.81.dist-info}/WHEEL +0 -0
  45. {scout_browser-4.79.1.dist-info → scout_browser-4.81.dist-info}/entry_points.txt +0 -0
  46. {scout_browser-4.79.1.dist-info → scout_browser-4.81.dist-info}/top_level.txt +0 -0
@@ -44,7 +44,9 @@
44
44
  </div>
45
45
  <div class="col-md-8">
46
46
  {{ synopsis_panel() }}
47
+ <div class="panel-default">
47
48
  {{ comments_panel(institute, case, current_user, comments) }}
49
+ </div>
48
50
  </div>
49
51
  </div> <!-- end of div class row -->
50
52
 
@@ -83,8 +83,18 @@
83
83
  </div>
84
84
  </div>
85
85
 
86
- <!-- If connected to a chanjo instance, display coverage report -->
87
- {% if config.SQLALCHEMY_DATABASE_URI and case.track != "cancer" %}
86
+ <!-- If connected to a chanjo or chanjo2 instance, display coverage report -->
87
+ {% if case.chanjo2_coverage %}
88
+ <div href="#" class="bg-dark list-group-item text-white">
89
+ <div class="d-flex flex-row flex-fill bd-highlight">
90
+ <span class="menu-collapsed">Coverage (chanjo2)</span>
91
+ <a href="{{ url_for('cases.chanjo2_coverage_report', institute_id=institute._id, case_name=case.display_name, panel_name=case.panel_names|join(', '), report_type='report') }}" target="_blank" rel="noopener">
92
+ <span class="fa fa-link"></span>
93
+ </a>
94
+ </div>
95
+ </div>
96
+ {% endif %}
97
+ {% if case.chanjo_coverage %}
88
98
  <div href="#" class="bg-dark list-group-item text-white">
89
99
  <div class="d-flex flex-row flex-fill bd-highlight">
90
100
  <span class="menu-collapsed">Coverage</span>
@@ -7,6 +7,7 @@
7
7
  <thead class="table-light thead">
8
8
  <tr style="cursor: pointer; white-space: nowrap">
9
9
  <th>Panel <i class="fas fa-sort" data-bs-toggle="tooltip" title="Sort by gene panel name"></i></th>
10
+ <th >Default <i class="fas fa-sort" data-bs-toggle="tooltip" title="Sort by default panel"></i></th>
10
11
  <th>Version <i class="fas fa-sort" data-bs-toggle="tooltip" title="Sort by panel version"></i></th>
11
12
  <th>Genes <i class="fas fa-sort" data-bs-toggle="tooltip" title="Sort by number of genes"></i></th>
12
13
  </tr>
@@ -21,8 +22,10 @@
21
22
  <span class="badge bg-danger">Removed</span>
22
23
  {% endif %}
23
24
  </a>
25
+ </td>
26
+ <td >
24
27
  {% if panel.is_default %}
25
- <span class="badge bg-dark float-end">Default</span>
28
+ <span class="badge bg-dark">Default</span>
26
29
  {% endif %}
27
30
  </td>
28
31
  <td>{{ panel.version }} <small class="text">({{ panel.updated_at.date() }})</small></td>
@@ -91,21 +94,6 @@
91
94
  {% endif %}
92
95
  )
93
96
  {% if case.dynamic_gene_list_edited %} <span class="text-danger ml-3"> (edited) </span> {% endif %}
94
- {% if case.track != 'cancer' and config.SQLALCHEMY_DATABASE_URI and case.dynamic_gene_list|length > 0 %}
95
- <span class="pull-right">
96
- <a href="#" onclick="document.getElementById('hpo-report-form').submit();">Coverage report</a>
97
- <form id="hpo-report-form" action="{{ url_for('report.report', sample_id=case.individuals|map(attribute='individual_id')|list, panel_name="HPO panel", level=institute.coverage_cutoff) }}" method="POST" target="_blank">
98
- <input type="hidden" name="gene_ids" value="{{ case.dynamic_gene_list|map(attribute='hgnc_id')|join(',') }}">
99
- </form>
100
- </span>
101
- <span class="pull-right">&nbsp;&nbsp;&nbsp;</span>
102
- <span class="pull-right">
103
- <a href="#" onclick="document.getElementById('hpo-overview-form').submit();">Coverage overview</a>
104
- <form id="hpo-overview-form" action="{{ url_for('report.genes', sample_id=case.individuals|map(attribute='individual_id')|list, panel_name="HPO panel", level=institute.coverage_cutoff) }}" method="POST" target="_blank">
105
- <input type="hidden" name="gene_ids" value="{{ case.dynamic_gene_list|map(attribute='hgnc_id')|join(',') }}">
106
- </form>
107
- </span>
108
- {% endif %}
109
97
  </h6>
110
98
  </div>
111
99
 
@@ -142,8 +130,8 @@
142
130
  </div>
143
131
  </div>
144
132
 
145
- <div class="row mt-2"> <!-- Show variants in dynamic gene list -->
146
- <div class="row">
133
+ <div>
134
+ <div class="row"> <!-- Show variants in dynamic gene list -->
147
135
  <form action="{{ url_for('cases.update_clinical_filter_hpo', institute_id=institute._id, case_name=case.display_name)+'#hpo_clinical_filter' }}" method="POST">
148
136
  <div class="form-check form-switch">
149
137
  <input type="checkbox" class="form-check-input" id="hpo_clinical_filter" onChange="this.form.submit()" name="hpo_clinical_filter"{% if case.hpo_clinical_filter %}checked{% endif %}>
@@ -207,11 +195,46 @@
207
195
  {% endif %}
208
196
  </div>
209
197
  </div>
210
- </div> <!-- End of Show variants in dynamic gene list -->
198
+ {% if case.chanjo_coverage or case.chanjo2_coverage and case.dynamic_gene_list|length > 0 %}
199
+ <div class="row mt-1">
200
+ <div class="btn-group btn-group-sm">
201
+ {% if case.chanjo_coverage %}
202
+ <a class="btn btn-secondary btn-sm text-white" href="#section" onClick="document.getElementById('hpo-report-form').submit();" >Coverage report</a>
203
+ <form id="hpo-report-form" action="{{ url_for('report.report', sample_id=case.individuals|map(attribute='individual_id')|list, panel_name='HPO panel', level=institute.coverage_cutoff) }}" method="POST" target="_blank">
204
+ <input type="hidden" name="gene_ids" value="{{ case.dynamic_gene_list|map(attribute='hgnc_id')|join(',') }}">
205
+ </form>
206
+
207
+ <a class="btn btn-secondary btn-sm text-white" href="#section" onClick="document.getElementById('hpo-overview-form').submit();" >Coverage overview</a>
208
+ <form id="hpo-overview-form" action="{{ url_for('report.genes', sample_id=case.individuals|map(attribute='individual_id')|list, panel_name='HPO panel', level=institute.coverage_cutoff) }}" method="POST" target="_blank">
209
+ <input type="hidden" name="gene_ids" value="{{ case.dynamic_gene_list|map(attribute='hgnc_id')|join(',') }}">
210
+ </form>
211
+ {% endif %}
212
+
213
+ {% if case.chanjo2_coverage %}
214
+ <a class="btn btn-secondary btn-sm text-white"
215
+ href="{{ url_for('cases.chanjo2_coverage_report', institute_id=institute._id,
216
+ case_name=case.display_name, panel_name='HPO Panel', report_type='report') }}" target="_blank" rel="noopener">
217
+ Coverage report (Chanjo2)
218
+ </a>
219
+
220
+ <a class="btn btn-secondary btn-sm text-white"
221
+ href="{{ url_for('cases.chanjo2_coverage_report', institute_id=institute._id,
222
+ case_name=case.display_name, panel_name='HPO Panel', report_type='overview') }}" target="_blank" rel="noopener">
223
+ Coverage overview (Chanjo2)
224
+ </a>
225
+ {% endif %}
226
+
227
+ </div>
228
+ </div>
229
+ {% endif %} <!-- End of if case.chanjo_coverage or case.chanjo2_coverage -->
230
+
231
+ <div class="row mt-1">
232
+ <div class="btn-group btn-group-sm"> <!-- Download genes in HPO gene panel -->
233
+ <a class="btn btn-sm btn-primary text-white" href="{{ url_for('cases.download_hpo_genes', institute_id=institute._id, case_name=case.display_name, category="clinical") }}" download><span class="fa fa-download text-white" aria-hidden="true"></span>&nbsp;&nbsp;Clinical HPO gene panel</a>
234
+ <a class="btn btn-sm btn-primary text-white" href="{{ url_for('cases.download_hpo_genes', institute_id=institute._id, case_name=case.display_name, category="research") }}" download><span class="fa fa-download text-white" aria-hidden="true"></span>&nbsp;&nbsp;Research HPO gene panel</a>
235
+ </div>
236
+ </div>
211
237
 
212
- <div class="btn-group d-flex justify-content-center mt-2"> <!-- Download genes in HPO gene panel -->
213
- <a class="btn btn-sm btn-primary mt-1 text-white" href="{{ url_for('cases.download_hpo_genes', institute_id=institute._id, case_name=case.display_name, category="clinical") }}" download><span class="fa fa-download text-white" aria-hidden="true"></span>&nbsp;&nbsp;Clinical HPO gene panel</a>
214
- <a class="btn btn-sm btn-primary mt-1 text-white" href="{{ url_for('cases.download_hpo_genes', institute_id=institute._id, case_name=case.display_name, category="research") }}" download><span class="fa fa-download text-white" aria-hidden="true"></span>&nbsp;&nbsp;Research HPO gene panel</a>
215
238
  </div>
216
239
 
217
240
  {% endif %}
@@ -1,4 +1,5 @@
1
1
  {% from "variants/indicators.html" import clinical_assessments_badge, research_assessments_badge %}
2
+ {% from "clinvar/clinvar_howto.html" import clinvar_howto_modal %}
2
3
 
3
4
  {% macro matchmaker_modal(institute, case, suspects, mme_nodes ) %}
4
5
  <div class="modal fade" id="matchmaker_modal" tabindex="-1" role="dialog" aria-hidden="true">
@@ -379,20 +380,21 @@
379
380
  {% endif %}
380
381
  </div>
381
382
  </div>
382
- <div style="max-height:300px; overflow-y: scroll;">
383
+ <div class="mb-3" style="max-height:300px; overflow-y: scroll;">
383
384
  <ul class="list-group">
384
385
  {% for variant in causatives %}
385
386
  <li class="list-group-item list-group-item-action">
386
387
  {% if variant._id %}
387
388
  {% do already_displayed_variant_ids.append( variant._id ) %}
388
389
  <div class="row">
389
- <div class="col-10">
390
+ <div class="col">
391
+ <i class="far fa-check-circle"></i>
390
392
  {{ pretty_link_variant(variant, case) }}
391
393
  {{ variant_validation_badge(variant) }}
392
394
  {{ clinical_assessments_badge(variant) }}
393
395
  {{ tumor_allele_freq(variant) }}
394
396
  </div>
395
- <div class="col-2">
397
+ <div class="col-auto" style="width:fit-content;">
396
398
  {{ remove_form(url_for('cases.mark_causative',
397
399
  institute_id=institute._id,
398
400
  case_name=case.display_name,
@@ -415,7 +417,7 @@
415
417
  {% if variant._id %}
416
418
  {% do already_displayed_variant_ids.append(variant._id) %}
417
419
  <div class="row">
418
- <div class="col-10">
420
+ <div class="col">
419
421
  <i class="far fa-check-circle"></i>
420
422
  {% if variant.category == "snv" %}
421
423
  <a href="{{ url_for('variant.variant',
@@ -433,7 +435,7 @@
433
435
  {% endif %}
434
436
  </a>
435
437
  </div>
436
- <div class="col-2">
438
+ <div class="col-2" style="width:fit-content;">
437
439
  {{ remove_form(url_for('cases.mark_causative',
438
440
  institute_id=institute._id,
439
441
  case_name=case.display_name,
@@ -444,6 +446,7 @@
444
446
  </div>
445
447
  <div class="row">
446
448
  <div class="col-4">
449
+ <i class="far fa-check-circle" style="color:transparent; background-color:transparent"></i>
447
450
  Diagnoses
448
451
  </div>
449
452
  <div class="col-8">
@@ -464,6 +467,7 @@
464
467
  </div>
465
468
  <div class="row">
466
469
  <div class="col-4">
470
+ <i class="far fa-check-circle" style="color:transparent; background-color:transparent"></i>
467
471
  HPO terms
468
472
  </div>
469
473
  <div class="col-8">
@@ -531,18 +535,18 @@
531
535
  {% endmacro %}
532
536
 
533
537
  {% macro suspects_list(suspects, institute, case, manual_rank_options, cancer_tier_options) %}
538
+ {{ clinvar_howto_modal() }}
534
539
  <div class="card mt-3">
535
- <div class="d-flex align-items-center" data-bs-toggle='tooltip' title="Displays all variants that has been pinned for this case">
536
- <h6><span class="fa fa-map-pin ms-3 mt-2"></span>&nbsp;Pinned variants ({{suspects|length}})
537
- </h6>
540
+ <div class="d-flex align-items-center" data-bs-toggle='tooltip' title="Displays all variants that have been pinned or included in a ClinVar submission for this case">
541
+ <h6><span class="fa fa-map-pin ms-3 mt-2"></span>&nbsp;Variants pinned ({{suspects|length}}) or included in a ClinVar submission({{ case.clinvar_variants.items()|length }}) <a data-bs-target="#howto" href="#" data-bs-toggle="modal">?</a></h6>
542
+ </div>
543
+ <div class="mb-3" style="max-height:300px; overflow-y: scroll;">
544
+ <ul class="list-group">
538
545
  {% if not suspects|length %}
539
546
  <span class="text-muted ms-3 mt-2">
540
547
  <h6>No pinned variants</h6>
541
548
  </span>
542
549
  {% endif %}
543
- </div>
544
- <div style="max-height:300px; overflow-y: scroll;">
545
- <ul class="list-group">
546
550
  {% for variant in suspects %}
547
551
  <li class="list-group-item">
548
552
  {% if variant._id %}
@@ -560,7 +564,7 @@
560
564
  </div>
561
565
  </div>
562
566
  </div>
563
- <div class="col-5">
567
+ <div class="col-auto">
564
568
  <form action="{{ url_for('cases.mark_validation',
565
569
  institute_id=variant.institute,
566
570
  case_name=case.display_name,
@@ -573,7 +577,8 @@
573
577
  </select>
574
578
  </form>
575
579
  </div>
576
- <div class="col-2">
580
+ <div class="col">{{ clinvar_var_status(variant, case, institute) }}</div>
581
+ <div class="col-auto" style="width: fit-content;">
577
582
  {{ remove_form(url_for('cases.pin_variant',
578
583
  institute_id=institute._id,
579
584
  case_name=case.display_name,
@@ -587,10 +592,43 @@
587
592
  </li>
588
593
  {% endfor %}
589
594
  </ul>
590
- </div>
595
+ {{ clinvar_vars_summary(suspects, case, institute) }}
596
+ </div>
591
597
  </div>
592
598
  {% endmacro %}
593
599
 
600
+ {% macro clinvar_var_status(variant, case, institute) %}
601
+ {% if variant._id and variant.category != 'str' %}
602
+ <form id="clinvar_submit" class="d-flex justify-content-center" action="{{ url_for('clinvar.clinvar_add_variant', institute_id=institute._id, case_name=case.display_name) }}" method="POST">
603
+ {% if case.clinvar_variants and variant._id in case.clinvar_variants.keys() %}
604
+ (included in ClinVar submission)
605
+ {% else %}
606
+ <button type="submit" name="var_id" value="{{variant._id}}" class="btn btn-secondary btn-sm" style="float: right;">Add to ClinVar submission</button>
607
+ {% endif %}
608
+ </form>
609
+ {% endif %}
610
+ {% endmacro %}
611
+
612
+ {% macro clinvar_vars_summary(suspects, case, institute) %}
613
+ {% if case.clinvar_variants %}
614
+ {% if case.clinvar_variants_not_in_suspects | length >0 %}
615
+ <div class="d-flex align-content-center flex-wrap">
616
+ <div class="col-auto d-flex align-items-center wrap">
617
+ <h6 class="m-2">&nbsp;Variants present in a ClinVar submission, no longer pinned:</h6>
618
+ </div>
619
+ {% for entry in case.clinvar_variants_not_in_suspects %}
620
+ <div class="m-2">{{ pretty_link_variant(entry, case) }}</div>
621
+ {% endfor %}
622
+ </div>
623
+ {% endif %}
624
+ <div class="card-footer d-flex justify-content-center pb-0" style="background-color:inherit;">
625
+ <a href="{{url_for('clinvar.clinvar_submissions', institute_id=institute._id)}}"
626
+ class="btn btn-secondary btn-sm text-white mx-3" target="_blank" rel="noopener noreferrer">View ClinVar
627
+ submissions <i class="fas fa-arrow-circle-right"></i></a>
628
+ </div>
629
+ {% endif %}
630
+ {% endmacro %}
631
+
594
632
  {% macro matching_causatives(other_causatives, institute, case, default=False) %}
595
633
  <div data-bs-toggle='tooltip' class="panel-heading" title="If there are any variants in this case
596
634
  that have been marked as causative in another case for this insitute. {% if default %}Variants in default panels for the case only.{% endif %}">
@@ -313,6 +313,28 @@ def pdf_case_report(institute_id, case_name):
313
313
  )
314
314
 
315
315
 
316
+ @cases_bp.route("/<institute_id>/<case_name>/chanjo2_report/<report_type>", methods=["GET"])
317
+ def chanjo2_coverage_report(institute_id: str, case_name: str, report_type: str):
318
+ """Return the HTML coverage report or coverage overview created by chanjo2."""
319
+
320
+ REPORT_TYPES = ["report", "overview"]
321
+ if report_type not in REPORT_TYPES:
322
+ flash(f"Wrong value for report_type parameter. Accepted values: {REPORT_TYPES}", "warning")
323
+ return redirect(request.referrer)
324
+
325
+ institute_obj, case_obj = institute_and_case(store, institute_id, case_name)
326
+ report_html_content: str = controllers.chanjo2_coverage_report_contents(
327
+ institute_obj=institute_obj,
328
+ case_obj=case_obj,
329
+ panel_name=request.args.get("panel_name"),
330
+ panel_id=request.args.get("panel_id"),
331
+ report_type=report_type,
332
+ )
333
+ if report_html_content is None:
334
+ return redirect(request.referrer)
335
+ return report_html_content
336
+
337
+
316
338
  @cases_bp.route("/<institute_id>/<case_name>/mt_report", methods=["GET"])
317
339
  def mt_report(institute_id, case_name):
318
340
  institute_obj, case_obj = institute_and_case(store, institute_id, case_name)
@@ -245,6 +245,8 @@ def _set_conditions(clinvar_var: dict, form: ImmutableMultiDict):
245
245
  clinvar_var["condition_id_value"] = ";".join(
246
246
  [f"{condition_prefix}{condition_id}" for condition_id in form.getlist("conditions")]
247
247
  )
248
+ if bool(form.get("multiple_condition_explanation")):
249
+ clinvar_var["explanation_for_multiple_conditions"] = form["multiple_condition_explanation"]
248
250
 
249
251
 
250
252
  def parse_variant_form_fields(form):
@@ -26,6 +26,7 @@ from scout.constants import (
26
26
  COLLECTION_METHOD,
27
27
  CONDITION_PREFIX,
28
28
  GERMLINE_CLASSIF_TERMS,
29
+ MULTIPLE_CONDITION_EXPLANATION,
29
30
  )
30
31
 
31
32
  LOG = logging.getLogger(__name__)
@@ -65,6 +66,10 @@ class ClinVarVariantForm(FlaskForm):
65
66
  "Condition ID type", choices=[(key, key) for key, value in CONDITION_PREFIX.items()]
66
67
  )
67
68
  conditions = SelectMultipleField("Condition ID value, without prefix")
69
+ multiple_condition_explanation = SelectField(
70
+ "Explanation for multiple conditions",
71
+ choices=[(item, item) for item in MULTIPLE_CONDITION_EXPLANATION],
72
+ )
68
73
 
69
74
  # Extra fields:
70
75
  assertion_method = StringField("Assertion method", default=ASSERTION_METHOD)
@@ -232,7 +232,7 @@
232
232
 
233
233
  <fieldset data-step="6">
234
234
  <legend>Associated Conditions</legend>
235
- <h3 class="fs-subtitle">The condition for which the variant is interpreted. Examples available at <a href="https://www.ncbi.nlm.nih.gov/clinvar/docs/spreadsheet/#condition" target="_blank" rel="noopener">ClinVar</a>"</h3>
235
+ <h3 class="fs-subtitle">The condition for which the variant is interpreted. Examples available at <a href="https://www.ncbi.nlm.nih.gov/clinvar/docs/spreadsheet/#condition" target="_blank" rel="noopener">ClinVar</a></h3>
236
236
 
237
237
  <div class="row">
238
238
  <div class="col-6" id="clinvar_condition_container">
@@ -249,7 +249,7 @@
249
249
  {% endfor %}
250
250
  </select>
251
251
  <br><br>
252
- {{variant_data.var_form.conditions.label(class="fw-bold, text-dark")}} <span class="text-danger" data-bs-toggle='tooltip' title="Required field. Include data from ONE DATABASE TYPE ONLY (i.e. only OMIM terms, only HPO terms etc)"><strong>*?</strong></span>
252
+ {{variant_data.var_form.conditions.label(class="fw-bold, text-dark")}} <span class="text-danger" data-bs-toggle='tooltip' title="Required field. Include data from ONE DATABASE TYPE ONLY (i.e. only OMIM terms, only HPO terms etc). If multiple conditions are submitted for a variant, this indicates that the variant was interpreted for the combination of conditions in the same individual(s). i.e. this variant causes both condition A and condition B in the same individual. This scenario is most common for a new disease or syndrome that does not yet have a name and is described by several clinical features. If you want to indicate that the variant has been interpreted for more than one condition, please submit these as separate records."><strong>*?</strong></span>
253
253
  <select class="select2" id="condition_tags" name="conditions" multiple="true" style="width:100%;">
254
254
  {% if variant_data.var_form.omim_terms.choices %}
255
255
  {% for term, _ in variant_data.var_form.omim_terms.choices %}
@@ -265,6 +265,18 @@
265
265
  {% endfor %}
266
266
  {% endif %}
267
267
  </select>
268
+
269
+ <div class="mt-3">
270
+ {{variant_data.var_form.multiple_condition_explanation.label(class="fw-bold, text-dark")}} <span class="text-danger" data-bs-toggle='tooltip' title="Required if you provide more than one condition ID."><strong>?</strong></span>
271
+ <select name="multiple_condition_explanation" id="multiple_condition_explanation" class="form-control, btn-secondary">
272
+ <option selected value>-</option>
273
+ {% for choice, _ in variant_data.var_form.multiple_condition_explanation.choices %}
274
+ <option value="{{choice}}">{{choice}}</option>
275
+ {% endfor %}
276
+ </select>
277
+ </div>
278
+
279
+
268
280
  </div>
269
281
  <div class="col-6">
270
282
  {{ variant_data.var_form.omim_terms.label(class="fw-bold, text-dark" )}}<br>
@@ -360,7 +372,22 @@ var tooltipList = tooltipTriggerList.map(function (tooltipTriggerEl) {
360
372
 
361
373
  // Validates fields for conditions associated to a variant
362
374
  function validateConditions(){
363
- return $("#condition_tags option:selected").length > 0;
375
+ if ($("#condition_tags option:selected").length == 0) {
376
+ alert("Please provide at least one condition ID");
377
+ return false;
378
+ }
379
+
380
+ if ($("#condition_tags option:selected").length > 1 && $("#multiple_condition_explanation option:selected").text() === "-") {
381
+ alert("When multiple condition IDs are provided then an option for 'Explanation for multiple conditions' must be provided");
382
+ return false;
383
+ }
384
+
385
+ if ($("#condition_tags option:selected").length == 1 && $("#multiple_condition_explanation option:selected").text() !== "-") {
386
+ alert("Please deselect the selected option in 'Explanation for multiple conditions' since only one condition ID was provided.");
387
+ return false;
388
+ }
389
+
390
+ return true
364
391
  }
365
392
 
366
393
  var current_fs, next_fs, previous_fs; //fieldsets
@@ -383,12 +410,10 @@ $(".next").click(function(){
383
410
  // check to see if the validator for the specific step we are on passed or not.
384
411
  if(validationPassed == false){
385
412
  // do not proceed
386
- alert("Please fill in required field");
387
413
  animating = false;
388
414
  return;
389
415
  }
390
416
 
391
-
392
417
  next_fs = $(this).parent().next();
393
418
 
394
419
  //activate next step on progressbar using the index of next_fs
@@ -83,7 +83,7 @@
83
83
  <table id="super_secret_table_template" style="position: absolute; width: 1px; height: 1px; margin: -1px; border: 0; padding: 0; white-space: nowrap; clip-path: inset(100%); clip: rect(0 0 0 0); overflow: hidden;">
84
84
  <tr id="diagnosis-row">
85
85
  <td><a id="external-link" href="http://omim.org/entry/" target="_blank" rel=noopener ></a></td>
86
- <td><a id="internal-link" href="{{ url_for('diagnoses.diagnosis',disease_id='')}}"><span class="fa fa-link"></span></a></td>
86
+ <td><a id="internal-link" href="{{ url_for('diagnoses.diagnosis',disease_id='')}}" target="_blank"><span class="fa fa-link"></span></a></td>
87
87
  <td><span id="description" class="text-body"></span></td>
88
88
  <td id="inheritance-container"><!-- inheritance-->
89
89
  <span id="inheritance" class="badge bg-info m-1"></span>
@@ -0,0 +1,62 @@
1
+ /* Dark Theme compatibility for select2 multiselects*/
2
+ @media (prefers-color-scheme: dark) {
3
+
4
+ .select2-dropdown,
5
+ .select2-selection {
6
+ color: #b1b1b1 !important;
7
+ background-color: #222 !important;
8
+ border: 1px solid #515151 !important;
9
+ }
10
+
11
+ .select2-results__option {
12
+ display: flex;
13
+ gap: 0.5rem;
14
+ color: #b1b1b1 !important;
15
+ background-color: #222 !important;
16
+ }
17
+
18
+ .select2-results__option:hover,
19
+ .select2-results__option[aria-selected=true]:hover {
20
+ color: #dfe0e1 !important;
21
+ background-color: #343a40 !important;
22
+ }
23
+
24
+ .select2-selection__choice:has(> span:hover) {
25
+ opacity: 0.5;
26
+ }
27
+
28
+ /* Filters adjusts color of svg used as remove-button for selected options */
29
+ .select2-selection__choice__remove:first-child {
30
+ background-color: transparent !important;
31
+ filter: brightness(70) saturate(0%);
32
+ }
33
+
34
+ .select2-selection__choice__remove:hover {
35
+ filter: invert(1)
36
+ }
37
+
38
+ .select2-results__option[aria-selected=true],
39
+ .select2-result__option,
40
+ .select2-selection__choice,
41
+ .select2-selection__choice__remove {
42
+ color: #fafafa !important;
43
+ background-color: #626262 !important;
44
+ border-color: #626262 !important;
45
+ }
46
+
47
+ /* This is a check mark displayed for the selected options */
48
+ .select2-results__option[aria-selected=true]::after {
49
+ content: '';
50
+ display: block;
51
+ width: 0.5em;
52
+ height: 1em;
53
+ border-style: solid;
54
+ border-width: 0 0.26em 0.26em 0;
55
+ -webkit-transform-style: preserve-3d;
56
+ transform-style: preserve-3d;
57
+ -webkit-transform: rotate(45deg);
58
+ -ms-transform: rotate(45deg);
59
+ -o-transform: rotate(45deg);
60
+ transform: rotate(45deg);
61
+ }
62
+ }
@@ -11,6 +11,7 @@
11
11
  <link href="https://cdn.jsdelivr.net/npm/select2@4.0.13/dist/css/select2.min.css" rel="stylesheet" integrity="sha512-nMNlpuaDPrqlEls3IX/Q56H36qvBASwb3ipuo3MxeWbsQB1881ox0cRv7UPTgBlriqoynt35KjEwgGUeUXIPnw==" crossorigin="anonymous" referrerpolicy="no-referrer"/>
12
12
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-select/1.14.0-beta3/css/bootstrap-select.min.css" integrity="sha512-g2SduJKxa4Lbn3GW+Q7rNz+pKP9AWMR++Ta8fgwsZRCUsawjPvF/BxSMkGS61VsR9yinGoEgrHPGPn2mrj8+4w==" crossorigin="anonymous" referrerpolicy="no-referrer" />
13
13
  <link href="https://cdn.jsdelivr.net/npm/select2-bootstrap-5-theme@1.2.0/dist/select2-bootstrap-5-theme.min.css" rel="stylesheet" />
14
+ <link rel="stylesheet" href="{{ url_for('overview.static', filename='select2_darktheme.css') }}"/>
14
15
  {% endblock %}
15
16
 
16
17
  {% block top_nav %}
@@ -124,5 +125,4 @@
124
125
  });
125
126
  });
126
127
  </script>
127
-
128
128
  {% endblock %}
@@ -81,7 +81,7 @@
81
81
  <label for="mainainer">Maintainers</label>
82
82
  <span class="float-end" id="maintainer"> {{ panel.maintainer_names|join(", ") }}</span>
83
83
  </li>
84
- {% if config.SQLALCHEMY_DATABASE_URI and case %}
84
+ {% if case and case.chanjo_coverage %}
85
85
  <li class="list-group-item">
86
86
  <label for="coverage_report">Coverage report</label>
87
87
  <a class="float-end" id="coverage_report" href="#" onclick="document.getElementById('report-form').submit();">
@@ -103,6 +103,20 @@
103
103
  </span>
104
104
  </li>
105
105
  {% endif %}
106
+ {% if case and case.chanjo2_coverage %}
107
+ <li class="list-group-item">
108
+ <label for="coverage_report">Coverage report (chanjo2)</label>
109
+ <a class="float-end" href="{{ url_for('cases.chanjo2_coverage_report', institute_id=institute._id, case_name=case.display_name, panel_name=panel.name_and_version, panel_id=panel._id, report_type='report') }}" target="_blank" rel="noopener">
110
+ {{ case.display_name }}
111
+ </a>
112
+ </li>
113
+ <li class="list-group-item">
114
+ <label for="coverage_report">Coverage overview (chanjo2)</label>
115
+ <a class="float-end" href="{{ url_for('cases.chanjo2_coverage_report', institute_id=institute._id, case_name=case.display_name, panel_name=panel.name_and_version, panel_id=panel._id, report_type='overview') }}" target="_blank" rel="noopener">
116
+ {{ case.display_name }}
117
+ </a>
118
+ </li>
119
+ {% endif %}
106
120
  <li class="list-group-item">
107
121
  <div class="d-flex justify-content-between">
108
122
  <a href="{{ url_for('panels.panel_export_pdf', panel_id=panel._id) }}" class="btn btn-secondary btn-sm" download>Export to PDF</a>
@@ -6,7 +6,7 @@
6
6
  <h4>Scout - Institute {{institute.display_name}} - case {{case.display_name}} - {{panel.name_and_version}}: panel extent report</h4> - created on:&nbsp;<strong>{{report_created_at}}</strong><br><br>
7
7
  {{ hits_panel() }}
8
8
  <br>[END OF REPORT]<br><br>
9
- <a href="https://clinical-genomics.github.io/scout" target="_blank" rel="noopener">clinical-genomics.github.io/scout</a>
9
+ <a style="text-decoration:none;" href="https://clinical-genomics.github.io/scout" target="_blank" rel="noopener">clinical-genomics.github.io/scout</a>
10
10
  </div>
11
11
  {% endblock %}
12
12
 
@@ -21,7 +21,7 @@
21
21
  Gene panel: <strong>{{panel.name_and_version}}</strong><br>
22
22
  Last updated: <strong>{{ panel.date.strftime('%Y-%m-%d') }}</strong>
23
23
  {% if case.outdated_panels and panel.panel_name in case.outdated_panels %}
24
- <a><span class="badge rounded-pill badge-sm bg-warning" data-bs-toggle="popover" data-bs-placement="left" data-bs-html="true" data-bs-content="Panel version used in the analysis ({{panel.version}}) is outdated. Latest panel version is used in variants filtering.<br /><strong>Genes present in case panel and not in latest version</strong>: {{case.outdated_panels[panel.panel_name]['extra_genes']|join(', ') or '-'}}.<br /><strong>Genes present only in latest version</strong>: {{case.outdated_panels[panel.panel_name]['missing_genes']|join(', ') or '-'}}.">!</span></a>
24
+ <a><span class="badge rounded-pill py-1 bg-warning" data-bs-toggle="popover" data-bs-placement="left" data-bs-html="true" data-bs-content="Panel version used in the analysis ({{panel.version}}) is outdated. Latest panel version is used in variants filtering.<br /><strong>Genes present in case panel and not in latest version</strong>: {{case.outdated_panels[panel.panel_name]['extra_genes']|join(', ') or '-'}}.<br /><strong>Genes present only in latest version</strong>: {{case.outdated_panels[panel.panel_name]['missing_genes']|join(', ') or '-'}}.">!</span></a>
25
25
  {% endif %}<br>
26
26
  Panel ID: {{ panel.panel_name }}<br>
27
27
  Description: {{ panel.description }}<br>
@@ -6,14 +6,14 @@
6
6
  <h4>Scout - Gene panel report</h4> - created on:&nbsp;<strong>{{report_created_at}}</strong><br><br>
7
7
  {{ genes_panel() }}
8
8
  [END OF REPORT]<br><br>
9
- <a href="https://clinical-genomics.github.io/scout" target="_blank">clinical-genomics.github.io/scout</a>
9
+ <a style="text-decoration:none;" href="https://clinical-genomics.github.io/scout" target="_blank">clinical-genomics.github.io/scout</a>
10
10
  </div>
11
11
  {% endblock %}
12
12
 
13
13
  {% macro genes_panel() %}
14
14
  <div class="card border-dark mb-3">
15
15
  <div class="card-header">
16
- Panel: <a href="{{ url_for('panels.panel', panel_id=panel._id) }}">{{panel.name_and_version}}</a>
16
+ Panel: <a style="text-decoration:none;" href="{{ url_for('panels.panel', panel_id=panel._id) }}">{{panel.name_and_version}}</a>
17
17
  </div>
18
18
  <div class="card-body">
19
19
  <table class="table table-sm">
@@ -58,7 +58,7 @@
58
58
  <tr>
59
59
  <td>{{loop.index}}</td>
60
60
  <td>
61
- <a href="https://www.genenames.org/cgi-bin/gene_symbol_report?hgnc_id={{gene.hgnc_id}}" target="_blank">{{gene.hgnc_id}}</a>
61
+ <a style="text-decoration:none;" href="https://www.genenames.org/cgi-bin/gene_symbol_report?hgnc_id={{gene.hgnc_id}}" target="_blank">{{gene.hgnc_id}}</a>
62
62
  </td>
63
63
  <td>{{ gene.symbol }}</td>
64
64
  <td>{{ gene.disease_associated_transcripts|join(', ') }}</td>
@@ -21,6 +21,8 @@ from scout.export.panel import export_gene_panels
21
21
  from scout.server.blueprints.cases.controllers import check_outdated_gene_panel
22
22
  from scout.server.extensions import store
23
23
  from scout.server.utils import (
24
+ case_has_chanjo2_coverage,
25
+ case_has_chanjo_coverage,
24
26
  html_to_pdf_file,
25
27
  institute_and_case,
26
28
  jsonconverter,
@@ -140,7 +142,6 @@ def panel(panel_id):
140
142
  raw_hgnc_id = request.form["hgnc_id"]
141
143
  if "|" in raw_hgnc_id:
142
144
  raw_hgnc_id = raw_hgnc_id.split(" | ", 1)[0]
143
- hgnc_id = 0
144
145
  try:
145
146
  hgnc_id = int(raw_hgnc_id)
146
147
  except ValueError:
@@ -168,6 +169,9 @@ def panel(panel_id):
168
169
  if request.args.get("case_id"):
169
170
  case_obj = store.case(request.args["case_id"])
170
171
 
172
+ case_has_chanjo_coverage(case_obj)
173
+ case_has_chanjo2_coverage(case_obj)
174
+
171
175
  case_obj["outdated_panels"] = {}
172
176
  panel_name = panel_obj["panel_name"]
173
177
  latest_panel = store.gene_panel(panel_name)
@@ -505,8 +505,11 @@ def observations(store: MongoAdapter, loqusdb: LoqusDB, variant_obj: dict) -> Di
505
505
  if obs_data[loqus_id].get("total"):
506
506
  obs_data[loqus_id]["observations"] = 0
507
507
  continue
508
-
509
- # collect cases where observations occurred
508
+ # Check if the current case is represented in the loqusdb instance
509
+ obs_data[loqus_id]["case_match"] = variant_obj["case_id"] in obs_data[loqus_id].get(
510
+ "families", []
511
+ )
512
+ # collect other cases where observations occurred
510
513
  obs_data[loqus_id]["cases"] = get_loqusdb_obs_cases(
511
514
  store, variant_obj, category, obs_data[loqus_id].get("families", [])
512
515
  )