admin: activity history filters become a live-apply toolbar
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:
@@ -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"
|
||||
|
||||
Reference in New Issue
Block a user