diff --git a/app.js b/app.js
index a8377ae..851028b 100644
--- a/app.js
+++ b/app.js
@@ -8,7 +8,6 @@ const ROUTES = {
instances: "/admin/instance",
backup: "/admin/backup-repo",
servers: "/admin/server",
- seats: "/server",
keys: "/admin/key",
crm: "/crm",
};
@@ -904,48 +903,47 @@ async function serversLoadData() {
document.getElementById("server-dashboard").innerHTML =
`
`;
try {
- const res = await apiFetch(apiUrl(ROUTES.servers), {
- headers: apiHeaders(),
- });
- if (!res.ok) throw new Error(`HTTP ${res.status}: ${res.statusText}`);
- const json = await res.json();
- const raw = Array.isArray(json) ? json : [json];
- serversData = raw
- .map((item) => {
- try {
- return typeof item.text === "string" ? JSON.parse(item.text) : item;
- } catch {
- return null;
- }
- })
- .filter(Boolean);
- /* ─── Fetch seat data ─────────────────────────────────────── */
- let seatMap = {};
- try {
- const seatRes = await fetch("https://n8n.derez.ai/webhook/server");
- if (seatRes.ok) {
- const seatJson = await seatRes.json();
- const seatArr = Array.isArray(seatJson?.data)
- ? seatJson.data
- : Array.isArray(seatJson)
- ? seatJson
- : [];
- for (const s of seatArr) {
- if (s.server) seatMap[s.server.toLowerCase().trim()] = s;
- }
- }
- } catch (_) {
- /* seat data is optional */
- }
+ /* ─── Step 1: Fetch server list with seats ──────────────── */
+ const seatRes = await fetch("https://n8n.derez.ai/webhook/server");
+ if (!seatRes.ok) throw new Error(`Seat API HTTP ${seatRes.status}`);
+ const seatJson = await seatRes.json();
+ const seatList = Array.isArray(seatJson?.data)
+ ? seatJson.data
+ : Array.isArray(seatJson)
+ ? seatJson
+ : [];
+ if (!seatList.length) throw new Error("No servers in seat endpoint");
- /* ─── Merge seats into server data ─────────────────────────── */
- for (const sv of serversData) {
- const key = (
- typeof sv.server === "string" ? sv.server : (sv.server?.name ?? "")
- )
- .toLowerCase()
- .trim();
- sv.seats = seatMap[key] || null;
+ /* ─── Step 2: Fetch full dashboard for each server ─────── */
+ serversData = [];
+ for (const seat of seatList) {
+ const serverName = seat.server;
+ try {
+ const res = await apiFetch(
+ apiUrl(ROUTES.servers) + "?server=" + encodeURIComponent(serverName),
+ {
+ headers: apiHeaders(),
+ },
+ );
+ if (res.ok) {
+ const json = await res.json();
+ const raw = Array.isArray(json) ? json : [json];
+ for (const item of raw) {
+ let parsed;
+ try {
+ parsed =
+ typeof item.text === "string" ? JSON.parse(item.text) : item;
+ } catch {
+ continue;
+ }
+ if (!parsed) continue;
+ parsed.seats = seat;
+ serversData.push(parsed);
+ }
+ }
+ } catch (_) {
+ /* skip servers that fail */
+ }
}
if (serversData.length === 0) throw new Error("No server data in response");
@@ -981,7 +979,9 @@ function serversRenderTabs() {
.map((s, i) => {
const status = s.summary?.overall_status ?? "unknown";
const color = dotColor[status] ?? "var(--text-muted)";
- const name = escHtml(s.server?.name ?? `Server ${i + 1}`);
+ const name = escHtml(
+ s.server?.name ?? s.seats?.server ?? `Server ${i + 1}`,
+ );
return `
${name}
@@ -1108,7 +1108,7 @@ function serversRenderDashboard(idx) {
- ${escHtml(server.name)}
+ ${escHtml(server.name ?? s.seats?.server)}
${summary.overall_status.toUpperCase()}