Skip to content

feat(web): Table view — client-side filter + sortable column headers - #589

Merged
CybotTM merged 2 commits into
mainfrom
feat/phase-3-table-search-sort
Apr 25, 2026
Merged

feat(web): Table view — client-side filter + sortable column headers#589
CybotTM merged 2 commits into
mainfrom
feat/phase-3-table-search-sort

Conversation

@CybotTM

@CybotTM CybotTM commented Apr 25, 2026

Copy link
Copy Markdown
Member

Summary

Closes the deferred follow-up from the live-review polish session (#588 handoff): the Table view now has a search input above the table and clickable column headers that toggle a server-side sort.

What ships

Client-side filter

  • Search input above each Table view (<input data-search-input> inside a data-search-filter / data-search-scope container).
  • Hooks into the existing v2-search-filter.js (no new JS needed). Rows hide via the hidden attribute when the haystack doesn't match.
  • data-search-text on each <tr> concatenates CN, SAM, mail (where present), and DN so the substring filter matches visible and adjacent attributes.
  • The visible row count in the subheader updates live via the existing data-search-count mechanism.
  • Esc clears the input.

Server-side sortable headers

  • Column headers are anchor links carrying ?sort=col&dir=asc|desc plus the preserved filter QS — so back/forward navigation and bookmarking work, no JS required.
  • Clicking the active column toggles the direction; clicking another column resets to asc. The active column shows / .
  • Sort columns:
    • Users: cn / sam / mail / status
    • Groups: cn / members / dn
    • Computers: cn / sam / status / dn
  • Status sort: enabled rows first under asc — the more useful default than alphabetical "Disabled" / "Enabled".

Tests

  • TestNormaliseSortDir + per-entity sort tests (ascending/descending, status semantics, unknown-key fallback to CN, members count desc).
  • TestHandleUsersV2_TableMode marker assertion updated to match the new sort-link / search-input markup.

Out of scope

Test plan

  • go test ./internal/web/ -count=1 — pass
  • golangci-lint run ./... — 0 issues
  • go build ./... — clean
  • templ generate — clean
  • CI verification on push
  • Visual smoke (after merge): /users → Table → click "Status" header → enabled rows top; "Filter users…" → type "ad" → only matching rows visible; click "Graph" → return to /users → still Table view (cookie still works)

…ders

Two paired UX additions to the Table view (List | Table | Graph):

- Search input above the table (`<input data-search-input>` inside a
  `data-search-filter`/`data-search-scope` container) hooks into the
  existing v2-search-filter.js — no new JS needed. Each row carries
  `data-search-text` with CN, SAM, mail, DN concatenated so the
  substring filter matches both visible and adjacent attributes.
- Column headers are now anchor links that toggle the active sort.
  Server-side sort via ?sort=col&dir=asc|desc (URL captures state for
  back/forward + bookmarking). Clicking the active column flips dir;
  clicking another resets to asc. Active-column heading shows ↑ / ↓.

New helpers in internal/web/table_sort.go:
- normaliseSortDir, sortUsersTable, sortGroupsTable, sortComputersTable
- Status sort puts enabled rows first under asc — the more useful
  default than alphabetical "Disabled" / "Enabled".

Tests:
- TestNormaliseSortDir + per-entity sort tests cover ascending/
  descending, status semantics, unknown-key fallback to CN.
- TestHandleUsersV2_TableMode marker assertion updated to match the
  new sort-link / search-input markup.

The cookie-persisted view selection from the previous PR is unaffected
— sort/dir don't persist across views (they're meaningful only inside
Table view), and the existing filterQS stays threaded through the
header links so column clicks keep ?ou=, ?memberOf=, etc.

Signed-off-by: Sebastian Mendel <info@sebastianmendel.de>
Copilot AI review requested due to automatic review settings April 25, 2026 19:30
@github-actions

github-actions Bot commented Apr 25, 2026

Copy link
Copy Markdown
Contributor

Dependency Review

✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.

Scanned Files

None

github-actions[bot]
github-actions Bot previously approved these changes Apr 25, 2026

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Automated approval for maintainer PR

All automated quality gates passed. See SECURITY_CONTROLS.md for compensating controls.

@github-actions

Copy link
Copy Markdown
Contributor

⚠️ Mutation Testing Results

Mutation Score: 0% (threshold: 60%)

⚠️ Score is below threshold. Consider improving test coverage or test quality.

What is mutation testing?

Mutation testing measures test quality by introducing small changes (mutations) to the code and checking if tests detect them. A higher score means better test effectiveness.

  • Killed mutants: Tests caught the mutation (good!)
  • Survived mutants: Tests missed the mutation (needs improvement)

@codecov

codecov Bot commented Apr 25, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 69.76744% with 26 lines in your changes missing coverage. Please review.
✅ Project coverage is 69.94%. Comparing base (d9df5f0) to head (88ab1e4).
⚠️ Report is 3 commits behind head on main.

Files with missing lines Patch % Lines
internal/web/table_sort.go 61.76% 24 Missing and 2 partials ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #589      +/-   ##
==========================================
- Coverage   70.00%   69.94%   -0.06%     
==========================================
  Files          33       34       +1     
  Lines        3357     3437      +80     
==========================================
+ Hits         2350     2404      +54     
- Misses        849      873      +24     
- Partials      158      160       +2     
Flag Coverage Δ
e2e 58.99% <ø> (ø)
unittests 70.40% <69.76%> (-0.08%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Code Review

This pull request implements server-side sorting and client-side filtering for the table views of users, groups, and computers. It introduces a new table_sort.go utility for handling sorting logic with stable secondary keys, updates the web handlers to process sort parameters, and enhances the templates with a search input and sortable column headers. Corresponding CSS and unit tests have also been added. I have no feedback to provide.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Adds table-view enhancements in the V2 web UI by introducing a client-side text filter for table rows and server-side sorting via clickable column headers, keeping sort state in the URL query string.

Changes:

  • Add search input + data-search-* wiring in Table view templates to reuse v2-search-filter.js for client-side row filtering.
  • Add server-side table sorting (?sort=...&dir=asc|desc) for users/groups/computers, plus sortable <th> header links.
  • Add unit tests for the new sort helpers and update existing handler test assertions for the new markup.

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 11 comments.

Show a summary per file
File Description
internal/web/users_v2_handler.go Parses sort params for table view, sorts users server-side, passes sort state to template.
internal/web/groups_v2_handler.go Parses sort params for table view, sorts groups server-side, passes sort state to template.
internal/web/computers_v2_handler.go Parses sort params for table view, sorts computers server-side, passes sort state to template.
internal/web/templates/list_table_v2.templ Adds filter UI + sortable headers; builds sort hrefs and search haystacks per row.
internal/web/table_sort.go Implements in-place sort helpers for users/groups/computers and normalizes direction.
internal/web/table_sort_test.go Unit coverage for sort helpers and direction normalization.
internal/web/graph_v2_handler_test.go Updates table-mode marker assertions for new header/link/filter markup.
internal/web/static/app.css Styles the new search input and sortable header links/indicators.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread internal/web/computers_v2_handler.go
Comment thread internal/web/table_sort.go Outdated
Comment thread internal/web/table_sort.go Outdated
Comment thread internal/web/templates/list_table_v2.templ Outdated
Comment thread internal/web/templates/list_table_v2.templ Outdated
Comment thread internal/web/groups_v2_handler.go
Comment thread internal/web/table_sort.go Outdated
Comment thread internal/web/templates/list_table_v2.templ Outdated
Comment thread internal/web/templates/list_table_v2.templ Outdated
Comment thread internal/web/users_v2_handler.go
Five concrete fixes from Copilot review:

- Skip the CN pre-sort in users/groups/computers handlers when the
  Table view is active; the table applies its own (sortKey, sortDir)
  immediately after, so the unconditional sortXByCN was an
  unnecessary O(n log n) pass.
- stringLess helper centralises the case-insensitive comparison +
  DN tie-break. Earlier the tie-break used `a == b` (case-sensitive)
  while the comparison used `strings.ToLower`, so two values
  differing only in case fell through to input-slice order. Now uses
  strings.EqualFold so the tie-break fires when the primary
  comparison considers them equal. Applied to sortUsersTable,
  sortGroupsTable (cn + dn cases), and sortComputersTable.
- Drop data-search-count from the table's count <p>. v2-search-
  filter.js rewrites the element to "<n> items" on every keystroke,
  so the initial "1 users" flips to "0 items" once the user types —
  ugly noun churn beats live count.
- Comment fix: buildSortHref → buildTableSortHref (renamed earlier
  to dodge a collision with graph_v2.templ's helper of the same
  name; the comment didn't follow).
- Comment fix: "Plain ascii arrows" → describe the actual Unicode
  ↑/↓ glyphs.

Signed-off-by: Sebastian Mendel <info@sebastianmendel.de>

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Automated approval for maintainer PR

All automated quality gates passed. See SECURITY_CONTROLS.md for compensating controls.

@CybotTM
CybotTM merged commit 98df57a into main Apr 25, 2026
25 checks passed
@CybotTM
CybotTM deleted the feat/phase-3-table-search-sort branch April 25, 2026 19:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants