fix(web/default): batch fix new UI issues #4880 #4893 #4817 #4877 #4898

- Add singleSelect to status/role filters in API keys, users, and redemptions tables (#4880)
- Fix affiliate link 404 by changing /register to /sign-up (#4893)
- Open FetchModelsDialog in channel creation mode via customFetcher prop (#4817)
- Add TruncatedText component with tooltip for long channel names, token names, and usernames (#4877)
- Elevate forgot-password link z-index to prevent label click interception (#4898)
This commit is contained in:
CaIon
2026-05-16 14:48:49 +08:00
parent 18282e610d
commit 3caa6e467b
10 changed files with 158 additions and 86 deletions
@@ -301,7 +301,6 @@ export function ChannelMutateDrawer({
const { setOpen } = useChannels()
const [isSubmitting, setIsSubmitting] = useState(false)
const [customModel, setCustomModel] = useState('')
const [isFetchingModels, setIsFetchingModels] = useState(false)
const [fetchModelsDialogOpen, setFetchModelsDialogOpen] = useState(false)
const [channelKey, setChannelKey] = useState<string | null>(null)
const [isChannelKeyLoading, setIsChannelKeyLoading] = useState(false)
@@ -767,43 +766,29 @@ export function ChannelMutateDrawer({
return
}
// For editing mode, open FetchModelsDialog to let user select
if (isEditing && currentRow) {
setFetchModelsDialogOpen(true)
return
}
// For creation mode, fetch and fill all models
const key = form.getValues('key')
if (!key?.trim()) {
toast.error(t('Please enter API key first'))
return
}
setIsFetchingModels(true)
try {
const response = await fetchModels({
type,
key,
base_url: form.getValues('base_url') || '',
})
if (response.success && response.data) {
updateModels(response.data, true)
toast.success(
t('Fetched {{count}} model(s) from upstream', {
count: response.data.length,
})
)
} else {
toast.error(t('No models fetched from upstream'))
// For creation mode, validate key before opening dialog
if (!isEditing) {
const key = form.getValues('key')
if (!key?.trim()) {
toast.error(t('Please enter API key first'))
return
}
} catch (error: unknown) {
toast.error(getErrorMessage(error) || t('Failed to fetch models'))
} finally {
setIsFetchingModels(false)
}
}, [isEditing, currentRow, form, t, updateModels])
setFetchModelsDialogOpen(true)
}, [isEditing, form, t])
const createModeFetcher = useCallback(async (): Promise<string[]> => {
const response = await fetchModels({
type: form.getValues('type'),
key: form.getValues('key'),
base_url: form.getValues('base_url') || '',
})
if (response.success && response.data) {
return response.data
}
throw new Error(response.message || 'No models fetched from upstream')
}, [form])
// Handle adding custom models
const handleAddCustomModels = useCallback(() => {
@@ -2234,13 +2219,8 @@ export function ChannelMutateDrawer({
variant='outline'
size='sm'
onClick={handleFetchModels}
disabled={isFetchingModels}
>
{isFetchingModels ? (
<Loader2 className='mr-2 h-4 w-4 animate-spin' />
) : (
<Sparkles className='mr-2 h-4 w-4' />
)}
<Sparkles className='mr-2 h-4 w-4' />
{t('Fetch from Upstream')}
</Button>
)}
@@ -3390,19 +3370,20 @@ export function ChannelMutateDrawer({
/>
)}
{/* Fetch Models Dialog (for editing mode) */}
{isEditing && currentRow && (
<FetchModelsDialog
open={fetchModelsDialogOpen}
onOpenChange={setFetchModelsDialogOpen}
onModelsSelected={(models) => {
// Fill selected models to form
form.setValue('models', formatModelsArray(models))
}}
redirectModels={redirectModelList}
redirectSourceModels={redirectModelKeyList}
/>
)}
{/* Fetch Models Dialog */}
<FetchModelsDialog
open={fetchModelsDialogOpen}
onOpenChange={setFetchModelsDialogOpen}
onModelsSelected={(models) => {
form.setValue('models', formatModelsArray(models))
}}
redirectModels={redirectModelList}
redirectSourceModels={redirectModelKeyList}
customFetcher={!isEditing ? createModeFetcher : undefined}
existingModelsOverride={
!isEditing ? parseModelsString(form.getValues('models') || '') : undefined
}
/>
<SecureVerificationDialog
open={verificationOpen}