Better URL visualization

This commit is contained in:
Luciano Gervasoni
2025-03-26 17:35:09 +01:00
parent e1f4787119
commit 8dce5206af
3 changed files with 237 additions and 79 deletions

View File

@@ -133,6 +133,7 @@ input[type="checkbox"] {
</style>
</head>
<body>
{% load custom_filters %}
<div class="container">
<div class="sidebar">
@@ -140,8 +141,28 @@ input[type="checkbox"] {
<form method="GET" action="" id="filterForm">
<!-- Pages Per Page Dropdown -->
<h3>Pages Per Page</h3>
<select id="perPageSelect" name="per_page">
<option value="25" {% if per_page == '25' %}selected{% endif %}>25</option>
<option value="100" {% if per_page == '100' %}selected{% endif %}>100</option>
<option value="500" {% if per_page == '500' %}selected{% endif %}>500</option>
</select>
<br><br>
<!-- Filter by Time Range -->
<h3>Fetch Date</h3>
<select id="timeFilterSelect" name="selected_days">
<option value="1" {% if selected_days|stringformat:"s" == '1' %}selected{% endif %}>Last 24 hours</option>
<option value="7" {% if selected_days|stringformat:"s" == '7' %}selected{% endif %}>Last 7 days</option>
<option value="30" {% if selected_days|stringformat:"s" == '30' %}selected{% endif %}>Last 30 days</option>
<option value="90" {% if selected_days|stringformat:"s" == '90' %}selected{% endif %}>Last 90 days</option>
</select>
<br><br>
<!-- Filter by Status -->
<h3>Status</h3>
<button type="button" class="toggle-all-btn" data-toggle="status">Toggle All</button><br>
{% for status in statuses %}
<label>
<input type="checkbox" name="status" value="{{ status.0 }}"
@@ -149,105 +170,137 @@ input[type="checkbox"] {
{{ status.1 }}
</label><br>
{% endfor %}
<br><br>
<!-- Filter by Search -->
<h3>Search</h3>
<button type="button" class="toggle-all-btn" data-toggle="search">Toggle All</button><br>
{% for search in searches %}
<label>
<input type="checkbox" name="search" value="{{ search.id }}"
{% if search.id|stringformat:"s" in selected_search %}checked{% endif %}>
[{{ search.type }}] {{ search.search }}
[{{ search.type }}] {{ search.search|truncatechars:70 }}
</label><br>
{% endfor %}
<br><br>
<!-- Filter by Source -->
<h3>Source</h3>
<button type="button" class="toggle-all-btn" data-toggle="source">Toggle All</button><br>
{% for source in sources %}
<label>
<input type="checkbox" name="source" value="{{ source.id }}"
{% if source.id|stringformat:"s" in selected_source %}checked{% endif %}>
{{ source.source }}
{{ source.source|truncatechars:70 }}
</label><br>
{% endfor %}
<br><br>
</form>
</div>
<div class="table-container">
<table>
<thead>
<div class="table-container">
<table>
<thead>
<tr>
<th>ID</th>
<th>URL</th>
<th>Status</th>
<th>Fetch Date</th>
<th>Search</th>
<th>Source</th>
</tr>
</thead>
<tbody>
{% for url in urls %}
<tr>
<th>ID</th>
<th>URL</th>
<th>Status</th>
<th>Fetch Date</th>
<th>Search</th>
<th>Source</th>
</tr>
</thead>
<tbody>
{% for url in urls %}
<tr>
<td><a href="./{{ url.id }}" class="btn btn-primary btn-sm" target="_blank">{{ url.id }}</a></td>
<td><a href="{{ url.url }}/" target="_blank">{{ url.url }}</a></td>
<td>
{% if url.status == 'raw' %}
<span class="badge bg-secondary">{{ url.status|capfirst }}</span>
{% elif url.status == 'error' %}
<span class="badge bg-danger">{{ url.status|capfirst }}</span>
{% elif url.status == 'valid' %}
<span class="badge bg-success">{{ url.status|capfirst }}</span>
{% elif url.status == 'unknown' %}
<span class="badge bg-warning">{{ url.status|capfirst }}</span>
{% elif url.status == 'invalid' %}
<span class="badge bg-danger">{{ url.status|capfirst }}</span>
{% elif url.status == 'duplicate' %}
<span class="badge bg-info">{{ url.status|capfirst }}</span>
<td><a href="./{{ url.id }}" class="btn btn-primary btn-sm" target="_blank">{{ url.id }}</a></td>
<td><a href="{{ url.url }}/" target="_blank">{{ url.url }}</a></td>
<td>
{% if url.status == 'raw' %}
<span class="badge bg-secondary">{{ url.status|capfirst }}</span>
{% elif url.status == 'error' %}
<span class="badge bg-danger">{{ url.status|capfirst }}</span>
{% elif url.status == 'valid' %}
<span class="badge bg-success">{{ url.status|capfirst }}</span>
{% elif url.status == 'unknown' %}
<span class="badge bg-warning">{{ url.status|capfirst }}</span>
{% elif url.status == 'invalid' %}
<span class="badge bg-danger">{{ url.status|capfirst }}</span>
{% elif url.status == 'duplicate' %}
<span class="badge bg-info">{{ url.status|capfirst }}</span>
{% else %}
<span class="badge bg-light">Unknown</span>
{% endif %}
</td>
<td>
<span class="ts-fetch" data-ts="{{ url.ts_fetch|date:'c' }}"></span>
</td>
<td>
{% with sources_map|dict_get:url.id as sources %}
{% if sources %}
{% for source in sources %}
<span class="badge bg-secondary">{{ source }}</span>
{% endfor %}
{% else %}
<span class="badge bg-light">Unknown</span>
<span class="text-muted">No sources</span>
{% endif %}
</td>
<td>{{ url.ts_fetch }}</td>
<td>
{% for search in url.urlssourcesearch_set.all %}
{{ search.id_search.search }}<br>
{% endfor %}
</td>
<td>
{% for source in url.urlssourcesearch_set.all %}
{{ source.id_source.source }}<br>
{% endfor %}
</td>
</tr>
{% empty %}
<tr>
<td colspan="5">No URLs found for the selected filters.</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endwith %}
</td>
<td>
{% with searches_map|dict_get:url.id as searches %}
{% if searches %}
{% for search in searches %}
<span class="badge bg-secondary">{{ search }}</span>
{% endfor %}
{% else %}
<span class="text-muted">No searches</span>
{% endif %}
{% endwith %}
</td>
</tr>
{% empty %}
<tr>
<td colspan="5">No URLs found for the selected filters.</td>
</tr>
{% endfor %}
</tbody>
</table>
<!-- Pagination Controls -->
<div class="pagination">
<div class="pagination-controls">
{% if urls.has_previous %}
<a href="#" class="pagination-link" data-page="1">« First</a>
<a href="#" class="pagination-link" data-page="{{ urls.previous_page_number }}">Previous</a>
{% endif %}
<span>Page {{ urls.number }} of {{ urls.paginator.num_pages }}</span>
{% if urls.has_next %}
<a href="#" class="pagination-link" data-page="{{ urls.next_page_number }}">Next</a>
<a href="#" class="pagination-link" data-page="{{ urls.paginator.num_pages }}">Last »</a>
{% endif %}
</div>
</div>
</div>
<!-- Passing the selected filters as JavaScript variables -->
<script type="text/javascript">
// Make sure these variables are accessible in your JavaScript
var selectedStatus = {{ selected_status|safe }};
var selectedSearch = {{ selected_search|safe }};
var selectedSource = {{ selected_source|safe }};
var perPage = {{ per_page|default:"25" }};
//var selectedDays = {{ selected_days|default:"30" }};
</script>
<script>
// Automatically submit the form when any checkbox changes
document.querySelectorAll('input[type="checkbox"]').forEach(function(checkbox) {
checkbox.addEventListener('change', function() {
// Automatically submit the form when a checkbox is toggled
document.getElementById('filterForm').submit();
});
});
//////////////////////////////////////////////////////////////////////
document.addEventListener("DOMContentLoaded", function () {
const themeToggle = document.getElementById("themeToggle");
const body = document.body;
@@ -270,7 +323,88 @@ input[type="checkbox"] {
themeToggle.textContent = "🌞";
}
});
document.querySelectorAll(".ts-fetch").forEach(element => {
let utcDate = element.getAttribute("data-ts"); // Get timestamp from data attribute
let options = { year: 'numeric', month: 'numeric', day: 'numeric', hour: '2-digit', minute: '2-digit', second: '2-digit', hour12:false};
if (utcDate) {
let localDate = new Date(utcDate).toLocaleString("en-GB", options); // Convert to local timezone
element.textContent = localDate; // Update the text content
}
});
});
//////////////////////////////////////////////////////////////////////
// Function to update pagination links
function updatePaginationLinks(pageNumber) {
// Get current URL and remove existing page parameter
const currentUrl = new URL(window.location.href);
currentUrl.searchParams.set('page', pageNumber); // Update page parameter
window.location.href = currentUrl.toString(); // Redirect to the updated URL
}
// Attach event listeners to pagination links
document.querySelectorAll('.pagination-link').forEach(link => {
link.addEventListener('click', function(e) {
e.preventDefault();
const pageNumber = this.getAttribute('data-page');
updatePaginationLinks(pageNumber); // Update the page number in the URL
});
});
//////////////////////////////////////////////////////////////////////
// Function to toggle all checkboxes in a section
function toggleCheckboxes(section) {
const checkboxes = document.querySelectorAll(`[name='${section}']`);
const allChecked = Array.from(checkboxes).every(checkbox => checkbox.checked);
checkboxes.forEach(checkbox => {
checkbox.checked = !allChecked;
});
// Automatically submit the form when a checkbox is toggled
document.getElementById('filterForm').submit();
}
// Attach event listeners to "Toggle All" buttons
document.querySelectorAll('.toggle-all-btn').forEach(button => {
button.addEventListener('click', function() {
const section = this.getAttribute('data-toggle');
toggleCheckboxes(section);
});
});
//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
// Automatically submit the form when any checkbox changes
document.querySelectorAll('input[type="checkbox"]').forEach(function(checkbox) {
checkbox.addEventListener('change', function() {
// Automatically submit the form when a checkbox is toggled
document.getElementById('filterForm').submit();
//const currentUrl = new URL(window.location.href);
//currentUrl.searchParams.set('page', 1); // Reset page number to 1 when any checkbox changes
//window.location.href = currentUrl.toString(); // Redirect to the updated URL with the new filter values
});
});
//////////////////////////////////////////////////////////////////////
// Automatically submit the form when per_page dropdown changes
document.getElementById('perPageSelect').addEventListener('change', function() {
const currentUrl = new URL(window.location.href);
currentUrl.searchParams.set('per_page', this.value); // Update per_page value
currentUrl.searchParams.set('page', 1); // Reset page number to 1 when any checkbox changes
window.location.href = currentUrl.toString(); // Redirect to the updated URL with new per_page value
});
document.getElementById('timeFilterSelect').addEventListener('change', function() {
const currentUrl = new URL(window.location.href);
currentUrl.searchParams.set('selected_days', this.value); // Update per_page value
currentUrl.searchParams.set('page', 1); // Reset page number to 1 when any checkbox changes
window.location.href = currentUrl.toString(); // Redirect to the updated URL with new per_page value
});
</script>
</body>