mirror of
https://github.com/langgenius/dify.git
synced 2026-08-02 02:40:43 +08:00
fix(web): stop chunk length/overlap inputs collapsing to an unusable width in narrow containers (#39600)
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
b81737cfb3
commit
d5c0e927c6
@ -197,4 +197,30 @@ describe('GeneralChunkingOptions', () => {
|
||||
expect(onSummaryIndexSettingChange).toHaveBeenCalledWith({ enable: true })
|
||||
})
|
||||
})
|
||||
|
||||
// Regression: dify issue 39592 — the delimiter/max-length/overlap row must
|
||||
// stack (one field per row) in a narrow card and sit three-across when wide,
|
||||
// driven by a container query rather than the viewport. Fails before this
|
||||
// change (row was flex-wrap; no @container ancestor).
|
||||
describe('#39592 narrow-container regression', () => {
|
||||
it('stacks by default and becomes a row across the 552px container query', () => {
|
||||
render(<GeneralChunkingOptions {...defaultProps} />)
|
||||
const delimiterLabel = screen.getByText(`${ns}.stepTwo.separator`)
|
||||
const row = delimiterLabel.closest('.gap-3')
|
||||
expect(row).not.toBeNull()
|
||||
// stacked by default (below threshold)
|
||||
expect(row!.className).toContain('flex-col')
|
||||
// three-across at/above the container threshold
|
||||
expect(row!.className).toContain('@min-[552px]/chunkfields:flex-row')
|
||||
// the previous flex-wrap approach is gone
|
||||
expect(row!.className).not.toContain('flex-wrap')
|
||||
})
|
||||
|
||||
it('marks an ancestor as the query container', () => {
|
||||
render(<GeneralChunkingOptions {...defaultProps} />)
|
||||
const delimiterLabel = screen.getByText(`${ns}.stepTwo.separator`)
|
||||
const container = delimiterLabel.closest('[class*="@container/chunkfields"]')
|
||||
expect(container).not.toBeNull()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@ -136,3 +136,38 @@ describe('OverlapInput', () => {
|
||||
expect(onChange).toHaveBeenLastCalledWith(100)
|
||||
})
|
||||
})
|
||||
|
||||
// Regression: dify issue 39592 — in a narrow card the number inputs collapsed
|
||||
// to a 32px, unusable sliver. The fix reflows on the container (a
|
||||
// @container/chunkfields ancestor, see general-chunking-options): below 552px
|
||||
// each field stacks and is capped at max-w-[288px] so the input reads as a form
|
||||
// field; at/above 552px it restores flex-1 (three across, pixel-identical to
|
||||
// stock). The input keeps a min-width floor as the belt against re-collapse.
|
||||
// jsdom has no layout engine, so we cannot assert pixel widths — we assert the
|
||||
// structural classes. These fail before this change and pass after.
|
||||
describe('#39592 narrow-container regression (structural)', () => {
|
||||
it('gives the MaxLength input a min-width floor so it can never collapse to a sliver', () => {
|
||||
render(<MaxLengthInput onChange={vi.fn()} />)
|
||||
const input = screen.getByRole('textbox')
|
||||
expect(input.className).toContain('min-w-[64px]')
|
||||
})
|
||||
|
||||
it('gives the OverlapInput input a min-width floor too', () => {
|
||||
render(<OverlapInput onChange={vi.fn()} />)
|
||||
const input = screen.getByRole('textbox')
|
||||
expect(input.className).toContain('min-w-[64px]')
|
||||
})
|
||||
|
||||
it('caps each field width when stacked and restores flex-1 across the 552px container query', () => {
|
||||
render(<MaxLengthInput onChange={vi.fn()} />)
|
||||
const field = screen.getByRole('textbox').closest('.space-y-2')
|
||||
expect(field).not.toBeNull()
|
||||
// stacked (default / below threshold): constrained width, no stretch
|
||||
expect(field!.className).toContain('max-w-[288px]')
|
||||
// three-across (at/above threshold): restore flex-1 and drop the cap
|
||||
expect(field!.className).toContain('@min-[552px]/chunkfields:flex-1')
|
||||
expect(field!.className).toContain('@min-[552px]/chunkfields:max-w-none')
|
||||
// the previous flex-wrap approach is gone
|
||||
expect(field!.className).not.toContain('basis-[176px]')
|
||||
})
|
||||
})
|
||||
|
||||
@ -127,8 +127,10 @@ export const GeneralChunkingOptions: FC<GeneralChunkingOptionsProps> = ({
|
||||
}
|
||||
noHighlight={isInUpload && isNotUploadInEmptyDataset}
|
||||
>
|
||||
<div className="flex flex-col gap-y-4">
|
||||
<div className="flex gap-3">
|
||||
<div className="@container/chunkfields flex flex-col gap-y-4">
|
||||
{/* Container query, not a viewport breakpoint: three across at/above a
|
||||
552px container, stacked one-per-row below (see inputs.tsx FormField). */}
|
||||
<div className="flex flex-col gap-3 @min-[552px]/chunkfields:flex-row">
|
||||
<DelimiterInput
|
||||
value={segmentIdentifier}
|
||||
onChange={(e) => onSegmentIdentifierChange(e.target.value)}
|
||||
|
||||
@ -5,6 +5,7 @@ import type {
|
||||
} from '@langgenius/dify-ui/number-field'
|
||||
import type { FC, PropsWithChildren, ReactNode } from 'react'
|
||||
import type { InputProps } from '@/app/components/base/input'
|
||||
import { cn } from '@langgenius/dify-ui/cn'
|
||||
import {
|
||||
NumberField,
|
||||
NumberFieldControls,
|
||||
@ -30,7 +31,12 @@ const TextLabel: FC<PropsWithChildren> = (props) => {
|
||||
|
||||
const FormField: FC<PropsWithChildren<{ label: ReactNode }>> = (props) => {
|
||||
return (
|
||||
<div className="flex-1 space-y-2">
|
||||
// Reflow on the container (a @container/chunkfields ancestor), not the
|
||||
// viewport. Below 552px the fields stack one per row, each capped at
|
||||
// max-w-[288px] so the input reads as a form field, not a full-bleed bar.
|
||||
// At/above 552px this restores flex-1 with no cap, so three columns resolve
|
||||
// to (container - gaps)/3 — pixel-identical to the stock flex-1 layout.
|
||||
<div className="max-w-[288px] space-y-2 @min-[552px]/chunkfields:max-w-none @min-[552px]/chunkfields:flex-1">
|
||||
<TextLabel>{props.label}</TextLabel>
|
||||
{props.children}
|
||||
</div>
|
||||
@ -142,7 +148,10 @@ function CompoundNumberInput({
|
||||
{...inputProps}
|
||||
aria-label={label}
|
||||
size={size}
|
||||
className={className}
|
||||
// min-w-[64px] overrides the component's default min-w-0 so the input
|
||||
// can never collapse to an unusable sliver, even in an unforeseen
|
||||
// container; belt to the row's flex-wrap braces.
|
||||
className={cn('min-w-[64px]', className)}
|
||||
onBlur={onBlur}
|
||||
/>
|
||||
{Boolean(unit) && <NumberFieldUnit size={size}>{unit}</NumberFieldUnit>}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user