refactor(web): make Switch controlled-only and migrate call sites (#32399)

This commit is contained in:
yyh 2026-02-18 23:47:07 +08:00 committed by GitHub
parent 368db04519
commit ea0e1b52a8
58 changed files with 182 additions and 223 deletions

View File

@ -94,7 +94,7 @@ const ConfigPopup: FC<PopupProps> = ({
const switchContent = ( const switchContent = (
<Switch <Switch
className="ml-3" className="ml-3"
defaultValue={enabled} value={enabled}
onChange={onStatusChange} onChange={onStatusChange}
disabled={providerAllNotConfigured} disabled={providerAllNotConfigured}
/> />

View File

@ -144,7 +144,7 @@ const Annotation: FC<Props> = (props) => {
return ( return (
<div className="flex h-full flex-col"> <div className="flex h-full flex-col">
<p className="system-sm-regular text-text-tertiary">{t('description', { ns: 'appLog' })}</p> <p className="text-text-tertiary system-sm-regular">{t('description', { ns: 'appLog' })}</p>
<div className="relative flex h-full flex-1 flex-col py-4"> <div className="relative flex h-full flex-1 flex-col py-4">
<Filter appId={appDetail.id} queryParams={queryParams} setQueryParams={setQueryParams}> <Filter appId={appDetail.id} queryParams={queryParams} setQueryParams={setQueryParams}>
<div className="flex items-center space-x-2"> <div className="flex items-center space-x-2">
@ -152,10 +152,10 @@ const Annotation: FC<Props> = (props) => {
<> <>
<div className={cn(!annotationConfig?.enabled && 'pr-2', 'flex h-7 items-center space-x-1 rounded-lg border border-components-panel-border bg-components-panel-bg-blur pl-2')}> <div className={cn(!annotationConfig?.enabled && 'pr-2', 'flex h-7 items-center space-x-1 rounded-lg border border-components-panel-border bg-components-panel-bg-blur pl-2')}>
<MessageFast className="h-4 w-4 text-util-colors-indigo-indigo-600" /> <MessageFast className="h-4 w-4 text-util-colors-indigo-indigo-600" />
<div className="system-sm-medium text-text-primary">{t('name', { ns: 'appAnnotation' })}</div> <div className="text-text-primary system-sm-medium">{t('name', { ns: 'appAnnotation' })}</div>
<Switch <Switch
key={controlRefreshSwitch} key={controlRefreshSwitch}
defaultValue={annotationConfig?.enabled} value={annotationConfig?.enabled ?? false}
size="md" size="md"
onChange={async (value) => { onChange={async (value) => {
if (value) { if (value) {

View File

@ -121,7 +121,7 @@ const ConfigVision: FC = () => {
<ParamConfig /> <ParamConfig />
<div className="ml-1 mr-3 h-3.5 w-[1px] bg-divider-regular"></div> <div className="ml-1 mr-3 h-3.5 w-[1px] bg-divider-regular"></div>
<Switch <Switch
defaultValue={isImageEnabled} value={isImageEnabled}
onChange={handleChange} onChange={handleChange}
size="md" size="md"
/> />

View File

@ -298,7 +298,7 @@ const AgentTools: FC = () => {
<div className={cn(item.isDeleted && 'opacity-50')}> <div className={cn(item.isDeleted && 'opacity-50')}>
{!item.notAuthor && ( {!item.notAuthor && (
<Switch <Switch
defaultValue={item.isDeleted ? false : item.enabled} value={item.isDeleted ? false : item.enabled}
disabled={item.isDeleted || readonly} disabled={item.isDeleted || readonly}
size="md" size="md"
onChange={(enabled) => { onChange={(enabled) => {

View File

@ -69,7 +69,7 @@ const ConfigAudio: FC = () => {
<div className="flex shrink-0 items-center"> <div className="flex shrink-0 items-center">
<div className="ml-1 mr-3 h-3.5 w-[1px] bg-divider-subtle"></div> <div className="ml-1 mr-3 h-3.5 w-[1px] bg-divider-subtle"></div>
<Switch <Switch
defaultValue={isAudioEnabled} value={isAudioEnabled}
onChange={handleChange} onChange={handleChange}
size="md" size="md"
/> />

View File

@ -69,7 +69,7 @@ const ConfigDocument: FC = () => {
<div className="flex shrink-0 items-center"> <div className="flex shrink-0 items-center">
<div className="ml-1 mr-3 h-3.5 w-[1px] bg-divider-subtle"></div> <div className="ml-1 mr-3 h-3.5 w-[1px] bg-divider-subtle"></div>
<Switch <Switch
defaultValue={isDocumentEnabled} value={isDocumentEnabled}
onChange={handleChange} onChange={handleChange}
size="md" size="md"
/> />

View File

@ -188,14 +188,14 @@ const ConfigContent: FC<Props> = ({
return ( return (
<div> <div>
<div className="system-xl-semibold text-text-primary">{t('retrievalSettings', { ns: 'dataset' })}</div> <div className="text-text-primary system-xl-semibold">{t('retrievalSettings', { ns: 'dataset' })}</div>
<div className="system-xs-regular text-text-tertiary"> <div className="text-text-tertiary system-xs-regular">
{t('defaultRetrievalTip', { ns: 'dataset' })} {t('defaultRetrievalTip', { ns: 'dataset' })}
</div> </div>
{type === RETRIEVE_TYPE.multiWay && ( {type === RETRIEVE_TYPE.multiWay && (
<> <>
<div className="my-2 flex flex-col items-center py-1"> <div className="my-2 flex flex-col items-center py-1">
<div className="system-xs-semibold-uppercase mb-2 mr-2 shrink-0 text-text-secondary"> <div className="mb-2 mr-2 shrink-0 text-text-secondary system-xs-semibold-uppercase">
{t('rerankSettings', { ns: 'dataset' })} {t('rerankSettings', { ns: 'dataset' })}
</div> </div>
<Divider bgStyle="gradient" className="m-0 !h-px" /> <Divider bgStyle="gradient" className="m-0 !h-px" />
@ -203,21 +203,21 @@ const ConfigContent: FC<Props> = ({
{ {
selectedDatasetsMode.inconsistentEmbeddingModel selectedDatasetsMode.inconsistentEmbeddingModel
&& ( && (
<div className="system-xs-medium mt-4 text-text-warning"> <div className="mt-4 text-text-warning system-xs-medium">
{t('inconsistentEmbeddingModelTip', { ns: 'dataset' })} {t('inconsistentEmbeddingModelTip', { ns: 'dataset' })}
</div> </div>
) )
} }
{ {
selectedDatasetsMode.mixtureInternalAndExternal && ( selectedDatasetsMode.mixtureInternalAndExternal && (
<div className="system-xs-medium mt-4 text-text-warning"> <div className="mt-4 text-text-warning system-xs-medium">
{t('mixtureInternalAndExternalTip', { ns: 'dataset' })} {t('mixtureInternalAndExternalTip', { ns: 'dataset' })}
</div> </div>
) )
} }
{ {
selectedDatasetsMode.allExternal && ( selectedDatasetsMode.allExternal && (
<div className="system-xs-medium mt-4 text-text-warning"> <div className="mt-4 text-text-warning system-xs-medium">
{t('allExternalTip', { ns: 'dataset' })} {t('allExternalTip', { ns: 'dataset' })}
</div> </div>
) )
@ -225,7 +225,7 @@ const ConfigContent: FC<Props> = ({
{ {
selectedDatasetsMode.mixtureHighQualityAndEconomic selectedDatasetsMode.mixtureHighQualityAndEconomic
&& ( && (
<div className="system-xs-medium mt-4 text-text-warning"> <div className="mt-4 text-text-warning system-xs-medium">
{t('mixtureHighQualityAndEconomicTip', { ns: 'dataset' })} {t('mixtureHighQualityAndEconomicTip', { ns: 'dataset' })}
</div> </div>
) )
@ -238,7 +238,7 @@ const ConfigContent: FC<Props> = ({
<div <div
key={option.value} key={option.value}
className={cn( className={cn(
'system-sm-medium flex h-8 w-[calc((100%-8px)/2)] cursor-pointer items-center justify-center rounded-lg border border-components-option-card-option-border bg-components-option-card-option-bg text-text-secondary', 'flex h-8 w-[calc((100%-8px)/2)] cursor-pointer items-center justify-center rounded-lg border border-components-option-card-option-border bg-components-option-card-option-bg text-text-secondary system-sm-medium',
selectedRerankMode === option.value && 'border-[1.5px] border-components-option-card-option-selected-border bg-components-option-card-option-selected-bg text-text-primary', selectedRerankMode === option.value && 'border-[1.5px] border-components-option-card-option-selected-border bg-components-option-card-option-selected-bg text-text-primary',
)} )}
onClick={() => handleRerankModeChange(option.value)} onClick={() => handleRerankModeChange(option.value)}
@ -267,12 +267,12 @@ const ConfigContent: FC<Props> = ({
canManuallyToggleRerank && ( canManuallyToggleRerank && (
<Switch <Switch
size="md" size="md"
defaultValue={showRerankModel} value={showRerankModel ?? false}
onChange={handleManuallyToggleRerank} onChange={handleManuallyToggleRerank}
/> />
) )
} }
<div className="system-sm-semibold ml-1 leading-[32px] text-text-secondary">{t('modelProvider.rerankModel.key', { ns: 'common' })}</div> <div className="ml-1 leading-[32px] text-text-secondary system-sm-semibold">{t('modelProvider.rerankModel.key', { ns: 'common' })}</div>
<Tooltip <Tooltip
popupContent={( popupContent={(
<div className="w-[200px]"> <div className="w-[200px]">

View File

@ -130,7 +130,7 @@ const Tools = () => {
className="flex h-7 cursor-pointer items-center px-3 text-xs font-medium text-gray-700" className="flex h-7 cursor-pointer items-center px-3 text-xs font-medium text-gray-700"
onClick={() => handleOpenExternalDataToolModal({}, -1)} onClick={() => handleOpenExternalDataToolModal({}, -1)}
> >
<RiAddLine className="mr-[5px] h-3.5 w-3.5 " /> <RiAddLine className="mr-[5px] h-3.5 w-3.5" />
{t('operation.add', { ns: 'common' })} {t('operation.add', { ns: 'common' })}
</div> </div>
</div> </div>
@ -180,7 +180,7 @@ const Tools = () => {
<div className="ml-2 mr-3 hidden h-3.5 w-[1px] bg-gray-200 group-hover:block" /> <div className="ml-2 mr-3 hidden h-3.5 w-[1px] bg-gray-200 group-hover:block" />
<Switch <Switch
size="l" size="l"
defaultValue={item.enabled} value={item.enabled ?? false}
onChange={(enabled: boolean) => handleSaveExternalDataToolModal({ ...item, enabled }, index)} onChange={(enabled: boolean) => handleSaveExternalDataToolModal({ ...item, enabled }, index)}
/> />
</div> </div>

View File

@ -260,7 +260,7 @@ function AppCard({
offset={24} offset={24}
> >
<div> <div>
<Switch defaultValue={runningStatus} onChange={onChangeStatus} disabled={toggleDisabled} /> <Switch value={runningStatus} onChange={onChangeStatus} disabled={toggleDisabled} />
</div> </div>
</Tooltip> </Tooltip>
</div> </div>

View File

@ -281,7 +281,7 @@ const SettingsModal: FC<ISettingsModalProps> = ({
<div className="flex items-center justify-between"> <div className="flex items-center justify-between">
<div className={cn('system-sm-semibold py-1 text-text-secondary')}>{t('answerIcon.title', { ns: 'app' })}</div> <div className={cn('system-sm-semibold py-1 text-text-secondary')}>{t('answerIcon.title', { ns: 'app' })}</div>
<Switch <Switch
defaultValue={inputInfo.use_icon_as_answer_icon} value={inputInfo.use_icon_as_answer_icon}
onChange={v => setInputInfo({ ...inputInfo, use_icon_as_answer_icon: v })} onChange={v => setInputInfo({ ...inputInfo, use_icon_as_answer_icon: v })}
/> />
</div> </div>
@ -315,7 +315,7 @@ const SettingsModal: FC<ISettingsModalProps> = ({
/> />
<div className="flex items-center justify-between"> <div className="flex items-center justify-between">
<p className={cn('body-xs-regular text-text-tertiary')}>{t(`${prefixSettings}.chatColorThemeInverted`, { ns: 'appOverview' })}</p> <p className={cn('body-xs-regular text-text-tertiary')}>{t(`${prefixSettings}.chatColorThemeInverted`, { ns: 'appOverview' })}</p>
<Switch defaultValue={inputInfo.chatColorThemeInverted} onChange={v => setInputInfo({ ...inputInfo, chatColorThemeInverted: v })}></Switch> <Switch value={inputInfo.chatColorThemeInverted} onChange={v => setInputInfo({ ...inputInfo, chatColorThemeInverted: v })}></Switch>
</div> </div>
</div> </div>
</div> </div>
@ -326,7 +326,7 @@ const SettingsModal: FC<ISettingsModalProps> = ({
<div className={cn('system-sm-semibold py-1 text-text-secondary')}>{t(`${prefixSettings}.workflow.subTitle`, { ns: 'appOverview' })}</div> <div className={cn('system-sm-semibold py-1 text-text-secondary')}>{t(`${prefixSettings}.workflow.subTitle`, { ns: 'appOverview' })}</div>
<Switch <Switch
disabled={!(appInfo.mode === AppModeEnum.WORKFLOW || appInfo.mode === AppModeEnum.ADVANCED_CHAT)} disabled={!(appInfo.mode === AppModeEnum.WORKFLOW || appInfo.mode === AppModeEnum.ADVANCED_CHAT)}
defaultValue={inputInfo.show_workflow_steps} value={inputInfo.show_workflow_steps}
onChange={v => setInputInfo({ ...inputInfo, show_workflow_steps: v })} onChange={v => setInputInfo({ ...inputInfo, show_workflow_steps: v })}
/> />
</div> </div>
@ -380,7 +380,7 @@ const SettingsModal: FC<ISettingsModalProps> = ({
> >
<Switch <Switch
disabled={!webappCopyrightEnabled} disabled={!webappCopyrightEnabled}
defaultValue={inputInfo.copyrightSwitchValue} value={inputInfo.copyrightSwitchValue}
onChange={v => setInputInfo({ ...inputInfo, copyrightSwitchValue: v })} onChange={v => setInputInfo({ ...inputInfo, copyrightSwitchValue: v })}
/> />
</Tooltip> </Tooltip>

View File

@ -192,7 +192,7 @@ function TriggerCard({ appInfo, onToggleResult }: ITriggerCardProps) {
</div> </div>
<div className="shrink-0"> <div className="shrink-0">
<Switch <Switch
defaultValue={trigger.status === 'enabled'} value={trigger.status === 'enabled'}
onChange={enabled => onToggleTrigger(trigger, enabled)} onChange={enabled => onToggleTrigger(trigger, enabled)}
disabled={!isCurrentWorkspaceEditor} disabled={!isCurrentWorkspaceEditor}
/> />

View File

@ -48,7 +48,7 @@ const FeatureCard = ({
</Tooltip> </Tooltip>
)} )}
</div> </div>
<Switch disabled={disabled} className="shrink-0" onChange={state => onChange?.(state)} defaultValue={value} /> <Switch disabled={disabled} className="shrink-0" onChange={state => onChange?.(state)} value={value} />
</div> </div>
{description && ( {description && (
<div className="system-xs-regular line-clamp-2 min-h-8 text-text-tertiary">{description}</div> <div className="system-xs-regular line-clamp-2 min-h-8 text-text-tertiary">{description}</div>

View File

@ -38,7 +38,7 @@ const ModerationContent: FC<ModerationContentProps> = ({
} }
<Switch <Switch
size="l" size="l"
defaultValue={config.enabled} value={config.enabled}
onChange={v => handleConfigChange('enabled', v)} onChange={v => handleConfigChange('enabled', v)}
/> />
</div> </div>

View File

@ -232,7 +232,7 @@ const VoiceParamConfig = ({
</div> </div>
<Switch <Switch
className="shrink-0" className="shrink-0"
defaultValue={text2speech?.autoPlay === TtsAutoPlay.enabled} value={text2speech?.autoPlay === TtsAutoPlay.enabled}
onChange={(value: boolean) => { onChange={(value: boolean) => {
handleChange({ handleChange({
autoPlay: value ? TtsAutoPlay.enabled : TtsAutoPlay.disabled, autoPlay: value ? TtsAutoPlay.enabled : TtsAutoPlay.disabled,

View File

@ -30,7 +30,7 @@ const ParamItem: FC<Props> = ({ className, id, name, noTooltip, tip, step = 0.1,
<Switch <Switch
size="md" size="md"
className="mr-2" className="mr-2"
defaultValue={enable} value={enable}
onChange={async (val) => { onChange={async (val) => {
onSwitchChange?.(id, val) onSwitchChange?.(id, val)
}} }}

View File

@ -4,41 +4,54 @@ import { describe, expect, it, vi } from 'vitest'
import Switch from './index' import Switch from './index'
describe('Switch', () => { describe('Switch', () => {
it('should render in unchecked state by default', () => { it('should render in unchecked state when value is false', () => {
render(<Switch />) render(<Switch value={false} />)
const switchElement = screen.getByRole('switch') const switchElement = screen.getByRole('switch')
expect(switchElement).toBeInTheDocument() expect(switchElement).toBeInTheDocument()
expect(switchElement).toHaveAttribute('aria-checked', 'false') expect(switchElement).toHaveAttribute('aria-checked', 'false')
}) })
it('should render in checked state when defaultValue is true', () => { it('should render in checked state when value is true', () => {
render(<Switch defaultValue={true} />) render(<Switch value={true} />)
const switchElement = screen.getByRole('switch') const switchElement = screen.getByRole('switch')
expect(switchElement).toHaveAttribute('aria-checked', 'true') expect(switchElement).toHaveAttribute('aria-checked', 'true')
}) })
it('should toggle state and call onChange when clicked', async () => { it('should call onChange with next value when clicked', async () => {
const onChange = vi.fn() const onChange = vi.fn()
const user = userEvent.setup() const user = userEvent.setup()
render(<Switch onChange={onChange} />) render(<Switch value={false} onChange={onChange} />)
const switchElement = screen.getByRole('switch') const switchElement = screen.getByRole('switch')
await user.click(switchElement) await user.click(switchElement)
expect(switchElement).toHaveAttribute('aria-checked', 'true')
expect(onChange).toHaveBeenCalledWith(true) expect(onChange).toHaveBeenCalledWith(true)
expect(onChange).toHaveBeenCalledTimes(1) expect(onChange).toHaveBeenCalledTimes(1)
await user.click(switchElement) // Controlled component stays the same until parent updates value.
expect(switchElement).toHaveAttribute('aria-checked', 'false') expect(switchElement).toHaveAttribute('aria-checked', 'false')
expect(onChange).toHaveBeenCalledWith(false) })
expect(onChange).toHaveBeenCalledTimes(2)
it('should work in controlled mode with value prop', async () => {
const onChange = vi.fn()
const user = userEvent.setup()
const { rerender } = render(<Switch value={false} onChange={onChange} />)
const switchElement = screen.getByRole('switch')
expect(switchElement).toHaveAttribute('aria-checked', 'false')
await user.click(switchElement)
expect(onChange).toHaveBeenCalledWith(true)
expect(switchElement).toHaveAttribute('aria-checked', 'false')
rerender(<Switch value={true} onChange={onChange} />)
expect(switchElement).toHaveAttribute('aria-checked', 'true')
}) })
it('should not call onChange when disabled', async () => { it('should not call onChange when disabled', async () => {
const onChange = vi.fn() const onChange = vi.fn()
const user = userEvent.setup() const user = userEvent.setup()
render(<Switch disabled onChange={onChange} />) render(<Switch value={false} disabled onChange={onChange} />)
const switchElement = screen.getByRole('switch') const switchElement = screen.getByRole('switch')
expect(switchElement).toHaveClass('!cursor-not-allowed', '!opacity-50') expect(switchElement).toHaveClass('!cursor-not-allowed', '!opacity-50')
@ -48,37 +61,36 @@ describe('Switch', () => {
}) })
it('should apply correct size classes', () => { it('should apply correct size classes', () => {
const { rerender } = render(<Switch size="xs" />) const { rerender } = render(<Switch value={false} size="xs" />)
// We only need to find the element once // We only need to find the element once
const switchElement = screen.getByRole('switch') const switchElement = screen.getByRole('switch')
expect(switchElement).toHaveClass('h-2.5', 'w-3.5', 'rounded-sm') expect(switchElement).toHaveClass('h-2.5', 'w-3.5', 'rounded-sm')
rerender(<Switch size="sm" />) rerender(<Switch value={false} size="sm" />)
expect(switchElement).toHaveClass('h-3', 'w-5') expect(switchElement).toHaveClass('h-3', 'w-5')
rerender(<Switch size="md" />) rerender(<Switch value={false} size="md" />)
expect(switchElement).toHaveClass('h-4', 'w-7') expect(switchElement).toHaveClass('h-4', 'w-7')
rerender(<Switch size="l" />) rerender(<Switch value={false} size="l" />)
expect(switchElement).toHaveClass('h-5', 'w-9') expect(switchElement).toHaveClass('h-5', 'w-9')
rerender(<Switch size="lg" />) rerender(<Switch value={false} size="lg" />)
expect(switchElement).toHaveClass('h-6', 'w-11') expect(switchElement).toHaveClass('h-6', 'w-11')
}) })
it('should apply custom className', () => { it('should apply custom className', () => {
render(<Switch className="custom-test-class" />) render(<Switch value={false} className="custom-test-class" />)
expect(screen.getByRole('switch')).toHaveClass('custom-test-class') expect(screen.getByRole('switch')).toHaveClass('custom-test-class')
}) })
it('should apply correct background colors based on state', async () => { it('should apply correct background colors based on value prop', () => {
const user = userEvent.setup() const { rerender } = render(<Switch value={false} />)
render(<Switch />)
const switchElement = screen.getByRole('switch') const switchElement = screen.getByRole('switch')
expect(switchElement).toHaveClass('bg-components-toggle-bg-unchecked') expect(switchElement).toHaveClass('bg-components-toggle-bg-unchecked')
await user.click(switchElement) rerender(<Switch value={true} />)
expect(switchElement).toHaveClass('bg-components-toggle-bg') expect(switchElement).toHaveClass('bg-components-toggle-bg')
}) })
}) })

View File

@ -14,15 +14,18 @@ const meta = {
}, },
}, },
tags: ['autodocs'], tags: ['autodocs'],
args: {
value: false,
},
argTypes: { argTypes: {
size: { size: {
control: 'select', control: 'select',
options: ['xs', 'sm', 'md', 'lg', 'l'], options: ['xs', 'sm', 'md', 'lg', 'l'],
description: 'Switch size', description: 'Switch size',
}, },
defaultValue: { value: {
control: 'boolean', control: 'boolean',
description: 'Default checked state', description: 'Checked state (controlled)',
}, },
disabled: { disabled: {
control: 'boolean', control: 'boolean',
@ -36,14 +39,14 @@ type Story = StoryObj<typeof meta>
// Interactive demo wrapper // Interactive demo wrapper
const SwitchDemo = (args: any) => { const SwitchDemo = (args: any) => {
const [enabled, setEnabled] = useState(args.defaultValue || false) const [enabled, setEnabled] = useState(args.value ?? false)
return ( return (
<div style={{ width: '300px' }}> <div style={{ width: '300px' }}>
<div className="flex items-center gap-3"> <div className="flex items-center gap-3">
<Switch <Switch
{...args} {...args}
defaultValue={enabled} value={enabled}
onChange={(value) => { onChange={(value) => {
setEnabled(value) setEnabled(value)
console.log('Switch toggled:', value) console.log('Switch toggled:', value)
@ -62,7 +65,7 @@ export const Default: Story = {
render: args => <SwitchDemo {...args} />, render: args => <SwitchDemo {...args} />,
args: { args: {
size: 'md', size: 'md',
defaultValue: false, value: false,
disabled: false, disabled: false,
}, },
} }
@ -72,7 +75,7 @@ export const DefaultOn: Story = {
render: args => <SwitchDemo {...args} />, render: args => <SwitchDemo {...args} />,
args: { args: {
size: 'md', size: 'md',
defaultValue: true, value: true,
disabled: false, disabled: false,
}, },
} }
@ -82,7 +85,7 @@ export const DisabledOff: Story = {
render: args => <SwitchDemo {...args} />, render: args => <SwitchDemo {...args} />,
args: { args: {
size: 'md', size: 'md',
defaultValue: false, value: false,
disabled: true, disabled: true,
}, },
} }
@ -92,7 +95,7 @@ export const DisabledOn: Story = {
render: args => <SwitchDemo {...args} />, render: args => <SwitchDemo {...args} />,
args: { args: {
size: 'md', size: 'md',
defaultValue: true, value: true,
disabled: true, disabled: true,
}, },
} }
@ -111,31 +114,31 @@ const SizeComparisonDemo = () => {
<div style={{ width: '400px' }} className="space-y-4"> <div style={{ width: '400px' }} className="space-y-4">
<div className="flex items-center justify-between"> <div className="flex items-center justify-between">
<div className="flex items-center gap-3"> <div className="flex items-center gap-3">
<Switch size="xs" defaultValue={states.xs} onChange={v => setStates({ ...states, xs: v })} /> <Switch size="xs" value={states.xs} onChange={v => setStates({ ...states, xs: v })} />
<span className="text-sm text-gray-700">Extra Small (xs)</span> <span className="text-sm text-gray-700">Extra Small (xs)</span>
</div> </div>
</div> </div>
<div className="flex items-center justify-between"> <div className="flex items-center justify-between">
<div className="flex items-center gap-3"> <div className="flex items-center gap-3">
<Switch size="sm" defaultValue={states.sm} onChange={v => setStates({ ...states, sm: v })} /> <Switch size="sm" value={states.sm} onChange={v => setStates({ ...states, sm: v })} />
<span className="text-sm text-gray-700">Small (sm)</span> <span className="text-sm text-gray-700">Small (sm)</span>
</div> </div>
</div> </div>
<div className="flex items-center justify-between"> <div className="flex items-center justify-between">
<div className="flex items-center gap-3"> <div className="flex items-center gap-3">
<Switch size="md" defaultValue={states.md} onChange={v => setStates({ ...states, md: v })} /> <Switch size="md" value={states.md} onChange={v => setStates({ ...states, md: v })} />
<span className="text-sm text-gray-700">Medium (md)</span> <span className="text-sm text-gray-700">Medium (md)</span>
</div> </div>
</div> </div>
<div className="flex items-center justify-between"> <div className="flex items-center justify-between">
<div className="flex items-center gap-3"> <div className="flex items-center gap-3">
<Switch size="l" defaultValue={states.l} onChange={v => setStates({ ...states, l: v })} /> <Switch size="l" value={states.l} onChange={v => setStates({ ...states, l: v })} />
<span className="text-sm text-gray-700">Large (l)</span> <span className="text-sm text-gray-700">Large (l)</span>
</div> </div>
</div> </div>
<div className="flex items-center justify-between"> <div className="flex items-center justify-between">
<div className="flex items-center gap-3"> <div className="flex items-center gap-3">
<Switch size="lg" defaultValue={states.lg} onChange={v => setStates({ ...states, lg: v })} /> <Switch size="lg" value={states.lg} onChange={v => setStates({ ...states, lg: v })} />
<span className="text-sm text-gray-700">Extra Large (lg)</span> <span className="text-sm text-gray-700">Extra Large (lg)</span>
</div> </div>
</div> </div>
@ -160,7 +163,7 @@ const WithLabelsDemo = () => {
</div> </div>
<Switch <Switch
size="md" size="md"
defaultValue={enabled} value={enabled}
onChange={setEnabled} onChange={setEnabled}
/> />
</div> </div>
@ -197,7 +200,7 @@ const SettingsPanelDemo = () => {
</div> </div>
<Switch <Switch
size="md" size="md"
defaultValue={settings.notifications} value={settings.notifications}
onChange={v => updateSetting('notifications', v)} onChange={v => updateSetting('notifications', v)}
/> />
</div> </div>
@ -209,7 +212,7 @@ const SettingsPanelDemo = () => {
</div> </div>
<Switch <Switch
size="md" size="md"
defaultValue={settings.autoSave} value={settings.autoSave}
onChange={v => updateSetting('autoSave', v)} onChange={v => updateSetting('autoSave', v)}
/> />
</div> </div>
@ -221,7 +224,7 @@ const SettingsPanelDemo = () => {
</div> </div>
<Switch <Switch
size="md" size="md"
defaultValue={settings.darkMode} value={settings.darkMode}
onChange={v => updateSetting('darkMode', v)} onChange={v => updateSetting('darkMode', v)}
/> />
</div> </div>
@ -233,7 +236,7 @@ const SettingsPanelDemo = () => {
</div> </div>
<Switch <Switch
size="md" size="md"
defaultValue={settings.analytics} value={settings.analytics}
onChange={v => updateSetting('analytics', v)} onChange={v => updateSetting('analytics', v)}
/> />
</div> </div>
@ -245,7 +248,7 @@ const SettingsPanelDemo = () => {
</div> </div>
<Switch <Switch
size="md" size="md"
defaultValue={settings.emailUpdates} value={settings.emailUpdates}
onChange={v => updateSetting('emailUpdates', v)} onChange={v => updateSetting('emailUpdates', v)}
/> />
</div> </div>
@ -279,7 +282,7 @@ const PrivacyControlsDemo = () => {
</div> </div>
<Switch <Switch
size="md" size="md"
defaultValue={privacy.profilePublic} value={privacy.profilePublic}
onChange={v => setPrivacy({ ...privacy, profilePublic: v })} onChange={v => setPrivacy({ ...privacy, profilePublic: v })}
/> />
</div> </div>
@ -291,7 +294,7 @@ const PrivacyControlsDemo = () => {
</div> </div>
<Switch <Switch
size="md" size="md"
defaultValue={privacy.showEmail} value={privacy.showEmail}
onChange={v => setPrivacy({ ...privacy, showEmail: v })} onChange={v => setPrivacy({ ...privacy, showEmail: v })}
/> />
</div> </div>
@ -303,7 +306,7 @@ const PrivacyControlsDemo = () => {
</div> </div>
<Switch <Switch
size="md" size="md"
defaultValue={privacy.allowMessages} value={privacy.allowMessages}
onChange={v => setPrivacy({ ...privacy, allowMessages: v })} onChange={v => setPrivacy({ ...privacy, allowMessages: v })}
/> />
</div> </div>
@ -315,7 +318,7 @@ const PrivacyControlsDemo = () => {
</div> </div>
<Switch <Switch
size="md" size="md"
defaultValue={privacy.shareActivity} value={privacy.shareActivity}
onChange={v => setPrivacy({ ...privacy, shareActivity: v })} onChange={v => setPrivacy({ ...privacy, shareActivity: v })}
/> />
</div> </div>
@ -351,7 +354,7 @@ const FeatureTogglesDemo = () => {
</div> </div>
<Switch <Switch
size="md" size="md"
defaultValue={features.betaFeatures} value={features.betaFeatures}
onChange={v => setFeatures({ ...features, betaFeatures: v })} onChange={v => setFeatures({ ...features, betaFeatures: v })}
/> />
</div> </div>
@ -366,7 +369,7 @@ const FeatureTogglesDemo = () => {
</div> </div>
<Switch <Switch
size="md" size="md"
defaultValue={features.experimentalUI} value={features.experimentalUI}
onChange={v => setFeatures({ ...features, experimentalUI: v })} onChange={v => setFeatures({ ...features, experimentalUI: v })}
/> />
</div> </div>
@ -381,7 +384,7 @@ const FeatureTogglesDemo = () => {
</div> </div>
<Switch <Switch
size="md" size="md"
defaultValue={features.advancedMode} value={features.advancedMode}
onChange={v => setFeatures({ ...features, advancedMode: v })} onChange={v => setFeatures({ ...features, advancedMode: v })}
/> />
</div> </div>
@ -396,7 +399,7 @@ const FeatureTogglesDemo = () => {
</div> </div>
<Switch <Switch
size="md" size="md"
defaultValue={features.developerTools} value={features.developerTools}
onChange={v => setFeatures({ ...features, developerTools: v })} onChange={v => setFeatures({ ...features, developerTools: v })}
/> />
</div> </div>
@ -440,7 +443,7 @@ const NotificationPreferencesDemo = () => {
</div> </div>
<Switch <Switch
size="md" size="md"
defaultValue={notifications.email} value={notifications.email}
onChange={v => setNotifications({ ...notifications, email: v })} onChange={v => setNotifications({ ...notifications, email: v })}
/> />
</div> </div>
@ -455,7 +458,7 @@ const NotificationPreferencesDemo = () => {
</div> </div>
<Switch <Switch
size="md" size="md"
defaultValue={notifications.push} value={notifications.push}
onChange={v => setNotifications({ ...notifications, push: v })} onChange={v => setNotifications({ ...notifications, push: v })}
/> />
</div> </div>
@ -470,7 +473,7 @@ const NotificationPreferencesDemo = () => {
</div> </div>
<Switch <Switch
size="md" size="md"
defaultValue={notifications.sms} value={notifications.sms}
onChange={v => setNotifications({ ...notifications, sms: v })} onChange={v => setNotifications({ ...notifications, sms: v })}
/> />
</div> </div>
@ -485,7 +488,7 @@ const NotificationPreferencesDemo = () => {
</div> </div>
<Switch <Switch
size="md" size="md"
defaultValue={notifications.desktop} value={notifications.desktop}
onChange={v => setNotifications({ ...notifications, desktop: v })} onChange={v => setNotifications({ ...notifications, desktop: v })}
/> />
</div> </div>
@ -523,7 +526,7 @@ const APIAccessControlDemo = () => {
</div> </div>
<Switch <Switch
size="md" size="md"
defaultValue={access.readAccess} value={access.readAccess}
onChange={v => setAccess({ ...access, readAccess: v })} onChange={v => setAccess({ ...access, readAccess: v })}
/> />
</div> </div>
@ -539,7 +542,7 @@ const APIAccessControlDemo = () => {
</div> </div>
<Switch <Switch
size="md" size="md"
defaultValue={access.writeAccess} value={access.writeAccess}
onChange={v => setAccess({ ...access, writeAccess: v })} onChange={v => setAccess({ ...access, writeAccess: v })}
/> />
</div> </div>
@ -555,7 +558,7 @@ const APIAccessControlDemo = () => {
</div> </div>
<Switch <Switch
size="md" size="md"
defaultValue={access.deleteAccess} value={access.deleteAccess}
onChange={v => setAccess({ ...access, deleteAccess: v })} onChange={v => setAccess({ ...access, deleteAccess: v })}
/> />
</div> </div>
@ -571,7 +574,7 @@ const APIAccessControlDemo = () => {
</div> </div>
<Switch <Switch
size="md" size="md"
defaultValue={access.adminAccess} value={access.adminAccess}
onChange={v => setAccess({ ...access, adminAccess: v })} onChange={v => setAccess({ ...access, adminAccess: v })}
/> />
</div> </div>
@ -609,7 +612,7 @@ const CompactListDemo = () => {
<span className="text-sm text-gray-700">{item.name}</span> <span className="text-sm text-gray-700">{item.name}</span>
<Switch <Switch
size="sm" size="sm"
defaultValue={item.enabled} value={item.enabled}
onChange={() => toggleItem(item.id)} onChange={() => toggleItem(item.id)}
/> />
</div> </div>
@ -628,7 +631,7 @@ export const Playground: Story = {
render: args => <SwitchDemo {...args} />, render: args => <SwitchDemo {...args} />,
args: { args: {
size: 'md', size: 'md',
defaultValue: false, value: false,
disabled: false, disabled: false,
}, },
} }

View File

@ -1,13 +1,12 @@
'use client' 'use client'
import { Switch as OriginalSwitch } from '@headlessui/react' import { Switch as OriginalSwitch } from '@headlessui/react'
import * as React from 'react' import * as React from 'react'
import { useEffect, useState } from 'react'
import { cn } from '@/utils/classnames' import { cn } from '@/utils/classnames'
type SwitchProps = { type SwitchProps = {
value: boolean
onChange?: (value: boolean) => void onChange?: (value: boolean) => void
size?: 'xs' | 'sm' | 'md' | 'lg' | 'l' size?: 'xs' | 'sm' | 'md' | 'lg' | 'l'
defaultValue?: boolean
disabled?: boolean disabled?: boolean
className?: string className?: string
} }
@ -15,19 +14,15 @@ type SwitchProps = {
const Switch = ( const Switch = (
{ {
ref: propRef, ref: propRef,
value,
onChange, onChange,
size = 'md', size = 'md',
defaultValue = false,
disabled = false, disabled = false,
className, className,
}: SwitchProps & { }: SwitchProps & {
ref?: React.RefObject<HTMLButtonElement> ref?: React.RefObject<HTMLButtonElement>
}, },
) => { ) => {
const [enabled, setEnabled] = useState(defaultValue)
useEffect(() => {
setEnabled(defaultValue)
}, [defaultValue])
const wrapStyle = { const wrapStyle = {
lg: 'h-6 w-11', lg: 'h-6 w-11',
l: 'h-5 w-9', l: 'h-5 w-9',
@ -54,18 +49,17 @@ const Switch = (
return ( return (
<OriginalSwitch <OriginalSwitch
ref={propRef} ref={propRef}
checked={enabled} checked={value}
onChange={(checked: boolean) => { onChange={(checked: boolean) => {
if (disabled) if (disabled)
return return
setEnabled(checked)
onChange?.(checked) onChange?.(checked)
}} }}
className={cn(wrapStyle[size], enabled ? 'bg-components-toggle-bg' : 'bg-components-toggle-bg-unchecked', 'relative inline-flex shrink-0 cursor-pointer rounded-[5px] border-2 border-transparent transition-colors duration-200 ease-in-out', disabled ? '!cursor-not-allowed !opacity-50' : '', size === 'xs' && 'rounded-sm', className)} className={cn(wrapStyle[size], value ? 'bg-components-toggle-bg' : 'bg-components-toggle-bg-unchecked', 'relative inline-flex shrink-0 cursor-pointer rounded-[5px] border-2 border-transparent transition-colors duration-200 ease-in-out', disabled ? '!cursor-not-allowed !opacity-50' : '', size === 'xs' && 'rounded-sm', className)}
> >
<span <span
aria-hidden="true" aria-hidden="true"
className={cn(circleStyle[size], enabled ? translateLeft[size] : 'translate-x-0', size === 'xs' && 'rounded-[1px]', 'pointer-events-none inline-block rounded-[3px] bg-components-toggle-knob shadow ring-0 transition duration-200 ease-in-out')} className={cn(circleStyle[size], value ? translateLeft[size] : 'translate-x-0', size === 'xs' && 'rounded-[1px]', 'pointer-events-none inline-block rounded-[3px] bg-components-toggle-knob shadow ring-0 transition duration-200 ease-in-out')}
/> />
</OriginalSwitch> </OriginalSwitch>
) )

View File

@ -24,12 +24,12 @@ const PlanRangeSwitcher: FC<PlanRangeSwitcherProps> = ({
<div className="flex items-center justify-end gap-x-3 pr-5"> <div className="flex items-center justify-end gap-x-3 pr-5">
<Switch <Switch
size="l" size="l"
defaultValue={value === PlanRange.yearly} value={value === PlanRange.yearly}
onChange={(v) => { onChange={(v) => {
onChange(v ? PlanRange.yearly : PlanRange.monthly) onChange(v ? PlanRange.yearly : PlanRange.monthly)
}} }}
/> />
<span className="system-md-regular text-text-tertiary"> <span className="text-text-tertiary system-md-regular">
{t('plansCommon.annualBilling', { ns: 'billing', percent: 17 })} {t('plansCommon.annualBilling', { ns: 'billing', percent: 17 })}
</span> </span>
</div> </div>

View File

@ -116,19 +116,19 @@ const CustomWebAppBrand = () => {
return ( return (
<div className="py-4"> <div className="py-4">
<div className="system-md-medium mb-2 flex items-center justify-between rounded-xl bg-background-section-burn p-4 text-text-primary"> <div className="mb-2 flex items-center justify-between rounded-xl bg-background-section-burn p-4 text-text-primary system-md-medium">
{t('webapp.removeBrand', { ns: 'custom' })} {t('webapp.removeBrand', { ns: 'custom' })}
<Switch <Switch
size="l" size="l"
defaultValue={webappBrandRemoved} value={webappBrandRemoved ?? false}
disabled={isSandbox || !isCurrentWorkspaceManager} disabled={isSandbox || !isCurrentWorkspaceManager}
onChange={handleSwitch} onChange={handleSwitch}
/> />
</div> </div>
<div className={cn('flex h-14 items-center justify-between rounded-xl bg-background-section-burn px-4', webappBrandRemoved && 'opacity-30')}> <div className={cn('flex h-14 items-center justify-between rounded-xl bg-background-section-burn px-4', webappBrandRemoved && 'opacity-30')}>
<div> <div>
<div className="system-md-medium text-text-primary">{t('webapp.changeLogo', { ns: 'custom' })}</div> <div className="text-text-primary system-md-medium">{t('webapp.changeLogo', { ns: 'custom' })}</div>
<div className="system-xs-regular text-text-tertiary">{t('webapp.changeLogoTip', { ns: 'custom' })}</div> <div className="text-text-tertiary system-xs-regular">{t('webapp.changeLogoTip', { ns: 'custom' })}</div>
</div> </div>
<div className="flex items-center"> <div className="flex items-center">
{(!uploadDisabled && webappLogo && !webappBrandRemoved) && ( {(!uploadDisabled && webappLogo && !webappBrandRemoved) && (
@ -204,7 +204,7 @@ const CustomWebAppBrand = () => {
<div className="mt-2 text-xs text-[#D92D20]">{t('uploadedFail', { ns: 'custom' })}</div> <div className="mt-2 text-xs text-[#D92D20]">{t('uploadedFail', { ns: 'custom' })}</div>
)} )}
<div className="mb-2 mt-5 flex items-center gap-2"> <div className="mb-2 mt-5 flex items-center gap-2">
<div className="system-xs-medium-uppercase shrink-0 text-text-tertiary">{t('overview.appInfo.preview', { ns: 'appOverview' })}</div> <div className="shrink-0 text-text-tertiary system-xs-medium-uppercase">{t('overview.appInfo.preview', { ns: 'appOverview' })}</div>
<Divider bgStyle="gradient" className="grow" /> <Divider bgStyle="gradient" className="grow" />
</div> </div>
<div className="relative mb-2 flex items-center gap-3"> <div className="relative mb-2 flex items-center gap-3">
@ -215,7 +215,7 @@ const CustomWebAppBrand = () => {
<div className={cn('inline-flex h-8 w-8 items-center justify-center rounded-lg border border-divider-regular', 'bg-components-icon-bg-blue-light-solid')}> <div className={cn('inline-flex h-8 w-8 items-center justify-center rounded-lg border border-divider-regular', 'bg-components-icon-bg-blue-light-solid')}>
<BubbleTextMod className="h-4 w-4 text-components-avatar-shape-fill-stop-100" /> <BubbleTextMod className="h-4 w-4 text-components-avatar-shape-fill-stop-100" />
</div> </div>
<div className="system-md-semibold grow text-text-secondary">Chatflow App</div> <div className="grow text-text-secondary system-md-semibold">Chatflow App</div>
<div className="p-1.5"> <div className="p-1.5">
<RiLayoutLeft2Line className="h-4 w-4 text-text-tertiary" /> <RiLayoutLeft2Line className="h-4 w-4 text-text-tertiary" />
</div> </div>
@ -246,7 +246,7 @@ const CustomWebAppBrand = () => {
<div className="flex items-center gap-1.5"> <div className="flex items-center gap-1.5">
{!webappBrandRemoved && ( {!webappBrandRemoved && (
<> <>
<div className="system-2xs-medium-uppercase text-text-tertiary">POWERED BY</div> <div className="text-text-tertiary system-2xs-medium-uppercase">POWERED BY</div>
{ {
systemFeatures.branding.enabled && systemFeatures.branding.workspace_logo systemFeatures.branding.enabled && systemFeatures.branding.workspace_logo
? <img src={systemFeatures.branding.workspace_logo} alt="logo" className="block h-5 w-auto" /> ? <img src={systemFeatures.branding.workspace_logo} alt="logo" className="block h-5 w-auto" />
@ -262,12 +262,12 @@ const CustomWebAppBrand = () => {
<div className="flex w-[138px] grow flex-col justify-between p-2 pr-0"> <div className="flex w-[138px] grow flex-col justify-between p-2 pr-0">
<div className="flex grow flex-col justify-between rounded-l-2xl border-[0.5px] border-r-0 border-components-panel-border-subtle bg-chatbot-bg pb-4 pl-[22px] pt-16"> <div className="flex grow flex-col justify-between rounded-l-2xl border-[0.5px] border-r-0 border-components-panel-border-subtle bg-chatbot-bg pb-4 pl-[22px] pt-16">
<div className="w-[720px] rounded-2xl border border-divider-subtle bg-chat-bubble-bg px-4 py-3"> <div className="w-[720px] rounded-2xl border border-divider-subtle bg-chat-bubble-bg px-4 py-3">
<div className="body-md-regular mb-1 text-text-primary">Hello! How can I assist you today?</div> <div className="mb-1 text-text-primary body-md-regular">Hello! How can I assist you today?</div>
<Button size="small"> <Button size="small">
<div className="h-2 w-[144px] rounded-sm bg-text-quaternary opacity-20"></div> <div className="h-2 w-[144px] rounded-sm bg-text-quaternary opacity-20"></div>
</Button> </Button>
</div> </div>
<div className="body-lg-regular flex h-[52px] w-[578px] items-center rounded-xl border border-components-chat-input-border bg-components-panel-bg-blur pl-3.5 text-text-placeholder shadow-md backdrop-blur-sm">Talk to Dify</div> <div className="flex h-[52px] w-[578px] items-center rounded-xl border border-components-chat-input-border bg-components-panel-bg-blur pl-3.5 text-text-placeholder shadow-md backdrop-blur-sm body-lg-regular">Talk to Dify</div>
</div> </div>
</div> </div>
</div> </div>
@ -278,14 +278,14 @@ const CustomWebAppBrand = () => {
<div className={cn('inline-flex h-8 w-8 items-center justify-center rounded-lg border border-divider-regular', 'bg-components-icon-bg-indigo-solid')}> <div className={cn('inline-flex h-8 w-8 items-center justify-center rounded-lg border border-divider-regular', 'bg-components-icon-bg-indigo-solid')}>
<RiExchange2Fill className="h-4 w-4 text-components-avatar-shape-fill-stop-100" /> <RiExchange2Fill className="h-4 w-4 text-components-avatar-shape-fill-stop-100" />
</div> </div>
<div className="system-md-semibold grow text-text-secondary">Workflow App</div> <div className="grow text-text-secondary system-md-semibold">Workflow App</div>
<div className="p-1.5"> <div className="p-1.5">
<RiLayoutLeft2Line className="h-4 w-4 text-text-tertiary" /> <RiLayoutLeft2Line className="h-4 w-4 text-text-tertiary" />
</div> </div>
</div> </div>
<div className="flex items-center gap-4"> <div className="flex items-center gap-4">
<div className="system-md-semibold-uppercase flex h-10 shrink-0 items-center border-b-2 border-components-tab-active text-text-primary">RUN ONCE</div> <div className="flex h-10 shrink-0 items-center border-b-2 border-components-tab-active text-text-primary system-md-semibold-uppercase">RUN ONCE</div>
<div className="system-md-semibold-uppercase flex h-10 grow items-center border-b-2 border-transparent text-text-tertiary">RUN BATCH</div> <div className="flex h-10 grow items-center border-b-2 border-transparent text-text-tertiary system-md-semibold-uppercase">RUN BATCH</div>
</div> </div>
</div> </div>
<div className="grow bg-components-panel-bg"> <div className="grow bg-components-panel-bg">
@ -293,7 +293,7 @@ const CustomWebAppBrand = () => {
<div className="mb-1 py-2"> <div className="mb-1 py-2">
<div className="h-2 w-20 rounded-sm bg-text-quaternary opacity-20"></div> <div className="h-2 w-20 rounded-sm bg-text-quaternary opacity-20"></div>
</div> </div>
<div className="h-16 w-full rounded-lg bg-components-input-bg-normal "></div> <div className="h-16 w-full rounded-lg bg-components-input-bg-normal"></div>
</div> </div>
<div className="flex items-center justify-between px-4 py-3"> <div className="flex items-center justify-between px-4 py-3">
<Button size="small"> <Button size="small">
@ -308,7 +308,7 @@ const CustomWebAppBrand = () => {
<div className="flex h-12 shrink-0 items-center gap-1.5 bg-components-panel-bg p-4 pt-3"> <div className="flex h-12 shrink-0 items-center gap-1.5 bg-components-panel-bg p-4 pt-3">
{!webappBrandRemoved && ( {!webappBrandRemoved && (
<> <>
<div className="system-2xs-medium-uppercase text-text-tertiary">POWERED BY</div> <div className="text-text-tertiary system-2xs-medium-uppercase">POWERED BY</div>
{ {
systemFeatures.branding.enabled && systemFeatures.branding.workspace_logo systemFeatures.branding.enabled && systemFeatures.branding.workspace_logo
? <img src={systemFeatures.branding.workspace_logo} alt="logo" className="block h-5 w-auto" /> ? <img src={systemFeatures.branding.workspace_logo} alt="logo" className="block h-5 w-auto" />

View File

@ -123,11 +123,11 @@ vi.mock('@/app/components/base/radio-card', () => ({
})) }))
vi.mock('@/app/components/base/switch', () => ({ vi.mock('@/app/components/base/switch', () => ({
default: ({ defaultValue, onChange }: { defaultValue: boolean, onChange: (v: boolean) => void }) => ( default: ({ value, onChange }: { value: boolean, onChange?: (v: boolean) => void }) => (
<button <button
data-testid="rerank-switch" data-testid="rerank-switch"
data-checked={defaultValue} data-checked={value}
onClick={() => onChange(!defaultValue)} onClick={() => onChange?.(!value)}
> >
Switch Switch
</button> </button>

View File

@ -122,7 +122,7 @@ const RetrievalParamConfig: FC<Props> = ({
{canToggleRerankModalEnable && ( {canToggleRerankModalEnable && (
<Switch <Switch
size="md" size="md"
defaultValue={value.reranking_enable} value={value.reranking_enable}
onChange={handleToggleRerankEnable} onChange={handleToggleRerankEnable}
/> />
)} )}

View File

@ -191,7 +191,7 @@ const Operations = ({
return ( return (
<div className="flex items-center" onClick={e => e.stopPropagation()}> <div className="flex items-center" onClick={e => e.stopPropagation()}>
{isListScene && !embeddingAvailable && ( {isListScene && !embeddingAvailable && (
<Switch defaultValue={false} onChange={noop} disabled={true} size="md" /> <Switch value={false} onChange={noop} disabled={true} size="md" />
)} )}
{isListScene && embeddingAvailable && ( {isListScene && embeddingAvailable && (
<> <>
@ -202,11 +202,11 @@ const Operations = ({
popupClassName="!font-semibold" popupClassName="!font-semibold"
> >
<div> <div>
<Switch defaultValue={false} onChange={noop} disabled={true} size="md" /> <Switch value={false} onChange={noop} disabled={true} size="md" />
</div> </div>
</Tooltip> </Tooltip>
) )
: <Switch defaultValue={enabled} onChange={v => handleSwitch(v ? 'enable' : 'disable')} size="md" />} : <Switch value={enabled} onChange={v => handleSwitch(v ? 'enable' : 'disable')} size="md" />}
<Divider className="!ml-4 !mr-2 !h-3" type="vertical" /> <Divider className="!ml-4 !mr-2 !h-3" type="vertical" />
</> </>
)} )}

View File

@ -216,7 +216,7 @@ const SegmentCard: FC<ISegmentCardProps> = ({
<Switch <Switch
size="md" size="md"
disabled={archived || detail?.status !== 'completed'} disabled={archived || detail?.status !== 'completed'}
defaultValue={enabled} value={enabled}
onChange={async (val) => { onChange={async (val) => {
await onChangeSwitch?.(val, id) await onChangeSwitch?.(val, id)
}} }}

View File

@ -119,7 +119,7 @@ const StatusItem = ({
disabled={!archived} disabled={!archived}
> >
<Switch <Switch
defaultValue={archived ? false : enabled} value={archived ? false : enabled}
onChange={v => !archived && handleSwitch(v ? 'enable' : 'disable')} onChange={v => !archived && handleSwitch(v ? 'enable' : 'disable')}
disabled={embedding || archived} disabled={embedding || archived}
size="md" size="md"

View File

@ -60,7 +60,7 @@ const Card = ({
</div> </div>
</div> </div>
<Switch <Switch
defaultValue={apiEnabled} value={apiEnabled}
onChange={onToggle} onChange={onToggle}
disabled={!isCurrentWorkspaceManager} disabled={!isCurrentWorkspaceManager}
/> />

View File

@ -204,7 +204,7 @@ const DatasetMetadataDrawer: FC<Props> = ({
<div className="mt-3 flex h-6 items-center"> <div className="mt-3 flex h-6 items-center">
<Switch <Switch
defaultValue={isBuiltInEnabled} value={isBuiltInEnabled}
onChange={onIsBuiltInEnabledChange} onChange={onIsBuiltInEnabledChange}
/> />
<div className="system-sm-semibold ml-2 mr-0.5 text-text-secondary">{t(`${i18nPrefix}.builtIn`, { ns: 'dataset' })}</div> <div className="system-sm-semibold ml-2 mr-0.5 text-text-secondary">{t(`${i18nPrefix}.builtIn`, { ns: 'dataset' })}</div>

View File

@ -72,7 +72,7 @@ const SummaryIndexSetting = ({
</Tooltip> </Tooltip>
</div> </div>
<Switch <Switch
defaultValue={summaryIndexSetting?.enable ?? false} value={summaryIndexSetting?.enable ?? false}
onChange={handleSummaryIndexEnableChange} onChange={handleSummaryIndexEnableChange}
size="md" size="md"
/> />
@ -119,7 +119,7 @@ const SummaryIndexSetting = ({
<div className="system-sm-semibold flex items-center text-text-secondary"> <div className="system-sm-semibold flex items-center text-text-secondary">
<Switch <Switch
className="mr-2" className="mr-2"
defaultValue={summaryIndexSetting?.enable ?? false} value={summaryIndexSetting?.enable ?? false}
onChange={handleSummaryIndexEnableChange} onChange={handleSummaryIndexEnableChange}
size="md" size="md"
/> />
@ -184,7 +184,7 @@ const SummaryIndexSetting = ({
<div className="flex h-6 items-center"> <div className="flex h-6 items-center">
<Switch <Switch
className="mr-2" className="mr-2"
defaultValue={summaryIndexSetting?.enable ?? false} value={summaryIndexSetting?.enable ?? false}
onChange={handleSummaryIndexEnableChange} onChange={handleSummaryIndexEnableChange}
size="md" size="md"
/> />

View File

@ -166,7 +166,7 @@ const CreateAppModal = ({
<div className="flex items-center justify-between"> <div className="flex items-center justify-between">
<div className="py-2 text-sm font-medium leading-[20px] text-text-primary">{t('answerIcon.title', { ns: 'app' })}</div> <div className="py-2 text-sm font-medium leading-[20px] text-text-primary">{t('answerIcon.title', { ns: 'app' })}</div>
<Switch <Switch
defaultValue={useIconAsAnswerIcon} value={useIconAsAnswerIcon}
onChange={v => setUseIconAsAnswerIcon(v)} onChange={v => setUseIconAsAnswerIcon(v)}
/> />
</div> </div>

View File

@ -257,7 +257,7 @@ const ParameterItem: FC<ParameterItemProps> = ({
!parameterRule.required && parameterRule.name !== 'stop' && ( !parameterRule.required && parameterRule.name !== 'stop' && (
<div className="mr-2 w-7"> <div className="mr-2 w-7">
<Switch <Switch
defaultValue={!isNullOrUndefined(value)} value={!isNullOrUndefined(value)}
onChange={handleSwitch} onChange={handleSwitch}
size="md" size="md"
/> />

View File

@ -92,13 +92,13 @@ const ModelListItem = ({ model, provider, isConfigurable, onChange, onModifyLoad
} }
offset={{ mainAxis: 4 }} offset={{ mainAxis: 4 }}
> >
<Switch defaultValue={false} disabled size="md" /> <Switch value={false} disabled size="md" />
</Tooltip> </Tooltip>
) )
: (isCurrentWorkspaceManager && ( : (isCurrentWorkspaceManager && (
<Switch <Switch
className="ml-2" className="ml-2"
defaultValue={model?.status === ModelStatusEnum.active} value={model?.status === ModelStatusEnum.active}
disabled={![ModelStatusEnum.active, ModelStatusEnum.disabled].includes(model.status)} disabled={![ModelStatusEnum.active, ModelStatusEnum.disabled].includes(model.status)}
size="md" size="md"
onChange={onEnablingStateChange} onChange={onEnablingStateChange}

View File

@ -167,7 +167,7 @@ const ModelLoadBalancingConfigs = ({
{ {
withSwitch && ( withSwitch && (
<Switch <Switch
defaultValue={Boolean(draftConfig.enabled)} value={Boolean(draftConfig.enabled)}
size="l" size="l"
className="ml-3 justify-self-end" className="ml-3 justify-self-end"
disabled={!modelLoadBalancingEnabled && !draftConfig.enabled} disabled={!modelLoadBalancingEnabled && !draftConfig.enabled}
@ -227,7 +227,7 @@ const ModelLoadBalancingConfigs = ({
<> <>
<span className="mr-2 h-3 border-r border-r-divider-subtle" /> <span className="mr-2 h-3 border-r border-r-divider-subtle" />
<Switch <Switch
defaultValue={credential?.not_allowed_to_use ? false : Boolean(config.enabled)} value={credential?.not_allowed_to_use ? false : Boolean(config.enabled)}
size="md" size="md"
className="justify-self-end" className="justify-self-end"
onChange={value => toggleConfigEntryEnabled(index, value)} onChange={value => toggleConfigEntryEnabled(index, value)}

View File

@ -181,7 +181,7 @@ const EndpointCard = ({
)} )}
<Switch <Switch
className="ml-3" className="ml-3"
defaultValue={active} value={active}
onChange={handleSwitch} onChange={handleSwitch}
size="sm" size="sm"
/> />

View File

@ -258,7 +258,7 @@ const ReasoningConfigForm: React.FC<Props> = ({
<span className="system-xs-medium text-text-secondary">{t('detailPanel.toolSelector.auto', { ns: 'plugin' })}</span> <span className="system-xs-medium text-text-secondary">{t('detailPanel.toolSelector.auto', { ns: 'plugin' })}</span>
<Switch <Switch
size="xs" size="xs"
defaultValue={!!auto} value={!!auto}
onChange={val => handleAutomatic(variable, val, type)} onChange={val => handleAutomatic(variable, val, type)}
/> />
</div> </div>

View File

@ -95,8 +95,8 @@ const ToolItem = ({
</div> </div>
)} )}
<div className={cn('grow truncate pl-0.5', isTransparent && 'opacity-50', isShowCanNotChooseMCPTip && 'opacity-30')}> <div className={cn('grow truncate pl-0.5', isTransparent && 'opacity-50', isShowCanNotChooseMCPTip && 'opacity-30')}>
<div className="system-2xs-medium-uppercase text-text-tertiary">{providerNameText}</div> <div className="text-text-tertiary system-2xs-medium-uppercase">{providerNameText}</div>
<div className="system-xs-medium text-text-secondary">{toolLabel}</div> <div className="text-text-secondary system-xs-medium">{toolLabel}</div>
</div> </div>
<div className="hidden items-center gap-1 group-hover:flex"> <div className="hidden items-center gap-1 group-hover:flex">
{!noAuth && !isError && !uninstalled && !versionMismatch && !isShowCanNotChooseMCPTip && ( {!noAuth && !isError && !uninstalled && !versionMismatch && !isShowCanNotChooseMCPTip && (
@ -120,7 +120,7 @@ const ToolItem = ({
<div className="mr-1" onClick={e => e.stopPropagation()}> <div className="mr-1" onClick={e => e.stopPropagation()}>
<Switch <Switch
size="md" size="md"
defaultValue={switchValue} value={switchValue ?? false}
onChange={onSwitchChange} onChange={onSwitchChange}
/> />
</div> </div>

View File

@ -250,7 +250,7 @@ const MCPServiceCard: FC<IAppCardProps> = ({
offset={24} offset={24}
> >
<div> <div>
<Switch defaultValue={activated} onChange={onChangeStatus} disabled={toggleDisabled} /> <Switch value={activated} onChange={onChangeStatus} disabled={toggleDisabled} />
</div> </div>
</Tooltip> </Tooltip>
</div> </div>

View File

@ -32,7 +32,7 @@ const AuthenticationSection: FC<AuthenticationSectionProps> = ({
<div className="mb-1 flex h-6 items-center"> <div className="mb-1 flex h-6 items-center">
<Switch <Switch
className="mr-2" className="mr-2"
defaultValue={isDynamicRegistration} value={isDynamicRegistration}
onChange={onDynamicRegistrationChange} onChange={onDynamicRegistrationChange}
/> />
<span className="system-sm-medium text-text-secondary">{t('mcp.modal.useDynamicClientRegistration', { ns: 'tools' })}</span> <span className="system-sm-medium text-text-secondary">{t('mcp.modal.useDynamicClientRegistration', { ns: 'tools' })}</span>

View File

@ -65,7 +65,7 @@ const ConfigVision: FC<Props> = ({
popupContent={t('vision.onlySupportVisionModelTip', { ns: 'appDebug' })!} popupContent={t('vision.onlySupportVisionModelTip', { ns: 'appDebug' })!}
disabled={isVisionModel} disabled={isVisionModel}
> >
<Switch disabled={readOnly || !isVisionModel} size="md" defaultValue={!isVisionModel ? false : enabled} onChange={onEnabledChange} /> <Switch disabled={readOnly || !isVisionModel} size="md" value={!isVisionModel ? false : enabled} onChange={onEnabledChange} />
</Tooltip> </Tooltip>
)} )}
> >

View File

@ -136,7 +136,7 @@ const MemoryConfig: FC<Props> = ({
tooltip={t(`${i18nPrefix}.memoryTip`, { ns: 'workflow' })!} tooltip={t(`${i18nPrefix}.memoryTip`, { ns: 'workflow' })!}
operations={( operations={(
<Switch <Switch
defaultValue={!!payload} value={!!payload}
onChange={handleMemoryEnabledChange} onChange={handleMemoryEnabledChange}
size="md" size="md"
disabled={readonly} disabled={readonly}
@ -149,7 +149,7 @@ const MemoryConfig: FC<Props> = ({
<div className="flex justify-between"> <div className="flex justify-between">
<div className="flex h-8 items-center space-x-2"> <div className="flex h-8 items-center space-x-2">
<Switch <Switch
defaultValue={payload?.window?.enabled} value={payload?.window?.enabled}
onChange={handleWindowEnabledChange} onChange={handleWindowEnabledChange}
size="md" size="md"
disabled={readonly} disabled={readonly}

View File

@ -196,7 +196,7 @@ const Editor: FC<Props> = ({
<Jinja className="h-3 w-6 text-text-quaternary" /> <Jinja className="h-3 w-6 text-text-quaternary" />
<Switch <Switch
size="sm" size="sm"
defaultValue={editionType === EditionType.jinja2} value={editionType === EditionType.jinja2}
onChange={(checked) => { onChange={(checked) => {
onEditionTypeChange?.(checked ? EditionType.jinja2 : EditionType.basic) onEditionTypeChange?.(checked ? EditionType.jinja2 : EditionType.basic)
}} }}

View File

@ -55,10 +55,10 @@ const RetryOnPanel = ({
<div className="pt-2"> <div className="pt-2">
<div className="flex h-10 items-center justify-between px-4 py-2"> <div className="flex h-10 items-center justify-between px-4 py-2">
<div className="flex items-center"> <div className="flex items-center">
<div className="system-sm-semibold-uppercase mr-0.5 text-text-secondary">{t('nodes.common.retry.retryOnFailure', { ns: 'workflow' })}</div> <div className="mr-0.5 text-text-secondary system-sm-semibold-uppercase">{t('nodes.common.retry.retryOnFailure', { ns: 'workflow' })}</div>
</div> </div>
<Switch <Switch
defaultValue={retry_config?.retry_enabled} value={retry_config?.retry_enabled ?? false}
onChange={v => handleRetryEnabledChange(v)} onChange={v => handleRetryEnabledChange(v)}
/> />
</div> </div>
@ -66,7 +66,7 @@ const RetryOnPanel = ({
retry_config?.retry_enabled && ( retry_config?.retry_enabled && (
<div className="px-4 pb-2"> <div className="px-4 pb-2">
<div className="mb-1 flex w-full items-center"> <div className="mb-1 flex w-full items-center">
<div className="system-xs-medium-uppercase mr-2 grow text-text-secondary">{t('nodes.common.retry.maxRetries', { ns: 'workflow' })}</div> <div className="mr-2 grow text-text-secondary system-xs-medium-uppercase">{t('nodes.common.retry.maxRetries', { ns: 'workflow' })}</div>
<Slider <Slider
className="mr-3 w-[108px]" className="mr-3 w-[108px]"
value={retry_config?.max_retries || 3} value={retry_config?.max_retries || 3}
@ -87,7 +87,7 @@ const RetryOnPanel = ({
/> />
</div> </div>
<div className="flex items-center"> <div className="flex items-center">
<div className="system-xs-medium-uppercase mr-2 grow text-text-secondary">{t('nodes.common.retry.retryInterval', { ns: 'workflow' })}</div> <div className="mr-2 grow text-text-secondary system-xs-medium-uppercase">{t('nodes.common.retry.retryInterval', { ns: 'workflow' })}</div>
<Slider <Slider
className="mr-3 w-[108px]" className="mr-3 w-[108px]"
value={retry_config?.retry_interval || 1000} value={retry_config?.retry_interval || 1000}

View File

@ -131,7 +131,7 @@ const Panel: FC<NodePanelProps<HttpNodeType>> = ({
tooltip={t(`${i18nPrefix}.verifySSL.warningTooltip`, { ns: 'workflow' })} tooltip={t(`${i18nPrefix}.verifySSL.warningTooltip`, { ns: 'workflow' })}
operations={( operations={(
<Switch <Switch
defaultValue={!!inputs.ssl_verify} value={!!inputs.ssl_verify}
onChange={handleSSLVerifyChange} onChange={handleSSLVerifyChange}
size="md" size="md"
disabled={readOnly} disabled={readOnly}

View File

@ -149,7 +149,7 @@ const EmailConfigureModal = ({
</div> </div>
</div> </div>
<Switch <Switch
defaultValue={debugMode} value={debugMode}
onChange={checked => setDebugMode(checked)} onChange={checked => setDebugMode(checked)}
/> />
</div> </div>

View File

@ -160,7 +160,7 @@ const DeliveryMethodItem: FC<DeliveryMethodItemProps> = ({
)} )}
{(method.config || method.type === DeliveryMethodType.WebApp) && ( {(method.config || method.type === DeliveryMethodType.WebApp) && (
<Switch <Switch
defaultValue={method.enabled} value={method.enabled}
onChange={handleEnableStatusChange} onChange={handleEnableStatusChange}
disabled={readonly} disabled={readonly}
/> />

View File

@ -91,7 +91,7 @@ const Recipient = ({
</div> </div>
<div className={cn('system-sm-medium grow text-text-secondary')}>{t(`${i18nPrefix}.deliveryMethod.emailConfigure.allMembers`, { workspaceName: currentWorkspace.name.replace(/'/g, ''), ns: 'workflow' })}</div> <div className={cn('system-sm-medium grow text-text-secondary')}>{t(`${i18nPrefix}.deliveryMethod.emailConfigure.allMembers`, { workspaceName: currentWorkspace.name.replace(/'/g, ''), ns: 'workflow' })}</div>
<Switch <Switch
defaultValue={data.whole_workspace} value={data.whole_workspace}
onChange={checked => onChange({ ...data, whole_workspace: checked })} onChange={checked => onChange({ ...data, whole_workspace: checked })}
/> />
</div> </div>

View File

@ -92,7 +92,7 @@ const Panel: FC<NodePanelProps<IterationNodeType>> = ({
</div> </div>
<div className="px-4 pb-2"> <div className="px-4 pb-2">
<Field title={t(`${i18nPrefix}.parallelMode`, { ns: 'workflow' })} tooltip={<div className="w-[230px]">{t(`${i18nPrefix}.parallelPanelDesc`, { ns: 'workflow' })}</div>} inline> <Field title={t(`${i18nPrefix}.parallelMode`, { ns: 'workflow' })} tooltip={<div className="w-[230px]">{t(`${i18nPrefix}.parallelPanelDesc`, { ns: 'workflow' })}</div>} inline>
<Switch defaultValue={inputs.is_parallel} onChange={changeParallel} /> <Switch value={inputs.is_parallel} onChange={changeParallel} />
</Field> </Field>
</div> </div>
{ {
@ -130,7 +130,7 @@ const Panel: FC<NodePanelProps<IterationNodeType>> = ({
tooltip={<div className="w-[230px]">{t(`${i18nPrefix}.flattenOutputDesc`, { ns: 'workflow' })}</div>} tooltip={<div className="w-[230px]">{t(`${i18nPrefix}.flattenOutputDesc`, { ns: 'workflow' })}</div>}
inline inline
> >
<Switch defaultValue={inputs.flatten_output} onChange={changeFlattenOutput} /> <Switch value={inputs.flatten_output} onChange={changeFlattenOutput} />
</Field> </Field>
</div> </div>
</div> </div>

View File

@ -166,10 +166,10 @@ const SearchMethodOption = ({
<div> <div>
{ {
showRerankModelSelectorSwitch && ( showRerankModelSelectorSwitch && (
<div className="system-sm-semibold mb-1 flex items-center text-text-secondary"> <div className="mb-1 flex items-center text-text-secondary system-sm-semibold">
<Switch <Switch
className="mr-1" className="mr-1"
defaultValue={rerankingModelEnabled} value={rerankingModelEnabled ?? false}
onChange={onRerankingModelEnabledChange} onChange={onRerankingModelEnabledChange}
disabled={readonly} disabled={readonly}
/> />
@ -192,7 +192,7 @@ const SearchMethodOption = ({
<div className="p-1"> <div className="p-1">
<AlertTriangle className="size-4 text-text-warning-secondary" /> <AlertTriangle className="size-4 text-text-warning-secondary" />
</div> </div>
<span className="system-xs-medium text-text-primary"> <span className="text-text-primary system-xs-medium">
{t('form.retrievalSetting.multiModalTip', { ns: 'datasetSettings' })} {t('form.retrievalSetting.multiModalTip', { ns: 'datasetSettings' })}
</span> </span>
</div> </div>

View File

@ -56,7 +56,7 @@ const TopKAndScoreThreshold = ({
return ( return (
<div className="grid grid-cols-2 gap-4"> <div className="grid grid-cols-2 gap-4">
<div> <div>
<div className="system-xs-medium mb-0.5 flex h-6 items-center text-text-secondary"> <div className="mb-0.5 flex h-6 items-center text-text-secondary system-xs-medium">
{t('datasetConfig.top_k', { ns: 'appDebug' })} {t('datasetConfig.top_k', { ns: 'appDebug' })}
<Tooltip <Tooltip
triggerClassName="ml-0.5 shrink-0 w-3.5 h-3.5" triggerClassName="ml-0.5 shrink-0 w-3.5 h-3.5"
@ -78,11 +78,11 @@ const TopKAndScoreThreshold = ({
<div className="mb-0.5 flex h-6 items-center"> <div className="mb-0.5 flex h-6 items-center">
<Switch <Switch
className="mr-2" className="mr-2"
defaultValue={isScoreThresholdEnabled} value={isScoreThresholdEnabled ?? false}
onChange={onScoreThresholdEnabledChange} onChange={onScoreThresholdEnabledChange}
disabled={readonly} disabled={readonly}
/> />
<div className="system-sm-medium grow truncate text-text-secondary"> <div className="grow truncate text-text-secondary system-sm-medium">
{t('datasetConfig.score_threshold', { ns: 'appDebug' })} {t('datasetConfig.score_threshold', { ns: 'appDebug' })}
</div> </div>
<Tooltip <Tooltip

View File

@ -56,7 +56,7 @@ const LimitConfig: FC<Props> = ({
title={t(`${i18nPrefix}.limit`, { ns: 'workflow' })} title={t(`${i18nPrefix}.limit`, { ns: 'workflow' })}
operations={( operations={(
<Switch <Switch
defaultValue={payload.enabled} value={payload.enabled}
onChange={handleLimitEnabledChange} onChange={handleLimitEnabledChange}
size="md" size="md"
disabled={readonly} disabled={readonly}

View File

@ -65,7 +65,7 @@ const Panel: FC<NodePanelProps<ListFilterNodeType>> = ({
title={t(`${i18nPrefix}.filterCondition`, { ns: 'workflow' })} title={t(`${i18nPrefix}.filterCondition`, { ns: 'workflow' })}
operations={( operations={(
<Switch <Switch
defaultValue={inputs.filter_by?.enabled} value={inputs.filter_by?.enabled}
onChange={handleFilterEnabledChange} onChange={handleFilterEnabledChange}
size="md" size="md"
disabled={readOnly} disabled={readOnly}
@ -90,7 +90,7 @@ const Panel: FC<NodePanelProps<ListFilterNodeType>> = ({
title={t(`${i18nPrefix}.extractsCondition`, { ns: 'workflow' })} title={t(`${i18nPrefix}.extractsCondition`, { ns: 'workflow' })}
operations={( operations={(
<Switch <Switch
defaultValue={inputs.extract_by?.enabled} value={inputs.extract_by?.enabled}
onChange={handleExtractsEnabledChange} onChange={handleExtractsEnabledChange}
size="md" size="md"
disabled={readOnly} disabled={readOnly}
@ -123,7 +123,7 @@ const Panel: FC<NodePanelProps<ListFilterNodeType>> = ({
title={t(`${i18nPrefix}.orderBy`, { ns: 'workflow' })} title={t(`${i18nPrefix}.orderBy`, { ns: 'workflow' })}
operations={( operations={(
<Switch <Switch
defaultValue={inputs.order_by?.enabled} value={inputs.order_by?.enabled}
onChange={handleOrderByEnabledChange} onChange={handleOrderByEnabledChange}
size="md" size="md"
disabled={readOnly} disabled={readOnly}

View File

@ -17,7 +17,7 @@ const RequiredSwitch: FC<RequiredSwitchProps> = ({
return ( return (
<div className="flex items-center gap-x-1 rounded-[5px] border border-divider-subtle bg-background-default-lighter px-1.5 py-1"> <div className="flex items-center gap-x-1 rounded-[5px] border border-divider-subtle bg-background-default-lighter px-1.5 py-1">
<span className="system-2xs-medium-uppercase text-text-secondary">{t('nodes.llm.jsonSchema.required', { ns: 'workflow' })}</span> <span className="system-2xs-medium-uppercase text-text-secondary">{t('nodes.llm.jsonSchema.required', { ns: 'workflow' })}</span>
<Switch size="xs" defaultValue={defaultValue} onChange={toggleRequired} /> <Switch size="xs" value={defaultValue} onChange={toggleRequired} />
</div> </div>
) )
} }

View File

@ -24,7 +24,7 @@ const ReasoningFormatConfig: FC<ReasoningFormatConfigProps> = ({
operations={( operations={(
// ON = separated, OFF = tagged // ON = separated, OFF = tagged
<Switch <Switch
defaultValue={value === 'separated'} value={value === 'separated'}
onChange={enabled => onChange(enabled ? 'separated' : 'tagged')} onChange={enabled => onChange(enabled ? 'separated' : 'tagged')}
size="md" size="md"
disabled={readonly} disabled={readonly}

View File

@ -285,7 +285,7 @@ const Panel: FC<NodePanelProps<LLMNodeType>> = ({
</Tooltip> </Tooltip>
<Switch <Switch
className="ml-2" className="ml-2"
defaultValue={!!inputs.structured_output_enabled} value={!!inputs.structured_output_enabled}
onChange={handleStructureOutputEnableChange} onChange={handleStructureOutputEnableChange}
size="md" size="md"
disabled={readOnly} disabled={readOnly}

View File

@ -174,7 +174,7 @@ const AddExtractParameter: FC<Props> = ({
<Field title={t(`${i18nPrefix}.addExtractParameterContent.required`, { ns: 'workflow' })}> <Field title={t(`${i18nPrefix}.addExtractParameterContent.required`, { ns: 'workflow' })}>
<> <>
<div className="mb-1.5 text-xs font-normal leading-[18px] text-text-tertiary">{t(`${i18nPrefix}.addExtractParameterContent.requiredContent`, { ns: 'workflow' })}</div> <div className="mb-1.5 text-xs font-normal leading-[18px] text-text-tertiary">{t(`${i18nPrefix}.addExtractParameterContent.requiredContent`, { ns: 'workflow' })}</div>
<Switch size="l" defaultValue={param.required} onChange={handleParamChange('required')} /> <Switch size="l" value={param.required ?? false} onChange={handleParamChange('required')} />
</> </>
</Field> </Field>
</div> </div>

View File

@ -90,7 +90,7 @@ const Panel: FC<NodePanelProps<VariableAssignerNodeType>> = ({
tooltip={t(`${i18nPrefix}.aggregationGroupTip`, { ns: 'workflow' })!} tooltip={t(`${i18nPrefix}.aggregationGroupTip`, { ns: 'workflow' })!}
operations={( operations={(
<Switch <Switch
defaultValue={isEnableGroup} value={isEnableGroup}
onChange={handleGroupEnabledChange} onChange={handleGroupEnabledChange}
size="md" size="md"
disabled={readOnly} disabled={readOnly}

View File

@ -80,7 +80,7 @@ const Operator = ({
<div>{t('nodes.note.editor.showAuthor', { ns: 'workflow' })}</div> <div>{t('nodes.note.editor.showAuthor', { ns: 'workflow' })}</div>
<Switch <Switch
size="l" size="l"
defaultValue={showAuthor} value={showAuthor}
onChange={onShowAuthorChange} onChange={onShowAuthorChange}
/> />
</div> </div>

View File

@ -21,7 +21,7 @@ const FilterSwitch: FC<FilterSwitchProps> = ({
{t('versionHistory.filter.onlyShowNamedVersions', { ns: 'workflow' })} {t('versionHistory.filter.onlyShowNamedVersions', { ns: 'workflow' })}
</div> </div>
<Switch <Switch
defaultValue={enabled} value={enabled}
onChange={v => handleSwitch(v)} onChange={v => handleSwitch(v)}
size="md" size="md"
className="shrink-0" className="shrink-0"

View File

@ -452,9 +452,6 @@
"react-hooks-extra/no-direct-set-state-in-use-effect": { "react-hooks-extra/no-direct-set-state-in-use-effect": {
"count": 1 "count": 1
}, },
"tailwindcss/enforce-consistent-class-order": {
"count": 2
},
"ts/no-explicit-any": { "ts/no-explicit-any": {
"count": 5 "count": 5
} }
@ -803,11 +800,6 @@
"count": 1 "count": 1
} }
}, },
"app/components/app/configuration/dataset-config/params-config/config-content.tsx": {
"tailwindcss/enforce-consistent-class-order": {
"count": 9
}
},
"app/components/app/configuration/dataset-config/params-config/index.tsx": { "app/components/app/configuration/dataset-config/params-config/index.tsx": {
"react-hooks-extra/no-direct-set-state-in-use-effect": { "react-hooks-extra/no-direct-set-state-in-use-effect": {
"count": 1 "count": 1
@ -954,11 +946,6 @@
"count": 2 "count": 2
} }
}, },
"app/components/app/configuration/tools/index.tsx": {
"tailwindcss/no-unnecessary-whitespace": {
"count": 1
}
},
"app/components/app/create-app-dialog/app-card/index.spec.tsx": { "app/components/app/create-app-dialog/app-card/index.spec.tsx": {
"ts/no-explicit-any": { "ts/no-explicit-any": {
"count": 1 "count": 1
@ -2758,14 +2745,6 @@
"count": 1 "count": 1
} }
}, },
"app/components/base/switch/index.tsx": {
"react-hooks-extra/no-direct-set-state-in-use-effect": {
"count": 1
},
"tailwindcss/no-unnecessary-whitespace": {
"count": 1
}
},
"app/components/base/tab-header/index.tsx": { "app/components/base/tab-header/index.tsx": {
"tailwindcss/enforce-consistent-class-order": { "tailwindcss/enforce-consistent-class-order": {
"count": 1 "count": 1
@ -2927,9 +2906,6 @@
"app/components/billing/pricing/plan-switcher/plan-range-switcher.tsx": { "app/components/billing/pricing/plan-switcher/plan-range-switcher.tsx": {
"react-refresh/only-export-components": { "react-refresh/only-export-components": {
"count": 1 "count": 1
},
"tailwindcss/enforce-consistent-class-order": {
"count": 1
} }
}, },
"app/components/billing/pricing/plan-switcher/tab.tsx": { "app/components/billing/pricing/plan-switcher/tab.tsx": {
@ -3001,12 +2977,6 @@
} }
}, },
"app/components/custom/custom-web-app-brand/index.tsx": { "app/components/custom/custom-web-app-brand/index.tsx": {
"tailwindcss/enforce-consistent-class-order": {
"count": 12
},
"tailwindcss/no-unnecessary-whitespace": {
"count": 1
},
"ts/no-explicit-any": { "ts/no-explicit-any": {
"count": 2 "count": 2
} }
@ -5034,11 +5004,6 @@
"count": 2 "count": 2
} }
}, },
"app/components/plugins/plugin-detail-panel/tool-selector/components/tool-item.tsx": {
"tailwindcss/enforce-consistent-class-order": {
"count": 2
}
},
"app/components/plugins/plugin-detail-panel/tool-selector/components/tool-settings-panel.tsx": { "app/components/plugins/plugin-detail-panel/tool-selector/components/tool-settings-panel.tsx": {
"tailwindcss/enforce-consistent-class-order": { "tailwindcss/enforce-consistent-class-order": {
"count": 4 "count": 4
@ -6319,11 +6284,6 @@
"count": 1 "count": 1
} }
}, },
"app/components/workflow/nodes/_base/components/retry/retry-on-panel.tsx": {
"tailwindcss/enforce-consistent-class-order": {
"count": 3
}
},
"app/components/workflow/nodes/_base/components/selector.tsx": { "app/components/workflow/nodes/_base/components/selector.tsx": {
"tailwindcss/no-unnecessary-whitespace": { "tailwindcss/no-unnecessary-whitespace": {
"count": 2 "count": 2
@ -6944,16 +6904,6 @@
"count": 1 "count": 1
} }
}, },
"app/components/workflow/nodes/knowledge-base/components/retrieval-setting/search-method-option.tsx": {
"tailwindcss/enforce-consistent-class-order": {
"count": 2
}
},
"app/components/workflow/nodes/knowledge-base/components/retrieval-setting/top-k-and-score-threshold.tsx": {
"tailwindcss/enforce-consistent-class-order": {
"count": 2
}
},
"app/components/workflow/nodes/knowledge-base/components/retrieval-setting/type.ts": { "app/components/workflow/nodes/knowledge-base/components/retrieval-setting/type.ts": {
"ts/no-explicit-any": { "ts/no-explicit-any": {
"count": 2 "count": 2