Skip to content
Open
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,3 +65,12 @@ For each PR made, an entry should be added to this changelog. It should contain
- Added universal search functionality tests
- Created search pane filter tests
- Added pattern application form tests with validation checks

- affected-urls-page
- Description: Added functionality to view affected URLs (both Delta and Curated URLs) for each pattern type (Include, Exclude, Title, Document Type).
- Changes:
- Created new URL patterns with dynamic URL type handling (`/<pattern-type>/<id>/<url-type>`)
- Added `BaseAffectedURLsListView` and pattern-specific views for handling URL displays
- Implemented `BaseAffectedURLsViewSet` and pattern-specific views for API endpoints
- Added `affected_urls.html`, `affected_urls.css` and`affected_urls.js`
- Enhanced pattern list views with clickable eye icons
35 changes: 35 additions & 0 deletions sde_collections/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,21 @@
router.register(r"document-type-patterns", views.DocumentTypePatternViewSet)
router.register(r"division-patterns", views.DivisionPatternViewSet)
router.register(r"environmental-justice", EnvironmentalJusticeRowViewSet)
router.register(
r"exclude-pattern-affected-urls", views.ExcludePatternAffectedURLsViewSet, basename="exclude-pattern-affected-urls"
)
router.register(
r"include-pattern-affected-urls", views.IncludePatternAffectedURLsViewSet, basename="include-pattern-affected-urls"
)
router.register(
r"title-pattern-affected-urls", views.TitlePatternAffectedURLsViewSet, basename="title-pattern-affected-urls"
)
router.register(
r"documenttype-pattern-affected-urls",
views.DocumentTypePatternAffectedURLsViewSet,
basename="documenttype-pattern-affected-urls",
)


app_name = "sde_collections"

Expand Down Expand Up @@ -67,4 +82,24 @@
name="candidate-url-api",
),
path("titles-and-errors/", views.TitlesAndErrorsView.as_view(), name="titles-and-errors-list"),
path(
"exclude-pattern/<int:id>/<str:url_type>-urls",
view=views.ExcludePatternAffectedURLsListView.as_view(),
name="exclude_pattern_urls",
),
path(
"include-pattern/<int:id>/<str:url_type>-urls",
view=views.IncludePatternAffectedURLsListView.as_view(),
name="include_pattern_urls",
),
path(
"title-pattern/<int:id>/<str:url_type>-urls",
view=views.TitlePatternAffectedURLsListView.as_view(),
name="title_pattern_urls",
),
path(
"document-type-pattern/<int:id>/<str:url_type>-urls",
view=views.DocumentTypePatternAffectedURLsListView.as_view(),
name="document_type_pattern_urls",
),
]
38 changes: 38 additions & 0 deletions sde_collections/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -632,3 +632,41 @@ def get(self, request, *args, **kwargs):
"resolved_title_errors": resolved_title_errors,
}
return render(request, "sde_collections/titles_and_errors_list.html", context)


class BaseAffectedURLsViewSet(CollectionFilterMixin, viewsets.ModelViewSet):

pattern_model = None
pattern_type = None

def get_serializer_class(self):
url_type = self.request.GET.get("url_type")
return DeltaURLSerializer if url_type == "delta" else CuratedURLSerializer

def get_queryset(self):
pattern_id = self.request.GET.get("pattern_id")
url_type = self.request.GET.get("url_type")
self.pattern = self.pattern_model.objects.get(id=pattern_id)
return (
self.pattern.get_matching_delta_urls() if url_type == "delta" else self.pattern.get_matching_curated_urls()
)


class ExcludePatternAffectedURLsViewSet(BaseAffectedURLsViewSet):
pattern_model = DeltaExcludePattern
pattern_type = "Exclude"


class IncludePatternAffectedURLsViewSet(BaseAffectedURLsViewSet):
pattern_model = DeltaIncludePattern
pattern_type = "Include"


class TitlePatternAffectedURLsViewSet(BaseAffectedURLsViewSet):
pattern_model = DeltaTitlePattern
pattern_type = "Title"


class DocumentTypePatternAffectedURLsViewSet(BaseAffectedURLsViewSet):
pattern_model = DeltaDocumentTypePattern
pattern_type = "Document Type"
41 changes: 41 additions & 0 deletions sde_indexing_helper/static/css/delta_url_list.css
Original file line number Diff line number Diff line change
Expand Up @@ -451,3 +451,44 @@ div.dt-container div.dt-paging ul.pagination {
max-width: 100%;
min-width: 100%;
}

/* Specific styling for affected URLs modal only */
#affectedURLsModal {
padding: 0 !important;
}

#affectedURLsModal .modal-dialog {
max-width: 90%;
height: auto;
margin: 1.75rem auto;
}

#affectedURLsModal .modal-content {
background-color: #15232E;
color: white;
width: 100%;
height: auto;
max-height: 80vh;
display: flex;
flex-direction: column;
}

#affectedURLsModal .modal-header {
border-bottom: 1px solid #3F4A58;
margin-bottom: 0px;
}

#affectedURLsModal .modal-body {
flex: 0 1 auto;
overflow: auto;
padding: 1rem;
}

#affectedURLsModal .close {
color: white;
}

#affectedURLsModal .dataTables_wrapper {
display: flex;
flex-direction: column;
}
137 changes: 137 additions & 0 deletions sde_indexing_helper/static/js/delta_url_list.js
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,23 @@
});
}

function renderCountWithViewButton(count, patternType, urlType, rowId) {
return `
<div style="display: flex; align-items: center; justify-content: center;">
<span class="urlCount" style="min-width: 50px; text-align: right; padding-right: 10px;">
${count}
</span>
<button type="button"
class="btn btn-sm view-pattern-urls"
data-row-id="${rowId}"
data-pattern-type="${patternType}"
data-url-type="${urlType}">
<i class="fa fa-eye"></i>
</button>
</div>
`;
}

function initializeDataTable() {
var true_icon = '<i class="material-icons" style="color: green">check</i>';
var false_icon = '<i class="material-icons" style="color: red">close</i>';
Expand Down Expand Up @@ -604,11 +621,17 @@
data: "delta_urls_count",
class: "text-center whiteText",
sortable: true,
render: function (data, type, row) {
return renderCountWithViewButton(data, 'exclude', 'delta', row.id);
},
},
{
data: "curated_urls_count",
class: "text-center whiteText",
sortable: true,
render: function (data, type, row) {
return renderCountWithViewButton(data, 'exclude', 'curated', row.id);
},
},
{
data: null,
Expand Down Expand Up @@ -690,11 +713,17 @@
data: "delta_urls_count",
class: "text-center whiteText",
sortable: true,
render: function (data, type, row) {
return renderCountWithViewButton(data, 'include', 'delta', row.id);
},
},
{
data: "curated_urls_count",
class: "text-center whiteText",
sortable: true,
render: function (data, type, row) {
return renderCountWithViewButton(data, 'include', 'curated', row.id);
},
},
{
data: null,
Expand Down Expand Up @@ -773,11 +802,17 @@
data: "delta_urls_count",
class: "text-center whiteText",
sortable: true,
render: function (data, type, row) {
return renderCountWithViewButton(data, 'title', 'delta', row.id);
},
},
{
data: "curated_urls_count",
class: "text-center whiteText",
sortable: true,
render: function (data, type, row) {
return renderCountWithViewButton(data, 'title', 'curated', row.id);
},
},
{
data: null,
Expand Down Expand Up @@ -856,11 +891,17 @@
data: "delta_urls_count",
class: "text-center whiteText",
sortable: true,
render: function (data, type, row) {
return renderCountWithViewButton(data, 'document-type', 'delta', row.id);
},
},
{
data: "curated_urls_count",
class: "text-center whiteText",
sortable: true,
render: function (data, type, row) {
return renderCountWithViewButton(data, 'document-type', 'curated', row.id);
},
},
{
data: null,
Expand Down Expand Up @@ -998,6 +1039,7 @@
handleDivisionSelect();
handleExcludeIndividualUrlClick();
handleNewTitleChange();
handleShowAffectedURLsListButtonClick();

handleUrlLinkClick();
handleTabsClick();
Expand Down Expand Up @@ -2246,3 +2288,98 @@
});
});
}

function handleShowAffectedURLsListButtonClick() {
const PATTERN_ENDPOINTS = {
'exclude': 'exclude-pattern-affected-urls',
'include': 'include-pattern-affected-urls',
'title': 'title-pattern-affected-urls',
'document-type': 'documenttype-pattern-affected-urls'
};

$("body").on("click", ".view-pattern-urls", function() {
const matchPatternId = $(this).data("row-id");
const patternType = $(this).data("pattern-type");
const urlType = $(this).data("url-type");
const patternName = $(this).closest('tr').find('td:first').text();
const urlCount = $(this).prev('.urlCount').text().trim();

// Update modal title and pattern info
$("#affectedURLsModalTitle").text(`Affected ${urlType} URLs`);
$("#patternInfo").html(`
${urlCount} affected URL${urlCount === '1' ? '' : 's'} for ${patternType} pattern:
<span style="color: #65B1EF;">${patternName}</span>
`);

if ($.fn.DataTable.isDataTable('#affectedURLsModalTable')) {
$('#affectedURLsModalTable').DataTable().destroy();
}

initializeModalDataTable(PATTERN_ENDPOINTS[patternType], matchPatternId, urlType);
$("#affectedURLsModal").modal('show');

});
}

function initializeModalDataTable(endpoint, patternId, urlType) {

affected_urls_table = $("#affectedURLsModalTable").DataTable({
processing: true,
pageLength: 100,
colReorder: true,
stateSave: true,
serverSide: true,
orderCellsTop: true,
pagingType: "input",
paging: true,
stateSave: false,
rowId: "url",
layout: {
bottomEnd: "inputPaging",
topEnd: null,
topStart: {
info: true,
pageLength: {
menu: [
[25, 50, 100, 500],
["Show 25", "Show 50", "Show 100", "Show 500"],
],
},
},
},
columnDefs: [
{ orderable: true, targets: "_all" },
{ orderable: false, targets: "filter-row" },
],
orderCellsTop: true,
ajax: {
url: `/api/${endpoint}/?format=datatables&url_type=${urlType}&pattern_id=${patternId}`,
data: function (d) {},
complete: function (xhr, status) {},
},

columns: [
getURLColumn(),
],
});

$("#affectedURLsFilter").on(
"beforeinput",
DataTable.util.debounce(function (val) {
affected_urls_table.columns(0).search(this.value).draw();
}, 200)
);
}

function getURLColumn() {
return {
data: "url",
width: "30%",
render: function (data, type, row) {
return `<div class="url-cell"><span class="candidate_url nameStyling">${data}</span>
<a target="_blank" href=${data} class="url-link">
<i class="material-icons url-icon">open_in_new</i></a>
</div>`;
},
};
}
26 changes: 26 additions & 0 deletions sde_indexing_helper/templates/sde_collections/delta_urls_list.html
Original file line number Diff line number Diff line change
Expand Up @@ -762,6 +762,32 @@ <h5 class="modal-title">Are you sure?</h5>
</div>
</div>

<div class="modal fade" id="affectedURLsModal" tabindex="-1" role="dialog" aria-labelledby="affectedURLsModalLabel">
<div class="modal-dialog modal-xl" role="document">
<div class="modal-content dark-theme">
<div class="modal-header">
<h5 class="modal-title" id="affectedURLsModalTitle"></h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<h3 class="whiteText candidateTitle" id="patternInfo"></h3>
<table id="affectedURLsModalTable" class="table" style="width:100%">
<thead class="tableHeader">
<tr>
<th scope="col" class="text-center">URL</th>
</tr>
<tr class="filter-row">
<td><input type="text" class="table_filter_row_input textBoxStyling" id="affectedURLsFilter" placeholder="URL" /></td>
</tr>
</thead>
</table>
</div>
</div>
</div>
</div>

{% endblock content %}

{% block javascripts %}
Expand Down
Loading