diff --git a/surfsense_web/components/assistant-ui/connector-popup/connect-forms/components/github-connect-form.tsx b/surfsense_web/components/assistant-ui/connector-popup/connect-forms/components/github-connect-form.tsx index 72d5811d3..4fb9e93bf 100644 --- a/surfsense_web/components/assistant-ui/connector-popup/connect-forms/components/github-connect-form.tsx +++ b/surfsense_web/components/assistant-ui/connector-popup/connect-forms/components/github-connect-form.tsx @@ -129,7 +129,6 @@ export const GithubConnectForm: FC = ({ onSubmit, isSubmitting > Get your token {" "} - . diff --git a/surfsense_web/components/assistant-ui/connector-popup/connector-configs/components/github-config.tsx b/surfsense_web/components/assistant-ui/connector-popup/connector-configs/components/github-config.tsx index d5169b49d..2c28758b8 100644 --- a/surfsense_web/components/assistant-ui/connector-popup/connector-configs/components/github-config.tsx +++ b/surfsense_web/components/assistant-ui/connector-popup/connector-configs/components/github-config.tsx @@ -1,9 +1,8 @@ "use client"; -import { Info, KeyRound } from "lucide-react"; +import { KeyRound } from "lucide-react"; import type { FC } from "react"; -import { useEffect, useState } from "react"; -import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert"; +import { useEffect, useRef, useState } from "react"; import { Badge } from "@/components/ui/badge"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; @@ -13,25 +12,29 @@ export interface GithubConfigProps extends ConnectorConfigProps { onNameChange?: (name: string) => void; } +// Helper functions moved outside component to avoid useEffect dependency issues +const stringToArray = (arr: string[] | string | undefined): string[] => { + if (Array.isArray(arr)) return arr; + if (typeof arr === "string") { + return arr + .split(",") + .map((item) => item.trim()) + .filter((item) => item.length > 0); + } + return []; +}; + +const arrayToString = (arr: string[]): string => { + return arr.join(", "); +}; + export const GithubConfig: FC = ({ connector, onConfigChange, onNameChange, }) => { - const stringToArray = (arr: string[] | string | undefined): string[] => { - if (Array.isArray(arr)) return arr; - if (typeof arr === "string") { - return arr - .split(",") - .map((item) => item.trim()) - .filter((item) => item.length > 0); - } - return []; - }; - - const arrayToString = (arr: string[]): string => { - return arr.join(", "); - }; + // Track internal changes to prevent useEffect from overwriting user input + const isInternalChange = useRef(false); const [githubPat, setGithubPat] = useState( (connector.config?.GITHUB_PAT as string) || "" @@ -41,8 +44,13 @@ export const GithubConfig: FC = ({ ); const [name, setName] = useState(connector.name || ""); - // Update values when connector changes + // Update values when connector changes externally (not from our own input) useEffect(() => { + // Skip if this is our own internal change + if (isInternalChange.current) { + isInternalChange.current = false; + return; + } const pat = (connector.config?.GITHUB_PAT as string) || ""; const repos = arrayToString(stringToArray(connector.config?.repo_full_names)); setGithubPat(pat); @@ -51,6 +59,7 @@ export const GithubConfig: FC = ({ }, [connector.config, connector.name]); const handleGithubPatChange = (value: string) => { + isInternalChange.current = true; setGithubPat(value); if (onConfigChange) { onConfigChange({ @@ -61,6 +70,7 @@ export const GithubConfig: FC = ({ }; const handleRepoFullNamesChange = (value: string) => { + isInternalChange.current = true; setRepoFullNames(value); const repoList = stringToArray(value); if (onConfigChange) { @@ -72,6 +82,7 @@ export const GithubConfig: FC = ({ }; const handleNameChange = (value: string) => { + isInternalChange.current = true; setName(value); if (onNameChange) { onNameChange(value); @@ -80,26 +91,6 @@ export const GithubConfig: FC = ({ return (
- - -
- Personal Access Token (Optional) - - A GitHub PAT is only required for private repositories. Public repos work without a - token. Create one from{" "} - - GitHub Settings - {" "} - if needed. - -
-
- {/* Connector Name */}
diff --git a/surfsense_web/content/docs/connectors/github.mdx b/surfsense_web/content/docs/connectors/github.mdx index bb2faca81..6a4574ec4 100644 --- a/surfsense_web/content/docs/connectors/github.mdx +++ b/surfsense_web/content/docs/connectors/github.mdx @@ -3,4 +3,81 @@ title: GitHub description: Connect your GitHub repositories to SurfSense --- -# Documentation in progress \ No newline at end of file +# GitHub Connector + +Connect your GitHub repositories to SurfSense for code search and AI-powered insights. The connector uses [gitingest](https://gitingest.com) to efficiently index entire codebases. + +## What Gets Indexed + +| Content Type | Examples | +|--------------|----------| +| Code Files | Python, JavaScript, TypeScript, Go, Rust, Java, etc. | +| Documentation | README files, Markdown documents, text files | +| Configuration | JSON, YAML, TOML, .env examples, Dockerfiles | + +> ⚠️ Binary files and files larger than 5MB are automatically excluded. + +--- + +## Quick Start (Public Repos) + +1. Navigate to **Connectors** → **Add Connector** → **GitHub** +2. Enter repository names: `owner/repo` (e.g., `facebook/react, vercel/next.js`) +3. Click **Connect GitHub** + +No authentication required for public repositories. + +--- + +## Private Repositories + +For private repos, you need a GitHub Personal Access Token (PAT). + +### Generate a PAT + +1. Go to [GitHub's token creation page](https://github.com/settings/tokens/new?description=surfsense&scopes=repo) (pre-filled with `repo` scope) +2. Set an expiration +3. Click **Generate token** and copy it + +> ⚠️ The token starts with `ghp_`. Store it securely. + +--- + +## Connector Configuration + +| Field | Description | Required | +|-------|-------------|----------| +| **Connector Name** | A friendly name to identify this connector | Yes | +| **GitHub Personal Access Token** | Your PAT (only for private repos) | No | +| **Repository Names** | Comma-separated list: `owner/repo1, owner/repo2` | Yes | + +--- + +## Periodic Sync + +Enable periodic sync to automatically re-index repositories when content changes: + +| Frequency | Use Case | +|-----------|----------| +| Every 5 minutes | Active development | +| Every 15 minutes | Frequent commits | +| Every hour | Regular workflow | +| Every 6 hours | Less active repos | +| Daily | Reference repositories | +| Weekly | Stable codebases | + +--- + +## Troubleshooting + +**Repository not found** +- Verify format is `owner/repo` +- For private repos, ensure PAT has access + +**Authentication failed** +- Check PAT is valid and not expired +- Token should start with `ghp_` or `github_pat_` + +**Rate limit exceeded** +- Use a PAT for higher limits (5,000/hour vs 60 unauthenticated) +- Reduce sync frequency