// Global variable to store JWT token
let authToken = localStorage.getItem('auth_token');
$(document).ready(function() {
// Check authentication status
if (!authToken) {
window.location.href = '/login';
return;
}
// Set AJAX default config
$.ajaxSetup({
beforeSend: function(xhr, settings) {
// Do not add auth header for login request
if (settings.url === '/api/auth/login') {
return;
}
if (authToken) {
xhr.setRequestHeader('Authorization', 'Bearer ' + authToken);
}
},
error: function(xhr, status, error) {
// If 401 received, redirect to login page
if (xhr.status === 401) {
localStorage.removeItem('auth_token');
window.location.href = '/login';
return;
}
handleAjaxError(xhr, status, error);
}
});
// Initialize tooltips
$('[data-bs-toggle="tooltip"]').tooltip();
// Load initial data
loadProjects();
loadAPIKeys();
loadLogs();
checkHealth();
loadHealthDetails();
loadStatsDetails();
// Set periodic health check
setInterval(checkHealth, 30000);
// Project management
$('#addProjectForm').on('submit', function(e) {
e.preventDefault();
const projectData = {
name: $('#projectName').val(),
jenkinsJob: $('#jenkinsJob').val(),
giteaRepo: $('#giteaRepo').val()
};
$.ajax({
url: '/api/projects/',
method: 'POST',
contentType: 'application/json',
data: JSON.stringify(projectData),
success: function() {
$('#addProjectModal').modal('hide');
$('#addProjectForm')[0].reset();
loadProjects();
showSuccess('Project added successfully');
},
error: handleAjaxError
});
});
// API key management
$('#generateKeyForm').on('submit', function(e) {
e.preventDefault();
$.ajax({
url: '/api/keys',
method: 'POST',
contentType: 'application/json',
data: JSON.stringify({ description: $('#keyDescription').val() }),
success: function(response) {
$('#generateKeyModal').modal('hide');
$('#generateKeyForm')[0].reset();
loadAPIKeys();
showSuccess('API key generated successfully');
// Show newly generated key
showApiKeyModal(response.key);
},
error: handleAjaxError
});
});
// Log query
$('#logQueryForm').on('submit', function(e) {
e.preventDefault();
loadLogs({
startTime: $('#startTime').val(),
endTime: $('#endTime').val(),
level: $('#logLevel').val(),
query: $('#logQuery').val()
});
});
// Tab switching
$('.nav-link').on('click', function() {
$('.nav-link').removeClass('active');
$(this).addClass('active');
});
});
function loadProjects() {
$.get('/api/projects/')
.done(function(data) {
const tbody = $('#projectsTable tbody');
tbody.empty();
data.projects.forEach(function(project) {
tbody.append(`
| ${escapeHtml(project.name)} |
${escapeHtml(project.jenkinsJob)} |
${escapeHtml(project.giteaRepo)} |
|
`);
});
})
.fail(handleAjaxError);
}
function loadAPIKeys() {
$.get('/api/keys')
.done(function(data) {
const tbody = $('#apiKeysTable tbody');
tbody.empty();
data.keys.forEach(function(key) {
tbody.append(`
| ${escapeHtml(key.description || 'No description')} |
${escapeHtml(key.key)} |
${new Date(key.created_at).toLocaleString('zh-CN')} |
|
`);
});
})
.fail(handleAjaxError);
}
function loadLogs(query = {}) {
$.get('/api/logs', query)
.done(function(data) {
const logContainer = $('#logEntries');
logContainer.empty();
if (data.logs && data.logs.length > 0) {
data.logs.forEach(function(log) {
const levelClass = {
'error': 'error',
'warn': 'warn',
'info': 'info',
'debug': 'debug'
}[log.level] || '';
logContainer.append(`
${new Date(log.timestamp).toLocaleString('zh-CN')}
[${escapeHtml(log.level.toUpperCase())}] ${escapeHtml(log.message)}
`);
});
} else {
logContainer.append('No log records
');
}
})
.fail(handleAjaxError);
}
function checkHealth() {
$.get('/health')
.done(function(data) {
const indicator = $('.health-indicator');
indicator.removeClass('healthy unhealthy')
.addClass(data.status === 'healthy' ? 'healthy' : 'unhealthy');
$('#healthStatus').text(data.status === 'healthy' ? 'Healthy' : 'Unhealthy');
})
.fail(function() {
const indicator = $('.health-indicator');
indicator.removeClass('healthy').addClass('unhealthy');
$('#healthStatus').text('Unhealthy');
});
}
function loadHealthDetails() {
$.get('/health')
.done(function(data) {
const healthDetails = $('#healthDetails');
healthDetails.html(`
Status:
${data.status === 'healthy' ? 'Healthy' : 'Unhealthy'}
Version: ${data.version || 'Unknown'}
Uptime: ${data.uptime || 'Unknown'}
Memory Usage: ${data.memory || 'Unknown'}
`);
})
.fail(function() {
$('#healthDetails').html('Unable to get health status
');
});
}
function loadStatsDetails() {
$.get('/api/stats')
.done(function(data) {
const statsDetails = $('#statsDetails');
statsDetails.html(`
Total Projects: ${data.total_projects || 0}
API Keys: ${data.total_api_keys || 0}
Today's Triggers: ${data.today_triggers || 0}
Successful Triggers: ${data.successful_triggers || 0}
`);
})
.fail(function() {
$('#statsDetails').html('Unable to get statistics
');
});
}
function deleteProject(id) {
if (!confirm('Are you sure you want to delete this project?')) return;
$.ajax({
url: `/api/projects/${id}`,
method: 'DELETE',
success: function() {
loadProjects();
showSuccess('Project deleted successfully');
},
error: handleAjaxError
});
}
function revokeKey(id) {
if (!confirm('Are you sure you want to revoke this API key?')) return;
$.ajax({
url: `/api/keys/${id}`,
method: 'DELETE',
success: function() {
loadAPIKeys();
showSuccess('API key revoked successfully');
},
error: handleAjaxError
});
}
function showApiKeyModal(key) {
// Create modal to show newly generated key
const modal = $(`
`);
$('body').append(modal);
modal.modal('show');
modal.on('hidden.bs.modal', function() {
modal.remove();
});
}
function copyToClipboard(text) {
navigator.clipboard.writeText(text).then(function() {
showSuccess('Copied to clipboard');
}, function() {
showError('Copy failed');
});
}
function handleAjaxError(jqXHR, textStatus, errorThrown) {
const message = jqXHR.responseJSON?.detail || errorThrown || 'An error occurred';
showError(`Error: ${message}`);
}
function showSuccess(message) {
// Create success alert
const alert = $(`
${message}
`);
$('.main-content').prepend(alert);
// Auto dismiss after 3 seconds
setTimeout(function() {
alert.alert('close');
}, 3000);
}
function showError(message) {
// Create error alert
const alert = $(`
${message}
`);
$('.main-content').prepend(alert);
// Auto dismiss after 5 seconds
setTimeout(function() {
alert.alert('close');
}, 5000);
}
function escapeHtml(unsafe) {
return unsafe
.replace(/&/g, '&')
.replace(//g, '>')
.replace(/"/g, '"')
.replace(/'/g, ''');
}