swarm-ui: sortable + filterable table columns
hyperhive#4020, mara. TableColumn gets two new optional extractors, each one the whole signal for its capability (mara: 'why separate selector and flag?' — dropped the sortable/filterable booleans that would've said the same thing twice and could disagree with the extractor's presence): - sortBy: (row) => string | number — column is click-to-sort iff present. Table owns the sort state (one active column, header click cycles none -> ascending -> descending), since a rendered cell often isn't the sortable value itself (e.g. AgentsPage's status column renders a Badge, not a plain string). - filterValue: (row) => string — column is filterable iff present. A text input row under the headers, substring match case-insensitive. Client-side only, no backend change - every consuming page already fetches its full row set. Wired into AgentsPage and HivesPage, the two pages with a real per-row Table. Left IssueReportPage alone (already has its own purpose-built sort + label/hide-blocked filters, predates this and covers its own domain better than a generic per-column text filter would) and JobsPage alone (renders an indented state tree via JobqGraph, no column table at all despite what my original scoping comment assumed). Verified: typecheck + build clean, nix fmt clean, static render of the actual built CSS confirms the new sort-header + filter-row markup doesn't break table layout.
This commit is contained in:
parent
9065898e08
commit
247ff4498d
4 changed files with 225 additions and 13 deletions
|
|
@ -35,3 +35,49 @@
|
|||
white-space: normal;
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
/* Sortable header — the whole header cell is the click target, not a
|
||||
separate icon-only button next to it, same "control lives on the
|
||||
thing it affects" reasoning as `Badge`'s own click-to-toggle shape. */
|
||||
.ui-table-sort-button {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.35em;
|
||||
background: none;
|
||||
border: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
font: inherit;
|
||||
font-weight: 600;
|
||||
color: inherit;
|
||||
cursor: pointer;
|
||||
}
|
||||
.ui-table-sort-button:hover {
|
||||
color: var(--fg);
|
||||
}
|
||||
.ui-table-sort-glyph {
|
||||
opacity: 0.6;
|
||||
font-size: 0.85em;
|
||||
}
|
||||
.ui-table-sort-button:hover .ui-table-sort-glyph {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
/* The per-column filter inputs' row — same cell padding as a header row,
|
||||
no bottom border of its own (the header row above already has one). */
|
||||
.ui-table-filter-row th {
|
||||
padding-top: 0;
|
||||
padding-bottom: 0.5em;
|
||||
font-weight: 400;
|
||||
}
|
||||
.ui-table-filter-input {
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
background: var(--bg);
|
||||
color: var(--fg);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 4px;
|
||||
padding: 0.25em 0.5em;
|
||||
font: inherit;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue