diff --git a/backend/onyx/server/documents/connector.py b/backend/onyx/server/documents/connector.py
index 13010fd8e..e3d756e0b 100644
--- a/backend/onyx/server/documents/connector.py
+++ b/backend/onyx/server/documents/connector.py
@@ -92,6 +92,7 @@ from onyx.db.enums import IndexingMode
from onyx.db.index_attempt import get_index_attempts_for_cc_pair
from onyx.db.index_attempt import get_latest_index_attempts_by_status
from onyx.db.index_attempt import get_latest_index_attempts_parallel
+from onyx.db.models import Connector
from onyx.db.models import ConnectorCredentialPair
from onyx.db.models import IndexAttempt
from onyx.db.models import IndexingStatus
@@ -789,6 +790,7 @@ def get_connector_indexing_status(
if latest_index_attempt
else None
),
+ is_seeded=is_connector_seeded(connector),
)
)
@@ -1243,9 +1245,18 @@ def get_connector_by_id(
class BasicCCPairInfo(BaseModel):
has_successful_run: bool
+ has_successful_sync_if_needs_sync: bool
+ seeded: bool
source: DocumentSource
+def is_connector_seeded(connector: Connector) -> bool:
+ return (
+ connector.connector_specific_config.get("base_url")
+ == "https://docs.onyx.app/more/use_cases"
+ )
+
+
@router.get("/connector-status")
def get_basic_connector_indexing_status(
user: User = Depends(current_chat_accesssible_user),
@@ -1257,10 +1268,16 @@ def get_basic_connector_indexing_status(
get_editable=False,
user=user,
)
+
return [
BasicCCPairInfo(
has_successful_run=cc_pair.last_successful_index_time is not None,
+ has_successful_sync_if_needs_sync=(
+ cc_pair.last_time_perm_sync is not None
+ or cc_pair.access_type != AccessType.SYNC
+ ),
source=cc_pair.connector.source,
+ seeded=is_connector_seeded(cc_pair.connector),
)
for cc_pair in cc_pairs
if cc_pair.connector.source != DocumentSource.INGESTION_API
diff --git a/backend/onyx/server/documents/models.py b/backend/onyx/server/documents/models.py
index ff1c4b2c8..48905810f 100644
--- a/backend/onyx/server/documents/models.py
+++ b/backend/onyx/server/documents/models.py
@@ -319,6 +319,7 @@ class ConnectorIndexingStatus(ConnectorStatus):
latest_index_attempt: IndexAttemptSnapshot | None
docs_indexed: int
in_progress: bool
+ is_seeded: bool
class ConnectorCredentialPairIdentifier(BaseModel):
diff --git a/web/src/app/admin/connector/[ccPairId]/page.tsx b/web/src/app/admin/connector/[ccPairId]/page.tsx
index 3f26179ce..d5e5236a3 100644
--- a/web/src/app/admin/connector/[ccPairId]/page.tsx
+++ b/web/src/app/admin/connector/[ccPairId]/page.tsx
@@ -421,7 +421,7 @@ function Main({ ccPairId }: { ccPairId: number }) {
{!ccPair.last_successful_index_time
? "This connector has never been successfully indexed. Documents from this connector will not appear in search results until indexing completes successfully."
- : "Permissions synchronization is still in progress for this connector. Some documents may not appear in search results until this process completes."}
+ : "Permissions sync is still in progress for this connector. Some documents may not appear in search results until this process completes."}
diff --git a/web/src/app/admin/indexing/status/ConnectorCreatedSuccessModal.tsx b/web/src/app/admin/indexing/status/ConnectorCreatedSuccessModal.tsx
new file mode 100644
index 000000000..b9a5d3141
--- /dev/null
+++ b/web/src/app/admin/indexing/status/ConnectorCreatedSuccessModal.tsx
@@ -0,0 +1,71 @@
+"use client";
+
+import { useState } from "react";
+import { useRouter } from "next/navigation";
+import {
+ Dialog,
+ DialogContent,
+ DialogHeader,
+ DialogTitle,
+ DialogDescription,
+ DialogFooter,
+} from "@/components/ui/dialog";
+import { Button } from "@/components/ui/button";
+import { CheckmarkIcon } from "@/components/icons/icons";
+
+export function ConnectorCreatedSuccessModal() {
+ const [open, setOpen] = useState(true);
+ const router = useRouter();
+
+ // Close the modal and update the URL to remove the query param
+ const handleClose = () => {
+ setOpen(false);
+ router.replace("/admin/indexing/status");
+ };
+
+ return (
+
+ );
+}
diff --git a/web/src/app/admin/indexing/status/page.tsx b/web/src/app/admin/indexing/status/page.tsx
index e55fdc2a7..74f8dbc9a 100644
--- a/web/src/app/admin/indexing/status/page.tsx
+++ b/web/src/app/admin/indexing/status/page.tsx
@@ -7,10 +7,19 @@ import { AdminPageTitle } from "@/components/admin/Title";
import Link from "next/link";
import Text from "@/components/ui/text";
import { useConnectorCredentialIndexingStatus } from "@/lib/hooks";
-import { usePopupFromQuery } from "@/components/popup/PopupFromQuery";
+import {
+ PopupMessages,
+ usePopupFromQuery,
+} from "@/components/popup/PopupFromQuery";
import { Button } from "@/components/ui/button";
+import { useSearchParams } from "next/navigation";
+import { ConnectorCreatedSuccessModal } from "./ConnectorCreatedSuccessModal";
+import { useMemo } from "react";
-function Main() {
+// Constants
+const ADD_CONNECTOR_PATH = "/admin/add-connector";
+
+const ConnectorStatusList = () => {
const {
data: indexAttemptData,
isLoading: indexAttemptIsLoading,
@@ -23,10 +32,12 @@ function Main() {
error: editableIndexAttemptError,
} = useConnectorCredentialIndexingStatus(undefined, true);
+ // Handle loading state
if (indexAttemptIsLoading || editableIndexAttemptIsLoading) {
return ;
}
+ // Handle error states
if (
indexAttemptError ||
!indexAttemptData ||
@@ -42,11 +53,12 @@ function Main() {
);
}
+ // Show empty state when no connectors
if (indexAttemptData.length === 0) {
return (
It looks like you don't have any connectors setup yet. Visit the{" "}
-
+
Add Connector
{" "}
page to get started!
@@ -54,36 +66,59 @@ function Main() {
);
}
- // sort by source name
- indexAttemptData.sort((a, b) => {
- if (a.connector.source < b.connector.source) {
- return -1;
- } else if (a.connector.source > b.connector.source) {
- return 1;
- } else {
- return 0;
- }
- });
+ // Sort data by source name
+ const sortedIndexAttemptData = [...indexAttemptData].sort((a, b) =>
+ a.connector.source.localeCompare(b.connector.source)
+ );
return (
-
+ <>
+
+ >
);
-}
+};
export default function Status() {
- const { popup } = usePopupFromQuery({
- "connector-created": {
- message: "Connector created successfully",
- type: "success",
- },
+ const searchParams = useSearchParams();
+ const justCreatedConnector =
+ searchParams.get("message") === "connector-created";
+
+ // Use data to determine if we should show the popup or modal
+ const { data: indexAttemptData, isLoading: indexAttemptIsLoading } =
+ useConnectorCredentialIndexingStatus();
+
+ // Only show popup if we're not showing the success modal and there's exactly one seeded connector
+ const showSuccessModal = useMemo(() => {
+ return (
+ !indexAttemptIsLoading &&
+ indexAttemptData &&
+ justCreatedConnector &&
+ indexAttemptData.filter((attempt) => attempt.is_seeded).length === 1
+ );
+ }, [indexAttemptIsLoading, indexAttemptData]);
+
+ // Create popup messages based on query parameters
+ const popupMessages: PopupMessages = {
"connector-deleted": {
message: "Connector deleted successfully",
type: "success",
},
- });
+ };
+
+ // Conditionally add connector-created message
+ if (!showSuccessModal) {
+ Object.assign(popupMessages, {
+ "connector-created": {
+ message: "Connector created successfully",
+ type: "success",
+ },
+ });
+ }
+
+ const { popup } = usePopupFromQuery(popupMessages);
return (