diff --git a/surfsense_backend/alembic/versions/86_add_document_created_by.py b/surfsense_backend/alembic/versions/86_add_document_created_by.py index 237ea03b4..19be8a09c 100644 --- a/surfsense_backend/alembic/versions/86_add_document_created_by.py +++ b/surfsense_backend/alembic/versions/86_add_document_created_by.py @@ -83,9 +83,9 @@ def upgrade() -> None: # 4. Backfill existing documents with search space owner's user_id # Process in batches with progress indicator print("Step 4/4: Backfilling created_by_id for existing documents...") - + connection = op.get_bind() - + # Get total count of documents that need backfilling result = connection.execute( sa.text(""" @@ -93,19 +93,19 @@ def upgrade() -> None: """) ) total_count = result.scalar() - + if total_count == 0: print(" No documents need backfilling. Skipping.") return - + print(f" Total documents to backfill: {total_count:,}") - + processed = 0 batch_num = 0 - + while processed < total_count: batch_num += 1 - + # Update a batch of documents using a subquery to limit the update # We use ctid (tuple identifier) for efficient batching in PostgreSQL result = connection.execute( @@ -121,21 +121,23 @@ def upgrade() -> None: LIMIT :batch_size ) """), - {"batch_size": BATCH_SIZE} + {"batch_size": BATCH_SIZE}, ) - + rows_updated = result.rowcount if rows_updated == 0: # No more rows to update break - + processed += rows_updated progress_pct = min(100.0, (processed / total_count) * 100) - + # Print progress with carriage return for in-place update - sys.stdout.write(f"\r Progress: {processed:,}/{total_count:,} documents ({progress_pct:.1f}%) - Batch {batch_num}") + sys.stdout.write( + f"\r Progress: {processed:,}/{total_count:,} documents ({progress_pct:.1f}%) - Batch {batch_num}" + ) sys.stdout.flush() - + # Final newline after progress print() print(f" Done: Backfilled {processed:,} documents.") diff --git a/surfsense_backend/app/routes/new_chat_routes.py b/surfsense_backend/app/routes/new_chat_routes.py index e6a8db689..42b8a821b 100644 --- a/surfsense_backend/app/routes/new_chat_routes.py +++ b/surfsense_backend/app/routes/new_chat_routes.py @@ -736,7 +736,9 @@ async def update_thread_visibility( # ============================================================================= -@router.post("/threads/{thread_id}/snapshots", response_model=PublicChatSnapshotCreateResponse) +@router.post( + "/threads/{thread_id}/snapshots", response_model=PublicChatSnapshotCreateResponse +) async def create_thread_snapshot( thread_id: int, session: AsyncSession = Depends(get_async_session), @@ -756,7 +758,9 @@ async def create_thread_snapshot( ) -@router.get("/threads/{thread_id}/snapshots", response_model=PublicChatSnapshotListResponse) +@router.get( + "/threads/{thread_id}/snapshots", response_model=PublicChatSnapshotListResponse +) async def list_thread_snapshots( thread_id: int, session: AsyncSession = Depends(get_async_session), diff --git a/surfsense_web/app/dashboard/[search_space_id]/team/page.tsx b/surfsense_web/app/dashboard/[search_space_id]/team/page.tsx index 6d457d5c3..55b511957 100644 --- a/surfsense_web/app/dashboard/[search_space_id]/team/page.tsx +++ b/surfsense_web/app/dashboard/[search_space_id]/team/page.tsx @@ -207,7 +207,15 @@ export default function TeamManagementPage() { ); const handleUpdateRole = useCallback( - async (roleId: number, data: { name?: string; description?: string | null; permissions?: string[]; is_default?: boolean }): Promise => { + async ( + roleId: number, + data: { + name?: string; + description?: string | null; + permissions?: string[]; + is_default?: boolean; + } + ): Promise => { const request: UpdateRoleRequest = { search_space_id: searchSpaceId, role_id: roleId, @@ -961,7 +969,15 @@ function RolesTab({ roles: Role[]; groupedPermissions: Record; loading: boolean; - onUpdateRole: (roleId: number, data: { name?: string; description?: string | null; permissions?: string[]; is_default?: boolean }) => Promise; + onUpdateRole: ( + roleId: number, + data: { + name?: string; + description?: string | null; + permissions?: string[]; + is_default?: boolean; + } + ) => Promise; onDeleteRole: (roleId: number) => Promise; onCreateRole: (data: CreateRoleRequest["data"]) => Promise; canUpdate: boolean; @@ -1006,18 +1022,19 @@ function RolesTab({ )} {/* Edit Role Form */} - {editingRoleId !== null && (() => { - const roleToEdit = roles.find((r) => r.id === editingRoleId); - if (!roleToEdit) return null; - return ( - setEditingRoleId(null)} - /> - ); - })()} + {editingRoleId !== null && + (() => { + const roleToEdit = roles.find((r) => r.id === editingRoleId); + if (!roleToEdit) return null; + return ( + setEditingRoleId(null)} + /> + ); + })()} {/* Roles Grid */}
@@ -1077,14 +1094,9 @@ function RolesTab({ - e.preventDefault()} - > + e.preventDefault()}> {canUpdate && ( - setEditingRoleId(role.id)} - > + setEditingRoleId(role.id)}> Edit Role @@ -2058,7 +2070,15 @@ function EditRoleSection({ }: { role: Role; groupedPermissions: Record; - onUpdateRole: (roleId: number, data: { name?: string; description?: string | null; permissions?: string[]; is_default?: boolean }) => Promise; + onUpdateRole: ( + roleId: number, + data: { + name?: string; + description?: string | null; + permissions?: string[]; + is_default?: boolean; + } + ) => Promise; onCancel: () => void; }) { const [saving, setSaving] = useState(false); diff --git a/surfsense_web/components/new-chat/chat-share-button.tsx b/surfsense_web/components/new-chat/chat-share-button.tsx index 336a3d4e8..fa05f44c1 100644 --- a/surfsense_web/components/new-chat/chat-share-button.tsx +++ b/surfsense_web/components/new-chat/chat-share-button.tsx @@ -5,9 +5,9 @@ import { useAtomValue, useSetAtom } from "jotai"; import { Globe, User, Users } from "lucide-react"; import { useCallback, useMemo, useState } from "react"; import { toast } from "sonner"; -import { createPublicChatSnapshotMutationAtom } from "@/atoms/public-chat-snapshots/public-chat-snapshots-mutation.atoms"; import { currentThreadAtom, setThreadVisibilityAtom } from "@/atoms/chat/current-thread.atom"; import { myAccessAtom } from "@/atoms/members/members-query.atoms"; +import { createPublicChatSnapshotMutationAtom } from "@/atoms/public-chat-snapshots/public-chat-snapshots-mutation.atoms"; import { Button } from "@/components/ui/button"; import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover"; import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip";