The page revamped: icon navigation, hints instead of prose, one Settings page, a weekly calendar, a PIN

- Top bar with icon navigation (Overview, Keys, Computers, Settings, Logs, History, Help); no side
  menu; every explanation moved into a hover hint; the [how] lines no longer shift the layout.
- One Settings page with sections: Playlist, Auto-fix (a paintable weekly calendar + which fixes),
  Changes wait (calendar), HyperDecks, MIDI links, Computers, Dante, Switcher, Companion (with the
  names check), Network, Site & PIN, Program & campus, Advanced (every field by screen).
- Fixes live under Keys as a tab; the jobs became sections or + buttons where they belong.
- Editing is switched on with a PIN (digits) plus a first name for History; the overview's
  status line became chips; 'Needs attention' instead of a person's name, and it no longer fires
  after a page-only Apply (page-only.json marker); last change comes from History.
- Deployed to NA Ingest; the campus PIN set there and in config.json.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
2026-10-14 17:42:03 -04:00
co-authored by Claude Fable 5.1
parent 9278e08acc
commit 69bb09ad27
5 changed files with 561 additions and 467 deletions
+8 -6
View File
@@ -196,7 +196,9 @@ class Site:
"level": "warn" if s.get("b") == 0xFFA000 else "err", "acked": s.get("b") == 0x8B0000, "since": None,
"action": "hold the %s key (%s)" % (tile["label"], hold) if hold and not hold.startswith("nothing")
else "no automatic fix: check the device"})
if started and started.get("config_sha") and started["config_sha"] != self.cfg_sha:
page_only = self.read_json("page-only.json", {}) or {} # the last Apply changed nothing the watchdog reads
if started and started.get("config_sha") and started["config_sha"] != self.cfg_sha \
and not (page_only.get("sha") == self.cfg_sha and page_only.get("watchdog_sha") == started["config_sha"]):
needs.append("The watchdog is running an older settings file than the one on disk (restart it to pick up the change).")
pages = self.pages_state()
if pages.get("status") and not pages["status"]["ok"]:
@@ -314,12 +316,12 @@ class Site:
return self.cached("pages", 60, look)
def last_change(self):
baks = sorted(glob.glob(os.path.join(self.data_dir, "config.json.bak-*")))
if not baks:
entries = applying.history_entries(self.data_dir)
if not entries:
return None
m = re.search(r"bak-(\d{8})-(\d{6})$", baks[-1])
return {"when": "%s-%s-%s %s:%s" % (m.group(1)[:4], m.group(1)[4:6], m.group(1)[6:], m.group(2)[:2], m.group(2)[2:4]) if m else None,
"by": "the installer", "note": "config.json replaced"}
e = entries[0]
return {"when": time.strftime("%Y-%m-%d %H:%M", time.localtime(e["when"])) if e.get("when") else None, "by": e.get("by"), "note": e.get("note"),
"outcome": e.get("outcome")}
def companion_view(self):
cfg = self.load()