fix(dashboard): eliminate @apply CSS, fix status column, fix click propagation
Playwright testing revealed 3 critical bugs:
1. Tailwind CDN @apply with custom brand-* colors produces empty CSS
rules, breaking ALL design components (kpi-card, data-table, badges,
filter-btn, section-card, nav-item). Fix: replace all @apply
directives with equivalent raw CSS values.
2. Traffic API and IP detail API reference non-existent 'status' column
in http_logs table → HTTP 500 on /traffic and /ip/{ip}. Fix: remove
status from SELECT, sort whitelist, filters, and templates.
3. Nested <a> links (fmtJA4, fmtASN, fmtCountry, fmtBotName) inside
clickable <tr onclick> capture clicks, preventing row navigation to
/ip/ detail. Fix: add event.stopPropagation() to all formatter links.
Verified with Playwright: 10 pages × 0 JS errors, all tooltips hidden
by default, sidebar toggle works, keyboard shortcuts (Alt+1-9, Alt+B),
classification form saves to DB, campaign detail panel opens on click.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
@ -35,7 +35,7 @@ _SCORE_SORT_COLS = {
|
||||
"asn_org", "country_code", "browser_family",
|
||||
}
|
||||
_TRAFFIC_SORT_COLS = {
|
||||
"time", "src_ip", "method", "status", "host", "path", "http_version",
|
||||
"time", "src_ip", "method", "host", "path", "http_version",
|
||||
"header_user_agent", "ja4", "src_country_code",
|
||||
}
|
||||
_ORDER_VALUES = {"ASC", "DESC"}
|
||||
@ -315,7 +315,7 @@ async def traffic(
|
||||
method: str | None = Query(None),
|
||||
host: str | None = Query(None),
|
||||
http_version: str | None = Query(None),
|
||||
status: int | None = Query(None),
|
||||
status: int | None = Query(None, description="Not implemented — reserved"),
|
||||
search: str | None = Query(None),
|
||||
) -> dict[str, Any]:
|
||||
sort = _validate_sort(sort, _TRAFFIC_SORT_COLS, "time")
|
||||
@ -337,10 +337,6 @@ async def traffic(
|
||||
where_clauses.append("http_version = {http_version:String}")
|
||||
params["http_version"] = http_version
|
||||
|
||||
if status is not None:
|
||||
where_clauses.append("status = {status:UInt16}")
|
||||
params["status"] = status
|
||||
|
||||
if search:
|
||||
where_clauses.append(
|
||||
"(toString(src_ip) LIKE {search:String} "
|
||||
@ -358,7 +354,7 @@ async def traffic(
|
||||
)
|
||||
|
||||
rows = query(
|
||||
f"SELECT time, toString(src_ip) AS src_ip, method, status, host, path, "
|
||||
f"SELECT time, toString(src_ip) AS src_ip, method, host, path, "
|
||||
f"http_version, header_user_agent, ja4, src_country_code "
|
||||
f"FROM {_DB_LOGS}.http_logs "
|
||||
f"WHERE {where} ORDER BY {sort} {order} "
|
||||
@ -406,7 +402,7 @@ async def ip_detail(ip: str) -> dict[str, Any]:
|
||||
)
|
||||
|
||||
http_logs = query(
|
||||
f"SELECT time, method, status, host, path, http_version, header_user_agent, ja4 "
|
||||
f"SELECT time, method, host, path, http_version, header_user_agent, ja4 "
|
||||
f"FROM {_DB_LOGS}.http_logs "
|
||||
"WHERE src_ip = toIPv4OrZero({ip:String}) "
|
||||
"AND time >= now() - INTERVAL 1 DAY "
|
||||
|
||||
Reference in New Issue
Block a user