Update instance_detail.html
This commit is contained in:
@@ -93,6 +93,16 @@
|
||||
<i class="fas fa-users me-2"></i>Contacts
|
||||
</button>
|
||||
</li>
|
||||
<li class="nav-item" role="presentation">
|
||||
<button class="nav-link" id="logs-tab" data-bs-toggle="tab" data-bs-target="#logs" type="button" role="tab" aria-controls="logs" aria-selected="false">
|
||||
<i class="fas fa-history me-2"></i>Activity Logs
|
||||
</button>
|
||||
</li>
|
||||
<li class="nav-item" role="presentation">
|
||||
<button class="nav-link" id="mails-tab" data-bs-toggle="tab" data-bs-target="#mails" type="button" role="tab" aria-controls="mails" aria-selected="false">
|
||||
<i class="fas fa-envelope me-2"></i>Mail Logs
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
@@ -170,6 +180,7 @@
|
||||
<th>Phone</th>
|
||||
<th>Company</th>
|
||||
<th>Position</th>
|
||||
<th>Role</th>
|
||||
<th>Status</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
@@ -182,6 +193,115 @@
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Logs Tab -->
|
||||
<div class="tab-pane fade" id="logs" role="tabpanel" aria-labelledby="logs-tab">
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<div class="card shadow-sm">
|
||||
<div class="card-body">
|
||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||
<h5 class="card-title mb-0">Activity Log</h5>
|
||||
<div class="d-flex gap-2">
|
||||
<select class="form-select form-select-sm" id="logCategory">
|
||||
<option value="">All Categories</option>
|
||||
<option value="AUTH">Authentication</option>
|
||||
<option value="FILE">File Operations</option>
|
||||
<option value="USER">User Management</option>
|
||||
<option value="SYSTEM">System</option>
|
||||
</select>
|
||||
<select class="form-select form-select-sm" id="dateRangeFilter">
|
||||
<option value="24h">Last 24 Hours</option>
|
||||
<option value="7d" selected>Last 7 Days</option>
|
||||
<option value="30d">Last 30 Days</option>
|
||||
<option value="all">All Time</option>
|
||||
</select>
|
||||
<button class="btn btn-secondary btn-sm" id="clearLogFiltersBtn">
|
||||
<i class="fas fa-times me-1"></i>Clear Filters
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Logs Table -->
|
||||
<div class="table-responsive">
|
||||
<table class="table table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Timestamp</th>
|
||||
<th>Event Type</th>
|
||||
<th>User</th>
|
||||
<th>IP Address</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="logsTableBody">
|
||||
<!-- Logs will be loaded here via JavaScript -->
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<!-- Pagination -->
|
||||
<nav aria-label="Logs pagination" class="mt-4">
|
||||
<ul class="pagination justify-content-center" id="logsPagination">
|
||||
<!-- Pagination will be loaded here via JavaScript -->
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Mails Tab -->
|
||||
<div class="tab-pane fade" id="mails" role="tabpanel" aria-labelledby="mails-tab">
|
||||
<div class="card shadow-sm">
|
||||
<div class="card-body">
|
||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||
<h5 class="card-title mb-0">Mail Log</h5>
|
||||
<div class="d-flex gap-2">
|
||||
<select class="form-select form-select-sm" id="statusFilter">
|
||||
<option value="">All Statuses</option>
|
||||
<option value="pending">Pending</option>
|
||||
<option value="sent">Sent</option>
|
||||
<option value="failed">Failed</option>
|
||||
</select>
|
||||
<select class="form-select form-select-sm" id="dateRangeFilter">
|
||||
<option value="24h">Last 24 Hours</option>
|
||||
<option value="7d" selected>Last 7 Days</option>
|
||||
<option value="30d">Last 30 Days</option>
|
||||
<option value="all">All Time</option>
|
||||
</select>
|
||||
<button class="btn btn-secondary btn-sm" id="clearFiltersBtn">
|
||||
<i class="fas fa-times me-1"></i>Clear Filters
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Mail Table -->
|
||||
<div class="table-responsive">
|
||||
<table class="table table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Created At</th>
|
||||
<th>Recipient</th>
|
||||
<th>Subject</th>
|
||||
<th>Sent At</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="mailsTableBody">
|
||||
<!-- Mails will be loaded here via JavaScript -->
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<!-- Pagination -->
|
||||
<nav aria-label="Mails pagination" class="mt-4">
|
||||
<ul class="pagination justify-content-center" id="mailsPagination">
|
||||
<!-- Pagination will be loaded here via JavaScript -->
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -318,6 +438,36 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Log Details Modal -->
|
||||
<div class="modal fade" id="logDetailsModal" tabindex="-1" aria-labelledby="logDetailsModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog modal-lg">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="logDetailsModalLabel">Log Details</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body" id="logDetailsContent">
|
||||
<!-- Log details will be loaded here -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Mail Details Modal -->
|
||||
<div class="modal fade" id="mailDetailsModal" tabindex="-1" aria-labelledby="mailDetailsModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog modal-lg">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="mailDetailsModalLabel">Mail Details</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body" id="mailDetailsContent">
|
||||
<!-- Mail details will be loaded here -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block extra_js %}
|
||||
@@ -461,22 +611,17 @@ async function fetchCompanyInfo() {
|
||||
// Update company name separately with debugging
|
||||
const companyNameElement = document.getElementById('company-name-value');
|
||||
const companyNameLabel = document.getElementById('company-name-label');
|
||||
console.log('Before update - Label:', companyNameLabel?.textContent);
|
||||
console.log('Before update - Value:', companyNameElement?.textContent);
|
||||
|
||||
// Ensure label text is set and maintained
|
||||
if (companyNameLabel) {
|
||||
companyNameLabel.textContent = 'Company Name:';
|
||||
}
|
||||
|
||||
if (companyNameElement) {
|
||||
companyNameElement.textContent = data.company_name || 'Not set';
|
||||
}
|
||||
|
||||
// Ensure label text is set
|
||||
if (companyNameLabel && !companyNameLabel.textContent) {
|
||||
companyNameLabel.textContent = 'Company Name:';
|
||||
}
|
||||
|
||||
console.log('After update - Label:', companyNameLabel?.textContent);
|
||||
console.log('After update - Value:', companyNameElement?.textContent);
|
||||
|
||||
// Update company details
|
||||
// Update other company details
|
||||
const updateElement = (id, value) => {
|
||||
const element = document.getElementById(id);
|
||||
if (element && element.classList.contains('company-value')) {
|
||||
@@ -594,7 +739,6 @@ window.addEventListener('beforeunload', function() {
|
||||
async function fetchContacts() {
|
||||
try {
|
||||
// First get JWT token
|
||||
console.log('Getting management token for contacts...');
|
||||
const tokenResponse = await fetch(`{{ instance.main_url }}/api/admin/management-token`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
@@ -612,7 +756,6 @@ async function fetchContacts() {
|
||||
throw new Error('No token received');
|
||||
}
|
||||
|
||||
// Then fetch contacts using the JWT token
|
||||
const response = await fetch(`{{ instance.main_url }}/api/admin/contacts`, {
|
||||
headers: {
|
||||
'Accept': 'application/json',
|
||||
@@ -628,29 +771,44 @@ async function fetchContacts() {
|
||||
const contactsList = document.getElementById('contactsTableBody');
|
||||
contactsList.innerHTML = '';
|
||||
|
||||
if (contacts.length === 0) {
|
||||
contactsList.innerHTML = `
|
||||
<div class="text-center text-muted py-4">
|
||||
<i class="fas fa-users fa-2x mb-3"></i>
|
||||
<p>No contacts found</p>
|
||||
</div>
|
||||
`;
|
||||
return;
|
||||
}
|
||||
|
||||
contacts.forEach(contact => {
|
||||
const row = document.createElement('tr');
|
||||
|
||||
// Role badge color mapping
|
||||
const roleBadgeClass = {
|
||||
'admin': 'bg-danger',
|
||||
'manager': 'bg-warning',
|
||||
'user': 'bg-info'
|
||||
}[contact.role] || 'bg-secondary';
|
||||
|
||||
// Status badge color mapping
|
||||
const statusBadgeClass = contact.is_active ? 'bg-success' : 'bg-secondary';
|
||||
|
||||
// Format phone number for tel: link (remove any non-digit characters)
|
||||
const phoneNumber = contact.phone ? contact.phone.replace(/\D/g, '') : '';
|
||||
|
||||
row.innerHTML = `
|
||||
<td>${contact.username}</td>
|
||||
<td>${contact.email || 'Not set'}</td>
|
||||
<td>${contact.phone || 'Not set'}</td>
|
||||
<td>${contact.company || 'Not set'}</td>
|
||||
<td>${contact.position || 'Not set'}</td>
|
||||
<td>${contact.username} ${contact.last_name}</td>
|
||||
<td>
|
||||
<span class="badge ${contact.is_active ? 'bg-success' : 'bg-danger'}">
|
||||
${contact.is_active ? 'Active' : 'Inactive'}
|
||||
</span>
|
||||
<a href="mailto:${contact.email}" class="text-decoration-none">
|
||||
<span class="badge bg-primary">
|
||||
<i class="fas fa-envelope me-1"></i>${contact.email}
|
||||
</span>
|
||||
</a>
|
||||
</td>
|
||||
<td>
|
||||
${contact.phone ? `
|
||||
<a href="tel:${phoneNumber}" class="text-decoration-none">
|
||||
<span class="badge bg-secondary">
|
||||
<i class="fas fa-phone me-1"></i>${contact.phone}
|
||||
</span>
|
||||
</a>
|
||||
` : '-'}
|
||||
</td>
|
||||
<td>${contact.company || '-'}</td>
|
||||
<td>${contact.position || '-'}</td>
|
||||
<td><span class="badge ${roleBadgeClass}">${contact.role.charAt(0).toUpperCase() + contact.role.slice(1)}</span></td>
|
||||
<td><span class="badge ${statusBadgeClass}">${contact.is_active ? 'Active' : 'Inactive'}</span></td>
|
||||
<td>
|
||||
<div class="btn-group">
|
||||
<button class="btn btn-sm btn-outline-primary" onclick="editContact(${contact.id})">
|
||||
@@ -666,13 +824,7 @@ async function fetchContacts() {
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Error fetching contacts:', error);
|
||||
const contactsList = document.getElementById('contactsTableBody');
|
||||
contactsList.innerHTML = `
|
||||
<div class="text-center text-danger py-4">
|
||||
<i class="fas fa-exclamation-circle fa-2x mb-3"></i>
|
||||
<p>Error loading contacts</p>
|
||||
</div>
|
||||
`;
|
||||
showToast('Error loading contacts', 'error');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -937,6 +1089,12 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
|
||||
// Fetch contacts when contacts tab is shown
|
||||
document.getElementById('contacts-tab').addEventListener('shown.bs.tab', fetchContacts);
|
||||
|
||||
// Fetch logs when logs tab is shown
|
||||
document.getElementById('logs-tab').addEventListener('shown.bs.tab', fetchLogs);
|
||||
|
||||
// Fetch mails when mails tab is shown
|
||||
document.getElementById('mails-tab').addEventListener('shown.bs.tab', fetchMails);
|
||||
|
||||
// Debug the company name label
|
||||
const label = document.getElementById('company-name-label');
|
||||
@@ -963,5 +1121,453 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
console.log('Company name label not found');
|
||||
}
|
||||
});
|
||||
|
||||
// Function to fetch logs
|
||||
async function fetchLogs() {
|
||||
try {
|
||||
// First get JWT token
|
||||
const tokenResponse = await fetch(`{{ instance.main_url }}/api/admin/management-token`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'X-API-Key': '{{ instance.connection_token }}',
|
||||
'Accept': 'application/json'
|
||||
}
|
||||
});
|
||||
|
||||
if (!tokenResponse.ok) {
|
||||
throw new Error('Failed to get management token');
|
||||
}
|
||||
|
||||
const tokenData = await tokenResponse.json();
|
||||
if (!tokenData.token) {
|
||||
throw new Error('No token received');
|
||||
}
|
||||
|
||||
const response = await fetch(`{{ instance.main_url }}/api/admin/logs`, {
|
||||
headers: {
|
||||
'Accept': 'application/json',
|
||||
'Authorization': `Bearer ${tokenData.token}`
|
||||
}
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error('Failed to fetch logs');
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
const logsTableBody = document.getElementById('logsTableBody');
|
||||
logsTableBody.innerHTML = '';
|
||||
|
||||
// Fetch all users to map IDs to names
|
||||
const usersResponse = await fetch(`{{ instance.main_url }}/api/admin/contacts`, {
|
||||
headers: {
|
||||
'Accept': 'application/json',
|
||||
'Authorization': `Bearer ${tokenData.token}`
|
||||
}
|
||||
});
|
||||
|
||||
if (!usersResponse.ok) {
|
||||
throw new Error('Failed to fetch users');
|
||||
}
|
||||
|
||||
const usersData = await usersResponse.json();
|
||||
const userMap = new Map(usersData.map(user => [user.id, `${user.username} ${user.last_name}`]));
|
||||
|
||||
data.events.forEach(event => {
|
||||
const row = document.createElement('tr');
|
||||
row.innerHTML = `
|
||||
<td>${new Date(event.timestamp).toLocaleString()}</td>
|
||||
<td>${event.event_type || '-'}</td>
|
||||
<td>${event.user_id ? userMap.get(event.user_id) || `User ${event.user_id}` : '-'}</td>
|
||||
<td>${event.ip_address || '-'}</td>
|
||||
`;
|
||||
logsTableBody.appendChild(row);
|
||||
});
|
||||
|
||||
// Update pagination
|
||||
updateLogsPagination(data.current_page, data.pages);
|
||||
} catch (error) {
|
||||
console.error('Error fetching logs:', error);
|
||||
showToast('Error loading logs', 'error');
|
||||
}
|
||||
}
|
||||
|
||||
// Function to fetch mails
|
||||
async function fetchMails() {
|
||||
try {
|
||||
// First get JWT token
|
||||
const tokenResponse = await fetch(`{{ instance.main_url }}/api/admin/management-token`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'X-API-Key': '{{ instance.connection_token }}',
|
||||
'Accept': 'application/json'
|
||||
}
|
||||
});
|
||||
|
||||
if (!tokenResponse.ok) {
|
||||
throw new Error('Failed to get management token');
|
||||
}
|
||||
|
||||
const tokenData = await tokenResponse.json();
|
||||
if (!tokenData.token) {
|
||||
throw new Error('No token received');
|
||||
}
|
||||
|
||||
const response = await fetch(`{{ instance.main_url }}/api/admin/mail-logs`, {
|
||||
headers: {
|
||||
'Accept': 'application/json',
|
||||
'Authorization': `Bearer ${tokenData.token}`
|
||||
}
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error('Failed to fetch mail logs');
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
const mailsTableBody = document.querySelector('#mails .table tbody');
|
||||
mailsTableBody.innerHTML = '';
|
||||
|
||||
data.mails.forEach(mail => {
|
||||
const row = document.createElement('tr');
|
||||
row.innerHTML = `
|
||||
<td>${new Date(mail.created_at).toLocaleString()}</td>
|
||||
<td>${mail.recipient}</td>
|
||||
<td>${mail.subject}</td>
|
||||
<td>${mail.sent_at ? new Date(mail.sent_at).toLocaleString() : '-'}</td>
|
||||
`;
|
||||
mailsTableBody.appendChild(row);
|
||||
});
|
||||
|
||||
// Update pagination
|
||||
updateMailsPagination(data.current_page, data.pages);
|
||||
} catch (error) {
|
||||
console.error('Error fetching mail logs:', error);
|
||||
showToast('Error loading mail logs', 'error');
|
||||
}
|
||||
}
|
||||
|
||||
// Helper function to get mail status badge class
|
||||
function getMailStatusBadgeClass(status) {
|
||||
const classes = {
|
||||
'pending': 'warning',
|
||||
'sent': 'success',
|
||||
'failed': 'danger'
|
||||
};
|
||||
return classes[status] || 'secondary';
|
||||
}
|
||||
|
||||
// Function to update logs pagination
|
||||
function updateLogsPagination(currentPage, totalPages) {
|
||||
const pagination = document.getElementById('logsPagination');
|
||||
if (!pagination) return;
|
||||
|
||||
pagination.innerHTML = '';
|
||||
|
||||
// Previous button
|
||||
const prevLi = document.createElement('li');
|
||||
prevLi.className = `page-item ${currentPage === 1 ? 'disabled' : ''}`;
|
||||
prevLi.innerHTML = `
|
||||
<button class="page-link" onclick="changeLogsPage(${currentPage - 1})" ${currentPage === 1 ? 'disabled' : ''}>
|
||||
<i class="fas fa-chevron-left"></i>
|
||||
</button>
|
||||
`;
|
||||
pagination.appendChild(prevLi);
|
||||
|
||||
// Page numbers
|
||||
for (let i = 1; i <= totalPages; i++) {
|
||||
const li = document.createElement('li');
|
||||
li.className = `page-item ${i === currentPage ? 'active' : ''}`;
|
||||
li.innerHTML = `
|
||||
<button class="page-link" onclick="changeLogsPage(${i})">${i}</button>
|
||||
`;
|
||||
pagination.appendChild(li);
|
||||
}
|
||||
|
||||
// Next button
|
||||
const nextLi = document.createElement('li');
|
||||
nextLi.className = `page-item ${currentPage === totalPages ? 'disabled' : ''}`;
|
||||
nextLi.innerHTML = `
|
||||
<button class="page-link" onclick="changeLogsPage(${currentPage + 1})" ${currentPage === totalPages ? 'disabled' : ''}>
|
||||
<i class="fas fa-chevron-right"></i>
|
||||
</button>
|
||||
`;
|
||||
pagination.appendChild(nextLi);
|
||||
}
|
||||
|
||||
// Function to update mails pagination
|
||||
function updateMailsPagination(currentPage, totalPages) {
|
||||
const pagination = document.querySelector('#mails .pagination');
|
||||
if (!pagination) return;
|
||||
|
||||
pagination.innerHTML = '';
|
||||
|
||||
// Previous button
|
||||
const prevLi = document.createElement('li');
|
||||
prevLi.className = `page-item ${currentPage === 1 ? 'disabled' : ''}`;
|
||||
prevLi.innerHTML = `
|
||||
<button class="page-link" onclick="changeMailsPage(${currentPage - 1})" ${currentPage === 1 ? 'disabled' : ''}>
|
||||
<i class="fas fa-chevron-left"></i>
|
||||
</button>
|
||||
`;
|
||||
pagination.appendChild(prevLi);
|
||||
|
||||
// Page numbers
|
||||
for (let i = 1; i <= totalPages; i++) {
|
||||
const li = document.createElement('li');
|
||||
li.className = `page-item ${i === currentPage ? 'active' : ''}`;
|
||||
li.innerHTML = `
|
||||
<button class="page-link" onclick="changeMailsPage(${i})">${i}</button>
|
||||
`;
|
||||
pagination.appendChild(li);
|
||||
}
|
||||
|
||||
// Next button
|
||||
const nextLi = document.createElement('li');
|
||||
nextLi.className = `page-item ${currentPage === totalPages ? 'disabled' : ''}`;
|
||||
nextLi.innerHTML = `
|
||||
<button class="page-link" onclick="changeMailsPage(${currentPage + 1})" ${currentPage === totalPages ? 'disabled' : ''}>
|
||||
<i class="fas fa-chevron-right"></i>
|
||||
</button>
|
||||
`;
|
||||
pagination.appendChild(nextLi);
|
||||
}
|
||||
|
||||
// Function to change logs page
|
||||
async function changeLogsPage(page) {
|
||||
try {
|
||||
// First get JWT token
|
||||
const tokenResponse = await fetch(`{{ instance.main_url }}/api/admin/management-token`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'X-API-Key': '{{ instance.connection_token }}',
|
||||
'Accept': 'application/json'
|
||||
}
|
||||
});
|
||||
|
||||
if (!tokenResponse.ok) {
|
||||
throw new Error('Failed to get management token');
|
||||
}
|
||||
|
||||
const tokenData = await tokenResponse.json();
|
||||
if (!tokenData.token) {
|
||||
throw new Error('No token received');
|
||||
}
|
||||
|
||||
const response = await fetch(`{{ instance.main_url }}/api/admin/logs?page=${page}`, {
|
||||
headers: {
|
||||
'Accept': 'application/json',
|
||||
'Authorization': `Bearer ${tokenData.token}`
|
||||
}
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error('Failed to fetch logs');
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
// Fetch all users to map IDs to names
|
||||
const usersResponse = await fetch(`{{ instance.main_url }}/api/admin/contacts`, {
|
||||
headers: {
|
||||
'Accept': 'application/json',
|
||||
'Authorization': `Bearer ${tokenData.token}`
|
||||
}
|
||||
});
|
||||
|
||||
if (!usersResponse.ok) {
|
||||
throw new Error('Failed to fetch users');
|
||||
}
|
||||
|
||||
const usersData = await usersResponse.json();
|
||||
const userMap = new Map(usersData.map(user => [user.id, `${user.username} ${user.last_name}`]));
|
||||
|
||||
const logsTableBody = document.getElementById('logsTableBody');
|
||||
logsTableBody.innerHTML = '';
|
||||
|
||||
data.events.forEach(event => {
|
||||
const row = document.createElement('tr');
|
||||
row.innerHTML = `
|
||||
<td>${new Date(event.timestamp).toLocaleString()}</td>
|
||||
<td>${event.event_type || '-'}</td>
|
||||
<td>${event.user_id ? userMap.get(event.user_id) || `User ${event.user_id}` : '-'}</td>
|
||||
<td>${event.ip_address || '-'}</td>
|
||||
`;
|
||||
logsTableBody.appendChild(row);
|
||||
});
|
||||
|
||||
// Update pagination
|
||||
updateLogsPagination(data.current_page, data.pages);
|
||||
} catch (error) {
|
||||
console.error('Error changing logs page:', error);
|
||||
showToast('Error loading logs', 'error');
|
||||
}
|
||||
}
|
||||
|
||||
// Function to change mails page
|
||||
async function changeMailsPage(page) {
|
||||
try {
|
||||
// First get JWT token
|
||||
const tokenResponse = await fetch(`{{ instance.main_url }}/api/admin/management-token`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'X-API-Key': '{{ instance.connection_token }}',
|
||||
'Accept': 'application/json'
|
||||
}
|
||||
});
|
||||
|
||||
if (!tokenResponse.ok) {
|
||||
throw new Error('Failed to get management token');
|
||||
}
|
||||
|
||||
const tokenData = await tokenResponse.json();
|
||||
if (!tokenData.token) {
|
||||
throw new Error('No token received');
|
||||
}
|
||||
|
||||
const response = await fetch(`{{ instance.main_url }}/api/admin/mail-logs?page=${page}`, {
|
||||
headers: {
|
||||
'Accept': 'application/json',
|
||||
'Authorization': `Bearer ${tokenData.token}`
|
||||
}
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error('Failed to fetch mail logs');
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
const mailsTableBody = document.querySelector('#mails .table tbody');
|
||||
mailsTableBody.innerHTML = '';
|
||||
|
||||
data.mails.forEach(mail => {
|
||||
const row = document.createElement('tr');
|
||||
row.innerHTML = `
|
||||
<td>${new Date(mail.created_at).toLocaleString()}</td>
|
||||
<td>${mail.recipient}</td>
|
||||
<td>${mail.subject}</td>
|
||||
<td>${mail.sent_at ? new Date(mail.sent_at).toLocaleString() : '-'}</td>
|
||||
`;
|
||||
mailsTableBody.appendChild(row);
|
||||
});
|
||||
|
||||
// Update pagination
|
||||
updateMailsPagination(data.current_page, data.pages);
|
||||
} catch (error) {
|
||||
console.error('Error changing mail logs page:', error);
|
||||
showToast('Error loading mail logs', 'error');
|
||||
}
|
||||
}
|
||||
|
||||
// Function to view mail details
|
||||
async function viewMailDetails(mailId) {
|
||||
try {
|
||||
// First get JWT token
|
||||
const tokenResponse = await fetch(`{{ instance.main_url }}/api/admin/management-token`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'X-API-Key': '{{ instance.connection_token }}',
|
||||
'Accept': 'application/json'
|
||||
}
|
||||
});
|
||||
|
||||
if (!tokenResponse.ok) {
|
||||
throw new Error('Failed to get management token');
|
||||
}
|
||||
|
||||
const tokenData = await tokenResponse.json();
|
||||
if (!tokenData.token) {
|
||||
throw new Error('No token received');
|
||||
}
|
||||
|
||||
const response = await fetch(`{{ instance.main_url }}/api/admin/mail-logs/${mailId}`, {
|
||||
headers: {
|
||||
'Accept': 'application/json',
|
||||
'Authorization': `Bearer ${tokenData.token}`
|
||||
}
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error('Failed to fetch mail details');
|
||||
}
|
||||
|
||||
const mail = await response.json();
|
||||
|
||||
// Update modal content
|
||||
document.getElementById('modalRecipient').textContent = mail.recipient;
|
||||
document.getElementById('modalStatus').innerHTML = `
|
||||
<span class="badge ${getMailStatusBadgeClass(mail.status)}">${mail.status}</span>
|
||||
`;
|
||||
document.getElementById('modalTemplate').textContent = mail.template_id ? mail.template_id : '-';
|
||||
document.getElementById('modalCreatedAt').textContent = new Date(mail.created_at).toLocaleString();
|
||||
document.getElementById('modalSentAt').textContent = mail.sent_at ? new Date(mail.sent_at).toLocaleString() : '-';
|
||||
document.getElementById('modalSubject').textContent = mail.subject;
|
||||
document.getElementById('modalBody').innerHTML = mail.body;
|
||||
|
||||
// Show modal
|
||||
const modal = new bootstrap.Modal(document.getElementById('mailDetailsModal'));
|
||||
modal.show();
|
||||
} catch (error) {
|
||||
console.error('Error viewing mail details:', error);
|
||||
showToast('Error loading mail details', 'error');
|
||||
}
|
||||
}
|
||||
|
||||
// Function to view log details
|
||||
function viewLogDetails(event) {
|
||||
const modal = new bootstrap.Modal(document.getElementById('logDetailsModal'));
|
||||
const content = document.getElementById('logDetailsContent');
|
||||
|
||||
// Format the details in a readable way
|
||||
let details = event.details;
|
||||
let formattedDetails = 'No details available';
|
||||
|
||||
if (details) {
|
||||
if (typeof details === 'string') {
|
||||
formattedDetails = details.replace(/\n/g, '<br>');
|
||||
} else if (typeof details === 'object') {
|
||||
formattedDetails = JSON.stringify(details, null, 2).replace(/\n/g, '<br>');
|
||||
} else {
|
||||
formattedDetails = String(details);
|
||||
}
|
||||
}
|
||||
|
||||
content.innerHTML = `
|
||||
<div class="mb-3">
|
||||
<strong>Timestamp:</strong> ${new Date(event.timestamp).toLocaleString()}
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<strong>Event Type:</strong> ${event.event_type || '-'}
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<strong>User:</strong> ${event.user_id ? userMap.get(event.user_id) || `User ${event.user_id}` : '-'}
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<strong>IP Address:</strong> ${event.ip_address || '-'}
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<strong>Details:</strong>
|
||||
<div class="mt-2 p-3 bg-light rounded">
|
||||
${formattedDetails}
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
modal.show();
|
||||
}
|
||||
|
||||
// Add event listener for clear filters button
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
// ... existing event listeners ...
|
||||
|
||||
const clearLogFiltersBtn = document.getElementById('clearLogFiltersBtn');
|
||||
if (clearLogFiltersBtn) {
|
||||
clearLogFiltersBtn.addEventListener('click', function() {
|
||||
document.getElementById('logCategory').value = '';
|
||||
document.getElementById('dateRangeFilter').value = '7d';
|
||||
fetchLogs();
|
||||
});
|
||||
}
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
Reference in New Issue
Block a user