mirror of
https://github.com/langbot-app/LangBot.git
synced 2026-06-21 04:54:21 +00:00
style(web): move adapter doc link to icon button beside selector with tooltip
This commit is contained in:
@@ -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>
|
||||||
)}
|
)}
|
||||||
|
|||||||
Reference in New Issue
Block a user