style(web): move adapter doc link to icon button beside selector with tooltip

This commit is contained in:
Junyan Qin
2026-03-31 00:06:15 +08:00
parent 44b8354dfd
commit 1b1cc7769b
@@ -15,8 +15,13 @@ import DynamicFormComponent from '@/app/home/components/dynamic-form/DynamicForm
import { httpClient } from '@/app/infra/http/HttpClient'; import { httpClient } from '@/app/infra/http/HttpClient';
import { Bot } from '@/app/infra/entities/api'; import { Bot } from '@/app/infra/entities/api';
import { getAdapterDocUrl } from '@/app/infra/entities/adapter-docs'; import { getAdapterDocUrl } from '@/app/infra/entities/adapter-docs';
import { ExternalLink } from 'lucide-react'; import { FileText } from 'lucide-react';
import { Button } from '@/components/ui/button'; import { Button } from '@/components/ui/button';
import {
Tooltip,
TooltipContent,
TooltipTrigger,
} from '@/components/ui/tooltip';
import { zodResolver } from '@hookform/resolvers/zod'; import { zodResolver } from '@hookform/resolvers/zod';
import { useForm } from 'react-hook-form'; import { useForm } from 'react-hook-form';
@@ -473,89 +478,99 @@ export default function BotForm({
<span className="text-destructive">*</span> <span className="text-destructive">*</span>
</FormLabel> </FormLabel>
<FormControl> <FormControl>
<Select <div className="flex items-center gap-2">
onValueChange={(value) => { <Select
field.onChange(value); onValueChange={(value) => {
handleAdapterSelect(value); field.onChange(value);
}} handleAdapterSelect(value);
value={field.value} }}
> value={field.value}
<SelectTrigger className="w-[240px]"> >
{field.value ? ( <SelectTrigger className="w-[240px]">
<div className="flex items-center gap-2"> {field.value ? (
<img <div className="flex items-center gap-2">
src={httpClient.getAdapterIconURL(field.value)} <img
alt="" src={httpClient.getAdapterIconURL(field.value)}
className="h-5 w-5 rounded" alt=""
className="h-5 w-5 rounded"
/>
<span>
{adapterNameList.find(
(a) => a.value === field.value,
)?.label ?? field.value}
</span>
</div>
) : (
<SelectValue
placeholder={t('bots.selectAdapter')}
/> />
<span> )}
{adapterNameList.find( </SelectTrigger>
(a) => a.value === field.value, <SelectContent>
)?.label ?? field.value} {groupedAdapters.map((group) => (
</span> <SelectGroup
</div> key={group.categoryId ?? 'uncategorized'}
) : ( >
<SelectValue placeholder={t('bots.selectAdapter')} /> {group.categoryId && (
)} <SelectLabel>
</SelectTrigger> {getCategoryLabel(t, group.categoryId)}
<SelectContent> </SelectLabel>
{groupedAdapters.map((group) => ( )}
<SelectGroup {group.items.map((item) => (
key={group.categoryId ?? 'uncategorized'} <SelectItem key={item.value} value={item.value}>
> <div className="flex items-center gap-2">
{group.categoryId && ( <img
<SelectLabel> src={httpClient.getAdapterIconURL(
{getCategoryLabel(t, group.categoryId)} item.value,
</SelectLabel> )}
)} alt=""
{group.items.map((item) => ( className="h-5 w-5 rounded"
<SelectItem key={item.value} value={item.value}> />
<div className="flex items-center gap-2"> <span>{item.label}</span>
<img </div>
src={httpClient.getAdapterIconURL( </SelectItem>
item.value, ))}
)} </SelectGroup>
alt="" ))}
className="h-5 w-5 rounded" </SelectContent>
/> </Select>
<span>{item.label}</span> {currentAdapter &&
</div> (() => {
</SelectItem> const docUrl = getAdapterDocUrl(
))} currentAdapter,
</SelectGroup> i18n.language,
))} );
</SelectContent> return docUrl ? (
</Select> <Tooltip>
<TooltipTrigger asChild>
<Button
variant="outline"
size="icon"
className="h-9 w-9 shrink-0"
asChild
>
<a
href={docUrl}
target="_blank"
rel="noopener noreferrer"
>
<FileText className="h-4 w-4" />
</a>
</Button>
</TooltipTrigger>
<TooltipContent>
{t('bots.viewAdapterDocs')}
</TooltipContent>
</Tooltip>
) : null;
})()}
</div>
</FormControl> </FormControl>
{currentAdapter && adapterDescriptionList[currentAdapter] && ( {currentAdapter && adapterDescriptionList[currentAdapter] && (
<FormDescription> <FormDescription>
{adapterDescriptionList[currentAdapter]} {adapterDescriptionList[currentAdapter]}
</FormDescription> </FormDescription>
)} )}
{currentAdapter &&
(() => {
const docUrl = getAdapterDocUrl(
currentAdapter,
i18n.language,
);
return docUrl ? (
<Button
variant="link"
size="sm"
className="h-auto p-0 text-xs"
asChild
>
<a
href={docUrl}
target="_blank"
rel="noopener noreferrer"
>
<ExternalLink className="mr-1 h-3 w-3" />
{t('bots.viewAdapterDocs')}
</a>
</Button>
) : null;
})()}
<FormMessage /> <FormMessage />
</FormItem> </FormItem>
)} )}