Heatmap drill-down to Journal, layout fixes, healthy-plant sim mode (B grade)
Heatmap -> Journal drill-down (PrimeBAT only): - clicking an Activations-by-hour/day cell jumps to the Journal filtered to that recurring day-of-week + hour (new query.filterDow/filterHour session props; same local-time bucketing as calc.heatmap) - Journal shows a "Time filter: Thu 12:00-12:59" chip with an X to clear; filter composes with existing filters and is included in CSV export - getJournalPage clamps out-of-range pages when a filter shrinks the set Layout: - filter bar moved below the tab strip so the tabs no longer shift when the bar hides on Overview (tab bar y verified pixel-stable across tabs) - popup titles (AlarmDetail/EventDetail) auto-shrink their font to fit long source paths on one line without colliding with the state/priority chips Alarm health -> B (score ~88): - alarmsim gains a MODE flag: "healthy" (default) generates ~12 activations/hr with an 80/15/5 priority mix and no chatter/standing/fleeting/floods; "chaos" restores the original stress profile - SimHarness gains a SimReset one-shot timer (disabled) that clears all sim tags; probe P3 reports health-grade ground truth for the 8h window - Dashboard onStartup now re-anchors relative range presets (4h/8h/24h/7d) to now on session start - fixes stale Designer-baked startMs/endMs pinning every new session to an old window Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -188,7 +188,8 @@ def _fetch_shelved():
|
||||
|
||||
|
||||
def _clean_filters(options):
|
||||
f = {"priorities": [], "areas": [], "states": [], "search": ""}
|
||||
f = {"priorities": [], "areas": [], "states": [], "search": "",
|
||||
"dow": -1, "hour": -1}
|
||||
if not options:
|
||||
return f
|
||||
try:
|
||||
@@ -202,6 +203,12 @@ def _clean_filters(options):
|
||||
f["search"] = str(options.get("search") or "")
|
||||
except:
|
||||
pass
|
||||
# Journal-only heatmap drill-down: day-of-week (0=Mon) + hour, -1 = off.
|
||||
for k in ("dow", "hour"):
|
||||
try:
|
||||
f[k] = int(options.get(k) if options.get(k) is not None else -1)
|
||||
except:
|
||||
f[k] = -1
|
||||
return f
|
||||
|
||||
|
||||
@@ -254,9 +261,23 @@ def _journal_rows(start_ms, end_ms, filters, max_rows):
|
||||
areas = set(filters.get("areas") or [])
|
||||
states = set(filters.get("states") or [])
|
||||
search = (filters.get("search") or "").strip().lower()
|
||||
dow = filters.get("dow", -1)
|
||||
hour = filters.get("hour", -1)
|
||||
if dow >= 0 or hour >= 0:
|
||||
import time
|
||||
for r in rows:
|
||||
if r["is_system"]:
|
||||
continue
|
||||
# same local-time bucketing as calc.heatmap (tm_wday 0=Mon, tm_hour)
|
||||
if dow >= 0 or hour >= 0:
|
||||
try:
|
||||
lt = time.localtime(r["ts"] / 1000.0)
|
||||
if dow >= 0 and lt.tm_wday != dow:
|
||||
continue
|
||||
if hour >= 0 and lt.tm_hour != hour:
|
||||
continue
|
||||
except:
|
||||
continue
|
||||
parsed = calc.parse_source(r["source"], r["display_path"])
|
||||
if prios and r["priority"] not in prios:
|
||||
continue
|
||||
@@ -286,6 +307,9 @@ def getJournalPage(startMs, endMs, filters=None, page=0, pageSize=50):
|
||||
int(calc.DEFAULTS["max_events"]))
|
||||
page = max(0, int(page or 0))
|
||||
page_size = max(1, int(pageSize or 50))
|
||||
last_page = max(0, (len(rows) - 1) // page_size)
|
||||
if page > last_page:
|
||||
page = last_page
|
||||
start = page * page_size
|
||||
return {"rows": rows[start:start + page_size], "total": len(rows),
|
||||
"page": page, "page_size": page_size, "truncated": truncated,
|
||||
|
||||
Reference in New Issue
Block a user