2025-05-24 15:17:02 +02:00

354 lines
14 KiB
JavaScript

// API Key management functionality
// Load API keys
async function loadApiKeys() {
if (!config.isConfigured()) {
showAlert('Please configure your API settings first.', 'warning');
return;
}
const container = document.getElementById('apiKeysContainer');
container.innerHTML = '<div class="text-center"><div class="loading-spinner"></div> Loading API keys...</div>';
try {
const apiKeys = await apiClient.getApiKeys();
displayApiKeys(apiKeys);
} catch (error) {
handleApiError(error, 'loading API keys');
container.innerHTML = '<div class="alert alert-danger">Failed to load API keys</div>';
}
}
// Display API keys
function displayApiKeys(apiKeys) {
const container = document.getElementById('apiKeysContainer');
if (!apiKeys || apiKeys.length === 0) {
container.innerHTML = `
<div class="text-center py-5">
<i class="fas fa-key fa-3x text-muted mb-3"></i>
<h4>No API keys found</h4>
<p class="text-muted">Create your first API key to get started!</p>
<button class="btn btn-primary" onclick="showCreateApiKeyModal()">
<i class="fas fa-plus me-1"></i>Create API Key
</button>
</div>
`;
return;
}
const apiKeysHtml = `
<div class="table-responsive">
<table class="table table-hover">
<thead>
<tr>
<th>Name</th>
<th>Key</th>
<th>Status</th>
<th>Created</th>
<th>Last Used</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
${apiKeys.map(key => `
<tr>
<td>
<div class="d-flex align-items-center">
<i class="fas fa-key me-2 text-primary"></i>
${escapeHtml(key.name)}
</div>
</td>
<td>
<div class="d-flex align-items-center">
<code class="me-2" id="key-${key.id}">
${key.key ? key.key.substring(0, 8) + '...' : 'Hidden'}
</code>
<button class="btn btn-sm btn-outline-secondary"
onclick="copyApiKey('${key.key || ''}')"
title="Copy to clipboard">
<i class="fas fa-copy"></i>
</button>
</div>
</td>
<td>
<span class="badge ${key.is_active ? 'bg-success' : 'bg-danger'}">
${key.is_active ? 'Active' : 'Inactive'}
</span>
</td>
<td class="text-muted small">${formatDate(key.created_at)}</td>
<td class="text-muted small">
${key.last_used_at ? formatDate(key.last_used_at) : 'Never'}
</td>
<td>
<div class="btn-group" role="group">
<button class="btn btn-sm btn-outline-primary" onclick="viewApiKey('${key.id}')">
<i class="fas fa-eye"></i>
</button>
<button class="btn btn-sm btn-outline-danger" onclick="deleteApiKey('${key.id}')">
<i class="fas fa-trash"></i>
</button>
</div>
</td>
</tr>
`).join('')}
</tbody>
</table>
</div>
`;
container.innerHTML = apiKeysHtml;
}
// Show create API key modal
function showCreateApiKeyModal() {
const modalBody = `
<form id="createApiKeyForm">
<div class="mb-3">
<label for="apiKeyName" class="form-label">API Key Name *</label>
<input type="text" class="form-control" id="apiKeyName" required
placeholder="e.g., Mobile App, Integration Service">
<div class="form-text">Choose a descriptive name to identify this API key</div>
</div>
<div class="mb-3">
<label for="apiKeyDescription" class="form-label">Description</label>
<textarea class="form-control" id="apiKeyDescription" rows="3"
placeholder="Describe what this API key will be used for..."></textarea>
</div>
<div class="alert alert-info">
<i class="fas fa-info-circle me-2"></i>
<strong>Important:</strong> The API key will only be shown once after creation.
Make sure to copy and store it securely.
</div>
</form>
`;
const modalFooter = `
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
<button type="button" class="btn btn-primary" onclick="createApiKey()">
<i class="fas fa-plus me-1"></i>Create API Key
</button>
`;
const modal = createModal('createApiKeyModal', 'Create New API Key', modalBody, modalFooter);
// Handle form submission
document.getElementById('createApiKeyForm').addEventListener('submit', (e) => {
e.preventDefault();
createApiKey();
});
modal.show();
// Focus on name field
setTimeout(() => document.getElementById('apiKeyName').focus(), 100);
}
// Create API key
async function createApiKey() {
const name = document.getElementById('apiKeyName').value.trim();
const description = document.getElementById('apiKeyDescription').value.trim();
if (!name) {
showAlert('API key name is required', 'danger');
return;
}
const createButton = document.querySelector('#createApiKeyModal .btn-primary');
setLoadingState(createButton);
try {
const result = await apiClient.createApiKey({
name,
description
});
// Close the create modal
bootstrap.Modal.getInstance(document.getElementById('createApiKeyModal')).hide();
removeModal('createApiKeyModal');
// Show the new API key
showNewApiKeyModal(result);
// Refresh the list
loadApiKeys();
} catch (error) {
handleApiError(error, 'creating API key');
} finally {
setLoadingState(createButton, false);
}
}
// Show new API key modal
function showNewApiKeyModal(apiKeyData) {
const modalBody = `
<div class="alert alert-success">
<i class="fas fa-check-circle me-2"></i>
<strong>API Key Created Successfully!</strong>
</div>
<div class="mb-4">
<label class="form-label"><strong>API Key Name:</strong></label>
<p>${escapeHtml(apiKeyData.name)}</p>
</div>
<div class="mb-4">
<label class="form-label"><strong>API Key:</strong></label>
<div class="input-group">
<input type="text" class="form-control" id="newApiKeyValue"
value="${apiKeyData.key}" readonly>
<button class="btn btn-outline-secondary" onclick="copyApiKey('${apiKeyData.key}')">
<i class="fas fa-copy"></i> Copy
</button>
</div>
</div>
<div class="alert alert-warning">
<i class="fas fa-exclamation-triangle me-2"></i>
<strong>Important:</strong> This is the only time you'll see this API key.
Make sure to copy and store it securely before closing this dialog.
</div>
`;
const modalFooter = `
<button type="button" class="btn btn-primary" data-bs-dismiss="modal" onclick="copyApiKey('${apiKeyData.key}')">
<i class="fas fa-copy me-1"></i>Copy & Close
</button>
`;
const modal = createModal('newApiKeyModal', 'New API Key Created', modalBody, modalFooter);
modal.show();
// Auto-select the API key text
setTimeout(() => {
const input = document.getElementById('newApiKeyValue');
input.select();
input.focus();
}, 100);
}
// Copy API key to clipboard
async function copyApiKey(key) {
if (!key) {
showAlert('No API key to copy', 'warning');
return;
}
try {
await copyToClipboard(key);
} catch (error) {
// Fallback for older browsers
const textArea = document.createElement('textarea');
textArea.value = key;
document.body.appendChild(textArea);
textArea.select();
document.execCommand('copy');
document.body.removeChild(textArea);
showAlert('API key copied to clipboard!', 'success');
}
}
// View API key details
async function viewApiKey(keyId) {
try {
const apiKeys = await apiClient.getApiKeys();
const apiKey = apiKeys.find(k => k.id === keyId);
if (!apiKey) {
showAlert('API key not found', 'danger');
return;
}
const modalBody = `
<div class="row">
<div class="col-12">
<h5><i class="fas fa-key me-2"></i>${escapeHtml(apiKey.name)}</h5>
<p class="text-muted">${escapeHtml(apiKey.description || 'No description')}</p>
<hr>
<div class="row">
<div class="col-md-6">
<h6>Key Information</h6>
<p><strong>Created:</strong> ${formatDate(apiKey.created_at)}</p>
<p><strong>Last Used:</strong> ${apiKey.last_used_at ? formatDate(apiKey.last_used_at) : 'Never'}</p>
<p><strong>ID:</strong> <code>${apiKey.id}</code></p>
</div>
<div class="col-md-6">
<h6>Status & Security</h6>
<p><strong>Status:</strong>
<span class="badge ${apiKey.is_active ? 'bg-success' : 'bg-danger'}">
${apiKey.is_active ? 'Active' : 'Inactive'}
</span>
</p>
<p><strong>Key Preview:</strong> <code>${apiKey.key ? apiKey.key.substring(0, 8) + '...' : 'Hidden'}</code></p>
</div>
</div>
${apiKey.last_used_at ? `
<div class="mt-3">
<h6>Usage Statistics</h6>
<div class="alert alert-info">
<i class="fas fa-chart-line me-2"></i>
This API key was last used on ${formatDate(apiKey.last_used_at)}
</div>
</div>
` : `
<div class="mt-3">
<div class="alert alert-warning">
<i class="fas fa-exclamation-triangle me-2"></i>
This API key has never been used
</div>
</div>
`}
</div>
</div>
`;
const modalFooter = `
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
<button type="button" class="btn btn-danger" onclick="deleteApiKey('${keyId}')">
<i class="fas fa-trash me-1"></i>Delete Key
</button>
`;
const modal = createModal('viewApiKeyModal', 'API Key Details', modalBody, modalFooter);
modal.show();
} catch (error) {
handleApiError(error, 'loading API key details');
}
}
// Delete API key
function deleteApiKey(keyId) {
confirmAction('Are you sure you want to delete this API key? This action cannot be undone and will immediately revoke access for any applications using this key.', async () => {
try {
await apiClient.deleteApiKey(keyId);
showAlert('API key deleted successfully!', 'success');
loadApiKeys();
// Close any open modals
const modals = ['viewApiKeyModal', 'newApiKeyModal'];
modals.forEach(modalId => {
const modalElement = document.getElementById(modalId);
if (modalElement) {
bootstrap.Modal.getInstance(modalElement)?.hide();
removeModal(modalId);
}
});
} catch (error) {
handleApiError(error, 'deleting API key');
}
});
}
// Generate API key usage report
function generateUsageReport() {
showAlert('Usage report functionality would be implemented here', 'info');
}
// Bulk operations for API keys
function bulkDeleteApiKeys() {
showAlert('Bulk operations functionality would be implemented here', 'info');
}