mirror of
https://github.com/langbot-app/LangBot.git
synced 2026-06-12 16:56:02 +00:00
fix(web): prevent plugin config form overflow
This commit is contained in:
@@ -126,13 +126,13 @@ function WebhookUrlField({
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<FormItem>
|
<FormItem className="min-w-0">
|
||||||
<FormLabel>{label}</FormLabel>
|
<FormLabel className="break-words">{label}</FormLabel>
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex min-w-0 items-center gap-2">
|
||||||
<Input
|
<Input
|
||||||
value={url}
|
value={url}
|
||||||
readOnly
|
readOnly
|
||||||
className="flex-1 bg-muted"
|
className="min-w-0 flex-1 bg-muted"
|
||||||
onClick={(e) => (e.target as HTMLInputElement).select()}
|
onClick={(e) => (e.target as HTMLInputElement).select()}
|
||||||
/>
|
/>
|
||||||
<Button
|
<Button
|
||||||
@@ -149,11 +149,11 @@ function WebhookUrlField({
|
|||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
{extraUrl && (
|
{extraUrl && (
|
||||||
<div className="flex items-center gap-2 mt-2">
|
<div className="mt-2 flex min-w-0 items-center gap-2">
|
||||||
<Input
|
<Input
|
||||||
value={extraUrl}
|
value={extraUrl}
|
||||||
readOnly
|
readOnly
|
||||||
className="flex-1 bg-muted"
|
className="min-w-0 flex-1 bg-muted"
|
||||||
onClick={(e) => (e.target as HTMLInputElement).select()}
|
onClick={(e) => (e.target as HTMLInputElement).select()}
|
||||||
/>
|
/>
|
||||||
<Button
|
<Button
|
||||||
@@ -171,12 +171,14 @@ function WebhookUrlField({
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{description && (
|
{description && (
|
||||||
<p className="text-sm text-muted-foreground">{description}</p>
|
<p className="text-sm break-words text-muted-foreground">
|
||||||
|
{description}
|
||||||
|
</p>
|
||||||
)}
|
)}
|
||||||
{systemInfo.edition === 'community' && (
|
{systemInfo.edition === 'community' && (
|
||||||
<div className="flex items-start gap-2.5 rounded-md border border-border/60 bg-muted/40 px-3 py-2.5 mt-1 max-w-2xl">
|
<div className="mt-1 flex max-w-full min-w-0 items-start gap-2.5 rounded-md border border-border/60 bg-muted/40 px-3 py-2.5">
|
||||||
<Globe className="h-4 w-4 text-muted-foreground shrink-0 mt-0.5" />
|
<Globe className="h-4 w-4 text-muted-foreground shrink-0 mt-0.5" />
|
||||||
<p className="text-sm text-muted-foreground leading-relaxed">
|
<p className="text-sm leading-relaxed break-words text-muted-foreground">
|
||||||
{t('bots.webhookSaasHint')}{' '}
|
{t('bots.webhookSaasHint')}{' '}
|
||||||
<a
|
<a
|
||||||
href="https://space.langbot.app/cloud?utm_source=local_webui&utm_medium=webhook_alert&utm_campaign=saas_conversion"
|
href="https://space.langbot.app/cloud?utm_source=local_webui&utm_medium=webhook_alert&utm_campaign=saas_conversion"
|
||||||
@@ -442,7 +444,7 @@ export default function DynamicFormComponent({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Form {...form}>
|
<Form {...form}>
|
||||||
<div className="space-y-4">
|
<div className="min-w-0 max-w-full space-y-4 overflow-x-hidden">
|
||||||
{itemConfigList.map((config) => {
|
{itemConfigList.map((config) => {
|
||||||
if (config.show_if) {
|
if (config.show_if) {
|
||||||
const dependValue = resolveShowIfValue(
|
const dependValue = resolveShowIfValue(
|
||||||
@@ -582,20 +584,20 @@ export default function DynamicFormComponent({
|
|||||||
control={form.control}
|
control={form.control}
|
||||||
name={config.name as keyof FormValues}
|
name={config.name as keyof FormValues}
|
||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<FormItem>
|
<FormItem className="min-w-0">
|
||||||
<div
|
<div
|
||||||
className={cn(
|
className={cn(
|
||||||
'flex flex-row items-center justify-between rounded-lg border p-4 max-w-2xl',
|
'flex w-full min-w-0 max-w-full flex-row items-center justify-between rounded-lg border p-4',
|
||||||
isFieldDisabled && 'pointer-events-none opacity-60',
|
isFieldDisabled && 'pointer-events-none opacity-60',
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<div className="space-y-0.5">
|
<div className="min-w-0 space-y-0.5">
|
||||||
<FormLabel className="text-base flex items-center gap-1.5">
|
<FormLabel className="flex min-w-0 items-center gap-1.5 text-base">
|
||||||
{extractI18nObject(config.label)}
|
{extractI18nObject(config.label)}
|
||||||
{renderDisabledTooltipIcon()}
|
{renderDisabledTooltipIcon()}
|
||||||
</FormLabel>
|
</FormLabel>
|
||||||
{config.description && (
|
{config.description && (
|
||||||
<p className="text-sm text-muted-foreground">
|
<p className="text-sm break-words text-muted-foreground">
|
||||||
{extractI18nObject(config.description)}
|
{extractI18nObject(config.description)}
|
||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
@@ -621,9 +623,9 @@ export default function DynamicFormComponent({
|
|||||||
control={form.control}
|
control={form.control}
|
||||||
name={config.name as keyof FormValues}
|
name={config.name as keyof FormValues}
|
||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<FormItem>
|
<FormItem className="min-w-0">
|
||||||
<FormLabel className="flex items-center gap-1.5">
|
<FormLabel className="flex min-w-0 items-center gap-1.5">
|
||||||
<span>
|
<span className="min-w-0 break-words">
|
||||||
{extractI18nObject(config.label)}{' '}
|
{extractI18nObject(config.label)}{' '}
|
||||||
{config.required && (
|
{config.required && (
|
||||||
<span className="text-red-500">*</span>
|
<span className="text-red-500">*</span>
|
||||||
@@ -633,9 +635,10 @@ export default function DynamicFormComponent({
|
|||||||
</FormLabel>
|
</FormLabel>
|
||||||
<FormControl>
|
<FormControl>
|
||||||
<div
|
<div
|
||||||
className={
|
className={cn(
|
||||||
isFieldDisabled ? 'pointer-events-none opacity-60' : ''
|
'min-w-0 max-w-full overflow-x-hidden',
|
||||||
}
|
isFieldDisabled && 'pointer-events-none opacity-60',
|
||||||
|
)}
|
||||||
>
|
>
|
||||||
<DynamicFormItemComponent
|
<DynamicFormItemComponent
|
||||||
config={config}
|
config={config}
|
||||||
@@ -645,7 +648,7 @@ export default function DynamicFormComponent({
|
|||||||
</div>
|
</div>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
{config.description && (
|
{config.description && (
|
||||||
<p className="text-sm text-muted-foreground">
|
<p className="text-sm break-words text-muted-foreground">
|
||||||
{extractI18nObject(config.description)}
|
{extractI18nObject(config.description)}
|
||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -69,7 +69,6 @@ export default function DynamicFormItemComponent({
|
|||||||
onFileUploaded,
|
onFileUploaded,
|
||||||
}: {
|
}: {
|
||||||
config: IDynamicFormItemSchema;
|
config: IDynamicFormItemSchema;
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
||||||
field: ControllerRenderProps<any, any>;
|
field: ControllerRenderProps<any, any>;
|
||||||
onFileUploaded?: (fileKey: string) => void;
|
onFileUploaded?: (fileKey: string) => void;
|
||||||
}) {
|
}) {
|
||||||
@@ -251,7 +250,7 @@ export default function DynamicFormItemComponent({
|
|||||||
return (
|
return (
|
||||||
<Input
|
<Input
|
||||||
type="number"
|
type="number"
|
||||||
className="max-w-xs"
|
className="w-full max-w-xs"
|
||||||
{...field}
|
{...field}
|
||||||
onChange={(e) => field.onChange(Number(e.target.value))}
|
onChange={(e) => field.onChange(Number(e.target.value))}
|
||||||
/>
|
/>
|
||||||
@@ -260,8 +259,8 @@ export default function DynamicFormItemComponent({
|
|||||||
case DynamicFormItemType.STRING:
|
case DynamicFormItemType.STRING:
|
||||||
if (config.options && config.options.length > 0) {
|
if (config.options && config.options.length > 0) {
|
||||||
return (
|
return (
|
||||||
<div className="flex items-center gap-1.5 max-w-md">
|
<div className="flex w-full max-w-md min-w-0 items-center gap-1.5">
|
||||||
<Input className="flex-1" {...field} />
|
<Input className="min-w-0 flex-1" {...field} />
|
||||||
<DropdownMenu>
|
<DropdownMenu>
|
||||||
<DropdownMenuTrigger asChild>
|
<DropdownMenuTrigger asChild>
|
||||||
<Button
|
<Button
|
||||||
@@ -292,21 +291,26 @@ export default function DynamicFormItemComponent({
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return <Input className="max-w-md" {...field} />;
|
return <Input className="w-full max-w-md" {...field} />;
|
||||||
|
|
||||||
case DynamicFormItemType.TEXT:
|
case DynamicFormItemType.TEXT:
|
||||||
return <Textarea {...field} className="min-h-[120px] max-w-2xl" />;
|
return (
|
||||||
|
<Textarea
|
||||||
|
{...field}
|
||||||
|
className="min-h-[120px] w-full max-w-full resize-y overflow-x-hidden break-all"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
case DynamicFormItemType.BOOLEAN:
|
case DynamicFormItemType.BOOLEAN:
|
||||||
return <Switch checked={field.value} onCheckedChange={field.onChange} />;
|
return <Switch checked={field.value} onCheckedChange={field.onChange} />;
|
||||||
|
|
||||||
case DynamicFormItemType.STRING_ARRAY:
|
case DynamicFormItemType.STRING_ARRAY:
|
||||||
return (
|
return (
|
||||||
<div className="space-y-2 max-w-md">
|
<div className="w-full max-w-md min-w-0 space-y-2">
|
||||||
{field.value.map((item: string, index: number) => (
|
{field.value.map((item: string, index: number) => (
|
||||||
<div key={index} className="flex gap-1.5 items-center">
|
<div key={index} className="flex min-w-0 items-center gap-1.5">
|
||||||
<Input
|
<Input
|
||||||
className="flex-1"
|
className="min-w-0 flex-1"
|
||||||
value={item}
|
value={item}
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
const newValue = [...field.value];
|
const newValue = [...field.value];
|
||||||
@@ -347,7 +351,7 @@ export default function DynamicFormItemComponent({
|
|||||||
case DynamicFormItemType.SELECT:
|
case DynamicFormItemType.SELECT:
|
||||||
return (
|
return (
|
||||||
<Select value={field.value} onValueChange={field.onChange}>
|
<Select value={field.value} onValueChange={field.onChange}>
|
||||||
<SelectTrigger className="max-w-md bg-[#ffffff] dark:bg-[#2a2a2e]">
|
<SelectTrigger className="w-full max-w-md bg-[#ffffff] dark:bg-[#2a2a2e]">
|
||||||
<SelectValue placeholder={t('common.select')} />
|
<SelectValue placeholder={t('common.select')} />
|
||||||
</SelectTrigger>
|
</SelectTrigger>
|
||||||
<SelectContent>
|
<SelectContent>
|
||||||
@@ -409,10 +413,10 @@ export default function DynamicFormItemComponent({
|
|||||||
];
|
];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="max-w-md flex items-center gap-1.5">
|
<div className="flex w-full max-w-md min-w-0 items-center gap-1.5">
|
||||||
<div className="flex-1">
|
<div className="min-w-0 flex-1">
|
||||||
<Select value={field.value} onValueChange={field.onChange}>
|
<Select value={field.value} onValueChange={field.onChange}>
|
||||||
<SelectTrigger className="bg-[#ffffff] dark:bg-[#2a2a2e]">
|
<SelectTrigger className="min-w-0 bg-[#ffffff] dark:bg-[#2a2a2e]">
|
||||||
<SelectValue placeholder={t('models.selectModel')} />
|
<SelectValue placeholder={t('models.selectModel')} />
|
||||||
</SelectTrigger>
|
</SelectTrigger>
|
||||||
<SelectContent>
|
<SelectContent>
|
||||||
@@ -577,9 +581,9 @@ export default function DynamicFormItemComponent({
|
|||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="max-w-md">
|
<div className="w-full max-w-md min-w-0">
|
||||||
<Select value={field.value} onValueChange={field.onChange}>
|
<Select value={field.value} onValueChange={field.onChange}>
|
||||||
<SelectTrigger className="bg-[#ffffff] dark:bg-[#2a2a2e]">
|
<SelectTrigger className="min-w-0 bg-[#ffffff] dark:bg-[#2a2a2e]">
|
||||||
<SelectValue placeholder={t('knowledge.selectEmbeddingModel')} />
|
<SelectValue placeholder={t('knowledge.selectEmbeddingModel')} />
|
||||||
</SelectTrigger>
|
</SelectTrigger>
|
||||||
<SelectContent>
|
<SelectContent>
|
||||||
@@ -612,12 +616,12 @@ export default function DynamicFormItemComponent({
|
|||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="max-w-md">
|
<div className="w-full max-w-md min-w-0">
|
||||||
<Select
|
<Select
|
||||||
value={field.value || '__none__'}
|
value={field.value || '__none__'}
|
||||||
onValueChange={(v) => field.onChange(v === '__none__' ? '' : v)}
|
onValueChange={(v) => field.onChange(v === '__none__' ? '' : v)}
|
||||||
>
|
>
|
||||||
<SelectTrigger className="bg-[#ffffff] dark:bg-[#2a2a2e]">
|
<SelectTrigger className="min-w-0 bg-[#ffffff] dark:bg-[#2a2a2e]">
|
||||||
<SelectValue placeholder={t('models.rerank')} />
|
<SelectValue placeholder={t('models.rerank')} />
|
||||||
</SelectTrigger>
|
</SelectTrigger>
|
||||||
<SelectContent>
|
<SelectContent>
|
||||||
@@ -713,7 +717,7 @@ export default function DynamicFormItemComponent({
|
|||||||
placeholder: string,
|
placeholder: string,
|
||||||
) => (
|
) => (
|
||||||
<Select value={value} onValueChange={onChange}>
|
<Select value={value} onValueChange={onChange}>
|
||||||
<SelectTrigger className="bg-[#ffffff] dark:bg-[#2a2a2e]">
|
<SelectTrigger className="min-w-0 bg-[#ffffff] dark:bg-[#2a2a2e]">
|
||||||
<SelectValue placeholder={placeholder} />
|
<SelectValue placeholder={placeholder} />
|
||||||
</SelectTrigger>
|
</SelectTrigger>
|
||||||
<SelectContent>
|
<SelectContent>
|
||||||
@@ -879,14 +883,14 @@ export default function DynamicFormItemComponent({
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="space-y-3">
|
<div className="w-full min-w-0 space-y-3">
|
||||||
{/* Primary model selector */}
|
{/* Primary model selector */}
|
||||||
<div>
|
<div>
|
||||||
<p className="text-xs text-muted-foreground mb-1">
|
<p className="text-xs text-muted-foreground mb-1">
|
||||||
{t('models.fallback.primary')}
|
{t('models.fallback.primary')}
|
||||||
</p>
|
</p>
|
||||||
<div className="flex items-center gap-1.5">
|
<div className="flex min-w-0 items-center gap-1.5">
|
||||||
<div className="flex-1">
|
<div className="min-w-0 flex-1">
|
||||||
{renderModelSelect(
|
{renderModelSelect(
|
||||||
modelValue.primary,
|
modelValue.primary,
|
||||||
(val) => updateValue({ primary: val }),
|
(val) => updateValue({ primary: val }),
|
||||||
@@ -918,16 +922,16 @@ export default function DynamicFormItemComponent({
|
|||||||
|
|
||||||
{/* Fallback models */}
|
{/* Fallback models */}
|
||||||
{modelValue.fallbacks.length > 0 && (
|
{modelValue.fallbacks.length > 0 && (
|
||||||
<div className="space-y-2">
|
<div className="min-w-0 space-y-2">
|
||||||
<p className="text-xs text-muted-foreground">
|
<p className="text-xs text-muted-foreground">
|
||||||
{t('models.fallback.fallbackList')}
|
{t('models.fallback.fallbackList')}
|
||||||
</p>
|
</p>
|
||||||
{modelValue.fallbacks.map((fbUuid: string, index: number) => (
|
{modelValue.fallbacks.map((fbUuid: string, index: number) => (
|
||||||
<div key={index} className="flex items-center gap-2">
|
<div key={index} className="flex min-w-0 items-center gap-2">
|
||||||
<span className="text-xs text-muted-foreground w-4 shrink-0">
|
<span className="text-xs text-muted-foreground w-4 shrink-0">
|
||||||
{index + 1}.
|
{index + 1}.
|
||||||
</span>
|
</span>
|
||||||
<div className="flex-1">
|
<div className="min-w-0 flex-1">
|
||||||
{renderModelSelect(
|
{renderModelSelect(
|
||||||
fbUuid,
|
fbUuid,
|
||||||
(val) => updateFallbackModel(index, val),
|
(val) => updateFallbackModel(index, val),
|
||||||
@@ -1003,20 +1007,22 @@ export default function DynamicFormItemComponent({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Select value={field.value} onValueChange={field.onChange}>
|
<Select value={field.value} onValueChange={field.onChange}>
|
||||||
<SelectTrigger className="bg-[#ffffff] dark:bg-[#2a2a2e]">
|
<SelectTrigger className="min-w-0 bg-[#ffffff] dark:bg-[#2a2a2e]">
|
||||||
{field.value && field.value !== '__none__' ? (
|
{field.value && field.value !== '__none__' ? (
|
||||||
(() => {
|
(() => {
|
||||||
const selectedKb = knowledgeBases.find(
|
const selectedKb = knowledgeBases.find(
|
||||||
(kb) => kb.uuid === field.value,
|
(kb) => kb.uuid === field.value,
|
||||||
);
|
);
|
||||||
return (
|
return (
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex min-w-0 items-center gap-2">
|
||||||
{selectedKb?.emoji && (
|
{selectedKb?.emoji && (
|
||||||
<span className="text-sm shrink-0">
|
<span className="text-sm shrink-0">
|
||||||
{selectedKb.emoji}
|
{selectedKb.emoji}
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
<span>{selectedKb?.name ?? field.value}</span>
|
<span className="truncate">
|
||||||
|
{selectedKb?.name ?? field.value}
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
})()
|
})()
|
||||||
@@ -1066,9 +1072,9 @@ export default function DynamicFormItemComponent({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="space-y-2">
|
<div className="min-w-0 space-y-2">
|
||||||
{field.value && field.value.length > 0 ? (
|
{field.value && field.value.length > 0 ? (
|
||||||
<div className="space-y-2">
|
<div className="min-w-0 space-y-2">
|
||||||
{field.value.map((kbId: string) => {
|
{field.value.map((kbId: string) => {
|
||||||
const currentKb = knowledgeBases.find(
|
const currentKb = knowledgeBases.find(
|
||||||
(base) => base.uuid === kbId,
|
(base) => base.uuid === kbId,
|
||||||
@@ -1078,17 +1084,17 @@ export default function DynamicFormItemComponent({
|
|||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
key={kbId}
|
key={kbId}
|
||||||
className="flex items-center justify-between rounded-lg border p-3 hover:bg-accent"
|
className="flex min-w-0 items-center justify-between rounded-lg border p-3 hover:bg-accent"
|
||||||
>
|
>
|
||||||
<div className="flex items-center gap-2 flex-1">
|
<div className="flex min-w-0 flex-1 items-center gap-2">
|
||||||
<div className="flex-1 min-w-0">
|
<div className="flex-1 min-w-0">
|
||||||
<div className="font-medium flex items-center gap-2">
|
<div className="flex min-w-0 items-center gap-2 font-medium">
|
||||||
{currentKb.emoji && (
|
{currentKb.emoji && (
|
||||||
<span className="text-sm shrink-0">
|
<span className="text-sm shrink-0">
|
||||||
{currentKb.emoji}
|
{currentKb.emoji}
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
{currentKb.name}
|
<span className="truncate">{currentKb.name}</span>
|
||||||
{currentKb.knowledge_engine?.name && (
|
{currentKb.knowledge_engine?.name && (
|
||||||
<span className="text-xs px-2 py-0.5 rounded-full bg-purple-100 text-purple-700 dark:bg-purple-900 dark:text-purple-300">
|
<span className="text-xs px-2 py-0.5 rounded-full bg-purple-100 text-purple-700 dark:bg-purple-900 dark:text-purple-300">
|
||||||
{extractI18nObject(
|
{extractI18nObject(
|
||||||
@@ -1098,7 +1104,7 @@ export default function DynamicFormItemComponent({
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
{currentKb.description && (
|
{currentKb.description && (
|
||||||
<div className="text-sm text-muted-foreground">
|
<div className="text-sm break-words text-muted-foreground">
|
||||||
{currentKb.description}
|
{currentKb.description}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
@@ -1221,7 +1227,7 @@ export default function DynamicFormItemComponent({
|
|||||||
case DynamicFormItemType.BOT_SELECTOR:
|
case DynamicFormItemType.BOT_SELECTOR:
|
||||||
return (
|
return (
|
||||||
<Select value={field.value} onValueChange={field.onChange}>
|
<Select value={field.value} onValueChange={field.onChange}>
|
||||||
<SelectTrigger className="bg-[#ffffff] dark:bg-[#2a2a2e]">
|
<SelectTrigger className="min-w-0 bg-[#ffffff] dark:bg-[#2a2a2e]">
|
||||||
<SelectValue placeholder={t('bots.selectBot')} />
|
<SelectValue placeholder={t('bots.selectBot')} />
|
||||||
</SelectTrigger>
|
</SelectTrigger>
|
||||||
<SelectContent>
|
<SelectContent>
|
||||||
@@ -1239,9 +1245,9 @@ export default function DynamicFormItemComponent({
|
|||||||
case DynamicFormItemType.TOOLS_SELECTOR:
|
case DynamicFormItemType.TOOLS_SELECTOR:
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="space-y-2">
|
<div className="min-w-0 space-y-2">
|
||||||
{field.value && field.value.length > 0 ? (
|
{field.value && field.value.length > 0 ? (
|
||||||
<div className="space-y-2">
|
<div className="min-w-0 space-y-2">
|
||||||
{field.value.map((toolName: string) => {
|
{field.value.map((toolName: string) => {
|
||||||
const currentTool = tools.find(
|
const currentTool = tools.find(
|
||||||
(tool) => tool.name === toolName,
|
(tool) => tool.name === toolName,
|
||||||
@@ -1250,12 +1256,12 @@ export default function DynamicFormItemComponent({
|
|||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
key={toolName}
|
key={toolName}
|
||||||
className="flex items-center justify-between rounded-lg border p-3 hover:bg-accent"
|
className="flex min-w-0 items-center justify-between rounded-lg border p-3 hover:bg-accent"
|
||||||
>
|
>
|
||||||
<div className="flex items-center gap-2 flex-1">
|
<div className="flex min-w-0 flex-1 items-center gap-2">
|
||||||
<Wrench className="h-4 w-4 shrink-0 text-muted-foreground" />
|
<Wrench className="h-4 w-4 shrink-0 text-muted-foreground" />
|
||||||
<div className="flex-1 min-w-0">
|
<div className="flex-1 min-w-0">
|
||||||
<div className="font-medium">{toolName}</div>
|
<div className="truncate font-medium">{toolName}</div>
|
||||||
{currentTool?.human_desc && (
|
{currentTool?.human_desc && (
|
||||||
<div className="text-sm text-muted-foreground truncate">
|
<div className="text-sm text-muted-foreground truncate">
|
||||||
{currentTool.human_desc}
|
{currentTool.human_desc}
|
||||||
@@ -1379,13 +1385,16 @@ export default function DynamicFormItemComponent({
|
|||||||
? field.value
|
? field.value
|
||||||
: [{ role: 'system', content: '' }];
|
: [{ role: 'system', content: '' }];
|
||||||
return (
|
return (
|
||||||
<div className="space-y-2">
|
<div className="min-w-0 space-y-2">
|
||||||
{promptItems.map(
|
{promptItems.map(
|
||||||
(item: { role: string; content: string }, index: number) => (
|
(item: { role: string; content: string }, index: number) => (
|
||||||
<div key={index} className="flex gap-2 items-center">
|
<div
|
||||||
|
key={index}
|
||||||
|
className="flex min-w-0 flex-col gap-2 sm:flex-row sm:items-center"
|
||||||
|
>
|
||||||
{/* 角色选择 */}
|
{/* 角色选择 */}
|
||||||
{index === 0 ? (
|
{index === 0 ? (
|
||||||
<div className="w-[120px] px-3 py-2 border rounded bg-gray-50 dark:bg-[#2a292e] text-gray-500 dark:text-white dark:border-gray-600">
|
<div className="w-full shrink-0 rounded border bg-gray-50 px-3 py-2 text-gray-500 sm:w-[120px] dark:border-gray-600 dark:bg-[#2a292e] dark:text-white">
|
||||||
system
|
system
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
@@ -1410,7 +1419,7 @@ export default function DynamicFormItemComponent({
|
|||||||
)}
|
)}
|
||||||
{/* 内容输入 */}
|
{/* 内容输入 */}
|
||||||
<Textarea
|
<Textarea
|
||||||
className="w-[300px]"
|
className="min-h-20 w-full min-w-0 flex-1 resize-y overflow-x-hidden break-all sm:w-[300px]"
|
||||||
value={item.content}
|
value={item.content}
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
const newValue = [...(field.value ?? promptItems)];
|
const newValue = [...(field.value ?? promptItems)];
|
||||||
@@ -1428,7 +1437,6 @@ export default function DynamicFormItemComponent({
|
|||||||
className="p-2 hover:bg-gray-100 rounded"
|
className="p-2 hover:bg-gray-100 rounded"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
const newValue = (field.value ?? promptItems).filter(
|
const newValue = (field.value ?? promptItems).filter(
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
||||||
(_: any, i: number) => i !== index,
|
(_: any, i: number) => i !== index,
|
||||||
);
|
);
|
||||||
field.onChange(newValue);
|
field.onChange(newValue);
|
||||||
|
|||||||
@@ -208,7 +208,7 @@ export default function PluginDetailContent({ id }: { id: string }) {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex min-h-0 max-w-full flex-1 flex-col gap-6 overflow-y-auto md:flex-row md:overflow-hidden">
|
<div className="flex min-h-0 max-w-full flex-1 flex-col gap-6 overflow-y-auto md:flex-row md:overflow-hidden">
|
||||||
<div className="space-y-4 pb-6 md:min-h-0 md:w-[380px] md:flex-shrink-0 md:overflow-y-auto md:overflow-x-hidden xl:w-[420px]">
|
<div className="min-w-0 max-w-full space-y-4 pb-6 md:min-h-0 md:w-[380px] md:flex-shrink-0 md:overflow-y-auto md:overflow-x-hidden xl:w-[420px]">
|
||||||
<PluginForm
|
<PluginForm
|
||||||
pluginAuthor={pluginAuthor}
|
pluginAuthor={pluginAuthor}
|
||||||
pluginName={pluginName}
|
pluginName={pluginName}
|
||||||
|
|||||||
@@ -42,7 +42,6 @@ export default function PluginForm({
|
|||||||
setPluginConfig(res);
|
setPluginConfig(res);
|
||||||
|
|
||||||
// 提取初始配置中的所有文件 key
|
// 提取初始配置中的所有文件 key
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
||||||
const extractFileKeys = (obj: any): string[] => {
|
const extractFileKeys = (obj: any): string[] => {
|
||||||
const keys: string[] = [];
|
const keys: string[] = [];
|
||||||
if (obj && typeof obj === 'object') {
|
if (obj && typeof obj === 'object') {
|
||||||
@@ -77,7 +76,6 @@ export default function PluginForm({
|
|||||||
);
|
);
|
||||||
|
|
||||||
// 提取最终保存的配置中的所有文件 key
|
// 提取最终保存的配置中的所有文件 key
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
||||||
const extractFileKeys = (obj: any): string[] => {
|
const extractFileKeys = (obj: any): string[] => {
|
||||||
const keys: string[] = [];
|
const keys: string[] = [];
|
||||||
if (obj && typeof obj === 'object') {
|
if (obj && typeof obj === 'object') {
|
||||||
@@ -143,13 +141,13 @@ export default function PluginForm({
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="space-y-4">
|
<div className="min-w-0 max-w-full space-y-4">
|
||||||
<Card>
|
<Card className="min-w-0 overflow-x-hidden">
|
||||||
<CardHeader>
|
<CardHeader>
|
||||||
<CardTitle>{t('plugins.pluginConfig')}</CardTitle>
|
<CardTitle>{t('plugins.pluginConfig')}</CardTitle>
|
||||||
<CardDescription>{t('plugins.saveConfig')}</CardDescription>
|
<CardDescription>{t('plugins.saveConfig')}</CardDescription>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent>
|
<CardContent className="min-w-0 overflow-x-hidden">
|
||||||
{pluginInfo.manifest.manifest.spec.config.length > 0 ? (
|
{pluginInfo.manifest.manifest.spec.config.length > 0 ? (
|
||||||
<DynamicFormComponent
|
<DynamicFormComponent
|
||||||
itemConfigList={pluginInfo.manifest.manifest.spec.config}
|
itemConfigList={pluginInfo.manifest.manifest.spec.config}
|
||||||
|
|||||||
@@ -78,7 +78,7 @@ function FormItem({ className, ...props }: React.ComponentProps<'div'>) {
|
|||||||
<FormItemContext.Provider value={{ id }}>
|
<FormItemContext.Provider value={{ id }}>
|
||||||
<div
|
<div
|
||||||
data-slot="form-item"
|
data-slot="form-item"
|
||||||
className={cn('grid gap-2', className)}
|
className={cn('grid min-w-0 gap-2', className)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
</FormItemContext.Provider>
|
</FormItemContext.Provider>
|
||||||
@@ -128,7 +128,7 @@ function FormDescription({ className, ...props }: React.ComponentProps<'p'>) {
|
|||||||
<p
|
<p
|
||||||
data-slot="form-description"
|
data-slot="form-description"
|
||||||
id={formDescriptionId}
|
id={formDescriptionId}
|
||||||
className={cn('text-muted-foreground text-sm', className)}
|
className={cn('text-muted-foreground text-sm break-words', className)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
@@ -146,7 +146,7 @@ function FormMessage({ className, ...props }: React.ComponentProps<'p'>) {
|
|||||||
<p
|
<p
|
||||||
data-slot="form-message"
|
data-slot="form-message"
|
||||||
id={formMessageId}
|
id={formMessageId}
|
||||||
className={cn('text-destructive text-sm', className)}
|
className={cn('text-destructive text-sm break-words', className)}
|
||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
{body}
|
{body}
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ function Textarea({ className, ...props }: React.ComponentProps<'textarea'>) {
|
|||||||
<textarea
|
<textarea
|
||||||
data-slot="textarea"
|
data-slot="textarea"
|
||||||
className={cn(
|
className={cn(
|
||||||
'border-input placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:bg-input/30 flex field-sizing-content min-h-16 w-full rounded-md border bg-transparent px-3 py-2 text-base shadow-xs transition-[color,box-shadow] outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50 md:text-sm',
|
'border-input placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:bg-input/30 flex min-h-16 w-full min-w-0 max-w-full resize-y overflow-x-hidden rounded-md border bg-transparent px-3 py-2 text-base break-words shadow-xs transition-[color,box-shadow] outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50 md:text-sm',
|
||||||
className,
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
|
|||||||
Reference in New Issue
Block a user