mirror of
https://github.com/MODSetter/SurfSense.git
synced 2026-06-28 21:49:40 +02:00
feat: add created_by_email field to document schema and update related components for improved user information display
This commit is contained in:
parent
12b119be59
commit
f3652ad7cf
7 changed files with 65 additions and 18 deletions
|
|
@ -373,10 +373,11 @@ async def read_documents(
|
||||||
# Convert database objects to API-friendly format
|
# Convert database objects to API-friendly format
|
||||||
api_documents = []
|
api_documents = []
|
||||||
for doc in db_documents:
|
for doc in db_documents:
|
||||||
# Get user name (display_name or email fallback)
|
|
||||||
created_by_name = None
|
created_by_name = None
|
||||||
|
created_by_email = None
|
||||||
if doc.created_by:
|
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
|
# Parse status from JSONB
|
||||||
status_data = None
|
status_data = None
|
||||||
|
|
@ -400,6 +401,7 @@ async def read_documents(
|
||||||
search_space_id=doc.search_space_id,
|
search_space_id=doc.search_space_id,
|
||||||
created_by_id=doc.created_by_id,
|
created_by_id=doc.created_by_id,
|
||||||
created_by_name=created_by_name,
|
created_by_name=created_by_name,
|
||||||
|
created_by_email=created_by_email,
|
||||||
status=status_data,
|
status=status_data,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
@ -528,10 +530,11 @@ async def search_documents(
|
||||||
# Convert database objects to API-friendly format
|
# Convert database objects to API-friendly format
|
||||||
api_documents = []
|
api_documents = []
|
||||||
for doc in db_documents:
|
for doc in db_documents:
|
||||||
# Get user name (display_name or email fallback)
|
|
||||||
created_by_name = None
|
created_by_name = None
|
||||||
|
created_by_email = None
|
||||||
if doc.created_by:
|
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
|
# Parse status from JSONB
|
||||||
status_data = None
|
status_data = None
|
||||||
|
|
@ -555,6 +558,7 @@ async def search_documents(
|
||||||
search_space_id=doc.search_space_id,
|
search_space_id=doc.search_space_id,
|
||||||
created_by_id=doc.created_by_id,
|
created_by_id=doc.created_by_id,
|
||||||
created_by_name=created_by_name,
|
created_by_name=created_by_name,
|
||||||
|
created_by_email=created_by_email,
|
||||||
status=status_data,
|
status=status_data,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -60,9 +60,8 @@ class DocumentRead(BaseModel):
|
||||||
updated_at: datetime | None
|
updated_at: datetime | None
|
||||||
search_space_id: int
|
search_space_id: int
|
||||||
created_by_id: UUID | None = None # User who created/uploaded this document
|
created_by_id: UUID | None = None # User who created/uploaded this document
|
||||||
created_by_name: str | None = (
|
created_by_name: str | None = None
|
||||||
None # Display name or email of the user who created this document
|
created_by_email: str | None = None
|
||||||
)
|
|
||||||
status: DocumentStatusSchema | None = (
|
status: DocumentStatusSchema | None = (
|
||||||
None # Processing status (ready, processing, failed)
|
None # Processing status (ready, processing, failed)
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -453,7 +453,7 @@ export function DocumentsTableShell({
|
||||||
) : error ? (
|
) : error ? (
|
||||||
<div className="flex h-[50vh] w-full items-center justify-center">
|
<div className="flex h-[50vh] w-full items-center justify-center">
|
||||||
<div className="flex flex-col items-center gap-3">
|
<div className="flex flex-col items-center gap-3">
|
||||||
<AlertCircle className="h-8 w-8 text-destructive/60" />
|
<AlertCircle className="h-8 w-8 text-destructive" />
|
||||||
<p className="text-sm text-destructive">{t("error_loading")}</p>
|
<p className="text-sm text-destructive">{t("error_loading")}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -627,11 +627,30 @@ export function DocumentsTableShell({
|
||||||
<DocumentTypeChip type={doc.document_type} />
|
<DocumentTypeChip type={doc.document_type} />
|
||||||
</TableCell>
|
</TableCell>
|
||||||
)}
|
)}
|
||||||
{columnVisibility.created_by && (
|
{columnVisibility.created_by && (
|
||||||
<TableCell className="w-36 py-2.5 text-sm text-foreground truncate border-r border-border/40">
|
<TableCell className="w-36 py-2.5 text-sm text-foreground truncate border-r border-border/40">
|
||||||
{doc.created_by_name || "—"}
|
{doc.created_by_name ? (
|
||||||
</TableCell>
|
doc.created_by_email ? (
|
||||||
)}
|
<Tooltip>
|
||||||
|
<TooltipTrigger asChild>
|
||||||
|
<span className="cursor-default truncate block">
|
||||||
|
{doc.created_by_name}
|
||||||
|
</span>
|
||||||
|
</TooltipTrigger>
|
||||||
|
<TooltipContent side="top" align="start">
|
||||||
|
{doc.created_by_email}
|
||||||
|
</TooltipContent>
|
||||||
|
</Tooltip>
|
||||||
|
) : (
|
||||||
|
<span className="truncate block">{doc.created_by_name}</span>
|
||||||
|
)
|
||||||
|
) : (
|
||||||
|
<span className="truncate block">
|
||||||
|
{doc.created_by_email || "—"}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
</TableCell>
|
||||||
|
)}
|
||||||
{columnVisibility.created_at && (
|
{columnVisibility.created_at && (
|
||||||
<TableCell className="w-32 py-2.5 text-sm text-foreground border-r border-border/40">
|
<TableCell className="w-32 py-2.5 text-sm text-foreground border-r border-border/40">
|
||||||
<Tooltip>
|
<Tooltip>
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@ export type Document = {
|
||||||
search_space_id: number;
|
search_space_id: number;
|
||||||
created_by_id?: string | null;
|
created_by_id?: string | null;
|
||||||
created_by_name?: string | null;
|
created_by_name?: string | null;
|
||||||
|
created_by_email?: string | null;
|
||||||
status?: DocumentStatus;
|
status?: DocumentStatus;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -115,6 +115,7 @@ export default function DocumentsTable() {
|
||||||
title: item.title,
|
title: item.title,
|
||||||
created_by_id: item.created_by_id ?? null,
|
created_by_id: item.created_by_id ?? null,
|
||||||
created_by_name: item.created_by_name ?? null,
|
created_by_name: item.created_by_name ?? null,
|
||||||
|
created_by_email: item.created_by_email ?? null,
|
||||||
created_at: item.created_at,
|
created_at: item.created_at,
|
||||||
status: (
|
status: (
|
||||||
item as {
|
item as {
|
||||||
|
|
|
||||||
|
|
@ -44,6 +44,7 @@ export const document = z.object({
|
||||||
search_space_id: z.number(),
|
search_space_id: z.number(),
|
||||||
created_by_id: z.string().nullable().optional(),
|
created_by_id: z.string().nullable().optional(),
|
||||||
created_by_name: z.string().nullable().optional(),
|
created_by_name: z.string().nullable().optional(),
|
||||||
|
created_by_email: z.string().nullable().optional(),
|
||||||
});
|
});
|
||||||
|
|
||||||
export const extensionDocumentContent = z.object({
|
export const extensionDocumentContent = z.object({
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@ interface DocumentElectric {
|
||||||
status: DocumentStatusType | null;
|
status: DocumentStatusType | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Document for display (with resolved user name)
|
// Document for display (with resolved user name and email)
|
||||||
export interface DocumentDisplay {
|
export interface DocumentDisplay {
|
||||||
id: number;
|
id: number;
|
||||||
search_space_id: number;
|
search_space_id: number;
|
||||||
|
|
@ -34,6 +34,7 @@ export interface DocumentDisplay {
|
||||||
title: string;
|
title: string;
|
||||||
created_by_id: string | null;
|
created_by_id: string | null;
|
||||||
created_by_name: string | null;
|
created_by_name: string | null;
|
||||||
|
created_by_email: string | null;
|
||||||
created_at: string;
|
created_at: string;
|
||||||
status: DocumentStatusType;
|
status: DocumentStatusType;
|
||||||
}
|
}
|
||||||
|
|
@ -94,8 +95,9 @@ export function useDocuments(
|
||||||
// Track if initial API load is complete (source of truth)
|
// Track if initial API load is complete (source of truth)
|
||||||
const apiLoadedRef = useRef(false);
|
const apiLoadedRef = useRef(false);
|
||||||
|
|
||||||
// User cache: userId → displayName
|
// User cache: userId → displayName / email
|
||||||
const userCacheRef = useRef<Map<string, string>>(new Map());
|
const userCacheRef = useRef<Map<string, string>>(new Map());
|
||||||
|
const emailCacheRef = useRef<Map<string, string>>(new Map());
|
||||||
|
|
||||||
// Electric sync refs
|
// Electric sync refs
|
||||||
const syncHandleRef = useRef<SyncHandle | null>(null);
|
const syncHandleRef = useRef<SyncHandle | null>(null);
|
||||||
|
|
@ -119,10 +121,21 @@ export function useDocuments(
|
||||||
|
|
||||||
// Populate user cache from API response
|
// Populate user cache from API response
|
||||||
const populateUserCache = useCallback(
|
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) {
|
for (const item of items) {
|
||||||
if (item.created_by_id && item.created_by_name) {
|
if (item.created_by_id) {
|
||||||
userCacheRef.current.set(item.created_by_id, item.created_by_name);
|
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;
|
title: string;
|
||||||
created_by_id?: string | null;
|
created_by_id?: string | null;
|
||||||
created_by_name?: string | null;
|
created_by_name?: string | null;
|
||||||
|
created_by_email?: string | null;
|
||||||
created_at: string;
|
created_at: string;
|
||||||
status?: DocumentStatusType | null;
|
status?: DocumentStatusType | null;
|
||||||
}): DocumentDisplay => ({
|
}): DocumentDisplay => ({
|
||||||
|
|
@ -147,6 +161,7 @@ export function useDocuments(
|
||||||
title: item.title,
|
title: item.title,
|
||||||
created_by_id: item.created_by_id ?? null,
|
created_by_id: item.created_by_id ?? null,
|
||||||
created_by_name: item.created_by_name ?? null,
|
created_by_name: item.created_by_name ?? null,
|
||||||
|
created_by_email: item.created_by_email ?? null,
|
||||||
created_at: item.created_at,
|
created_at: item.created_at,
|
||||||
status: item.status ?? { state: "ready" },
|
status: item.status ?? { state: "ready" },
|
||||||
}),
|
}),
|
||||||
|
|
@ -160,6 +175,9 @@ export function useDocuments(
|
||||||
created_by_name: doc.created_by_id
|
created_by_name: doc.created_by_id
|
||||||
? (userCacheRef.current.get(doc.created_by_id) ?? null)
|
? (userCacheRef.current.get(doc.created_by_id) ?? null)
|
||||||
: null,
|
: null,
|
||||||
|
created_by_email: doc.created_by_id
|
||||||
|
? (emailCacheRef.current.get(doc.created_by_id) ?? null)
|
||||||
|
: null,
|
||||||
status: doc.status ?? { state: "ready" },
|
status: doc.status ?? { state: "ready" },
|
||||||
}),
|
}),
|
||||||
[]
|
[]
|
||||||
|
|
@ -351,6 +369,9 @@ export function useDocuments(
|
||||||
created_by_name: doc.created_by_id
|
created_by_name: doc.created_by_id
|
||||||
? (userCacheRef.current.get(doc.created_by_id) ?? null)
|
? (userCacheRef.current.get(doc.created_by_id) ?? null)
|
||||||
: 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([]);
|
setAllDocuments([]);
|
||||||
apiLoadedRef.current = false;
|
apiLoadedRef.current = false;
|
||||||
userCacheRef.current.clear();
|
userCacheRef.current.clear();
|
||||||
|
emailCacheRef.current.clear();
|
||||||
}
|
}
|
||||||
prevSearchSpaceIdRef.current = searchSpaceId;
|
prevSearchSpaceIdRef.current = searchSpaceId;
|
||||||
}, [searchSpaceId]);
|
}, [searchSpaceId]);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue