Add service restart API and modal restart action
Agent-Logs-Url: https://github.com/naturallaw777/staging_alpha/sessions/8e6c98f7-8b24-4ec0-944b-0310e0989495 Co-authored-by: naturallaw777 <99053422+naturallaw777@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
parent
8fd08057d8
commit
fce4608647
@@ -2963,6 +2963,35 @@ async def api_ping():
|
|||||||
return {"ok": True}
|
return {"ok": True}
|
||||||
|
|
||||||
|
|
||||||
|
@app.post("/api/service/{unit}/restart")
|
||||||
|
async def api_service_restart(unit: str):
|
||||||
|
cfg = load_config()
|
||||||
|
services = cfg.get("services", [])
|
||||||
|
allowed_units = {
|
||||||
|
str(s.get("unit", "")).strip()
|
||||||
|
for s in services
|
||||||
|
if s.get("unit")
|
||||||
|
}
|
||||||
|
if unit not in allowed_units:
|
||||||
|
raise HTTPException(status_code=404, detail="Service not found")
|
||||||
|
|
||||||
|
try:
|
||||||
|
proc = await asyncio.create_subprocess_exec(
|
||||||
|
"systemctl", "restart", unit,
|
||||||
|
stdout=asyncio.subprocess.PIPE,
|
||||||
|
stderr=asyncio.subprocess.PIPE,
|
||||||
|
)
|
||||||
|
_, stderr = await proc.communicate()
|
||||||
|
except Exception as exc:
|
||||||
|
raise HTTPException(status_code=500, detail=f"Failed to restart service: {exc}")
|
||||||
|
|
||||||
|
if proc.returncode != 0:
|
||||||
|
detail = stderr.decode(errors="ignore").strip() or "systemctl restart failed"
|
||||||
|
raise HTTPException(status_code=500, detail=detail)
|
||||||
|
|
||||||
|
return {"ok": True}
|
||||||
|
|
||||||
|
|
||||||
@app.post("/api/reboot")
|
@app.post("/api/reboot")
|
||||||
async def api_reboot():
|
async def api_reboot():
|
||||||
try:
|
try:
|
||||||
|
|||||||
@@ -353,6 +353,47 @@
|
|||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.btn-warning {
|
||||||
|
background-color: #d97706;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-warning:hover:not(:disabled) {
|
||||||
|
background-color: #b45309;
|
||||||
|
}
|
||||||
|
|
||||||
|
.svc-detail-restart-section {
|
||||||
|
border-top: 1px solid var(--border-color);
|
||||||
|
padding-top: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.svc-detail-restart-btn {
|
||||||
|
margin-top: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.svc-detail-restart-result {
|
||||||
|
margin-top: 12px;
|
||||||
|
padding: 12px 16px;
|
||||||
|
border-radius: 8px;
|
||||||
|
font-size: 0.88rem;
|
||||||
|
line-height: 1.5;
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.svc-detail-restart-result.success {
|
||||||
|
background-color: rgba(109, 191, 139, 0.12);
|
||||||
|
border: 1px solid var(--green);
|
||||||
|
color: var(--green);
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.svc-detail-restart-result.error {
|
||||||
|
background-color: rgba(239, 68, 68, 0.12);
|
||||||
|
border: 1px solid #ef4444;
|
||||||
|
color: #f87171;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* ── Desktop launch buttons ──────────────────────────────────────── */
|
/* ── Desktop launch buttons ──────────────────────────────────────── */
|
||||||
|
|
||||||
|
|||||||
@@ -270,6 +270,15 @@ async function openServiceDetailModal(unit, name, icon) {
|
|||||||
'</div>';
|
'</div>';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (effectiveEnabled || data.enabled) {
|
||||||
|
html += '<div class="svc-detail-section svc-detail-restart-section">' +
|
||||||
|
'<div class="svc-detail-section-title">Troubleshooting</div>' +
|
||||||
|
'<p class="svc-detail-desc">If you\'re experiencing issues with this service, try restarting it.</p>' +
|
||||||
|
'<button class="btn btn-warning svc-detail-restart-btn" id="svc-detail-restart-btn">🔄 Restart Service</button>' +
|
||||||
|
'<div class="svc-detail-restart-result" id="svc-detail-restart-result"></div>' +
|
||||||
|
'</div>';
|
||||||
|
}
|
||||||
|
|
||||||
$credsBody.innerHTML = html;
|
$credsBody.innerHTML = html;
|
||||||
_attachCopyHandlers($credsBody);
|
_attachCopyHandlers($credsBody);
|
||||||
|
|
||||||
@@ -296,6 +305,33 @@ async function openServiceDetailModal(unit, name, icon) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var restartBtn = document.getElementById("svc-detail-restart-btn");
|
||||||
|
var restartResult = document.getElementById("svc-detail-restart-result");
|
||||||
|
if (restartBtn && restartResult) {
|
||||||
|
restartBtn.addEventListener("click", async function() {
|
||||||
|
restartBtn.disabled = true;
|
||||||
|
restartBtn.textContent = "Restarting…";
|
||||||
|
restartResult.className = "svc-detail-restart-result";
|
||||||
|
restartResult.textContent = "";
|
||||||
|
|
||||||
|
try {
|
||||||
|
await apiFetch("/api/service/" + encodeURIComponent(unit) + "/restart", { method: "POST" });
|
||||||
|
restartResult.classList.add("success");
|
||||||
|
restartResult.textContent = "✅ Service restarted successfully.";
|
||||||
|
restartBtn.disabled = false;
|
||||||
|
restartBtn.textContent = "🔄 Restart Service";
|
||||||
|
setTimeout(function() {
|
||||||
|
openServiceDetailModal(unit, name, icon);
|
||||||
|
}, 3000);
|
||||||
|
} catch (e) {
|
||||||
|
restartResult.classList.add("error");
|
||||||
|
restartResult.textContent = e && e.message ? e.message : "Failed to restart service.";
|
||||||
|
restartBtn.disabled = false;
|
||||||
|
restartBtn.textContent = "🔄 Restart Service";
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// Configure / Reconfigure Domain buttons (for non-feature services that need a domain)
|
// Configure / Reconfigure Domain buttons (for non-feature services that need a domain)
|
||||||
var configDomainBtn = document.getElementById("svc-detail-config-domain-btn");
|
var configDomainBtn = document.getElementById("svc-detail-config-domain-btn");
|
||||||
var reconfigDomainBtn = document.getElementById("svc-detail-reconfig-domain-btn");
|
var reconfigDomainBtn = document.getElementById("svc-detail-reconfig-domain-btn");
|
||||||
|
|||||||
Reference in New Issue
Block a user