Skip to content

Commit

Permalink
Merge pull request #92 from ministryofjustice/dp-3072-data-product-de…
Browse files Browse the repository at this point in the history
…tail-page

Dp 3072 data product detail page
  • Loading branch information
LavMatt authored Feb 26, 2024
2 parents 8344582 + d104620 commit 6048171
Show file tree
Hide file tree
Showing 14 changed files with 236 additions and 66 deletions.
44 changes: 41 additions & 3 deletions home/service/details.py
Original file line number Diff line number Diff line change
@@ -1,24 +1,53 @@
from data_platform_catalogue.search_types import MultiSelectFilter, ResultType
from django.core.exceptions import ObjectDoesNotExist


from .base import GenericService


class DetailsService(GenericService):
class DataProductDetailsService(GenericService):
def __init__(self, urn: str):
self.urn = urn
self.client = self._get_catalogue_client()

filter_value = [MultiSelectFilter("urn", [urn])]
search_results = self.client.search(
query="", page=None, filters=filter_value)
search_results = self.client.search(query="", page=None, filters=filter_value)

if not search_results.page_results:
raise ObjectDoesNotExist(urn)

self.result = search_results.page_results[0]
self.assets_in_data_product = self._get_data_product_entities()
self.context = self._get_context()

def _get_data_product_entities(self):
# we might want to implement pagination for data product children
# details at some point
data_product_search = self.client.list_data_product_assets(
urn=self.urn, count=500
).page_results

assets_in_data_product = []
for result in data_product_search:
# name is like that as fully qualified name ({data_product}.{asset}) seems
# too verbose to display here.
assets_in_data_product.append(
{
"name": (
result.name
if not result.name.split(".")[0] == self.result.name
else result.name.split(".")[1]
),
"urn": result.id,
"description": result.description,
"type": "TABLE",
}
)

assets_in_data_product = sorted(assets_in_data_product, key=lambda d: d["name"])

return assets_in_data_product

def _get_context(self):
context = {
"result": self.result,
Expand All @@ -27,7 +56,16 @@ def _get_context(self):
if self.result.result_type == ResultType.DATA_PRODUCT
else "Table"
),
"tables": self.assets_in_data_product,
"page_title": f"{self.result.name} - Data catalogue",
}

return context


class DatasetDetailsService(GenericService):
def __init__(self, urn: str):
self.context = self._get_context()

def _get_context(self):
return {}
7 changes: 5 additions & 2 deletions home/service/search.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,10 +103,13 @@ def _highlight_results(self):
return highlighted_results

else:
pattern = f'({re.escape(query)})'
pattern = f"({re.escape(query)})"
for result in highlighted_results.page_results:
result.description = re.sub(
pattern, r'**\1**', result.description, flags=re.IGNORECASE,
pattern,
r"**\1**",
result.description,
flags=re.IGNORECASE,
)

return highlighted_results
Expand Down
6 changes: 5 additions & 1 deletion home/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@
urlpatterns = [
path("", views.home_view, name="home"),
path("search", views.search_view, name="search"),
path("details/<str:id>/", views.details_view, name="details"),
path(
"details/<str:result_type>/<str:id>",
views.details_view,
name="details",
),
path("pagination/<str:page>", views.search_view, name="pagination"),
]
28 changes: 24 additions & 4 deletions home/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from django.shortcuts import render

from home.forms.search import SearchForm
from home.service.details import DetailsService
from home.service.details import DataProductDetailsService, DatasetDetailsService
from home.service.search import SearchService


Expand All @@ -12,15 +12,35 @@ def home_view(request):
return render(request, "home.html", context)


def details_view(request, id):
def details_view(request, result_type, id):
if result_type == "data_product":
context = data_product_details(request, id)
return render(request, "details_data_product.html", context)
if result_type == "table":
context = dataset_details(request, id)
return render(request, "details_dataset.html", context)


def data_product_details(request, id):
try:
service = DataProductDetailsService(id)
except ObjectDoesNotExist:
raise Http404("Asset does not exist")

context = service.context

return context


def dataset_details(request, id):
try:
service = DetailsService(id)
service = DatasetDetailsService(id)
except ObjectDoesNotExist:
raise Http404("Asset does not exist")

context = service.context

return render(request, "details.html", context)
return context


def search_view(request, page: str = "1"):
Expand Down
10 changes: 5 additions & 5 deletions poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ django = "^5.0.1"
pyyaml = "^6.0.1"
gunicorn = "^21.2.0"
whitenoise = "^6.6.0"
ministryofjustice-data-platform-catalogue = "^0.10.0"
ministryofjustice-data-platform-catalogue = "^0.15.0"
markdown = "^3.5.2"
python-dotenv = "^1.0.1"
faker = "^22.6.0"
Expand Down
38 changes: 19 additions & 19 deletions templates/details.html → templates/details_data_product.html
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
<a onclick="history.back()" class="govuk-back-link">Back</a>
<main class="govuk-main-wrapper">
<div class="govuk-grid-row">
<span class="govuk-caption-m">{{result_type}}</span>
<span class="govuk-caption-m">Data product</span>
<h2 class="govuk-heading-l">{{result.name}}</h2>
<div class="govuk-grid-column-two-thirds">
<div class="govuk-summary-card__title-wrapper" >
Expand All @@ -33,7 +33,7 @@ <h2 class="govuk-heading-l">{{result.name}}</h2>
<div class="govuk-summary-list__row">
<dt class="govuk-summary-list__key">Domain name</dt>
<dd class="govuk-summary-list__value">
{{result.metadata.domain.properties.name}}
{{result.metadata.domain_name}}
</dd>
</div>

Expand All @@ -57,7 +57,7 @@ <h2 class="govuk-heading-l">{{result.name}}</h2>
<div class="govuk-summary-list__row">
<dt class="govuk-summary-list__key">Retention period</dt>
<dd class="govuk-summary-list__value">

{{result.metadata.retention_period_in_days|intcomma}}
</dd>
</div>
<div class="govuk-summary-list__row">
Expand All @@ -82,7 +82,7 @@ <h2 class="govuk-heading-l">{{result.name}}</h2>
</div>
<br/>
<table class="govuk-table">
<caption class="govuk-table__caption govuk-table__caption--m">Database content</caption>
<caption class="govuk-table__caption govuk-table__caption--m">Data product content</caption>
<thead class="govuk-table__head">
<tr class="govuk-table__row">
<th scope="col" class="govuk-table__header app-custom-class">Table name</th>
Expand All @@ -91,21 +91,21 @@ <h2 class="govuk-heading-l">{{result.name}}</h2>
</tr>
</thead>
<tbody class="govuk-table__body">
<tr class="govuk-table__row">
<th scope="row" class="govuk-table__header">Table 1</th>
<td class="govuk-table__cell">This is description about the table</td>
<td class="govuk-table__cell"> <a href="#" class="govuk-link">Schema details</a></td>
</tr>
<tr class="govuk-table__row">
<th scope="row" class="govuk-table__header">Table 2</th>
<td class="govuk-table__cell">This is description about the table</td>
<td class="govuk-table__cell"> <a href="#" class="govuk-link">Schema details</a></td>
</tr>
<tr class="govuk-table__row">
<th scope="row" class="govuk-table__header">Table 3</th>
<td class="govuk-table__cell">This is description about the table</td>
<td class="govuk-table__cell"> <a href="#" class="govuk-link">Schema details</a></td>
</tr>
{% for table in tables %}
{% with table_type=table.type|lower %}
<tr class="govuk-table__row">
<th scope="row" class="govuk-table__header">{{table.name}}</th>
<td class="govuk-table__cell">
{% if table.description|length > 200 %}
{{ table.description|slice:":200"|add:"..."|markdown }}
{% else %}
{{ table.description|markdown }}
{% endif %}
</td>
<td class="govuk-table__cell"> <a href="{% url 'home:details' result_type=table_type id=table.urn %}" class="govuk-link">Schema details</a></td>
</tr>
{% endwith %}
{% endfor %}
</tbody>
</table>
</div>
Expand Down
1 change: 1 addition & 0 deletions templates/details_dataset.html
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
TODO
8 changes: 5 additions & 3 deletions templates/partial/search_result.html
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,15 @@
<div class="govuk-grid-row">
<div class="govuk-grid-column-full">
<h3 class="govuk-heading-m govuk-!-margin-bottom-2">
<a href="{% url 'home:details' id=result.id %}" class="govuk-link">{{result.name}}</a>
{% with result_type=result.result_type.name|lower %}
<a href="{% url 'home:details' result_type=result_type id=result.id %}" class="govuk-link">{{result.name}}</a>
{% endwith %}
{% if result.result_type.name == "DATA_PRODUCT" %}
<strong class="govuk-tag govuk-!-margin-left-2">
<strong class="govuk-tag govuk-!-margin-left-2" id="result-type">
Data product
</strong>
{% elif result.result_type.name == "TABLE" %}
<strong class="govuk-tag govuk-!-margin-left-2">
<strong class="govuk-tag govuk-!-margin-left-2" id="result-type">
Table
</strong>
{% endif %}
Expand Down
45 changes: 40 additions & 5 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,14 @@
from faker import Faker

from home.forms.search import SearchForm
from home.service.details import DetailsService
from home.service.details import DataProductDetailsService
from home.service.search import SearchService

from datahub.metadata.schema_classes import (
DataProductPropertiesClass,
DataProductAssociationClass,
)

fake = Faker()


Expand All @@ -29,7 +34,8 @@ def chromedriver_path(request):
return request.config.getoption("--chromedriver-path")


def generate_page(page_size=20):
def generate_page(page_size=20, result_type: ResultType = None):

"""
Generate a fake search page
"""
Expand All @@ -38,7 +44,11 @@ def generate_page(page_size=20):
results.append(
SearchResult(
id=fake.unique.name(),
result_type=choice((ResultType.DATA_PRODUCT, ResultType.TABLE)),
result_type=(
choice((ResultType.DATA_PRODUCT, ResultType.TABLE))
if result_type is None
else result_type
),
name=fake.name(),
description=fake.paragraph(),
metadata={"search_summary": "a"},
Expand Down Expand Up @@ -79,6 +89,11 @@ def mock_catalogue():
mock_catalogue, page_results=generate_page(), total_results=100
)
mock_search_facets_response(mock_catalogue, domains=generate_options())
mock_list_data_product_response(
mock_catalogue,
page_results=generate_page(page_size=1, result_type=ResultType.TABLE),
total_results=1,
)

yield mock_catalogue

Expand All @@ -96,6 +111,25 @@ def mock_search_facets_response(mock_catalogue, domains):
mock_catalogue.search_facets.return_value = SearchFacets({"domains": domains})


def mock_list_data_product_response(mock_catalogue, total_results, page_results=()):
search_response = SearchResponse(
total_results=total_results, page_results=page_results
)
mock_catalogue.list_data_product_assets.return_value = search_response


def mock_get_dataproduct_aspect(mock_catalogue):
data_product_association = DataProductAssociationClass(
destinationUrn="urn:li:dataset:(urn:li:dataPlatform:glue,test.test,PROD)",
sourceUrn="urn:li:dataProduct:test",
)

response = DataProductPropertiesClass(
name="test", assets=[data_product_association], description="test"
)
mock_catalogue.graph.get_aspect.return_value = response


@pytest.fixture
def valid_form():
valid_form = SearchForm(
Expand Down Expand Up @@ -123,10 +157,11 @@ def search_context(search_service):


@pytest.fixture
def detail_context(mock_catalogue):
def detail_dataproduct_context(mock_catalogue):
mock_catalogue.search.return_value = SearchResponse(
total_results=1, page_results=generate_page(page_size=1)
)
details_service = DetailsService(urn="urn:li:dataProduct:test")

details_service = DataProductDetailsService(urn="urn:li:dataProduct:test")
context = details_service._get_context()
return context
Loading

0 comments on commit 6048171

Please sign in to comment.