feat(hosts): host card scan link + working Group/Filters + server-persisted view preference#611
Merged
Merged
Conversation
Backend (api-hosts v1.6.0 C-13/AC-24): GET /hosts items now carry a
nullable latest_scan_id = the newest COMPLETED scan_run id per host,
loaded with one DISTINCT ON query (no N+1). Queued/running-only and
never-scanned hosts resolve to null.
Frontend (frontend-hosts-list v1.7.0 C-09/AC-22): the previously-inert
chart icon on each host card + table row is now a ViewReportButton that
links to /scans/{latestScanId}. Hidden when the host has no completed
scan or the viewer lacks scan:read (the destination is scan:read-gated).
frontend-hosts-list v1.7.0 C-10/C-11, AC-23/AC-24. Group: drop the inert 'Team' option (no backing host field) and actually partition the list — groupHosts() sections by monitoring band (worst-first) or OS (alphabetical, Unknown last) with labelled GroupHeaders; None stays flat. Filters: the dead Filters button becomes a real popover (FiltersControl) with multi-select Status / Compliance-tier / OS facets, persisted to the URL (status/os/tier params) and applied client-side via applyHostFilters (AND across dimensions, OR within). Active-filter count on the button + Clear all. Logic lives in pure, unit-tested host-filtering.ts.
…iew (Part C) system-user-preferences v1.0.0 (new spec, 111 total). Backend: migration 0040 adds users.preferences JSONB; internal/userpref service (Get + shallow JSONB-|| Merge, scoped to one active user); GET/PATCH /api/v1/users/me/preferences — self-scoped (user id from identity, 401 for anonymous, no RBAC perm), unknown keys dropped via the typed contract, invalid enums rejected 400. Wired pool-only in newHandlers (never 503). Frontend: usePreferencesStore now hydrates from + writes through to the server (PATCH on each setter, hydrateFromServer on AppFrame mount), keeping the ow-preferences localStorage cache for instant load + offline. The /hosts view toggle resolves URL ?view= first, else the persisted hostsViewDefault, and toggling persists the per-user default — so a chosen view 'becomes the default until changed' and follows the user across devices. Specs: frontend-settings C-06/AC-30 (store now server-synced), frontend-hosts-list C-12/AC-25 (view default). New error codes validation.invalid_body / validation.invalid_value.
…-embed) The embed copy is gitignored and was only refreshed by make build / make vet's file prereq, so editing api/openapi.yaml + running 'make generate-api' (the natural 'I changed the contract' command) left it stale — a bare 'go test ./internal/server/' then failed TestOpenAPIDocs_EmbeddedMatchesSource. Close the gap at the regeneration point: generate-api now depends on the embed target (re-copies when openapi.yaml is newer), and a //go:generate directive lets 'go generate ./...' refresh it via standard tooling. The drift test remains the backstop.
remyluslosius
added a commit
that referenced
this pull request
Jun 20, 2026
- SESSION_LOG.md: 2026-06-20 entry for the /hosts page fixes (chart-icon scan link, working Group/Filters, server-side per-user view preference, embed-staleness build fix), with next-steps + gotchas. - BACKLOG.md: note the page fixes shipped; record the pending P3 browser verification of the chart icon (blocked on the Chrome extension); cross- reference the new userpref service as the home for per-user alert prefs.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Addresses three asks on the Host Management page (
/hosts), eachspec-driven (spec -> tests -> code) and committed as its own stacked commit.
A — Host card chart icon links to the latest scan report
The previously-inert
BarChart3icon on each host card + table row is now aViewReportButtonlinking to/scans/{latest_scan_id}. Backend adds anullable
latest_scan_idto the/hostslist item (newest completedscan_runper host, oneDISTINCT ONquery — no N+1). The icon is hiddenwhen the host has no completed scan or the viewer lacks
scan:read(thedestination is
scan:read-gated).Specs: api-hosts v1.6.0 C-13/AC-24, frontend-hosts-list C-09/AC-22.
B — Group + Filters actually work
Teamoption (no backing host field; youchose Drop).
None/Status/OSnow partition the list into labelledsections (
groupHosts): Status worst-first, OS alphabetical (Unknown last).Status / Compliance-tier / OS facets, persisted to the URL and applied
client-side (
applyHostFilters: AND across dimensions, OR within), with anactive-count badge + Clear all. Logic is in pure, unit-tested
host-filtering.ts.Specs: frontend-hosts-list C-10/C-11, AC-23/AC-24.
C — Server-side per-user view preference (follows you across devices)
New system-user-preferences spec + a general preferences service:
migration
0040(users.preferencesJSONB),internal/userpref(Get +shallow JSONB-
||Merge), and self-scopedGET/PATCH /api/v1/users/me/preferences(user id from identity, 401 anon, enum-validated,unknown keys dropped). The frontend
usePreferencesStorenow hydrates from +writes through to the server (localStorage kept as cache),
AppFramereconciles on mount, and the
/hostsview toggle resolves?view=first,else the persisted
hostsViewDefault— toggling persists the per-user default,so a chosen view "becomes the default until changed".
Specs: system-user-preferences v1.0.0, frontend-settings C-06/AC-30,
frontend-hosts-list C-12/AC-25.
Validation
go build,go vet, fullinternal/server+internal/userprefintegration suites green (DSN-gated, isolated pg on :5433).
tsc --noEmitclean, full vitest suite green (315+).specter check111 specs pass; annotation hygiene 0 errors.source-inspection + behavioral unit tests.
Note:
internal/server/openapi_embed.yamlis gitignored and regenerated fromapi/openapi.yamlbymake vet/make build(runs beforego testin CI).