Context
workers/request-handlers/entities.mjs (handleSubnetEvents, lines 2716-2780) already validates and applies ?kind= server-side against INGESTED_EVENT_KINDS, rejecting an unknown kind with a 400 before it forces a full index walk. But apps/ui/src/lib/metagraphed/queries.ts's subnetEventsQuery (line 2683) never forwards a kind param — it hardcodes `/api/v1/subnets/${netuid}/events?limit=100` — and the consumer, ActivityPanel/ActivityTableLoader in apps/ui/src/routes/subnets.$netuid.tsx (lines 459-545), renders the table with zero filter UI. The identical pattern already ships for accounts: AccountEventsSection in apps/ui/src/routes/accounts.$ss58.tsx (lines 624-793) wires a SelectFilter (from apps/ui/src/components/metagraphed/table-controls.tsx, lines 80-110) to a ?ev_kind= route search param and passes it through to accountEventsQuery.
Requirement
Add a ?kind= filter dropdown to the subnet on-chain-activity table (the "On-chain activity" section on /subnets/$netuid), mirroring the account page's kind-filter UX and wiring it through to the existing server-side ?kind= support in handleSubnetEvents.
Deliverable
apps/ui/src/routes/subnets.$netuid.tsx: extend the existing SearchParams type (line 73) and its validateSearch (line 80) with a new string field (e.g. ev_kind, matching the accounts page's naming so it stays consistent), following the same pattern as SearchParams.ev_kind in accounts.$ss58.tsx (line 51/64). Wire ActivityPanel/ActivityTableLoader (lines 459-545) to read that search param, pass { kind } through to subnetEventsQuery, and render a SelectFilter (already imported pattern from table-controls.tsx) in the section header, matching AccountEventsSection's right={<SelectFilter .../>} usage (accounts.$ss58.tsx line 672-681). Since subnets have no per-subnet event_kinds summary field to source dropdown options from (unlike AccountSummary.event_kinds used at accounts.$ss58.tsx line 629), source the option list from the existing shared EVENT_KIND_LABELS map in apps/ui/src/lib/metagraphed/event-kinds.ts (lines 46-72) instead — this keeps the same value/label shape ({ value, label }) the SelectFilter component expects.
apps/ui/src/lib/metagraphed/queries.ts: update subnetEventsQuery (line 2683) to accept an optional kind param and forward it as a query-string param on the /api/v1/subnets/{netuid}/events fetch, alongside the existing limit=100, matching how accountEventsQuery (line 2071) already forwards params.kind.
- "Done" looks like: selecting a kind in the new dropdown re-fetches
/api/v1/subnets/{netuid}/events?kind=<Kind>&limit=100 and re-renders the table filtered to that kind; clearing the selection (the SelectFilter's built-in "all" option) returns to the unfiltered feed; the selection round-trips through the URL (a shareable/reloadable link), same as ev_kind does today on /accounts/$ss58.
- No coordination needed with another open issue — the backend half (
?kind= validation/application in handleSubnetEvents) is already merged and live; this is a frontend-only PR.
Acceptance criteria
Non-goals
- Do not touch
workers/request-handlers/entities.mjs or any backend validation logic — ?kind= support is already implemented and live server-side.
- Do not add offset/cursor pagination to the subnet activity table in this PR — that's a separate scope from the account page's
AccountEventsSection (which already has pagination); this issue is only about the kind filter.
- Do not modify the accounts page (
apps/ui/src/routes/accounts.$ss58.tsx) — it's the reference pattern being copied, not something to change here.
Size
Size: S — keep this PR small (aim for ≤10 files / ≤1000 LOC).
Part of #2542.
Context
workers/request-handlers/entities.mjs(handleSubnetEvents, lines 2716-2780) already validates and applies?kind=server-side againstINGESTED_EVENT_KINDS, rejecting an unknown kind with a 400 before it forces a full index walk. Butapps/ui/src/lib/metagraphed/queries.ts'ssubnetEventsQuery(line 2683) never forwards akindparam — it hardcodes`/api/v1/subnets/${netuid}/events?limit=100`— and the consumer,ActivityPanel/ActivityTableLoaderinapps/ui/src/routes/subnets.$netuid.tsx(lines 459-545), renders the table with zero filter UI. The identical pattern already ships for accounts:AccountEventsSectioninapps/ui/src/routes/accounts.$ss58.tsx(lines 624-793) wires aSelectFilter(fromapps/ui/src/components/metagraphed/table-controls.tsx, lines 80-110) to a?ev_kind=route search param and passes it through toaccountEventsQuery.Requirement
Add a
?kind=filter dropdown to the subnet on-chain-activity table (the "On-chain activity" section on/subnets/$netuid), mirroring the account page's kind-filter UX and wiring it through to the existing server-side?kind=support inhandleSubnetEvents.Deliverable
apps/ui/src/routes/subnets.$netuid.tsx: extend the existingSearchParamstype (line 73) and itsvalidateSearch(line 80) with a new string field (e.g.ev_kind, matching the accounts page's naming so it stays consistent), following the same pattern asSearchParams.ev_kindinaccounts.$ss58.tsx(line 51/64). WireActivityPanel/ActivityTableLoader(lines 459-545) to read that search param, pass{ kind }through tosubnetEventsQuery, and render aSelectFilter(already imported pattern fromtable-controls.tsx) in the section header, matchingAccountEventsSection'sright={<SelectFilter .../>}usage (accounts.$ss58.tsx line 672-681). Since subnets have no per-subnetevent_kindssummary field to source dropdown options from (unlikeAccountSummary.event_kindsused at accounts.$ss58.tsx line 629), source the option list from the existing sharedEVENT_KIND_LABELSmap inapps/ui/src/lib/metagraphed/event-kinds.ts(lines 46-72) instead — this keeps the same value/label shape ({ value, label }) theSelectFiltercomponent expects.apps/ui/src/lib/metagraphed/queries.ts: updatesubnetEventsQuery(line 2683) to accept an optionalkindparam and forward it as a query-string param on the/api/v1/subnets/{netuid}/eventsfetch, alongside the existinglimit=100, matching howaccountEventsQuery(line 2071) already forwardsparams.kind./api/v1/subnets/{netuid}/events?kind=<Kind>&limit=100and re-renders the table filtered to that kind; clearing the selection (theSelectFilter's built-in "all" option) returns to the unfiltered feed; the selection round-trips through the URL (a shareable/reloadable link), same asev_kinddoes today on/accounts/$ss58.?kind=validation/application inhandleSubnetEvents) is already merged and live; this is a frontend-only PR.Acceptance criteria
apps/ui/src/routes/subnets.$netuid.tsxandapps/ui/src/lib/metagraphed/queries.tsboth appear in the diffsubnetEventsQueryaccepts and forwards an optionalkindparameter to/api/v1/subnets/{netuid}/events/subnets/$netuidrenders aSelectFilterkind dropdown (usingEVENT_KIND_LABELSfromevent-kinds.tsas the option source) that is absent today?ev_kind=StakeAdded) and the fetched/rendered events are filtered to that kindhandleSubnetEventsinworkers/request-handlers/entities.mjsalready supports?kind=and needs no changesapps/uivisual change per the metagraphed contributor rules)Non-goals
workers/request-handlers/entities.mjsor any backend validation logic —?kind=support is already implemented and live server-side.AccountEventsSection(which already has pagination); this issue is only about the kind filter.apps/ui/src/routes/accounts.$ss58.tsx) — it's the reference pattern being copied, not something to change here.Size
Size: S — keep this PR small (aim for ≤10 files / ≤1000 LOC).
Part of #2542.