import { withStatus } from "./api.js"; import { openChart, renderChart } from "./chart.js"; import { dom } from "./dom.js"; import { closeApiDocDrawer, openApiDocDrawer, openReadmeDrawer } from "./docs.js"; import { loadEvents } from "./events.js"; import { applyBatchEquipmentUnit, clearPointBinding, clearSelectedEquipments, closeEquipmentModal, loadEquipments, openCreateEquipmentModal, resetEquipmentForm, saveEquipment, } from "./equipment.js"; import { startPointSocket, startLogs, stopLogs } from "./logs.js"; import { startOps, renderOpsUnits, loadAllEquipmentCards } from "./ops.js"; import { clearBatchBinding, browseAndLoadTree, clearSelectedPoints, createPoints, loadPoints, loadTree, openBatchBinding, openPointCreateModal, renderSelectedNodes, saveBatchBinding, savePointBinding, updatePointFilterSummary, updateSelectedPointSummary, } from "./points.js"; import { state } from "./state.js"; import { loadSources, saveSource } from "./sources.js"; import { bindUnitEquipmentModalEvents, closeUnitModal, loadUnits, openCreateUnitModal, resetUnitForm, renderUnits, saveUnit } from "./units.js"; let _configLoaded = false; let _appConfigLoaded = false; function switchView(view) { state.activeView = view; const main = document.querySelector("main"); main.className = view === "ops" ? "grid-ops" : view === "app-config" ? "grid-app-config" : "grid-config"; dom.tabOps.classList.toggle("active", view === "ops"); dom.tabAppConfig.classList.toggle("active", view === "app-config"); dom.tabConfig.classList.toggle("active", view === "config"); // config-only panels (platform config view) ["top-left", "top-right", "bottom-left", "bottom-right"].forEach((cls) => { const el = main.querySelector(`.panel.${cls}`); if (el) el.classList.toggle("hidden", view !== "config"); }); const logStreamPanel = main.querySelector(".panel.bottom-mid"); if (logStreamPanel) logStreamPanel.classList.toggle("hidden", view !== "config"); // ops-only panels const opsMain = main.querySelector(".panel.ops-main"); const opsBottom = main.querySelector(".panel.ops-bottom"); if (opsMain) opsMain.classList.toggle("hidden", view !== "ops"); if (opsBottom) opsBottom.classList.toggle("hidden", view !== "ops"); // app-config-only panels const appConfigMain = main.querySelector(".panel.app-config-main"); if (appConfigMain) appConfigMain.classList.toggle("hidden", view !== "app-config"); if (view === "config") { startLogs(); if (!_configLoaded) { _configLoaded = true; withStatus((async () => { await Promise.all([loadSources(), loadEquipments(), loadEvents()]); await loadPoints(); })()); } } else { stopLogs(); } if (view === "app-config") { if (!_appConfigLoaded) { _appConfigLoaded = true; withStatus(Promise.all([loadUnits(), loadEquipments()])); } } } function bindEvents() { dom.unitForm.addEventListener("submit", (event) => withStatus(saveUnit(event))); dom.sourceForm.addEventListener("submit", (event) => withStatus(saveSource(event))); dom.equipmentForm.addEventListener("submit", (event) => withStatus(saveEquipment(event))); dom.pointBindingForm.addEventListener("submit", (event) => withStatus(savePointBinding(event))); dom.batchBindingForm.addEventListener("submit", (event) => withStatus(saveBatchBinding(event))); dom.unitResetBtn.addEventListener("click", resetUnitForm); if (dom.refreshUnitBtn) dom.refreshUnitBtn.addEventListener("click", () => withStatus(loadUnits().then(loadEvents))); if (dom.newUnitBtn) dom.newUnitBtn.addEventListener("click", openCreateUnitModal); dom.closeUnitModalBtn.addEventListener("click", closeUnitModal); dom.sourceResetBtn.addEventListener("click", () => dom.sourceForm.reset()); dom.equipmentResetBtn.addEventListener("click", resetEquipmentForm); dom.refreshEquipmentBtn.addEventListener("click", () => withStatus(loadEquipments())); dom.newEquipmentBtn.addEventListener("click", openCreateEquipmentModal); dom.closeEquipmentModalBtn.addEventListener("click", closeEquipmentModal); dom.applyEquipmentUnitBtn.addEventListener("click", () => withStatus(applyBatchEquipmentUnit())); dom.clearEquipmentSelectionBtn.addEventListener("click", clearSelectedEquipments); dom.openPointModalBtn.addEventListener("click", openPointCreateModal); dom.pointSourceSelect.addEventListener("change", () => { dom.nodeTree.innerHTML = '
Click "Load Nodes" to fetch node tree
'; dom.pointSourceNodeCount.textContent = "Nodes: 0"; }); dom.browseNodesBtn.addEventListener("click", () => withStatus(browseAndLoadTree())); dom.refreshTreeBtn.addEventListener("click", () => withStatus(loadTree())); dom.createPointsBtn.addEventListener("click", () => withStatus(createPoints())); dom.closeModalBtn.addEventListener("click", () => dom.pointModal.classList.add("hidden")); dom.openSourceFormBtn.addEventListener("click", () => { dom.sourceForm.reset(); dom.sourceId.value = ""; dom.sourceModal.classList.remove("hidden"); }); dom.closeSourceModalBtn.addEventListener("click", () => dom.sourceModal.classList.add("hidden")); dom.clearPointBindingBtn.addEventListener("click", () => withStatus(clearPointBinding())); dom.closePointBindingModalBtn.addEventListener("click", () => { dom.pointBindingModal.classList.add("hidden"); }); dom.openBatchBindingBtn.addEventListener("click", openBatchBinding); dom.clearSelectedPointsBtn.addEventListener("click", clearSelectedPoints); dom.closeBatchBindingModalBtn.addEventListener("click", () => { dom.batchBindingModal.classList.add("hidden"); }); dom.clearBatchBindingBtn.addEventListener("click", () => withStatus(clearBatchBinding())); dom.toggleAllPoints.addEventListener("change", () => { const checked = dom.toggleAllPoints.checked; dom.pointList.querySelectorAll('input[data-point-select="true"]').forEach((input) => { input.checked = checked; input.dispatchEvent(new Event("change")); }); }); dom.openReadmeDocBtn.addEventListener("click", () => withStatus(openReadmeDrawer())); dom.openApiDocBtn.addEventListener("click", () => withStatus(openApiDocDrawer())); dom.closeApiDocBtn.addEventListener("click", closeApiDocDrawer); dom.refreshEventBtn.addEventListener("click", () => withStatus(loadEvents())); dom.refreshChartBtn.addEventListener("click", () => { if (!state.chartPointId) { return; } withStatus(openChart(state.chartPointId, state.chartPointName)); }); dom.prevPointsBtn.addEventListener("click", () => { if (state.pointsPage > 1) { state.pointsPage -= 1; withStatus(loadPoints()); } }); dom.nextPointsBtn.addEventListener("click", () => { const totalPages = Math.max(1, Math.ceil(state.pointsTotal / state.pointsPageSize)); if (state.pointsPage < totalPages) { state.pointsPage += 1; withStatus(loadPoints()); } }); dom.equipmentKeyword.addEventListener("keydown", (event) => { if (event.key === "Enter") { event.preventDefault(); withStatus(loadEquipments()); } }); dom.tabOps.addEventListener("click", () => switchView("ops")); dom.tabAppConfig.addEventListener("click", () => switchView("app-config")); dom.tabConfig.addEventListener("click", () => switchView("config")); dom.refreshUnitBtn2.addEventListener("click", () => withStatus(loadUnits().then(loadEvents))); dom.newUnitBtn2.addEventListener("click", openCreateUnitModal); bindUnitEquipmentModalEvents(); document.addEventListener("equipments-updated", () => { renderUnits(); // Re-fetch units so embedded equipment data stays in sync with config changes. loadUnits().catch(() => {}); }); document.addEventListener("units-loaded", () => { renderOpsUnits(); if (!state.selectedOpsUnitId) loadAllEquipmentCards(); }); } async function bootstrap() { bindEvents(); switchView("ops"); renderSelectedNodes(); updateSelectedPointSummary(); updatePointFilterSummary(); renderChart(); startPointSocket(); await withStatus(Promise.all([loadUnits(), loadEvents()])); startOps(); } bootstrap();