From 7af3d1bc1a3c289feaf180287aa5825fd87d7863 Mon Sep 17 00:00:00 2001 From: Anish Sarkar <104695310+AnishSarkar22@users.noreply.github.com> Date: Sat, 17 Jan 2026 12:59:18 +0530 Subject: [PATCH] feat: improve Google Drive connector handling and UI feedback - Added logic to refresh connector and notification attributes after indexing to ensure up-to-date information. - Enhanced periodic sync configuration to disable the option when no folders or files are selected for Google Drive, providing user feedback through a message. - Updated the connector edit view to reflect the new disabled state for periodic sync based on selected items. - Implemented validation in the connector dialog to prevent enabling periodic sync without selected items, improving user experience. --- .../routes/search_source_connectors_routes.py | 2 ++ .../celery_tasks/schedule_checker_task.py | 20 ++++++++++----- .../google_drive_indexer.py | 3 +++ .../components/periodic-sync-config.tsx | 19 +++++++++++++- .../views/connector-edit-view.tsx | 25 ++++++++++++++----- .../hooks/use-connector-dialog.ts | 18 +++++++++++++ 6 files changed, 74 insertions(+), 13 deletions(-) diff --git a/surfsense_backend/app/routes/search_source_connectors_routes.py b/surfsense_backend/app/routes/search_source_connectors_routes.py index 66551b130..903250521 100644 --- a/surfsense_backend/app/routes/search_source_connectors_routes.py +++ b/surfsense_backend/app/routes/search_source_connectors_routes.py @@ -1840,6 +1840,8 @@ async def run_google_drive_indexing( # Update notification on completion if notification: + # Refresh notification to reload attributes that may have been expired by earlier commits + await session.refresh(notification) await NotificationService.connector_indexing.notify_indexing_completed( session=session, notification=notification, diff --git a/surfsense_backend/app/tasks/celery_tasks/schedule_checker_task.py b/surfsense_backend/app/tasks/celery_tasks/schedule_checker_task.py index c993173e0..e8c2a728c 100644 --- a/surfsense_backend/app/tasks/celery_tasks/schedule_checker_task.py +++ b/surfsense_backend/app/tasks/celery_tasks/schedule_checker_task.py @@ -111,10 +111,10 @@ async def _check_and_trigger_schedules(): # Special handling for Google Drive - uses config for folder/file selection if connector.connector_type == SearchSourceConnectorType.GOOGLE_DRIVE_CONNECTOR: - config = connector.config or {} - selected_folders = config.get("selected_folders", []) - selected_files = config.get("selected_files", []) - indexing_options = config.get("indexing_options", { + connector_config = connector.config or {} + selected_folders = connector_config.get("selected_folders", []) + selected_files = connector_config.get("selected_files", []) + indexing_options = connector_config.get("indexing_options", { "max_files_per_folder": 100, "incremental_sync": True, "include_subfolders": True, @@ -132,9 +132,17 @@ async def _check_and_trigger_schedules(): }, ) else: - logger.warning( - f"Google Drive connector {connector.id} has no folders or files selected, skipping periodic indexing" + # No folders/files selected - skip indexing but still update next_scheduled_at + # to prevent checking every minute + logger.info( + f"Google Drive connector {connector.id} has no folders or files selected, " + "skipping periodic indexing (will check again at next scheduled time)" ) + from datetime import timedelta + connector.next_scheduled_at = now + timedelta( + minutes=connector.indexing_frequency_minutes + ) + await session.commit() continue else: task.delay( diff --git a/surfsense_backend/app/tasks/connector_indexers/google_drive_indexer.py b/surfsense_backend/app/tasks/connector_indexers/google_drive_indexer.py index 7b6c97e53..aecc24661 100644 --- a/surfsense_backend/app/tasks/connector_indexers/google_drive_indexer.py +++ b/surfsense_backend/app/tasks/connector_indexers/google_drive_indexer.py @@ -172,6 +172,9 @@ async def index_google_drive_files( if new_token and not token_error: from sqlalchemy.orm.attributes import flag_modified + # Refresh connector to reload attributes that may have been expired by earlier commits + await session.refresh(connector) + if "folder_tokens" not in connector.config: connector.config["folder_tokens"] = {} connector.config["folder_tokens"][target_folder_id] = new_token diff --git a/surfsense_web/components/assistant-ui/connector-popup/components/periodic-sync-config.tsx b/surfsense_web/components/assistant-ui/connector-popup/components/periodic-sync-config.tsx index f390b1d1b..aaf52a01f 100644 --- a/surfsense_web/components/assistant-ui/connector-popup/components/periodic-sync-config.tsx +++ b/surfsense_web/components/assistant-ui/connector-popup/components/periodic-sync-config.tsx @@ -1,6 +1,7 @@ "use client"; import type { FC } from "react"; +import { AlertCircle } from "lucide-react"; import { Label } from "@/components/ui/label"; import { Select, @@ -16,6 +17,8 @@ interface PeriodicSyncConfigProps { frequencyMinutes: string; onEnabledChange: (enabled: boolean) => void; onFrequencyChange: (frequency: string) => void; + disabled?: boolean; + disabledMessage?: string; } export const PeriodicSyncConfig: FC = ({ @@ -23,6 +26,8 @@ export const PeriodicSyncConfig: FC = ({ frequencyMinutes, onEnabledChange, onFrequencyChange, + disabled = false, + disabledMessage, }) => { return (
@@ -33,9 +38,21 @@ export const PeriodicSyncConfig: FC = ({ Automatically re-index at regular intervals

- + + {/* Show disabled message when periodic sync can't be enabled */} + {disabled && disabledMessage && ( +
+ +

{disabledMessage}

+
+ )} + {enabled && (
diff --git a/surfsense_web/components/assistant-ui/connector-popup/connector-configs/views/connector-edit-view.tsx b/surfsense_web/components/assistant-ui/connector-popup/connector-configs/views/connector-edit-view.tsx index e59800b4d..5291ca231 100644 --- a/surfsense_web/components/assistant-ui/connector-popup/connector-configs/views/connector-edit-view.tsx +++ b/surfsense_web/components/assistant-ui/connector-popup/connector-configs/views/connector-edit-view.tsx @@ -219,12 +219,25 @@ export const ConnectorEditView: FC = ({ )} {/* Periodic sync - shown for all indexable connectors */} - + {(() => { + // Check if Google Drive has folders/files selected + const isGoogleDrive = connector.connector_type === "GOOGLE_DRIVE_CONNECTOR"; + const selectedFolders = (connector.config?.selected_folders as Array<{ id: string; name: string }> | undefined) || []; + const selectedFiles = (connector.config?.selected_files as Array<{ id: string; name: string }> | undefined) || []; + const hasItemsSelected = selectedFolders.length > 0 || selectedFiles.length > 0; + const isDisabled = isGoogleDrive && !hasItemsSelected; + + return ( + + ); + })()} )} diff --git a/surfsense_web/components/assistant-ui/connector-popup/hooks/use-connector-dialog.ts b/surfsense_web/components/assistant-ui/connector-popup/hooks/use-connector-dialog.ts index 2fa490d2d..17209a253 100644 --- a/surfsense_web/components/assistant-ui/connector-popup/hooks/use-connector-dialog.ts +++ b/surfsense_web/components/assistant-ui/connector-popup/hooks/use-connector-dialog.ts @@ -1038,6 +1038,24 @@ export const useConnectorDialog = () => { return; } + // Prevent periodic indexing for Google Drive without folders/files selected + if (periodicEnabled && editingConnector.connector_type === "GOOGLE_DRIVE_CONNECTOR") { + const selectedFolders = (connectorConfig || editingConnector.config)?.selected_folders as + | Array<{ id: string; name: string }> + | undefined; + const selectedFiles = (connectorConfig || editingConnector.config)?.selected_files as + | Array<{ id: string; name: string }> + | undefined; + const hasItemsSelected = + (selectedFolders && selectedFolders.length > 0) || + (selectedFiles && selectedFiles.length > 0); + + if (!hasItemsSelected) { + toast.error("Select at least one folder or file to enable periodic sync"); + return; + } + } + // Validate frequency minutes if periodic is enabled (only for indexable connectors) if (periodicEnabled && editingConnector.is_indexable) { const frequencyValidation = frequencyMinutesSchema.safeParse(frequencyMinutes);