Step 1 in progress: the settings page server, probes, teaching pages and UI (not deployed yet)

- settings/server.py: read-only routes (overview, keys, computers, gear, companion, logs, history,
  help facts, key guide / cheat sheet / where things are), the editing-code check with a lockout,
  LAN-only binding with a per-minute rebind
- settings/probes.py: fixed read-only probes per computer; whole lists fetched and matched locally
- settings/keyguide.py: the generated teaching pages
- settings/ui: the page, every screen read-only
- status_panel.py: snapshot.json every 5 s for the page; the Companion database lookup prefers the
  running build's folder and skips a database that will not open (a stale v5.1 folder was breaking it)
- config.json: every computer's record (what runs there, network ports, done-by-hand ticks), the
  editing code (kept in the repo, the user's choice), an empty gear list
- install.sh: the settings page as a second LaunchAgent; settings/ and schema.py deployed

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
2026-10-13 16:23:59 -04:00
co-authored by Claude Fable 5.1
parent b05ff408d5
commit 2343a27529
11 changed files with 2266 additions and 19 deletions
+27
View File
@@ -380,6 +380,21 @@ class TestChecks(unittest.TestCase):
tiles, _ = run_steps(sp.Engine(CONFIG), self.snap, self.now, 4)
self.assertEqual(tiles["rf"]["x"], "RF\nPSM 3 NO PING")
def test_companion_db_path_skips_a_dead_newer_folder(self):
import sqlite3
root = tempfile.mkdtemp(prefix="sp-companion-")
for v in ("v5.0", "v5.1"):
os.makedirs(os.path.join(root, v))
good = os.path.join(root, "v5.0", "db.sqlite")
db = sqlite3.connect(good); db.execute("CREATE TABLE instances (id TEXT, value TEXT)"); db.commit(); db.close()
open(os.path.join(root, "v5.1", "db.sqlite"), "w").write("not a database") # an abandoned upgrade
from unittest import mock
real = os.path.expanduser
with mock.patch.object(sp.os.path, "expanduser", lambda p: root if "companion" in p else real(p)):
self.assertEqual(sp.companion_db_path({"companion": {"build": "5.0.7+9763"}}), good)
self.assertEqual(sp.companion_db_path({"companion": {}}), good) # newest that opens
self.assertEqual(sp.companion_db_path({"companion": {"db": "/x/y.sqlite"}}), "/x/y.sqlite")
def test_companion_conn_hosts_reads_its_database_read_only(self):
import sqlite3
d = tempfile.mkdtemp()
@@ -1489,6 +1504,18 @@ class TestFixes(unittest.TestCase):
with self.assertRaises(ValueError):
sp.load_config(path)
def test_snapshot_summary_is_plain_json(self):
snap = self.snap
snap.conns["ATEM"]["category"] = "error"
run_steps(self.engine, snap, SUNDAY, 5)
out = sp.snapshot_summary(snap, self.engine, SUNDAY + 5)
json.dumps(out) # nothing in it that JSON cannot hold
self.assertEqual(out["conns"]["ATEM"]["category"], "error")
self.assertEqual(out["faults"]["atem"][0]["msg"], "OFFLINE")
self.assertEqual(out["faults"]["atem"][0]["check"], "ATEM")
self.assertEqual(out["live"], [False, ""])
self.assertEqual(out["midi"]["NA Ingest"]["peers"][0]["name"], "Lighting PC")
def test_every_fix_is_valid(self):
for f in CONFIG["fixes"].values():
self.assertIn(f.get("kind", "ssh"), sp.FIX_KINDS)