Add hub auto-launch: XDG autostart, API endpoints, and frontend toggle
Agent-Logs-Url: https://github.com/naturallaw777/staging_alpha/sessions/0b0d70c0-01d1-49d1-b9ca-8d4f8e5af64a Co-authored-by: naturallaw777 <99053422+naturallaw777@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
parent
27502c6997
commit
13e3b76c88
@@ -57,6 +57,7 @@ ZEUS_CONNECT_FILE = "/var/lib/secrets/zeus-connect-url"
|
|||||||
REBOOT_COMMAND = ["reboot"]
|
REBOOT_COMMAND = ["reboot"]
|
||||||
|
|
||||||
ONBOARDING_FLAG = "/var/lib/sovran/onboarding-complete"
|
ONBOARDING_FLAG = "/var/lib/sovran/onboarding-complete"
|
||||||
|
AUTOLAUNCH_DISABLE_FLAG = "/var/lib/sovran/hub-autolaunch-disabled"
|
||||||
|
|
||||||
# ── Tech Support constants ────────────────────────────────────────
|
# ── Tech Support constants ────────────────────────────────────────
|
||||||
|
|
||||||
@@ -1390,6 +1391,39 @@ async def api_onboarding_complete():
|
|||||||
return {"ok": True}
|
return {"ok": True}
|
||||||
|
|
||||||
|
|
||||||
|
# ── Auto-launch endpoints ─────────────────────────────────────────
|
||||||
|
|
||||||
|
@app.get("/api/autolaunch/status")
|
||||||
|
async def api_autolaunch_status():
|
||||||
|
"""Check if Hub auto-launch on login is enabled."""
|
||||||
|
disabled = os.path.exists(AUTOLAUNCH_DISABLE_FLAG)
|
||||||
|
return {"enabled": not disabled}
|
||||||
|
|
||||||
|
|
||||||
|
class AutolaunchToggleRequest(BaseModel):
|
||||||
|
enabled: bool
|
||||||
|
|
||||||
|
|
||||||
|
@app.post("/api/autolaunch/toggle")
|
||||||
|
async def api_autolaunch_toggle(req: AutolaunchToggleRequest):
|
||||||
|
"""Enable or disable Hub auto-launch on login."""
|
||||||
|
if req.enabled:
|
||||||
|
# Remove the disable flag to enable auto-launch
|
||||||
|
try:
|
||||||
|
os.remove(AUTOLAUNCH_DISABLE_FLAG)
|
||||||
|
except FileNotFoundError:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
# Create the disable flag to suppress auto-launch
|
||||||
|
os.makedirs(os.path.dirname(AUTOLAUNCH_DISABLE_FLAG), exist_ok=True)
|
||||||
|
try:
|
||||||
|
with open(AUTOLAUNCH_DISABLE_FLAG, "w") as f:
|
||||||
|
f.write("")
|
||||||
|
except OSError as exc:
|
||||||
|
raise HTTPException(status_code=500, detail=f"Could not write flag file: {exc}")
|
||||||
|
return {"ok": True, "enabled": req.enabled}
|
||||||
|
|
||||||
|
|
||||||
@app.get("/api/config")
|
@app.get("/api/config")
|
||||||
async def api_config():
|
async def api_config():
|
||||||
cfg = load_config()
|
cfg = load_config()
|
||||||
|
|||||||
@@ -105,12 +105,14 @@ async function init() {
|
|||||||
if (cfg.feature_manager) {
|
if (cfg.feature_manager) {
|
||||||
loadFeatureManager();
|
loadFeatureManager();
|
||||||
}
|
}
|
||||||
|
loadAutolaunchToggle();
|
||||||
} catch (_) {
|
} catch (_) {
|
||||||
await refreshServices();
|
await refreshServices();
|
||||||
loadNetwork();
|
loadNetwork();
|
||||||
checkUpdates();
|
checkUpdates();
|
||||||
setInterval(refreshServices, POLL_INTERVAL_SERVICES);
|
setInterval(refreshServices, POLL_INTERVAL_SERVICES);
|
||||||
setInterval(checkUpdates, POLL_INTERVAL_UPDATES);
|
setInterval(checkUpdates, POLL_INTERVAL_UPDATES);
|
||||||
|
loadAutolaunchToggle();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -579,3 +579,66 @@ function buildFeatureCard(feat) {
|
|||||||
|
|
||||||
return card;
|
return card;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ── Auto-launch toggle ────────────────────────────────────────────
|
||||||
|
|
||||||
|
async function loadAutolaunchToggle() {
|
||||||
|
try {
|
||||||
|
var data = await apiFetch("/api/autolaunch/status");
|
||||||
|
renderAutolaunchToggle(data.enabled);
|
||||||
|
} catch (err) {
|
||||||
|
console.warn("Failed to load autolaunch status:", err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderAutolaunchToggle(enabled) {
|
||||||
|
// Remove existing section if any
|
||||||
|
var old = $sidebarFeatures.querySelector(".autolaunch-section");
|
||||||
|
if (old) old.parentNode.removeChild(old);
|
||||||
|
|
||||||
|
var section = document.createElement("div");
|
||||||
|
section.className = "category-section autolaunch-section";
|
||||||
|
|
||||||
|
section.innerHTML =
|
||||||
|
'<div class="section-header">Preferences</div>' +
|
||||||
|
'<hr class="section-divider" />' +
|
||||||
|
'<div class="feature-card">' +
|
||||||
|
'<div class="feature-card-top">' +
|
||||||
|
'<div class="feature-card-info">' +
|
||||||
|
'<div class="feature-card-name">Auto-launch Hub on Login</div>' +
|
||||||
|
'<div class="feature-card-desc">Automatically open the Sovran Hub dashboard in your browser when you log in to the desktop.</div>' +
|
||||||
|
'</div>' +
|
||||||
|
'<label class="feature-toggle' + (enabled ? " active" : "") + '" id="autolaunch-toggle-label" title="Toggle auto-launch">' +
|
||||||
|
'<input type="checkbox" class="feature-toggle-input" id="autolaunch-toggle-input"' + (enabled ? " checked" : "") + ' />' +
|
||||||
|
'<span class="feature-toggle-slider"></span>' +
|
||||||
|
'</label>' +
|
||||||
|
'</div>' +
|
||||||
|
'</div>';
|
||||||
|
|
||||||
|
$sidebarFeatures.appendChild(section);
|
||||||
|
|
||||||
|
var input = document.getElementById("autolaunch-toggle-input");
|
||||||
|
var label = document.getElementById("autolaunch-toggle-label");
|
||||||
|
if (!input || !label) return;
|
||||||
|
|
||||||
|
input.addEventListener("change", async function() {
|
||||||
|
var newEnabled = input.checked;
|
||||||
|
// Revert visually until confirmed
|
||||||
|
input.checked = !newEnabled;
|
||||||
|
if (newEnabled) { label.classList.remove("active"); } else { label.classList.add("active"); }
|
||||||
|
input.disabled = true;
|
||||||
|
try {
|
||||||
|
await apiFetch("/api/autolaunch/toggle", {
|
||||||
|
method: "POST",
|
||||||
|
headers: { "Content-Type": "application/json" },
|
||||||
|
body: JSON.stringify({ enabled: newEnabled }),
|
||||||
|
});
|
||||||
|
input.checked = newEnabled;
|
||||||
|
if (newEnabled) { label.classList.add("active"); } else { label.classList.remove("active"); }
|
||||||
|
} catch (err) {
|
||||||
|
alert("Failed to update auto-launch setting. Please try again.");
|
||||||
|
} finally {
|
||||||
|
input.disabled = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|||||||
@@ -203,6 +203,30 @@ let
|
|||||||
fi
|
fi
|
||||||
'';
|
'';
|
||||||
|
|
||||||
|
# ── Hub auto-launch wrapper script ────────────────────────────────
|
||||||
|
hub-autolaunch-script = pkgs.writeShellScript "sovran-hub-autolaunch.sh" ''
|
||||||
|
export PATH="${lib.makeBinPath [ pkgs.curl pkgs.xdg-utils ]}:$PATH"
|
||||||
|
|
||||||
|
DISABLE_FLAG="/var/lib/sovran/hub-autolaunch-disabled"
|
||||||
|
BOOT_FLAG="/run/sovran-hub-autolaunch-done"
|
||||||
|
|
||||||
|
# User disabled auto-launch via Hub toggle
|
||||||
|
[ -f "$DISABLE_FLAG" ] && exit 0
|
||||||
|
|
||||||
|
# Already launched this boot
|
||||||
|
[ -f "$BOOT_FLAG" ] && exit 0
|
||||||
|
|
||||||
|
touch "$BOOT_FLAG"
|
||||||
|
|
||||||
|
# Wait for Hub server to become ready (max ~15 seconds)
|
||||||
|
for i in $(seq 1 15); do
|
||||||
|
curl -s -o /dev/null -w "" http://localhost:8937 && break
|
||||||
|
sleep 1
|
||||||
|
done
|
||||||
|
|
||||||
|
xdg-open http://localhost:8937
|
||||||
|
'';
|
||||||
|
|
||||||
sovran-hub-web = pkgs.python3Packages.buildPythonApplication {
|
sovran-hub-web = pkgs.python3Packages.buildPythonApplication {
|
||||||
pname = "sovran-systemsos-hub-web";
|
pname = "sovran-systemsos-hub-web";
|
||||||
version = "1.0.0";
|
version = "1.0.0";
|
||||||
@@ -313,5 +337,16 @@ in
|
|||||||
|
|
||||||
networking.firewall.allowedTCPPorts = [ 3051 8937 60847 ];
|
networking.firewall.allowedTCPPorts = [ 3051 8937 60847 ];
|
||||||
|
|
||||||
|
# ── Auto-launch Hub in browser on login ───────────────────────
|
||||||
|
environment.etc."xdg/autostart/sovran-hub-autolaunch.desktop".text = ''
|
||||||
|
[Desktop Entry]
|
||||||
|
Type=Application
|
||||||
|
Name=Sovran Hub Auto-Launch
|
||||||
|
Exec=${hub-autolaunch-script}
|
||||||
|
Terminal=false
|
||||||
|
X-GNOME-Autostart-enabled=true
|
||||||
|
NoDisplay=true
|
||||||
|
'';
|
||||||
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user