scout-browser 4.99.0__py3-none-any.whl → 4.100.1__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 (64) hide show
  1. scout/adapter/mongo/case.py +30 -15
  2. scout/adapter/mongo/clinvar.py +23 -31
  3. scout/adapter/mongo/event.py +14 -4
  4. scout/adapter/mongo/omics_variant.py +14 -1
  5. scout/adapter/mongo/query.py +24 -1
  6. scout/adapter/mongo/variant.py +37 -19
  7. scout/adapter/mongo/variant_loader.py +159 -176
  8. scout/build/individual.py +3 -1
  9. scout/commands/download/ensembl.py +1 -2
  10. scout/commands/load/research.py +2 -3
  11. scout/commands/update/individual.py +1 -0
  12. scout/constants/__init__.py +7 -2
  13. scout/constants/igv_tracks.py +4 -3
  14. scout/constants/indexes.py +5 -4
  15. scout/constants/query_terms.py +1 -0
  16. scout/models/case/case.py +1 -0
  17. scout/models/case/case_loading_models.py +3 -1
  18. scout/parse/ensembl.py +8 -3
  19. scout/server/app.py +6 -0
  20. scout/server/blueprints/alignviewers/templates/alignviewers/igv_viewer.html +10 -0
  21. scout/server/blueprints/cases/controllers.py +9 -3
  22. scout/server/blueprints/cases/templates/cases/case_report.html +25 -13
  23. scout/server/blueprints/cases/templates/cases/chanjo2_form.html +1 -1
  24. scout/server/blueprints/cases/templates/cases/collapsible_actionbar.html +1 -1
  25. scout/server/blueprints/cases/templates/cases/gene_panel.html +1 -1
  26. scout/server/blueprints/cases/templates/cases/utils.html +19 -0
  27. scout/server/blueprints/clinvar/controllers.py +5 -1
  28. scout/server/blueprints/clinvar/templates/clinvar/clinvar_submissions.html +34 -12
  29. scout/server/blueprints/clinvar/templates/clinvar/multistep_add_variant.html +1 -1
  30. scout/server/blueprints/diagnoses/static/diagnoses.js +8 -1
  31. scout/server/blueprints/institutes/static/variants_list_scripts.js +9 -1
  32. scout/server/blueprints/institutes/templates/overview/institute_sidebar.html +9 -1
  33. scout/server/blueprints/mme/__init__.py +1 -0
  34. scout/server/blueprints/mme/controllers.py +18 -0
  35. scout/server/blueprints/mme/templates/mme/mme_submissions.html +153 -0
  36. scout/server/blueprints/mme/views.py +34 -0
  37. scout/server/blueprints/panels/templates/panels/panel.html +19 -6
  38. scout/server/blueprints/phenotypes/templates/phenotypes/hpo_terms.html +8 -1
  39. scout/server/blueprints/variant/controllers.py +19 -10
  40. scout/server/blueprints/variant/templates/variant/acmg.html +9 -0
  41. scout/server/blueprints/variant/templates/variant/cancer-variant.html +1 -1
  42. scout/server/blueprints/variant/templates/variant/components.html +19 -16
  43. scout/server/blueprints/variant/templates/variant/sv-variant.html +2 -2
  44. scout/server/blueprints/variant/templates/variant/utils.html +20 -8
  45. scout/server/blueprints/variant/templates/variant/variant.html +42 -1
  46. scout/server/blueprints/variant/views.py +12 -0
  47. scout/server/blueprints/variants/controllers.py +17 -9
  48. scout/server/blueprints/variants/forms.py +8 -3
  49. scout/server/blueprints/variants/templates/variants/components.html +8 -2
  50. scout/server/blueprints/variants/templates/variants/indicators.html +11 -13
  51. scout/server/blueprints/variants/templates/variants/utils.html +27 -22
  52. scout/server/extensions/bionano_extension.py +0 -1
  53. scout/server/extensions/chanjo2_extension.py +54 -13
  54. scout/server/links.py +15 -0
  55. scout/server/static/bs_styles.css +34 -6
  56. scout/server/templates/utils.html +9 -10
  57. scout/server/utils.py +18 -0
  58. scout/utils/ensembl_biomart_clients.py +1 -0
  59. scout/utils/scout_requests.py +1 -3
  60. {scout_browser-4.99.0.dist-info → scout_browser-4.100.1.dist-info}/METADATA +1 -1
  61. {scout_browser-4.99.0.dist-info → scout_browser-4.100.1.dist-info}/RECORD +64 -60
  62. {scout_browser-4.99.0.dist-info → scout_browser-4.100.1.dist-info}/WHEEL +0 -0
  63. {scout_browser-4.99.0.dist-info → scout_browser-4.100.1.dist-info}/entry_points.txt +0 -0
  64. {scout_browser-4.99.0.dist-info → scout_browser-4.100.1.dist-info}/licenses/LICENSE +0 -0
@@ -132,6 +132,16 @@
132
132
  sourceType: 'file'
133
133
  },
134
134
  {% endfor %}
135
+ {% for maftrack in minor_allele_frequency_wigs %}
136
+ {
137
+ type: "wig",
138
+ format: 'bw',
139
+ name: '{{ maftrack.name }}',
140
+ url: '{{ url_for("alignviewers.remote_static", file=maftrack.url) }}',
141
+ color: "rgb(60, 60, 140)",
142
+ sourceType: 'file'
143
+ },
144
+ {% endfor %}
135
145
  {% for ptrack in paraphase_alignments %}
136
146
  {
137
147
  type: "alignment",
@@ -40,7 +40,12 @@ from scout.constants.variant_tags import (
40
40
  MANUAL_RANK_OPTIONS,
41
41
  )
42
42
  from scout.export.variant import export_mt_variants
43
- from scout.parse.matchmaker import genomic_features, hpo_terms, omim_terms, parse_matches
43
+ from scout.parse.matchmaker import (
44
+ genomic_features,
45
+ hpo_terms,
46
+ omim_terms,
47
+ parse_matches,
48
+ )
44
49
  from scout.server.blueprints.variant.controllers import variant as variant_decorator
45
50
  from scout.server.blueprints.variants.controllers import get_manual_assessments
46
51
  from scout.server.extensions import (
@@ -61,6 +66,7 @@ from scout.server.utils import (
61
66
  case_has_mt_alignments,
62
67
  case_has_mtdna_report,
63
68
  case_has_rna_tracks,
69
+ get_case_mito_chromosome,
64
70
  institute_and_case,
65
71
  )
66
72
  from scout.utils.acmg import get_acmg_temperature
@@ -788,11 +794,11 @@ def mt_excel_files(store, case_obj, temp_excel_dir):
788
794
 
789
795
  # Check if coverage and MT copy number stats are available via chanjo2 or chanjo
790
796
  if case_obj.get("chanjo2_coverage"):
791
- coverage_stats: Dict[str, dict] = chanjo2.mt_coverage_stats(individuals=samples)
797
+ coverage_stats: Dict[str, dict] = chanjo2.mt_coverage_stats(case_obj=case_obj)
792
798
  elif case_obj.get("chanjo_coverage"):
793
799
  coverage_stats: Dict[str, dict] = chanjo_report.mt_coverage_stats(individuals=samples)
794
800
 
795
- query = {"chrom": "MT"}
801
+ query = {"chrom": get_case_mito_chromosome(case_obj)}
796
802
  mt_variants = list(
797
803
  store.variants(case_id=case_obj["_id"], query=query, nr_of_variants=-1, sort_key="position")
798
804
  )
@@ -63,7 +63,7 @@
63
63
  </nav>
64
64
 
65
65
  <div id="container" class="container">
66
- <h4>Scout case analysis report</h4> - created on:&nbsp;<strong>{{report_created_at}}</strong> using <strong>Scout v.{{current_scout_version}}</strong><br><br>
66
+ <h4>Scout case analysis report</h4> - created on:&nbsp;<strong>{{report_created_at}}</strong> using <strong>Scout v{{current_scout_version}}</strong> for genome build <strong>{{case.genome_build }}</strong>.<br><br>
67
67
  {{ phenotype_panel() }}
68
68
  {{ gene_panels_panel()}}
69
69
  {{ causatives_panel()}}
@@ -104,7 +104,7 @@
104
104
  <td>Case created: <strong>{{case.created_at.strftime('%Y-%m-%d')}}</strong></td>
105
105
  <td>Last updated: <strong>{{case.updated_at.strftime('%Y-%m-%d') if case.updated_at else "n.a." }}</strong></td>
106
106
  {% if case.scout_load_version %}
107
- <td> Loaded with <strong>Scout v.{{case.scout_load_version}}</strong></td>
107
+ <td> Loaded with <strong>Scout v{{case.scout_load_version}}</strong></td>
108
108
  {% endif %}
109
109
  </tr>
110
110
  </table>
@@ -383,7 +383,7 @@
383
383
  {% set duplicated_variants = [] %}
384
384
  {% if variants.classified_detailed %}
385
385
  {% for variant in variants.classified_detailed|sort(attribute='variant_rank') %}
386
- {% if variant['_id'] not in printed_vars %}
386
+ {% if variant['_id'] not in printed_vars and variant not in variants.dismissed_detailed %}
387
387
  {% do printed_vars.append(variant['_id']) %}
388
388
  {{ variant_content(variant, loop.index) }}
389
389
  <br>
@@ -395,7 +395,7 @@
395
395
  No ACMG-classified variants available for this case
396
396
  {% endif %}
397
397
  {% if variants.classified_detailed and duplicated_variants|length == variants.classified_detailed|length %}
398
- All ACMG-classified variants are already described in the previous views
398
+ All ACMG-classified variants are already described in the other panels
399
399
  {% endif %}
400
400
  </div>
401
401
  </div>
@@ -410,7 +410,7 @@
410
410
  {% set duplicated_variants = [] %}
411
411
  {% if variants.ccv_classified_detailed %}
412
412
  {% for variant in variants.ccv_classified_detailed|sort(attribute='variant_rank') %}
413
- {% if variant['_id'] not in printed_vars %}
413
+ {% if variant['_id'] not in printed_vars and variant not in variants.dismissed_detailed %}
414
414
  {% do printed_vars.append(variant['_id']) %}
415
415
  {{ variant_content(variant, loop.index) }}
416
416
  <br>
@@ -422,7 +422,7 @@
422
422
  No ClinGen-CGC-VICC-classified variants available for this case
423
423
  {% endif %}
424
424
  {% if variants.ccv_classified_detailed and duplicated_variants|length == variants.ccv_classified_detailed|length %}
425
- All ClinGen-CGC-VICC-classified variants are already described in the previous views
425
+ All ClinGen-CGC-VICC-classified variants are already described in the other panels
426
426
  {% endif %}
427
427
  </div>
428
428
  </div>
@@ -437,7 +437,7 @@
437
437
  {% set duplicated_variants = [] %}
438
438
  {% if variants.tagged_detailed %}
439
439
  {% for variant in variants.tagged_detailed|sort(attribute='variant_rank') %}
440
- {% if variant['_id'] not in printed_vars %}
440
+ {% if variant['_id'] not in printed_vars and variant not in variants.dismissed_detailed %}
441
441
  {% do printed_vars.append(variant['_id']) %}
442
442
  {{ variant_content(variant, loop.index) }}
443
443
  <br>
@@ -461,7 +461,7 @@
461
461
  No tagged variants for this case
462
462
  {% endif %}
463
463
  {% if (variants.tagged_detailed or variants.tier_detailed) and duplicated_variants|length == (variants.tagged_detailed|length+variants.tier_detailed|length) %}
464
- All tagged variants are already described in the previous views
464
+ All tagged variants are already described in the other panels
465
465
  {% endif %}
466
466
  </div>
467
467
  </div>
@@ -500,7 +500,7 @@
500
500
  {% set duplicated_variants = [] %}
501
501
  {% if variants.commented_detailed %}
502
502
  {% for variant in variants.commented_detailed|sort(attribute='variant_rank') %}
503
- {% if variant['_id'] not in printed_vars %}
503
+ {% if variant['_id'] not in printed_vars and variant not in variants.dismissed_detailed %}
504
504
  {% do printed_vars.append(variant['_id']) %}
505
505
  {% if variant.category == 'snv' %}
506
506
  {{ sn_variant_content(variant, loop.index) }}
@@ -520,7 +520,7 @@
520
520
  No commented variants for this case
521
521
  {% endif %}
522
522
  {% if variants.commented_detailed and duplicated_variants|length == variants.commented_detailed|length %}
523
- All commented variants are already described in the previous views
523
+ All commented variants are already described in the other panels
524
524
  {% endif %}
525
525
  </div>
526
526
  </div>
@@ -845,7 +845,8 @@
845
845
  <th class="w-5"></th>
846
846
  <th class="w-25"><strong>Variant</strong></th>
847
847
  <th class="w-5"><strong>Category</strong></th>
848
- <th class="w-25"><strong>Genes</strong></th>
848
+ <th class="w-20"><strong>Genes</strong></th>
849
+ <th class="w-5"><strong>Classification</strong></th>
849
850
  <th class="w-45"><strong>Dismissed description</strong></th>
850
851
  </tr>
851
852
  </thead>
@@ -867,7 +868,14 @@
867
868
  <td style="width:15%;"
868
869
  {{ dismissed_gene_list(variant) }}
869
870
  </td>
870
-
871
+ <td>
872
+ {% if variant.acmg_classification %}
873
+ <span class="badge rounded-pill bg-{{variant.acmg_classification['color'] if variant.acmg_classification['color'] else 'secondary'}}" title="{{variant.acmg_classification['code']}}">{{variant.acmg_classification['short'] }}</span>
874
+ {% endif %}
875
+ {% if variant.ccv_classification %}
876
+ <span class="badge rounded-pill bg-{{variant.ccv_classification['color'] if variant.ccv_classification['color'] else 'secondary'}}" title="{{variant.ccv_classification['code']}}">{{variant.ccv_classification['short'] }}</span>
877
+ {% endif %}
878
+ </td>
871
879
  <td rowspan="2">
872
880
  <ul>
873
881
  {% for reason in variant.dismiss_variant if not reason == "Select a tag" %}
@@ -1531,7 +1539,11 @@
1531
1539
  <td>
1532
1540
  {% if variant.acmg_classification %}
1533
1541
  <span class="badge rounded-pill bg-{{variant.acmg_classification['color'] if variant.acmg_classification['color'] else 'secondary'}}" title="{{variant.acmg_classification['code']}}">{{variant.acmg_classification['short'] }}</span>
1534
- {% elif variant.manual_rank %}
1542
+ {% endif %}
1543
+ {% if variant.ccv_classification%}
1544
+ <span class="badge rounded-pill bg-{{variant.ccv_classification['color'] if variant.ccv_classification['color'] else 'secondary'}}" title="{{variant.ccv_classification['code']}}">{{variant.ccv_classification['short'] }}</span>
1545
+ {% endif%}
1546
+ {% if variant.manual_rank %}
1535
1547
  <span class="badge rounded-pill bg-secondary" title="Manual rank">{{ manual_rank_options[variant.manual_rank]['label'] }}</span>
1536
1548
  {% else %}
1537
1549
  -
@@ -1,6 +1,6 @@
1
1
  {% macro chanjo2_report_form(institute_obj, case_obj, panel_name, report_type, hgnc_ids, link_text, link_class = "link-primary") %}
2
2
 
3
- {% set form_name = "chanjo2_"+panel_name+"_"+report_type %}
3
+ {% set form_name = "chanjo2_" ~ panel_name ~ "_" ~ report_type %}
4
4
  {% set form_action = config.CHANJO2_URL+"/"+report_type %}
5
5
  {% set build = "GRCh38" if "38" in case_obj.get("genome_build", "37") else "GRCh37" %}
6
6
  {% set default_level = institute_obj.coverage_cutoff %}
@@ -196,7 +196,7 @@
196
196
  <div href="#" class="bg-dark list-group-item text-white" data-bs-toggle="tooltip" title="Scout version used for loading the case" data-bs-placement="right">
197
197
  <div class="d-flex w-100 justify-content-start align-items-center">
198
198
  <span class="fa fa-gear fa-fw me-3"></span>
199
- <span class="menu-collapsed">v.{{ case.scout_load_version }}</span>
199
+ <span class="menu-collapsed">v{{ case.scout_load_version }}</span>
200
200
  </div>
201
201
  </div>
202
202
  {% endif %}
@@ -18,7 +18,7 @@
18
18
  {% for panel in case.panels %}
19
19
  <tr {% if panel.is_default %} class="bg-info" {% endif %}>
20
20
  <td>
21
- <a {% if panel.is_default %} class="text-white" {% endif %} href="{{ url_for('panels.panel', panel_id=panel.panel_id, case_id=case._id, institute_id=institute._id) }}">
21
+ <a {% if panel.is_default %} class="text-white" {% endif %} href="{{ url_for('panels.panel', panel_id=panel.panel_id, case_id=case._id, institute_id=institute._id) }}" target="_blank" rel="noopener">
22
22
  {{ panel.display_name|truncate(30, True) }}
23
23
  </a>
24
24
  {% if panel.removed %}
@@ -313,6 +313,22 @@
313
313
 
314
314
  {{ display_genes|join(", ") }}
315
315
 
316
+ {% elif variant.category == "outlier" %}
317
+ {{ variant.sub_category|upper }} - {% if variant.genes %}
318
+ {% for gene in variant.genes %}
319
+ {% if gene.hgnc_symbol %}
320
+ {{ gene.hgnc_symbol }}
321
+ {% else %}
322
+ {{gene.hgnc_id}}
323
+ {% endif %}
324
+ {% endfor %} - {% if variant.sub_category == "splicing" %}
325
+ {{ variant.delta_psi }}&Delta;&psi; {{ variant.potential_impact }} - fs {{ variant.causes_frameshift }}
326
+ {% else %}
327
+ {{ variant.l2fc }}{% if variant.l2fc > 0 %}&uarr;{% elif variant.l2fc < 0 %}&darr;{% endif %}
328
+ {% endif %}
329
+ {% else %}
330
+ {{ variant.gene_name_orig }}
331
+ {% endif %}
316
332
  {% else %} <!-- structural variants -->
317
333
  {{ variant.sub_category|upper }}({{ variant.chromosome }}{{ variant.cytoband_start }}-{{ variant.end_chrom }}{{ variant.cytoband_end }})
318
334
  {% endif %}
@@ -335,6 +351,9 @@
335
351
  case_name=case.display_name,
336
352
  variant_id=variant._id) }}' target='_blank'>
337
353
  {% endif %}
354
+ {% elif variant.category == "outlier" %}
355
+ <a href='{{ url_for('omics_variants.outliers',
356
+ institute_id=variant.institute, case_name=case.display_name) }}' target='_blank'>
338
357
  {% else %} <!-- structural variants -->
339
358
  <a href='{{ url_for('variant.sv_variant',
340
359
  institute_id=variant.institute,
@@ -619,8 +619,12 @@ def remove_item_from_submission(submission: str, object_type: str, subm_variant_
619
619
  if object_type == "variant_data":
620
620
  variant_id: str = subm_variant_id.split("_")[-1]
621
621
  variant_obj: dict = store.variant(document_id=variant_id)
622
+ if not variant_obj:
623
+ return
624
+ case_obj = store.case(case_id=variant_obj["case_id"])
625
+ if not case_obj:
626
+ return
622
627
  institute_obj: dict = store.institute(institute_id=variant_obj["institute"])
623
- case_obj: dict = store.case(case_id=variant_obj["case_id"])
624
628
  user_obj: dict = store.user(user_id=current_user._id)
625
629
  for category in ["case", "variant"]:
626
630
  store.create_event(
@@ -126,13 +126,19 @@
126
126
  </thead>
127
127
  <tbody>
128
128
  {% set var_key_name = {} %}
129
+
129
130
  {% for subm_variant in subm_obj.variant_data %} <!-- loop over the submitted variants-->
131
+ {% set case_name = subm_obj.cases[subm_variant.case_id] %}
130
132
  <tr>
131
133
  <td>{{loop.index}}</td>
132
134
  {% if subm_variant.category == 'sv' %}
133
135
  {% do var_key_name.update( {subm_variant.local_id : '_'.join([subm_variant.var_type, subm_variant.chromosome, subm_variant.breakpoint1 or subm_variant.outer_start or ""]) }) %}
134
136
  <td>
135
- <a href="{{ url_for('variant.sv_variant', institute_id=institute._id, case_name=subm_obj.cases[subm_variant.case_id], variant_id=subm_variant.local_id) }}" target="_blank" rel="noopener"><strong>{{var_key_name[subm_variant.local_id]|truncate(25,true,'..')}}</strong></a>
137
+ {% if "N/A" not in case_name %}
138
+ <a href="{{ url_for('variant.sv_variant', institute_id=institute._id, case_name=case_name, variant_id=subm_variant.local_id) }}" target="_blank" rel="noopener"><strong>{{var_key_name[subm_variant.local_id]|truncate(25,true,'..')}}</strong></a>
139
+ {% else %}
140
+ {{ var_key_name[subm_variant.local_id]|truncate(25,true,'..') }} (N/A)
141
+ {% endif %}
136
142
  </td>
137
143
  <td><button id="{{subm_variant._id}}" type="button" class="btn btn-primary btn-xs var_btn"><span class="fa fa-search-plus" aria-hidden="true"></span></button></td>
138
144
  <td><div class="badge bg-warning">SV</div></td>
@@ -143,21 +149,27 @@
143
149
  {% do var_key_name.update({subm_variant.local_id : '_'.join([subm_variant.chromosome, subm_variant.start, subm_variant.ref[0:5], subm_variant.alt[0:5]]) }) %}
144
150
  {% endif %}
145
151
  <td>
146
- <a href="{{ url_for('variant.variant', institute_id=institute._id, case_name=subm_obj.cases[subm_variant.case_id], variant_id=subm_variant.local_id) }}" target="_blank" rel="noopener"><strong>{{var_key_name[subm_variant.local_id]|truncate(25,true,'..')}}</strong></a>
152
+ {% if "N/A" not in case_name %}
153
+ <a href="{{ url_for('variant.variant', institute_id=institute._id, case_name=case_name, variant_id=subm_variant.local_id) }}" target="_blank" rel="noopener"><strong>{{var_key_name[subm_variant.local_id]|truncate(25,true,'..')}}</strong></a>
154
+ {% else %}
155
+ {{ var_key_name[subm_variant.local_id]|truncate(25,true,'..') }} (N/A)
156
+ {% endif %}
147
157
  </td>
148
158
  <td><button id="{{subm_variant._id}}" type="button" class="btn btn-primary btn-xs var_btn"><span class="fa fa-search-plus" aria-hidden="true"></span></button></td>
149
159
  <td><div class="badge bg-success">SNV</div></td>
150
160
  {% endif %}
151
161
  </td>
152
- <td><a href="{{ url_for('cases.case', institute_id=institute._id, case_name=subm_obj.cases[subm_variant.case_id]) }}" target="_blank" rel="noopener">{{subm_obj.cases[subm_variant.case_id]}}</a></td>
162
+ <td>{{ case_link(institute_id=institute._id, case_name=case_name) }}</td>
153
163
  <td>{{subm_variant.ref_seq or '-'}}</td>
154
164
  <td>{{subm_variant.gene_symbol or '-'}}</td>
155
165
  <td>{{subm_variant.hgvs|truncate(100,true,'..') or '-'}}</td>
156
166
  <td>{{subm_variant.clinsig}}</td>
157
167
  <td>{{subm_variant.added_by or "N/A"}}</td>
158
- <form id="delete_variant_{{subm_variant._id}}" action="{{ url_for('clinvar.clinvar_delete_object', submission=subm_obj._id, object_type='variant_data') }}" method="POST">
159
- <td><button type="submit" name="delete_object" value="{{subm_variant._id}}" class="btn btn-danger btn-xs"><span class="fa fa-trash" aria-hidden="true"></span></button></td>
160
- </form>
168
+ <td>
169
+ <form id="delete_variant_{{subm_variant._id}}" action="{{ url_for('clinvar.clinvar_delete_object', submission=subm_obj._id, object_type='variant_data') }}" method="POST">
170
+ <button type="submit" name="delete_object" value="{{subm_variant._id}}" class="btn btn-danger btn-xs"><span class="fa fa-trash" aria-hidden="true"></span></button>
171
+ </form>
172
+ </td>
161
173
  </tr>
162
174
  <tr>
163
175
  <td colspan=11>
@@ -191,9 +203,9 @@
191
203
  <thead>
192
204
  <tr>
193
205
  <th></th>
194
- <th>Individual ID</th>
206
+ <th>Individual</th>
195
207
  <th></th>
196
- <th>Case ID</th>
208
+ <th>Case</th>
197
209
  <th>Variant</th>
198
210
  <th>Allele origin</th>
199
211
  <th></th>
@@ -209,12 +221,14 @@
209
221
  </td>
210
222
  </form>
211
223
  <td><button id="{{case._id}}" type="button" class="btn btn-primary btn-xs cd_btn"><span class="fa fa-search-plus" aria-hidden="true"></span></button></td>
212
- <td><a href="{{ url_for('cases.case', institute_id=institute._id, case_name=subm_obj.cases[case.case_id]) }}" target="_blank" rel="noopener">{{subm_obj.cases[case.case_id]}}</a></td>
224
+ <td>{{ case_link(institute_id=institute._id, case_name=subm_obj.cases[case.case_id]) }}</td>
213
225
  <td>{{var_key_name[case.linking_id]|truncate(100,true,'..')}}</td>
214
226
  <td>{{case.allele_origin}}</td>
215
- <form id="delete_casedata_{{case._id}}" action="{{ url_for('clinvar.clinvar_delete_object', submission=subm_obj._id, object_type='case_data') }}" method="POST">
216
- <td><button type="submit" name="delete_object" value="{{case._id}}" class="btn btn-danger btn-xs"><span class="fa fa-trash" aria-hidden="true"></span></button></td>
217
- </form>
227
+ <td>
228
+ <form id="delete_casedata_{{case._id}}" action="{{ url_for('clinvar.clinvar_delete_object', submission=subm_obj._id, object_type='case_data') }}" method="POST">
229
+ <button type="submit" name="delete_object" value="{{case._id}}" class="btn btn-danger btn-xs"><span class="fa fa-trash" aria-hidden="true"></span></button>
230
+ </form>
231
+ </td>
218
232
  </tr>
219
233
  <tr>
220
234
  <td colspan=8>
@@ -242,6 +256,14 @@
242
256
  </div>
243
257
  {% endmacro %}
244
258
 
259
+ {% macro case_link(institute_id, case_name) %}
260
+ {% if "N/A" in case_name %}
261
+ {{ case_name }}
262
+ {% else %}
263
+ <a href="{{ url_for('cases.case', institute_id=institute_id, case_name=case_name) }}" target="_blank">{{case_name}}</a>
264
+ {% endif %}
265
+ {% endmacro %}
266
+
245
267
  {% macro action_modal(action_type, subm_id) %}
246
268
  <div class="modal fade" id="{{action_type}}Modal_{{subm_id}}" tabindex="-1">
247
269
  <div class="modal-dialog">
@@ -81,7 +81,7 @@
81
81
  </div>
82
82
  <div class="my-2 mx-lg-2" style="width:30%; display: inline">{{variant_data.var_form.assertion_method_cit_id(class="bg-white")}}</div>
83
83
  </div>
84
-
84
+ <input type="button" name="previous" class="previous action-button-previous" value="Previous"/>
85
85
  <input type="button" name="next" class="next action-button" value="Next"/>
86
86
  </fieldset>
87
87
  <fieldset data-step="3">
@@ -135,7 +135,14 @@ function initialiseTable(data) {
135
135
  $('#diagnoses_table').DataTable({
136
136
  data: data,
137
137
  paging: true,
138
- dom: 'Brtip',
138
+ layout: {
139
+ topStart: 'buttons',
140
+ topEnd: {
141
+ search: {
142
+ placeholder: 'Filter further...'
143
+ }
144
+ }
145
+ },
139
146
  buttons: [
140
147
  {
141
148
  extend: 'excelHtml5',
@@ -1,7 +1,15 @@
1
1
  $(document).ready(function() {
2
2
  $('#variants_table').DataTable( {
3
3
  paging: false,
4
- dom: 'Bfrtip',
4
+ searching: true,
5
+ layout: {
6
+ topStart: 'buttons',
7
+ topEnd: {
8
+ search: {
9
+ placeholder: 'Search'
10
+ }
11
+ }
12
+ },
5
13
  buttons: [
6
14
  'copyHtml5',
7
15
  'excelHtml5',
@@ -51,7 +51,15 @@
51
51
  </div>
52
52
  </a>
53
53
 
54
- <!-- Variant filters -->
54
+ <!-- MME data menu item -->
55
+ <a href="{{ url_for('mme.mme_submissions', institute_id=institute._id) }}" class="bg-dark list-group-item list-group-item-action flex-column align-items-start">
56
+ <div class="d-flex w-100 justify-content-start align-items-center">
57
+ <span class="fas fa-people-arrows me-3"></span>
58
+ <span class="menu-collapsed">MME submissions</span>
59
+ </div>
60
+ </a>
61
+
62
+ <!-- Variant filters -->
55
63
  <a href="{{ url_for('overview.filters', institute_id=institute._id) }}" class="bg-dark list-group-item list-group-item-action flex-column align-items-start">
56
64
  <div class="d-flex w-100 justify-content-start align-items-center">
57
65
  <span class="fa fa-filter me-3"></span>
@@ -0,0 +1 @@
1
+ from .views import mme_bp
@@ -0,0 +1,18 @@
1
+ from typing import List
2
+
3
+ from scout.server.extensions import store
4
+
5
+
6
+ def institute_mme_cases(institute_id: str) -> List[dict]:
7
+ """Retrieves all cases for a given institute with an active MatchMaker Exchange submission."""
8
+ institute_mme_events = store.institute_events_by_verb(
9
+ category="case", institute_id=institute_id, verb="mme_add"
10
+ )
11
+ unique_case_ids = set([event["case"] for event in institute_mme_events])
12
+ mme_cases = []
13
+ for case_id in unique_case_ids:
14
+ case_obj = store.case(case_id=case_id)
15
+ if not case_obj or not case_obj.get("mme_submission"):
16
+ continue
17
+ mme_cases.append(case_obj)
18
+ return mme_cases
@@ -0,0 +1,153 @@
1
+ {% extends "layout.html" %}
2
+ {% from "overview/institute_sidebar.html" import institute_actionbar %}
3
+ {% from "utils.html" import db_table_external_scripts, db_table_external_stylesheets %}
4
+
5
+ {% block title %}
6
+ {{ super() }} - Institutes
7
+ {% endblock %}
8
+
9
+ {% block css %}
10
+ {{ super() }}
11
+ {{ db_table_external_stylesheets() }}
12
+ {% endblock %}
13
+
14
+ {% block top_nav %}
15
+ {{ super() }}
16
+ <li class="nav-item">
17
+ <a class="nav-link" href="{{ url_for('cases.index') }}">Institutes</a>
18
+ </li>
19
+ <li class="nav-item">
20
+ <a class="nav-link" href="{{ url_for('overview.cases', institute_id=institute._id) }}">{{ institute.display_name }}</a>
21
+ </li>
22
+ <li class="nav-item active d-flex align-items-center">
23
+ <span class="navbar-text">Cases in MatchMaker Exchange</span>
24
+ </li>
25
+ {% endblock %}
26
+
27
+ {% block content_main %}
28
+ <div class="container-float">
29
+ <div class="row mt-3" id="body-row"> <!--sidebar and main container are on the same row-->
30
+ <div class="col">
31
+ {{ mme_submitted() }}
32
+ </div>
33
+ </div>
34
+ </div>
35
+ {% endblock %}
36
+
37
+ {% macro mme_submitted() %}
38
+ <table class="table table-bordered table-striped" id="mmeTable">
39
+ <thead>
40
+ <tr>
41
+ <th>Case Name</th>
42
+ <th>Synopsis</th>
43
+ <th>Status</th>
44
+ <th>Case Assignees</th>
45
+ <th>MME Submission Updated</th>
46
+ <th>MME Patient(s)</th>
47
+ <th>MME Phenotype Features</th>
48
+ <th>MME Genomic Features</th>
49
+ </tr>
50
+ </thead>
51
+ <tbody>
52
+ {% for case in mme_cases %}
53
+ <tr>
54
+ <td>
55
+ <a class="me-2" href="{{ url_for('cases.case', institute_id=case.owner, case_name=case.display_name) }}" target="_blank" rel="noopener">
56
+ {{ case.display_name }}
57
+ </a>
58
+ </td>
59
+ <td class="synopsis-cell" style="max-width: 300px;">
60
+ {% set collapse_id = 'collapse-' + case._id %}
61
+ {% set max_chars = 300 %}
62
+
63
+ {% if case.synopsis|length > max_chars %}
64
+ <div>
65
+ {{ case.synopsis[:max_chars] }}…
66
+ </div>
67
+
68
+ <a
69
+ class="btn btn-link p-0"
70
+ data-bs-toggle="collapse"
71
+ href="#{{ collapse_id }}"
72
+ role="button"
73
+ aria-expanded="false"
74
+ aria-controls="{{ collapse_id }}"
75
+ >More…</a>
76
+
77
+ <div class="collapse mt-1" id="{{ collapse_id }}">
78
+ <div class="card card-body p-2">
79
+ {{ case.synopsis }}
80
+ </div>
81
+ </div>
82
+ {% else %}
83
+ {{ case.synopsis }}
84
+ {% endif %}
85
+ </td>
86
+ <td>{{ case.status }}</td>
87
+ <td>
88
+ {% for assignee in case.assignees %}
89
+ <div>{{ assignee }}</div>
90
+ {% endfor %}
91
+ </td>
92
+ <td>
93
+ {{ case.mme_submission.updated_at.strftime('%Y-%m-%d %H:%M') }}
94
+ </td>
95
+ <td>
96
+ {% for patient in case.mme_submission.patients %}
97
+ <div>
98
+ <strong>{{ patient.label }}</strong> ({{ patient.sex }})<br>
99
+ <small>Contact: {{ patient.contact.name }} - <a href="{{ patient.contact.href }}">{{ patient.contact.href }}</a></small>
100
+ </div>
101
+ {% endfor %}
102
+ </td>
103
+ <td>
104
+ {% for disorder in case.mme_submission.disorders %}
105
+ <div>{{ disorder.label }} ({{ disorder.id }})</div>
106
+ {% endfor %}
107
+ </td>
108
+ <td>
109
+ {% for patient in case.mme_submission.patients %}
110
+ {% for gf in patient.genomicFeatures %}
111
+ <div>
112
+ <strong>{{ gf.gene.id }}</strong><br>
113
+ {% if gf.variant %}
114
+ Chr{{ gf.variant.referenceName }}:
115
+ {{ gf.variant.start|human_longint|safe }}-{{ gf.variant.end|human_longint|safe }}<br>
116
+ {{ gf.variant.referenceBases }} → {{ gf.variant.alternateBases }}<br>
117
+ Assembly: {{ gf.variant.assembly }}<br>
118
+ Zygosity: {{ gf.zygosity }}
119
+ {% endif %}
120
+ </div>
121
+ <hr>
122
+ {% endfor %}
123
+ {% endfor %}
124
+ </td>
125
+ </tr>
126
+ {% endfor %}
127
+ </tbody>
128
+ </table>
129
+ {% endmacro %}
130
+
131
+
132
+ {% block scripts %}
133
+ {{ super() }}
134
+ {{ db_table_external_scripts() }}
135
+ <script>
136
+ $(document).ready(function () {
137
+ $('#mmeTable').DataTable({
138
+ paging: true,
139
+ searching: true,
140
+ ordering: true,
141
+ responsive: true,
142
+ language: {
143
+ search: "Search all fields:",
144
+ lengthMenu: "Show _MENU_ entries",
145
+ info: "Showing _START_ to _END_ of _TOTAL_ cases",
146
+ },
147
+ columnDefs: [
148
+ { orderable: false, targets: [3, 5, 6, 7] } // Disable sorting for multi-line complex columns
149
+ ]
150
+ });
151
+ });
152
+ </script>
153
+ {% endblock %}
@@ -0,0 +1,34 @@
1
+ import logging
2
+
3
+ from flask import (
4
+ Blueprint,
5
+ render_template,
6
+ url_for,
7
+ )
8
+
9
+ from scout.server.extensions import store
10
+ from scout.server.utils import institute_and_case
11
+
12
+ from . import controllers
13
+
14
+ LOG = logging.getLogger(__name__)
15
+
16
+ mme_bp = Blueprint(
17
+ "mme",
18
+ __name__,
19
+ template_folder="templates",
20
+ static_folder="static",
21
+ static_url_path="/mme/static",
22
+ )
23
+
24
+
25
+ @mme_bp.route("/<institute_id>/mme_submissions", methods=["GET"])
26
+ def mme_submissions(institute_id: str):
27
+ """Retrieve all cases for an institute with associated a MME submission."""
28
+
29
+ institute_obj = institute_and_case(store, institute_id)
30
+ data = {
31
+ "institute": institute_obj,
32
+ "mme_cases": controllers.institute_mme_cases(institute_id=institute_id),
33
+ }
34
+ return render_template("mme/mme_submissions.html", **data)