freeleaps-ops/apps/gitea-webhook-ambassador/internal/web/assets/js/dashboard.js
zhenyus db590f3f27 refactor: update gitea-webhook-ambassador Dockerfile and configuration
- Changed the build process to include a web UI build stage using Node.js.
- Updated Go build stage to copy web UI files to the correct location.
- Removed the main.go file as it is no longer needed.
- Added SQLite database configuration to example config.
- Updated dependencies in go.mod and go.sum, including new packages for JWT and SQLite.
- Modified .gitignore to include new database and configuration files.

Signed-off-by: zhenyus <zhenyus@mathmast.com>
2025-06-10 16:00:52 +08:00

268 lines
7.2 KiB
JavaScript

// Global variable to store the JWT token
let authToken = localStorage.getItem("auth_token");
$(document).ready(function () {
// Initialize tooltips
$('[data-bs-toggle="tooltip"]').tooltip();
// Set up AJAX defaults to include auth token
$.ajaxSetup({
beforeSend: function (xhr, settings) {
// Don't 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 we get a 401, redirect to login
if (xhr.status === 401) {
localStorage.removeItem("auth_token");
window.location.href = "/login";
return;
}
handleAjaxError(xhr, status, error);
},
});
// Handle login form submission
$("#loginForm").on("submit", function (e) {
e.preventDefault();
const secretKey = $("#secret_key").val();
$("#loginError").hide();
$.ajax({
url: "/api/auth/login",
method: "POST",
contentType: "application/json",
data: JSON.stringify({ secret_key: secretKey }),
success: function (response) {
if (response && response.token) {
// Store token and redirect
localStorage.setItem("auth_token", response.token);
authToken = response.token;
window.location.href = "/dashboard";
} else {
$("#loginError").text("Invalid response from server").show();
}
},
error: function (xhr) {
console.error("Login error:", xhr);
if (xhr.responseJSON && xhr.responseJSON.error) {
$("#loginError").text(xhr.responseJSON.error).show();
} else {
$("#loginError").text("Login failed. Please try again.").show();
}
$("#secret_key").val("").focus();
},
});
});
// Only load dashboard data if we're on the dashboard page
if (window.location.pathname === "/dashboard") {
if (!authToken) {
window.location.href = "/login";
return;
}
// Load initial data
loadProjects();
loadAPIKeys();
loadLogs();
checkHealth();
// Set up 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");
loadProjects();
},
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 () {
$("#generateKeyModal").modal("hide");
loadAPIKeys();
},
error: handleAjaxError,
});
});
// Log querying
$("#logQueryForm").on("submit", function (e) {
e.preventDefault();
loadLogs({
startTime: $("#startTime").val(),
endTime: $("#endTime").val(),
level: $("#logLevel").val(),
query: $("#logQuery").val(),
});
});
});
function loadProjects() {
$.get("/api/projects")
.done(function (data) {
const tbody = $("#projectsTable tbody");
tbody.empty();
data.projects.forEach(function (project) {
tbody.append(`
<tr>
<td>${escapeHtml(project.name)}</td>
<td>${escapeHtml(project.jenkinsJob)}</td>
<td>${escapeHtml(project.giteaRepo)}</td>
</tr>
`);
});
})
.fail(handleAjaxError);
}
function loadAPIKeys() {
$.get("/api/keys")
.done(function (data) {
const tbody = $("#apiKeysTable tbody");
tbody.empty();
data.keys.forEach(function (key) {
tbody.append(`
<tr>
<td>${escapeHtml(key.description)}</td>
<td><code class="api-key">${escapeHtml(
key.value
)}</code></td>
<td>${new Date(key.created).toLocaleString()}</td>
<td>
<button class="btn btn-sm btn-danger" onclick="revokeKey('${
key.id
}')">
Revoke
</button>
</td>
</tr>
`);
});
})
.fail(handleAjaxError);
}
function loadLogs(query = {}) {
$.get("/api/logs", query)
.done(function (data) {
const logContainer = $("#logEntries");
logContainer.empty();
data.logs.forEach(function (log) {
const levelClass =
{
error: "text-danger",
warn: "text-warning",
info: "text-info",
debug: "text-secondary",
}[log.level] || "";
logContainer.append(`
<div class="log-entry ${levelClass}">
<small>${new Date(log.timestamp).toISOString()}</small>
[${escapeHtml(log.level)}] ${escapeHtml(log.message)}
</div>
`);
});
})
.fail(handleAjaxError);
}
function checkHealth() {
$.get("/api/health")
.done(function (data) {
const indicator = $(".health-indicator");
indicator
.removeClass("healthy unhealthy")
.addClass(data.status === "healthy" ? "healthy" : "unhealthy");
$("#healthStatus").text(data.status);
})
.fail(function () {
const indicator = $(".health-indicator");
indicator.removeClass("healthy").addClass("unhealthy");
$("#healthStatus").text("unhealthy");
});
}
function deleteProject(id) {
if (!confirm("Are you sure you want to delete this project?")) return;
$.ajax({
url: `/api/projects/${id}`,
method: "DELETE",
success: loadProjects,
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: loadAPIKeys,
error: handleAjaxError,
});
}
function handleAjaxError(jqXHR, textStatus, errorThrown) {
const message =
jqXHR.responseJSON?.error || errorThrown || "An error occurred";
alert(`Error: ${message}`);
}
function escapeHtml(unsafe) {
return unsafe
.replace(/&/g, "&amp;")
.replace(/</g, "&lt;")
.replace(/>/g, "&gt;")
.replace(/"/g, "&quot;")
.replace(/'/g, "&#039;");
}
function getCookie(name) {
const cookies = document.cookie.split(";");
for (let cookie of cookies) {
const [cookieName, cookieValue] = cookie.split("=").map((c) => c.trim());
if (cookieName === name) {
console.debug(`Found cookie ${name}`);
return cookieValue;
}
}
console.debug(`Cookie ${name} not found`);
return null;
}