admin: activity history filters become a live-apply toolbar
Gates / frontend (push) Failing after 1m4s
Gates / package (push) Skipped
Gates / container (push) Skipped
Gates / test (push) Successful in 2m33s
Gates / test-aarch64 (push) Successful in 7m33s
CI / gates (push) Failing after 10m6s

the five-field form with its apply button is gone. one row holds a search-shaped domain field and a client ip field that debounce into the url with enter flushing at once, result segments and a time menu that commit instantly, and a clear that appears only when a filter is active without reflowing the row. presets freeze both absolute bounds at click time so a bookmark describes the same investigation later, custom ranges apply atomically through set range with inline validation, and echo queues keep in-flight commits from clobbering newer typing or newer picks. live mode renders no toolbar, the availability banner became a footer note, previous rows stay visible during refetch, and every control carries a 44px hit target.
This commit is contained in:
2026-08-29 14:56:40 +02:00
parent c65d92d8f8
commit 039eeeda96
7 changed files with 1107 additions and 233 deletions
@@ -56,7 +56,8 @@ const styles = stylex.create({
lineHeight: "1.25rem",
color: colors.textMuted,
},
refetching: {
/** The gap a line standing on its own needs from the block above it. */
spacedTop: {
marginTop: "0.75rem",
},
moreButton: {
@@ -81,7 +82,9 @@ export default function HistoryActivity({ search }: { search: ActivitySearch })
const pages = base.data?.pages ?? [];
const rows: QueryRow[] = pages.flatMap((page) => page.queries);
const coverage = pages[0]?.coverage;
// Only from the settled response. Placeholder pages belong to the previous
// filter, and a watermark is a claim about the window being displayed.
const coverage = base.isPlaceholderData ? undefined : pages[0]?.coverage;
const filterActive = Object.keys(filter).length > 0;
// `base.hasNextPage` reads the query state, which is empty while placeholder
// data stands in for a filter change; derive the cursor from what is on
@@ -112,16 +115,27 @@ export default function HistoryActivity({ search }: { search: ActivitySearch })
return (
<>
{/*
* A quiet line, never a skeleton: the rows on screen stay put while a
* filter change is in flight, so a keystroke must not blank the table
* it is narrowing.
*/}
{base.isFetching && (
<p {...stylex.props(styles.note, styles.refetching)} role="status">
Loading
<p {...stylex.props(styles.note, styles.spacedTop)} role="status">
Updating
</p>
)}
{coverage !== undefined && <CoverageNotice coverage={coverage} />}
{rows.length === 0 ? (
<p {...stylex.props(styles.empty)}>
{filterActive ? "No queries match the current filters." : "No queries logged yet."}
</p>
<>
<p {...stylex.props(styles.empty)}>
{filterActive ? "No queries match the current filters." : "No queries logged yet."}
</p>
{coverage !== undefined && (
<div {...stylex.props(styles.spacedTop)}>
<CoverageNotice coverage={coverage} variant="note" />
</div>
)}
</>
) : (
<>
<div {...stylex.props(styles.tableWrap)}>
@@ -158,6 +172,7 @@ export default function HistoryActivity({ search }: { search: ActivitySearch })
Showing {rows.length} {rows.length === 1 ? "query" : "queries"}
{hasMore ? "" : " — end of log"}
</p>
{coverage !== undefined && <CoverageNotice coverage={coverage} variant="note" />}
{hasMore && (
<button
type="button"