feat: add multi-server control panel and host-aware sync
This commit is contained in:
@@ -0,0 +1,178 @@
|
||||
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();
|
||||
});
|
||||
Reference in New Issue
Block a user