import { state as appState } from "/assets/js/state.js"; import { $, esc } from "/assets/js/shared.js"; import { get, rows } from "/assets/js/navigation.js"; import { loadConfig } from "/assets/js/settings.js"; export function tokenHeaders() { return { "Content-Type": "application/json" }; } export async function loadServices() { if (!$("systemServices")) return; try { appState.serviceReadOnly = false; const d = await get( `/api/v1/services?host=${encodeURIComponent(appState.currentConfigHost)}`, ); appState.serviceCache = d.services; renderServiceLists(); } catch (e) { $("systemServices").innerHTML = `
${esc(e.message)}
`; } } export function renderServiceLists() { if (!$("systemServices")) return; const q = $("serviceSearch").value.trim().toLowerCase(), filtered = appState.serviceCache.filter( (s) => !q || `${s.unit} ${s.description} ${s.note}`.toLowerCase().includes(q), ); rows( "systemServices", filtered.map( (s) => `
${esc(s.unit)}
${esc(s.description || "暂无服务说明")} · ${esc(s.active === "active" ? "正在运行" : "未运行")}
${s.monitored ? (s.paused ? "已暂停" : "已监控") : "未监控"}
`, ), "没有匹配的服务", ); const monitored = appState.serviceCache.filter((s) => s.monitored); rows( "monitoredServices", monitored.map( (s) => `
${esc(s.monitor_name)} ${s.paused ? "监控已暂停" : s.active === "active" ? "运行中" : "服务已停止"}
${esc(s.unit)}
备注:${esc(s.note || "未填写")}
`, ), "尚未监控任何服务", ); if (appState.serviceReadOnly) document .querySelectorAll("#configRows button") .forEach((b) => (b.disabled = true)); document .querySelectorAll("[data-select-service]") .forEach((b) => (b.onclick = () => selectService(b.dataset.selectService))); document .querySelectorAll("[data-monitor-action]") .forEach( (b) => (b.onclick = () => monitorAction(b.dataset.unit, b.dataset.monitorAction)), ); document .querySelectorAll("[data-service-action]") .forEach( (b) => (b.onclick = () => serviceAction(b.dataset.unit, b.dataset.serviceAction)), ); document .querySelectorAll("[data-delete-monitor]") .forEach((b) => (b.onclick = () => deleteMonitor(b.dataset.deleteMonitor))); } export function selectService(unit) { const s = appState.serviceCache.find((x) => x.unit === unit); if (!s) return; appState.editingServiceName = s.monitor_name || ""; $("monitorTarget").value = s.unit; $("monitorName").value = s.monitor_name || s.unit .replace(/\.service$/, "") .replace(/[^A-Za-z0-9_.-]/g, "_") .slice(0, 16) .toUpperCase(); $("monitorNote").value = s.note || s.description || ""; $("serviceFormTitle").textContent = s.monitored ? "编辑服务监控" : "新建服务监控"; $("serviceMessage").textContent = "已自动填写,可继续修改。"; $("monitorName").scrollIntoView({ behavior: "smooth", block: "center" }); } export function resetMonitorForm() { appState.editingServiceName = ""; $("monitorName").value = ""; $("monitorTarget").value = ""; $("monitorNote").value = ""; $("serviceFormTitle").textContent = "新建服务监控"; $("serviceMessage").textContent = ""; $("serviceMessage").className = "muted"; } export async function saveMonitor() { const body = { host: appState.currentConfigHost, operation: "save", name: $("monitorName").value.trim(), target: $("monitorTarget").value.trim(), note: $("monitorNote").value.trim(), previous_name: appState.editingServiceName, }; try { $("serviceMessage").textContent = "正在保存…"; await get("/api/v1/services", { method: "PUT", headers: tokenHeaders(), body: JSON.stringify(body), }); resetMonitorForm(); await loadServices(); $("serviceMessage").textContent = "保存成功"; $("serviceMessage").className = "success"; } catch (e) { $("serviceMessage").textContent = e.message; $("serviceMessage").className = "error"; } } export async function deleteMonitor(unit) { const s = appState.serviceCache.find((x) => x.unit === unit); if ( !s || !confirm( appState.LANG === "zh" ? `确定删除 ${s.monitor_name} 的监控吗?\n不会删除或停止 ${unit}。` : `Remove monitoring for ${s.monitor_name}?\nThis will not remove or stop ${unit}.`, ) ) return; try { await get("/api/v1/services", { method: "PUT", headers: tokenHeaders(), body: JSON.stringify({ host: appState.currentConfigHost, operation: "delete", name: s.monitor_name, target: s.unit, note: "", }), }); await loadConfig(); document.querySelector('[data-config-section="services"]')?.click(); } catch (e) { alert(e.message); } } export async function monitorAction(unit, action) { const s = appState.serviceCache.find((x) => x.unit === unit); if (!s) return; try { await get("/api/v1/services", { method: "PUT", headers: tokenHeaders(), body: JSON.stringify({ host: appState.currentConfigHost, operation: action, name: s.monitor_name, target: s.unit, note: s.note || "", }), }); await loadServices(); } catch (e) { alert(e.message); } } export async function serviceAction(unit, action) { if ( !confirm( appState.LANG === "zh" ? `确定${action === "start" ? "启动服务" : "停止服务"} ${unit} 吗?\n这会直接执行 systemctl ${action}。` : `${action === "start" ? "Start" : "Stop"} ${unit}?\nThis runs systemctl ${action} directly.`, ) ) return; try { await get("/api/v1/services/control", { method: "PUT", headers: tokenHeaders(), body: JSON.stringify({ host: appState.currentConfigHost, unit, action }), }); setTimeout(loadServices, 700); } catch (e) { alert(e.message); } }