diff --git a/web/src/app/home/agents/components/PluginProcessorSettings.tsx b/web/src/app/home/agents/components/PluginProcessorSettings.tsx index e318259e0..127152392 100644 --- a/web/src/app/home/agents/components/PluginProcessorSettings.tsx +++ b/web/src/app/home/agents/components/PluginProcessorSettings.tsx @@ -31,7 +31,10 @@ export default function PluginProcessorSettings({ }, }); return ( -
+
(function BotForm( [adapterNameToDynamicConfigMap, currentAdapter], ); + const connectionModeControllerNames = useMemo(() => { + if (supportedConnectionModes.length <= 1) return []; + const webhookField = dynamicFormConfigList.find( + (item) => item.type === DynamicFormItemType.WEBHOOK_URL, + ); + return webhookField?.show_if?.field ? [webhookField.show_if.field] : []; + }, [dynamicFormConfigList, supportedConnectionModes.length]); + const botGuideSteps = useMemo(() => { const steps: GuidedTourStep[] = []; @@ -1155,6 +1163,7 @@ const BotForm = forwardRef(function BotForm(
{ form.setValue('adapter_config', values, { diff --git a/web/src/app/home/components/dynamic-form/DynamicFormComponent.tsx b/web/src/app/home/components/dynamic-form/DynamicFormComponent.tsx index 8c66f787d..d8e64e79f 100644 --- a/web/src/app/home/components/dynamic-form/DynamicFormComponent.tsx +++ b/web/src/app/home/components/dynamic-form/DynamicFormComponent.tsx @@ -441,6 +441,7 @@ export default function DynamicFormComponent({ systemContext, onValidate, renderItem, + hiddenItemNames, }: { itemConfigList: IDynamicFormItemSchema[]; onSubmit?: (val: object) => unknown; @@ -463,6 +464,8 @@ export default function DynamicFormComponent({ formValues: Record; setFormValue: (name: string, value: unknown) => void; }) => ReactNode | undefined; + /** Fields retained in form state but omitted from the rendered form. */ + hiddenItemNames?: readonly string[]; }) { const isInitialMount = useRef(true); const previousInitialValues = useRef(initialValues); @@ -628,6 +631,7 @@ export default function DynamicFormComponent({ externalDependentValues={externalDependentValues} systemContext={systemContext} renderItem={renderItem} + hiddenItemNames={hiddenItemNames} /> ); } @@ -661,6 +665,7 @@ function DynamicFormFieldList({ externalDependentValues, systemContext, renderItem, + hiddenItemNames, }: DynamicFormFieldsProps) { type FormValues = Record; const { t, i18n } = useTranslation(); @@ -725,6 +730,8 @@ function DynamicFormFieldList({ /> {itemConfigList.map((config, index) => { + if (hiddenItemNames?.includes(config.name)) return null; + // Create a normalized config with type converted to frontend format const normalizedConfig = { ...config, diff --git a/web/tests/e2e/contextual-guides.spec.ts b/web/tests/e2e/contextual-guides.spec.ts index ad6d3c808..d41d5e122 100644 --- a/web/tests/e2e/contextual-guides.spec.ts +++ b/web/tests/e2e/contextual-guides.spec.ts @@ -203,7 +203,8 @@ test('bot guide starts on the detail page after adapter-only creation', async ({ const adapterCard = page.locator('[data-slot="card"]').filter({ has: page.getByText('Adapter Configuration', { exact: true }), }); - await expect(adapterCard.getByRole('switch')).toBeChecked(); + await expect(adapterCard.getByRole('switch')).toHaveCount(0); + await expect(page.getByRole('radio', { name: /^Webhook/ })).toBeChecked(); await guide.getByRole('button', { name: 'Next' }).click(); await expect( diff --git a/web/tests/unit/oss-cloud-ui-privacy.test.mjs b/web/tests/unit/oss-cloud-ui-privacy.test.mjs index 4481aa18f..41a81e375 100644 --- a/web/tests/unit/oss-cloud-ui-privacy.test.mjs +++ b/web/tests/unit/oss-cloud-ui-privacy.test.mjs @@ -17,6 +17,9 @@ const homeSidebarSource = readSource( const botFormSource = readSource( 'src/app/home/bots/components/bot-form/BotForm.tsx', ); +const dynamicFormSource = readSource( + 'src/app/home/components/dynamic-form/DynamicFormComponent.tsx', +); const kbFormSource = readSource( 'src/app/home/knowledge/components/kb-form/KBForm.tsx', ); @@ -52,6 +55,27 @@ test('keeps bot forms spaced with responsive setup and detail columns', () => { assert.match(kbFormSource, / { + assert.match( + botFormSource, + /webhookField\?\.show_if\?\.field\s*\?\s*\[webhookField\.show_if\.field\]/, + ); + assert.match( + botFormSource, + /hiddenItemNames=\{connectionModeControllerNames\}/, + ); + assert.match( + dynamicFormSource, + /if \(hiddenItemNames\?\.includes\(config\.name\)\) return null/, + ); + assert.doesNotMatch( + dynamicFormSource.match( + /const editableItems = useMemo\([\s\S]*?\n \);/, + )?.[0] ?? '', + /hiddenItemNames/, + ); +}); + test('does not expose storage analysis in Cloud settings or via a deep link', () => { assert.match( homeSidebarSource,