mirror of
https://github.com/MODSetter/SurfSense.git
synced 2026-04-25 00:36:31 +02:00
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:
commit
97139bc239
17 changed files with 16 additions and 221 deletions
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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 () => {
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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[],
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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(",")
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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[],
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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({
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -258,6 +258,7 @@ export const ConnectorEditView: FC<ConnectorEditViewProps> = ({
|
|||
{/* Connector-specific configuration */}
|
||||
{ConnectorConfigComponent && (
|
||||
<ConnectorConfigComponent
|
||||
key={connector.id}
|
||||
connector={connector}
|
||||
onConfigChange={onConfigChange}
|
||||
onNameChange={onNameChange}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue