feat: add recipient filter to documents search in admin panel

This commit is contained in:
Catalin Pit
2026-08-24 15:29:08 +03:00
parent 1de57a9e43
commit 2cc6007c82
4 changed files with 45 additions and 4 deletions
@@ -131,7 +131,7 @@ export default function AdminDocumentsPage() {
<div>
<Input
type="search"
placeholder={_(msg`Search by document title, team:123 or user:123`)}
placeholder={_(msg`Search by document title, team:123, user:123 or recipient:email@example.com`)}
value={term}
onChange={(e) => setTerm(e.target.value)}
/>
+6
View File
@@ -0,0 +1,6 @@
/**
* The maximum value of a Postgres `INT4` (32-bit signed integer) column, which
* is what Prisma `Int` ID columns are stored as. Filtering an `Int` column by
* a larger value makes Prisma throw a conversion error at runtime.
*/
export const MAX_POSTGRES_INT = 2147483647;
@@ -2,6 +2,7 @@ import { prisma } from '@documenso/prisma';
import { EnvelopeType, type Prisma } from '@prisma/client';
import { z } from 'zod';
import { MAX_POSTGRES_INT } from '../../constants/database';
import type { FindResultResponse } from '../../types/search-params';
export interface AdminFindDocumentsOptions {
@@ -10,7 +11,7 @@ export interface AdminFindDocumentsOptions {
perPage?: number;
}
const ZPositiveIntegerSchema = z.coerce.number().int().positive();
const ZPositiveIntegerSchema = z.coerce.number().int().positive().max(MAX_POSTGRES_INT);
const emptyResponse = {
data: [],
@@ -58,6 +59,40 @@ export const adminFindDocuments = async ({ query, page = 1, perPage = 10 }: Admi
}
}
if (query?.startsWith('recipient:')) {
const recipientQuery = query.slice('recipient:'.length).trim();
if (!recipientQuery) {
return emptyResponse;
}
// Match admin-global-search semantics: only bare digit strings are ID
// lookups, so numeric-looking email fragments (1e3, 0x10, +40) stay text.
const isRecipientIdLookup = /^\d+$/.test(recipientQuery);
const parsedRecipientId = ZPositiveIntegerSchema.safeParse(recipientQuery);
termFilters =
isRecipientIdLookup && parsedRecipientId.success
? {
recipients: {
some: {
id: parsedRecipientId.data,
},
},
}
: {
recipients: {
some: {
email: {
contains: recipientQuery,
mode: 'insensitive',
},
},
},
};
}
if (query && query?.startsWith('envelope_')) {
termFilters = {
id: {
@@ -1,9 +1,9 @@
import { prisma } from '@documenso/prisma';
import { EnvelopeType } from '@prisma/client';
export const ADMIN_SEARCH_RESULTS_PER_TYPE = 5;
import { MAX_POSTGRES_INT } from '../../constants/database';
const MAX_POSTGRES_INT = 2147483647;
export const ADMIN_SEARCH_RESULTS_PER_TYPE = 5;
const GROUP_ORDER = ['document', 'user', 'organisation', 'team', 'recipient', 'subscription'] as const;