diff --git a/surfsense_backend/app/routes/documents_routes.py b/surfsense_backend/app/routes/documents_routes.py index ed4d6dea3..4349edc20 100644 --- a/surfsense_backend/app/routes/documents_routes.py +++ b/surfsense_backend/app/routes/documents_routes.py @@ -373,10 +373,11 @@ async def read_documents( # Convert database objects to API-friendly format api_documents = [] for doc in db_documents: - # Get user name (display_name or email fallback) created_by_name = None + created_by_email = None if doc.created_by: - created_by_name = doc.created_by.display_name or doc.created_by.email + created_by_name = doc.created_by.display_name + created_by_email = doc.created_by.email # Parse status from JSONB status_data = None @@ -400,6 +401,7 @@ async def read_documents( search_space_id=doc.search_space_id, created_by_id=doc.created_by_id, created_by_name=created_by_name, + created_by_email=created_by_email, status=status_data, ) ) @@ -528,10 +530,11 @@ async def search_documents( # Convert database objects to API-friendly format api_documents = [] for doc in db_documents: - # Get user name (display_name or email fallback) created_by_name = None + created_by_email = None if doc.created_by: - created_by_name = doc.created_by.display_name or doc.created_by.email + created_by_name = doc.created_by.display_name + created_by_email = doc.created_by.email # Parse status from JSONB status_data = None @@ -555,6 +558,7 @@ async def search_documents( search_space_id=doc.search_space_id, created_by_id=doc.created_by_id, created_by_name=created_by_name, + created_by_email=created_by_email, status=status_data, ) ) diff --git a/surfsense_backend/app/schemas/documents.py b/surfsense_backend/app/schemas/documents.py index 2ca341921..be464f9ec 100644 --- a/surfsense_backend/app/schemas/documents.py +++ b/surfsense_backend/app/schemas/documents.py @@ -60,9 +60,8 @@ class DocumentRead(BaseModel): updated_at: datetime | None search_space_id: int created_by_id: UUID | None = None # User who created/uploaded this document - created_by_name: str | None = ( - None # Display name or email of the user who created this document - ) + created_by_name: str | None = None + created_by_email: str | None = None status: DocumentStatusSchema | None = ( None # Processing status (ready, processing, failed) ) diff --git a/surfsense_web/app/dashboard/[search_space_id]/documents/(manage)/components/DocumentsTableShell.tsx b/surfsense_web/app/dashboard/[search_space_id]/documents/(manage)/components/DocumentsTableShell.tsx index 905f00eae..6d4187593 100644 --- a/surfsense_web/app/dashboard/[search_space_id]/documents/(manage)/components/DocumentsTableShell.tsx +++ b/surfsense_web/app/dashboard/[search_space_id]/documents/(manage)/components/DocumentsTableShell.tsx @@ -453,7 +453,7 @@ export function DocumentsTableShell({ ) : error ? (
- +

{t("error_loading")}

@@ -627,11 +627,30 @@ export function DocumentsTableShell({ )} - {columnVisibility.created_by && ( - - {doc.created_by_name || "—"} - - )} + {columnVisibility.created_by && ( + + {doc.created_by_name ? ( + doc.created_by_email ? ( + + + + {doc.created_by_name} + + + + {doc.created_by_email} + + + ) : ( + {doc.created_by_name} + ) + ) : ( + + {doc.created_by_email || "—"} + + )} + + )} {columnVisibility.created_at && ( diff --git a/surfsense_web/app/dashboard/[search_space_id]/documents/(manage)/components/types.ts b/surfsense_web/app/dashboard/[search_space_id]/documents/(manage)/components/types.ts index 9dcf0ef00..d87f7374b 100644 --- a/surfsense_web/app/dashboard/[search_space_id]/documents/(manage)/components/types.ts +++ b/surfsense_web/app/dashboard/[search_space_id]/documents/(manage)/components/types.ts @@ -16,6 +16,7 @@ export type Document = { search_space_id: number; created_by_id?: string | null; created_by_name?: string | null; + created_by_email?: string | null; status?: DocumentStatus; }; diff --git a/surfsense_web/app/dashboard/[search_space_id]/documents/(manage)/page.tsx b/surfsense_web/app/dashboard/[search_space_id]/documents/(manage)/page.tsx index 585a09c43..824460a5d 100644 --- a/surfsense_web/app/dashboard/[search_space_id]/documents/(manage)/page.tsx +++ b/surfsense_web/app/dashboard/[search_space_id]/documents/(manage)/page.tsx @@ -115,6 +115,7 @@ export default function DocumentsTable() { title: item.title, created_by_id: item.created_by_id ?? null, created_by_name: item.created_by_name ?? null, + created_by_email: item.created_by_email ?? null, created_at: item.created_at, status: ( item as { diff --git a/surfsense_web/contracts/types/document.types.ts b/surfsense_web/contracts/types/document.types.ts index f96ecf85e..6ec577f51 100644 --- a/surfsense_web/contracts/types/document.types.ts +++ b/surfsense_web/contracts/types/document.types.ts @@ -44,6 +44,7 @@ export const document = z.object({ search_space_id: z.number(), created_by_id: z.string().nullable().optional(), created_by_name: z.string().nullable().optional(), + created_by_email: z.string().nullable().optional(), }); export const extensionDocumentContent = z.object({ diff --git a/surfsense_web/hooks/use-documents.ts b/surfsense_web/hooks/use-documents.ts index e3a315cd1..55d48c4f1 100644 --- a/surfsense_web/hooks/use-documents.ts +++ b/surfsense_web/hooks/use-documents.ts @@ -26,7 +26,7 @@ interface DocumentElectric { status: DocumentStatusType | null; } -// Document for display (with resolved user name) +// Document for display (with resolved user name and email) export interface DocumentDisplay { id: number; search_space_id: number; @@ -34,6 +34,7 @@ export interface DocumentDisplay { title: string; created_by_id: string | null; created_by_name: string | null; + created_by_email: string | null; created_at: string; status: DocumentStatusType; } @@ -94,8 +95,9 @@ export function useDocuments( // Track if initial API load is complete (source of truth) const apiLoadedRef = useRef(false); - // User cache: userId → displayName + // User cache: userId → displayName / email const userCacheRef = useRef>(new Map()); + const emailCacheRef = useRef>(new Map()); // Electric sync refs const syncHandleRef = useRef(null); @@ -119,10 +121,21 @@ export function useDocuments( // Populate user cache from API response const populateUserCache = useCallback( - (items: Array<{ created_by_id?: string | null; created_by_name?: string | null }>) => { + ( + items: Array<{ + created_by_id?: string | null; + created_by_name?: string | null; + created_by_email?: string | null; + }> + ) => { for (const item of items) { - if (item.created_by_id && item.created_by_name) { - userCacheRef.current.set(item.created_by_id, item.created_by_name); + if (item.created_by_id) { + if (item.created_by_name) { + userCacheRef.current.set(item.created_by_id, item.created_by_name); + } + if (item.created_by_email) { + emailCacheRef.current.set(item.created_by_id, item.created_by_email); + } } } }, @@ -138,6 +151,7 @@ export function useDocuments( title: string; created_by_id?: string | null; created_by_name?: string | null; + created_by_email?: string | null; created_at: string; status?: DocumentStatusType | null; }): DocumentDisplay => ({ @@ -147,6 +161,7 @@ export function useDocuments( title: item.title, created_by_id: item.created_by_id ?? null, created_by_name: item.created_by_name ?? null, + created_by_email: item.created_by_email ?? null, created_at: item.created_at, status: item.status ?? { state: "ready" }, }), @@ -160,6 +175,9 @@ export function useDocuments( created_by_name: doc.created_by_id ? (userCacheRef.current.get(doc.created_by_id) ?? null) : null, + created_by_email: doc.created_by_id + ? (emailCacheRef.current.get(doc.created_by_id) ?? null) + : null, status: doc.status ?? { state: "ready" }, }), [] @@ -351,6 +369,9 @@ export function useDocuments( created_by_name: doc.created_by_id ? (userCacheRef.current.get(doc.created_by_id) ?? null) : null, + created_by_email: doc.created_by_id + ? (emailCacheRef.current.get(doc.created_by_id) ?? null) + : null, })) ); } @@ -455,6 +476,7 @@ export function useDocuments( setAllDocuments([]); apiLoadedRef.current = false; userCacheRef.current.clear(); + emailCacheRef.current.clear(); } prevSearchSpaceIdRef.current = searchSpaceId; }, [searchSpaceId]);