mirror of
https://github.com/langgenius/dify.git
synced 2026-09-08 02:43:49 +08:00
fix(dify-ui): improve picker type inference (#38428)
This commit is contained in:
parent
acfef79a8f
commit
e742e0ec17
@ -17,7 +17,30 @@ import { parsePlacement } from '../placement'
|
|||||||
|
|
||||||
export type { Placement }
|
export type { Placement }
|
||||||
|
|
||||||
export const Autocomplete = BaseAutocomplete.Root
|
export type AutocompleteRootProps<ItemValue> = BaseAutocomplete.Root.Props<ItemValue>
|
||||||
|
export type AutocompleteRootGroupedProps<
|
||||||
|
Items extends readonly { items: readonly unknown[] }[],
|
||||||
|
> = Omit<AutocompleteRootProps<Items[number]['items'][number]>, 'items'> & {
|
||||||
|
items: Items
|
||||||
|
}
|
||||||
|
export type AutocompleteRootFlatProps<ItemValue>
|
||||||
|
= Omit<AutocompleteRootProps<ItemValue>, 'items'>
|
||||||
|
& {
|
||||||
|
items?: readonly ItemValue[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export function Autocomplete<Items extends readonly { items: readonly unknown[] }[]>(
|
||||||
|
props: AutocompleteRootGroupedProps<Items>,
|
||||||
|
): React.JSX.Element
|
||||||
|
export function Autocomplete<ItemValue>(
|
||||||
|
props: AutocompleteRootFlatProps<ItemValue>,
|
||||||
|
): React.JSX.Element
|
||||||
|
export function Autocomplete(
|
||||||
|
props: AutocompleteRootProps<unknown>,
|
||||||
|
): React.JSX.Element {
|
||||||
|
return <BaseAutocomplete.Root {...props} />
|
||||||
|
}
|
||||||
|
|
||||||
export const AutocompleteValue = BaseAutocomplete.Value
|
export const AutocompleteValue = BaseAutocomplete.Value
|
||||||
export const AutocompleteGroup = BaseAutocomplete.Group
|
export const AutocompleteGroup = BaseAutocomplete.Group
|
||||||
export const AutocompleteCollection = BaseAutocomplete.Collection
|
export const AutocompleteCollection = BaseAutocomplete.Collection
|
||||||
@ -25,7 +48,6 @@ export const AutocompleteRow = BaseAutocomplete.Row
|
|||||||
export const useAutocompleteFilter = BaseAutocomplete.useFilter
|
export const useAutocompleteFilter = BaseAutocomplete.useFilter
|
||||||
export const useAutocompleteFilteredItems = BaseAutocomplete.useFilteredItems
|
export const useAutocompleteFilteredItems = BaseAutocomplete.useFilteredItems
|
||||||
|
|
||||||
export type AutocompleteRootProps<ItemValue> = BaseAutocomplete.Root.Props<ItemValue>
|
|
||||||
export type AutocompleteRootChangeEventDetails = BaseAutocomplete.Root.ChangeEventDetails
|
export type AutocompleteRootChangeEventDetails = BaseAutocomplete.Root.ChangeEventDetails
|
||||||
export type AutocompleteRootHighlightEventDetails = BaseAutocomplete.Root.HighlightEventDetails
|
export type AutocompleteRootHighlightEventDetails = BaseAutocomplete.Root.HighlightEventDetails
|
||||||
|
|
||||||
|
|||||||
@ -17,7 +17,15 @@ import { parsePlacement } from '../placement'
|
|||||||
|
|
||||||
export type { Placement }
|
export type { Placement }
|
||||||
|
|
||||||
export const Combobox = BaseCombobox.Root
|
export type ComboboxRootProps<Value, Multiple extends boolean | undefined = false>
|
||||||
|
= BaseCombobox.Root.Props<Value, Multiple>
|
||||||
|
|
||||||
|
export function Combobox<Value, Multiple extends boolean | undefined = false>(
|
||||||
|
props: ComboboxRootProps<Value, Multiple>,
|
||||||
|
): React.JSX.Element {
|
||||||
|
return <BaseCombobox.Root {...props} />
|
||||||
|
}
|
||||||
|
|
||||||
export const ComboboxValue = BaseCombobox.Value
|
export const ComboboxValue = BaseCombobox.Value
|
||||||
export const ComboboxGroup = BaseCombobox.Group
|
export const ComboboxGroup = BaseCombobox.Group
|
||||||
export const ComboboxCollection = BaseCombobox.Collection
|
export const ComboboxCollection = BaseCombobox.Collection
|
||||||
@ -25,8 +33,6 @@ export const ComboboxRow = BaseCombobox.Row
|
|||||||
export const useComboboxFilter = BaseCombobox.useFilter
|
export const useComboboxFilter = BaseCombobox.useFilter
|
||||||
export const useComboboxFilteredItems = BaseCombobox.useFilteredItems
|
export const useComboboxFilteredItems = BaseCombobox.useFilteredItems
|
||||||
|
|
||||||
export type ComboboxRootProps<Value, Multiple extends boolean | undefined = false>
|
|
||||||
= BaseCombobox.Root.Props<Value, Multiple>
|
|
||||||
export type ComboboxRootChangeEventDetails = BaseCombobox.Root.ChangeEventDetails
|
export type ComboboxRootChangeEventDetails = BaseCombobox.Root.ChangeEventDetails
|
||||||
export type ComboboxRootHighlightEventDetails = BaseCombobox.Root.HighlightEventDetails
|
export type ComboboxRootHighlightEventDetails = BaseCombobox.Root.HighlightEventDetails
|
||||||
|
|
||||||
|
|||||||
@ -16,7 +16,17 @@ import { parsePlacement } from '../placement'
|
|||||||
|
|
||||||
export type { Placement }
|
export type { Placement }
|
||||||
|
|
||||||
export const Select = BaseSelect.Root
|
export type SelectRootProps<
|
||||||
|
Value,
|
||||||
|
Multiple extends boolean | undefined = false,
|
||||||
|
> = BaseSelect.Root.Props<Value, Multiple>
|
||||||
|
|
||||||
|
export function Select<Value, Multiple extends boolean | undefined = false>(
|
||||||
|
props: SelectRootProps<Value, Multiple>,
|
||||||
|
): React.JSX.Element {
|
||||||
|
return <BaseSelect.Root {...props} />
|
||||||
|
}
|
||||||
|
|
||||||
export const SelectValue = BaseSelect.Value
|
export const SelectValue = BaseSelect.Value
|
||||||
export const SelectGroup = BaseSelect.Group
|
export const SelectGroup = BaseSelect.Group
|
||||||
|
|
||||||
|
|||||||
@ -36,9 +36,9 @@ const RangeSelector: FC<Props> = ({
|
|||||||
name: t(`filter.period.${range.name}`, { ns: 'appLog' }),
|
name: t(`filter.period.${range.name}`, { ns: 'appLog' }),
|
||||||
}))
|
}))
|
||||||
}, [ranges, t])
|
}, [ranges, t])
|
||||||
const [value, setValue] = useState('0')
|
const [value, setValue] = useState(0)
|
||||||
const selectedItem = useMemo(() => {
|
const selectedItem = useMemo(() => {
|
||||||
return items.find(item => String(item.value) === value) ?? null
|
return items.find(item => item.value === value) ?? null
|
||||||
}, [items, value])
|
}, [items, value])
|
||||||
|
|
||||||
const handleSelectRange = useCallback((item: TimePeriodOption) => {
|
const handleSelectRange = useCallback((item: TimePeriodOption) => {
|
||||||
@ -50,20 +50,20 @@ const RangeSelector: FC<Props> = ({
|
|||||||
period = { start: startOfToday, end: endOfToday }
|
period = { start: startOfToday, end: endOfToday }
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
period = { start: today.subtract(item.value as number, 'day').startOf('day'), end: today.endOf('day') }
|
period = { start: today.subtract(item.value, 'day').startOf('day'), end: today.endOf('day') }
|
||||||
}
|
}
|
||||||
onSelect({ query: period!, name })
|
onSelect({ query: period!, name })
|
||||||
}, [onSelect])
|
}, [onSelect])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Select
|
<Select<number>
|
||||||
value={selectedItem ? String(selectedItem.value) : null}
|
value={selectedItem?.value ?? null}
|
||||||
open={open}
|
open={open}
|
||||||
onOpenChange={setOpen}
|
onOpenChange={setOpen}
|
||||||
onValueChange={(nextValue) => {
|
onValueChange={(nextValue) => {
|
||||||
if (!nextValue)
|
if (nextValue == null)
|
||||||
return
|
return
|
||||||
const nextItem = items.find(item => String(item.value) === nextValue)
|
const nextItem = items.find(item => item.value === nextValue)
|
||||||
if (!nextItem)
|
if (!nextItem)
|
||||||
return
|
return
|
||||||
setValue(nextValue)
|
setValue(nextValue)
|
||||||
@ -80,7 +80,7 @@ const RangeSelector: FC<Props> = ({
|
|||||||
</SelectTrigger>
|
</SelectTrigger>
|
||||||
<SelectContent className="translate-x-[-24px]" popupClassName="w-[200px]" listClassName="p-1">
|
<SelectContent className="translate-x-[-24px]" popupClassName="w-[200px]" listClassName="p-1">
|
||||||
{items.map(item => (
|
{items.map(item => (
|
||||||
<SelectItem key={item.value} value={String(item.value)} className="h-8 py-0 pr-2 pl-7 system-md-regular">
|
<SelectItem key={item.value} value={item.value} className="h-8 py-0 pr-2 pl-7 system-md-regular">
|
||||||
<SelectItemText className="px-0">{item.name}</SelectItemText>
|
<SelectItemText className="px-0">{item.name}</SelectItemText>
|
||||||
<SelectItemIndicator className="absolute top-[8px] left-2 ml-0" />
|
<SelectItemIndicator className="absolute top-[8px] left-2 ml-0" />
|
||||||
</SelectItem>
|
</SelectItem>
|
||||||
|
|||||||
@ -33,7 +33,7 @@ import TypeSelector from './type-select'
|
|||||||
import { CHECKBOX_DEFAULT_FALSE_VALUE, CHECKBOX_DEFAULT_TRUE_VALUE, TEXT_MAX_LENGTH } from './utils'
|
import { CHECKBOX_DEFAULT_FALSE_VALUE, CHECKBOX_DEFAULT_TRUE_VALUE, TEXT_MAX_LENGTH } from './utils'
|
||||||
|
|
||||||
type Translate = (key: string, options?: Record<string, unknown>) => string
|
type Translate = (key: string, options?: Record<string, unknown>) => string
|
||||||
const EMPTY_SELECT_VALUE = '__empty__'
|
const EMPTY_SELECT_VALUE = '__empty__' as const
|
||||||
|
|
||||||
type ConfigModalFormFieldsProps = {
|
type ConfigModalFormFieldsProps = {
|
||||||
checkboxDefaultSelectValue: string
|
checkboxDefaultSelectValue: string
|
||||||
@ -169,10 +169,14 @@ const ConfigModalFormFields: FC<ConfigModalFormFieldsProps> = ({
|
|||||||
</Field>
|
</Field>
|
||||||
{options && options.length > 0 && (
|
{options && options.length > 0 && (
|
||||||
<Field title={t('variableConfig.defaultValue', { ns: 'appDebug' })}>
|
<Field title={t('variableConfig.defaultValue', { ns: 'appDebug' })}>
|
||||||
<Select
|
<Select<string>
|
||||||
key={`default-select-${options.join('-')}`}
|
key={`default-select-${options.join('-')}`}
|
||||||
value={tempPayload.default ? String(tempPayload.default) : EMPTY_SELECT_VALUE}
|
value={typeof tempPayload.default === 'string' ? tempPayload.default : EMPTY_SELECT_VALUE}
|
||||||
onValueChange={value => onPayloadChange('default')(value === EMPTY_SELECT_VALUE ? undefined : value)}
|
onValueChange={(value) => {
|
||||||
|
if (value == null)
|
||||||
|
return
|
||||||
|
onPayloadChange('default')(value === EMPTY_SELECT_VALUE ? undefined : value)
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<SelectTrigger size="large" className="w-full">
|
<SelectTrigger size="large" className="w-full">
|
||||||
<SelectValue placeholder={t('variableConfig.selectDefaultValue', { ns: 'appDebug' })} />
|
<SelectValue placeholder={t('variableConfig.selectDefaultValue', { ns: 'appDebug' })} />
|
||||||
|
|||||||
@ -105,17 +105,17 @@ const ChatUserInput = ({
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{type === 'select' && (
|
{type === 'select' && (
|
||||||
<Select
|
<Select<string>
|
||||||
value={inputs[key] ? String(inputs[key]) : null}
|
value={typeof inputs[key] === 'string' && inputs[key] !== '' ? inputs[key] : null}
|
||||||
disabled={debugInputReadonly}
|
disabled={debugInputReadonly}
|
||||||
onValueChange={(nextValue) => {
|
onValueChange={(nextValue) => {
|
||||||
if (!nextValue)
|
if (nextValue == null || nextValue === '')
|
||||||
return
|
return
|
||||||
handleInputValueChange(key, nextValue)
|
handleInputValueChange(key, nextValue)
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<SelectTrigger className="w-full">
|
<SelectTrigger className="w-full">
|
||||||
{String(inputs[key] || t('placeholder.select', { ns: 'common' }))}
|
{typeof inputs[key] === 'string' && inputs[key] !== '' ? inputs[key] : t('placeholder.select', { ns: 'common' })}
|
||||||
</SelectTrigger>
|
</SelectTrigger>
|
||||||
<SelectContent>
|
<SelectContent>
|
||||||
{(options || []).map(option => (
|
{(options || []).map(option => (
|
||||||
|
|||||||
@ -165,17 +165,17 @@ const PromptValuePanel: FC<IPromptValuePanelProps> = ({
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{type === 'select' && (
|
{type === 'select' && (
|
||||||
<Select
|
<Select<string>
|
||||||
value={inputs[key] ? String(inputs[key]) : null}
|
value={typeof inputs[key] === 'string' && inputs[key] !== '' ? inputs[key] : null}
|
||||||
disabled={debugInputReadonly}
|
disabled={debugInputReadonly}
|
||||||
onValueChange={(nextValue) => {
|
onValueChange={(nextValue) => {
|
||||||
if (!nextValue)
|
if (nextValue == null || nextValue === '')
|
||||||
return
|
return
|
||||||
handleInputValueChange(key, nextValue)
|
handleInputValueChange(key, nextValue)
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<SelectTrigger className="w-full bg-gray-50">
|
<SelectTrigger className="w-full bg-gray-50">
|
||||||
{String(inputs[key] || t('placeholder.select', { ns: 'common' }))}
|
{typeof inputs[key] === 'string' && inputs[key] !== '' ? inputs[key] : t('placeholder.select', { ns: 'common' })}
|
||||||
</SelectTrigger>
|
</SelectTrigger>
|
||||||
<SelectContent>
|
<SelectContent>
|
||||||
{(options || []).map(option => (
|
{(options || []).map(option => (
|
||||||
|
|||||||
@ -21,7 +21,7 @@ import { useAppVoices } from '@/service/use-apps'
|
|||||||
import { TtsAutoPlay } from '@/types/app'
|
import { TtsAutoPlay } from '@/types/app'
|
||||||
|
|
||||||
type SelectOption = {
|
type SelectOption = {
|
||||||
value: string | number
|
value: string
|
||||||
name: string
|
name: string
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -40,7 +40,7 @@ const VoiceParamConfig = ({
|
|||||||
const text2speech = useFeatures(state => state.features.text2speech)
|
const text2speech = useFeatures(state => state.features.text2speech)
|
||||||
const featuresStore = useFeaturesStore()
|
const featuresStore = useFeaturesStore()
|
||||||
const formatLanguageName = (item: SelectOption) => {
|
const formatLanguageName = (item: SelectOption) => {
|
||||||
return t(`voice.language.${replace(String(item.value), '-', '')}`, item.name, { ns: 'common' as const })
|
return t(`voice.language.${replace(item.value, '-', '')}`, item.name, { ns: 'common' as const })
|
||||||
}
|
}
|
||||||
|
|
||||||
let languageItem = languages.find(item => item.value === text2speech?.language)
|
let languageItem = languages.find(item => item.value === text2speech?.language)
|
||||||
@ -101,9 +101,9 @@ const VoiceParamConfig = ({
|
|||||||
</Infotip>
|
</Infotip>
|
||||||
</div>
|
</div>
|
||||||
<Select
|
<Select
|
||||||
value={languageItem ? String(languageItem.value) : null}
|
value={languageItem?.value ?? null}
|
||||||
onValueChange={(nextValue) => {
|
onValueChange={(nextValue) => {
|
||||||
if (!nextValue)
|
if (nextValue == null)
|
||||||
return
|
return
|
||||||
handleChange({
|
handleChange({
|
||||||
language: nextValue,
|
language: nextValue,
|
||||||
@ -115,7 +115,7 @@ const VoiceParamConfig = ({
|
|||||||
</SelectTrigger>
|
</SelectTrigger>
|
||||||
<SelectContent listClassName="max-h-60">
|
<SelectContent listClassName="max-h-60">
|
||||||
{languages.map(item => (
|
{languages.map(item => (
|
||||||
<SelectItem key={item.value} value={String(item.value)}>
|
<SelectItem key={item.value} value={item.value}>
|
||||||
<SelectItemText>
|
<SelectItemText>
|
||||||
{formatLanguageName(item)}
|
{formatLanguageName(item)}
|
||||||
</SelectItemText>
|
</SelectItemText>
|
||||||
@ -131,10 +131,10 @@ const VoiceParamConfig = ({
|
|||||||
</div>
|
</div>
|
||||||
<div className="flex items-center gap-1">
|
<div className="flex items-center gap-1">
|
||||||
<Select
|
<Select
|
||||||
value={voiceItem ? String(voiceItem.value) : null}
|
value={voiceItem?.value ?? null}
|
||||||
disabled={!languageItem}
|
disabled={!languageItem}
|
||||||
onValueChange={(nextValue) => {
|
onValueChange={(nextValue) => {
|
||||||
if (!nextValue)
|
if (nextValue == null || nextValue === '')
|
||||||
return
|
return
|
||||||
handleChange({
|
handleChange({
|
||||||
voice: nextValue,
|
voice: nextValue,
|
||||||
@ -147,7 +147,7 @@ const VoiceParamConfig = ({
|
|||||||
</SelectTrigger>
|
</SelectTrigger>
|
||||||
<SelectContent listClassName="max-h-60">
|
<SelectContent listClassName="max-h-60">
|
||||||
{voiceItems?.map((item: SelectOption) => (
|
{voiceItems?.map((item: SelectOption) => (
|
||||||
<SelectItem key={item.value} value={String(item.value)}>
|
<SelectItem key={item.value} value={item.value}>
|
||||||
<SelectItemText>
|
<SelectItemText>
|
||||||
{item.name}
|
{item.name}
|
||||||
</SelectItemText>
|
</SelectItemText>
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
import type { ComponentProps } from 'react'
|
||||||
import { CheckboxGroup } from '@langgenius/dify-ui/checkbox-group'
|
import { CheckboxGroup } from '@langgenius/dify-ui/checkbox-group'
|
||||||
import { fireEvent, render, screen } from '@testing-library/react'
|
import { fireEvent, render, screen } from '@testing-library/react'
|
||||||
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||||
@ -12,7 +13,7 @@ vi.mock('../../display-toggle', () => ({
|
|||||||
}))
|
}))
|
||||||
|
|
||||||
describe('MenuBar', () => {
|
describe('MenuBar', () => {
|
||||||
const defaultProps = {
|
const defaultProps: ComponentProps<typeof MenuBar> = {
|
||||||
hasSelectableSegments: true,
|
hasSelectableSegments: true,
|
||||||
isLoading: false,
|
isLoading: false,
|
||||||
totalText: '10 Chunks',
|
totalText: '10 Chunks',
|
||||||
@ -21,7 +22,7 @@ describe('MenuBar', () => {
|
|||||||
{ value: 0, name: 'Enabled' },
|
{ value: 0, name: 'Enabled' },
|
||||||
{ value: 1, name: 'Disabled' },
|
{ value: 1, name: 'Disabled' },
|
||||||
],
|
],
|
||||||
selectDefaultValue: 'all' as const,
|
selectDefaultValue: 'all',
|
||||||
onChangeStatus: vi.fn(),
|
onChangeStatus: vi.fn(),
|
||||||
inputValue: '',
|
inputValue: '',
|
||||||
onInputChange: vi.fn(),
|
onInputChange: vi.fn(),
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
'use client'
|
'use client'
|
||||||
|
import type { SegmentStatusFilterOption, SegmentStatusFilterValue } from '../hooks/use-search-filter'
|
||||||
import { Checkbox } from '@langgenius/dify-ui/checkbox'
|
import { Checkbox } from '@langgenius/dify-ui/checkbox'
|
||||||
import { Select, SelectContent, SelectItem, SelectItemIndicator, SelectItemText, SelectTrigger } from '@langgenius/dify-ui/select'
|
import { Select, SelectContent, SelectItem, SelectItemIndicator, SelectItemText, SelectTrigger } from '@langgenius/dify-ui/select'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
@ -7,18 +8,13 @@ import Input from '@/app/components/base/input'
|
|||||||
import DisplayToggle from '../display-toggle'
|
import DisplayToggle from '../display-toggle'
|
||||||
import s from '../style.module.css'
|
import s from '../style.module.css'
|
||||||
|
|
||||||
type Item = {
|
|
||||||
value: number | string
|
|
||||||
name: string
|
|
||||||
} & Record<string, unknown>
|
|
||||||
|
|
||||||
type MenuBarProps = {
|
type MenuBarProps = {
|
||||||
hasSelectableSegments: boolean
|
hasSelectableSegments: boolean
|
||||||
isLoading: boolean
|
isLoading: boolean
|
||||||
totalText: string
|
totalText: string
|
||||||
statusList: Item[]
|
statusList: SegmentStatusFilterOption[]
|
||||||
selectDefaultValue: 'all' | 0 | 1
|
selectDefaultValue: SegmentStatusFilterValue
|
||||||
onChangeStatus: (item: Item) => void
|
onChangeStatus: (item: SegmentStatusFilterOption) => void
|
||||||
inputValue: string
|
inputValue: string
|
||||||
onInputChange: (value: string) => void
|
onInputChange: (value: string) => void
|
||||||
isCollapsed: boolean
|
isCollapsed: boolean
|
||||||
@ -55,12 +51,12 @@ function MenuBar({
|
|||||||
<span className="size-4 shrink-0" aria-hidden />
|
<span className="size-4 shrink-0" aria-hidden />
|
||||||
)}
|
)}
|
||||||
<div className="flex-1 pl-5 system-sm-semibold-uppercase text-text-secondary">{totalText}</div>
|
<div className="flex-1 pl-5 system-sm-semibold-uppercase text-text-secondary">{totalText}</div>
|
||||||
<Select
|
<Select<SegmentStatusFilterValue>
|
||||||
value={selectedStatus ? String(selectedStatus.value) : null}
|
value={selectedStatus?.value ?? null}
|
||||||
onValueChange={(nextValue) => {
|
onValueChange={(nextValue) => {
|
||||||
if (!nextValue)
|
if (nextValue == null)
|
||||||
return
|
return
|
||||||
const nextItem = statusList.find(item => String(item.value) === nextValue)
|
const nextItem = statusList.find(item => item.value === nextValue)
|
||||||
if (nextItem)
|
if (nextItem)
|
||||||
onChangeStatus(nextItem)
|
onChangeStatus(nextItem)
|
||||||
}}
|
}}
|
||||||
@ -70,7 +66,7 @@ function MenuBar({
|
|||||||
</SelectTrigger>
|
</SelectTrigger>
|
||||||
<SelectContent popupClassName="w-[160px]">
|
<SelectContent popupClassName="w-[160px]">
|
||||||
{statusList.map(item => (
|
{statusList.map(item => (
|
||||||
<SelectItem key={item.value} value={String(item.value)}>
|
<SelectItem key={item.value} value={item.value}>
|
||||||
<SelectItemText>{item.name}</SelectItemText>
|
<SelectItemText>{item.name}</SelectItemText>
|
||||||
<SelectItemIndicator />
|
<SelectItemIndicator />
|
||||||
</SelectItem>
|
</SelectItem>
|
||||||
|
|||||||
@ -2,8 +2,10 @@ import { useDebounceFn } from 'ahooks'
|
|||||||
import { useCallback, useMemo, useRef, useState } from 'react'
|
import { useCallback, useMemo, useRef, useState } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
|
|
||||||
type SelectOption = {
|
export type SegmentStatusFilterValue = 'all' | 0 | 1
|
||||||
value: string | number
|
|
||||||
|
export type SegmentStatusFilterOption = {
|
||||||
|
value: SegmentStatusFilterValue
|
||||||
name: string
|
name: string
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -11,10 +13,10 @@ type UseSearchFilterReturn = {
|
|||||||
inputValue: string
|
inputValue: string
|
||||||
searchValue: string
|
searchValue: string
|
||||||
selectedStatus: boolean | 'all'
|
selectedStatus: boolean | 'all'
|
||||||
statusList: SelectOption[]
|
statusList: SegmentStatusFilterOption[]
|
||||||
selectDefaultValue: 'all' | 0 | 1
|
selectDefaultValue: SegmentStatusFilterValue
|
||||||
handleInputChange: (value: string) => void
|
handleInputChange: (value: string) => void
|
||||||
onChangeStatus: (item: SelectOption) => void
|
onChangeStatus: (item: SegmentStatusFilterOption) => void
|
||||||
onClearFilter: () => void
|
onClearFilter: () => void
|
||||||
resetPage: () => void
|
resetPage: () => void
|
||||||
}
|
}
|
||||||
@ -31,7 +33,7 @@ export const useSearchFilter = (options: UseSearchFilterOptions): UseSearchFilte
|
|||||||
const [searchValue, setSearchValue] = useState<string>('')
|
const [searchValue, setSearchValue] = useState<string>('')
|
||||||
const [selectedStatus, setSelectedStatus] = useState<boolean | 'all'>('all')
|
const [selectedStatus, setSelectedStatus] = useState<boolean | 'all'>('all')
|
||||||
|
|
||||||
const statusList = useRef<SelectOption[]>([
|
const statusList = useRef<SegmentStatusFilterOption[]>([
|
||||||
{ value: 'all', name: t('list.index.all', { ns: 'datasetDocuments' }) },
|
{ value: 'all', name: t('list.index.all', { ns: 'datasetDocuments' }) },
|
||||||
{ value: 0, name: t('list.status.disabled', { ns: 'datasetDocuments' }) },
|
{ value: 0, name: t('list.status.disabled', { ns: 'datasetDocuments' }) },
|
||||||
{ value: 1, name: t('list.status.enabled', { ns: 'datasetDocuments' }) },
|
{ value: 1, name: t('list.status.enabled', { ns: 'datasetDocuments' }) },
|
||||||
@ -47,7 +49,7 @@ export const useSearchFilter = (options: UseSearchFilterOptions): UseSearchFilte
|
|||||||
handleSearch()
|
handleSearch()
|
||||||
}, [handleSearch])
|
}, [handleSearch])
|
||||||
|
|
||||||
const onChangeStatus = useCallback(({ value }: SelectOption) => {
|
const onChangeStatus = useCallback(({ value }: SegmentStatusFilterOption) => {
|
||||||
setSelectedStatus(value === 'all' ? 'all' : !!value)
|
setSelectedStatus(value === 'all' ? 'all' : !!value)
|
||||||
onPageChange(1)
|
onPageChange(1)
|
||||||
}, [onPageChange])
|
}, [onPageChange])
|
||||||
|
|||||||
@ -19,7 +19,7 @@ type SelectOption = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type TimezoneOption = {
|
type TimezoneOption = {
|
||||||
value: string | number
|
value: string
|
||||||
name: string
|
name: string
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -119,7 +119,7 @@ export default function PreferencePage() {
|
|||||||
value={selectedLanguage?.value ?? null}
|
value={selectedLanguage?.value ?? null}
|
||||||
disabled={editing}
|
disabled={editing}
|
||||||
onValueChange={(nextValue) => {
|
onValueChange={(nextValue) => {
|
||||||
if (!nextValue)
|
if (nextValue == null)
|
||||||
return
|
return
|
||||||
const nextItem = languageOptions.find(item => item.value === nextValue)
|
const nextItem = languageOptions.find(item => item.value === nextValue)
|
||||||
if (nextItem)
|
if (nextItem)
|
||||||
@ -142,12 +142,12 @@ export default function PreferencePage() {
|
|||||||
<div className="mb-6">
|
<div className="mb-6">
|
||||||
<div className={titleClassName}>{t('language.timezone', { ns: 'common' })}</div>
|
<div className={titleClassName}>{t('language.timezone', { ns: 'common' })}</div>
|
||||||
<Select
|
<Select
|
||||||
value={selectedTimezone ? String(selectedTimezone.value) : null}
|
value={selectedTimezone?.value ?? null}
|
||||||
disabled={editing}
|
disabled={editing}
|
||||||
onValueChange={(nextValue) => {
|
onValueChange={(nextValue) => {
|
||||||
if (!nextValue)
|
if (!nextValue)
|
||||||
return
|
return
|
||||||
const nextItem = timezones.find(item => String(item.value) === nextValue)
|
const nextItem = timezones.find(item => item.value === nextValue)
|
||||||
if (nextItem)
|
if (nextItem)
|
||||||
handleSelectTimezone(nextItem)
|
handleSelectTimezone(nextItem)
|
||||||
}}
|
}}
|
||||||
@ -157,7 +157,7 @@ export default function PreferencePage() {
|
|||||||
</SelectTrigger>
|
</SelectTrigger>
|
||||||
<SelectContent>
|
<SelectContent>
|
||||||
{timezones.map(item => (
|
{timezones.map(item => (
|
||||||
<SelectItem key={item.value} value={String(item.value)}>
|
<SelectItem key={item.value} value={item.value}>
|
||||||
<SelectItemText>{item.name}</SelectItemText>
|
<SelectItemText>{item.name}</SelectItemText>
|
||||||
<SelectItemIndicator />
|
<SelectItemIndicator />
|
||||||
</SelectItem>
|
</SelectItem>
|
||||||
|
|||||||
@ -24,7 +24,7 @@ import SelectPackage from './steps/selectPackage'
|
|||||||
const i18nPrefix = 'installFromGitHub'
|
const i18nPrefix = 'installFromGitHub'
|
||||||
|
|
||||||
type SelectOption = {
|
type SelectOption = {
|
||||||
value: string | number
|
value: string
|
||||||
name: string
|
name: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -5,7 +5,7 @@ import { PluginCategoryEnum } from '../../../../types'
|
|||||||
import SelectPackage from '../selectPackage'
|
import SelectPackage from '../selectPackage'
|
||||||
|
|
||||||
type SelectOption = {
|
type SelectOption = {
|
||||||
value: string | number
|
value: string
|
||||||
name: string
|
name: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -12,7 +12,7 @@ import { handleUpload } from '../../hooks'
|
|||||||
const i18nPrefix = 'installFromGitHub'
|
const i18nPrefix = 'installFromGitHub'
|
||||||
|
|
||||||
type SelectOption = {
|
type SelectOption = {
|
||||||
value: string | number
|
value: string
|
||||||
name: string
|
name: string
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -49,8 +49,8 @@ const SelectPackage: React.FC<SelectPackageProps> = ({
|
|||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
const isEdit = Boolean(updatePayload)
|
const isEdit = Boolean(updatePayload)
|
||||||
const [isUploading, setIsUploading] = React.useState(false)
|
const [isUploading, setIsUploading] = React.useState(false)
|
||||||
const selectedVersionOption = versions.find(item => String(item.value) === selectedVersion) ?? null
|
const selectedVersionOption = versions.find(item => item.value === selectedVersion) ?? null
|
||||||
const selectedPackageOption = packages.find(item => String(item.value) === selectedPackage) ?? null
|
const selectedPackageOption = packages.find(item => item.value === selectedPackage) ?? null
|
||||||
|
|
||||||
const handleUploadPackage = async () => {
|
const handleUploadPackage = async () => {
|
||||||
if (isUploading)
|
if (isUploading)
|
||||||
@ -80,11 +80,11 @@ const SelectPackage: React.FC<SelectPackageProps> = ({
|
|||||||
<>
|
<>
|
||||||
<FieldRoot name="version" className="gap-4 self-stretch">
|
<FieldRoot name="version" className="gap-4 self-stretch">
|
||||||
<Select
|
<Select
|
||||||
value={selectedVersionOption ? String(selectedVersionOption.value) : null}
|
value={selectedVersionOption?.value ?? null}
|
||||||
onValueChange={(value) => {
|
onValueChange={(value) => {
|
||||||
if (!value)
|
if (value == null)
|
||||||
return
|
return
|
||||||
const selectedItem = versions.find(item => String(item.value) === value)
|
const selectedItem = versions.find(item => item.value === value)
|
||||||
if (selectedItem)
|
if (selectedItem)
|
||||||
onSelectVersion(selectedItem)
|
onSelectVersion(selectedItem)
|
||||||
}}
|
}}
|
||||||
@ -110,7 +110,7 @@ const SelectPackage: React.FC<SelectPackageProps> = ({
|
|||||||
</SelectTrigger>
|
</SelectTrigger>
|
||||||
<SelectContent popupClassName="w-[512px]">
|
<SelectContent popupClassName="w-[512px]">
|
||||||
{versions.map(item => (
|
{versions.map(item => (
|
||||||
<SelectItem key={item.value} value={String(item.value)}>
|
<SelectItem key={item.value} value={item.value}>
|
||||||
<SelectItemText>{item.name}</SelectItemText>
|
<SelectItemText>{item.name}</SelectItemText>
|
||||||
{item.value === updatePayload?.originalPackageInfo.version && (
|
{item.value === updatePayload?.originalPackageInfo.version && (
|
||||||
<Badge uppercase={true} className="ml-1 shrink-0">INSTALLED</Badge>
|
<Badge uppercase={true} className="ml-1 shrink-0">INSTALLED</Badge>
|
||||||
@ -123,12 +123,12 @@ const SelectPackage: React.FC<SelectPackageProps> = ({
|
|||||||
</FieldRoot>
|
</FieldRoot>
|
||||||
<FieldRoot name="package" className="gap-4 self-stretch">
|
<FieldRoot name="package" className="gap-4 self-stretch">
|
||||||
<Select
|
<Select
|
||||||
value={selectedPackageOption ? String(selectedPackageOption.value) : null}
|
value={selectedPackageOption?.value ?? null}
|
||||||
readOnly={!selectedVersion}
|
readOnly={!selectedVersion}
|
||||||
onValueChange={(value) => {
|
onValueChange={(value) => {
|
||||||
if (!value)
|
if (value == null)
|
||||||
return
|
return
|
||||||
const selectedItem = packages.find(item => String(item.value) === value)
|
const selectedItem = packages.find(item => item.value === value)
|
||||||
if (selectedItem)
|
if (selectedItem)
|
||||||
onSelectPackage(selectedItem)
|
onSelectPackage(selectedItem)
|
||||||
}}
|
}}
|
||||||
@ -141,7 +141,7 @@ const SelectPackage: React.FC<SelectPackageProps> = ({
|
|||||||
</SelectTrigger>
|
</SelectTrigger>
|
||||||
<SelectContent popupClassName="w-[512px]">
|
<SelectContent popupClassName="w-[512px]">
|
||||||
{packages.map(item => (
|
{packages.map(item => (
|
||||||
<SelectItem key={item.value} value={String(item.value)}>
|
<SelectItem key={item.value} value={item.value}>
|
||||||
<SelectItemText>{item.name}</SelectItemText>
|
<SelectItemText>{item.name}</SelectItemText>
|
||||||
<SelectItemIndicator />
|
<SelectItemIndicator />
|
||||||
</SelectItem>
|
</SelectItem>
|
||||||
|
|||||||
@ -156,8 +156,9 @@ const ReasoningConfigForm: React.FC<Props> = ({
|
|||||||
language,
|
language,
|
||||||
schema,
|
schema,
|
||||||
})
|
})
|
||||||
|
const selectValue = typeof varInput?.value === 'string' ? varInput.value : null
|
||||||
const selectedOption = isSelect && options
|
const selectedOption = isSelect && options
|
||||||
? pickerProps.selectItems.find(item => item.value === (varInput?.value as string | number | undefined)) ?? null
|
? pickerProps.selectItems.find(item => item.value === selectValue) ?? null
|
||||||
: null
|
: null
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -230,13 +231,20 @@ const ReasoningConfigForm: React.FC<Props> = ({
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{isSelect && options && (
|
{isSelect && options && (
|
||||||
<Select value={selectedOption ? String(selectedOption.value) : null} onValueChange={value => value && handleValueChange(variable, type)(value)}>
|
<Select<string>
|
||||||
|
value={selectedOption?.value ?? null}
|
||||||
|
onValueChange={(value) => {
|
||||||
|
if (value == null || value === '')
|
||||||
|
return
|
||||||
|
handleValueChange(variable, type)(value)
|
||||||
|
}}
|
||||||
|
>
|
||||||
<SelectTrigger className="h-8 grow">
|
<SelectTrigger className="h-8 grow">
|
||||||
{selectedOption?.name ?? placeholder?.[language] ?? placeholder?.en_US}
|
{selectedOption?.name ?? placeholder?.[language] ?? placeholder?.en_US}
|
||||||
</SelectTrigger>
|
</SelectTrigger>
|
||||||
<SelectContent>
|
<SelectContent>
|
||||||
{pickerProps.selectItems.map(item => (
|
{pickerProps.selectItems.map(item => (
|
||||||
<SelectItem key={item.value} value={String(item.value)}>
|
<SelectItem key={item.value} value={item.value}>
|
||||||
<SelectItemText>{item.name}</SelectItemText>
|
<SelectItemText>{item.name}</SelectItemText>
|
||||||
<SelectItemIndicator />
|
<SelectItemIndicator />
|
||||||
</SelectItem>
|
</SelectItem>
|
||||||
|
|||||||
@ -38,6 +38,7 @@ type IRunOnceProps = {
|
|||||||
isStopping: boolean
|
isStopping: boolean
|
||||||
} | null
|
} | null
|
||||||
}
|
}
|
||||||
|
|
||||||
const RunOnce: FC<IRunOnceProps> = ({
|
const RunOnce: FC<IRunOnceProps> = ({
|
||||||
promptConfig,
|
promptConfig,
|
||||||
inputs,
|
inputs,
|
||||||
@ -117,109 +118,115 @@ const RunOnce: FC<IRunOnceProps> = ({
|
|||||||
<form onSubmit={onSubmit}>
|
<form onSubmit={onSubmit}>
|
||||||
{(inputs === null || inputs === undefined || Object.keys(inputs).length === 0) || !isInitialized
|
{(inputs === null || inputs === undefined || Object.keys(inputs).length === 0) || !isInitialized
|
||||||
? null
|
? null
|
||||||
: promptConfig.prompt_variables.filter(item => item.hide !== true).map(item => (
|
: promptConfig.prompt_variables.filter(item => item.hide !== true).map((item) => {
|
||||||
<div className="mt-4 w-full" key={item.key}>
|
const inputValue = inputs[item.key]
|
||||||
{item.type !== 'checkbox' && (
|
const selectValue = typeof inputValue === 'string' && inputValue !== '' ? inputValue : null
|
||||||
<div className="flex h-6 items-center gap-1 system-md-semibold text-text-secondary">
|
const defaultSelectValue = typeof item.default === 'string' && item.default !== '' ? item.default : null
|
||||||
<div className="truncate">{item.name}</div>
|
|
||||||
{!item.required && <span className="system-xs-regular text-text-tertiary">{t('panel.optional', { ns: 'workflow' })}</span>}
|
return (
|
||||||
|
<div className="mt-4 w-full" key={item.key}>
|
||||||
|
{item.type !== 'checkbox' && (
|
||||||
|
<div className="flex h-6 items-center gap-1 system-md-semibold text-text-secondary">
|
||||||
|
<div className="truncate">{item.name}</div>
|
||||||
|
{!item.required && <span className="system-xs-regular text-text-tertiary">{t('panel.optional', { ns: 'workflow' })}</span>}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
<div className="mt-1">
|
||||||
|
{item.type === 'select' && (
|
||||||
|
<Select<string>
|
||||||
|
value={selectValue}
|
||||||
|
onValueChange={(nextValue) => {
|
||||||
|
if (nextValue == null || nextValue === '')
|
||||||
|
return
|
||||||
|
handleInputsChange({ ...inputsRef.current, [item.key]: nextValue })
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<SelectTrigger className="w-full">
|
||||||
|
{selectValue ?? defaultSelectValue ?? t('placeholder.select', { ns: 'common' })}
|
||||||
|
</SelectTrigger>
|
||||||
|
<SelectContent>
|
||||||
|
{(item.options || []).map(option => (
|
||||||
|
<SelectItem key={option} value={option}>
|
||||||
|
<SelectItemText>{option}</SelectItemText>
|
||||||
|
<SelectItemIndicator />
|
||||||
|
</SelectItem>
|
||||||
|
))}
|
||||||
|
</SelectContent>
|
||||||
|
</Select>
|
||||||
|
)}
|
||||||
|
{item.type === 'string' && (
|
||||||
|
<Input
|
||||||
|
type="text"
|
||||||
|
placeholder={item.name}
|
||||||
|
value={inputs[item.key] as string}
|
||||||
|
onChange={(e: ChangeEvent<HTMLInputElement>) => { handleInputsChange({ ...inputsRef.current, [item.key]: e.target.value }) }}
|
||||||
|
maxLength={item.max_length}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{item.type === 'paragraph' && (
|
||||||
|
<Textarea
|
||||||
|
aria-label={item.name}
|
||||||
|
className="h-[104px] sm:text-xs"
|
||||||
|
placeholder={item.name}
|
||||||
|
value={inputs[item.key] as string}
|
||||||
|
onValueChange={(value) => { handleInputsChange({ ...inputsRef.current, [item.key]: value }) }}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{item.type === 'number' && (
|
||||||
|
<Input
|
||||||
|
type="number"
|
||||||
|
placeholder={item.name}
|
||||||
|
value={inputs[item.key] as number}
|
||||||
|
onChange={(e: ChangeEvent<HTMLInputElement>) => { handleInputsChange({ ...inputsRef.current, [item.key]: e.target.value }) }}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{item.type === 'checkbox' && (
|
||||||
|
<BoolInput
|
||||||
|
name={item.name || item.key}
|
||||||
|
value={!!inputs[item.key] as boolean}
|
||||||
|
required={item.required}
|
||||||
|
onChange={(value) => { handleInputsChange({ ...inputsRef.current, [item.key]: value }) }}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{item.type === 'file' && (
|
||||||
|
<FileUploaderInAttachmentWrapper
|
||||||
|
value={inputs[item.key] && typeof inputs[item.key] === 'object' && !Array.isArray(inputs[item.key])
|
||||||
|
? [inputs[item.key] as FileEntity]
|
||||||
|
: []}
|
||||||
|
onChange={(files) => { handleInputsChange({ ...inputsRef.current, [item.key]: files[0] }) }}
|
||||||
|
fileConfig={{
|
||||||
|
...item.config,
|
||||||
|
fileUploadConfig: (visionConfig as any).fileUploadConfig,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{item.type === 'file-list' && (
|
||||||
|
<FileUploaderInAttachmentWrapper
|
||||||
|
value={Array.isArray(inputs[item.key]) ? inputs[item.key] as FileEntity[] : []}
|
||||||
|
onChange={(files) => { handleInputsChange({ ...inputsRef.current, [item.key]: files }) }}
|
||||||
|
fileConfig={{
|
||||||
|
...item.config,
|
||||||
|
// eslint-disable-next-line ts/no-explicit-any
|
||||||
|
fileUploadConfig: (visionConfig as any).fileUploadConfig,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{item.type === 'json_object' && (
|
||||||
|
<CodeEditor
|
||||||
|
language={CodeLanguage.json}
|
||||||
|
value={inputs[item.key] as string}
|
||||||
|
onChange={(value) => { handleInputsChange({ ...inputsRef.current, [item.key]: value }) }}
|
||||||
|
noWrapper
|
||||||
|
className="bg h-[80px] overflow-y-auto rounded-[10px] bg-components-input-bg-normal p-1"
|
||||||
|
placeholder={
|
||||||
|
<div className="whitespace-pre">{typeof item.json_schema === 'string' ? item.json_schema : JSON.stringify(item.json_schema || '', null, 2)}</div>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
)}
|
|
||||||
<div className="mt-1">
|
|
||||||
{item.type === 'select' && (
|
|
||||||
<Select
|
|
||||||
value={inputs[item.key] ? String(inputs[item.key]) : null}
|
|
||||||
onValueChange={(nextValue) => {
|
|
||||||
if (!nextValue)
|
|
||||||
return
|
|
||||||
handleInputsChange({ ...inputsRef.current, [item.key]: nextValue })
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<SelectTrigger className="w-full">
|
|
||||||
{String(inputs[item.key] || item.default || t('placeholder.select', { ns: 'common' }))}
|
|
||||||
</SelectTrigger>
|
|
||||||
<SelectContent>
|
|
||||||
{(item.options || []).map(option => (
|
|
||||||
<SelectItem key={option} value={option}>
|
|
||||||
<SelectItemText>{option}</SelectItemText>
|
|
||||||
<SelectItemIndicator />
|
|
||||||
</SelectItem>
|
|
||||||
))}
|
|
||||||
</SelectContent>
|
|
||||||
</Select>
|
|
||||||
)}
|
|
||||||
{item.type === 'string' && (
|
|
||||||
<Input
|
|
||||||
type="text"
|
|
||||||
placeholder={item.name}
|
|
||||||
value={inputs[item.key] as string}
|
|
||||||
onChange={(e: ChangeEvent<HTMLInputElement>) => { handleInputsChange({ ...inputsRef.current, [item.key]: e.target.value }) }}
|
|
||||||
maxLength={item.max_length}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
{item.type === 'paragraph' && (
|
|
||||||
<Textarea
|
|
||||||
aria-label={item.name}
|
|
||||||
className="h-[104px] sm:text-xs"
|
|
||||||
placeholder={item.name}
|
|
||||||
value={inputs[item.key] as string}
|
|
||||||
onValueChange={(value) => { handleInputsChange({ ...inputsRef.current, [item.key]: value }) }}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
{item.type === 'number' && (
|
|
||||||
<Input
|
|
||||||
type="number"
|
|
||||||
placeholder={item.name}
|
|
||||||
value={inputs[item.key] as number}
|
|
||||||
onChange={(e: ChangeEvent<HTMLInputElement>) => { handleInputsChange({ ...inputsRef.current, [item.key]: e.target.value }) }}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
{item.type === 'checkbox' && (
|
|
||||||
<BoolInput
|
|
||||||
name={item.name || item.key}
|
|
||||||
value={!!inputs[item.key] as boolean}
|
|
||||||
required={item.required}
|
|
||||||
onChange={(value) => { handleInputsChange({ ...inputsRef.current, [item.key]: value }) }}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
{item.type === 'file' && (
|
|
||||||
<FileUploaderInAttachmentWrapper
|
|
||||||
value={inputs[item.key] && typeof inputs[item.key] === 'object' && !Array.isArray(inputs[item.key])
|
|
||||||
? [inputs[item.key] as FileEntity]
|
|
||||||
: []}
|
|
||||||
onChange={(files) => { handleInputsChange({ ...inputsRef.current, [item.key]: files[0] }) }}
|
|
||||||
fileConfig={{
|
|
||||||
...item.config,
|
|
||||||
fileUploadConfig: (visionConfig as any).fileUploadConfig,
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
{item.type === 'file-list' && (
|
|
||||||
<FileUploaderInAttachmentWrapper
|
|
||||||
value={Array.isArray(inputs[item.key]) ? inputs[item.key] as FileEntity[] : []}
|
|
||||||
onChange={(files) => { handleInputsChange({ ...inputsRef.current, [item.key]: files }) }}
|
|
||||||
fileConfig={{
|
|
||||||
...item.config,
|
|
||||||
// eslint-disable-next-line ts/no-explicit-any
|
|
||||||
fileUploadConfig: (visionConfig as any).fileUploadConfig,
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
{item.type === 'json_object' && (
|
|
||||||
<CodeEditor
|
|
||||||
language={CodeLanguage.json}
|
|
||||||
value={inputs[item.key] as string}
|
|
||||||
onChange={(value) => { handleInputsChange({ ...inputsRef.current, [item.key]: value }) }}
|
|
||||||
noWrapper
|
|
||||||
className="bg h-[80px] overflow-y-auto rounded-[10px] bg-components-input-bg-normal p-1"
|
|
||||||
placeholder={
|
|
||||||
<div className="whitespace-pre">{typeof item.json_schema === 'string' ? item.json_schema : JSON.stringify(item.json_schema || '', null, 2)}</div>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
)
|
||||||
))}
|
})}
|
||||||
{
|
{
|
||||||
visionConfig?.enabled && (
|
visionConfig?.enabled && (
|
||||||
<div className="mt-4 w-full">
|
<div className="mt-4 w-full">
|
||||||
|
|||||||
@ -74,7 +74,7 @@ const createVar = (type: VarType, variable = 'test.variable'): Var => ({
|
|||||||
|
|
||||||
type SelectOption = {
|
type SelectOption = {
|
||||||
name: string
|
name: string
|
||||||
value: string | number
|
value: ErrorHandleMode
|
||||||
}
|
}
|
||||||
|
|
||||||
describe('iteration/use-config', () => {
|
describe('iteration/use-config', () => {
|
||||||
|
|||||||
@ -124,12 +124,12 @@ const Panel: FC<NodePanelProps<IterationNodeType>> = ({
|
|||||||
|
|
||||||
<div className="px-4 py-2">
|
<div className="px-4 py-2">
|
||||||
<Field title={errorResponseMethodLabel}>
|
<Field title={errorResponseMethodLabel}>
|
||||||
<Select
|
<Select<ErrorHandleMode>
|
||||||
value={selectedResponseMethod ? String(selectedResponseMethod.value) : null}
|
value={selectedResponseMethod?.value ?? null}
|
||||||
onValueChange={(nextValue) => {
|
onValueChange={(nextValue) => {
|
||||||
if (!nextValue)
|
if (nextValue == null)
|
||||||
return
|
return
|
||||||
const nextItem = responseMethod.find(item => String(item.value) === nextValue)
|
const nextItem = responseMethod.find(item => item.value === nextValue)
|
||||||
if (nextItem)
|
if (nextItem)
|
||||||
changeErrorResponseMode(nextItem)
|
changeErrorResponseMode(nextItem)
|
||||||
}}
|
}}
|
||||||
@ -140,7 +140,7 @@ const Panel: FC<NodePanelProps<IterationNodeType>> = ({
|
|||||||
</SelectTrigger>
|
</SelectTrigger>
|
||||||
<SelectContent>
|
<SelectContent>
|
||||||
{responseMethod.map(item => (
|
{responseMethod.map(item => (
|
||||||
<SelectItem key={item.value} value={String(item.value)}>
|
<SelectItem key={item.value} value={item.value}>
|
||||||
<SelectItemText>{item.name}</SelectItemText>
|
<SelectItemText>{item.name}</SelectItemText>
|
||||||
<SelectItemIndicator />
|
<SelectItemIndicator />
|
||||||
</SelectItem>
|
</SelectItem>
|
||||||
|
|||||||
@ -22,7 +22,7 @@ import { toNodeOutputVars } from '../_base/components/variable/utils'
|
|||||||
import useNodeCrud from '../_base/hooks/use-node-crud'
|
import useNodeCrud from '../_base/hooks/use-node-crud'
|
||||||
|
|
||||||
type SelectOption = {
|
type SelectOption = {
|
||||||
value: string | number
|
value: ErrorHandleMode
|
||||||
name: string
|
name: string
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -98,7 +98,7 @@ const useConfig = (id: string, payload: IterationNodeType) => {
|
|||||||
|
|
||||||
const changeErrorResponseMode = useCallback((item: SelectOption) => {
|
const changeErrorResponseMode = useCallback((item: SelectOption) => {
|
||||||
const newInputs = produce(inputs, (draft) => {
|
const newInputs = produce(inputs, (draft) => {
|
||||||
draft.error_handle_mode = item.value as ErrorHandleMode
|
draft.error_handle_mode = item.value
|
||||||
})
|
})
|
||||||
setInputs(newInputs)
|
setInputs(newInputs)
|
||||||
}, [inputs, setInputs])
|
}, [inputs, setInputs])
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import tz from './timezone.json'
|
import tz from './timezone.json'
|
||||||
|
|
||||||
type Item = {
|
type Item = {
|
||||||
value: number | string
|
value: string
|
||||||
name: string
|
name: string
|
||||||
}
|
}
|
||||||
export const timezones: Item[] = tz
|
export const timezones: Item[] = tz
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user