-LAN- 85cda47c70
feat: knowledge pipeline (#25360)
Signed-off-by: -LAN- <laipz8200@outlook.com>
Co-authored-by: twwu <twwu@dify.ai>
Co-authored-by: crazywoola <100913391+crazywoola@users.noreply.github.com>
Co-authored-by: jyong <718720800@qq.com>
Co-authored-by: Wu Tianwei <30284043+WTW0313@users.noreply.github.com>
Co-authored-by: QuantumGhost <obelisk.reg+git@gmail.com>
Co-authored-by: lyzno1 <yuanyouhuilyz@gmail.com>
Co-authored-by: quicksand <quicksandzn@gmail.com>
Co-authored-by: Jyong <76649700+JohnJyong@users.noreply.github.com>
Co-authored-by: lyzno1 <92089059+lyzno1@users.noreply.github.com>
Co-authored-by: zxhlyh <jasonapring2015@outlook.com>
Co-authored-by: Yongtao Huang <yongtaoh2022@gmail.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: Joel <iamjoel007@gmail.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: nite-knite <nkCoding@gmail.com>
Co-authored-by: Hanqing Zhao <sherry9277@gmail.com>
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Co-authored-by: Harry <xh001x@hotmail.com>
2025-09-18 12:49:10 +08:00

167 lines
4.5 KiB
TypeScript

import {
useCallback,
useState,
} from 'react'
import { useTranslation } from 'react-i18next'
import {
RiArrowDownSLine,
RiCheckLine,
} from '@remixicon/react'
import {
PortalToFollowElem,
PortalToFollowElemContent,
PortalToFollowElemTrigger,
} from '@/app/components/base/portal-to-follow-elem'
import type {
PortalToFollowElemOptions,
} from '@/app/components/base/portal-to-follow-elem'
import cn from '@/utils/classnames'
export type Option = {
label: string
value: string
}
export type PureSelectProps = {
options: Option[]
value?: string
onChange?: (value: string) => void
containerProps?: PortalToFollowElemOptions & {
open?: boolean
onOpenChange?: (open: boolean) => void
}
triggerProps?: {
className?: string
},
popupProps?: {
wrapperClassName?: string
className?: string
itemClassName?: string
title?: string
},
placeholder?: string
disabled?: boolean
triggerPopupSameWidth?: boolean
}
const PureSelect = ({
options,
value,
onChange,
containerProps,
triggerProps,
popupProps,
placeholder,
disabled,
triggerPopupSameWidth,
}: PureSelectProps) => {
const { t } = useTranslation()
const {
open,
onOpenChange,
placement,
offset,
} = containerProps || {}
const {
className: triggerClassName,
} = triggerProps || {}
const {
wrapperClassName: popupWrapperClassName,
className: popupClassName,
itemClassName: popupItemClassName,
title: popupTitle,
} = popupProps || {}
const [localOpen, setLocalOpen] = useState(false)
const mergedOpen = open ?? localOpen
const handleOpenChange = useCallback((openValue: boolean) => {
onOpenChange?.(openValue)
setLocalOpen(openValue)
}, [onOpenChange])
const selectedOption = options.find(option => option.value === value)
const triggerText = selectedOption?.label || placeholder || t('common.placeholder.select')
return (
<PortalToFollowElem
placement={placement || 'bottom-start'}
offset={offset || 4}
open={mergedOpen}
onOpenChange={handleOpenChange}
triggerPopupSameWidth={triggerPopupSameWidth}
>
<PortalToFollowElemTrigger
onClick={() => !disabled && handleOpenChange(!mergedOpen)}
asChild >
<div
className={cn(
'system-sm-regular group flex h-8 items-center rounded-lg bg-components-input-bg-normal px-2 text-components-input-text-filled',
!disabled && 'cursor-pointer hover:bg-state-base-hover-alt',
disabled && 'cursor-not-allowed opacity-50',
mergedOpen && !disabled && 'bg-state-base-hover-alt',
triggerClassName,
)}
>
<div
className='grow'
title={triggerText}
>
{triggerText}
</div>
<RiArrowDownSLine
className={cn(
'h-4 w-4 shrink-0 text-text-quaternary group-hover:text-text-secondary',
mergedOpen && 'text-text-secondary',
)}
/>
</div>
</PortalToFollowElemTrigger>
<PortalToFollowElemContent className={cn(
'z-[9999]',
popupWrapperClassName,
)}>
<div
className={cn(
'rounded-xl border-[0.5px] border-components-panel-border bg-components-panel-bg-blur p-1 shadow-lg',
popupClassName,
)}
>
{
popupTitle && (
<div className='system-xs-medium-uppercase flex h-[22px] items-center px-3 text-text-tertiary'>
{popupTitle}
</div>
)
}
{
options.map(option => (
<div
key={option.value}
className={cn(
'system-sm-medium flex h-8 cursor-pointer items-center rounded-lg px-2 text-text-secondary hover:bg-state-base-hover',
popupItemClassName,
)}
title={option.label}
onClick={() => {
if (disabled) return
onChange?.(option.value)
handleOpenChange(false)
}}
>
<div className='mr-1 grow truncate px-1'>
{option.label}
</div>
{
value === option.value && <RiCheckLine className='h-4 w-4 shrink-0 text-text-accent' />
}
</div>
))
}
</div>
</PortalToFollowElemContent>
</PortalToFollowElem>
)
}
export default PureSelect