{isFetching ? (
@@ -237,12 +234,15 @@ function ChunksPageContent() {
diff --git a/frontend/src/app/knowledge/page.tsx b/frontend/src/app/knowledge/page.tsx
index cf35486b..1b8b60ef 100644
--- a/frontend/src/app/knowledge/page.tsx
+++ b/frontend/src/app/knowledge/page.tsx
@@ -255,7 +255,7 @@ function SearchPage() {
{selectedFilter?.name && (
@@ -267,8 +267,12 @@ function SearchPage() {
/>
)}
+
params.data.filename}
- domLayout="autoHeight"
+ domLayout="normal"
onSelectionChanged={onSelectionChanged}
noRowsOverlayComponent={() => (
-
-
-
- No documents found
-
-
- Try adjusting your search terms
-
+
+
+ No knowledge
+
+
+ Add files from local or your preferred cloud.
+
)}
/>
diff --git a/frontend/src/app/login/page.tsx b/frontend/src/app/login/page.tsx
index 1639a4be..837706d7 100644
--- a/frontend/src/app/login/page.tsx
+++ b/frontend/src/app/login/page.tsx
@@ -69,18 +69,12 @@ function LoginPageContent() {
/>
+
Welcome to OpenRAG
-
- All your knowledge at your fingertips.
-
-
-
-
Systems Operational
•
-
Privacy Policy
+
);
diff --git a/frontend/src/app/onboarding/components/ibm-onboarding.tsx b/frontend/src/app/onboarding/components/ibm-onboarding.tsx
index 63e3fe6a..b696e220 100644
--- a/frontend/src/app/onboarding/components/ibm-onboarding.tsx
+++ b/frontend/src/app/onboarding/components/ibm-onboarding.tsx
@@ -111,6 +111,7 @@ export function IBMOnboarding({
setProjectId(e.target.value)}
+ />
+ setApiKey(e.target.value)}
/>
- setProjectId(e.target.value)}
- />
{isLoadingModels && (
Validating configuration...
diff --git a/frontend/src/app/onboarding/components/model-selector.tsx b/frontend/src/app/onboarding/components/model-selector.tsx
index dfed52ee..67021b93 100644
--- a/frontend/src/app/onboarding/components/model-selector.tsx
+++ b/frontend/src/app/onboarding/components/model-selector.tsx
@@ -1,115 +1,158 @@
import { CheckIcon, ChevronsUpDownIcon } from "lucide-react";
import { useEffect, useState } from "react";
+import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import {
- Command,
- CommandEmpty,
- CommandGroup,
- CommandInput,
- CommandItem,
- CommandList,
+ Command,
+ CommandEmpty,
+ CommandGroup,
+ CommandInput,
+ CommandItem,
+ CommandList,
} from "@/components/ui/command";
import {
- Popover,
- PopoverContent,
- PopoverTrigger,
+ Popover,
+ PopoverContent,
+ PopoverTrigger,
} from "@/components/ui/popover";
import { cn } from "@/lib/utils";
export function ModelSelector({
- options,
- value,
- onValueChange,
- icon,
- placeholder = "Select model...",
- searchPlaceholder = "Search model...",
- noOptionsPlaceholder = "No models available",
+ options,
+ value,
+ onValueChange,
+ icon,
+ placeholder = "Select model...",
+ searchPlaceholder = "Search model...",
+ noOptionsPlaceholder = "No models available",
+ custom = false,
}: {
- options: {
- value: string;
- label: string;
- default?: boolean;
- }[];
- value: string;
- icon?: React.ReactNode;
- placeholder?: string;
- searchPlaceholder?: string;
- noOptionsPlaceholder?: string;
- onValueChange: (value: string) => void;
+ options: {
+ value: string;
+ label: string;
+ default?: boolean;
+ }[];
+ value: string;
+ icon?: React.ReactNode;
+ placeholder?: string;
+ searchPlaceholder?: string;
+ noOptionsPlaceholder?: string;
+ custom?: boolean;
+ onValueChange: (value: string) => void;
}) {
- const [open, setOpen] = useState(false);
- useEffect(() => {
- if (value && !options.find((option) => option.value === value)) {
- onValueChange("");
- }
- }, [options, value, onValueChange]);
- return (
-
-
- {/** biome-ignore lint/a11y/useSemanticElements: has to be a Button */}
-
-
-
-
-
-
- {noOptionsPlaceholder}
-
- {options.map((option) => (
- {
- if (currentValue !== value) {
- onValueChange(currentValue);
- }
- setOpen(false);
- }}
- >
-
-
- {option.label}
- {option.default && (
-
- Default
-
- )}
-
-
- ))}
-
-
-
-
-
- );
+ const [open, setOpen] = useState(false);
+ const [searchValue, setSearchValue] = useState("");
+
+ useEffect(() => {
+ if (value && (!options.find((option) => option.value === value) && !custom)) {
+ onValueChange("");
+ }
+ }, [options, value, custom, onValueChange]);
+ return (
+
+
+ {/** biome-ignore lint/a11y/useSemanticElements: has to be a Button */}
+
+
+
+
+
+
+ {noOptionsPlaceholder}
+
+ {options.map((option) => (
+ {
+ if (currentValue !== value) {
+ onValueChange(currentValue);
+ }
+ setOpen(false);
+ }}
+ >
+
+
+ {option.label}
+ {/* {option.default && (
+ // DISABLING DEFAULT TAG FOR NOW
+ Default
+
+ )} */}
+
+
+ ))}
+ {custom &&
+ searchValue &&
+ !options.find((option) => option.value === searchValue) && (
+ {
+ if (currentValue !== value) {
+ onValueChange(currentValue);
+ }
+ setOpen(false);
+ }}
+ >
+
+
+ {searchValue}
+
+ Custom
+
+
+
+ )}
+
+
+
+
+
+ );
}
diff --git a/frontend/src/app/onboarding/components/openai-onboarding.tsx b/frontend/src/app/onboarding/components/openai-onboarding.tsx
index b202756d..b057efc0 100644
--- a/frontend/src/app/onboarding/components/openai-onboarding.tsx
+++ b/frontend/src/app/onboarding/components/openai-onboarding.tsx
@@ -2,7 +2,7 @@ import { useState } from "react";
import { LabelInput } from "@/components/label-input";
import { LabelWrapper } from "@/components/label-wrapper";
import OpenAILogo from "@/components/logo/openai-logo";
-import { Checkbox } from "@/components/ui/checkbox";
+import { Switch } from "@/components/ui/switch";
import { useDebouncedValue } from "@/lib/debounce";
import type { OnboardingVariables } from "../../api/mutations/useOnboardingMutation";
import { useGetOpenAIModelsQuery } from "../../api/queries/useGetModelsQuery";
@@ -11,121 +11,114 @@ import { useUpdateSettings } from "../hooks/useUpdateSettings";
import { AdvancedOnboarding } from "./advanced";
export function OpenAIOnboarding({
- setSettings,
- sampleDataset,
- setSampleDataset,
+ setSettings,
+ sampleDataset,
+ setSampleDataset,
}: {
- setSettings: (settings: OnboardingVariables) => void;
- sampleDataset: boolean;
- setSampleDataset: (dataset: boolean) => void;
+ setSettings: (settings: OnboardingVariables) => void;
+ sampleDataset: boolean;
+ setSampleDataset: (dataset: boolean) => void;
}) {
- const [apiKey, setApiKey] = useState("");
- const [getFromEnv, setGetFromEnv] = useState(true);
- const debouncedApiKey = useDebouncedValue(apiKey, 500);
+ const [apiKey, setApiKey] = useState("");
+ const [getFromEnv, setGetFromEnv] = useState(true);
+ const debouncedApiKey = useDebouncedValue(apiKey, 500);
- // Fetch models from API when API key is provided
- const {
- data: modelsData,
- isLoading: isLoadingModels,
- error: modelsError,
- } = useGetOpenAIModelsQuery(
- getFromEnv
- ? { apiKey: "" }
- : debouncedApiKey
- ? { apiKey: debouncedApiKey }
- : undefined,
- { enabled: debouncedApiKey !== "" || getFromEnv },
- );
- // Use custom hook for model selection logic
- const {
- languageModel,
- embeddingModel,
- setLanguageModel,
- setEmbeddingModel,
- languageModels,
- embeddingModels,
- } = useModelSelection(modelsData);
- const handleSampleDatasetChange = (dataset: boolean) => {
- setSampleDataset(dataset);
- };
+ // Fetch models from API when API key is provided
+ const {
+ data: modelsData,
+ isLoading: isLoadingModels,
+ error: modelsError,
+ } = useGetOpenAIModelsQuery(
+ getFromEnv
+ ? { apiKey: "" }
+ : debouncedApiKey
+ ? { apiKey: debouncedApiKey }
+ : undefined,
+ { enabled: debouncedApiKey !== "" || getFromEnv },
+ );
+ // Use custom hook for model selection logic
+ const {
+ languageModel,
+ embeddingModel,
+ setLanguageModel,
+ setEmbeddingModel,
+ languageModels,
+ embeddingModels,
+ } = useModelSelection(modelsData);
+ const handleSampleDatasetChange = (dataset: boolean) => {
+ setSampleDataset(dataset);
+ };
- const handleGetFromEnvChange = (fromEnv: boolean) => {
- setGetFromEnv(fromEnv);
- if (fromEnv) {
- setApiKey("");
- }
- setLanguageModel("");
- setEmbeddingModel("");
- };
+ const handleGetFromEnvChange = (fromEnv: boolean) => {
+ setGetFromEnv(fromEnv);
+ if (fromEnv) {
+ setApiKey("");
+ }
+ setLanguageModel("");
+ setEmbeddingModel("");
+ };
- // Update settings when values change
- useUpdateSettings(
- "openai",
- {
- apiKey,
- languageModel,
- embeddingModel,
- },
- setSettings,
- );
- return (
- <>
-
-
- Reuse the key from your environment config.
-
- Uncheck to enter a different key.
- >
- }
- flex
- start
- >
-
-
- {!getFromEnv && (
-
-
setApiKey(e.target.value)}
- />
- {isLoadingModels && (
-
- Validating API key...
-
- )}
- {modelsError && (
-
- Invalid OpenAI API key. Verify or replace the key.
-
- )}
-
- )}
-
- }
- languageModels={languageModels}
- embeddingModels={embeddingModels}
- languageModel={languageModel}
- embeddingModel={embeddingModel}
- sampleDataset={sampleDataset}
- setLanguageModel={setLanguageModel}
- setSampleDataset={handleSampleDatasetChange}
- setEmbeddingModel={setEmbeddingModel}
- />
- >
- );
+ // Update settings when values change
+ useUpdateSettings(
+ "openai",
+ {
+ apiKey,
+ languageModel,
+ embeddingModel,
+ },
+ setSettings,
+ );
+ return (
+ <>
+
+
+
+
+ {!getFromEnv && (
+
+
setApiKey(e.target.value)}
+ />
+ {isLoadingModels && (
+
+ Validating API key...
+
+ )}
+ {modelsError && (
+
+ Invalid OpenAI API key. Verify or replace the key.
+
+ )}
+
+ )}
+
+ }
+ languageModels={languageModels}
+ embeddingModels={embeddingModels}
+ languageModel={languageModel}
+ embeddingModel={embeddingModel}
+ sampleDataset={sampleDataset}
+ setLanguageModel={setLanguageModel}
+ setSampleDataset={handleSampleDatasetChange}
+ setEmbeddingModel={setEmbeddingModel}
+ />
+ >
+ );
}
diff --git a/frontend/src/app/onboarding/page.tsx b/frontend/src/app/onboarding/page.tsx
index a82e5fab..ca938eeb 100644
--- a/frontend/src/app/onboarding/page.tsx
+++ b/frontend/src/app/onboarding/page.tsx
@@ -68,7 +68,6 @@ function OnboardingPage() {
// Mutations
const onboardingMutation = useOnboardingMutation({
onSuccess: (data) => {
- toast.success("Onboarding completed successfully!");
console.log("Onboarding completed successfully", data);
router.push(redirect);
},
@@ -137,7 +136,7 @@ function OnboardingPage() {
Connect a model provider
-
+
- IBM
+ IBM watsonx.ai
@@ -192,7 +191,7 @@ function OnboardingPage() {
disabled={!isComplete}
loading={onboardingMutation.isPending}
>
- Complete
+ Complete
diff --git a/frontend/src/app/settings/icons/google-drive-icon.tsx b/frontend/src/app/settings/icons/google-drive-icon.tsx
new file mode 100644
index 00000000..0980e644
--- /dev/null
+++ b/frontend/src/app/settings/icons/google-drive-icon.tsx
@@ -0,0 +1,36 @@
+const GoogleDriveIcon = () => (
+
+);
+
+export default GoogleDriveIcon;
diff --git a/frontend/src/app/settings/icons/one-drive-icon.tsx b/frontend/src/app/settings/icons/one-drive-icon.tsx
new file mode 100644
index 00000000..30b77a65
--- /dev/null
+++ b/frontend/src/app/settings/icons/one-drive-icon.tsx
@@ -0,0 +1,164 @@
+const OneDriveIcon = () => (
+
+);
+
+export default OneDriveIcon;
diff --git a/frontend/src/app/settings/icons/share-point-icon.tsx b/frontend/src/app/settings/icons/share-point-icon.tsx
new file mode 100644
index 00000000..3f51dfae
--- /dev/null
+++ b/frontend/src/app/settings/icons/share-point-icon.tsx
@@ -0,0 +1,211 @@
+const SharePointIcon = () => (
+
+);
+
+export default SharePointIcon;
diff --git a/frontend/src/app/settings/page.tsx b/frontend/src/app/settings/page.tsx
index ad936d9c..9df9b5b1 100644
--- a/frontend/src/app/settings/page.tsx
+++ b/frontend/src/app/settings/page.tsx
@@ -1,7 +1,8 @@
"use client";
-import { ArrowUpRight, Loader2, PlugZap, RefreshCw } from "lucide-react";
-import { useSearchParams } from "next/navigation";
+import { ArrowUpRight, Loader2, Minus, Plus } from "lucide-react";
+import Link from "next/link";
+import { useRouter, useSearchParams } from "next/navigation";
import { Suspense, useCallback, useEffect, useState } from "react";
import { useUpdateFlowSettingMutation } from "@/app/api/mutations/useUpdateFlowSettingMutation";
import {
@@ -11,9 +12,8 @@ import {
} from "@/app/api/queries/useGetModelsQuery";
import { useGetSettingsQuery } from "@/app/api/queries/useGetSettingsQuery";
import { ConfirmationDialog } from "@/components/confirmation-dialog";
-import { LabelWrapper } from "@/components/label-wrapper";
+import { LabelWrapper, LabelWrapper } from "@/components/label-wrapper";
import { ProtectedRoute } from "@/components/protected-route";
-import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import {
Card,
@@ -22,7 +22,6 @@ import {
CardHeader,
CardTitle,
} from "@/components/ui/card";
-import { Checkbox } from "@/components/ui/checkbox";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import {
@@ -31,19 +30,26 @@ import {
SelectTrigger,
SelectValue,
} from "@/components/ui/select";
-import { Switch } from "@/components/ui/switch";
+import { Switch, Switch } from "@/components/ui/switch";
import { Textarea } from "@/components/ui/textarea";
import { useAuth } from "@/contexts/auth-context";
import { useTask } from "@/contexts/task-context";
import {
+ DEFAULT_AGENT_SETTINGS,
DEFAULT_AGENT_SETTINGS,
DEFAULT_KNOWLEDGE_SETTINGS,
+ DEFAULT_KNOWLEDGE_SETTINGS,
+ UI_CONSTANTS,
UI_CONSTANTS,
} from "@/lib/constants";
import { useDebounce } from "@/lib/debounce";
import { getFallbackModels, type ModelProvider } from "./helpers/model-helpers";
import { ModelSelectItems } from "./helpers/model-select-item";
+import GoogleDriveIcon from "./icons/google-drive-icon";
+import OneDriveIcon from "./icons/one-drive-icon";
+import SharePointIcon from "./icons/share-point-icon";
+
const { MAX_SYSTEM_PROMPT_CHARS } = UI_CONSTANTS;
interface GoogleDriveFile {
@@ -92,10 +98,38 @@ interface Connection {
last_sync?: string;
}
+const DEFAULT_CONNECTORS: Connector[] = [
+ {
+ id: "google_drive",
+ name: "Google Drive",
+ description: "Google Drive is not configured.",
+ icon:
,
+ status: "not_connected",
+ type: "google_drive",
+ },
+ {
+ id: "one_drive",
+ name: "OneDrive",
+ description: "OneDrive is not configured.",
+ icon:
,
+ status: "not_connected",
+ type: "one_drive",
+ },
+ {
+ id: "amazon_s3",
+ name: "SharePoint",
+ description: "SharePoint is not configured.",
+ icon:
,
+ status: "not_connected",
+ type: "sharepoint",
+ },
+];
+
function KnowledgeSourcesPage() {
const { isAuthenticated, isNoAuthMode } = useAuth();
const { addTask, tasks } = useTask();
const searchParams = useSearchParams();
+ const router = useRouter();
// Connectors state
const [connectors, setConnectors] = useState
([]);
@@ -265,19 +299,15 @@ function KnowledgeSourcesPage() {
// Helper function to get connector icon
const getConnectorIcon = useCallback((iconName: string) => {
const iconMap: { [key: string]: React.ReactElement } = {
- "google-drive": (
-
- G
-
- ),
+ "google-drive": ,
sharepoint: (
SP
),
onedrive: (
-
- OD
+
+
),
};
@@ -398,93 +428,77 @@ function KnowledgeSourcesPage() {
}
};
- const handleSync = async (connector: Connector) => {
- if (!connector.connectionId) return;
+ // const handleSync = async (connector: Connector) => {
+ // if (!connector.connectionId) return;
- setIsSyncing(connector.id);
- setSyncResults((prev) => ({ ...prev, [connector.id]: null }));
+ // setIsSyncing(connector.id);
+ // setSyncResults(prev => ({ ...prev, [connector.id]: null }));
- try {
- const syncBody: {
- connection_id: string;
- max_files?: number;
- selected_files?: string[];
- } = {
- connection_id: connector.connectionId,
- max_files: syncAllFiles ? 0 : maxFiles || undefined,
- };
+ // try {
+ // const syncBody: {
+ // connection_id: string;
+ // max_files?: number;
+ // selected_files?: string[];
+ // } = {
+ // connection_id: connector.connectionId,
+ // max_files: syncAllFiles ? 0 : maxFiles || undefined,
+ // };
- // Note: File selection is now handled via the cloud connectors dialog
+ // // Note: File selection is now handled via the cloud connectors dialog
- const response = await fetch(`/api/connectors/${connector.type}/sync`, {
- method: "POST",
- headers: {
- "Content-Type": "application/json",
- },
- body: JSON.stringify(syncBody),
- });
+ // const response = await fetch(`/api/connectors/${connector.type}/sync`, {
+ // method: "POST",
+ // headers: {
+ // "Content-Type": "application/json",
+ // },
+ // body: JSON.stringify(syncBody),
+ // });
- const result = await response.json();
+ // const result = await response.json();
- if (response.status === 201) {
- const taskId = result.task_id;
- if (taskId) {
- addTask(taskId);
- setSyncResults((prev) => ({
- ...prev,
- [connector.id]: {
- processed: 0,
- total: result.total_files || 0,
- },
- }));
- }
- } else if (response.ok) {
- setSyncResults((prev) => ({ ...prev, [connector.id]: result }));
- // Note: Stats will auto-refresh via task completion watcher for async syncs
- } else {
- console.error("Sync failed:", result.error);
- }
- } catch (error) {
- console.error("Sync error:", error);
- } finally {
- setIsSyncing(null);
- }
- };
+ // if (response.status === 201) {
+ // const taskId = result.task_id;
+ // if (taskId) {
+ // addTask(taskId);
+ // setSyncResults(prev => ({
+ // ...prev,
+ // [connector.id]: {
+ // processed: 0,
+ // total: result.total_files || 0,
+ // },
+ // }));
+ // }
+ // } else if (response.ok) {
+ // setSyncResults(prev => ({ ...prev, [connector.id]: result }));
+ // // Note: Stats will auto-refresh via task completion watcher for async syncs
+ // } else {
+ // console.error("Sync failed:", result.error);
+ // }
+ // } catch (error) {
+ // console.error("Sync error:", error);
+ // } finally {
+ // setIsSyncing(null);
+ // }
+ // };
const getStatusBadge = (status: Connector["status"]) => {
switch (status) {
case "connected":
- return (
-
- Connected
-
- );
+ return
;
case "connecting":
- return (
-
- Connecting...
-
- );
+ return
;
case "error":
- return
Error;
+ return
;
default:
- return (
-
- Not Connected
-
- );
+ return
;
}
};
+ const navigateToKnowledgePage = (connector: Connector) => {
+ const provider = connector.type.replace(/-/g, "_");
+ router.push(`/upload/${provider}`);
+ };
+
// Check connector status on mount and when returning from OAuth
useEffect(() => {
if (isAuthenticated) {
@@ -609,166 +623,172 @@ function KnowledgeSourcesPage() {
{/* Connectors Section */}
-
+
Cloud Connectors
{/* Conditional Sync Settings or No-Auth Message */}
- {isNoAuthMode ? (
-
-
-
- Cloud connectors are only available with auth mode enabled
-
-
- Please provide the following environment variables and restart:
-
-
-
-
-
- # make here https://console.cloud.google.com/apis/credentials
+ {
+ isNoAuthMode ? (
+
+
+
+ Cloud connectors are only available with auth mode enabled
+
+
+ Please provide the following environment variables and
+ restart:
+
+
+
+
+
+ # make here
+ https://console.cloud.google.com/apis/credentials
+
+
GOOGLE_OAUTH_CLIENT_ID=
+
GOOGLE_OAUTH_CLIENT_SECRET=
- GOOGLE_OAUTH_CLIENT_ID=
- GOOGLE_OAUTH_CLIENT_SECRET=
-
-
-
- ) : (
-
-
-
Sync Settings
-
- Configure how many files to sync when manually triggering a sync
-
-
-
-
- {
- setSyncAllFiles(!!checked);
- if (checked) {
- setMaxFiles(0);
- } else {
- setMaxFiles(10);
- }
- }}
- />
-
-
-
-
- setMaxFiles(parseInt(e.target.value) || 10)}
- disabled={syncAllFiles}
- className="w-16 min-w-16 max-w-16 flex-shrink-0 disabled:opacity-50 disabled:cursor-not-allowed"
- min="1"
- max="100"
- title={
- syncAllFiles
- ? "Disabled when 'Sync all files' is checked"
- : "Leave blank or set to 0 for unlimited"
- }
- />
-
-
-
- )}
+
+
+ ) : null
+ //
+ //
+ //
Sync Settings
+ //
+ // Configure how many files to sync when manually triggering a sync
+ //
+ //
+ //
+ //
+ // {
+ // setSyncAllFiles(!!checked);
+ // if (checked) {
+ // setMaxFiles(0);
+ // } else {
+ // setMaxFiles(10);
+ // }
+ // }}
+ // />
+ //
+ //
+ //
+ //
+ // setMaxFiles(parseInt(e.target.value) || 10)}
+ // disabled={syncAllFiles}
+ // className="w-16 min-w-16 max-w-16 flex-shrink-0 disabled:opacity-50 disabled:cursor-not-allowed"
+ // min="1"
+ // max="100"
+ // title={
+ // syncAllFiles
+ // ? "Disabled when 'Sync all files' is checked"
+ // : "Leave blank or set to 0 for unlimited"
+ // }
+ // />
+ //
+ //
+ //
+ }
{/* Connectors Grid */}
- {connectors.map((connector) => (
-
-
-
-
- {connector.icon}
-
-
+ {DEFAULT_CONNECTORS.map((connector) => {
+ const actualConnector = connectors.find(
+ (c) => c.id === connector.id,
+ );
+ return (
+
+
+
+
+
+
{connector.name}
+ {actualConnector &&
+ getStatusBadge(actualConnector.status)}
-
- {connector.description}
+
+ {actualConnector?.description
+ ? `${actualConnector.name} is configured.`
+ : connector.description}
- {getStatusBadge(connector.status)}
-
-
-
- {connector.status === "connected" ? (
-
-
+
+
+ {actualConnector?.status === "connected" ? (
+
+
- {syncResults[connector.id] && (
-
-
- Processed: {syncResults[connector.id]?.processed || 0}
+ {syncResults[connector.id] && (
+
+
+ Processed:{" "}
+ {syncResults[connector.id]?.processed || 0}
+
+
+ Added: {syncResults[connector.id]?.added || 0}
+
+ {syncResults[connector.id]?.errors && (
+
+ Errors: {syncResults[connector.id]?.errors}
+
+ )}
-
- Added: {syncResults[connector.id]?.added || 0}
-
- {syncResults[connector.id]?.errors && (
-
Errors: {syncResults[connector.id]?.errors}
- )}
-
- )}
-
- ) : (
-
- )}
-
-
- ))}
+ )}
+
+ ) : (
+
+
+ See our{" "}
+
+ Cloud Connectors installation guide
+ {" "}
+ for more detail.
+
+
+ )}
+
+
+ );
+ })}
{/* Agent Behavior Section */}
@@ -878,32 +898,31 @@ function KnowledgeSourcesPage() {
-
-