From 7c348e994c35b514ac9d9edac3fd48bc5acdc2af Mon Sep 17 00:00:00 2001 From: JzoNg Date: Thu, 23 Apr 2026 17:43:58 +0800 Subject: [PATCH] fix(web): form content style issues --- .../__tests__/type-select.spec.tsx | 41 ++++++--- .../config-var/config-modal/type-select.tsx | 91 +++++++++---------- .../__tests__/component-ui.spec.tsx | 19 ++++ .../plugins/hitl-input-block/component-ui.tsx | 8 +- .../plugins/hitl-input-block/input-field.tsx | 1 + .../plugins/shortcuts-popup-plugin/index.tsx | 2 +- 6 files changed, 98 insertions(+), 64 deletions(-) diff --git a/web/app/components/app/configuration/config-var/config-modal/__tests__/type-select.spec.tsx b/web/app/components/app/configuration/config-var/config-modal/__tests__/type-select.spec.tsx index 2512aa93e8..1d50350229 100644 --- a/web/app/components/app/configuration/config-var/config-modal/__tests__/type-select.spec.tsx +++ b/web/app/components/app/configuration/config-var/config-modal/__tests__/type-select.spec.tsx @@ -1,22 +1,16 @@ /* eslint-disable ts/no-explicit-any */ -import { fireEvent, render, screen } from '@testing-library/react' +import { render, screen } from '@testing-library/react' +import userEvent from '@testing-library/user-event' import TypeSelector from '../type-select' -vi.mock('@/app/components/base/portal-to-follow-elem', () => ({ - PortalToFollowElem: ({ children }: { children: React.ReactNode }) =>
{children}
, - PortalToFollowElemTrigger: ({ children, onClick }: { children: React.ReactNode, onClick?: () => void }) => ( - - ), - PortalToFollowElemContent: ({ children }: { children: React.ReactNode }) =>
{children}
, -})) - vi.mock('@/app/components/workflow/nodes/_base/components/input-var-type-icon', () => ({ default: ({ type }: { type: string }) => {type}, })) describe('TypeSelector', () => { - it('should toggle open state and select a new variable type', () => { + it('should select a new variable type when an option is clicked', async () => { const onSelect = vi.fn() + const user = userEvent.setup() render( { />, ) - fireEvent.click(screen.getByRole('button')) - fireEvent.click(screen.getByText('Number')) + await user.click(screen.getByRole('combobox')) + const [, numberOption] = await screen.findAllByRole('option') + await user.click(numberOption) expect(onSelect).toHaveBeenCalledWith({ value: 'number', name: 'Number' }) }) + + it('should size popup content to match the trigger width', async () => { + const user = userEvent.setup() + + render( + , + ) + + await user.click(screen.getByRole('combobox')) + + const [, numberOption] = await screen.findAllByRole('option') + const popup = numberOption.closest('[data-side]') + + expect(popup).toHaveClass('w-(--anchor-width)') + }) }) diff --git a/web/app/components/app/configuration/config-var/config-modal/type-select.tsx b/web/app/components/app/configuration/config-var/config-modal/type-select.tsx index 5fd7c88b82..6d4ab48b0c 100644 --- a/web/app/components/app/configuration/config-var/config-modal/type-select.tsx +++ b/web/app/components/app/configuration/config-var/config-modal/type-select.tsx @@ -1,16 +1,10 @@ 'use client' import type { FC } from 'react' import type { InputVarType } from '@/app/components/workflow/types' -import { ChevronDownIcon } from '@heroicons/react/20/solid' import { cn } from '@langgenius/dify-ui/cn' +import { Select, SelectContent, SelectItem, SelectItemText, SelectTrigger } from '@langgenius/dify-ui/select' import * as React from 'react' -import { useState } from 'react' import Badge from '@/app/components/base/badge' -import { - PortalToFollowElem, - PortalToFollowElemContent, - PortalToFollowElemTrigger, -} from '@/app/components/base/portal-to-follow-elem' import InputVarTypeIcon from '@/app/components/workflow/nodes/_base/components/input-var-type-icon' import { inputVarTypeToVarType } from '@/app/components/workflow/nodes/_base/components/variable/utils' @@ -32,65 +26,68 @@ const TypeSelector: FC = ({ value, onSelect, items, + popupClassName, popupInnerClassName, readonly, }) => { - const [open, setOpen] = useState(false) - const selectedItem = value ? items.find(item => item.value === value) : undefined + const selectedItem = value ? items.find(item => `${item.value}` === `${value}`) : undefined return ( - { + if (!nextValue) + return + + const nextItem = items.find(item => `${item.value}` === nextValue) + if (nextItem) + onSelect(nextItem) + }} > - !readonly && setOpen(v => !v)} className="w-full"> -
-
+ +
+
{selectedItem?.name}
-
+
{inputVarTypeToVarType(selectedItem?.value as InputVarType)} -
- - - -
- {items.map((item: Item) => ( -
{ - onSelect(item) - setOpen(false) - }} - > -
+ + + {items.map((item: Item) => ( + +
+
- {item.name} + {item.name}
{inputVarTypeToVarType(item.value)}
- ))} -
- - + + ))} + + ) } diff --git a/web/app/components/base/prompt-editor/plugins/hitl-input-block/__tests__/component-ui.spec.tsx b/web/app/components/base/prompt-editor/plugins/hitl-input-block/__tests__/component-ui.spec.tsx index 065f94a27f..317f314eaa 100644 --- a/web/app/components/base/prompt-editor/plugins/hitl-input-block/__tests__/component-ui.spec.tsx +++ b/web/app/components/base/prompt-editor/plugins/hitl-input-block/__tests__/component-ui.spec.tsx @@ -129,6 +129,25 @@ describe('HITLInputComponentUI', () => { expect(getByText('alpha, beta')).toBeInTheDocument() }) + it('should render input type label after the summary content', () => { + const { getByText } = renderComponent({ + formInput: { + type: InputVarType.select, + output_variable_name: 'customer_name', + option_source: { + type: 'constant', + selector: [], + value: ['alpha', 'beta'], + }, + } satisfies FormInputItem, + }) + + const summary = getByText('alpha, beta') + const typeLabel = getByText('appDebug.variableConfig.select') + + expect(summary.compareDocumentPosition(typeLabel) & Node.DOCUMENT_POSITION_FOLLOWING).toBeTruthy() + }) + it('should render file-list summary with max uploads', () => { const { getByText } = renderComponent({ formInput: { diff --git a/web/app/components/base/prompt-editor/plugins/hitl-input-block/component-ui.tsx b/web/app/components/base/prompt-editor/plugins/hitl-input-block/component-ui.tsx index 89d6ef4049..8786fd7407 100644 --- a/web/app/components/base/prompt-editor/plugins/hitl-input-block/component-ui.tsx +++ b/web/app/components/base/prompt-editor/plugins/hitl-input-block/component-ui.tsx @@ -147,11 +147,8 @@ const HITLInputComponentUI: FC = ({
-
+
-
- {inputTypeLabel} -
{variableSelector ? ( = ({
)}
+
+ {inputTypeLabel} +
{/* Actions */} {!readonly && ( diff --git a/web/app/components/base/prompt-editor/plugins/hitl-input-block/input-field.tsx b/web/app/components/base/prompt-editor/plugins/hitl-input-block/input-field.tsx index 2d13d32384..1ae7e248fd 100644 --- a/web/app/components/base/prompt-editor/plugins/hitl-input-block/input-field.tsx +++ b/web/app/components/base/prompt-editor/plugins/hitl-input-block/input-field.tsx @@ -203,6 +203,7 @@ const InputField: React.FC = ({
diff --git a/web/app/components/base/prompt-editor/plugins/shortcuts-popup-plugin/index.tsx b/web/app/components/base/prompt-editor/plugins/shortcuts-popup-plugin/index.tsx index 19a2efb5bc..56b34b96e3 100644 --- a/web/app/components/base/prompt-editor/plugins/shortcuts-popup-plugin/index.tsx +++ b/web/app/components/base/prompt-editor/plugins/shortcuts-popup-plugin/index.tsx @@ -158,7 +158,7 @@ export default function ShortcutsPopupPlugin({ apply({ availableWidth, availableHeight, elements }) { Object.assign(elements.floating.style, { maxWidth: `${Math.min(400, availableWidth)}px`, - maxHeight: `${Math.min(300, availableHeight)}px`, + maxHeight: `${Math.min(560, availableHeight)}px`, overflow: 'auto', }) },