fix: migrate select to Base UI items API (#4655)

This commit is contained in:
yyhhyyyyyy
2026-05-06 21:38:58 +08:00
committed by GitHub
parent 38a3314b9b
commit d98f0e8ac3
38 changed files with 1187 additions and 485 deletions
@@ -6,6 +6,7 @@ import { Label } from '@/components/ui/label'
import {
Select,
SelectContent,
SelectGroup,
SelectItem,
SelectTrigger,
SelectValue,
@@ -89,18 +90,26 @@ export function PresetSelector(props: PresetSelectorProps) {
<div className='space-y-1.5'>
<Label>{t('Preset Template')}</Label>
<Select
items={[
...OAUTH_PRESETS.map((preset) => ({
value: preset.key,
label: preset.name,
})),
]}
value={selectedPreset}
onValueChange={(v) => v !== null && handlePresetChange(v)}
>
<SelectTrigger className='w-full'>
<SelectValue placeholder={t('Select a preset...')} />
</SelectTrigger>
<SelectContent>
{OAUTH_PRESETS.map((preset) => (
<SelectItem key={preset.key} value={preset.key}>
{preset.name}
</SelectItem>
))}
<SelectContent alignItemWithTrigger={false}>
<SelectGroup>
{OAUTH_PRESETS.map((preset) => (
<SelectItem key={preset.key} value={preset.key}>
{preset.name}
</SelectItem>
))}
</SelectGroup>
</SelectContent>
</Select>
</div>
@@ -24,6 +24,7 @@ import { Input } from '@/components/ui/input'
import {
Select,
SelectContent,
SelectGroup,
SelectItem,
SelectTrigger,
SelectValue,
@@ -302,6 +303,12 @@ export function ProviderFormDialog(props: ProviderFormDialogProps) {
<FormItem>
<FormLabel>{t('Auth Style')}</FormLabel>
<Select
items={[
...AUTH_STYLE_OPTIONS.map((option) => ({
value: String(option.value),
label: t(option.labelKey),
})),
]}
value={String(field.value)}
onValueChange={(val) => field.onChange(Number(val))}
>
@@ -310,15 +317,17 @@ export function ProviderFormDialog(props: ProviderFormDialogProps) {
<SelectValue />
</SelectTrigger>
</FormControl>
<SelectContent>
{AUTH_STYLE_OPTIONS.map((option) => (
<SelectItem
key={option.value}
value={String(option.value)}
>
{t(option.labelKey)}
</SelectItem>
))}
<SelectContent alignItemWithTrigger={false}>
<SelectGroup>
{AUTH_STYLE_OPTIONS.map((option) => (
<SelectItem
key={option.value}
value={String(option.value)}
>
{t(option.labelKey)}
</SelectItem>
))}
</SelectGroup>
</SelectContent>
</Select>
<FormDescription>
@@ -17,6 +17,7 @@ import { Input } from '@/components/ui/input'
import {
Select,
SelectContent,
SelectGroup,
SelectItem,
SelectTrigger,
SelectValue,
@@ -221,18 +222,30 @@ export function PasskeySection({ defaultValues }: PasskeySectionProps) {
<FormItem>
<FormLabel>{t('User Verification')}</FormLabel>
<FormControl>
<Select value={field.value} onValueChange={field.onChange}>
<Select
items={[
{ value: 'required', label: t('Required') },
{ value: 'preferred', label: t('Recommended') },
{ value: 'discouraged', label: t('Discouraged') },
]}
value={field.value}
onValueChange={field.onChange}
>
<SelectTrigger>
<SelectValue placeholder={t('Select requirement')} />
</SelectTrigger>
<SelectContent>
<SelectItem value='required'>{t('Required')}</SelectItem>
<SelectItem value='preferred'>
{t('Recommended')}
</SelectItem>
<SelectItem value='discouraged'>
{t('Discouraged')}
</SelectItem>
<SelectContent alignItemWithTrigger={false}>
<SelectGroup>
<SelectItem value='required'>
{t('Required')}
</SelectItem>
<SelectItem value='preferred'>
{t('Recommended')}
</SelectItem>
<SelectItem value='discouraged'>
{t('Discouraged')}
</SelectItem>
</SelectGroup>
</SelectContent>
</Select>
</FormControl>
@@ -253,18 +266,28 @@ export function PasskeySection({ defaultValues }: PasskeySectionProps) {
<FormItem>
<FormLabel>{t('Device Type Preference')}</FormLabel>
<FormControl>
<Select value={field.value} onValueChange={field.onChange}>
<Select
items={[
{ value: 'none', label: t('Unlimited') },
{ value: 'platform', label: t('Built-in Device') },
{ value: 'cross-platform', label: t('External Device') },
]}
value={field.value}
onValueChange={field.onChange}
>
<SelectTrigger>
<SelectValue placeholder={t('No preference')} />
</SelectTrigger>
<SelectContent>
<SelectItem value='none'>{t('Unlimited')}</SelectItem>
<SelectItem value='platform'>
{t('Built-in Device')}
</SelectItem>
<SelectItem value='cross-platform'>
{t('External Device')}
</SelectItem>
<SelectContent alignItemWithTrigger={false}>
<SelectGroup>
<SelectItem value='none'>{t('Unlimited')}</SelectItem>
<SelectItem value='platform'>
{t('Built-in Device')}
</SelectItem>
<SelectItem value='cross-platform'>
{t('External Device')}
</SelectItem>
</SelectGroup>
</SelectContent>
</Select>
</FormControl>
@@ -39,6 +39,7 @@ import { Input } from '@/components/ui/input'
import {
Select,
SelectContent,
SelectGroup,
SelectItem,
SelectTrigger,
SelectValue,
@@ -513,7 +514,23 @@ export function AnnouncementsSection({
render={({ field }) => (
<FormItem>
<FormLabel>{t('Type')}</FormLabel>
<Select onValueChange={field.onChange} value={field.value}>
<Select
items={[
...typeOptions.map((option) => ({
value: option.value,
label: (
<div className='flex items-center gap-2'>
<div
className={`h-3 w-3 rounded-full ${option.color}`}
/>
{option.label}
</div>
),
})),
]}
onValueChange={field.onChange}
value={field.value}
>
<FormControl>
<SelectTrigger>
<SelectValue
@@ -521,17 +538,19 @@ export function AnnouncementsSection({
/>
</SelectTrigger>
</FormControl>
<SelectContent>
{typeOptions.map((option) => (
<SelectItem key={option.value} value={option.value}>
<div className='flex items-center gap-2'>
<div
className={`h-3 w-3 rounded-full ${option.color}`}
/>
{option.label}
</div>
</SelectItem>
))}
<SelectContent alignItemWithTrigger={false}>
<SelectGroup>
{typeOptions.map((option) => (
<SelectItem key={option.value} value={option.value}>
<div className='flex items-center gap-2'>
<div
className={`h-3 w-3 rounded-full ${option.color}`}
/>
{option.label}
</div>
</SelectItem>
))}
</SelectGroup>
</SelectContent>
</Select>
<FormMessage />
@@ -38,6 +38,7 @@ import { Input } from '@/components/ui/input'
import {
Select,
SelectContent,
SelectGroup,
SelectItem,
SelectTrigger,
SelectValue,
@@ -462,23 +463,41 @@ export function ApiInfoSection({ enabled, data }: ApiInfoSectionProps) {
render={({ field }) => (
<FormItem>
<FormLabel>{t('Badge Color')}</FormLabel>
<Select onValueChange={field.onChange} value={field.value}>
<FormControl>
<SelectTrigger>
<SelectValue placeholder={t('Select a color')} />
</SelectTrigger>
</FormControl>
<SelectContent>
{colorOptions.map((option) => (
<SelectItem key={option.value} value={option.value}>
<Select
items={[
...colorOptions.map((option) => ({
value: option.value,
label: (
<div className='flex items-center gap-2'>
<div
className={`h-4 w-4 rounded-full ${option.bgClass}`}
/>
{option.label}
</div>
</SelectItem>
))}
),
})),
]}
onValueChange={field.onChange}
value={field.value}
>
<FormControl>
<SelectTrigger>
<SelectValue placeholder={t('Select a color')} />
</SelectTrigger>
</FormControl>
<SelectContent alignItemWithTrigger={false}>
<SelectGroup>
{colorOptions.map((option) => (
<SelectItem key={option.value} value={option.value}>
<div className='flex items-center gap-2'>
<div
className={`h-4 w-4 rounded-full ${option.bgClass}`}
/>
{option.label}
</div>
</SelectItem>
))}
</SelectGroup>
</SelectContent>
</Select>
<FormDescription>
@@ -17,6 +17,7 @@ import { Input } from '@/components/ui/input'
import {
Select,
SelectContent,
SelectGroup,
SelectItem,
SelectTrigger,
SelectValue,
@@ -129,6 +130,12 @@ export function DashboardSection({ defaultValues }: DashboardSectionProps) {
<FormItem>
<FormLabel>{t('Default time granularity')}</FormLabel>
<Select
items={[
...granularityOptions.map((option) => ({
value: option.value,
label: option.label,
})),
]}
onValueChange={field.onChange}
value={field.value}
disabled={!isEnabled}
@@ -138,12 +145,14 @@ export function DashboardSection({ defaultValues }: DashboardSectionProps) {
<SelectValue placeholder={t('Select granularity')} />
</SelectTrigger>
</FormControl>
<SelectContent>
{granularityOptions.map((option) => (
<SelectItem key={option.value} value={option.value}>
{option.label}
</SelectItem>
))}
<SelectContent alignItemWithTrigger={false}>
<SelectGroup>
{granularityOptions.map((option) => (
<SelectItem key={option.value} value={option.value}>
{option.label}
</SelectItem>
))}
</SelectGroup>
</SelectContent>
</Select>
<FormDescription>
@@ -21,6 +21,7 @@ import { Label } from '@/components/ui/label'
import {
Select,
SelectContent,
SelectGroup,
SelectItem,
SelectTrigger,
SelectValue,
@@ -276,6 +277,9 @@ export function RuleEditorDialog(props: Props) {
{keySources.map((src, idx) => (
<div key={idx} className='flex items-center gap-2'>
<Select
items={[
...KEY_SOURCE_TYPES.map((t) => ({ value: t, label: t })),
]}
value={src.type}
onValueChange={(v) => {
if (v === null) return
@@ -290,12 +294,14 @@ export function RuleEditorDialog(props: Props) {
<SelectTrigger className='w-[160px]'>
<SelectValue />
</SelectTrigger>
<SelectContent>
{KEY_SOURCE_TYPES.map((t) => (
<SelectItem key={t} value={t}>
{t}
</SelectItem>
))}
<SelectContent alignItemWithTrigger={false}>
<SelectGroup>
{KEY_SOURCE_TYPES.map((t) => (
<SelectItem key={t} value={t}>
{t}
</SelectItem>
))}
</SelectGroup>
</SelectContent>
</Select>
<Input
@@ -18,6 +18,7 @@ import { Input } from '@/components/ui/input'
import {
Select,
SelectContent,
SelectGroup,
SelectItem,
SelectTrigger,
SelectValue,
@@ -162,23 +163,34 @@ export function PricingSection({ defaultValues }: PricingSectionProps) {
render={({ field }) => (
<FormItem>
<FormLabel>{t('Display Mode')}</FormLabel>
<Select value={field.value} onValueChange={field.onChange}>
<Select
items={[
{ value: 'USD', label: t('USD') },
{ value: 'CNY', label: t('CNY') },
{ value: 'CUSTOM', label: t('Custom Currency') },
{ value: 'TOKENS', label: t('Tokens Only') },
]}
value={field.value}
onValueChange={field.onChange}
>
<FormControl>
<SelectTrigger>
<SelectValue placeholder={t('Select display mode')} />
</SelectTrigger>
</FormControl>
<SelectContent>
<SelectItem value='USD'>{t('USD')}</SelectItem>
<SelectItem value='CNY'>{t('CNY')}</SelectItem>
<SelectItem value='CUSTOM'>
{t('Custom Currency')}
</SelectItem>
{showTokensOnlyOption && (
<SelectItem value='TOKENS'>
{t('Tokens Only')}
<SelectContent alignItemWithTrigger={false}>
<SelectGroup>
<SelectItem value='USD'>{t('USD')}</SelectItem>
<SelectItem value='CNY'>{t('CNY')}</SelectItem>
<SelectItem value='CUSTOM'>
{t('Custom Currency')}
</SelectItem>
)}
{showTokensOnlyOption && (
<SelectItem value='TOKENS'>
{t('Tokens Only')}
</SelectItem>
)}
</SelectGroup>
</SelectContent>
</Select>
<FormDescription>
@@ -17,6 +17,7 @@ import { Input } from '@/components/ui/input'
import {
Select,
SelectContent,
SelectGroup,
SelectItem,
SelectTrigger,
SelectValue,
@@ -133,19 +134,31 @@ export function SystemInfoSection({ defaultValues }: SystemInfoSectionProps) {
render={({ field }) => (
<FormItem>
<FormLabel>{t('Frontend Theme')}</FormLabel>
<Select onValueChange={field.onChange} value={field.value}>
<Select
items={[
{ value: 'default', label: t('Default (New Frontend)') },
{
value: 'classic',
label: t('Classic (Legacy Frontend)'),
},
]}
onValueChange={field.onChange}
value={field.value}
>
<FormControl>
<SelectTrigger className='w-full'>
<SelectValue />
</SelectTrigger>
</FormControl>
<SelectContent>
<SelectItem value='default'>
{t('Default (New Frontend)')}
</SelectItem>
<SelectItem value='classic'>
{t('Classic (Legacy Frontend)')}
</SelectItem>
<SelectContent alignItemWithTrigger={false}>
<SelectGroup>
<SelectItem value='default'>
{t('Default (New Frontend)')}
</SelectItem>
<SelectItem value='classic'>
{t('Classic (Legacy Frontend)')}
</SelectItem>
</SelectGroup>
</SelectContent>
</Select>
<FormDescription>
@@ -25,6 +25,7 @@ import { Input } from '@/components/ui/input'
import {
Select,
SelectContent,
SelectGroup,
SelectItem,
SelectTrigger,
SelectValue,
@@ -160,15 +161,24 @@ export function CreemProductDialog({
render={({ field }) => (
<FormItem>
<FormLabel>{t('Currency')}</FormLabel>
<Select onValueChange={field.onChange} value={field.value}>
<Select
items={[
{ value: 'USD', label: 'USD ($)' },
{ value: 'EUR', label: 'EUR (€)' },
]}
onValueChange={field.onChange}
value={field.value}
>
<FormControl>
<SelectTrigger>
<SelectValue placeholder={t('Select currency')} />
</SelectTrigger>
</FormControl>
<SelectContent>
<SelectItem value='USD'>USD ($)</SelectItem>
<SelectItem value='EUR'>EUR ()</SelectItem>
<SelectContent alignItemWithTrigger={false}>
<SelectGroup>
<SelectItem value='USD'>USD ($)</SelectItem>
<SelectItem value='EUR'>EUR ()</SelectItem>
</SelectGroup>
</SelectContent>
</Select>
<FormMessage />
@@ -33,6 +33,7 @@ import { Progress } from '@/components/ui/progress'
import {
Select,
SelectContent,
SelectGroup,
SelectItem,
SelectTrigger,
SelectValue,
@@ -508,6 +509,11 @@ export function PerformanceSection(props: Props) {
<FormItem>
<FormLabel>{t('Aggregation bucket')}</FormLabel>
<Select
items={[
{ value: 'minute', label: t('1 minute') },
{ value: '5min', label: t('5 minutes') },
{ value: 'hour', label: t('1 hour') },
]}
value={field.value}
onValueChange={field.onChange}
disabled={!perfMetricsEnabled}
@@ -517,10 +523,12 @@ export function PerformanceSection(props: Props) {
<SelectValue />
</SelectTrigger>
</FormControl>
<SelectContent>
<SelectItem value='minute'>{t('1 minute')}</SelectItem>
<SelectItem value='5min'>{t('5 minutes')}</SelectItem>
<SelectItem value='hour'>{t('1 hour')}</SelectItem>
<SelectContent alignItemWithTrigger={false}>
<SelectGroup>
<SelectItem value='minute'>{t('1 minute')}</SelectItem>
<SelectItem value='5min'>{t('5 minutes')}</SelectItem>
<SelectItem value='hour'>{t('1 hour')}</SelectItem>
</SelectGroup>
</SelectContent>
</Select>
</FormItem>
@@ -605,19 +613,25 @@ export function PerformanceSection(props: Props) {
<div className='grid gap-1.5'>
<Label className='text-xs'>{t('Cleanup Mode')}</Label>
<Select
items={[
{ value: 'by_count', label: t('Retain last N files') },
{ value: 'by_days', label: t('Retain last N days') },
]}
value={logCleanupMode}
onValueChange={(v) => v !== null && setLogCleanupMode(v)}
>
<SelectTrigger className='w-[160px]'>
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectItem value='by_count'>
{t('Retain last N files')}
</SelectItem>
<SelectItem value='by_days'>
{t('Retain last N days')}
</SelectItem>
<SelectContent alignItemWithTrigger={false}>
<SelectGroup>
<SelectItem value='by_count'>
{t('Retain last N files')}
</SelectItem>
<SelectItem value='by_days'>
{t('Retain last N days')}
</SelectItem>
</SelectGroup>
</SelectContent>
</Select>
</div>
@@ -24,6 +24,7 @@ import { Input } from '@/components/ui/input'
import {
Select,
SelectContent,
SelectGroup,
SelectItem,
SelectTrigger,
SelectValue,
@@ -224,18 +225,26 @@ export function ChannelSelectorDialog({
return (
<div className='flex items-center gap-2'>
<Select
items={[
...ENDPOINT_OPTIONS.map((option) => ({
value: option.value,
label: option.label,
})),
]}
value={endpointType}
onValueChange={(v) => v !== null && handleTypeChange(v)}
>
<SelectTrigger className='h-8 w-32'>
<SelectValue />
</SelectTrigger>
<SelectContent>
{ENDPOINT_OPTIONS.map((option) => (
<SelectItem key={option.value} value={option.value}>
{option.label}
</SelectItem>
))}
<SelectContent alignItemWithTrigger={false}>
<SelectGroup>
{ENDPOINT_OPTIONS.map((option) => (
<SelectItem key={option.value} value={option.value}>
{option.label}
</SelectItem>
))}
</SelectGroup>
</SelectContent>
</Select>
{endpointType === 'custom' && (
@@ -18,6 +18,7 @@ import { Input } from '@/components/ui/input'
import {
Select,
SelectContent,
SelectGroup,
SelectItem,
SelectTrigger,
SelectValue,
@@ -176,6 +177,38 @@ function GroupSection(props: GroupSectionProps) {
{props.items.map((rule) => (
<div key={rule._id} className='flex items-center gap-2'>
<Select
items={[
{
value: OP_ADD,
label: (
<StatusBadge
label={t(OP_BADGE_MAP[OP_ADD].label)}
variant={OP_BADGE_MAP[OP_ADD].variant}
copyable={false}
/>
),
},
{
value: OP_REMOVE,
label: (
<StatusBadge
label={t(OP_BADGE_MAP[OP_REMOVE].label)}
variant={OP_BADGE_MAP[OP_REMOVE].variant}
copyable={false}
/>
),
},
{
value: OP_APPEND,
label: (
<StatusBadge
label={t(OP_BADGE_MAP[OP_APPEND].label)}
variant={OP_BADGE_MAP[OP_APPEND].variant}
copyable={false}
/>
),
},
]}
value={rule.op}
onValueChange={(v) =>
v !== null && props.onUpdate(rule._id, 'op', v)
@@ -190,28 +223,30 @@ function GroupSection(props: GroupSectionProps) {
/>
</SelectValue>
</SelectTrigger>
<SelectContent>
<SelectItem value={OP_ADD}>
<StatusBadge
label={t(OP_BADGE_MAP[OP_ADD].label)}
variant={OP_BADGE_MAP[OP_ADD].variant}
copyable={false}
/>
</SelectItem>
<SelectItem value={OP_REMOVE}>
<StatusBadge
label={t(OP_BADGE_MAP[OP_REMOVE].label)}
variant={OP_BADGE_MAP[OP_REMOVE].variant}
copyable={false}
/>
</SelectItem>
<SelectItem value={OP_APPEND}>
<StatusBadge
label={t(OP_BADGE_MAP[OP_APPEND].label)}
variant={OP_BADGE_MAP[OP_APPEND].variant}
copyable={false}
/>
</SelectItem>
<SelectContent alignItemWithTrigger={false}>
<SelectGroup>
<SelectItem value={OP_ADD}>
<StatusBadge
label={t(OP_BADGE_MAP[OP_ADD].label)}
variant={OP_BADGE_MAP[OP_ADD].variant}
copyable={false}
/>
</SelectItem>
<SelectItem value={OP_REMOVE}>
<StatusBadge
label={t(OP_BADGE_MAP[OP_REMOVE].label)}
variant={OP_BADGE_MAP[OP_REMOVE].variant}
copyable={false}
/>
</SelectItem>
<SelectItem value={OP_APPEND}>
<StatusBadge
label={t(OP_BADGE_MAP[OP_APPEND].label)}
variant={OP_BADGE_MAP[OP_APPEND].variant}
copyable={false}
/>
</SelectItem>
</SelectGroup>
</SelectContent>
</Select>
<Input
@@ -27,6 +27,7 @@ import { Label } from '@/components/ui/label'
import {
Select,
SelectContent,
SelectGroup,
SelectItem,
SelectTrigger,
SelectValue,
@@ -415,6 +416,12 @@ function ConditionRow({ condition, onChange, onRemove }: ConditionRowProps) {
return (
<div className='flex items-center gap-2'>
<Select
items={[
...CONDITION_INPUT_OPTIONS.map((option) => ({
value: option.value,
label: t(option.labelKey),
})),
]}
value={condition.var}
onValueChange={(value) =>
onChange({ ...condition, var: value as TierConditionInput['var'] })
@@ -427,15 +434,18 @@ function ConditionRow({ condition, onChange, onRemove }: ConditionRowProps) {
: condition.var}
</SelectValue>
</SelectTrigger>
<SelectContent>
{CONDITION_INPUT_OPTIONS.map((option) => (
<SelectItem key={option.value} value={option.value}>
{t(option.labelKey)}
</SelectItem>
))}
<SelectContent alignItemWithTrigger={false}>
<SelectGroup>
{CONDITION_INPUT_OPTIONS.map((option) => (
<SelectItem key={option.value} value={option.value}>
{t(option.labelKey)}
</SelectItem>
))}
</SelectGroup>
</SelectContent>
</Select>
<Select
items={[...OPS.map((op) => ({ value: op, label: op }))]}
value={condition.op}
onValueChange={(value) =>
onChange({ ...condition, op: value as TierConditionInput['op'] })
@@ -444,12 +454,14 @@ function ConditionRow({ condition, onChange, onRemove }: ConditionRowProps) {
<SelectTrigger className='w-20' size='sm'>
<SelectValue />
</SelectTrigger>
<SelectContent>
{OPS.map((op) => (
<SelectItem key={op} value={op}>
{op}
</SelectItem>
))}
<SelectContent alignItemWithTrigger={false}>
<SelectGroup>
{OPS.map((op) => (
<SelectItem key={op} value={op}>
{op}
</SelectItem>
))}
</SelectGroup>
</SelectContent>
</Select>
<DraftNumberInput
@@ -960,6 +972,12 @@ function RuleConditionRow({
const renderTimeCondition = (timeCond: TimeCondition) => (
<>
<Select
items={[
...TIME_FUNCS.map((fn) => ({
value: fn,
label: getTimeFuncLabel(fn),
})),
]}
value={timeCond.timeFunc}
onValueChange={(value) =>
onChange({ ...timeCond, timeFunc: value as TimeFunc })
@@ -968,15 +986,23 @@ function RuleConditionRow({
<SelectTrigger className='w-32' size='sm'>
<SelectValue>{getTimeFuncLabel(timeCond.timeFunc)}</SelectValue>
</SelectTrigger>
<SelectContent>
{TIME_FUNCS.map((fn) => (
<SelectItem key={fn} value={fn}>
{getTimeFuncLabel(fn)}
</SelectItem>
))}
<SelectContent alignItemWithTrigger={false}>
<SelectGroup>
{TIME_FUNCS.map((fn) => (
<SelectItem key={fn} value={fn}>
{getTimeFuncLabel(fn)}
</SelectItem>
))}
</SelectGroup>
</SelectContent>
</Select>
<Select
items={[
...COMMON_TIMEZONES.map((tz) => ({
value: tz.value,
label: tz.label,
})),
]}
value={timeCond.timezone}
onValueChange={(value) =>
value !== null && onChange({ ...timeCond, timezone: value })
@@ -988,27 +1014,37 @@ function RuleConditionRow({
?.label ?? timeCond.timezone}
</SelectValue>
</SelectTrigger>
<SelectContent>
{COMMON_TIMEZONES.map((tz) => (
<SelectItem key={tz.value} value={tz.value}>
{tz.label}
</SelectItem>
))}
<SelectContent alignItemWithTrigger={false}>
<SelectGroup>
{COMMON_TIMEZONES.map((tz) => (
<SelectItem key={tz.value} value={tz.value}>
{tz.label}
</SelectItem>
))}
</SelectGroup>
</SelectContent>
</Select>
<Select
items={[
...matchOptions.map((option) => ({
value: option.value,
label: getMatchLabel(option.value),
})),
]}
value={timeCond.mode}
onValueChange={(v) => v !== null && handleModeChange(v)}
>
<SelectTrigger className='w-32' size='sm'>
<SelectValue>{getMatchLabel(timeCond.mode)}</SelectValue>
</SelectTrigger>
<SelectContent>
{matchOptions.map((option) => (
<SelectItem key={option.value} value={option.value}>
{getMatchLabel(option.value)}
</SelectItem>
))}
<SelectContent alignItemWithTrigger={false}>
<SelectGroup>
{matchOptions.map((option) => (
<SelectItem key={option.value} value={option.value}>
{getMatchLabel(option.value)}
</SelectItem>
))}
</SelectGroup>
</SelectContent>
</Select>
{timeCond.mode === MATCH_RANGE ? (
@@ -1055,18 +1091,26 @@ function RuleConditionRow({
className='w-44'
/>
<Select
items={[
...matchOptions.map((option) => ({
value: option.value,
label: getMatchLabel(option.value),
})),
]}
value={phCond.mode}
onValueChange={(v) => v !== null && handleModeChange(v)}
>
<SelectTrigger className='w-32' size='sm'>
<SelectValue>{getMatchLabel(phCond.mode)}</SelectValue>
</SelectTrigger>
<SelectContent>
{matchOptions.map((option) => (
<SelectItem key={option.value} value={option.value}>
{getMatchLabel(option.value)}
</SelectItem>
))}
<SelectContent alignItemWithTrigger={false}>
<SelectGroup>
{matchOptions.map((option) => (
<SelectItem key={option.value} value={option.value}>
{getMatchLabel(option.value)}
</SelectItem>
))}
</SelectGroup>
</SelectContent>
</Select>
{phCond.mode !== MATCH_EXISTS && (
@@ -1085,16 +1129,23 @@ function RuleConditionRow({
return (
<div className='flex flex-wrap items-center gap-2'>
<Select
items={[
{ value: SOURCE_PARAM, label: t('Body param') },
{ value: SOURCE_HEADER, label: t('Header') },
{ value: SOURCE_TIME, label: t('Time') },
]}
value={condition.source}
onValueChange={(v) => v !== null && handleSourceChange(v)}
>
<SelectTrigger className='w-28' size='sm'>
<SelectValue>{sourceLabel}</SelectValue>
</SelectTrigger>
<SelectContent>
<SelectItem value={SOURCE_PARAM}>{t('Body param')}</SelectItem>
<SelectItem value={SOURCE_HEADER}>{t('Header')}</SelectItem>
<SelectItem value={SOURCE_TIME}>{t('Time')}</SelectItem>
<SelectContent alignItemWithTrigger={false}>
<SelectGroup>
<SelectItem value={SOURCE_PARAM}>{t('Body param')}</SelectItem>
<SelectItem value={SOURCE_HEADER}>{t('Header')}</SelectItem>
<SelectItem value={SOURCE_TIME}>{t('Time')}</SelectItem>
</SelectGroup>
</SelectContent>
</Select>
{condition.source === SOURCE_TIME
@@ -1705,15 +1756,21 @@ export const TieredPricingEditor = memo(function TieredPricingEditor({
<div className='flex items-center justify-between gap-2'>
<Label className='text-xs'>{t('Editor mode')}</Label>
<Select
items={[
{ value: 'visual', label: t('Visual editor') },
{ value: 'raw', label: t('Expression editor') },
]}
value={editorMode}
onValueChange={(value) => handleModeChange(value as EditorMode)}
>
<SelectTrigger className='w-44' size='sm'>
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectItem value='visual'>{t('Visual editor')}</SelectItem>
<SelectItem value='raw'>{t('Expression editor')}</SelectItem>
<SelectContent alignItemWithTrigger={false}>
<SelectGroup>
<SelectItem value='visual'>{t('Visual editor')}</SelectItem>
<SelectItem value='raw'>{t('Expression editor')}</SelectItem>
</SelectGroup>
</SelectContent>
</Select>
</div>
@@ -11,6 +11,7 @@ import { Input } from '@/components/ui/input'
import {
Select,
SelectContent,
SelectGroup,
SelectItem,
SelectTrigger,
SelectValue,
@@ -212,6 +213,13 @@ export function UpstreamRatioSyncTable({
/>
</div>
<Select
items={[
{ value: '__all__', label: t('All Types') },
...RATIO_TYPE_OPTIONS.map((option) => ({
value: option.value,
label: t(option.label),
})),
]}
value={ratioTypeFilter}
onValueChange={(v) => v !== null && setRatioTypeFilter(v)}
disabled={isDisabled}
@@ -219,13 +227,15 @@ export function UpstreamRatioSyncTable({
<SelectTrigger className='w-full sm:w-56'>
<SelectValue placeholder={t('Filter by price field')} />
</SelectTrigger>
<SelectContent>
<SelectItem value='__all__'>{t('All Types')}</SelectItem>
{RATIO_TYPE_OPTIONS.map((option) => (
<SelectItem key={option.value} value={option.value}>
{t(option.label)}
</SelectItem>
))}
<SelectContent alignItemWithTrigger={false}>
<SelectGroup>
<SelectItem value='__all__'>{t('All Types')}</SelectItem>
{RATIO_TYPE_OPTIONS.map((option) => (
<SelectItem key={option.value} value={option.value}>
{t(option.label)}
</SelectItem>
))}
</SelectGroup>
</SelectContent>
</Select>
</div>
@@ -18,6 +18,7 @@ import { Input } from '@/components/ui/input'
import {
Select,
SelectContent,
SelectGroup,
SelectItem,
SelectTrigger,
SelectValue,
@@ -242,6 +243,16 @@ export function SSRFSection({ defaultValues }: SSRFSectionProps) {
<FormItem>
<FormLabel>{t('Domain Filter Mode')}</FormLabel>
<Select
items={[
{
value: 'false',
label: t('Blacklist (Block listed domains)'),
},
{
value: 'true',
label: t('Whitelist (Only allow listed domains)'),
},
]}
onValueChange={(value) => field.onChange(value === 'true')}
value={field.value ? 'true' : 'false'}
>
@@ -250,13 +261,15 @@ export function SSRFSection({ defaultValues }: SSRFSectionProps) {
<SelectValue />
</SelectTrigger>
</FormControl>
<SelectContent>
<SelectItem value='false'>
{t('Blacklist (Block listed domains)')}
</SelectItem>
<SelectItem value='true'>
{t('Whitelist (Only allow listed domains)')}
</SelectItem>
<SelectContent alignItemWithTrigger={false}>
<SelectGroup>
<SelectItem value='false'>
{t('Blacklist (Block listed domains)')}
</SelectItem>
<SelectItem value='true'>
{t('Whitelist (Only allow listed domains)')}
</SelectItem>
</SelectGroup>
</SelectContent>
</Select>
<FormDescription>
@@ -295,6 +308,16 @@ export function SSRFSection({ defaultValues }: SSRFSectionProps) {
<FormItem>
<FormLabel>{t('IP Filter Mode')}</FormLabel>
<Select
items={[
{
value: 'false',
label: t('Blacklist (Block listed IPs)'),
},
{
value: 'true',
label: t('Whitelist (Only allow listed IPs)'),
},
]}
onValueChange={(value) => field.onChange(value === 'true')}
value={field.value ? 'true' : 'false'}
>
@@ -303,13 +326,15 @@ export function SSRFSection({ defaultValues }: SSRFSectionProps) {
<SelectValue />
</SelectTrigger>
</FormControl>
<SelectContent>
<SelectItem value='false'>
{t('Blacklist (Block listed IPs)')}
</SelectItem>
<SelectItem value='true'>
{t('Whitelist (Only allow listed IPs)')}
</SelectItem>
<SelectContent alignItemWithTrigger={false}>
<SelectGroup>
<SelectItem value='false'>
{t('Blacklist (Block listed IPs)')}
</SelectItem>
<SelectItem value='true'>
{t('Whitelist (Only allow listed IPs)')}
</SelectItem>
</SelectGroup>
</SelectContent>
</Select>
<FormDescription>