activity: select-only multi-client filter
the freetype client field is gone. the picker is a select-only menu of known clients with multi-select, chips for the active set, and a 32-client cap shared with the server. the api accepts a comma-separated client list and filters any-of with bound parameters. the trigger carets come from phosphor icons, newly adopted. bundle budget rises to 900000 bytes for the picker and the icon dependency.
This commit is contained in:
@@ -57,6 +57,37 @@ export function validateText(value: unknown): string | undefined {
|
||||
return trimmed === "" ? undefined : trimmed;
|
||||
}
|
||||
|
||||
/** `queries_repo.max_clients`: past this the API answers 400 rather than filter. */
|
||||
export const MAX_CLIENTS = 32;
|
||||
|
||||
/**
|
||||
* The client filter: a comma-separated list of exact addresses, canonicalized
|
||||
* here and nowhere else.
|
||||
*
|
||||
* This is the one place the value is read, so it is the one place it can be made
|
||||
* to mean exactly one thing. Everything downstream — the chips that show the
|
||||
* filter and the request that applies it — reads what this returns, so the two
|
||||
* cannot disagree about a link somebody pasted.
|
||||
*
|
||||
* The rule: entries are trimmed, blanks are dropped, repeats are dropped, and
|
||||
* the list is cut to the cap. A blank entry names no client and a repeat asks
|
||||
* for the same client twice, so neither changes which rows come back; dropping
|
||||
* them is not a different filter, it is the same filter written once. The cut is
|
||||
* a different filter, and it is the honest one available: the API refuses a
|
||||
* longer list outright, so keeping the extra addresses would show a filter that
|
||||
* cannot be applied at all.
|
||||
*/
|
||||
export function validateClients(value: unknown): string | undefined {
|
||||
if (typeof value !== "string") return undefined;
|
||||
const seen = new Set<string>();
|
||||
for (const entry of value.split(",")) {
|
||||
const trimmed = entry.trim();
|
||||
if (trimmed !== "") seen.add(trimmed);
|
||||
if (seen.size === MAX_CLIENTS) break;
|
||||
}
|
||||
return seen.size === 0 ? undefined : [...seen].join(",");
|
||||
}
|
||||
|
||||
/**
|
||||
* The API filter for a validated search, built field by field.
|
||||
*
|
||||
@@ -82,7 +113,7 @@ export function validateActivitySearch(search: Record<string, unknown>): Activit
|
||||
since: validateTimestamp(search["since"]),
|
||||
until: validateTimestamp(search["until"]),
|
||||
domain: validateText(search["domain"]),
|
||||
client: validateText(search["client"]),
|
||||
client: validateClients(search["client"]),
|
||||
blocked: validateBlocked(search["blocked"]),
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user