263 lines
9.8 KiB
Django/Jinja

{% extends "base.html.jinja" %}
{% block title %}Activity Logs{% endblock title %}
{% block styles %}
{{ super() }}
<style>
.logs-container {
background: white;
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
.filter-panel {
background: #f8f9fa;
border-bottom: 1px solid #dee2e6;
padding: 1rem;
}
.log-entry {
cursor: pointer;
transition: background-color 0.2s ease;
}
.log-entry:hover {
background-color: #f8f9fa;
}
.category-badge {
font-size: 0.75rem;
padding: 0.25rem 0.5rem;
}
.activity-controls {
width: auto;
display: inline-block;
}
.logs-table th {
background-color: #f8f9fa;
font-weight: 600;
}
.log-entry {
cursor: pointer;
transition: background-color 0.2s ease;
}
.log-entry:hover {
background-color: #f8f9fa;
}
.pagination-info {
font-size: 0.875rem;
color: #6c757d;
}
.search-results-container {
max-height: 600px;
overflow-y: auto;
}
/* JSON formatting styles */
.json-formatted {
background-color: #f8f9fa;
border: 1px solid #e9ecef;
border-radius: 0.375rem;
font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
font-size: 0.875rem;
line-height: 1.4;
}
.json-formatted code {
color: #495057;
background: transparent;
}
</style>
{% endblock styles %}
{% block content %}
<div class="container-fluid mt-4">
<h1><i class="bi bi-list-ul"></i> Activity Logs</h1>
<!-- Include standardized flash messages -->
{% include "partials/flash_messages.html.jinja" %}
<div class="logs-container">
<!-- Filter Panel -->
<div class="filter-panel">
<form id="filterForm" class="row g-3">
<div class="col-md-3">
<label class="form-label">Categories:</label>
<div class="category-checkbox-container p-2"
style="max-height: 200px; overflow-y: auto; background-color: white; border: 1px solid #ced4da; border-radius: 0.375rem;">
<div class="form-check">
<input class="form-check-input" type="checkbox" id="selectAllCategories" {% if not
selected_categories or selected_categories|length==categories|length %}checked{% endif
%}>
<label class="form-check-label fw-bold" for="selectAllCategories">
All Categories
</label>
</div>
<hr class="my-2">
{% for cat in categories %}
<div class="form-check">
<input class="form-check-input category-checkbox" type="checkbox" id="category_{{ cat }}"
value="{{ cat }}" {% if not selected_categories or cat in selected_categories
%}checked{% endif %}>
<label class="form-check-label" for="category_{{ cat }}">
{{ cat.replace('_', ' ').title() }}
</label>
</div>
{% endfor %}
</div>
</div>
<div class="col-md-3">
<div class="row">
<label for="statusFilter" class="form-label">Status:</label>
<select id="statusFilter" class="form-select form-select-sm">
<option value="">All Statuses</option>
<option value="success">Success</option>
<option value="error">Error</option>
<option value="warning">Warning</option>
<option value="info">Info</option>
<option value="pending">Pending</option>
</select>
</div>
</div>
<div class="col-md-3">
<label for="startDate" class="form-label">Start Date:</label>
<input type="date" id="startDate" class="form-control form-control-sm"
value="{{ start_date or '' }}">
<label for="endDate" class="form-label mt-2">End Date:</label>
<input type="date" id="endDate" class="form-control form-control-sm" value="{{ end_date or '' }}">
</div>
<div class="col-md-3">
<label for="searchTerm" class="form-label">Search:</label>
<input type="text" id="searchTerm" class="form-control form-control-sm"
placeholder="Search in actions and descriptions" value="{{ search_term or '' }}">
</div>
<div class="col-12 d-flex justify-content-end mt-3">
<button type="button" id="clearFilters" class="btn btn-outline-secondary btn-sm">
<i class="bi bi-x"></i> Clear Filters
</button>
</div>
</form>
</div>
<!-- Controls Panel -->
<div class="d-flex justify-content-between align-items-center p-3 border-bottom">
<div class="d-flex align-items-center gap-3">
<div class="form-group mb-0">
<label for="pageSize" class="form-label mb-0 me-2">Show:</label>
<select id="pageSize" class="form-select form-select-sm activity-controls">
<option value="20">20</option>
<option value="50" selected>50</option>
<option value="100">100</option>
</select>
</div>
<span id="paginationInfo" class="pagination-info">Loading...</span>
</div>
<div class="d-flex gap-2">
<button type="button" id="refreshLogs" class="btn btn-outline-primary btn-sm">
<i class="bi bi-arrow-clockwise"></i> Refresh
</button>
<button type="button" id="downloadLogs" class="btn btn-outline-success btn-sm">
<i class="bi bi-download"></i> Download CSV
</button>
</div>
</div>
<!-- Logs Table -->
<div class="search-results-container">
<table class="table table-hover logs-table mb-0">
<thead class="sticky-top">
<tr>
<th style="width: 150px;">Timestamp</th>
<th style="width: 120px;">Category</th>
<th style="width: 180px;">Action</th>
<th style="width: 100px;">Status</th>
<th>Description</th>
</tr>
</thead>
<tbody id="logsTableBody">
<tr>
<td colspan="5" class="text-center py-4">
<div class="spinner-border spinner-border-sm text-primary" role="status">
<span class="visually-hidden">Loading...</span>
</div>
Loading logs...
</td>
</tr>
</tbody>
</table>
</div>
<!-- Pagination Controls -->
<nav id="logsPagination" aria-label="Logs pagination" class="p-3 border-top d-none">
<div class="d-flex justify-content-between align-items-center">
<div class="pagination-info">
<span id="paginationDetails">Showing 0 - 0 of 0 entries</span>
</div>
<ul class="pagination pagination-sm mb-0">
<li class="page-item" id="prevPage">
<a class="page-link" href="#" aria-label="Previous">
<span aria-hidden="true">«</span>
</a>
</li>
<li class="page-item active" id="currentPageItem">
<span class="page-link" id="currentPageSpan">1</span>
</li>
<li class="page-item" id="nextPage">
<a class="page-link" href="#" aria-label="Next">
<span aria-hidden="true">»</span>
</a>
</li>
</ul>
</div>
</nav>
</div>
</div>
<!-- Modal for log details -->
<div class="modal fade" id="logDetailModal" tabindex="-1" aria-hidden="true" data-bs-backdrop="true"
data-bs-keyboard="true">
<div class="modal-dialog modal-lg modal-dialog-scrollable">
<div class="modal-content" id="log-detail-content">
<!-- Log details will be loaded here via AJAX -->
</div>
</div>
</div>
{% endblock content %}
{% block scripts %}
{{ super() }}
<script src="{{ url_for('static', filename='js/modal-handler.js') }}"></script>
<script src="{{ url_for('static', filename='js/logger-manager.js') }}"></script>
<script>
document.addEventListener('DOMContentLoaded', function () {
// Initialize the logger manager
window.loggerManager = new LoggerManager({
initialFilters: {
category: {{ selected_categories | tojson }},
start_date: "{{ start_date or '' }}",
end_date: "{{ end_date or '' }}",
search_term: "{{ search_term or '' }}"
}
});
// Set up modal handler for log details
const logModal = new ModalHandler('logDetailModal', 'log-detail-content');
window.loggerManager.setModalHandler(logModal);
});
</script>
{% endblock scripts %}