fix: bot form error

This commit is contained in:
Junyan Qin
2026-03-13 12:26:45 +08:00
parent 4b0fad233e
commit 6896a55485
2 changed files with 30 additions and 27 deletions

View File

@@ -1,4 +1,4 @@
import React, { useEffect, useState } from 'react'; import React, { useEffect, useMemo, useState } from 'react';
import { import {
IChooseAdapterEntity, IChooseAdapterEntity,
IPipelineEntity, IPipelineEntity,
@@ -113,8 +113,6 @@ export default function BotForm({
const [dynamicFormConfigList, setDynamicFormConfigList] = useState< const [dynamicFormConfigList, setDynamicFormConfigList] = useState<
IDynamicFormItemSchema[] IDynamicFormItemSchema[]
>([]); >([]);
const [filteredDynamicFormConfigList, setFilteredDynamicFormConfigList] =
useState<IDynamicFormItemSchema[]>([]);
const [, setIsLoading] = useState<boolean>(false); const [, setIsLoading] = useState<boolean>(false);
const [webhookUrl, setWebhookUrl] = useState<string>(''); const [webhookUrl, setWebhookUrl] = useState<string>('');
const [extraWebhookUrl, setExtraWebhookUrl] = useState<string>(''); const [extraWebhookUrl, setExtraWebhookUrl] = useState<string>('');
@@ -125,31 +123,27 @@ export default function BotForm({
const currentAdapter = form.watch('adapter'); const currentAdapter = form.watch('adapter');
const currentAdapterConfig = form.watch('adapter_config'); const currentAdapterConfig = form.watch('adapter_config');
// Derive the filtered config list via useMemo instead of useEffect+setState
// to avoid creating new array references that would cause DynamicFormComponent
// to re-subscribe its form.watch, re-emit values, and trigger an infinite loop.
// Only depend on the specific field we care about (enable-webhook) rather than
// the entire currentAdapterConfig object, which changes on every emission.
const enableWebhook = currentAdapterConfig?.['enable-webhook'];
const filteredDynamicFormConfigList = useMemo(() => {
if (currentAdapter === 'lark' && enableWebhook === false) {
// Hide encrypt-key field when webhook is disabled
return dynamicFormConfigList.filter(
(config) => config.name !== 'encrypt-key',
);
}
// For non-Lark adapters or when webhook is enabled/undefined, show all fields
return dynamicFormConfigList;
}, [currentAdapter, enableWebhook, dynamicFormConfigList]);
useEffect(() => { useEffect(() => {
setBotFormValues(); setBotFormValues();
}, []); }, []);
// Filter dynamic form config list based on enable-webhook status for Lark adapter
useEffect(() => {
if (currentAdapter === 'lark') {
const enableWebhook = currentAdapterConfig?.['enable-webhook'];
if (enableWebhook === false) {
// Hide encrypt-key field when webhook is disabled
setFilteredDynamicFormConfigList(
dynamicFormConfigList.filter(
(config) => config.name !== 'encrypt-key',
),
);
} else {
// Show all fields when webhook is enabled or undefined
setFilteredDynamicFormConfigList(dynamicFormConfigList);
}
} else {
// For non-Lark adapters, show all fields
setFilteredDynamicFormConfigList(dynamicFormConfigList);
}
}, [currentAdapter, currentAdapterConfig, dynamicFormConfigList]);
// 复制到剪贴板的辅助函数 // 复制到剪贴板的辅助函数
const copyToClipboard = ( const copyToClipboard = (
text: string, text: string,
@@ -510,8 +504,7 @@ export default function BotForm({
{/* Webhook 地址显示(统一 Webhook 模式) */} {/* Webhook 地址显示(统一 Webhook 模式) */}
{webhookUrl && {webhookUrl &&
(currentAdapter !== 'lark' || (currentAdapter !== 'lark' || enableWebhook !== false) && (
currentAdapterConfig?.['enable-webhook'] !== false) && (
<FormItem> <FormItem>
<FormLabel>{t('bots.webhookUrl')}</FormLabel> <FormLabel>{t('bots.webhookUrl')}</FormLabel>
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
@@ -675,7 +668,7 @@ export default function BotForm({
</div> </div>
<DynamicFormComponent <DynamicFormComponent
itemConfigList={filteredDynamicFormConfigList} itemConfigList={filteredDynamicFormConfigList}
initialValues={form.watch('adapter_config')} initialValues={currentAdapterConfig}
onSubmit={(values) => { onSubmit={(values) => {
form.setValue('adapter_config', values); form.setValue('adapter_config', values);
}} }}

View File

@@ -211,6 +211,15 @@ export default function DynamicFormComponent({
); );
onSubmitRef.current?.(initialFinalValues); onSubmitRef.current?.(initialFinalValues);
// Update previousInitialValues to the emitted snapshot so that if the
// parent writes these values back as new initialValues, the deep
// comparison in the initialValues-sync useEffect won't detect a change
// and won't trigger an infinite update loop.
previousInitialValues.current = initialFinalValues as Record<
string,
object
>;
const subscription = form.watch(() => { const subscription = form.watch(() => {
const formValues = form.getValues(); const formValues = form.getValues();
const finalValues = itemConfigList.reduce( const finalValues = itemConfigList.reduce(
@@ -221,6 +230,7 @@ export default function DynamicFormComponent({
{} as Record<string, object>, {} as Record<string, object>,
); );
onSubmitRef.current?.(finalValues); onSubmitRef.current?.(finalValues);
previousInitialValues.current = finalValues as Record<string, object>;
}); });
return () => subscription.unsubscribe(); return () => subscription.unsubscribe();
}, [form, itemConfigList]); }, [form, itemConfigList]);