Skip to content

Multi-site: rack list building filter + re-enable /buildings/:id View racks (#274)#285

Merged
flesher merged 3 commits into
mainfrom
issue-274
May 22, 2026
Merged

Multi-site: rack list building filter + re-enable /buildings/:id View racks (#274)#285
flesher merged 3 commits into
mainfrom
issue-274

Conversation

@flesher
Copy link
Copy Markdown
Contributor

@flesher flesher commented May 21, 2026

Summary

Wires the ?building=<id> URL contract through the rack list and re-enables the View racks affordance on /buildings/:id (was disabled in #269 pending this work). Backend building_ids / include_no_building filter on ListDeviceSetsRequest already shipped in #229 / #198; this PR is the FE side.

Closes #274.

Changes

  • RacksPage.tsx — parses ?building=<id> from URL (accepts repeated-key + legacy comma-joined forms, matches filterUrlParams.ts), loads all buildings via listAllBuildings, registers a Building filter in FilterChipsBar with the building name. URL is the source of truth — back/forward navigation and chip removal stay in sync.
  • useDeviceSets.ts / useDeviceSetListState.ts — thread buildingIds through listRacksListDeviceSets.
  • BuildingPageHeader.tsx — replaces the disabled View racks button + tooltip with <Link to="/racks?building=…">. Mirrors the existing View miners URL contract.
  • MinerList.handleServerFilter (drive-by, fixes regression surfaced by this PR's deep-link) — also translates dropdownFilters.buildingMinerListFilter.buildingIds. Without this, the building filter was silently dropped on mount and the URL was rewritten without ?building=. savedViews.FILTER_AND_SORT_KEYS now includes "building" so building-scoped URLs canonicalize as filtered state (instead of "All miners").

Deferred

Test plan

  • On /buildings/:id, click View racks — lands on /racks?building=<id>.
  • Building chip on /racks renders the building name, removable like other filters; clearing the chip strips ?building= from the URL.
  • Back/forward navigation keeps the chip and list in sync with the URL.
  • On /buildings/:id, click View miners — lands on /miners?building=<id> and the URL stays intact (no on-mount strip).
  • just lint, tsc --noEmit, vitest run (full client suite), Go tests for internal/handlers/deviceset + internal/domain/collection all pass locally.

🤖 Generated with Claude Code

…d View racks (#274)

Wires the `?building=<id>` URL contract through the rack list and re-enables
the "View racks" link from `/buildings/:id`. Backend filter (building_ids /
include_no_building on ListDeviceSetsRequest) already shipped in #229; this
PR is the FE side.

- RacksPage: parses `?building=<id>` (repeated + legacy comma-joined),
  loads ListAllBuildings, registers a Building chip in FilterChipsBar
  with the building name, treats the URL as the source of truth so
  back/forward + chip removal stay in sync.
- useDeviceSets / useDeviceSetListState: thread buildingIds through
  listRacks → ListDeviceSets.
- BuildingPageHeader: re-enables the disabled "View racks" button,
  linking to /racks?building=<id> (mirrors the existing "View miners"
  contract).
- MinerList.handleServerFilter: also translates dropdownFilters.building
  → MinerListFilter.buildingIds (was silently dropped, stripping
  ?building= from the URL on initial mount). FILTER_AND_SORT_KEYS now
  includes "building" so the saved-views machinery canonicalizes
  building-scoped URLs as filtered state.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@flesher flesher requested a review from a team as a code owner May 21, 2026 16:08
Copilot AI review requested due to automatic review settings May 21, 2026 16:08
@github-actions github-actions Bot added javascript Pull requests that update javascript code client labels May 21, 2026
@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 21, 2026

🔐 Codex Security Review

Note: This is an automated security-focused code review generated by Codex.
It should be used as a supplementary check alongside human review.
False positives are possible - use your judgment.

Scope summary

  • Reviewed pull request diff only (2bf18b57c9765ca25a3634b67b225ee1b4b9e91d...1425dabcd852ff993458d9e8a48afe05d902cc58, exact PR three-dot diff)
  • Model: gpt-5.5

💡 Click "edited" above to see previous reviews for this PR.


Review Summary

Overall Risk: MEDIUM

Findings

[MEDIUM] Miner building filter is applied without a visible filter control

  • Category: Frontend
  • Location: client/src/protoFleet/features/fleetManagement/components/MinerList/MinerList.tsx:873
  • Description: The PR now converts filters.dropdownFilters.building into minerFilter.buildingIds, so /miners?building=<id> becomes an active server-side filter. However, the miner list filter definitions still do not include a building dropdown source, and the shared filter UI only renders chips for configured filter sources. The result is a filtered miner list with no visible Building chip/control.
  • Impact: Operators can land on a building-filtered miner list and see/export/act on a subset of miners without an obvious UI indication that the list is constrained.
  • Recommendation: Add a Building filter item to the miner list, backed by building options and labels, so URL-driven building filters render as normal chips and can be edited/cleared. Alternatively, defer applying buildingIds until the UI can expose the active filter.

Notes

No auth, SQL, command execution, plugin, infrastructure, protobuf wire-format, or mining pool/payout hijack issues were introduced in the reviewed diff. I did not run tests; this was a scoped diff review of .git/codex-review.diff.


Generated by Codex Security Review |
Triggered by: @flesher |
Review workflow run

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR wires the existing ?building=<id> URL filter contract into the racks list, re-enables the “View racks” navigation from /buildings/:id, and ensures the miner list preserves building-scoped deep links by translating the building dropdown filter into MinerListFilter.buildingIds.

Changes:

  • Add building-aware rack listing by parsing ?building= on /racks, loading building names for the filter chip, and passing buildingIds through to ListDeviceSets.
  • Re-enable /buildings/:id/racks?building=… navigation via a “View racks” link.
  • Fix miner list deep-link canonicalization by mapping dropdownFilters.buildingMinerListFilter.buildingIds and whitelisting building in saved-view URL canonicalization.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
client/src/protoFleet/hooks/useDeviceSetListState.ts Threads optional buildingIds into paginated rack listing requests.
client/src/protoFleet/features/rackManagement/pages/RacksPage.tsx Parses ?building= from URL, loads building options, and binds a Building filter chip to URL state.
client/src/protoFleet/features/fleetManagement/views/savedViews.ts Treats building as a canonical filter/sort key so deep links persist as filtered state.
client/src/protoFleet/features/fleetManagement/components/MinerList/MinerList.tsx Translates building dropdown selections into minerFilter.buildingIds.
client/src/protoFleet/features/buildings/components/BuildingPageHeader.tsx Re-enables “View racks” navigation using the building URL param.
client/src/protoFleet/api/useDeviceSets.ts Passes buildingIds through in listRacks requests to the backend.
Comments suppressed due to low confidence (1)

client/src/protoFleet/features/rackManagement/pages/RacksPage.tsx:242

  • handleClearFilters calls setBuildingFilter([]) and then immediately resetAndFetch(). Because the building filter is URL-driven and selectedBuildingIdsRef is updated in an effect, this first fetch can still run with the old buildingIds (and then the separate URL-change effect triggers another fetch). This can briefly show stale, still-building-filtered results and does an extra round-trip.

Consider making the clear-all path update the buildingIds ref synchronously (or set it to [] before fetching), or remove the direct resetAndFetch() here and instead have a single refetch effect that responds to all filter changes (building/zone/issues) so the fetch always uses the latest filter state once per change.

  const handleClearFilters = useCallback(() => {
    setSelectedZones([]);
    selectedZonesRef.current = [];
    setSelectedIssues([]);
    selectedIssuesRef.current = [];
    setBuildingFilter([]);
    resetAndFetch();
  }, [resetAndFetch, selectedIssuesRef, selectedZonesRef, setBuildingFilter]);

Comment thread client/src/protoFleet/features/rackManagement/pages/RacksPage.tsx Outdated
#225 added direct imports of otel/metric, otlpmetricgrpc, sdk/metric, and
proto/otlp under server/internal/infrastructure/metrics/ but committed
go.mod with those modules still in the // indirect block. `go mod tidy`
promotes them to direct and bumps docker/go-connections 0.6.0 → 0.7.0 as
a transitive resolution. Unrelated to #274; folded in here to unblock the
tree.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@github-actions github-actions Bot added dependencies Pull requests that update a dependency file server labels May 21, 2026
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: b10cdd3ca8

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread client/src/protoFleet/features/rackManagement/pages/RacksPage.tsx
Addresses three findings from PR #285 review:

1. RacksPage filter-empty state (Codex P2). `hasEverLoaded` only flips when
   `total > 0`, so deep-linking `/racks?building=<id>` where the building has
   zero racks (but the org has racks elsewhere) fell through to the
   "You haven't set up any racks" null state instead of the filtered-empty
   state. Including `hasActiveFilters` in the `hasRacks` check short-circuits
   the null state whenever a filter is active.

2. `handleClearFilters` double-fetch (Copilot suppressed). When the building
   filter was active, clearing all triggered one synchronous resetAndFetch
   with stale ref values plus a second via the URL-change effect. Snapshot
   the building-active state up front; skip the explicit resetAndFetch
   when the URL-change effect will handle the refetch.

3. No FE tests for the URL parse (me + Copilot). Extracted
   `parseBuildingIdsFromParams` + `BUILDING_URL_PARAM` to a new
   `rackManagement/utils/buildingFilterUrl.ts` module and added a vitest
   covering repeated keys, legacy comma-joined values, invalid input,
   ordering, and large bigint ids.

Follow-up issue #291 tracks the pre-existing `<Link><Button/></Link>`
nesting on BuildingPageHeader (PR review finding #2) — fixing both View
racks and View miners together rather than mixing scope into this PR.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@flesher
Copy link
Copy Markdown
Contributor Author

flesher commented May 21, 2026

Review polish — 1425dab

Addressed three of the four review findings; filed #291 for the fourth.

Finding Source Action
Wrong null state for empty-result building deep links Codex P2 (inline) Fixed. hasRacks now short-circuits on hasActiveFilters so the filtered-empty branch (chip + NoFilterResultsEmptyState) wins.
handleClearFilters double-fetches when building was active Copilot (suppressed) Fixed. Snapshot hadBuildingFilter up front; skip the explicit resetAndFetch when the URL-change effect will handle the refetch.
No FE tests for the URL parse Copilot (inline) + me Fixed. Extracted parseBuildingIdsFromParams + BUILDING_URL_PARAM to rackManagement/utils/buildingFilterUrl.ts and added 13 vitest cases covering repeated keys, legacy comma-joined, mixed forms, invalid input, ordering, large bigints.
<Link><Button/></Link> nests interactive elements Copilot (inline) Filed as #291. Pre-existing pattern on View miners; #285 added View racks with the same shape. Better to fix both instances + audit other call sites in one focused PR than mix scope here.

Deferred chip-name resolution for the miner-list still tracked on #202.

Local verification: just format, just lint, tsc --noEmit, vitest for the new util + adjacent suites all green.

Copy link
Copy Markdown
Contributor

@negarn negarn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks good! just wondering if you meant to include the server/ changes in this PR

@flesher
Copy link
Copy Markdown
Contributor Author

flesher commented May 22, 2026

ya i think that dependency tidying was missed in a previous PR so i just included it.

@flesher flesher merged commit aa721b4 into main May 22, 2026
71 checks passed
@flesher flesher deleted the issue-274 branch May 22, 2026 13:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

client dependencies Pull requests that update a dependency file javascript Pull requests that update javascript code server

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Multi-site — rack list building filter (re-enable View racks button from /buildings/:id)

3 participants