Fix Bootstrap compatibility and UI issues in user_tokens.html template

- Replace Bootstrap 5 classes and components with custom CSS compatible with base template
- Convert inline onclick handlers to data attributes with event delegation
- Add comprehensive custom CSS for modals, forms, cards, badges, and buttons
- Fix JavaScript template variable issues using data attributes
- Implement modern clipboard API with fallback for older browsers
- Add proper event listeners for token management actions (revoke, extend, delete)
- Template now works with existing custom CSS framework instead of Bootstrap
parent 89693099
...@@ -2,241 +2,542 @@ ...@@ -2,241 +2,542 @@
{% block title %}API Tokens - Fixture Manager{% endblock %} {% block title %}API Tokens - Fixture Manager{% endblock %}
{% block extra_css %}
/* Modal styles */
.modal {
display: none;
position: fixed;
z-index: 1000;
left: 0;
top: 0;
width: 100%;
height: 100%;
background-color: rgba(0,0,0,0.5);
}
.modal.show {
display: flex;
align-items: center;
justify-content: center;
}
.modal-dialog {
background: white;
border-radius: 8px;
max-width: 500px;
width: 90%;
max-height: 90vh;
overflow-y: auto;
box-shadow: 0 4px 20px rgba(0,0,0,0.3);
}
.modal-header {
padding: 1rem;
border-bottom: 1px solid #ddd;
display: flex;
justify-content: space-between;
align-items: center;
background-color: #f8f9fa;
border-radius: 8px 8px 0 0;
}
.modal-header.bg-success {
background-color: #28a745;
color: white;
}
.modal-title {
margin: 0;
font-size: 1.2rem;
font-weight: bold;
}
.modal-body {
padding: 1rem;
}
.modal-footer {
padding: 1rem;
border-top: 1px solid #ddd;
display: flex;
justify-content: flex-end;
gap: 0.5rem;
background-color: #f8f9fa;
border-radius: 0 0 8px 8px;
}
.close-btn {
background: none;
border: none;
font-size: 1.5rem;
cursor: pointer;
color: #666;
padding: 0;
width: 30px;
height: 30px;
display: flex;
align-items: center;
justify-content: center;
}
.close-btn:hover {
color: #000;
}
.close-btn.white {
color: white;
}
.close-btn.white:hover {
color: #ccc;
}
/* Form styles */
.form-label {
display: block;
margin-bottom: 0.5rem;
font-weight: bold;
color: #333;
}
.form-control {
width: 100%;
padding: 8px 12px;
border: 1px solid #ddd;
border-radius: 4px;
box-sizing: border-box;
font-size: 1rem;
}
.form-control:focus {
outline: none;
border-color: #007bff;
}
.form-control[readonly] {
background-color: #f8f9fa;
font-family: monospace;
}
.form-text {
font-size: 0.875rem;
color: #666;
margin-top: 0.25rem;
}
.form-select {
width: 100%;
padding: 8px 12px;
border: 1px solid #ddd;
border-radius: 4px;
box-sizing: border-box;
font-size: 1rem;
background-color: white;
}
/* Input group */
.input-group {
display: flex;
}
.input-group .form-control {
border-radius: 4px 0 0 4px;
border-right: none;
}
.input-group .btn {
border-radius: 0 4px 4px 0;
border-left: 1px solid #007bff;
}
/* Card styles */
.card {
background: white;
border: 1px solid #ddd;
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
margin-bottom: 1rem;
}
.card-header {
padding: 1rem;
background-color: #f8f9fa;
border-bottom: 1px solid #ddd;
border-radius: 8px 8px 0 0;
}
.card-header.bg-info {
background-color: #17a2b8;
color: white;
}
.card-body {
padding: 1rem;
}
/* Table styles */
.table-responsive {
overflow-x: auto;
}
.table-hover tbody tr:hover {
background-color: #f8f9fa;
}
/* Badge styles */
.badge {
display: inline-block;
padding: 0.25rem 0.5rem;
font-size: 0.75rem;
font-weight: bold;
border-radius: 4px;
color: white;
}
.badge.bg-success {
background-color: #28a745;
}
.badge.bg-danger {
background-color: #dc3545;
}
.badge.bg-secondary {
background-color: #6c757d;
}
/* Button group */
.btn-group {
display: inline-flex;
gap: 2px;
}
.btn-outline-warning {
background-color: transparent;
color: #ffc107;
border: 1px solid #ffc107;
}
.btn-outline-warning:hover {
background-color: #ffc107;
color: #212529;
}
.btn-outline-info {
background-color: transparent;
color: #17a2b8;
border: 1px solid #17a2b8;
}
.btn-outline-info:hover {
background-color: #17a2b8;
color: white;
}
.btn-outline-danger {
background-color: transparent;
color: #dc3545;
border: 1px solid #dc3545;
}
.btn-outline-danger:hover {
background-color: #dc3545;
color: white;
}
.btn-outline-secondary {
background-color: transparent;
color: #6c757d;
border: 1px solid #6c757d;
}
.btn-outline-secondary:hover {
background-color: #6c757d;
color: white;
}
/* Utility classes */
.mb-3 {
margin-bottom: 1rem;
}
.mb-4 {
margin-bottom: 1.5rem;
}
.text-muted {
color: #666;
}
.font-monospace {
font-family: monospace;
}
.py-5 {
padding-top: 3rem;
padding-bottom: 3rem;
}
.fa-3x {
font-size: 3rem;
}
/* Hide elements by default */
.d-none {
display: none;
}
/* Success message styling */
.success-message {
background-color: #d4edda;
color: #155724;
border: 1px solid #c3e6cb;
padding: 12px;
border-radius: 4px;
margin-bottom: 1rem;
}
/* Warning message styling */
.warning-message {
background-color: #fff3cd;
color: #856404;
border: 1px solid #ffeaa7;
padding: 12px;
border-radius: 4px;
margin-bottom: 1rem;
}
/* Danger message styling */
.danger-message {
background-color: #f8d7da;
color: #721c24;
border: 1px solid #f5c6cb;
padding: 12px;
border-radius: 4px;
margin-bottom: 1rem;
}
{% endblock %}
{% block content %} {% block content %}
<div class="container-fluid"> <div class="content">
<!-- Header --> <!-- Header -->
<div class="row mb-4"> <div class="mb-4">
<div class="col-12"> <div class="d-flex justify-content-between align-items-center">
<div class="d-flex justify-content-between align-items-center"> <div>
<div> <h1>🔑 API Tokens</h1>
<h1 class="h3 mb-0">🔑 API Tokens</h1> <p class="text-muted">Manage your API tokens for external application access</p>
<p class="text-muted">Manage your API tokens for external application access</p>
</div>
<button type="button" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#createTokenModal">
<i class="fas fa-plus"></i> Create New Token
</button>
</div> </div>
<button type="button" class="btn" onclick="showCreateModal()">
➕ Create New Token
</button>
</div> </div>
</div> </div>
<!-- API Documentation Card --> <!-- API Documentation Card -->
<div class="row mb-4"> <div class="card mb-4">
<div class="col-12"> <div class="card-header bg-info">
<div class="card border-info"> <h5 style="margin: 0; color: white;">ℹ️ API Usage</h5>
<div class="card-header bg-info text-white"> </div>
<h5 class="mb-0"><i class="fas fa-info-circle"></i> API Usage</h5> <div class="card-body">
</div> <p><strong>Base URL:</strong> <code>{{ request.url_root }}api/</code></p>
<div class="card-body"> <p><strong>Authentication:</strong> Include your token in the Authorization header:</p>
<p class="mb-2"><strong>Base URL:</strong> <code>{{ request.url_root }}api/</code></p> <pre style="background: #f8f9fa; padding: 0.5rem; border-radius: 4px; margin: 0.5rem 0;"><code>Authorization: Bearer YOUR_TOKEN_HERE</code></pre>
<p class="mb-2"><strong>Authentication:</strong> Include your token in the Authorization header:</p> <p><strong>Available Endpoints:</strong></p>
<pre class="bg-light p-2 rounded"><code>Authorization: Bearer YOUR_TOKEN_HERE</code></pre> <ul>
<p class="mb-2"><strong>Available Endpoints:</strong></p> <li><code>GET /api/fixtures</code> - List all fixtures</li>
<ul class="mb-0"> <li><code>GET /api/matches</code> - List all matches</li>
<li><code>GET /api/fixtures</code> - List all fixtures</li> <li><code>GET /api/match/&lt;id&gt;</code> - Get match details</li>
<li><code>GET /api/matches</code> - List all matches</li> </ul>
<li><code>GET /api/match/&lt;id&gt;</code> - Get match details</li>
</ul>
</div>
</div>
</div> </div>
</div> </div>
<!-- Tokens List --> <!-- Tokens List -->
<div class="row"> <div class="card">
<div class="col-12"> <div class="card-header">
<div class="card"> <h5 style="margin: 0;">Your API Tokens</h5>
<div class="card-header"> </div>
<h5 class="mb-0">Your API Tokens</h5> <div class="card-body">
</div> {% if tokens %}
<div class="card-body"> <div class="table-responsive">
{% if tokens %} <table class="table table-hover">
<div class="table-responsive"> <thead>
<table class="table table-hover"> <tr>
<thead> <th>Name</th>
<tr> <th>Status</th>
<th>Name</th> <th>Created</th>
<th>Status</th> <th>Expires</th>
<th>Created</th> <th>Last Used</th>
<th>Expires</th> <th>Actions</th>
<th>Last Used</th> </tr>
<th>Actions</th> </thead>
</tr> <tbody id="tokensTableBody">
</thead> {% for token in tokens %}
<tbody id="tokensTableBody"> <tr data-token-id="{{ token.id }}">
{% for token in tokens %} <td>
<tr data-token-id="{{ token.id }}"> <strong>{{ token.name }}</strong>
<td> </td>
<strong>{{ token.name }}</strong> <td>
</td> {% if token.is_valid() %}
<td> <span class="badge bg-success">Active</span>
{% if token.is_valid() %} {% elif token.is_expired() %}
<span class="badge bg-success">Active</span> <span class="badge bg-danger">Expired</span>
{% elif token.is_expired() %} {% else %}
<span class="badge bg-danger">Expired</span> <span class="badge bg-secondary">Revoked</span>
{% else %} {% endif %}
<span class="badge bg-secondary">Revoked</span> </td>
<td>
<small class="text-muted">
{{ token.created_at.strftime('%Y-%m-%d %H:%M') }}
</small>
</td>
<td>
<small class="text-muted">
{{ token.expires_at.strftime('%Y-%m-%d %H:%M') }}
</small>
</td>
<td>
<small class="text-muted">
{% if token.last_used_at %}
{{ token.last_used_at.strftime('%Y-%m-%d %H:%M') }}
{% if token.last_used_ip %}
<br>from {{ token.last_used_ip }}
{% endif %} {% endif %}
</td> {% else %}
<td> Never used
<small class="text-muted"> {% endif %}
{{ token.created_at.strftime('%Y-%m-%d %H:%M') }} </small>
</small> </td>
</td> <td>
<td> <div class="btn-group">
<small class="text-muted"> {% if token.is_active and not token.is_expired() %}
{{ token.expires_at.strftime('%Y-%m-%d %H:%M') }} <button type="button" class="btn btn-sm btn-outline-warning revoke-token-btn"
</small> data-token-id="{{ token.id }}"
</td> data-token-name="{{ token.name }}"
<td> title="Revoke Token">
<small class="text-muted"> 🚫
{% if token.last_used_at %} </button>
{{ token.last_used_at.strftime('%Y-%m-%d %H:%M') }} <button type="button" class="btn btn-sm btn-outline-info extend-token-btn"
{% if token.last_used_ip %} data-token-id="{{ token.id }}"
<br>from {{ token.last_used_ip }} data-token-name="{{ token.name }}"
{% endif %} title="Extend Expiration">
{% else %} 🕒
Never used </button>
{% endif %} {% endif %}
</small> <button type="button" class="btn btn-sm btn-outline-danger delete-token-btn"
</td> data-token-id="{{ token.id }}"
<td> data-token-name="{{ token.name }}"
<div class="btn-group btn-group-sm" role="group"> title="Delete Token">
{% if token.is_active and not token.is_expired() %} 🗑️
<button type="button" class="btn btn-outline-warning" </button>
onclick="revokeToken({{ token.id }}, '{{ token.name }}')" </div>
title="Revoke Token"> </td>
<i class="fas fa-ban"></i> </tr>
</button> {% endfor %}
<button type="button" class="btn btn-outline-info" </tbody>
onclick="extendToken({{ token.id }}, '{{ token.name }}')" </table>
title="Extend Expiration">
<i class="fas fa-clock"></i>
</button>
{% endif %}
<button type="button" class="btn btn-outline-danger"
onclick="deleteToken({{ token.id }}, '{{ token.name }}')"
title="Delete Token">
<i class="fas fa-trash"></i>
</button>
</div>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% else %}
<div class="text-center py-5">
<i class="fas fa-key fa-3x text-muted mb-3"></i>
<h5 class="text-muted">No API tokens yet</h5>
<p class="text-muted">Create your first API token to start accessing the API</p>
<button type="button" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#createTokenModal">
<i class="fas fa-plus"></i> Create Your First Token
</button>
</div>
{% endif %}
</div> </div>
</div> {% else %}
<div class="text-center py-5">
<div style="font-size: 3rem; margin-bottom: 1rem;">🔑</div>
<h5 class="text-muted">No API tokens yet</h5>
<p class="text-muted">Create your first API token to start accessing the API</p>
<button type="button" class="btn" onclick="showCreateModal()">
➕ Create Your First Token
</button>
</div>
{% endif %}
</div> </div>
</div> </div>
</div> </div>
<!-- Create Token Modal --> <!-- Create Token Modal -->
<div class="modal fade" id="createTokenModal" tabindex="-1" aria-labelledby="createTokenModalLabel" aria-hidden="true"> <div class="modal" id="createTokenModal">
<div class="modal-dialog"> <div class="modal-dialog">
<div class="modal-content"> <div class="modal-header">
<div class="modal-header"> <h5 class="modal-title">Create New API Token</h5>
<h5 class="modal-title" id="createTokenModalLabel">Create New API Token</h5> <button type="button" class="close-btn" onclick="hideCreateModal()">×</button>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> </div>
</div> <form id="createTokenForm">
<form id="createTokenForm"> <div class="modal-body">
<div class="modal-body"> <div class="mb-3">
<div class="mb-3"> <label for="tokenName" class="form-label">Token Name</label>
<label for="tokenName" class="form-label">Token Name</label> <input type="text" class="form-control" id="tokenName" name="name" required
<input type="text" class="form-control" id="tokenName" name="name" required placeholder="e.g., Mobile App, Dashboard Integration">
placeholder="e.g., Mobile App, Dashboard Integration"> <div class="form-text">Choose a descriptive name to identify this token</div>
<div class="form-text">Choose a descriptive name to identify this token</div>
</div>
<div class="alert alert-warning">
<i class="fas fa-exclamation-triangle"></i>
<strong>Important:</strong> The token will only be shown once after creation. Make sure to copy and store it securely.
</div>
</div> </div>
<div class="modal-footer"> <div class="warning-message">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button> ⚠️ <strong>Important:</strong> The token will only be shown once after creation. Make sure to copy and store it securely.
<button type="submit" class="btn btn-primary">
<i class="fas fa-plus"></i> Create Token
</button>
</div> </div>
</form> </div>
</div> <div class="modal-footer">
<button type="button" class="btn btn-secondary" onclick="hideCreateModal()">Cancel</button>
<button type="submit" class="btn">
➕ Create Token
</button>
</div>
</form>
</div> </div>
</div> </div>
<!-- Token Created Modal --> <!-- Token Created Modal -->
<div class="modal fade" id="tokenCreatedModal" tabindex="-1" aria-labelledby="tokenCreatedModalLabel" aria-hidden="true"> <div class="modal" id="tokenCreatedModal">
<div class="modal-dialog modal-lg"> <div class="modal-dialog">
<div class="modal-content"> <div class="modal-header bg-success">
<div class="modal-header bg-success text-white"> <h5 class="modal-title" style="color: white;">
<h5 class="modal-title" id="tokenCreatedModalLabel"> ✅ Token Created Successfully
<i class="fas fa-check-circle"></i> Token Created Successfully </h5>
</h5> <button type="button" class="close-btn white" onclick="hideTokenCreatedModal()">×</button>
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal" aria-label="Close"></button> </div>
<div class="modal-body">
<div class="success-message">
<strong>Your new API token has been created!</strong>
</div> </div>
<div class="modal-body"> <div class="mb-3">
<div class="alert alert-success"> <label for="newTokenValue" class="form-label"><strong>Token Value:</strong></label>
<strong>Your new API token has been created!</strong> <div class="input-group">
</div> <input type="text" class="form-control font-monospace" id="newTokenValue" readonly>
<div class="mb-3"> <button class="btn btn-outline-secondary" type="button" onclick="copyToken()">
<label for="newTokenValue" class="form-label"><strong>Token Value:</strong></label> 📋 Copy
<div class="input-group"> </button>
<input type="text" class="form-control font-monospace" id="newTokenValue" readonly>
<button class="btn btn-outline-secondary" type="button" onclick="copyToken()">
<i class="fas fa-copy"></i> Copy
</button>
</div>
</div>
<div class="alert alert-danger">
<i class="fas fa-exclamation-triangle"></i>
<strong>Warning:</strong> This token will not be shown again. Make sure to copy and store it in a secure location.
</div> </div>
</div> </div>
<div class="modal-footer"> <div class="danger-message">
<button type="button" class="btn btn-primary" data-bs-dismiss="modal">I've Saved the Token</button> ⚠️ <strong>Warning:</strong> This token will not be shown again. Make sure to copy and store it in a secure location.
</div> </div>
</div> </div>
<div class="modal-footer">
<button type="button" class="btn" onclick="hideTokenCreatedModal()">I've Saved the Token</button>
</div>
</div> </div>
</div> </div>
<!-- Extend Token Modal --> <!-- Extend Token Modal -->
<div class="modal fade" id="extendTokenModal" tabindex="-1" aria-labelledby="extendTokenModalLabel" aria-hidden="true"> <div class="modal" id="extendTokenModal">
<div class="modal-dialog"> <div class="modal-dialog">
<div class="modal-content"> <div class="modal-header">
<div class="modal-header"> <h5 class="modal-title">Extend Token Expiration</h5>
<h5 class="modal-title" id="extendTokenModalLabel">Extend Token Expiration</h5> <button type="button" class="close-btn" onclick="hideExtendModal()">×</button>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<form id="extendTokenForm">
<div class="modal-body">
<p>Extend the expiration date for token: <strong id="extendTokenName"></strong></p>
<div class="mb-3">
<label for="extensionDays" class="form-label">Extend by (days)</label>
<select class="form-select" id="extensionDays" name="days">
<option value="30">30 days</option>
<option value="90">90 days</option>
<option value="180">180 days</option>
<option value="365" selected>365 days (1 year)</option>
</select>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
<button type="submit" class="btn btn-info">
<i class="fas fa-clock"></i> Extend Token
</button>
</div>
</form>
</div> </div>
<form id="extendTokenForm">
<div class="modal-body">
<p>Extend the expiration date for token: <strong id="extendTokenName"></strong></p>
<div class="mb-3">
<label for="extensionDays" class="form-label">Extend by (days)</label>
<select class="form-select" id="extensionDays" name="days">
<option value="30">30 days</option>
<option value="90">90 days</option>
<option value="180">180 days</option>
<option value="365" selected>365 days (1 year)</option>
</select>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" onclick="hideExtendModal()">Cancel</button>
<button type="submit" class="btn btn-outline-info">
🕒 Extend Token
</button>
</div>
</form>
</div> </div>
</div> </div>
...@@ -244,6 +545,33 @@ ...@@ -244,6 +545,33 @@
// Global variables for token management // Global variables for token management
let currentTokenId = null; let currentTokenId = null;
// Modal management functions
function showCreateModal() {
document.getElementById('createTokenModal').classList.add('show');
}
function hideCreateModal() {
document.getElementById('createTokenModal').classList.remove('show');
document.getElementById('createTokenForm').reset();
}
function showExtendModal(tokenId, tokenName) {
currentTokenId = tokenId;
document.getElementById('extendTokenName').textContent = tokenName;
document.getElementById('extendTokenModal').classList.add('show');
}
function hideExtendModal() {
document.getElementById('extendTokenModal').classList.remove('show');
currentTokenId = null;
}
function hideTokenCreatedModal() {
document.getElementById('tokenCreatedModal').classList.remove('show');
// Reload page to show the new token in the list
setTimeout(() => location.reload(), 500);
}
// Create token form submission // Create token form submission
document.getElementById('createTokenForm').addEventListener('submit', async function(e) { document.getElementById('createTokenForm').addEventListener('submit', async function(e) {
e.preventDefault(); e.preventDefault();
...@@ -269,21 +597,11 @@ document.getElementById('createTokenForm').addEventListener('submit', async func ...@@ -269,21 +597,11 @@ document.getElementById('createTokenForm').addEventListener('submit', async func
if (response.ok) { if (response.ok) {
// Hide create modal // Hide create modal
const createModal = bootstrap.Modal.getInstance(document.getElementById('createTokenModal')); hideCreateModal();
createModal.hide();
// Show token value in success modal // Show token value in success modal
document.getElementById('newTokenValue').value = data.token.token; document.getElementById('newTokenValue').value = data.token.token;
const tokenCreatedModal = new bootstrap.Modal(document.getElementById('tokenCreatedModal')); document.getElementById('tokenCreatedModal').classList.add('show');
tokenCreatedModal.show();
// Reset form
this.reset();
// Reload page after modal is closed
document.getElementById('tokenCreatedModal').addEventListener('hidden.bs.modal', function() {
location.reload();
}, { once: true });
} else { } else {
showAlert(data.error || 'Failed to create token', 'danger'); showAlert(data.error || 'Failed to create token', 'danger');
...@@ -316,8 +634,7 @@ document.getElementById('extendTokenForm').addEventListener('submit', async func ...@@ -316,8 +634,7 @@ document.getElementById('extendTokenForm').addEventListener('submit', async func
if (response.ok) { if (response.ok) {
showAlert(data.message, 'success'); showAlert(data.message, 'success');
const modal = bootstrap.Modal.getInstance(document.getElementById('extendTokenModal')); hideExtendModal();
modal.hide();
setTimeout(() => location.reload(), 1500); setTimeout(() => location.reload(), 1500);
} else { } else {
showAlert(data.error || 'Failed to extend token', 'danger'); showAlert(data.error || 'Failed to extend token', 'danger');
...@@ -381,13 +698,6 @@ async function deleteToken(tokenId, tokenName) { ...@@ -381,13 +698,6 @@ async function deleteToken(tokenId, tokenName) {
} }
} }
function extendToken(tokenId, tokenName) {
currentTokenId = tokenId;
document.getElementById('extendTokenName').textContent = tokenName;
const modal = new bootstrap.Modal(document.getElementById('extendTokenModal'));
modal.show();
}
function copyToken() { function copyToken() {
const tokenInput = document.getElementById('newTokenValue'); const tokenInput = document.getElementById('newTokenValue');
const tokenValue = tokenInput.value; const tokenValue = tokenInput.value;
...@@ -427,15 +737,16 @@ function fallbackCopyToken(tokenInput) { ...@@ -427,15 +737,16 @@ function fallbackCopyToken(tokenInput) {
function showAlert(message, type) { function showAlert(message, type) {
// Create alert element // Create alert element
const alertDiv = document.createElement('div'); const alertDiv = document.createElement('div');
alertDiv.className = `alert alert-${type} alert-dismissible fade show`; let alertClass = 'success-message';
alertDiv.innerHTML = ` if (type === 'danger') alertClass = 'danger-message';
${message} if (type === 'warning') alertClass = 'warning-message';
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
`;
// Insert at top of container alertDiv.className = alertClass;
const container = document.querySelector('.container-fluid'); alertDiv.innerHTML = message;
container.insertBefore(alertDiv, container.firstChild);
// Insert at top of content
const content = document.querySelector('.content');
content.insertBefore(alertDiv, content.firstChild);
// Auto-dismiss after 5 seconds // Auto-dismiss after 5 seconds
setTimeout(() => { setTimeout(() => {
...@@ -444,5 +755,33 @@ function showAlert(message, type) { ...@@ -444,5 +755,33 @@ function showAlert(message, type) {
} }
}, 5000); }, 5000);
} }
// Event listeners for token action buttons
document.addEventListener('click', function(e) {
if (e.target.classList.contains('modal')) {
e.target.classList.remove('show');
}
// Handle revoke token button clicks
if (e.target.classList.contains('revoke-token-btn')) {
const tokenId = e.target.getAttribute('data-token-id');
const tokenName = e.target.getAttribute('data-token-name');
revokeToken(tokenId, tokenName);
}
// Handle extend token button clicks
if (e.target.classList.contains('extend-token-btn')) {
const tokenId = e.target.getAttribute('data-token-id');
const tokenName = e.target.getAttribute('data-token-name');
showExtendModal(tokenId, tokenName);
}
// Handle delete token button clicks
if (e.target.classList.contains('delete-token-btn')) {
const tokenId = e.target.getAttribute('data-token-id');
const tokenName = e.target.getAttribute('data-token-name');
deleteToken(tokenId, tokenName);
}
});
</script> </script>
{% endblock %} {% endblock %}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment