Merge pull request #1061 from JoeMakuta/feat/use-key-to-reset-connectors

refactor: Use key={connector.id} to reset connector config forms and cleanup useEffects
This commit is contained in:
Rohan Verma 2026-03-31 14:34:34 -07:00 committed by GitHub
commit 97139bc239
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
17 changed files with 16 additions and 221 deletions

View file

@ -2,7 +2,7 @@
import { KeyRound } from "lucide-react";
import type { FC } from "react";
import { useEffect, useState } from "react";
import { useState } from "react";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import type { ConnectorConfigProps } from "../index";
@ -19,13 +19,6 @@ export const BaiduSearchApiConfig: FC<BaiduSearchApiConfigProps> = ({
const [apiKey, setApiKey] = useState<string>((connector.config?.BAIDU_API_KEY as string) || "");
const [name, setName] = useState<string>(connector.name || "");
// Update API key and name when connector changes
useEffect(() => {
const key = (connector.config?.BAIDU_API_KEY as string) || "";
setApiKey(key);
setName(connector.name || "");
}, [connector.config, connector.name]);
const handleApiKeyChange = (value: string) => {
setApiKey(value);
if (onConfigChange) {

View file

@ -2,7 +2,7 @@
import { KeyRound } from "lucide-react";
import type { FC } from "react";
import { useEffect, useState } from "react";
import { useState } from "react";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import type { ConnectorConfigProps } from "../index";
@ -27,17 +27,6 @@ export const BookStackConfig: FC<BookStackConfigProps> = ({
);
const [name, setName] = useState<string>(connector.name || "");
// Update values when connector changes
useEffect(() => {
const url = (connector.config?.BOOKSTACK_BASE_URL as string) || "";
const id = (connector.config?.BOOKSTACK_TOKEN_ID as string) || "";
const secret = (connector.config?.BOOKSTACK_TOKEN_SECRET as string) || "";
setBaseUrl(url);
setTokenId(id);
setTokenSecret(secret);
setName(connector.name || "");
}, [connector.config, connector.name]);
const handleBaseUrlChange = (value: string) => {
setBaseUrl(value);
if (onConfigChange) {

View file

@ -34,11 +34,6 @@ export const CirclebackConfig: FC<CirclebackConfigProps> = ({ connector, onNameC
const [isLoading, setIsLoading] = useState(true);
const [copied, setCopied] = useState(false);
// Update name when connector changes
useEffect(() => {
setName(connector.name || "");
}, [connector.name]);
// Fetch webhook info
useEffect(() => {
const fetchWebhookInfo = async () => {

View file

@ -2,7 +2,7 @@
import { Info, KeyRound } from "lucide-react";
import type { FC } from "react";
import { useEffect, useState } from "react";
import { useState } from "react";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import type { ConnectorConfigProps } from "../index";
@ -24,15 +24,6 @@ export const ClickUpConfig: FC<ClickUpConfigProps> = ({
);
const [name, setName] = useState<string>(connector.name || "");
// Update values when connector changes (only for legacy connectors)
useEffect(() => {
if (!isOAuth) {
const token = (connector.config?.CLICKUP_API_TOKEN as string) || "";
setApiToken(token);
}
setName(connector.name || "");
}, [connector.config, connector.name, isOAuth]);
const handleApiTokenChange = (value: string) => {
setApiToken(value);
if (onConfigChange) {

View file

@ -12,7 +12,7 @@ import {
X,
} from "lucide-react";
import type { FC } from "react";
import { useCallback, useEffect, useState } from "react";
import { useCallback, useState } from "react";
import { DriveFolderTree, type SelectedFolder } from "@/components/connectors/drive-folder-tree";
import { Label } from "@/components/ui/label";
import {
@ -111,17 +111,6 @@ export const ComposioDriveConfig: FC<ConnectorConfigProps> = ({ connector, onCon
const [isEditMode] = useState(() => existingFolders.length > 0 || existingFiles.length > 0);
const [isFolderTreeOpen, setIsFolderTreeOpen] = useState(!isEditMode);
useEffect(() => {
const folders = (connector.config?.selected_folders as SelectedFolder[] | undefined) || [];
const files = (connector.config?.selected_files as SelectedFolder[] | undefined) || [];
const options =
(connector.config?.indexing_options as IndexingOptions | undefined) ||
DEFAULT_INDEXING_OPTIONS;
setSelectedFolders(folders);
setSelectedFiles(files);
setIndexingOptions(options);
}, [connector.config]);
const updateConfig = (
folders: SelectedFolder[],
files: SelectedFolder[],

View file

@ -2,7 +2,7 @@
import { Info, KeyRound } from "lucide-react";
import type { FC } from "react";
import { useEffect, useState } from "react";
import { useState } from "react";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import type { ConnectorConfigProps } from "../index";
@ -28,19 +28,6 @@ export const ConfluenceConfig: FC<ConfluenceConfigProps> = ({
);
const [name, setName] = useState<string>(connector.name || "");
// Update values when connector changes (only for legacy connectors)
useEffect(() => {
if (!isOAuth) {
const url = (connector.config?.CONFLUENCE_BASE_URL as string) || "";
const emailVal = (connector.config?.CONFLUENCE_EMAIL as string) || "";
const token = (connector.config?.CONFLUENCE_API_TOKEN as string) || "";
setBaseUrl(url);
setEmail(emailVal);
setApiToken(token);
}
setName(connector.name || "");
}, [connector.config, connector.name, isOAuth]);
const handleBaseUrlChange = (value: string) => {
setBaseUrl(value);
if (onConfigChange) {

View file

@ -2,7 +2,7 @@
import { KeyRound, Server } from "lucide-react";
import type { FC } from "react";
import { useEffect, useId, useRef, useState } from "react";
import { useId, useState } from "react";
import { Badge } from "@/components/ui/badge";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
@ -56,38 +56,6 @@ export const ElasticsearchConfig: FC<ElasticsearchConfigProps> = ({
: ""
);
// Update values when the connector identity changes (e.g. switching to a different connector)
const connectorIdRef = useRef(connector.id);
useEffect(() => {
if (connectorIdRef.current === connector.id) return;
connectorIdRef.current = connector.id;
setName(connector.name || "");
setEndpointUrl((connector.config?.ELASTICSEARCH_URL as string) || "");
setAuthMethod(
(connector.config?.ELASTICSEARCH_API_KEY ? "api_key" : "basic") as "basic" | "api_key"
);
setUsername((connector.config?.ELASTICSEARCH_USERNAME as string) || "");
setPassword((connector.config?.ELASTICSEARCH_PASSWORD as string) || "");
setApiKey((connector.config?.ELASTICSEARCH_API_KEY as string) || "");
setIndices(
Array.isArray(connector.config?.ELASTICSEARCH_INDEX)
? (connector.config?.ELASTICSEARCH_INDEX as string[]).join(", ")
: (connector.config?.ELASTICSEARCH_INDEX as string) || ""
);
setQuery((connector.config?.ELASTICSEARCH_QUERY as string) || "*");
setSearchFields(
Array.isArray(connector.config?.ELASTICSEARCH_FIELDS)
? (connector.config?.ELASTICSEARCH_FIELDS as string[]).join(", ")
: ""
);
setMaxDocuments(
connector.config?.ELASTICSEARCH_MAX_DOCUMENTS
? String(connector.config.ELASTICSEARCH_MAX_DOCUMENTS)
: ""
);
}, [connector]);
const stringToArray = (str: string): string[] => {
const items = str
.split(",")

View file

@ -2,7 +2,7 @@
import { KeyRound } from "lucide-react";
import type { FC } from "react";
import { useEffect, useRef, useState } from "react";
import { useState } from "react";
import { Badge } from "@/components/ui/badge";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
@ -33,9 +33,6 @@ export const GithubConfig: FC<GithubConfigProps> = ({
onConfigChange,
onNameChange,
}) => {
// Track internal changes to prevent useEffect from overwriting user input
const isInternalChange = useRef(false);
const [githubPat, setGithubPat] = useState<string>(
(connector.config?.GITHUB_PAT as string) || ""
);
@ -44,22 +41,7 @@ export const GithubConfig: FC<GithubConfigProps> = ({
);
const [name, setName] = useState<string>(connector.name || "");
// 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);
setRepoFullNames(repos);
setName(connector.name || "");
}, [connector.config, connector.name]);
const handleGithubPatChange = (value: string) => {
isInternalChange.current = true;
setGithubPat(value);
if (onConfigChange) {
onConfigChange({
@ -70,7 +52,6 @@ export const GithubConfig: FC<GithubConfigProps> = ({
};
const handleRepoFullNamesChange = (value: string) => {
isInternalChange.current = true;
setRepoFullNames(value);
const repoList = stringToArray(value);
if (onConfigChange) {
@ -82,7 +63,6 @@ export const GithubConfig: FC<GithubConfigProps> = ({
};
const handleNameChange = (value: string) => {
isInternalChange.current = true;
setName(value);
if (onNameChange) {
onNameChange(value);

View file

@ -10,7 +10,7 @@ import {
X,
} from "lucide-react";
import type { FC } from "react";
import { useCallback, useEffect, useState } from "react";
import { useCallback, useState } from "react";
import { Button } from "@/components/ui/button";
import { Label } from "@/components/ui/label";
import {
@ -92,17 +92,6 @@ export const GoogleDriveConfig: FC<ConnectorConfigProps> = ({ connector, onConfi
const [selectedFiles, setSelectedFiles] = useState<SelectedItem[]>(existingFiles);
const [indexingOptions, setIndexingOptions] = useState<IndexingOptions>(existingIndexingOptions);
useEffect(() => {
const folders = (connector.config?.selected_folders as SelectedItem[] | undefined) || [];
const files = (connector.config?.selected_files as SelectedItem[] | undefined) || [];
const options =
(connector.config?.indexing_options as IndexingOptions | undefined) ||
DEFAULT_INDEXING_OPTIONS;
setSelectedFolders(folders);
setSelectedFiles(files);
setIndexingOptions(options);
}, [connector.config]);
const updateConfig = (
folders: SelectedItem[],
files: SelectedItem[],

View file

@ -2,7 +2,7 @@
import { Info, KeyRound } from "lucide-react";
import type { FC } from "react";
import { useEffect, useState } from "react";
import { useState } from "react";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import type { ConnectorConfigProps } from "../index";
@ -22,19 +22,6 @@ export const JiraConfig: FC<JiraConfigProps> = ({ connector, onConfigChange, onN
);
const [name, setName] = useState<string>(connector.name || "");
// Update values when connector changes (only for legacy connectors)
useEffect(() => {
if (!isOAuth) {
const url = (connector.config?.JIRA_BASE_URL as string) || "";
const emailVal = (connector.config?.JIRA_EMAIL as string) || "";
const token = (connector.config?.JIRA_API_TOKEN as string) || "";
setBaseUrl(url);
setEmail(emailVal);
setApiToken(token);
}
setName(connector.name || "");
}, [connector.config, connector.name, isOAuth]);
const handleBaseUrlChange = (value: string) => {
setBaseUrl(value);
if (onConfigChange) {

View file

@ -2,7 +2,7 @@
import { KeyRound } from "lucide-react";
import type { FC } from "react";
import { useEffect, useState } from "react";
import { useState } from "react";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import type { ConnectorConfigProps } from "../index";
@ -19,13 +19,6 @@ export const LinkupApiConfig: FC<LinkupApiConfigProps> = ({
const [apiKey, setApiKey] = useState<string>((connector.config?.LINKUP_API_KEY as string) || "");
const [name, setName] = useState<string>(connector.name || "");
// Update API key and name when connector changes
useEffect(() => {
const key = (connector.config?.LINKUP_API_KEY as string) || "";
setApiKey(key);
setName(connector.name || "");
}, [connector.config, connector.name]);
const handleApiKeyChange = (value: string) => {
setApiKey(value);
if (onConfigChange) {

View file

@ -2,7 +2,7 @@
import { KeyRound } from "lucide-react";
import type { FC } from "react";
import { useEffect, useState } from "react";
import { useState } from "react";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import type { ConnectorConfigProps } from "../index";
@ -15,13 +15,6 @@ export const LumaConfig: FC<LumaConfigProps> = ({ connector, onConfigChange, onN
const [apiKey, setApiKey] = useState<string>((connector.config?.LUMA_API_KEY as string) || "");
const [name, setName] = useState<string>(connector.name || "");
// Update API key and name when connector changes
useEffect(() => {
const key = (connector.config?.LUMA_API_KEY as string) || "";
setApiKey(key);
setName(connector.name || "");
}, [connector.config, connector.name]);
const handleApiKeyChange = (value: string) => {
setApiKey(value);
if (onConfigChange) {

View file

@ -1,7 +1,7 @@
"use client";
import type { FC } from "react";
import { useEffect, useState } from "react";
import { useState } from "react";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { Switch } from "@/components/ui/switch";
@ -34,25 +34,6 @@ export const ObsidianConfig: FC<ObsidianConfigProps> = ({
);
const [name, setName] = useState<string>(connector.name || "");
// Update values when connector changes
useEffect(() => {
const path = (connector.config?.vault_path as string) || "";
const vName = (connector.config?.vault_name as string) || "";
const folders = connector.config?.exclude_folders;
const attachments = (connector.config?.include_attachments as boolean) || false;
setVaultPath(path);
setVaultName(vName);
setIncludeAttachments(attachments);
setName(connector.name || "");
if (Array.isArray(folders)) {
setExcludeFolders(folders.join(", "));
} else if (typeof folders === "string") {
setExcludeFolders(folders);
}
}, [connector.config, connector.name]);
const handleVaultPathChange = (value: string) => {
setVaultPath(value);
if (onConfigChange) {

View file

@ -2,7 +2,7 @@
import { Globe, KeyRound } from "lucide-react";
import type { FC } from "react";
import { useEffect, useState } from "react";
import { useState } from "react";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { Switch } from "@/components/ui/switch";
@ -55,32 +55,6 @@ export const SearxngConfig: FC<SearxngConfigProps> = ({
);
const [name, setName] = useState<string>(connector.name || "");
// Update all fields when connector changes
useEffect(() => {
const hostValue = (connector.config?.SEARXNG_HOST as string) || "";
const apiKeyValue = (connector.config?.SEARXNG_API_KEY as string) || "";
const enginesValue = arrayToString(connector.config?.SEARXNG_ENGINES);
const categoriesValue = arrayToString(connector.config?.SEARXNG_CATEGORIES);
const languageValue = (connector.config?.SEARXNG_LANGUAGE as string) || "";
const safesearchValue =
connector.config?.SEARXNG_SAFESEARCH !== undefined
? String(connector.config.SEARXNG_SAFESEARCH)
: "";
const verifySslValue =
connector.config?.SEARXNG_VERIFY_SSL !== undefined
? (connector.config.SEARXNG_VERIFY_SSL as boolean)
: true;
setHost(hostValue);
setApiKey(apiKeyValue);
setEngines(enginesValue);
setCategories(categoriesValue);
setLanguage(languageValue);
setSafesearch(safesearchValue);
setVerifySsl(verifySslValue);
setName(connector.name || "");
}, [connector.config, connector.name]);
const updateConfig = (updates: Record<string, unknown>) => {
if (onConfigChange) {
onConfigChange({

View file

@ -2,7 +2,7 @@
import { KeyRound } from "lucide-react";
import type { FC } from "react";
import { useEffect, useState } from "react";
import { useState } from "react";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import type { ConnectorConfigProps } from "../index";
@ -19,13 +19,6 @@ export const TavilyApiConfig: FC<TavilyApiConfigProps> = ({
const [apiKey, setApiKey] = useState<string>((connector.config?.TAVILY_API_KEY as string) || "");
const [name, setName] = useState<string>(connector.name || "");
// Update API key and name when connector changes
useEffect(() => {
const key = (connector.config?.TAVILY_API_KEY as string) || "";
setApiKey(key);
setName(connector.name || "");
}, [connector.config, connector.name]);
const handleApiKeyChange = (value: string) => {
setApiKey(value);
if (onConfigChange) {

View file

@ -2,7 +2,7 @@
import { Info } from "lucide-react";
import type { FC } from "react";
import { useEffect, useState } from "react";
import { useState } from "react";
import { Alert, AlertDescription } from "@/components/ui/alert";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
@ -19,14 +19,6 @@ export const WebcrawlerConfig: FC<ConnectorConfigProps> = ({ connector, onConfig
const [initialUrls, setInitialUrls] = useState(existingUrls);
const [showApiKey, setShowApiKey] = useState(false);
// Update state when connector config changes
useEffect(() => {
const apiKeyValue = (connector.config?.FIRECRAWL_API_KEY as string | undefined) || "";
const urlsValue = (connector.config?.INITIAL_URLS as string | undefined) || "";
setApiKey(apiKeyValue);
setInitialUrls(urlsValue);
}, [connector.config]);
const handleApiKeyChange = (value: string) => {
setApiKey(value);
if (onConfigChange) {

View file

@ -258,6 +258,7 @@ export const ConnectorEditView: FC<ConnectorEditViewProps> = ({
{/* Connector-specific configuration */}
{ConnectorConfigComponent && (
<ConnectorConfigComponent
key={connector.id}
connector={connector}
onConfigChange={onConfigChange}
onNameChange={onNameChange}