240 lines
8.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;
}
.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="fas fa-list-alt"></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-2">
<label for="categoryFilter" class="form-label">Category:</label>
<select id="categoryFilter" class="form-select form-select-sm">
<option value="">All Categories</option>
{% for cat in categories %}
<option value="{{ cat }}" {% if category==cat %}selected{% endif %}>{{ cat.replace('_', '
').title() }}</option>
{% endfor %}
</select>
</div>
<div class="col-md-2">
<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 class="col-md-2">
<label for="startDate" class="form-label">Start Date:</label>
<input type="date" id="startDate" class="form-control form-control-sm"
value="{{ start_date or '' }}">
</div>
<div class="col-md-2">
<label for="endDate" class="form-label">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 action or description..." value="{{ search_term or '' }}">
</div>
<div class="col-md-1">
<label class="form-label">&nbsp;</label>
<div class="d-flex gap-2">
<button type="button" id="applyFilters" class="btn btn-primary btn-sm">
<i class="fas fa-filter"></i> Filter
</button>
<button type="button" id="clearFilters" class="btn btn-outline-secondary btn-sm">
<i class="fas fa-times"></i>
</button>
</div>
</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="fas fa-sync-alt"></i> Refresh
</button>
<button type="button" id="downloadLogs" class="btn btn-outline-success btn-sm">
<i class="fas fa-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>
<th style="width: 60px;">Details</th>
</tr>
</thead>
<tbody id="logsTableBody">
<tr>
<td colspan="6" class="text-center py-4">
<i class="fas fa-spinner fa-spin"></i> 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({
initialCategory: "{{ category or '' }}",
initialStartDate: "{{ start_date or '' }}",
initialEndDate: "{{ end_date or '' }}",
initialSearchTerm: "{{ 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 %}