Skip to content

Commit

Permalink
Merge pull request #500 from UW-GAC/feature/add-associated-data-prep-…
Browse files Browse the repository at this point in the history
…workspace-tables-on-workspace-detail

Add "associated data prep workspace" accordions/tables on some workspace detail pages
  • Loading branch information
amstilp authored Mar 14, 2024
2 parents 6e5806f + 9a63e19 commit 750dac6
Show file tree
Hide file tree
Showing 8 changed files with 281 additions and 2 deletions.
44 changes: 44 additions & 0 deletions add_data_prep_example_data.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# Temporary script to create some test data.
# Run with: python manage.py shell < add_data_prep_example_data.py


from primed.cdsa.tests.factories import CDSAWorkspaceFactory
from primed.dbgap.tests.factories import dbGaPWorkspaceFactory
from primed.miscellaneous_workspaces.tests import factories
from primed.primed_anvil.tests.factories import StudyFactory

# Create a dbGaP workspace.
fhs = StudyFactory.create(short_name="FHS", full_name="Framingham Heart Study")
workspace_dbgap = dbGaPWorkspaceFactory.create(
dbgap_study_accession__dbgap_phs=7,
dbgap_study_accession__studies=[fhs],
dbgap_version=33,
dbgap_participant_set=12,
dbgap_consent_code=1,
dbgap_consent_abbreviation="HMB",
workspace__name="DBGAP_FHS_v33_p12_HMB",
)

# Create a data prep workspace.
workspace_dbgap_prep = factories.DataPrepWorkspaceFactory.create(
target_workspace=workspace_dbgap.workspace,
workspace__name="DBGAP_FHS_v33_p12_HMB_PREP",
)


# Create a CDSA workspace.
workspace_cdsa = CDSAWorkspaceFactory.create(
study__short_name="MESA",
workspace__name="CDSA_MESA_HMB",
)

# Create a data prep workspace.
factories.DataPrepWorkspaceFactory.create(
target_workspace=workspace_cdsa.workspace,
workspace__name="CDSA_MESA_HMB_PREP_1",
is_active=False,
)
workspace_cdsa_prep = factories.DataPrepWorkspaceFactory.create(
target_workspace=workspace_cdsa.workspace,
workspace__name="CDSA_MESA_HMB_PREP_2",
)
15 changes: 13 additions & 2 deletions primed/cdsa/adapters.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
from anvil_consortium_manager.adapters.workspace import BaseWorkspaceAdapter
from anvil_consortium_manager.forms import WorkspaceForm
from anvil_consortium_manager.models import Workspace

from primed.miscellaneous_workspaces.tables import DataPrepWorkspaceTable

from . import forms, models, tables

Expand All @@ -20,9 +23,17 @@ class CDSAWorkspaceAdapter(BaseWorkspaceAdapter):
workspace_detail_template_name = "cdsa/cdsaworkspace_detail.html"

def get_extra_detail_context_data(self, workspace, request):
# Get the primary CDSA for this study, assuming it exists.
extra_context = {}
# Data use limitations from CDSA
associated_data_prep = Workspace.objects.filter(
dataprepworkspace__target_workspace=workspace
)
extra_context["associated_data_prep_workspaces"] = DataPrepWorkspaceTable(
associated_data_prep
)
extra_context["data_prep_active"] = associated_data_prep.filter(
dataprepworkspace__is_active=True
).exists()
# Get the primary CDSA for this study, assuming it exists.
try:
extra_context["primary_cdsa"] = workspace.cdsaworkspace.get_primary_cdsa()
except models.DataAffiliateAgreement.DoesNotExist:
Expand Down
91 changes: 91 additions & 0 deletions primed/cdsa/tests/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@
from freezegun import freeze_time

from primed.duo.tests.factories import DataUseModifierFactory, DataUsePermissionFactory
from primed.miscellaneous_workspaces.tables import DataPrepWorkspaceTable
from primed.miscellaneous_workspaces.tests.factories import DataPrepWorkspaceFactory
from primed.primed_anvil.tests.factories import (
AvailableDataFactory,
StudyFactory,
Expand Down Expand Up @@ -7283,6 +7285,95 @@ def test_render_duo_modifiers(self):
self.assertContains(response, modifiers[0].abbreviation)
self.assertContains(response, modifiers[1].abbreviation)

def test_associated_data_prep_workspaces_context_exists(self):
obj = factories.CDSAWorkspaceFactory.create()
self.client.force_login(self.user)
response = self.client.get(obj.get_absolute_url())
self.assertIn("associated_data_prep_workspaces", response.context_data)
self.assertIsInstance(
response.context_data["associated_data_prep_workspaces"],
DataPrepWorkspaceTable,
)

def test_only_show_one_associated_data_prep_workspace(self):
cdsa_obj = factories.CDSAWorkspaceFactory.create()
dataPrep_obj = DataPrepWorkspaceFactory.create(
target_workspace=cdsa_obj.workspace
)
self.client.force_login(self.user)
response = self.client.get(cdsa_obj.get_absolute_url())
self.assertIn("associated_data_prep_workspaces", response.context_data)
self.assertEqual(
len(response.context_data["associated_data_prep_workspaces"].rows), 1
)
self.assertIn(
dataPrep_obj.workspace,
response.context_data["associated_data_prep_workspaces"].data,
)

def test_show_two_associated_data_prep_workspaces(self):
cdsa_obj = factories.CDSAWorkspaceFactory.create()
dataPrep_obj1 = DataPrepWorkspaceFactory.create(
target_workspace=cdsa_obj.workspace
)
dataPrep_obj2 = DataPrepWorkspaceFactory.create(
target_workspace=cdsa_obj.workspace
)
self.client.force_login(self.user)
response = self.client.get(cdsa_obj.get_absolute_url())
self.assertIn("associated_data_prep_workspaces", response.context_data)
self.assertEqual(
len(response.context_data["associated_data_prep_workspaces"].rows), 2
)
self.assertIn(
dataPrep_obj1.workspace,
response.context_data["associated_data_prep_workspaces"].data,
)
self.assertIn(
dataPrep_obj2.workspace,
response.context_data["associated_data_prep_workspaces"].data,
)

def test_context_data_prep_active_with_no_prep_workspace(self):
instance = factories.CDSAWorkspaceFactory.create()
self.client.force_login(self.user)
response = self.client.get(instance.get_absolute_url())
self.assertIn("data_prep_active", response.context_data)
self.assertFalse(response.context["data_prep_active"])

def test_context_data_prep_active_with_one_inactive_prep_workspace(self):
instance = factories.CDSAWorkspaceFactory.create()
DataPrepWorkspaceFactory.create(
target_workspace=instance.workspace, is_active=False
)
self.client.force_login(self.user)
response = self.client.get(instance.get_absolute_url())
self.assertIn("data_prep_active", response.context_data)
self.assertFalse(response.context["data_prep_active"])

def test_context_data_prep_active_with_one_active_prep_workspace(self):
instance = factories.CDSAWorkspaceFactory.create()
DataPrepWorkspaceFactory.create(
target_workspace=instance.workspace, is_active=True
)
self.client.force_login(self.user)
response = self.client.get(instance.get_absolute_url())
self.assertIn("data_prep_active", response.context_data)
self.assertTrue(response.context["data_prep_active"])

def test_context_data_prep_active_with_one_active_one_inactive_prep_workspace(self):
instance = factories.CDSAWorkspaceFactory.create()
DataPrepWorkspaceFactory.create(
target_workspace=instance.workspace, is_active=True
)
DataPrepWorkspaceFactory.create(
target_workspace=instance.workspace, is_active=True
)
self.client.force_login(self.user)
response = self.client.get(instance.get_absolute_url())
self.assertIn("data_prep_active", response.context_data)
self.assertTrue(response.context["data_prep_active"])

def test_response_context_primary_cdsa(self):
agreement = factories.DataAffiliateAgreementFactory.create(
signed_agreement__is_primary=True,
Expand Down
16 changes: 16 additions & 0 deletions primed/dbgap/adapters.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
from anvil_consortium_manager.adapters.workspace import BaseWorkspaceAdapter
from anvil_consortium_manager.forms import WorkspaceForm
from anvil_consortium_manager.models import Workspace

from primed.miscellaneous_workspaces.tables import DataPrepWorkspaceTable

from . import forms, models, tables

Expand All @@ -16,3 +19,16 @@ class dbGaPWorkspaceAdapter(BaseWorkspaceAdapter):
workspace_data_model = models.dbGaPWorkspace
workspace_data_form_class = forms.dbGaPWorkspaceForm
workspace_detail_template_name = "dbgap/dbgapworkspace_detail.html"

def get_extra_detail_context_data(self, workspace, request):
extra_context = {}
associated_data_prep = Workspace.objects.filter(
dataprepworkspace__target_workspace=workspace
)
extra_context["associated_data_prep_workspaces"] = DataPrepWorkspaceTable(
associated_data_prep
)
extra_context["data_prep_active"] = associated_data_prep.filter(
dataprepworkspace__is_active=True
).exists()
return extra_context
91 changes: 91 additions & 0 deletions primed/dbgap/tests/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@
from freezegun import freeze_time

from primed.duo.tests.factories import DataUseModifierFactory, DataUsePermissionFactory
from primed.miscellaneous_workspaces.tables import DataPrepWorkspaceTable
from primed.miscellaneous_workspaces.tests.factories import DataPrepWorkspaceFactory
from primed.primed_anvil.tests.factories import ( # DataUseModifierFactory,; DataUsePermissionFactory,
StudyFactory,
)
Expand Down Expand Up @@ -951,6 +953,95 @@ def test_links_audit_access_view_permission(self):
),
)

def test_associated_data_prep_workspaces_context_exists(self):
obj = factories.dbGaPWorkspaceFactory.create()
self.client.force_login(self.user)
response = self.client.get(obj.get_absolute_url())
self.assertIn("associated_data_prep_workspaces", response.context_data)
self.assertIsInstance(
response.context_data["associated_data_prep_workspaces"],
DataPrepWorkspaceTable,
)

def test_only_show_one_associated_data_prep_workspace(self):
dbGaP_obj = factories.dbGaPWorkspaceFactory.create()
dataPrep_obj = DataPrepWorkspaceFactory.create(
target_workspace=dbGaP_obj.workspace
)
self.client.force_login(self.user)
response = self.client.get(dbGaP_obj.get_absolute_url())
self.assertIn("associated_data_prep_workspaces", response.context_data)
self.assertEqual(
len(response.context_data["associated_data_prep_workspaces"].rows), 1
)
self.assertIn(
dataPrep_obj.workspace,
response.context_data["associated_data_prep_workspaces"].data,
)

def test_show_two_associated_data_prep_workspaces(self):
dbGaP_obj = factories.dbGaPWorkspaceFactory.create()
dataPrep_obj1 = DataPrepWorkspaceFactory.create(
target_workspace=dbGaP_obj.workspace
)
dataPrep_obj2 = DataPrepWorkspaceFactory.create(
target_workspace=dbGaP_obj.workspace
)
self.client.force_login(self.user)
response = self.client.get(dbGaP_obj.get_absolute_url())
self.assertIn("associated_data_prep_workspaces", response.context_data)
self.assertEqual(
len(response.context_data["associated_data_prep_workspaces"].rows), 2
)
self.assertIn(
dataPrep_obj1.workspace,
response.context_data["associated_data_prep_workspaces"].data,
)
self.assertIn(
dataPrep_obj2.workspace,
response.context_data["associated_data_prep_workspaces"].data,
)

def test_context_data_prep_active_with_no_prep_workspace(self):
instance = factories.dbGaPWorkspaceFactory.create()
self.client.force_login(self.user)
response = self.client.get(instance.get_absolute_url())
self.assertIn("data_prep_active", response.context_data)
self.assertFalse(response.context["data_prep_active"])

def test_context_data_prep_active_with_one_inactive_prep_workspace(self):
instance = factories.dbGaPWorkspaceFactory.create()
DataPrepWorkspaceFactory.create(
target_workspace=instance.workspace, is_active=False
)
self.client.force_login(self.user)
response = self.client.get(instance.get_absolute_url())
self.assertIn("data_prep_active", response.context_data)
self.assertFalse(response.context["data_prep_active"])

def test_context_data_prep_active_with_one_active_prep_workspace(self):
instance = factories.dbGaPWorkspaceFactory.create()
DataPrepWorkspaceFactory.create(
target_workspace=instance.workspace, is_active=True
)
self.client.force_login(self.user)
response = self.client.get(instance.get_absolute_url())
self.assertIn("data_prep_active", response.context_data)
self.assertTrue(response.context["data_prep_active"])

def test_context_data_prep_active_with_one_active_one_inactive_prep_workspace(self):
instance = factories.dbGaPWorkspaceFactory.create()
DataPrepWorkspaceFactory.create(
target_workspace=instance.workspace, is_active=True
)
DataPrepWorkspaceFactory.create(
target_workspace=instance.workspace, is_active=True
)
self.client.force_login(self.user)
response = self.client.get(instance.get_absolute_url())
self.assertIn("data_prep_active", response.context_data)
self.assertTrue(response.context["data_prep_active"])


class dbGaPWorkspaceCreateTest(AnVILAPIMockTestMixin, TestCase):
"""Tests of the WorkspaceCreate view from ACM with this app's dbGaPWorkspace model."""
Expand Down
3 changes: 3 additions & 0 deletions primed/templates/cdsa/cdsaworkspace_detail.html
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{% extends "anvil_consortium_manager/workspace_detail.html" %}
{% load render_table from django_tables2 %}

{% block pills %}
{% if workspace_data_object.gsr_restricted %}
Expand Down Expand Up @@ -100,5 +101,7 @@ <h2 class="accordion-header" id="headingAcknowledgments">
</div>
</div>

{% include "snippets/data_prep_workspace_table.html" with table=associated_data_prep_workspaces is_active=data_prep_active %}

{{block.super}}
{% endblock after_panel %}
3 changes: 3 additions & 0 deletions primed/templates/dbgap/dbgapworkspace_detail.html
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{% extends "anvil_consortium_manager/workspace_detail.html" %}
{% load render_table from django_tables2%}

{% block pills %}
{% if workspace_data_object.gsr_restricted %}
Expand Down Expand Up @@ -93,6 +94,8 @@ <h2 class="accordion-header" id="headingAcknowledgments">
</div>
</div>

{% include "snippets/data_prep_workspace_table.html" with table=associated_data_prep_workspaces is_active=data_prep_active %}

{{block.super}}
{% endblock after_panel %}

Expand Down
20 changes: 20 additions & 0 deletions primed/templates/snippets/data_prep_workspace_table.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{% load render_table from django_tables2 %}

<div class="my-3">
<div class="accordion" id="accordionDataPrepWorkspace">
<div class="accordion-item">
<h2 class="accordion-header" id="headingDataPrepWorkspace">
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapseDataPrepWorkspace" aria-expanded="false" aria-controls="collapseDataPrepWorkspace">
<span class="fa-solid fa-spinner mx-2"></span>
Associated data prep workspaces
<span class="badge mx-2 bg-{% if is_active %}success{% else %}secondary{% endif %} pill"> {{ table.rows|length }}</span>
</button>
</h2>
<div id="collapseDataPrepWorkspace" class="accordion-collapse collapse" aria-labelledby="headingDataPrepWorkspace" data-bs-parent="#accordionDataPrepWorkspace">
<div class="accordion-body">
{% render_table table %}
</div>
</div>
</div>
</div>
</div>

0 comments on commit 750dac6

Please sign in to comment.