Files
llm-monitor/app/web/static/js/servers.js
T
2026-04-25 15:40:20 +02:00

179 lines
5.5 KiB
JavaScript

class ServersPage {
constructor() {
this.form = document.getElementById("server-form");
this.serverIdInput = document.getElementById("server-id");
this.serverNameInput = document.getElementById("server-name");
this.serverHostInput = document.getElementById("server-host");
this.clearFormBtn = document.getElementById("clear-form-btn");
this.serversList = document.getElementById("servers-list");
this.serversCount = document.getElementById("servers-count");
this.init();
}
init() {
this.form?.addEventListener("submit", (event) => {
event.preventDefault();
this.saveServer();
});
this.clearFormBtn?.addEventListener("click", () => this.resetForm());
this.renderServers();
}
saveServer() {
const name = this.serverNameInput?.value.trim() || "";
const host = normalizeHost(this.serverHostInput?.value || "");
if (!name || !host) {
return;
}
const existingId = this.serverIdInput?.value || "";
const servers = loadServers();
if (existingId) {
const index = servers.findIndex((server) => server.id === existingId);
if (index >= 0) {
servers[index] = { ...servers[index], name, host };
}
saveServers(servers);
setActiveServerId(existingId);
} else {
const newServer = {
id: generateServerId(),
name,
host
};
servers.push(newServer);
saveServers(servers);
setActiveServerId(newServer.id);
}
this.resetForm();
this.renderServers();
}
editServer(serverId) {
const server = getServerById(serverId);
if (!server) {
return;
}
this.serverIdInput.value = server.id;
this.serverNameInput.value = server.name;
this.serverHostInput.value = server.host;
}
deleteServer(serverId) {
const servers = loadServers().filter((server) => server.id !== serverId);
saveServers(servers);
const activeServerId = getActiveServerId();
if (activeServerId === serverId) {
if (servers.length > 0) {
setActiveServerId(servers[0].id);
} else {
localStorage.removeItem(ACTIVE_SERVER_KEY);
}
}
this.renderServers();
}
selectServer(serverId) {
setActiveServerId(serverId);
this.renderServers();
}
openAvailable(serverId) {
window.location.href = buildServerUrl("/models-available", serverId);
}
openRunning(serverId) {
window.location.href = buildServerUrl("/models-running", serverId);
}
resetForm() {
this.serverIdInput.value = "";
this.serverNameInput.value = "";
this.serverHostInput.value = "";
}
renderServers() {
const servers = loadServers();
const activeServerId = getActiveServerId();
if (this.serversCount) {
this.serversCount.textContent = `${servers.length} server${servers.length === 1 ? "" : "s"}`;
}
if (!this.serversList) {
return;
}
if (servers.length === 0) {
this.serversList.innerHTML = `
<div class="text-center py-10 text-gray-400 border border-dashed border-gray-600 rounded-lg">
No servers configured yet. Add your first Ollama endpoint in the control panel.
</div>
`;
return;
}
this.serversList.innerHTML = servers
.map((server) => {
const isActive = server.id === activeServerId;
return `
<div class="bg-gray-700 border ${isActive ? "border-purple-500" : "border-gray-600"} rounded-lg p-4">
<div class="flex flex-col md:flex-row md:items-center md:justify-between gap-4">
<div>
<h3 class="text-lg font-semibold">${this.escapeHtml(server.name)}</h3>
<p class="text-xs text-gray-300 mt-1">${this.escapeHtml(server.host)}</p>
</div>
<div class="flex flex-wrap gap-2">
<button data-action="select" data-server-id="${server.id}" class="bg-gray-800 hover:bg-gray-900 px-3 py-2 rounded text-xs">${isActive ? "Selected" : "Select"}</button>
<button data-action="available" data-server-id="${server.id}" class="bg-blue-700 hover:bg-blue-800 px-3 py-2 rounded text-xs">Available</button>
<button data-action="running" data-server-id="${server.id}" class="bg-green-700 hover:bg-green-800 px-3 py-2 rounded text-xs">Running</button>
<button data-action="edit" data-server-id="${server.id}" class="bg-amber-700 hover:bg-amber-800 px-3 py-2 rounded text-xs">Edit</button>
<button data-action="delete" data-server-id="${server.id}" class="bg-red-700 hover:bg-red-800 px-3 py-2 rounded text-xs">Delete</button>
</div>
</div>
</div>
`;
})
.join("");
this.bindServerActions();
}
bindServerActions() {
this.serversList.querySelectorAll("button[data-action]").forEach((button) => {
button.addEventListener("click", () => {
const action = button.getAttribute("data-action");
const serverId = button.getAttribute("data-server-id") || "";
if (!serverId) {
return;
}
if (action === "select") this.selectServer(serverId);
if (action === "available") this.openAvailable(serverId);
if (action === "running") this.openRunning(serverId);
if (action === "edit") this.editServer(serverId);
if (action === "delete") this.deleteServer(serverId);
});
});
}
escapeHtml(text) {
const div = document.createElement("div");
div.textContent = text;
return div.innerHTML;
}
}
document.addEventListener("DOMContentLoaded", () => {
window.serversPage = new ServersPage();
});