add relevant coderrabit suggestions

This commit is contained in:
CREDO23 2025-07-27 13:31:41 +02:00
parent dee54bf5e1
commit 8e52a0b201
7 changed files with 534 additions and 296 deletions

View file

@ -920,7 +920,10 @@ async def fetch_relevant_documents(
} }
) )
elif connector == "CONFLUENCE_CONNECTOR": elif connector == "CONFLUENCE_CONNECTOR":
source_object, confluence_chunks = await connector_service.search_confluence( (
source_object,
confluence_chunks,
) = await connector_service.search_confluence(
user_query=reformulated_query, user_query=reformulated_query,
user_id=user_id, user_id=user_id,
search_space_id=search_space_id, search_space_id=search_space_id,

View file

@ -6,7 +6,6 @@ Allows fetching pages and their comments from specified spaces.
""" """
import base64 import base64
from datetime import datetime, timezone
from typing import Any from typing import Any
import requests import requests

View file

@ -918,7 +918,9 @@ async def run_confluence_indexing_with_new_session(
await run_confluence_indexing( await run_confluence_indexing(
session, connector_id, search_space_id, user_id, start_date, end_date session, connector_id, search_space_id, user_id, start_date, end_date
) )
logger.info(f"Background task finished: Indexing Confluence connector {connector_id}") logger.info(
f"Background task finished: Indexing Confluence connector {connector_id}"
)
async def run_confluence_indexing( async def run_confluence_indexing(

View file

@ -145,7 +145,11 @@ class SearchSourceConnectorBase(BaseModel):
elif connector_type == SearchSourceConnectorType.CONFLUENCE_CONNECTOR: elif connector_type == SearchSourceConnectorType.CONFLUENCE_CONNECTOR:
# For CONFLUENCE_CONNECTOR, only allow specific keys # For CONFLUENCE_CONNECTOR, only allow specific keys
allowed_keys = ["CONFLUENCE_BASE_URL", "CONFLUENCE_EMAIL", "CONFLUENCE_API_TOKEN"] allowed_keys = [
"CONFLUENCE_BASE_URL",
"CONFLUENCE_EMAIL",
"CONFLUENCE_API_TOKEN",
]
if set(config.keys()) != set(allowed_keys): if set(config.keys()) != set(allowed_keys):
raise ValueError( raise ValueError(
f"For CONFLUENCE_CONNECTOR connector type, config must only contain these keys: {allowed_keys}" f"For CONFLUENCE_CONNECTOR connector type, config must only contain these keys: {allowed_keys}"

View file

@ -1072,6 +1072,7 @@ class ConnectorService:
} }
return result_object, jira_chunks return result_object, jira_chunks
async def search_confluence( async def search_confluence(
self, self,
user_query: str, user_query: str,
@ -1145,7 +1146,7 @@ class ConnectorService:
description += "..." description += "..."
# For URL, we can use a placeholder or construct a URL to the Confluence page if available # For URL, we can use a placeholder or construct a URL to the Confluence page if available
url = "" url = "" # TODO: Add base_url to metadata
if page_id: if page_id:
url = f"{metadata.get('base_url')}/pages/{page_id}" url = f"{metadata.get('base_url')}/pages/{page_id}"

View file

@ -2413,7 +2413,9 @@ async def index_confluence_pages(
) )
confluence_client = ConfluenceConnector( confluence_client = ConfluenceConnector(
base_url=confluence_base_url, email=confluence_email, api_token=confluence_api_token base_url=confluence_base_url,
email=confluence_email,
api_token=confluence_api_token,
) )
# Calculate date range # Calculate date range
@ -2528,9 +2530,7 @@ async def index_confluence_pages(
logger.warning( logger.warning(
f"Skipping page with missing ID or title: {page_id or 'Unknown'}" f"Skipping page with missing ID or title: {page_id or 'Unknown'}"
) )
skipped_pages.append( skipped_pages.append(f"{page_title or 'Unknown'} (missing data)")
f"{page_title or 'Unknown'} (missing data)"
)
documents_skipped += 1 documents_skipped += 1
continue continue
@ -2549,7 +2549,9 @@ async def index_confluence_pages(
if comment.get("body") and comment["body"].get("storage"): if comment.get("body") and comment["body"].get("storage"):
comment_body = comment["body"]["storage"].get("value", "") comment_body = comment["body"]["storage"].get("value", "")
comment_author = comment.get("version", {}).get("authorId", "Unknown") comment_author = comment.get("version", {}).get(
"authorId", "Unknown"
)
comment_date = comment.get("version", {}).get("createdAt", "") comment_date = comment.get("version", {}).get("createdAt", "")
comments_content += f"**Comment by {comment_author}** ({comment_date}):\n{comment_body}\n\n" comments_content += f"**Comment by {comment_author}** ({comment_date}):\n{comment_body}\n\n"
@ -2558,15 +2560,15 @@ async def index_confluence_pages(
full_content = f"# {page_title}\n\n{page_content}{comments_content}" full_content = f"# {page_title}\n\n{page_content}{comments_content}"
if not full_content.strip(): if not full_content.strip():
logger.warning( logger.warning(f"Skipping page with no content: {page_title}")
f"Skipping page with no content: {page_title}"
)
skipped_pages.append(f"{page_title} (no content)") skipped_pages.append(f"{page_title} (no content)")
documents_skipped += 1 documents_skipped += 1
continue continue
# Create a simple summary # Create a simple summary
summary_content = f"Confluence Page: {page_title}\n\nSpace ID: {space_id}\n\n" summary_content = (
f"Confluence Page: {page_title}\n\nSpace ID: {space_id}\n\n"
)
if page_content: if page_content:
# Take first 500 characters of content for summary # Take first 500 characters of content for summary
content_preview = page_content[:500] content_preview = page_content[:500]
@ -2611,9 +2613,7 @@ async def index_confluence_pages(
] ]
# Create and store new document # Create and store new document
logger.info( logger.info(f"Creating new document for page {page_title}")
f"Creating new document for page {page_title}"
)
document = Document( document = Document(
search_space_id=search_space_id, search_space_id=search_space_id,
title=f"Confluence - {page_title}", title=f"Confluence - {page_title}",
@ -2633,9 +2633,7 @@ async def index_confluence_pages(
session.add(document) session.add(document)
documents_indexed += 1 documents_indexed += 1
logger.info( logger.info(f"Successfully indexed new page {page_title}")
f"Successfully indexed new page {page_title}"
)
except Exception as e: except Exception as e:
logger.error( logger.error(
@ -2656,7 +2654,9 @@ async def index_confluence_pages(
# Commit all changes # Commit all changes
await session.commit() await session.commit()
logger.info("Successfully committed all Confluence document changes to database") logger.info(
"Successfully committed all Confluence document changes to database"
)
# Log success # Log success
await task_logger.log_task_success( await task_logger.log_task_success(

View file

@ -1,29 +1,46 @@
import { useState, useEffect, useCallback } from 'react'; import { useState, useEffect, useCallback } from "react";
import { useRouter } from 'next/navigation'; import { useRouter } from "next/navigation";
import { useForm } from 'react-hook-form'; import { useForm } from "react-hook-form";
import { zodResolver } from '@hookform/resolvers/zod'; import { zodResolver } from "@hookform/resolvers/zod";
import { toast } from 'sonner'; import { toast } from "sonner";
import { useSearchSourceConnectors, SearchSourceConnector } from '@/hooks/useSearchSourceConnectors'; import {
useSearchSourceConnectors,
SearchSourceConnector,
} from "@/hooks/useSearchSourceConnectors";
import { import {
GithubRepo, GithubRepo,
EditMode, EditMode,
githubPatSchema, githubPatSchema,
editConnectorSchema, editConnectorSchema,
GithubPatFormValues, GithubPatFormValues,
EditConnectorFormValues EditConnectorFormValues,
} from '@/components/editConnector/types'; } from "@/components/editConnector/types";
export function useConnectorEditPage(connectorId: number, searchSpaceId: string) { export function useConnectorEditPage(
connectorId: number,
searchSpaceId: string,
) {
const router = useRouter(); const router = useRouter();
const { connectors, updateConnector, isLoading: connectorsLoading } = useSearchSourceConnectors(); const {
connectors,
updateConnector,
isLoading: connectorsLoading,
} = useSearchSourceConnectors();
// State managed by the hook // State managed by the hook
const [connector, setConnector] = useState<SearchSourceConnector | null>(null); const [connector, setConnector] = useState<SearchSourceConnector | null>(
const [originalConfig, setOriginalConfig] = useState<Record<string, any> | null>(null); null,
);
const [originalConfig, setOriginalConfig] = useState<Record<
string,
any
> | null>(null);
const [isSaving, setIsSaving] = useState(false); const [isSaving, setIsSaving] = useState(false);
const [currentSelectedRepos, setCurrentSelectedRepos] = useState<string[]>([]); const [currentSelectedRepos, setCurrentSelectedRepos] = useState<string[]>(
[],
);
const [originalPat, setOriginalPat] = useState<string>(""); const [originalPat, setOriginalPat] = useState<string>("");
const [editMode, setEditMode] = useState<EditMode>('viewing'); const [editMode, setEditMode] = useState<EditMode>("viewing");
const [fetchedRepos, setFetchedRepos] = useState<GithubRepo[] | null>(null); const [fetchedRepos, setFetchedRepos] = useState<GithubRepo[] | null>(null);
const [newSelectedRepos, setNewSelectedRepos] = useState<string[]>([]); const [newSelectedRepos, setNewSelectedRepos] = useState<string[]>([]);
const [isFetchingRepos, setIsFetchingRepos] = useState(false); const [isFetchingRepos, setIsFetchingRepos] = useState(false);
@ -55,7 +72,7 @@ export function useConnectorEditPage(connectorId: number, searchSpaceId: string)
// Effect to load initial data // Effect to load initial data
useEffect(() => { useEffect(() => {
if (!connectorsLoading && connectors.length > 0 && !connector) { if (!connectorsLoading && connectors.length > 0 && !connector) {
const currentConnector = connectors.find(c => c.id === connectorId); const currentConnector = connectors.find((c) => c.id === connectorId);
if (currentConnector) { if (currentConnector) {
setConnector(currentConnector); setConnector(currentConnector);
const config = currentConnector.config || {}; const config = currentConnector.config || {};
@ -69,50 +86,92 @@ export function useConnectorEditPage(connectorId: number, searchSpaceId: string)
LINEAR_API_KEY: config.LINEAR_API_KEY || "", LINEAR_API_KEY: config.LINEAR_API_KEY || "",
LINKUP_API_KEY: config.LINKUP_API_KEY || "", LINKUP_API_KEY: config.LINKUP_API_KEY || "",
DISCORD_BOT_TOKEN: config.DISCORD_BOT_TOKEN || "", DISCORD_BOT_TOKEN: config.DISCORD_BOT_TOKEN || "",
CONFLUENCE_BASE_URL: config.CONFLUENCE_BASE_URL || "",
CONFLUENCE_EMAIL: config.CONFLUENCE_EMAIL || "",
CONFLUENCE_API_TOKEN: config.CONFLUENCE_API_TOKEN || "",
JIRA_BASE_URL: config.JIRA_BASE_URL || "",
JIRA_EMAIL: config.JIRA_EMAIL || "",
JIRA_API_TOKEN: config.JIRA_API_TOKEN || "",
}); });
if (currentConnector.connector_type === 'GITHUB_CONNECTOR') { if (currentConnector.connector_type === "GITHUB_CONNECTOR") {
const savedRepos = config.repo_full_names || []; const savedRepos = config.repo_full_names || [];
const savedPat = config.GITHUB_PAT || ""; const savedPat = config.GITHUB_PAT || "";
setCurrentSelectedRepos(savedRepos); setCurrentSelectedRepos(savedRepos);
setNewSelectedRepos(savedRepos); setNewSelectedRepos(savedRepos);
setOriginalPat(savedPat); setOriginalPat(savedPat);
patForm.reset({ github_pat: savedPat }); patForm.reset({ github_pat: savedPat });
setEditMode('viewing'); setEditMode("viewing");
} }
} else { } else {
toast.error("Connector not found."); toast.error("Connector not found.");
router.push(`/dashboard/${searchSpaceId}/connectors`); router.push(`/dashboard/${searchSpaceId}/connectors`);
} }
} }
}, [connectorId, connectors, connectorsLoading, router, searchSpaceId, connector, editForm, patForm]); }, [
connectorId,
connectors,
connectorsLoading,
router,
searchSpaceId,
connector,
editForm,
patForm,
]);
// Handlers managed by the hook // Handlers managed by the hook
const handleFetchRepositories = useCallback(async (values: GithubPatFormValues) => { const handleFetchRepositories = useCallback(
async (values: GithubPatFormValues) => {
setIsFetchingRepos(true); setIsFetchingRepos(true);
setFetchedRepos(null); setFetchedRepos(null);
try { try {
const token = localStorage.getItem('surfsense_bearer_token'); const token = localStorage.getItem("surfsense_bearer_token");
if (!token) throw new Error('No auth token'); if (!token) throw new Error("No auth token");
const response = await fetch( const response = await fetch(
`${process.env.NEXT_PUBLIC_FASTAPI_BACKEND_URL}/api/v1/github/repositories/`, `${process.env.NEXT_PUBLIC_FASTAPI_BACKEND_URL}/api/v1/github/repositories/`,
{ method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}` }, body: JSON.stringify({ github_pat: values.github_pat }) } {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${token}`,
},
body: JSON.stringify({ github_pat: values.github_pat }),
},
); );
if (!response.ok) { const err = await response.json(); throw new Error(err.detail || 'Fetch failed'); } if (!response.ok) {
const err = await response.json();
throw new Error(err.detail || "Fetch failed");
}
const data: GithubRepo[] = await response.json(); const data: GithubRepo[] = await response.json();
setFetchedRepos(data); setFetchedRepos(data);
setNewSelectedRepos(currentSelectedRepos); setNewSelectedRepos(currentSelectedRepos);
toast.success(`Found ${data.length} repos.`); toast.success(`Found ${data.length} repos.`);
} catch (error) { } catch (error) {
console.error("Error fetching GitHub repositories:", error); console.error("Error fetching GitHub repositories:", error);
toast.error(error instanceof Error ? error.message : "Failed to fetch repositories."); toast.error(
} finally { setIsFetchingRepos(false); } error instanceof Error
}, [currentSelectedRepos]); // Added dependency ? error.message
: "Failed to fetch repositories.",
);
} finally {
setIsFetchingRepos(false);
}
},
[currentSelectedRepos],
); // Added dependency
const handleRepoSelectionChange = useCallback((repoFullName: string, checked: boolean) => { const handleRepoSelectionChange = useCallback(
setNewSelectedRepos(prev => checked ? [...prev, repoFullName] : prev.filter(name => name !== repoFullName)); (repoFullName: string, checked: boolean) => {
}, []); setNewSelectedRepos((prev) =>
checked
? [...prev, repoFullName]
: prev.filter((name) => name !== repoFullName),
);
},
[],
);
const handleSaveChanges = useCallback(async (formData: EditConnectorFormValues) => { const handleSaveChanges = useCallback(
async (formData: EditConnectorFormValues) => {
if (!connector || !originalConfig) return; if (!connector || !originalConfig) return;
setIsSaving(true); setIsSaving(true);
const updatePayload: Partial<SearchSourceConnector> = {}; const updatePayload: Partial<SearchSourceConnector> = {};
@ -124,46 +183,88 @@ export function useConnectorEditPage(connectorId: number, searchSpaceId: string)
} }
switch (connector.connector_type) { switch (connector.connector_type) {
case 'GITHUB_CONNECTOR': case "GITHUB_CONNECTOR": {
const currentPatInForm = patForm.getValues('github_pat'); const currentPatInForm = patForm.getValues("github_pat");
const patChanged = currentPatInForm !== originalPat; const patChanged = currentPatInForm !== originalPat;
const initialRepoSet = new Set(currentSelectedRepos); const initialRepoSet = new Set(currentSelectedRepos);
const newRepoSet = new Set(newSelectedRepos); const newRepoSet = new Set(newSelectedRepos);
const reposChanged = initialRepoSet.size !== newRepoSet.size || ![...initialRepoSet].every(repo => newRepoSet.has(repo)); const reposChanged =
if (patChanged || (editMode === 'editing_repos' && reposChanged && fetchedRepos !== null)) { initialRepoSet.size !== newRepoSet.size ||
if (!currentPatInForm || !(currentPatInForm.startsWith('ghp_') || currentPatInForm.startsWith('github_pat_'))) { ![...initialRepoSet].every((repo) => newRepoSet.has(repo));
toast.error("Invalid GitHub PAT format. Cannot save."); setIsSaving(false); return; if (
patChanged ||
(editMode === "editing_repos" &&
reposChanged &&
fetchedRepos !== null)
) {
if (
!currentPatInForm ||
!(
currentPatInForm.startsWith("ghp_") ||
currentPatInForm.startsWith("github_pat_")
)
) {
toast.error("Invalid GitHub PAT format. Cannot save.");
setIsSaving(false);
return;
}
newConfig = {
GITHUB_PAT: currentPatInForm,
repo_full_names: newSelectedRepos,
};
if (reposChanged && newSelectedRepos.length === 0) {
toast.warning("Warning: No repositories selected.");
} }
newConfig = { GITHUB_PAT: currentPatInForm, repo_full_names: newSelectedRepos };
if (reposChanged && newSelectedRepos.length === 0) { toast.warning("Warning: No repositories selected."); }
} }
break; break;
case 'SLACK_CONNECTOR': }
case "SLACK_CONNECTOR":
if (formData.SLACK_BOT_TOKEN !== originalConfig.SLACK_BOT_TOKEN) { if (formData.SLACK_BOT_TOKEN !== originalConfig.SLACK_BOT_TOKEN) {
if (!formData.SLACK_BOT_TOKEN) { toast.error("Slack Token empty."); setIsSaving(false); return; } if (!formData.SLACK_BOT_TOKEN) {
toast.error("Slack Token empty.");
setIsSaving(false);
return;
}
newConfig = { SLACK_BOT_TOKEN: formData.SLACK_BOT_TOKEN }; newConfig = { SLACK_BOT_TOKEN: formData.SLACK_BOT_TOKEN };
} }
break; break;
case 'NOTION_CONNECTOR': case "NOTION_CONNECTOR":
if (formData.NOTION_INTEGRATION_TOKEN !== originalConfig.NOTION_INTEGRATION_TOKEN) { if (
if (!formData.NOTION_INTEGRATION_TOKEN) { toast.error("Notion Token empty."); setIsSaving(false); return; } formData.NOTION_INTEGRATION_TOKEN !==
newConfig = { NOTION_INTEGRATION_TOKEN: formData.NOTION_INTEGRATION_TOKEN }; originalConfig.NOTION_INTEGRATION_TOKEN
) {
if (!formData.NOTION_INTEGRATION_TOKEN) {
toast.error("Notion Token empty.");
setIsSaving(false);
return;
}
newConfig = {
NOTION_INTEGRATION_TOKEN: formData.NOTION_INTEGRATION_TOKEN,
};
} }
break; break;
case 'SERPER_API': case "SERPER_API":
if (formData.SERPER_API_KEY !== originalConfig.SERPER_API_KEY) { if (formData.SERPER_API_KEY !== originalConfig.SERPER_API_KEY) {
if (!formData.SERPER_API_KEY) { toast.error("Serper Key empty."); setIsSaving(false); return; } if (!formData.SERPER_API_KEY) {
toast.error("Serper Key empty.");
setIsSaving(false);
return;
}
newConfig = { SERPER_API_KEY: formData.SERPER_API_KEY }; newConfig = { SERPER_API_KEY: formData.SERPER_API_KEY };
} }
break; break;
case 'TAVILY_API': case "TAVILY_API":
if (formData.TAVILY_API_KEY !== originalConfig.TAVILY_API_KEY) { if (formData.TAVILY_API_KEY !== originalConfig.TAVILY_API_KEY) {
if (!formData.TAVILY_API_KEY) { toast.error("Tavily Key empty."); setIsSaving(false); return; } if (!formData.TAVILY_API_KEY) {
toast.error("Tavily Key empty.");
setIsSaving(false);
return;
}
newConfig = { TAVILY_API_KEY: formData.TAVILY_API_KEY }; newConfig = { TAVILY_API_KEY: formData.TAVILY_API_KEY };
} }
break; break;
case 'LINEAR_CONNECTOR': case "LINEAR_CONNECTOR":
if (formData.LINEAR_API_KEY !== originalConfig.LINEAR_API_KEY) { if (formData.LINEAR_API_KEY !== originalConfig.LINEAR_API_KEY) {
if (!formData.LINEAR_API_KEY) { if (!formData.LINEAR_API_KEY) {
toast.error("Linear API Key cannot be empty."); toast.error("Linear API Key cannot be empty.");
@ -173,18 +274,72 @@ export function useConnectorEditPage(connectorId: number, searchSpaceId: string)
newConfig = { LINEAR_API_KEY: formData.LINEAR_API_KEY }; newConfig = { LINEAR_API_KEY: formData.LINEAR_API_KEY };
} }
break; break;
case 'LINKUP_API': case "LINKUP_API":
if (formData.LINKUP_API_KEY !== originalConfig.LINKUP_API_KEY) { if (formData.LINKUP_API_KEY !== originalConfig.LINKUP_API_KEY) {
if (!formData.LINKUP_API_KEY) { toast.error("Linkup API Key cannot be empty."); setIsSaving(false); return; } if (!formData.LINKUP_API_KEY) {
toast.error("Linkup API Key cannot be empty.");
setIsSaving(false);
return;
}
newConfig = { LINKUP_API_KEY: formData.LINKUP_API_KEY }; newConfig = { LINKUP_API_KEY: formData.LINKUP_API_KEY };
} }
break; break;
case 'DISCORD_CONNECTOR': case "DISCORD_CONNECTOR":
if (formData.DISCORD_BOT_TOKEN !== originalConfig.DISCORD_BOT_TOKEN) { if (formData.DISCORD_BOT_TOKEN !== originalConfig.DISCORD_BOT_TOKEN) {
if (!formData.DISCORD_BOT_TOKEN) { toast.error("Discord Bot Token cannot be empty."); setIsSaving(false); return; } if (!formData.DISCORD_BOT_TOKEN) {
toast.error("Discord Bot Token cannot be empty.");
setIsSaving(false);
return;
}
newConfig = { DISCORD_BOT_TOKEN: formData.DISCORD_BOT_TOKEN }; newConfig = { DISCORD_BOT_TOKEN: formData.DISCORD_BOT_TOKEN };
} }
break; break;
case "CONFLUENCE_CONNECTOR":
if (
formData.CONFLUENCE_BASE_URL !==
originalConfig.CONFLUENCE_BASE_URL ||
formData.CONFLUENCE_EMAIL !== originalConfig.CONFLUENCE_EMAIL ||
formData.CONFLUENCE_API_TOKEN !==
originalConfig.CONFLUENCE_API_TOKEN
) {
if (
!formData.CONFLUENCE_BASE_URL ||
!formData.CONFLUENCE_EMAIL ||
!formData.CONFLUENCE_API_TOKEN
) {
toast.error("All Confluence fields are required.");
setIsSaving(false);
return;
}
newConfig = {
CONFLUENCE_BASE_URL: formData.CONFLUENCE_BASE_URL,
CONFLUENCE_EMAIL: formData.CONFLUENCE_EMAIL,
CONFLUENCE_API_TOKEN: formData.CONFLUENCE_API_TOKEN,
};
}
break;
case "JIRA_CONNECTOR":
if (
formData.JIRA_BASE_URL !== originalConfig.JIRA_BASE_URL ||
formData.JIRA_EMAIL !== originalConfig.JIRA_EMAIL ||
formData.JIRA_API_TOKEN !== originalConfig.JIRA_API_TOKEN
) {
if (
!formData.JIRA_BASE_URL ||
!formData.JIRA_EMAIL ||
!formData.JIRA_API_TOKEN
) {
toast.error("All Jira fields are required.");
setIsSaving(false);
return;
}
newConfig = {
JIRA_BASE_URL: formData.JIRA_BASE_URL,
JIRA_EMAIL: formData.JIRA_EMAIL,
JIRA_API_TOKEN: formData.JIRA_API_TOKEN,
};
}
break;
} }
if (newConfig !== null) { if (newConfig !== null) {
@ -195,7 +350,10 @@ export function useConnectorEditPage(connectorId: number, searchSpaceId: string)
if (Object.keys(updatePayload).length === 0) { if (Object.keys(updatePayload).length === 0) {
toast.info("No changes detected."); toast.info("No changes detected.");
setIsSaving(false); setIsSaving(false);
if (connector.connector_type === 'GITHUB_CONNECTOR') { setEditMode('viewing'); patForm.reset({ github_pat: originalPat }); } if (connector.connector_type === "GITHUB_CONNECTOR") {
setEditMode("viewing");
patForm.reset({ github_pat: originalPat });
}
return; return;
} }
@ -205,41 +363,112 @@ export function useConnectorEditPage(connectorId: number, searchSpaceId: string)
const newlySavedConfig = updatePayload.config || originalConfig; const newlySavedConfig = updatePayload.config || originalConfig;
setOriginalConfig(newlySavedConfig); setOriginalConfig(newlySavedConfig);
if (updatePayload.name) { if (updatePayload.name) {
setConnector(prev => prev ? { ...prev, name: updatePayload.name!, config: newlySavedConfig } : null); setConnector((prev) =>
prev
? { ...prev, name: updatePayload.name!, config: newlySavedConfig }
: null,
);
} }
if (configChanged) { if (configChanged) {
if (connector.connector_type === 'GITHUB_CONNECTOR') { if (connector.connector_type === "GITHUB_CONNECTOR") {
const savedGitHubConfig = newlySavedConfig as { GITHUB_PAT?: string; repo_full_names?: string[] }; const savedGitHubConfig = newlySavedConfig as {
GITHUB_PAT?: string;
repo_full_names?: string[];
};
setCurrentSelectedRepos(savedGitHubConfig.repo_full_names || []); setCurrentSelectedRepos(savedGitHubConfig.repo_full_names || []);
setOriginalPat(savedGitHubConfig.GITHUB_PAT || ""); setOriginalPat(savedGitHubConfig.GITHUB_PAT || "");
setNewSelectedRepos(savedGitHubConfig.repo_full_names || []); setNewSelectedRepos(savedGitHubConfig.repo_full_names || []);
patForm.reset({ github_pat: savedGitHubConfig.GITHUB_PAT || "" }); patForm.reset({ github_pat: savedGitHubConfig.GITHUB_PAT || "" });
} else if(connector.connector_type === 'SLACK_CONNECTOR') { } else if (connector.connector_type === "SLACK_CONNECTOR") {
editForm.setValue('SLACK_BOT_TOKEN', newlySavedConfig.SLACK_BOT_TOKEN || ""); editForm.setValue(
} else if(connector.connector_type === 'NOTION_CONNECTOR') { "SLACK_BOT_TOKEN",
editForm.setValue('NOTION_INTEGRATION_TOKEN', newlySavedConfig.NOTION_INTEGRATION_TOKEN || ""); newlySavedConfig.SLACK_BOT_TOKEN || "",
} else if(connector.connector_type === 'SERPER_API') { );
editForm.setValue('SERPER_API_KEY', newlySavedConfig.SERPER_API_KEY || ""); } else if (connector.connector_type === "NOTION_CONNECTOR") {
} else if(connector.connector_type === 'TAVILY_API') { editForm.setValue(
editForm.setValue('TAVILY_API_KEY', newlySavedConfig.TAVILY_API_KEY || ""); "NOTION_INTEGRATION_TOKEN",
} else if(connector.connector_type === 'LINEAR_CONNECTOR') { newlySavedConfig.NOTION_INTEGRATION_TOKEN || "",
editForm.setValue('LINEAR_API_KEY', newlySavedConfig.LINEAR_API_KEY || ""); );
} else if(connector.connector_type === 'LINKUP_API') { } else if (connector.connector_type === "SERPER_API") {
editForm.setValue('LINKUP_API_KEY', newlySavedConfig.LINKUP_API_KEY || ""); editForm.setValue(
} else if(connector.connector_type === 'DISCORD_CONNECTOR') { "SERPER_API_KEY",
editForm.setValue('DISCORD_BOT_TOKEN', newlySavedConfig.DISCORD_BOT_TOKEN || ""); newlySavedConfig.SERPER_API_KEY || "",
);
} else if (connector.connector_type === "TAVILY_API") {
editForm.setValue(
"TAVILY_API_KEY",
newlySavedConfig.TAVILY_API_KEY || "",
);
} else if (connector.connector_type === "LINEAR_CONNECTOR") {
editForm.setValue(
"LINEAR_API_KEY",
newlySavedConfig.LINEAR_API_KEY || "",
);
} else if (connector.connector_type === "LINKUP_API") {
editForm.setValue(
"LINKUP_API_KEY",
newlySavedConfig.LINKUP_API_KEY || "",
);
} else if (connector.connector_type === "DISCORD_CONNECTOR") {
editForm.setValue(
"DISCORD_BOT_TOKEN",
newlySavedConfig.DISCORD_BOT_TOKEN || "",
);
} else if (connector.connector_type === "CONFLUENCE_CONNECTOR") {
editForm.setValue(
"CONFLUENCE_BASE_URL",
newlySavedConfig.CONFLUENCE_BASE_URL || "",
);
editForm.setValue(
"CONFLUENCE_EMAIL",
newlySavedConfig.CONFLUENCE_EMAIL || "",
);
editForm.setValue(
"CONFLUENCE_API_TOKEN",
newlySavedConfig.CONFLUENCE_API_TOKEN || "",
);
} else if (connector.connector_type === "JIRA_CONNECTOR") {
editForm.setValue(
"JIRA_BASE_URL",
newlySavedConfig.JIRA_BASE_URL || "",
);
editForm.setValue("JIRA_EMAIL", newlySavedConfig.JIRA_EMAIL || "");
editForm.setValue(
"JIRA_API_TOKEN",
newlySavedConfig.JIRA_API_TOKEN || "",
);
} }
} }
if (connector.connector_type === 'GITHUB_CONNECTOR') { if (connector.connector_type === "GITHUB_CONNECTOR") {
setEditMode('viewing'); setEditMode("viewing");
setFetchedRepos(null); setFetchedRepos(null);
} }
// Resetting simple form values is handled by useEffect if connector state updates // Resetting simple form values is handled by useEffect if connector state updates
} catch (error) { } catch (error) {
console.error("Error updating connector:", error); console.error("Error updating connector:", error);
toast.error(error instanceof Error ? error.message : "Failed to update connector."); toast.error(
} finally { setIsSaving(false); } error instanceof Error
}, [connector, originalConfig, updateConnector, connectorId, patForm, originalPat, currentSelectedRepos, newSelectedRepos, editMode, fetchedRepos, editForm]); // Added editForm to dependencies ? error.message
: "Failed to update connector.",
);
} finally {
setIsSaving(false);
}
},
[
connector,
originalConfig,
updateConnector,
connectorId,
patForm,
originalPat,
currentSelectedRepos,
newSelectedRepos,
editMode,
fetchedRepos,
editForm,
],
); // Added editForm to dependencies
// Return values needed by the component // Return values needed by the component
return { return {