feat(web): base-ui slider (#34064)

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
This commit is contained in:
yyh
2026-03-25 16:03:49 +08:00
committed by GitHub
parent 1789988be7
commit a8e1ff85db
43 changed files with 425 additions and 1068 deletions

View File

@ -145,7 +145,7 @@ describe('AgentStrategy', () => {
/>,
)
expect(screen.getByRole('slider')).toBeInTheDocument()
expect(screen.getByLabelText('Count')).toBeInTheDocument()
expect(screen.getByRole('textbox')).toBeInTheDocument()
})

View File

@ -9,7 +9,6 @@ import { memo } from 'react'
import { useTranslation } from 'react-i18next'
import { Agent } from '@/app/components/base/icons/src/vender/workflow'
import ListEmpty from '@/app/components/base/list-empty'
import Slider from '@/app/components/base/slider'
import {
NumberField,
NumberFieldControls,
@ -18,6 +17,7 @@ import {
NumberFieldIncrement,
NumberFieldInput,
} from '@/app/components/base/ui/number-field'
import { Slider } from '@/app/components/base/ui/slider'
import { FormTypeEnum, ModelTypeEnum } from '@/app/components/header/account-setting/model-provider-page/declarations'
import { useDefaultModel } from '@/app/components/header/account-setting/model-provider-page/hooks'
import Form from '@/app/components/header/account-setting/model-provider-page/model-modal/Form'
@ -147,10 +147,11 @@ export const AgentStrategy = memo((props: AgentStrategyProps) => {
<div className="flex w-[200px] items-center gap-3">
<Slider
value={value}
onChange={onChange}
onValueChange={onChange}
className="w-full"
min={def.min}
max={def.max}
aria-label={renderI18nObject(def.label)}
/>
<NumberField
value={value}

View File

@ -2,7 +2,7 @@
import type { FC } from 'react'
import * as React from 'react'
import { useCallback } from 'react'
import Slider from '@/app/components/base/slider'
import { Slider } from '@/app/components/base/ui/slider'
export type InputNumberWithSliderProps = {
value: number
@ -22,7 +22,7 @@ const InputNumberWithSlider: FC<InputNumberWithSliderProps> = ({
onChange,
}) => {
const handleBlur = useCallback(() => {
if (value === undefined || value === null) {
if (value === undefined || value === null || Number.isNaN(value)) {
onChange(defaultValue)
return
}
@ -57,8 +57,9 @@ const InputNumberWithSlider: FC<InputNumberWithSliderProps> = ({
min={min}
max={max}
step={1}
onChange={onChange}
onValueChange={onChange}
disabled={readonly}
aria-label="Number input slider"
/>
</div>
)

View File

@ -6,8 +6,8 @@ import * as React from 'react'
import { useCallback } from 'react'
import { useTranslation } from 'react-i18next'
import Input from '@/app/components/base/input'
import Slider from '@/app/components/base/slider'
import Switch from '@/app/components/base/switch'
import { Slider } from '@/app/components/base/ui/slider'
import Field from '@/app/components/workflow/nodes/_base/components/field'
import { cn } from '@/utils/classnames'
import { MemoryRole } from '../../../types'
@ -154,7 +154,7 @@ const MemoryConfig: FC<Props> = ({
size="md"
disabled={readonly}
/>
<div className="system-xs-medium-uppercase text-text-tertiary">{t(`${i18nPrefix}.windowSize`, { ns: 'workflow' })}</div>
<div className="text-text-tertiary system-xs-medium-uppercase">{t(`${i18nPrefix}.windowSize`, { ns: 'workflow' })}</div>
</div>
<div className="flex h-8 items-center space-x-2">
<Slider
@ -163,8 +163,9 @@ const MemoryConfig: FC<Props> = ({
min={WINDOW_SIZE_MIN}
max={WINDOW_SIZE_MAX}
step={1}
onChange={handleWindowSizeChange}
onValueChange={handleWindowSizeChange}
disabled={readonly || !payload.window?.enabled}
aria-label={t(`${i18nPrefix}.windowSize`, { ns: 'workflow' })}
/>
<Input
value={(payload.window?.size || WINDOW_SIZE_DEFAULT) as number}

View File

@ -3,8 +3,8 @@ import type {
} from '@/app/components/workflow/types'
import { useTranslation } from 'react-i18next'
import Input from '@/app/components/base/input'
import Slider from '@/app/components/base/slider'
import Switch from '@/app/components/base/switch'
import { Slider } from '@/app/components/base/ui/slider'
import Split from '@/app/components/workflow/nodes/_base/components/split'
import { useRetryConfig } from './hooks'
import s from './style.module.css'
@ -70,9 +70,10 @@ const RetryOnPanel = ({
<Slider
className="mr-3 w-[108px]"
value={retry_config?.max_retries || 3}
onChange={handleMaxRetriesChange}
onValueChange={handleMaxRetriesChange}
min={1}
max={10}
aria-label={t('nodes.common.retry.maxRetries', { ns: 'workflow' })}
/>
<Input
type="number"
@ -91,9 +92,10 @@ const RetryOnPanel = ({
<Slider
className="mr-3 w-[108px]"
value={retry_config?.retry_interval || 1000}
onChange={handleRetryIntervalChange}
onValueChange={handleRetryIntervalChange}
min={100}
max={5000}
aria-label={t('nodes.common.retry.retryInterval', { ns: 'workflow' })}
/>
<Input
type="number"

View File

@ -5,8 +5,8 @@ import * as React from 'react'
import { useTranslation } from 'react-i18next'
import Input from '@/app/components/base/input'
import Select from '@/app/components/base/select'
import Slider from '@/app/components/base/slider'
import Switch from '@/app/components/base/switch'
import { Slider } from '@/app/components/base/ui/slider'
import Field from '@/app/components/workflow/nodes/_base/components/field'
import { ErrorHandleMode } from '@/app/components/workflow/types'
import { MAX_PARALLEL_LIMIT } from '@/config'
@ -57,7 +57,7 @@ const Panel: FC<NodePanelProps<IterationNodeType>> = ({
title={t(`${i18nPrefix}.input`, { ns: 'workflow' })}
required
operations={(
<div className="system-2xs-medium-uppercase flex h-[18px] items-center rounded-[5px] border border-divider-deep px-1 capitalize text-text-tertiary">Array</div>
<div className="flex h-[18px] items-center rounded-[5px] border border-divider-deep px-1 capitalize text-text-tertiary system-2xs-medium-uppercase">Array</div>
)}
>
<VarReferencePicker
@ -76,7 +76,7 @@ const Panel: FC<NodePanelProps<IterationNodeType>> = ({
title={t(`${i18nPrefix}.output`, { ns: 'workflow' })}
required
operations={(
<div className="system-2xs-medium-uppercase flex h-[18px] items-center rounded-[5px] border border-divider-deep px-1 capitalize text-text-tertiary">Array</div>
<div className="flex h-[18px] items-center rounded-[5px] border border-divider-deep px-1 capitalize text-text-tertiary system-2xs-medium-uppercase">Array</div>
)}
>
<VarReferencePicker
@ -103,10 +103,11 @@ const Panel: FC<NodePanelProps<IterationNodeType>> = ({
<Input type="number" wrapperClassName="w-18 mr-4 " max={MAX_PARALLEL_LIMIT} min={MIN_ITERATION_PARALLEL_NUM} value={inputs.parallel_nums} onChange={(e) => { changeParallelNums(Number(e.target.value)) }} />
<Slider
value={inputs.parallel_nums}
onChange={changeParallelNums}
onValueChange={changeParallelNums}
max={MAX_PARALLEL_LIMIT}
min={MIN_ITERATION_PARALLEL_NUM}
className=" mt-4 flex-1 shrink-0"
className="mt-4 flex-1 shrink-0"
aria-label={t(`${i18nPrefix}.MaxParallelismTitle`, { ns: 'workflow' })}
/>
</div>

View File

@ -39,7 +39,7 @@ describe('IndexMethod', () => {
fireEvent.change(container.querySelector('input') as HTMLInputElement, { target: { value: '7' } })
expect(onKeywordNumberChange).toHaveBeenCalledWith(7)
expect(onKeywordNumberChange).toHaveBeenCalledWith(7, expect.anything())
})
it('should disable keyword controls when readonly is enabled', () => {

View File

@ -9,8 +9,8 @@ import {
HighQuality,
} from '@/app/components/base/icons/src/vender/knowledge'
import Input from '@/app/components/base/input'
import Slider from '@/app/components/base/slider'
import Tooltip from '@/app/components/base/tooltip'
import { Slider } from '@/app/components/base/ui/slider'
import { Field } from '@/app/components/workflow/nodes/_base/components/layout'
import { cn } from '@/utils/classnames'
import {
@ -94,7 +94,7 @@ const IndexMethod = ({
>
<div className="flex items-center">
<div className="flex grow items-center">
<div className="system-xs-medium truncate text-text-secondary">
<div className="truncate text-text-secondary system-xs-medium">
{t('form.numberOfKeywords', { ns: 'datasetSettings' })}
</div>
<Tooltip
@ -107,7 +107,8 @@ const IndexMethod = ({
disabled={readonly}
className="mr-3 w-24 shrink-0"
value={keywordNumber}
onChange={onKeywordNumberChange}
onValueChange={onKeywordNumberChange}
aria-label={t('form.numberOfKeywords', { ns: 'datasetSettings' })}
/>
<Input
disabled={readonly}

View File

@ -93,11 +93,11 @@ describe('trigger-schedule components', () => {
const onChange = vi.fn()
render(<OnMinuteSelector value={15} onChange={onChange} />)
const slider = screen.getByRole('slider')
const slider = screen.getByLabelText('workflow.nodes.triggerSchedule.onMinute')
slider.focus()
await user.keyboard('{ArrowRight}')
expect(onChange).toHaveBeenCalledWith(16, 0)
expect(onChange).toHaveBeenCalledWith(16, expect.objectContaining({ activeThumbIndex: 0 }))
})
it('should keep at least one weekday selected', async () => {

View File

@ -1,6 +1,6 @@
import * as React from 'react'
import { useTranslation } from 'react-i18next'
import Slider from '@/app/components/base/slider'
import { Slider } from '@/app/components/base/ui/slider'
type OnMinuteSelectorProps = {
value?: number
@ -27,7 +27,8 @@ const OnMinuteSelector = ({ value = 0, onChange }: OnMinuteSelectorProps) => {
min={0}
max={59}
step={1}
onChange={onChange}
onValueChange={onChange}
aria-label={t('nodes.triggerSchedule.onMinute', { ns: 'workflow' })}
/>
</div>
</div>