import { apiFetch } from "./api.js";
import { dom } from "./dom.js";
import { loadPoints, updatePointFilterSummary } from "./points.js";
import { state } from "./state.js";
function renderPointSourceOptions() {
if (!dom.pointSourceSelect) {
return;
}
const options = [''];
state.sources.forEach((source) => {
const selected = source.id === state.selectedSourceId ? "selected" : "";
options.push(``);
});
dom.pointSourceSelect.innerHTML = options.join("");
}
export function renderSources() {
dom.sourceList.innerHTML = "";
state.sources.forEach((source) => {
const card = document.createElement("div");
card.className = `list-item source-card ${state.selectedSourceId === source.id ? "selected" : ""}`;
card.innerHTML = `
${source.name}
${source.is_connected ? "ONLINE" : "OFFLINE"}
${source.endpoint}
`;
card.addEventListener("click", () => {
selectSource(source.id).catch((error) => {
dom.statusText.textContent = error.message;
});
});
const actionRow = card.querySelector(".source-card-actions");
const editBtn = document.createElement("button");
editBtn.className = "secondary";
editBtn.textContent = "Edit";
editBtn.addEventListener("click", (event) => {
event.stopPropagation();
dom.sourceId.value = source.id;
dom.sourceName.value = source.name || "";
dom.sourceEndpoint.value = source.endpoint || "";
dom.sourceEnabled.checked = !!source.enabled;
dom.sourceModal.classList.remove("hidden");
});
const reconnectBtn = document.createElement("button");
reconnectBtn.className = "secondary";
reconnectBtn.textContent = "Reconnect";
reconnectBtn.addEventListener("click", (event) => {
event.stopPropagation();
reconnectSource(source.id, source.name).catch((error) => {
dom.statusText.textContent = error.message;
});
});
const deleteBtn = document.createElement("button");
deleteBtn.className = "danger";
deleteBtn.textContent = "Delete";
deleteBtn.addEventListener("click", (event) => {
event.stopPropagation();
deleteSource(source.id).catch((error) => {
dom.statusText.textContent = error.message;
});
});
actionRow.append(editBtn, reconnectBtn, deleteBtn);
card.appendChild(actionRow);
dom.sourceList.appendChild(card);
});
renderPointSourceOptions();
}
export async function loadSources() {
state.sources = await apiFetch("/api/source");
if (state.selectedSourceId && !state.sources.some((item) => item.id === state.selectedSourceId)) {
state.selectedSourceId = null;
}
renderSources();
updatePointFilterSummary();
}
export async function selectSource(sourceId) {
state.selectedSourceId = state.selectedSourceId === sourceId ? null : sourceId;
state.selectedNodeIds.clear();
state.pointsPage = 1;
renderSources();
updatePointFilterSummary();
await loadPoints();
}
export async function saveSource(event) {
event.preventDefault();
const payload = {
name: dom.sourceName.value.trim(),
endpoint: dom.sourceEndpoint.value.trim(),
enabled: dom.sourceEnabled.checked,
};
const id = dom.sourceId.value;
await apiFetch(id ? `/api/source/${id}` : "/api/source", {
method: id ? "PUT" : "POST",
body: JSON.stringify(payload),
});
dom.sourceModal.classList.add("hidden");
dom.sourceForm.reset();
await loadSources();
}
export async function reconnectSource(sourceId, name) {
dom.statusText.textContent = `Reconnecting ${name || "Source"}...`;
await apiFetch(`/api/source/${sourceId}/reconnect`, { method: "POST" });
await loadSources();
dom.statusText.textContent = "Ready";
}
export async function deleteSource(sourceId) {
if (!window.confirm("Delete this source?")) {
return;
}
await apiFetch(`/api/source/${sourceId}`, { method: "DELETE" });
if (state.selectedSourceId === sourceId) {
state.selectedSourceId = null;
}
await loadSources();
await loadPoints();
}