diff --git a/Dockerfile.allinone b/Dockerfile.allinone index 12eee5c90..1c04ffb99 100644 --- a/Dockerfile.allinone +++ b/Dockerfile.allinone @@ -37,14 +37,11 @@ COPY surfsense_web/ ./ # Run fumadocs-mdx postinstall now that source files are available RUN pnpm fumadocs-mdx -# Build args for frontend -ARG NEXT_PUBLIC_FASTAPI_BACKEND_URL=http://localhost:8000 -ARG NEXT_PUBLIC_FASTAPI_BACKEND_AUTH_TYPE=LOCAL -ARG NEXT_PUBLIC_ETL_SERVICE=DOCLING - -ENV NEXT_PUBLIC_FASTAPI_BACKEND_URL=$NEXT_PUBLIC_FASTAPI_BACKEND_URL -ENV NEXT_PUBLIC_FASTAPI_BACKEND_AUTH_TYPE=$NEXT_PUBLIC_FASTAPI_BACKEND_AUTH_TYPE -ENV NEXT_PUBLIC_ETL_SERVICE=$NEXT_PUBLIC_ETL_SERVICE +# Build with placeholder values that will be replaced at runtime +# These unique strings allow runtime substitution via entrypoint script +ENV NEXT_PUBLIC_FASTAPI_BACKEND_URL=__NEXT_PUBLIC_FASTAPI_BACKEND_URL__ +ENV NEXT_PUBLIC_FASTAPI_BACKEND_AUTH_TYPE=__NEXT_PUBLIC_FASTAPI_BACKEND_AUTH_TYPE__ +ENV NEXT_PUBLIC_ETL_SERVICE=__NEXT_PUBLIC_ETL_SERVICE__ # Build RUN pnpm run build @@ -233,6 +230,12 @@ ENV AUTH_TYPE=LOCAL ENV ETL_SERVICE=DOCLING ENV EMBEDDING_MODEL=sentence-transformers/all-MiniLM-L6-v2 +# Frontend configuration (can be overridden at runtime) +# These are injected into the Next.js build at container startup +ENV NEXT_PUBLIC_FASTAPI_BACKEND_URL=http://localhost:8000 +ENV NEXT_PUBLIC_FASTAPI_BACKEND_AUTH_TYPE=LOCAL +ENV NEXT_PUBLIC_ETL_SERVICE=DOCLING + # Data volume VOLUME ["/data"] diff --git a/scripts/docker/entrypoint-allinone.sh b/scripts/docker/entrypoint-allinone.sh index 427256f6d..8248968ab 100644 --- a/scripts/docker/entrypoint-allinone.sh +++ b/scripts/docker/entrypoint-allinone.sh @@ -96,6 +96,30 @@ if [ -d /app/frontend/.next/standalone ]; then cp -r /app/frontend/.next/static /app/frontend/.next/static 2>/dev/null || true fi +# ================================================ +# Runtime Environment Variable Replacement +# ================================================ +# Next.js NEXT_PUBLIC_* vars are baked in at build time. +# This replaces placeholder values with actual runtime env vars. +echo "🔧 Applying runtime environment configuration..." + +# Set defaults if not provided +NEXT_PUBLIC_FASTAPI_BACKEND_URL="${NEXT_PUBLIC_FASTAPI_BACKEND_URL:-http://localhost:8000}" +NEXT_PUBLIC_FASTAPI_BACKEND_AUTH_TYPE="${NEXT_PUBLIC_FASTAPI_BACKEND_AUTH_TYPE:-LOCAL}" +NEXT_PUBLIC_ETL_SERVICE="${NEXT_PUBLIC_ETL_SERVICE:-DOCLING}" + +# Replace placeholders in all JS files +find /app/frontend -type f \( -name "*.js" -o -name "*.json" \) -exec sed -i \ + -e "s|__NEXT_PUBLIC_FASTAPI_BACKEND_URL__|${NEXT_PUBLIC_FASTAPI_BACKEND_URL}|g" \ + -e "s|__NEXT_PUBLIC_FASTAPI_BACKEND_AUTH_TYPE__|${NEXT_PUBLIC_FASTAPI_BACKEND_AUTH_TYPE}|g" \ + -e "s|__NEXT_PUBLIC_ETL_SERVICE__|${NEXT_PUBLIC_ETL_SERVICE}|g" \ + {} + + +echo "✅ Environment configuration applied" +echo " Backend URL: ${NEXT_PUBLIC_FASTAPI_BACKEND_URL}" +echo " Auth Type: ${NEXT_PUBLIC_FASTAPI_BACKEND_AUTH_TYPE}" +echo " ETL Service: ${NEXT_PUBLIC_ETL_SERVICE}" + # ================================================ # Run database migrations # ================================================ @@ -135,10 +159,10 @@ echo "===========================================" echo " 📋 Configuration" echo "===========================================" echo " Frontend URL: http://localhost:3000" -echo " Backend API: http://localhost:8000" -echo " API Docs: http://localhost:8000/docs" -echo " Auth Type: ${AUTH_TYPE:-LOCAL}" -echo " ETL Service: ${ETL_SERVICE:-DOCLING}" +echo " Backend API: ${NEXT_PUBLIC_FASTAPI_BACKEND_URL}" +echo " API Docs: ${NEXT_PUBLIC_FASTAPI_BACKEND_URL}/docs" +echo " Auth Type: ${NEXT_PUBLIC_FASTAPI_BACKEND_AUTH_TYPE}" +echo " ETL Service: ${NEXT_PUBLIC_ETL_SERVICE}" echo " TTS Service: ${TTS_SERVICE}" echo " STT Service: ${STT_SERVICE}" echo "===========================================" diff --git a/surfsense_web/app/dashboard/[search_space_id]/client-layout.tsx b/surfsense_web/app/dashboard/[search_space_id]/client-layout.tsx index 6e61ff7ac..c78cc7762 100644 --- a/surfsense_web/app/dashboard/[search_space_id]/client-layout.tsx +++ b/surfsense_web/app/dashboard/[search_space_id]/client-layout.tsx @@ -17,6 +17,7 @@ import { activeSearchSpaceIdAtom } from "@/atoms/search-spaces/search-space-quer import { DocumentUploadDialogProvider } from "@/components/assistant-ui/document-upload-popup"; import { DashboardBreadcrumb } from "@/components/dashboard-breadcrumb"; import { LanguageSwitcher } from "@/components/LanguageSwitcher"; +import { OnboardingTour } from "@/components/onboarding-tour"; import { AppSidebarProvider } from "@/components/sidebar/AppSidebarProvider"; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; import { Separator } from "@/components/ui/separator"; @@ -242,6 +243,7 @@ export function DashboardClientLayout({ return ( + {/* Use AppSidebarProvider which fetches user, search space, and recent chats */} { return ( + {/* Dark overlay with cutout using box-shadow technique */} +
+ {/* Blue shadow behind the button - starts from button border */} +
+ + ); +} + +function TourTooltip({ + step, + stepIndex, + totalSteps, + position, + onNext, + onPrev, + onSkip, + isDarkMode, +}: { + step: TourStep; + stepIndex: number; + totalSteps: number; + position: TooltipPosition; + targetRect: DOMRect; + onNext: () => void; + onPrev: () => void; + onSkip: () => void; + isDarkMode: boolean; +}) { + const [contentKey, setContentKey] = useState(stepIndex); + const [shouldAnimate, setShouldAnimate] = useState(false); + const prevStepIndexRef = useRef(stepIndex); + const isLastStep = stepIndex === totalSteps - 1; + const isFirstStep = stepIndex === 0; + + // Update content key when step changes to trigger animation + // Only animate if stepIndex actually changes (not on initial mount) + useEffect(() => { + if (prevStepIndexRef.current !== stepIndex) { + setShouldAnimate(true); + setContentKey(stepIndex); + prevStepIndexRef.current = stepIndex; + } + }, [stepIndex]); + + const bgColor = isDarkMode ? "#18181b" : "#ffffff"; + const textColor = isDarkMode ? "#ffffff" : "#18181b"; + const mutedTextColor = isDarkMode ? "#a1a1aa" : "#71717a"; + + // Calculate pointer line position + const getPointerStyles = (): React.CSSProperties => { + const lineLength = 16; + const dotSize = 6; + // Check if this is the documents step (stepIndex === 1) + const isDocumentsStep = stepIndex === 1; + + if (position.pointerPosition === "left") { + return { + position: "absolute", + left: -lineLength - dotSize, + top: isDocumentsStep ? "calc(50% - 8px)" : "50%", + transform: "translateY(-50%)", + display: "flex", + alignItems: "center", + }; + } + if (position.pointerPosition === "top") { + return { + position: "absolute", + top: -lineLength - dotSize, + left: "50%", + transform: "translateX(-50%)", + display: "flex", + flexDirection: "column", + alignItems: "center", + }; + } + return {}; + }; + + const renderPointer = () => { + const lineColor = isDarkMode ? "#18181B" : "#ffffff"; + + if (position.pointerPosition === "left") { + return ( +
+
+
+
+ ); + } + if (position.pointerPosition === "top") { + return ( +
+
+
+
+ ); + } + return null; + }; + + // Render step dots + const renderStepDots = () => { + return ( +
+ {Array.from({ length: totalSteps }).map((_, i) => ( +
+ ))} +
+ ); + }; + + return ( +
e.stopPropagation()} + onKeyDown={(e) => e.stopPropagation()} + > + {/* Pointer line */} + {renderPointer()} + +
+ {/* Content */} +
setShouldAnimate(false)} + > +

+ {step.title} +

+

+ {step.content} +

+
+ + {/* Footer */} +
+ {/* Step dots */} + {renderStepDots()} + + {/* Navigation buttons */} +
+ {!isFirstStep && ( + + )} + {isFirstStep && ( + + )} + +
+
+
+
+ ); +} + +export function OnboardingTour() { + const [isActive, setIsActive] = useState(false); + const [stepIndex, setStepIndex] = useState(0); + const [targetEl, setTargetEl] = useState(null); + const [spotlightTargetEl, setSpotlightTargetEl] = useState(null); + const [spotlightStepTarget, setSpotlightStepTarget] = useState(null); + const [position, setPosition] = useState(null); + const [targetRect, setTargetRect] = useState(null); + const [mounted, setMounted] = useState(false); + const { resolvedTheme } = useTheme(); + const pathname = usePathname(); + const retryCountRef = useRef(0); + const maxRetries = 10; + // Track previous user ID to detect user changes + const previousUserIdRef = useRef(null); + + // Get user data + const { data: user } = useAtomValue(currentUserAtom); + const searchSpaceId = useAtomValue(activeSearchSpaceIdAtom); + + // Fetch threads data + const { data: threadsData } = useQuery({ + queryKey: ["threads", searchSpaceId], + queryFn: () => fetchThreads(Number(searchSpaceId), 1), // Only need to check if any exist + enabled: !!searchSpaceId, + }); + + // Get document type counts + const { data: documentTypeCounts } = useAtomValue(documentTypeCountsAtom); + + // Get connectors + const { data: connectors = [] } = useAtomValue(connectorsAtom); + + const isDarkMode = resolvedTheme === "dark"; + const currentStep = TOUR_STEPS[stepIndex]; + + // Handle mounting for portal + useEffect(() => { + setMounted(true); + }, []); + + // Find and track target element with retry logic + const updateTarget = useCallback(() => { + if (!currentStep) return; + + const el = document.querySelector(currentStep.target); + if (el) { + setTargetEl(el); + setTargetRect(el.getBoundingClientRect()); + setPosition(calculatePosition(el, currentStep.placement)); + retryCountRef.current = 0; + } else if (retryCountRef.current < maxRetries) { + retryCountRef.current++; + setTimeout(() => { + const retryEl = document.querySelector(currentStep.target); + if (retryEl) { + setTargetEl(retryEl); + setTargetRect(retryEl.getBoundingClientRect()); + setPosition(calculatePosition(retryEl, currentStep.placement)); + retryCountRef.current = 0; + } + }, 200); + } + }, [currentStep]); + + // Check if tour should run: localStorage + data validation with user ID tracking + useEffect(() => { + // Don't check if not mounted or no user + if (!mounted || !user?.id || !searchSpaceId) return; + + // Check if on new-chat page + const isNewChatPage = pathname?.includes("/new-chat"); + if (!isNewChatPage) return; + + // Wait for all data to be loaded before making decision + // Data is considered loaded when: + // - threadsData is defined (query completed, even if empty) + // - documentTypeCounts is defined (query completed, even if empty object) + // - connectors is an array (always defined with default []) + // If searchSpaceId is not set, connectors query won't run, but that's okay + const dataLoaded = threadsData !== undefined && documentTypeCounts !== undefined; + if (!dataLoaded) return; + + const currentUserId = user.id; + const previousUserId = previousUserIdRef.current; + + // Detect user change - if user ID changed, reset tour state + if (previousUserId !== null && previousUserId !== currentUserId) { + // User changed - reset tour state and re-evaluate for new user + setIsActive(false); + setStepIndex(0); + setTargetEl(null); + setSpotlightTargetEl(null); + setSpotlightStepTarget(null); + setPosition(null); + setTargetRect(null); + retryCountRef.current = 0; + } + + // Update previous user ID ref + previousUserIdRef.current = currentUserId; + + // Check localStorage for CURRENT user ID (not stale cache) + // This ensures we check the correct user's tour status + const tourKey = `surfsense-tour-${currentUserId}`; + const hasSeenTour = localStorage.getItem(tourKey); + if (hasSeenTour === "true") { + return; // Current user has seen tour, don't show + } + + // Validate user is actually new (reliable check) + const threads = threadsData?.threads ?? []; + const hasThreads = threads.length > 0; + + // Check document counts - sum all document type counts + const totalDocuments = documentTypeCounts + ? Object.values(documentTypeCounts).reduce((sum, count) => sum + count, 0) + : 0; + const hasDocuments = totalDocuments > 0; + + const hasConnectors = connectors.length > 0; + + // User is new if they have no threads, documents, or connectors + const isNewUser = !hasThreads && !hasDocuments && !hasConnectors; + + // Only show tour if user is new and hasn't seen it + // Don't auto-mark as seen if user has data - let them explicitly dismiss it + if (!isNewUser) { + return; // User has data, don't show tour + } + + // User is new and hasn't seen tour - wait for DOM elements and start tour + const checkAndStartTour = () => { + // Check if both required elements exist + const connectorEl = document.querySelector(TOUR_STEPS[0].target); + const documentsEl = document.querySelector(TOUR_STEPS[1].target); + + if (connectorEl && documentsEl) { + // Both elements found, start tour + setIsActive(true); + setTargetEl(connectorEl); + setSpotlightTargetEl(connectorEl); + setSpotlightStepTarget(TOUR_STEPS[0].target); + setTargetRect(connectorEl.getBoundingClientRect()); + setPosition(calculatePosition(connectorEl, TOUR_STEPS[0].placement)); + } else { + // Retry after delay + setTimeout(checkAndStartTour, 200); + } + }; + + // Start checking after initial delay + const timer = setTimeout(checkAndStartTour, 500); + return () => clearTimeout(timer); + }, [mounted, user?.id, searchSpaceId, pathname, threadsData, documentTypeCounts, connectors]); + + // Update position on resize/scroll + useEffect(() => { + if (!isActive || !targetEl) return; + + const handleUpdate = () => { + const rect = targetEl.getBoundingClientRect(); + if (rect.width > 0 && rect.height > 0) { + setTargetRect(rect); + setPosition(calculatePosition(targetEl, currentStep?.placement || "bottom")); + } + }; + + window.addEventListener("resize", handleUpdate); + window.addEventListener("scroll", handleUpdate, true); + + return () => { + window.removeEventListener("resize", handleUpdate); + window.removeEventListener("scroll", handleUpdate, true); + }; + }, [isActive, targetEl, currentStep?.placement]); + + // Update target when step changes + useEffect(() => { + if (isActive && currentStep) { + // Try to find element synchronously first to prevent any delay + const el = document.querySelector(currentStep.target); + if (el) { + // Found immediately - update state synchronously to prevent flicker + const rect = el.getBoundingClientRect(); + const newPosition = calculatePosition(el, currentStep.placement); + // React 18+ automatically batches these updates + setTargetEl(el); + setTargetRect(rect); + setPosition(newPosition); + retryCountRef.current = 0; + } else { + // Not found immediately, use updateTarget with retry logic + // Use requestAnimationFrame to batch with next paint + const frameId = requestAnimationFrame(() => { + updateTarget(); + }); + return () => cancelAnimationFrame(frameId); + } + } + }, [isActive, updateTarget, currentStep]); + + // Delay spotlight update to sync with tooltip animation + useEffect(() => { + if (targetEl && currentStep) { + const timer = setTimeout(() => { + setSpotlightTargetEl(targetEl); + setSpotlightStepTarget(currentStep.target); + }, 100); + return () => clearTimeout(timer); + } + }, [targetEl, currentStep]); + + // Ensure target element is above overlay layers so content is fully visible + useEffect(() => { + if (!targetEl || !isActive) return; + + const originalZIndex = (targetEl as HTMLElement).style.zIndex; + const originalPosition = (targetEl as HTMLElement).style.position; + + // Ensure the element has a position that allows z-index + if (getComputedStyle(targetEl).position === "static") { + (targetEl as HTMLElement).style.position = "relative"; + } + (targetEl as HTMLElement).style.zIndex = "99999"; + + return () => { + (targetEl as HTMLElement).style.zIndex = originalZIndex; + if (originalPosition) { + (targetEl as HTMLElement).style.position = originalPosition; + } else if (getComputedStyle(targetEl).position === "relative" && originalPosition === "") { + (targetEl as HTMLElement).style.position = ""; + } + }; + }, [targetEl, isActive]); + + const handleNext = useCallback(() => { + if (stepIndex < TOUR_STEPS.length - 1) { + retryCountRef.current = 0; + setStepIndex(stepIndex + 1); + } else { + // Tour completed - save to localStorage + if (user?.id) { + const tourKey = `surfsense-tour-${user.id}`; + localStorage.setItem(tourKey, "true"); + } + setIsActive(false); + } + }, [stepIndex, user?.id]); + + const handlePrev = useCallback(() => { + if (stepIndex > 0) { + retryCountRef.current = 0; + setStepIndex(stepIndex - 1); + } + }, [stepIndex]); + + const handleSkip = useCallback(() => { + // Tour skipped - save to localStorage + if (user?.id) { + const tourKey = `surfsense-tour-${user.id}`; + localStorage.setItem(tourKey, "true"); + } + setIsActive(false); + }, [user?.id]); + + // Handle overlay click to close + const handleOverlayClick = useCallback(() => { + // Tour closed - save to localStorage + if (user?.id) { + const tourKey = `surfsense-tour-${user.id}`; + localStorage.setItem(tourKey, "true"); + } + setIsActive(false); + }, [user?.id]); + + // Handle escape key + useEffect(() => { + const handleKeyDown = (e: KeyboardEvent) => { + if (e.key === "Escape" && isActive) { + // Tour closed via escape - save to localStorage + if (user?.id) { + const tourKey = `surfsense-tour-${user.id}`; + localStorage.setItem(tourKey, "true"); + } + setIsActive(false); + } + }; + window.addEventListener("keydown", handleKeyDown); + return () => window.removeEventListener("keydown", handleKeyDown); + }, [isActive, user?.id]); + + // Don't render if not active or not mounted + if (!mounted || !isActive) { + return null; + } + + return createPortal( + <> + +
+ {/* Clickable backdrop to close */} +
+ , + document.body + ); +} diff --git a/surfsense_web/components/sidebar/nav-main.tsx b/surfsense_web/components/sidebar/nav-main.tsx index 43c551875..a0dbe912f 100644 --- a/surfsense_web/components/sidebar/nav-main.tsx +++ b/surfsense_web/components/sidebar/nav-main.tsx @@ -131,7 +131,11 @@ export function NavMain({ items }: NavMainProps) { isActive={isActive} aria-label={`${translatedTitle} with submenu`} > - @@ -152,10 +156,18 @@ export function NavMain({ items }: NavMainProps) { {item.items?.map((subItem, subIndex) => { const translatedSubTitle = translateTitle(subItem.title); + const isDocumentsLink = + subItem.title === "Manage Documents" || + translatedSubTitle.toLowerCase().includes("documents"); return ( - + {translatedSubTitle} @@ -173,7 +185,13 @@ export function NavMain({ items }: NavMainProps) { isActive={isActive} aria-label={translatedTitle} > - + {translatedTitle} diff --git a/surfsense_web/content/docs/connectors/airtable.mdx b/surfsense_web/content/docs/connectors/airtable.mdx index 647208271..1fbe427ec 100644 --- a/surfsense_web/content/docs/connectors/airtable.mdx +++ b/surfsense_web/content/docs/connectors/airtable.mdx @@ -3,31 +3,4 @@ title: Airtable description: Connect your Airtable bases to SurfSense --- -# Airtable Connector - -Index your Airtable bases, tables, and records. - -## Prerequisites - -- An Airtable account -- API access to the bases you want to connect - -## Setup - -1. Navigate to your Search Space settings -2. Click on **Add Connector** -3. Select **Airtable** from the list -4. Enter your Airtable API key -5. Select the bases and tables you want to index - -## What Gets Indexed - -- Table records -- Field values -- Attachments -- Linked records - -## Sync Frequency - -The Airtable connector supports scheduled syncing to keep your data up to date. - +# Documentation in progress diff --git a/surfsense_web/content/docs/connectors/bookstack.mdx b/surfsense_web/content/docs/connectors/bookstack.mdx index c05a6376b..8ee581948 100644 --- a/surfsense_web/content/docs/connectors/bookstack.mdx +++ b/surfsense_web/content/docs/connectors/bookstack.mdx @@ -3,31 +3,4 @@ title: Bookstack description: Connect your Bookstack instance to SurfSense --- -# Bookstack Connector - -Index your Bookstack books, chapters, and pages. - -## Prerequisites - -- A Bookstack instance -- API access credentials - -## Setup - -1. Navigate to your Search Space settings -2. Click on **Add Connector** -3. Select **Bookstack** from the list -4. Enter your Bookstack instance URL and API credentials -5. Select the shelves and books you want to index - -## What Gets Indexed - -- Books and chapters -- Pages and content -- Attachments -- Tags and metadata - -## Sync Frequency - -The Bookstack connector supports scheduled syncing to keep your content up to date. - +# Documentation in progress \ No newline at end of file diff --git a/surfsense_web/content/docs/connectors/circleback.mdx b/surfsense_web/content/docs/connectors/circleback.mdx new file mode 100644 index 000000000..a5c90a28f --- /dev/null +++ b/surfsense_web/content/docs/connectors/circleback.mdx @@ -0,0 +1,8 @@ +--- +title: Circleback +description: Connect your circleback to SurfSense +--- + +# Documentation in progress + + diff --git a/surfsense_web/content/docs/connectors/clickup.mdx b/surfsense_web/content/docs/connectors/clickup.mdx index 90734555a..f59030788 100644 --- a/surfsense_web/content/docs/connectors/clickup.mdx +++ b/surfsense_web/content/docs/connectors/clickup.mdx @@ -3,31 +3,4 @@ title: ClickUp description: Connect your ClickUp workspace to SurfSense --- -# ClickUp Connector - -Sync your ClickUp tasks, docs, and content to SurfSense. - -## Prerequisites - -- A ClickUp account -- Access to the workspaces you want to connect - -## Setup - -1. Navigate to your Search Space settings -2. Click on **Add Connector** -3. Select **ClickUp** from the list -4. Authorize SurfSense to access your ClickUp workspace -5. Select the spaces and folders you want to index - -## What Gets Indexed - -- Tasks and subtasks -- Task descriptions and comments -- ClickUp Docs -- Custom fields - -## Sync Frequency - -The ClickUp connector supports scheduled syncing to keep your content up to date. - +# Documentation in progress \ No newline at end of file diff --git a/surfsense_web/content/docs/connectors/confluence.mdx b/surfsense_web/content/docs/connectors/confluence.mdx index 17643a86d..aa220fcbe 100644 --- a/surfsense_web/content/docs/connectors/confluence.mdx +++ b/surfsense_web/content/docs/connectors/confluence.mdx @@ -3,32 +3,104 @@ title: Confluence description: Connect your Confluence spaces to SurfSense --- -# Confluence Connector +# Confluence OAuth Integration Setup Guide -Index your Confluence pages, spaces, and documentation. +This guide walks you through setting up an Atlassian OAuth 2.0 (3LO) integration for SurfSense to connect your Confluence spaces. -## Prerequisites +## Step 1: Access the Developer Console -- A Confluence account (Cloud or Data Center) -- Access to the spaces you want to connect +1. Navigate to [developer.atlassian.com](https://developer.atlassian.com) +2. Click your profile icon in the top-right corner +3. Select **"Developer console"** from the dropdown -## Setup +![Atlassian Developer Console Access](/docs/connectors/atlassian/atlassian-dev-console-access.png) -1. Navigate to your Search Space settings -2. Click on **Add Connector** -3. Select **Confluence** from the list -4. Enter your Confluence instance URL and credentials -5. Select the spaces you want to index +## Step 2: Create a New OAuth 2.0 Integration -## What Gets Indexed +1. In the Developer Console, under **My apps**, click the **"Create"** button +2. Select **"OAuth 2.0 integration"** from the dropdown -- Pages and blog posts -- Page comments -- Attachments -- Space documentation -- Page hierarchy +![Create OAuth 2.0 Integration](/docs/connectors/atlassian/atlassian-create-app.png) -## Sync Frequency +## Step 3: Name Your Integration -The Confluence connector supports scheduled syncing to keep your content up to date. +1. Enter **Name**: `SurfSense` +2. Check the box to agree to Atlassian's developer terms +3. Click **"Create"** +> â„šī¸ New OAuth 2.0 integrations use rotating refresh tokens, which improve security by limiting token validity and enabling automatic detection of token reuse. + +![Create New Integration Form](/docs/connectors/atlassian/atlassian-name-integration.png) + +## Step 4: Configure Callback URL + +1. In the left sidebar, click **"Authorization"** +2. Under **Callback URLs**, enter the redirect URI: + ``` + http://localhost:8000/api/v1/auth/confluence/connector/callback + ``` +3. Click **"Save changes"** + +> â„šī¸ You can enter up to 10 redirect URIs, one per line. + +![Authorization Callback URLs](/docs/connectors/atlassian/atlassian-authorization.png) + +## Step 5: Configure API Permissions + +1. In the left sidebar, click **"Permissions"** +2. You'll see a list of available APIs including Confluence API + +![Permissions Overview](/docs/connectors/atlassian/atlassian-permissions.png) + +## Step 6: Configure Confluence API Scopes + +1. Click **"Configure"** next to **Confluence API** + +### Classic Scopes + +Select the **"Classic scopes"** tab and enable: + +| Scope Name | Code | Description | +|------------|------|-------------| +| ✅ Read user | `read:confluence-user` | View user information in Confluence that you have access to, including usernames, email addresses and profile pictures | + +![Confluence API Classic Scopes](/docs/connectors/atlassian/confluence/atlassian-confluence-classic-scopes.png) + +### Granular Scopes + +Select the **"Granular scopes"** tab and enable: + +| Scope Name | Code | Description | +|------------|------|-------------| +| ✅ View pages | `read:page:confluence` | View page content | +| ✅ View comments | `read:comment:confluence` | View comments on pages or blogposts | +| ✅ View spaces | `read:space:confluence` | View space details | + +4. Click **"Save"** + +![Confluence API Granular Scopes](/docs/connectors/atlassian/confluence/atlassian-confluence-granular-scopes.png) + +## Step 7: Get OAuth Credentials + +1. In the left sidebar, click **"Settings"** +2. Copy your **Client ID** and **Client Secret** + +> âš ī¸ Never share your client secret publicly or include it in code repositories. + +--- + +## Running SurfSense with Confluence Connector + +Add the Atlassian environment variables to your Docker run command: + +```bash +docker run -d -p 3000:3000 -p 8000:8000 \ + -v surfsense-data:/data \ + # Confluence Connector + -e ATLASSIAN_CLIENT_ID=your_atlassian_client_id \ + -e ATLASSIAN_CLIENT_SECRET=your_atlassian_client_secret \ + -e CONFLUENCE_REDIRECT_URI=http://localhost:8000/api/v1/auth/confluence/connector/callback \ + --name surfsense \ + --restart unless-stopped \ + ghcr.io/modsetter/surfsense:latest +``` diff --git a/surfsense_web/content/docs/connectors/discord.mdx b/surfsense_web/content/docs/connectors/discord.mdx index 2dd2c1205..6bb64e7e7 100644 --- a/surfsense_web/content/docs/connectors/discord.mdx +++ b/surfsense_web/content/docs/connectors/discord.mdx @@ -3,30 +3,74 @@ title: Discord description: Connect your Discord servers to SurfSense --- -# Discord Connector +# Discord OAuth Integration Setup Guide -Index your Discord server conversations and content. +This guide walks you through setting up a Discord OAuth integration for SurfSense. -## Prerequisites +## Step 1: Create a New Discord Application -- A Discord account -- Server admin permissions +1. Navigate to [discord.com/developers/applications](https://discord.com/developers/applications) +2. Click **"New Application"** +3. Enter the application name: `SurfSense` +4. Click **"Create"** -## Setup +## Step 2: Configure General Information -1. Navigate to your Search Space settings -2. Click on **Add Connector** -3. Select **Discord** from the list -4. Authorize SurfSense to access your Discord server -5. Select the channels you want to index +On the **General Information** page, fill in the details: -## What Gets Indexed +| Field | Value | +|-------|-------| +| **App Icon** | Upload an icon (1024x1024px, PNG/GIF/JPG/WEBP, max 10MB) | +| **Name** | `SurfSense` | +| **Description** | Connect any LLM to your internal knowledge sources and chat with it in real time alongside your team. | +| **Tags** | Add up to 5 tags (optional) | -- Text channel messages -- Thread messages -- Shared files and links +You'll also see your **Application ID** and **Public Key** on this page. -## Sync Frequency +![General Information](/docs/connectors/discord/discord-general-info.png) -The Discord connector supports scheduled syncing to keep your content up to date. +## Step 3: Configure OAuth2 Settings +1. In the left sidebar, click **"OAuth2"** +2. Copy your **Client ID** and **Client Secret** (click to reveal) +3. Under **Redirects**, click **"Add Another"** and enter: + ``` + http://localhost:8000/api/v1/auth/discord/connector/callback + ``` + +> âš ī¸ Keep **Public Client** disabled (off) since SurfSense uses a server to make requests. + +![OAuth2 Configuration](/docs/connectors/discord/discord-oauth2.png) + +## Step 4: Configure Bot Settings + +1. In the left sidebar, click **"Bot"** +2. Configure the **Authorization Flow**: + - ✅ **Public Bot** - Enable to allow anyone to add the bot to servers + +3. Enable **Privileged Gateway Intents**: + - ✅ **Server Members Intent** - Required to receive GUILD_MEMBERS events + - ✅ **Message Content Intent** - Required to receive message content + +> âš ī¸ Once your bot reaches 100+ servers, these intents will require verification and approval. + +![Bot Settings](/docs/connectors/discord/discord-bot-settings.png) + +--- + +## Running SurfSense with Discord Connector + +Add the Discord environment variables to your Docker run command: + +```bash +docker run -d -p 3000:3000 -p 8000:8000 \ + -v surfsense-data:/data \ + # Discord Connector + -e DISCORD_CLIENT_ID=your_discord_client_id \ + -e DISCORD_CLIENT_SECRET=your_discord_client_secret \ + -e DISCORD_REDIRECT_URI=http://localhost:8000/api/v1/auth/discord/connector/callback \ + -e DISCORD_BOT_TOKEN=http://localhost:8000/api/v1/auth/discord/connector/callback \ + --name surfsense \ + --restart unless-stopped \ + ghcr.io/modsetter/surfsense:latest +``` diff --git a/surfsense_web/content/docs/connectors/elasticsearch.mdx b/surfsense_web/content/docs/connectors/elasticsearch.mdx index 8fb003253..ac43cca4e 100644 --- a/surfsense_web/content/docs/connectors/elasticsearch.mdx +++ b/surfsense_web/content/docs/connectors/elasticsearch.mdx @@ -3,30 +3,4 @@ title: Elasticsearch description: Connect your Elasticsearch cluster to SurfSense --- -# Elasticsearch Connector - -Index data from your Elasticsearch cluster. - -## Prerequisites - -- An Elasticsearch cluster -- Access credentials - -## Setup - -1. Navigate to your Search Space settings -2. Click on **Add Connector** -3. Select **Elasticsearch** from the list -4. Enter your Elasticsearch cluster URL and credentials -5. Configure the indices you want to index - -## What Gets Indexed - -- Documents from specified indices -- Custom field mappings -- Metadata - -## Sync Frequency - -The Elasticsearch connector supports scheduled syncing to keep your data up to date. - +# Documentation in progress \ No newline at end of file diff --git a/surfsense_web/content/docs/connectors/github.mdx b/surfsense_web/content/docs/connectors/github.mdx index 90bb91a96..bb2faca81 100644 --- a/surfsense_web/content/docs/connectors/github.mdx +++ b/surfsense_web/content/docs/connectors/github.mdx @@ -3,32 +3,4 @@ title: GitHub description: Connect your GitHub repositories to SurfSense --- -# GitHub Connector - -Index your GitHub repositories, issues, pull requests, and documentation. - -## Prerequisites - -- A GitHub account -- Access to the repositories you want to connect - -## Setup - -1. Navigate to your Search Space settings -2. Click on **Add Connector** -3. Select **GitHub** from the list -4. Authorize SurfSense to access your GitHub account -5. Select the repositories you want to index - -## What Gets Indexed - -- Repository README and documentation -- Issues and issue comments -- Pull requests and PR comments -- Code files (configurable) -- Discussions - -## Sync Frequency - -The GitHub connector supports scheduled syncing to keep your content up to date. - +# Documentation in progress \ No newline at end of file diff --git a/surfsense_web/content/docs/connectors/gmail.mdx b/surfsense_web/content/docs/connectors/gmail.mdx index ac5486ce6..6c08804fc 100644 --- a/surfsense_web/content/docs/connectors/gmail.mdx +++ b/surfsense_web/content/docs/connectors/gmail.mdx @@ -3,32 +3,81 @@ title: Gmail description: Connect your Gmail to SurfSense --- -# Gmail Connector +# Gmail OAuth Integration Setup Guide -Index your Gmail emails and make them searchable. +This guide walks you through setting up a Google OAuth 2.0 integration for SurfSense to connect your Gmail account. -## Prerequisites +## Step 1: Access the Google Cloud Console -- A Google account -- Google OAuth configured in SurfSense (see [Prerequisites](/docs)) -- Gmail API enabled in Google Cloud Console +1. Navigate to [Google Cloud Console](https://console.cloud.google.com/) +2. Select an existing project or create a new one -## Setup +## Step 2: Enable Required APIs -1. Navigate to your Search Space settings -2. Click on **Add Connector** -3. Select **Gmail** from the list -4. Authorize SurfSense to access your Gmail -5. Configure which labels/folders to index +1. Go to **APIs & Services** > **Library** +2. Search for and enable the following APIs: + - **People API** (required for Google OAuth) + - **Gmail API** (required for Gmail connector) -## What Gets Indexed +![Google Developer Console People API](/docs/connectors/google/google_oauth_people_api.png) -- Email content -- Email attachments -- Thread conversations -- Labels and categories +## Step 3: Configure OAuth Consent Screen -## Sync Frequency +1. Go to **APIs & Services** > **OAuth consent screen** +2. Select **External** user type (or Internal if using Google Workspace) +3. Fill in the required information: + - **App name**: `SurfSense` + - **User support email**: Your email address + - **Developer contact information**: Your email address +4. Click **Save and Continue** -The Gmail connector supports scheduled syncing to keep your emails indexed. +![Google Developer Console OAuth consent screen](/docs/connectors/google/google_oauth_screen.png) +### Add Scopes + +1. Click **Add or Remove Scopes** +2. Add the following scopes: + - `https://www.googleapis.com/auth/gmail.readonly` - Read Gmail messages + - `https://www.googleapis.com/auth/userinfo.email` - View user email address +3. Click **Update** and then **Save and Continue** + +## Step 4: Create OAuth Client ID + +1. Go to **APIs & Services** > **Credentials** +2. Click **Create Credentials** > **OAuth client ID** +3. Select **Web application** as the application type +4. Enter **Name**: `SurfSense` +5. Under **Authorized redirect URIs**, add: + ``` + http://localhost:8000/api/v1/auth/google/gmail/connector/callback + ``` +6. Click **Create** + +![Google Developer Console OAuth client ID](/docs/connectors/google/google_oauth_client.png) + +## Step 5: Get OAuth Credentials + +1. After creating the OAuth client, you'll see a dialog with your credentials +2. Copy your **Client ID** and **Client Secret** + +> âš ī¸ Never share your client secret publicly or include it in code repositories. + +![Google Developer Console Config](/docs/connectors/google/google_oauth_config.png) + +--- + +## Running SurfSense with Gmail Connector + +Add the Google OAuth environment variables to your Docker run command: + +```bash +docker run -d -p 3000:3000 -p 8000:8000 \ + -v surfsense-data:/data \ + # Gmail Connector + -e GOOGLE_OAUTH_CLIENT_ID=your_google_client_id \ + -e GOOGLE_OAUTH_CLIENT_SECRET=your_google_client_secret \ + -e GOOGLE_GMAIL_REDIRECT_URI=http://localhost:8000/api/v1/auth/google/gmail/connector/callback \ + --name surfsense \ + --restart unless-stopped \ + ghcr.io/modsetter/surfsense:latest +``` diff --git a/surfsense_web/content/docs/connectors/google-calendar.mdx b/surfsense_web/content/docs/connectors/google-calendar.mdx index 76b3ea588..e6ae4d593 100644 --- a/surfsense_web/content/docs/connectors/google-calendar.mdx +++ b/surfsense_web/content/docs/connectors/google-calendar.mdx @@ -3,32 +3,80 @@ title: Google Calendar description: Connect your Google Calendar to SurfSense --- -# Google Calendar Connector +# Google Calendar OAuth Integration Setup Guide -Index your Google Calendar events and make them searchable. +This guide walks you through setting up a Google OAuth 2.0 integration for SurfSense to connect your Google Calendar. -## Prerequisites +## Step 1: Access the Google Cloud Console -- A Google account -- Google OAuth configured in SurfSense (see [Prerequisites](/docs)) -- Google Calendar API enabled in Google Cloud Console +1. Navigate to [Google Cloud Console](https://console.cloud.google.com/) +2. Select an existing project or create a new one -## Setup +## Step 2: Enable Required APIs -1. Navigate to your Search Space settings -2. Click on **Add Connector** -3. Select **Google Calendar** from the list -4. Authorize SurfSense to access your Google Calendar -5. Select which calendars to index +1. Go to **APIs & Services** > **Library** +2. Search for and enable the following APIs: + - **People API** (required for Google OAuth) + - **Google Calendar API** (required for Calendar connector) -## What Gets Indexed +![Google Developer Console People API](/docs/connectors/google/google_oauth_people_api.png) -- Event titles and descriptions -- Event attendees -- Meeting notes -- Recurring events +## Step 3: Configure OAuth Consent Screen -## Sync Frequency +1. Go to **APIs & Services** > **OAuth consent screen** +2. Select **External** user type (or Internal if using Google Workspace) +3. Fill in the required information: + - **App name**: `SurfSense` + - **User support email**: Your email address + - **Developer contact information**: Your email address +4. Click **Save and Continue** -The Google Calendar connector supports scheduled syncing to keep your events indexed. +![Google Developer Console OAuth consent screen](/docs/connectors/google/google_oauth_screen.png) +### Add Scopes + +1. Click **Add or Remove Scopes** +2. Add the following scope: + - `https://www.googleapis.com/auth/calendar.readonly` - Read Google Calendar events +3. Click **Update** and then **Save and Continue** + +## Step 4: Create OAuth Client ID + +1. Go to **APIs & Services** > **Credentials** +2. Click **Create Credentials** > **OAuth client ID** +3. Select **Web application** as the application type +4. Enter **Name**: `SurfSense` +5. Under **Authorized redirect URIs**, add: + ``` + http://localhost:8000/api/v1/auth/google/calendar/connector/callback + ``` +6. Click **Create** + +![Google Developer Console OAuth client ID](/docs/connectors/google/google_oauth_client.png) + +## Step 5: Get OAuth Credentials + +1. After creating the OAuth client, you'll see a dialog with your credentials +2. Copy your **Client ID** and **Client Secret** + +> âš ī¸ Never share your client secret publicly or include it in code repositories. + +![Google Developer Console Config](/docs/connectors/google/google_oauth_config.png) + +--- + +## Running SurfSense with Google Calendar Connector + +Add the Google OAuth environment variables to your Docker run command: + +```bash +docker run -d -p 3000:3000 -p 8000:8000 \ + -v surfsense-data:/data \ + # Google Calendar Connector + -e GOOGLE_OAUTH_CLIENT_ID=your_google_client_id \ + -e GOOGLE_OAUTH_CLIENT_SECRET=your_google_client_secret \ + -e GOOGLE_CALENDAR_REDIRECT_URI=http://localhost:8000/api/v1/auth/google/calendar/connector/callback \ + --name surfsense \ + --restart unless-stopped \ + ghcr.io/modsetter/surfsense:latest +``` diff --git a/surfsense_web/content/docs/connectors/google-drive.mdx b/surfsense_web/content/docs/connectors/google-drive.mdx index 6538e24b5..f2b0105fc 100644 --- a/surfsense_web/content/docs/connectors/google-drive.mdx +++ b/surfsense_web/content/docs/connectors/google-drive.mdx @@ -3,32 +3,81 @@ title: Google Drive description: Connect your Google Drive to SurfSense --- -# Google Drive Connector +# Google Drive OAuth Integration Setup Guide -Index your Google Drive files, documents, and shared content. +This guide walks you through setting up a Google OAuth 2.0 integration for SurfSense to connect your Google Drive. -## Prerequisites +## Step 1: Access the Google Cloud Console -- A Google account -- Google OAuth configured in SurfSense (see [Prerequisites](/docs)) +1. Navigate to [Google Cloud Console](https://console.cloud.google.com/) +2. Select an existing project or create a new one -## Setup +## Step 2: Enable Required APIs -1. Navigate to your Search Space settings -2. Click on **Add Connector** -3. Select **Google Drive** from the list -4. Authorize SurfSense to access your Google Drive -5. Select the folders you want to index +1. Go to **APIs & Services** > **Library** +2. Search for and enable the following APIs: + - **People API** (required for Google OAuth) + - **Google Drive API** (required for Drive connector) -## What Gets Indexed +![Google Developer Console People API](/docs/connectors/google/google_oauth_people_api.png) -- Google Docs -- Google Sheets -- Google Slides -- PDFs and other documents -- Shared files +## Step 3: Configure OAuth Consent Screen -## Sync Frequency +1. Go to **APIs & Services** > **OAuth consent screen** +2. Select **External** user type (or Internal if using Google Workspace) +3. Fill in the required information: + - **App name**: `SurfSense` + - **User support email**: Your email address + - **Developer contact information**: Your email address +4. Click **Save and Continue** -The Google Drive connector supports scheduled syncing to keep your content up to date. +![Google Developer Console OAuth consent screen](/docs/connectors/google/google_oauth_screen.png) +### Add Scopes + +1. Click **Add or Remove Scopes** +2. Add the following scopes: + - `https://www.googleapis.com/auth/drive.readonly` - Read-only access to Google Drive + - `https://www.googleapis.com/auth/userinfo.email` - View user email address +3. Click **Update** and then **Save and Continue** + +## Step 4: Create OAuth Client ID + +1. Go to **APIs & Services** > **Credentials** +2. Click **Create Credentials** > **OAuth client ID** +3. Select **Web application** as the application type +4. Enter **Name**: `SurfSense` +5. Under **Authorized redirect URIs**, add: + ``` + http://localhost:8000/api/v1/auth/google/drive/connector/callback + ``` +6. Click **Create** + +![Google Developer Console OAuth client ID](/docs/connectors/google/google_oauth_client.png) + +## Step 5: Get OAuth Credentials + +1. After creating the OAuth client, you'll see a dialog with your credentials +2. Copy your **Client ID** and **Client Secret** + +> âš ī¸ Never share your client secret publicly or include it in code repositories. + +![Google Developer Console Config](/docs/connectors/google/google_oauth_config.png) + +--- + +## Running SurfSense with Google Drive Connector + +Add the Google OAuth environment variables to your Docker run command: + +```bash +docker run -d -p 3000:3000 -p 8000:8000 \ + -v surfsense-data:/data \ + # Google Drive Connector + -e GOOGLE_OAUTH_CLIENT_ID=your_google_client_id \ + -e GOOGLE_OAUTH_CLIENT_SECRET=your_google_client_secret \ + -e GOOGLE_DRIVE_REDIRECT_URI=http://localhost:8000/api/v1/auth/google/drive/connector/callback \ + --name surfsense \ + --restart unless-stopped \ + ghcr.io/modsetter/surfsense:latest +``` diff --git a/surfsense_web/content/docs/connectors/jira.mdx b/surfsense_web/content/docs/connectors/jira.mdx index 9c086d24b..9d00a56af 100644 --- a/surfsense_web/content/docs/connectors/jira.mdx +++ b/surfsense_web/content/docs/connectors/jira.mdx @@ -3,32 +3,91 @@ title: Jira description: Connect your Jira projects to SurfSense --- -# Jira Connector +# Jira OAuth Integration Setup Guide -Sync your Jira issues, projects, and documentation to SurfSense. +This guide walks you through setting up an Atlassian OAuth 2.0 (3LO) integration for SurfSense to connect your Jira projects. -## Prerequisites +## Step 1: Access the Developer Console -- A Jira account (Cloud or Data Center) -- Access to the projects you want to connect +1. Navigate to [developer.atlassian.com](https://developer.atlassian.com) +2. Click your profile icon in the top-right corner +3. Select **"Developer console"** from the dropdown -## Setup +![Atlassian Developer Console Access](/docs/connectors/atlassian/atlassian-dev-console-access.png) -1. Navigate to your Search Space settings -2. Click on **Add Connector** -3. Select **Jira** from the list -4. Enter your Jira instance URL and credentials -5. Select the projects you want to index +## Step 2: Create a New OAuth 2.0 Integration -## What Gets Indexed +1. In the Developer Console, under **My apps**, click the **"Create"** button +2. Select **"OAuth 2.0 integration"** from the dropdown -- Issues and subtasks -- Issue descriptions and comments -- Attachments -- Custom fields -- Project documentation +![Create OAuth 2.0 Integration](/docs/connectors/atlassian/atlassian-create-app.png) -## Sync Frequency +## Step 3: Name Your Integration -The Jira connector supports scheduled syncing to keep your content up to date. +1. Enter **Name**: `SurfSense` +2. Check the box to agree to Atlassian's developer terms +3. Click **"Create"** +> â„šī¸ New OAuth 2.0 integrations use rotating refresh tokens, which improve security by limiting token validity and enabling automatic detection of token reuse. + +![Create New Integration Form](/docs/connectors/atlassian/atlassian-name-integration.png) + +## Step 4: Configure Callback URL + +1. In the left sidebar, click **"Authorization"** +2. Under **Callback URLs**, enter the redirect URI: + ``` + http://localhost:8000/api/v1/auth/jira/connector/callback + ``` +3. Click **"Save changes"** + +> â„šī¸ You can enter up to 10 redirect URIs, one per line. + +![Authorization Callback URLs](/docs/connectors/atlassian/atlassian-authorization.png) + +## Step 5: Configure API Permissions + +1. In the left sidebar, click **"Permissions"** +2. You'll see a list of available APIs including Jira API + +![Permissions Overview](/docs/connectors/atlassian/atlassian-permissions.png) + +## Step 6: Configure Jira API Scopes + +1. Click **"Configure"** next to **Jira API** +2. Select the **"Classic scopes"** tab +3. Under **Jira platform REST API**, select the following scopes: + +| Scope Name | Code | Description | +|------------|------|-------------| +| ✅ View Jira issue data | `read:jira-work` | Read Jira project and issue data, search for issues, and objects associated with issues like attachments and worklogs | +| ✅ View user profiles | `read:jira-user` | View user information in Jira that the user has access to, including usernames, email addresses, and avatars | + +4. Click **"Save"** + +![Jira API Scopes](/docs/connectors/atlassian/jira/atlassian-jira-scopes.png) + +## Step 7: Get OAuth Credentials + +1. In the left sidebar, click **"Settings"** +2. Copy your **Client ID** and **Client Secret** + +> âš ī¸ Never share your client secret publicly or include it in code repositories. + +--- + +## Running SurfSense with Jira Connector + +Add the Atlassian environment variables to your Docker run command: + +```bash +docker run -d -p 3000:3000 -p 8000:8000 \ + -v surfsense-data:/data \ + # Jira Connector + -e ATLASSIAN_CLIENT_ID=your_atlassian_client_id \ + -e ATLASSIAN_CLIENT_SECRET=your_atlassian_client_secret \ + -e JIRA_REDIRECT_URI=http://localhost:8000/api/v1/auth/jira/connector/callback \ + --name surfsense \ + --restart unless-stopped \ + ghcr.io/modsetter/surfsense:latest +``` diff --git a/surfsense_web/content/docs/connectors/linear.mdx b/surfsense_web/content/docs/connectors/linear.mdx index 20b31cabc..f9dc9a62b 100644 --- a/surfsense_web/content/docs/connectors/linear.mdx +++ b/surfsense_web/content/docs/connectors/linear.mdx @@ -3,31 +3,65 @@ title: Linear description: Connect your Linear workspace to SurfSense --- -# Linear Connector +# Linear OAuth Integration Setup Guide -Sync your Linear issues, projects, and documentation to SurfSense. +This guide walks you through setting up a Linear OAuth integration for SurfSense. -## Prerequisites +## Step 1: Access Linear API Settings -- A Linear account -- Access to the teams you want to connect +1. Navigate to your workspace's API settings at `linear.app//settings/api` +2. Under **OAuth Applications**, click **"+ New OAuth application"** -## Setup +![Linear API Settings Page](/docs/connectors/linear/linear-api-settings.png) -1. Navigate to your Search Space settings -2. Click on **Add Connector** -3. Select **Linear** from the list -4. Authorize SurfSense to access your Linear workspace -5. Select the teams and projects you want to index +## Step 2: Create New Application -## What Gets Indexed +Fill in the application details: -- Issues and sub-issues -- Issue descriptions and comments -- Project documentation -- Roadmap items +| Field | Value | +|-------|-------| +| **Application icon** | Upload an icon (at least 256x256px) | +| **Application name** | `SurfSense` | +| **Developer name** | `SurfSense` | +| **Developer URL** | `https://www.surfsense.com/` | +| **Description** | Connect any LLM to your internal knowledge sources and chat with it in real time alongside your team. | +| **Callback URLs** | `http://localhost:8000/api/v1/auth/linear/connector/callback` | +| **GitHub username** | Your GitHub username (optional) | -## Sync Frequency +### Settings -The Linear connector supports scheduled syncing to keep your content up to date. +- ✅ **Public** - Enable this to allow the application to be installed by other workspaces + +Click **Create** to create the application. + +![Create New Application Form](/docs/connectors/linear/linear-new-application.png) + +## Step 3: Get OAuth Credentials + +After creating the application, you'll see your OAuth credentials: + +1. Copy your **Client ID** +2. Copy your **Client Secret** + +> âš ī¸ Never share your client secret publicly. + +![OAuth Credentials](/docs/connectors/linear/linear-oauth-credentials.png) + +--- + +## Running SurfSense with Linear Connector + +Add the Linear environment variables to your Docker run command: + +```bash +docker run -d -p 3000:3000 -p 8000:8000 \ + -v surfsense-data:/data \ + # Linear Connector + -e LINEAR_CLIENT_ID=your_linear_client_id \ + -e LINEAR_CLIENT_SECRET=your_linear_client_secret \ + -e LINEAR_REDIRECT_URI=http://localhost:8000/api/v1/auth/linear/connector/callback \ + --name surfsense \ + --restart unless-stopped \ + ghcr.io/modsetter/surfsense:latest +``` diff --git a/surfsense_web/content/docs/connectors/luma.mdx b/surfsense_web/content/docs/connectors/luma.mdx index 8a244df07..e16e5a949 100644 --- a/surfsense_web/content/docs/connectors/luma.mdx +++ b/surfsense_web/content/docs/connectors/luma.mdx @@ -3,31 +3,4 @@ title: Luma description: Connect your Luma events to SurfSense --- -# Luma Connector - -Index your Luma events and event content. - -## Prerequisites - -- A Luma account -- API access - -## Setup - -1. Navigate to your Search Space settings -2. Click on **Add Connector** -3. Select **Luma** from the list -4. Authorize SurfSense to access your Luma account -5. Select the events you want to index - -## What Gets Indexed - -- Event details and descriptions -- Event schedules -- Attendee information (if authorized) -- Event updates - -## Sync Frequency - -The Luma connector supports scheduled syncing to keep your events up to date. - +# Documentation in progress \ No newline at end of file diff --git a/surfsense_web/content/docs/connectors/meta.json b/surfsense_web/content/docs/connectors/meta.json index 82e04e44f..7a075fbb5 100644 --- a/surfsense_web/content/docs/connectors/meta.json +++ b/surfsense_web/content/docs/connectors/meta.json @@ -1,22 +1,22 @@ { "title": "Connectors", "pages": [ - "notion", - "slack", - "discord", - "clickup", - "github", - "jira", - "linear", "google-drive", "gmail", "google-calendar", + "notion", + "slack", + "discord", + "jira", + "linear", "confluence", - "bookstack", "airtable", + "clickup", + "github", + "luma", + "circleback", "elasticsearch", - "web-crawler", - "luma" + "bookstack" ], "defaultOpen": true } diff --git a/surfsense_web/content/docs/connectors/notion.mdx b/surfsense_web/content/docs/connectors/notion.mdx index 784875e3c..936972f7e 100644 --- a/surfsense_web/content/docs/connectors/notion.mdx +++ b/surfsense_web/content/docs/connectors/notion.mdx @@ -3,31 +3,82 @@ title: Notion description: Connect your Notion workspaces to SurfSense --- -# Notion Connector +# Notion OAuth Integration Setup Guide -Connect your Notion workspaces to index pages, databases, and content. +This guide walks you through setting up a Notion OAuth integration for SurfSense. -## Prerequisites +## Step 1: Access Notion Integrations -- A Notion account -- Access to the workspaces you want to connect +1. Navigate to [notion.so/profile/integrations](https://notion.so/profile/integrations) +2. Click the **"New integration"** button -## Setup +![Notion Integrations Page](/docs/connectors/notion/notion-integrations-page.png) -1. Navigate to your Search Space settings -2. Click on **Add Connector** -3. Select **Notion** from the list -4. Authorize SurfSense to access your Notion workspace -5. Select the pages and databases you want to index +## Step 2: Configure New Integration -## What Gets Indexed +Fill in the integration details: -- Pages and subpages -- Database entries -- Comments and discussions -- Embedded content +| Field | Value | +|-------|-------| +| **Integration Name** | `SurfSense` | +| **Associated workspace** | Select your workspace | +| **Type** | `Public` | +| **Company name** | Your company name | +| **Website** | Your website URL | +| **Tagline** | Brief description | +| **Privacy Policy URL** | Your privacy policy URL | +| **Terms of Use URL** | Your terms of use URL | +| **Email** | Your developer email | +| **Logo** | Upload a 512x512 logo | -## Sync Frequency +### OAuth Redirect URI -The Notion connector supports scheduled syncing to keep your content up to date. +Under **OAuth domains & URIs**, set the **Redirect URI** to: +``` +http://localhost:8000/api/v1/auth/notion/connector/callback +``` + +Click **Save** to create the integration. + +![New Integration Form](/docs/connectors/notion/notion-new-integration-form.png) + +## Step 3: Get OAuth Credentials & Configure Capabilities + +After creating the integration, you'll see the configuration page with your credentials: + +1. Copy your **OAuth Client ID** +2. Copy your **OAuth Client Secret** (click Refresh if needed) + +### Set Required Capabilities + +Under **Content Capabilities**, enable: +- ✅ Read content + +Under **Comment Capabilities**, enable: +- ✅ Read comments + +Under **User Capabilities**, select: +- 🔘 Read user information including email addresses + +Click **Save** to apply the capabilities. + +![Integration Configuration](/docs/connectors/notion/notion-integration-config.png) + +--- + +## Running SurfSense with Notion Connector + +Add the Notion environment variables to your Docker run command: + +```bash +docker run -d -p 3000:3000 -p 8000:8000 \ + -v surfsense-data:/data \ + # Notion Connector + -e NOTION_OAUTH_CLIENT_ID=your_notion_client_id \ + -e NOTION_OAUTH_CLIENT_SECRET=your_notion_client_secret \ + -e NOTION_REDIRECT_URI=http://localhost:8000/api/v1/auth/notion/connector/callback \ + --name surfsense \ + --restart unless-stopped \ + ghcr.io/modsetter/surfsense:latest +``` diff --git a/surfsense_web/content/docs/connectors/slack.mdx b/surfsense_web/content/docs/connectors/slack.mdx index 089ccf67d..838408cd7 100644 --- a/surfsense_web/content/docs/connectors/slack.mdx +++ b/surfsense_web/content/docs/connectors/slack.mdx @@ -3,31 +3,89 @@ title: Slack description: Connect your Slack workspace to SurfSense --- -# Slack Connector +# Slack OAuth Integration Setup Guide -Index your Slack conversations and make them searchable. +This guide walks you through setting up a Slack OAuth integration for SurfSense. -## Prerequisites +## Step 1: Create a New Slack App -- A Slack workspace -- Admin permissions to install apps +1. Navigate to [api.slack.com/apps](https://api.slack.com/apps) +2. Click **"Create New App"** +3. Select **"From scratch"** to manually configure your app -## Setup +![Create an App Dialog](/docs/connectors/slack/slack-create-app.png) -1. Navigate to your Search Space settings -2. Click on **Add Connector** -3. Select **Slack** from the list -4. Authorize SurfSense to access your Slack workspace -5. Select the channels you want to index +## Step 2: Name App & Choose Workspace -## What Gets Indexed +1. Enter **App Name**: `SurfSense` +2. Select the workspace to develop your app in +3. Click **"Create App"** -- Public channel messages -- Private channels (if authorized) -- Thread replies -- Shared files and links +> âš ī¸ You won't be able to change the workspace later. The workspace will control the app even if you leave it. -## Sync Frequency +![Name App & Choose Workspace](/docs/connectors/slack/slack-name-workspace.png) -The Slack connector supports scheduled syncing to keep your conversations indexed. +## Step 3: Get App Credentials +After creating the app, you'll be taken to the **Basic Information** page. Here you'll find your credentials: + +1. Copy your **Client ID** +2. Copy your **Client Secret** (click Show to reveal) + +> âš ī¸ Never share your app credentials publicly or include them in code repositories. + +![Basic Information - App Credentials](/docs/connectors/slack/slack-app-credentials.png) + +## Step 4: Configure Redirect URLs + +1. In the left sidebar, click **"OAuth & Permissions"** +2. Scroll down to **Redirect URLs** +3. Click **"Add New Redirect URL"** +4. Enter: `https://localhost:8000/api/v1/auth/slack/connector/callback` +5. Click **"Add"**, then **"Save URLs"** + +![Redirect URLs Configuration](/docs/connectors/slack/slack-redirect-urls.png) + +## Step 5: Configure Bot Token Scopes + +On the same **OAuth & Permissions** page, scroll to **Scopes** and add the following **Bot Token Scopes**: + +| OAuth Scope | Description | +|-------------|-------------| +| `channels:history` | View messages and other content in public channels | +| `channels:read` | View basic information about public channels | +| `groups:history` | View messages and other content in private channels | +| `groups:read` | View basic information about private channels | +| `im:history` | View messages and other content in direct messages | +| `mpim:history` | View messages and other content in group direct messages | +| `users:read` | View people in a workspace | + +Click **"Add an OAuth Scope"** to add each scope. + +![Bot Token Scopes](/docs/connectors/slack/slack-scopes.png) + +## Step 6: Enable Public Distribution + +1. In the left sidebar, click **"Manage Distribution"** +2. Under **Share Your App with Other Workspaces**, ensure distribution is enabled +3. You can use the **"Add to Slack"** button or **Sharable URL** to install the app + +![Manage Distribution](/docs/connectors/slack/slack-distribution.png) + +--- + +## Running SurfSense with Slack Connector + +Add the Slack environment variables to your Docker run command: + +```bash +docker run -d -p 3000:3000 -p 8000:8000 \ + -v surfsense-data:/data \ + # Slack Connector + -e SLACK_CLIENT_ID=your_slack_client_id \ + -e SLACK_CLIENT_SECRET=your_slack_client_secret \ + -e SLACK_REDIRECT_URI=https://localhost:8000/api/v1/auth/slack/connector/callback \ + --name surfsense \ + --restart unless-stopped \ + ghcr.io/modsetter/surfsense:latest +``` diff --git a/surfsense_web/content/docs/connectors/web-crawler.mdx b/surfsense_web/content/docs/connectors/web-crawler.mdx index 2a23dea1a..6ea5b1c2b 100644 --- a/surfsense_web/content/docs/connectors/web-crawler.mdx +++ b/surfsense_web/content/docs/connectors/web-crawler.mdx @@ -3,36 +3,4 @@ title: Web Crawler description: Crawl and index websites with SurfSense --- -# Web Crawler Connector - -Crawl and index public websites to make them searchable. - -## Prerequisites - -- Firecrawl API key (see [Prerequisites](/docs)) - -## Setup - -1. Navigate to your Search Space settings -2. Click on **Add Connector** -3. Select **Web Crawler** from the list -4. Enter the URL(s) you want to crawl -5. Configure crawl depth and settings - -## What Gets Indexed - -- Web page content -- Page titles and metadata -- Links and navigation -- Images and media (configurable) - -## Configuration Options - -- **Crawl Depth**: How many levels deep to crawl -- **Include/Exclude Patterns**: Filter which URLs to index -- **Rate Limiting**: Control crawl speed - -## Sync Frequency - -The Web Crawler connector supports scheduled re-crawling to keep your content up to date. - +# Documentation in progress \ No newline at end of file diff --git a/surfsense_web/content/docs/index.mdx b/surfsense_web/content/docs/index.mdx index 42f863176..bb07c5f68 100644 --- a/surfsense_web/content/docs/index.mdx +++ b/surfsense_web/content/docs/index.mdx @@ -15,15 +15,13 @@ To set up Google OAuth: 1. Login to your [Google Developer Console](https://console.cloud.google.com/) 2. Enable the required APIs: - **People API** (required for basic Google OAuth) - - **Gmail API** (required if you want to use the Gmail connector) - - **Google Calendar API** (required if you want to use the Google Calendar connector) -![Google Developer Console People API](/docs/google_oauth_people_api.png) +![Google Developer Console People API](/docs/connectors/google/google_oauth_people_api.png) 3. Set up OAuth consent screen. -![Google Developer Console OAuth consent screen](/docs/google_oauth_screen.png) +![Google Developer Console OAuth consent screen](/docs/connectors/google/google_oauth_screen.png) 4. Create OAuth client ID and secret. -![Google Developer Console OAuth client ID](/docs/google_oauth_client.png) +![Google Developer Console OAuth client ID](/docs/connectors/google/google_oauth_client.png) 5. It should look like this. -![Google Developer Console Config](/docs/google_oauth_config.png) +![Google Developer Console Config](/docs/connectors/google/google_oauth_config.png) --- diff --git a/surfsense_web/mdx-components.tsx b/surfsense_web/mdx-components.tsx index cea62b834..f6d86e543 100644 --- a/surfsense_web/mdx-components.tsx +++ b/surfsense_web/mdx-components.tsx @@ -7,12 +7,17 @@ import { AccordionTrigger, } from "@/components/ui/accordion"; import { cn } from "@/lib/utils"; +import Image, { type ImageProps } from "next/image"; export function getMDXComponents(components?: MDXComponents): MDXComponents { return { ...defaultMdxComponents, - img: ({ className, ...props }: React.ComponentProps<"img">) => ( - + img: ({ className, alt, ...props }: React.ComponentProps<"img">) => ( + {alt ), Video: ({ className, ...props }: React.ComponentProps<"video">) => (