feat: server-side reason/origin/limit filters + client-side row filter
All checks were successful
Deploy / deploy (push) Successful in 17s
All checks were successful
Deploy / deploy (push) Successful in 17s
Two new performance + UX wins: - Server: /decisions now accepts reason (scenarios_containing), origin (origins), and limit. Default 200, max 2000. Header shows current count and warns when at the cap. - Client: a "quick filter rows" input does substring match across all visible columns instantly with no server round-trip. Useful when the server-side result is small enough to scroll but you still want to find one scenario fast. - Bulk select-all now toggles only currently visible rows so you can filter then bulk-unban. Drops inline onclick handlers in favor of delegated change listeners to keep per-row cost low at large limits. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
32
app/app.py
32
app/app.py
@@ -87,19 +87,35 @@ def index():
|
||||
return render_template("index.html", my_ip=caller_ip())
|
||||
|
||||
|
||||
DEFAULT_LIMIT = 200
|
||||
MAX_LIMIT = 2000
|
||||
|
||||
|
||||
@app.get("/decisions")
|
||||
def list_decisions():
|
||||
q = request.args.get("ip", "").strip()
|
||||
params = {}
|
||||
if q:
|
||||
if not valid_ip(q):
|
||||
return render_template("_decisions.html", error="invalid IP", decisions=[]), 400
|
||||
params["ip"] = q
|
||||
ip = request.args.get("ip", "").strip()
|
||||
reason = request.args.get("reason", "").strip()
|
||||
origin = request.args.get("origin", "").strip()
|
||||
try:
|
||||
limit = max(1, min(MAX_LIMIT, int(request.args.get("limit", DEFAULT_LIMIT))))
|
||||
except ValueError:
|
||||
limit = DEFAULT_LIMIT
|
||||
|
||||
params = {"limit": limit}
|
||||
if ip:
|
||||
if not valid_ip(ip):
|
||||
return render_template("_decisions.html", error="invalid IP", decisions=[], total=0, limit=limit), 400
|
||||
params["ip"] = ip
|
||||
if reason:
|
||||
params["scenarios_containing"] = reason
|
||||
if origin:
|
||||
params["origins"] = origin
|
||||
|
||||
r = _bouncer("GET", "/v1/decisions", params=params)
|
||||
if r.status_code != 200:
|
||||
return render_template("_decisions.html", error=f"LAPI {r.status_code}: {r.text[:200]}", decisions=[]), 502
|
||||
return render_template("_decisions.html", error=f"LAPI {r.status_code}: {r.text[:200]}", decisions=[], total=0, limit=limit), 502
|
||||
decisions = r.json() or []
|
||||
return render_template("_decisions.html", decisions=decisions, error=None)
|
||||
return render_template("_decisions.html", decisions=decisions, error=None, total=len(decisions), limit=limit)
|
||||
|
||||
|
||||
@app.post("/unban")
|
||||
|
||||
Reference in New Issue
Block a user