fix: SimpleSelect chevron icon state sync and add notClearable to monitoring selector (#23858)

This commit is contained in:
lyzno1
2025-08-13 13:55:10 +08:00
committed by GitHub
parent 21e1b825fe
commit e11a334c9b
5 changed files with 77 additions and 82 deletions

View File

@@ -54,6 +54,7 @@ export default function ChartView({ appId, headerRight }: IChartViewProps) {
<SimpleSelect <SimpleSelect
items={Object.entries(TIME_PERIOD_MAPPING).map(([k, v]) => ({ value: k, name: t(`appLog.filter.period.${v.name}`) }))} items={Object.entries(TIME_PERIOD_MAPPING).map(([k, v]) => ({ value: k, name: t(`appLog.filter.period.${v.name}`) }))}
className='mt-0 !w-40' className='mt-0 !w-40'
notClearable={true}
onSelect={(item) => { onSelect={(item) => {
const id = item.value const id = item.value
const value = TIME_PERIOD_MAPPING[id]?.value ?? '-1' const value = TIME_PERIOD_MAPPING[id]?.value ?? '-1'

View File

@@ -1,5 +1,5 @@
import React from 'react' import React from 'react'
import ChartView from './chartView' import ChartView from './chart-view'
import TracingPanel from './tracing/panel' import TracingPanel from './tracing/panel'
import ApikeyInfoPanel from '@/app/components/app/overview/apikey-info-panel' import ApikeyInfoPanel from '@/app/components/app/overview/apikey-info-panel'

View File

@@ -25,7 +25,7 @@ import type { EnvironmentVariable } from '@/app/components/workflow/types'
import { fetchWorkflowDraft } from '@/service/workflow' import { fetchWorkflowDraft } from '@/service/workflow'
import ContentDialog from '@/app/components/base/content-dialog' import ContentDialog from '@/app/components/base/content-dialog'
import Button from '@/app/components/base/button' import Button from '@/app/components/base/button'
import CardView from '@/app/(commonLayout)/app/(appDetailLayout)/[appId]/overview/cardView' import CardView from '@/app/(commonLayout)/app/(appDetailLayout)/[appId]/overview/card-view'
import Divider from '../base/divider' import Divider from '../base/divider'
import type { Operation } from './app-operations' import type { Operation } from './app-operations'
import AppOperations from './app-operations' import AppOperations from './app-operations'

View File

@@ -192,7 +192,6 @@ const SimpleSelect: FC<ISelectProps> = ({
const localPlaceholder = placeholder || t('common.placeholder.select') const localPlaceholder = placeholder || t('common.placeholder.select')
const [selectedItem, setSelectedItem] = useState<Item | null>(null) const [selectedItem, setSelectedItem] = useState<Item | null>(null)
const [open, setOpen] = useState(false)
useEffect(() => { useEffect(() => {
let defaultSelect = null let defaultSelect = null
@@ -215,88 +214,83 @@ const SimpleSelect: FC<ISelectProps> = ({
} }
}} }}
> >
<div className={classNames('group/simple-select relative h-9', wrapperClassName)}> {({ open }) => (
{renderTrigger && <ListboxButton className='w-full'>{renderTrigger(selectedItem)}</ListboxButton>} <div className={classNames('group/simple-select relative h-9', wrapperClassName)}>
{!renderTrigger && ( {renderTrigger && <ListboxButton className='w-full'>{renderTrigger(selectedItem)}</ListboxButton>}
<ListboxButton onClick={() => { {!renderTrigger && (
// get data-open, use setTimeout to ensure the attribute is set <ListboxButton onClick={() => {
setTimeout(() => { onOpenChange?.(open)
if (listboxRef.current) { }} className={classNames(`flex h-full w-full items-center rounded-lg border-0 bg-components-input-bg-normal pl-3 pr-10 focus-visible:bg-state-base-hover-alt focus-visible:outline-none group-hover/simple-select:bg-state-base-hover-alt sm:text-sm sm:leading-6 ${disabled ? 'cursor-not-allowed' : 'cursor-pointer'}`, className)}>
const isOpen = listboxRef.current.getAttribute('data-open') !== null <span className={classNames('system-sm-regular block truncate text-left text-components-input-text-filled', !selectedItem?.name && 'text-components-input-text-placeholder')}>{selectedItem?.name ?? localPlaceholder}</span>
setOpen(isOpen) <span className="absolute inset-y-0 right-0 flex items-center pr-2">
onOpenChange?.(isOpen) {isLoading ? <RiLoader4Line className='h-3.5 w-3.5 animate-spin text-text-secondary' />
} : (selectedItem && !notClearable)
}) ? (
}} className={classNames(`flex h-full w-full items-center rounded-lg border-0 bg-components-input-bg-normal pl-3 pr-10 focus-visible:bg-state-base-hover-alt focus-visible:outline-none group-hover/simple-select:bg-state-base-hover-alt sm:text-sm sm:leading-6 ${disabled ? 'cursor-not-allowed' : 'cursor-pointer'}`, className)}> <XMarkIcon
<span className={classNames('system-sm-regular block truncate text-left text-components-input-text-filled', !selectedItem?.name && 'text-components-input-text-placeholder')}>{selectedItem?.name ?? localPlaceholder}</span> onClick={(e) => {
<span className="absolute inset-y-0 right-0 flex items-center pr-2"> e.stopPropagation()
{isLoading ? <RiLoader4Line className='h-3.5 w-3.5 animate-spin text-text-secondary' /> setSelectedItem(null)
: (selectedItem && !notClearable) onSelect({ name: '', value: '' })
? ( }}
<XMarkIcon className="h-4 w-4 cursor-pointer text-text-quaternary"
onClick={(e) => { aria-hidden="false"
e.stopPropagation()
setSelectedItem(null)
onSelect({ name: '', value: '' })
}}
className="h-4 w-4 cursor-pointer text-text-quaternary"
aria-hidden="false"
/>
)
: (
open ? (
<ChevronUpIcon
className="h-4 w-4 text-text-quaternary group-hover/simple-select:text-text-secondary"
aria-hidden="true"
/>
) : (
<ChevronDownIcon
className="h-4 w-4 text-text-quaternary group-hover/simple-select:text-text-secondary"
aria-hidden="true"
/> />
) )
)} : (
</span> open ? (
</ListboxButton> <ChevronUpIcon
)} className="h-4 w-4 text-text-quaternary group-hover/simple-select:text-text-secondary"
aria-hidden="true"
/>
) : (
<ChevronDownIcon
className="h-4 w-4 text-text-quaternary group-hover/simple-select:text-text-secondary"
aria-hidden="true"
/>
)
)}
</span>
</ListboxButton>
)}
{(!disabled) && ( {(!disabled) && (
<ListboxOptions className={classNames('absolute z-10 mt-1 max-h-60 w-full overflow-auto rounded-xl border-[0.5px] border-components-panel-border bg-components-panel-bg-blur px-1 py-1 text-base shadow-lg backdrop-blur-sm focus:outline-none sm:text-sm', optionWrapClassName)}> <ListboxOptions className={classNames('absolute z-10 mt-1 max-h-60 w-full overflow-auto rounded-xl border-[0.5px] border-components-panel-border bg-components-panel-bg-blur px-1 py-1 text-base shadow-lg backdrop-blur-sm focus:outline-none sm:text-sm', optionWrapClassName)}>
{items.map((item: Item) => ( {items.map((item: Item) => (
<ListboxOption <ListboxOption
key={item.value} key={item.value}
className={ className={
classNames( classNames(
'relative cursor-pointer select-none rounded-lg py-2 pl-3 pr-9 text-text-secondary hover:bg-state-base-hover', 'relative cursor-pointer select-none rounded-lg py-2 pl-3 pr-9 text-text-secondary hover:bg-state-base-hover',
optionClassName, optionClassName,
) )
} }
value={item} value={item}
disabled={disabled} disabled={disabled}
> >
{({ /* active, */ selected }) => ( {({ /* active, */ selected }) => (
<> <>
{renderOption {renderOption
? renderOption({ item, selected }) ? renderOption({ item, selected })
: (<> : (<>
<span className={classNames('block', selected && 'font-normal')}>{item.name}</span> <span className={classNames('block', selected && 'font-normal')}>{item.name}</span>
{selected && !hideChecked && ( {selected && !hideChecked && (
<span <span
className={classNames( className={classNames(
'absolute inset-y-0 right-0 flex items-center pr-4 text-text-accent', 'absolute inset-y-0 right-0 flex items-center pr-4 text-text-accent',
)} )}
> >
<RiCheckLine className="h-4 w-4" aria-hidden="true" /> <RiCheckLine className="h-4 w-4" aria-hidden="true" />
</span> </span>
)} )}
</>)} </>)}
</> </>
)} )}
</ListboxOption> </ListboxOption>
))} ))}
</ListboxOptions> </ListboxOptions>
)} )}
</div> </div>
)}
</Listbox> </Listbox>
) )
} }