diff --git a/surfsense_backend/app/routes/airtable_add_connector_route.py b/surfsense_backend/app/routes/airtable_add_connector_route.py index fa124f1c2..3bcbe4dc0 100644 --- a/surfsense_backend/app/routes/airtable_add_connector_route.py +++ b/surfsense_backend/app/routes/airtable_add_connector_route.py @@ -255,9 +255,10 @@ async def airtable_callback( await session.commit() logger.info(f"Successfully saved Airtable connector for user {user_id}") - # Redirect to the frontend success page + # Redirect to the frontend with success params for indexing config + # Using query params to auto-open the popup with config view on new-chat page return RedirectResponse( - url=f"{config.NEXT_FRONTEND_URL}/dashboard/{space_id}/connectors/add/airtable-connector?success=true" + url=f"{config.NEXT_FRONTEND_URL}/dashboard/{space_id}/new-chat?modal=connectors&tab=all&success=true&connector=airtable-connector" ) except ValidationError as e: diff --git a/surfsense_backend/app/routes/google_calendar_add_connector_route.py b/surfsense_backend/app/routes/google_calendar_add_connector_route.py index fa4ef5466..8bb685450 100644 --- a/surfsense_backend/app/routes/google_calendar_add_connector_route.py +++ b/surfsense_backend/app/routes/google_calendar_add_connector_route.py @@ -131,8 +131,10 @@ async def calendar_callback( session.add(db_connector) await session.commit() await session.refresh(db_connector) + # Redirect to the frontend with success params for indexing config + # Using query params to auto-open the popup with config view on new-chat page return RedirectResponse( - f"{config.NEXT_FRONTEND_URL}/dashboard/{space_id}/connectors/add/google-calendar-connector?success=true" + f"{config.NEXT_FRONTEND_URL}/dashboard/{space_id}/new-chat?modal=connectors&tab=all&success=true&connector=google-calendar-connector" ) except ValidationError as e: await session.rollback() diff --git a/surfsense_backend/app/routes/google_drive_add_connector_route.py b/surfsense_backend/app/routes/google_drive_add_connector_route.py index 200441d33..52461319b 100644 --- a/surfsense_backend/app/routes/google_drive_add_connector_route.py +++ b/surfsense_backend/app/routes/google_drive_add_connector_route.py @@ -212,9 +212,8 @@ async def drive_callback( f"Successfully created Google Drive connector {db_connector.id} for user {user_id}" ) - # Redirect to connectors management page (not to folder selection) return RedirectResponse( - url=f"{config.NEXT_FRONTEND_URL}/dashboard/{space_id}/connectors?success=google-drive-connected" + url=f"{config.NEXT_FRONTEND_URL}/dashboard/{space_id}/new-chat?modal=connectors&tab=all&success=true&connector=google-drive-connector" ) except HTTPException: diff --git a/surfsense_backend/app/routes/google_gmail_add_connector_route.py b/surfsense_backend/app/routes/google_gmail_add_connector_route.py index 6d37da244..21fcf2c38 100644 --- a/surfsense_backend/app/routes/google_gmail_add_connector_route.py +++ b/surfsense_backend/app/routes/google_gmail_add_connector_route.py @@ -135,9 +135,10 @@ async def gmail_callback( f"Successfully created Gmail connector for user {user_id} with ID {db_connector.id}" ) - # Redirect to the frontend success page + # Redirect to the frontend with success params for indexing config + # Using query params to auto-open the popup with config view on new-chat page return RedirectResponse( - url=f"{config.NEXT_FRONTEND_URL}/dashboard/{space_id}/connectors/add/google-gmail-connector?success=true" + url=f"{config.NEXT_FRONTEND_URL}/dashboard/{space_id}/new-chat?modal=connectors&tab=all&success=true&connector=google-gmail-connector" ) except IntegrityError as e: diff --git a/surfsense_backend/app/routes/logs_routes.py b/surfsense_backend/app/routes/logs_routes.py index e7e00280e..b82e02077 100644 --- a/surfsense_backend/app/routes/logs_routes.py +++ b/surfsense_backend/app/routes/logs_routes.py @@ -322,6 +322,9 @@ async def get_logs_summary( document_id = ( log.log_metadata.get("document_id") if log.log_metadata else None ) + connector_id = ( + log.log_metadata.get("connector_id") if log.log_metadata else None + ) summary["active_tasks"].append( { "id": log.id, @@ -330,6 +333,7 @@ async def get_logs_summary( "started_at": log.created_at, "source": log.source, "document_id": document_id, + "connector_id": connector_id, } ) diff --git a/surfsense_web/app/dashboard/[search_space_id]/connectors/(manage)/page.tsx b/surfsense_web/app/dashboard/[search_space_id]/connectors/(manage)/page.tsx index d12112110..614958018 100644 --- a/surfsense_web/app/dashboard/[search_space_id]/connectors/(manage)/page.tsx +++ b/surfsense_web/app/dashboard/[search_space_id]/connectors/(manage)/page.tsx @@ -38,7 +38,6 @@ import { } from "@/components/ui/alert-dialog"; import { Button } from "@/components/ui/button"; import { Calendar } from "@/components/ui/calendar"; -import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; import { Dialog, DialogContent, @@ -349,221 +348,213 @@ export default function ConnectorsPage() { - - - {t("your_connectors")} - {t("view_manage")} - - - {isLoading ? ( -
-
-
-
-
-
- ) : connectors.length === 0 ? ( -
-

{t("no_connectors")}

-

{t("no_connectors_desc")}

- -
- ) : ( -
- - - - {t("name")} - {t("type")} - {t("last_indexed")} - {t("periodic")} - {t("actions")} - - - - {connectors.map((connector) => ( - - {connector.name} - {getConnectorIcon(connector.connector_type)} - - {connector.is_indexable - ? formatDateTime(connector.last_indexed_at) - : t("not_indexable")} - - - {connector.is_indexable ? ( - connector.periodic_indexing_enabled ? ( - - - -
- - - {connector.indexing_frequency_minutes - ? formatFrequency(connector.indexing_frequency_minutes) - : "Enabled"} - -
-
- -

- Runs every {connector.indexing_frequency_minutes} minutes - {connector.next_scheduled_at && ( - <> -
- Next: {formatDateTime(connector.next_scheduled_at)} - - )} -

-
-
-
- ) : ( - Disabled - ) - ) : ( - - - )} -
- -
- {connector.is_indexable && ( -
- - - - - - -

- {connector.connector_type === EnumConnectorName.GOOGLE_DRIVE_CONNECTOR - ? "Select folder to index" - : t("index_date_range")} -

-
-
-
- {/* Hide quick index button for Google Drive (requires folder selection) */} - {connector.connector_type !== EnumConnectorName.GOOGLE_DRIVE_CONNECTOR && ( - - - - - - -

{t("quick_index_auto")}

-
-
-
- )} -
- )} - {connector.is_indexable && ( + {isLoading ? ( +
+
+
+
+
+
+ ) : connectors.length === 0 ? ( +
+

{t("no_connectors")}

+

{t("no_connectors_desc")}

+ +
+ ) : ( +
+
+ + + {t("name")} + {t("type")} + {t("last_indexed")} + {t("periodic")} + {t("actions")} + + + + {connectors.map((connector) => ( + + {connector.name} + {getConnectorIcon(connector.connector_type)} + + {connector.is_indexable + ? formatDateTime(connector.last_indexed_at) + : t("not_indexable")} + + + {connector.is_indexable ? ( + connector.periodic_indexing_enabled ? ( + + + +
+ + + {connector.indexing_frequency_minutes + ? formatFrequency(connector.indexing_frequency_minutes) + : "Enabled"} + +
+
+ +

+ Runs every {connector.indexing_frequency_minutes} minutes + {connector.next_scheduled_at && ( + <> +
+ Next: {formatDateTime(connector.next_scheduled_at)} + + )} +

+
+
+
+ ) : ( + Disabled + ) + ) : ( + - + )} +
+ +
+ {connector.is_indexable && ( +
+ + + + + + +

+ {connector.connector_type === EnumConnectorName.GOOGLE_DRIVE_CONNECTOR + ? "Select folder to index" + : t("index_date_range")} +

+
+
+
+ {/* Hide quick index button for Google Drive (requires folder selection) */} + {connector.connector_type !== EnumConnectorName.GOOGLE_DRIVE_CONNECTOR && ( -

Configure Periodic Indexing

+

{t("quick_index_auto")}

)} - - - +
+ )} + {connector.is_indexable && ( + + + - - - - {t("delete_connector")} - - {t("delete_confirm")} - - - - setConnectorToDelete(null)}> - {tCommon("cancel")} - - - {tCommon("delete")} - - - - -
-
-
- ))} -
-
-
- )} -
-
+ + +

Configure Periodic Indexing

+
+ + + )} + + + + + + + + {t("delete_connector")} + + {t("delete_confirm")} + + + + setConnectorToDelete(null)}> + {tCommon("cancel")} + + + {tCommon("delete")} + + + + + + + + ))} + + + + )} {/* Date Picker Dialog */} diff --git a/surfsense_web/app/dashboard/[search_space_id]/connectors/[connector_id]/edit/page.tsx b/surfsense_web/app/dashboard/[search_space_id]/connectors/[connector_id]/edit/page.tsx deleted file mode 100644 index 4c7bb3a3a..000000000 --- a/surfsense_web/app/dashboard/[search_space_id]/connectors/[connector_id]/edit/page.tsx +++ /dev/null @@ -1,336 +0,0 @@ -"use client"; - -import { ArrowLeft, Check, Loader2 } from "lucide-react"; -import { motion } from "motion/react"; -import { useParams, useRouter } from "next/navigation"; -import { useEffect } from "react"; -import { toast } from "sonner"; -import { EditConnectorLoadingSkeleton } from "@/components/editConnector/EditConnectorLoadingSkeleton"; -import { EditConnectorNameForm } from "@/components/editConnector/EditConnectorNameForm"; -import { EditGitHubConnectorConfig } from "@/components/editConnector/EditGitHubConnectorConfig"; -import { EditSimpleTokenForm } from "@/components/editConnector/EditSimpleTokenForm"; -import { Button } from "@/components/ui/button"; -import { - Card, - CardContent, - CardDescription, - CardFooter, - CardHeader, - CardTitle, -} from "@/components/ui/card"; -import { - Form, - FormControl, - FormDescription, - FormField, - FormItem, - FormLabel, - FormMessage, -} from "@/components/ui/form"; -import { Textarea } from "@/components/ui/textarea"; -import { getConnectorIcon } from "@/contracts/enums/connectorIcons"; -import { useConnectorEditPage } from "@/hooks/use-connector-edit-page"; -// Import Utils, Types, Hook, and Components -import { getConnectorTypeDisplay } from "@/lib/connectors/utils"; - -export default function EditConnectorPage() { - const router = useRouter(); - const params = useParams(); - const searchSpaceId = params.search_space_id as string; - // Ensure connectorId is parsed safely - const connectorIdParam = params.connector_id as string; - const connectorId = connectorIdParam ? parseInt(connectorIdParam, 10) : NaN; - - // Use the custom hook to manage state and logic - const { - connectorsLoading, - connector, - isSaving, - editForm, - patForm, // Needed for GitHub child component - handleSaveChanges, - // GitHub specific props for the child component - editMode, - setEditMode, // Pass down if needed by GitHub component - originalPat, - currentSelectedRepos, - fetchedRepos, - setFetchedRepos, - newSelectedRepos, - setNewSelectedRepos, - isFetchingRepos, - handleFetchRepositories, - handleRepoSelectionChange, - } = useConnectorEditPage(connectorId, searchSpaceId); - - // Redirect if connectorId is not a valid number after parsing - useEffect(() => { - if (Number.isNaN(connectorId)) { - toast.error("Invalid Connector ID."); - router.push(`/dashboard/${searchSpaceId}/connectors`); - } - }, [connectorId, router, searchSpaceId]); - - // Loading State - if (connectorsLoading || !connector) { - // Handle NaN case before showing skeleton - if (Number.isNaN(connectorId)) return null; - return ; - } - - // Main Render using data/handlers from the hook - return ( -
- - - - - - - {getConnectorIcon(connector.connector_type)} - Edit {getConnectorTypeDisplay(connector.connector_type)} Connector - - Modify connector name and configuration. - - -
- {/* Pass hook's handleSaveChanges */} - - - {/* Pass form control from hook */} - - -
- -

Configuration

- - {/* == GitHub == */} - {connector.connector_type === "GITHUB_CONNECTOR" && ( - - )} - - {/* == Slack == */} - {connector.connector_type === "SLACK_CONNECTOR" && ( - - )} - {/* == Notion == */} - {connector.connector_type === "NOTION_CONNECTOR" && ( - - )} - {/* == Tavily == */} - {connector.connector_type === "TAVILY_API" && ( - - )} - - {/* == Linear == */} - {connector.connector_type === "LINEAR_CONNECTOR" && ( - - )} - - {/* == Jira == */} - {connector.connector_type === "JIRA_CONNECTOR" && ( -
- - - -
- )} - - {/* == Confluence == */} - {connector.connector_type === "CONFLUENCE_CONNECTOR" && ( -
- - - -
- )} - - {/* == ClickUp == */} - {connector.connector_type === "CLICKUP_CONNECTOR" && ( - - )} - - {/* == Linkup == */} - {connector.connector_type === "LINKUP_API" && ( - - )} - - {/* == Discord == */} - {connector.connector_type === "DISCORD_CONNECTOR" && ( - - )} - - {/* == Luma == */} - {connector.connector_type === "LUMA_CONNECTOR" && ( - - )} - - {/* == Elasticsearch == */} - {connector.connector_type === "ELASTICSEARCH_CONNECTOR" && ( - - )} - - {/* == Webcrawler == */} - {connector.connector_type === "WEBCRAWLER_CONNECTOR" && ( -
- - ( - - URLs to Crawl - -