mirror of
https://github.com/danny-avila/LibreChat.git
synced 2026-08-04 14:57:42 +00:00
refactor(client): migrate Agent Builder and Tool Library to @librechat/client
Swap raw buttons, inputs, labels, textareas and native title tooltips for the @librechat/client Button/Input/Label/Textarea/TooltipAnchor components across the Agent Builder panel (SidePanel/Agents) and the Tools marketplace. Remove heavy input focus rings in favor of subtle borders, soften dropdown trigger borders, and convert stray shadcn/raw colors in touched lines to semantic tokens. Localize the tool delete aria-label and toast messages. Update co-located test mocks to provide the newly-used Button component.
This commit is contained in:
parent
8a6047ac34
commit
9a68fe6da0
38 changed files with 283 additions and 226 deletions
|
|
@ -8,10 +8,12 @@ import {
|
|||
AuthTypeEnum,
|
||||
} from 'librechat-data-provider';
|
||||
import {
|
||||
Label,
|
||||
Button,
|
||||
Spinner,
|
||||
Textarea,
|
||||
OGDialog,
|
||||
TooltipAnchor,
|
||||
OGDialogTitle,
|
||||
OGDialogHeader,
|
||||
OGDialogContent,
|
||||
|
|
@ -243,15 +245,20 @@ export default function ActionsInput({
|
|||
>
|
||||
{localize('com_ui_schema')}
|
||||
</label>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setIsSchemaDialogOpen(true)}
|
||||
aria-label={localize('com_ui_expand_editor')}
|
||||
title={localize('com_ui_expand_editor')}
|
||||
className="inline-flex h-7 w-7 items-center justify-center rounded-lg text-text-secondary transition-colors hover:bg-surface-secondary hover:text-text-primary focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring-primary"
|
||||
>
|
||||
<Maximize2 className="h-4 w-4" strokeWidth={1.75} aria-hidden={true} />
|
||||
</button>
|
||||
<TooltipAnchor
|
||||
side="top"
|
||||
description={localize('com_ui_expand_editor')}
|
||||
render={
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setIsSchemaDialogOpen(true)}
|
||||
aria-label={localize('com_ui_expand_editor')}
|
||||
className="inline-flex h-7 w-7 items-center justify-center rounded-lg text-text-secondary transition-colors hover:bg-surface-secondary hover:text-text-primary focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-text-primary"
|
||||
>
|
||||
<Maximize2 className="h-4 w-4" strokeWidth={1.75} aria-hidden={true} />
|
||||
</button>
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
<Textarea
|
||||
id="schemaInput"
|
||||
|
|
@ -271,9 +278,9 @@ export default function ActionsInput({
|
|||
</div>
|
||||
{(data || showSkeleton) && (
|
||||
<div className="mt-4 flex min-h-0 flex-1 flex-col">
|
||||
<label className="mb-1 block shrink-0 text-sm font-medium text-text-primary">
|
||||
<Label className="mb-1 shrink-0 font-medium">
|
||||
{localize('com_assistants_available_actions')}
|
||||
</label>
|
||||
</Label>
|
||||
<div className="min-h-0 flex-1 overflow-y-auto">
|
||||
{data ? <ActionsTable columns={columns} data={data} /> : <ActionsTableSkeleton />}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ export default function DataTable<TData, TValue>({ columns, data }: DataTablePro
|
|||
{headerGroup.headers.map((header) => (
|
||||
<th
|
||||
key={header.id}
|
||||
className="sticky top-0 z-10 border-b border-border-light bg-background py-2 pr-3 text-left text-[11px] font-medium uppercase tracking-wide text-text-secondary"
|
||||
className="sticky top-0 z-10 border-b border-border-light bg-surface-primary py-2 pr-3 text-left text-[11px] font-medium uppercase tracking-wide text-text-secondary"
|
||||
>
|
||||
{header.isPlaceholder
|
||||
? null
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import React from 'react';
|
||||
import { Settings2 } from 'lucide-react';
|
||||
import { Button } from '@librechat/client';
|
||||
import { useLocalize } from '~/hooks';
|
||||
import { Panel } from '~/common';
|
||||
|
||||
|
|
@ -11,15 +12,15 @@ const AdvancedButton: React.FC<AdvancedButtonProps> = ({ setActivePanel }) => {
|
|||
const localize = useLocalize();
|
||||
|
||||
return (
|
||||
<button
|
||||
type="button"
|
||||
<Button
|
||||
variant="subtle"
|
||||
onClick={() => setActivePanel(Panel.advanced)}
|
||||
aria-label={localize('com_ui_advanced')}
|
||||
className="inline-flex h-9 w-full items-center justify-center gap-2 rounded-xl border border-border-light bg-transparent px-3 text-sm font-medium text-text-primary transition-colors hover:bg-surface-secondary focus:outline-none focus-visible:ring-2 focus-visible:ring-ring-primary"
|
||||
className="h-9 w-full px-3"
|
||||
>
|
||||
<Settings2 className="h-4 w-4" strokeWidth={1.75} aria-hidden="true" />
|
||||
{localize('com_ui_advanced')}
|
||||
</button>
|
||||
</Button>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { useState } from 'react';
|
||||
import { useFormContext } from 'react-hook-form';
|
||||
import { useToastContext } from '@librechat/client';
|
||||
import { ChevronLeft, Check, Copy } from 'lucide-react';
|
||||
import { Button, TooltipAnchor, useToastContext } from '@librechat/client';
|
||||
import type { AgentForm } from '~/common';
|
||||
import { sectionLabelClass, groupHeadingClass } from './ui';
|
||||
import { useAgentPanelContext } from '~/Providers';
|
||||
|
|
@ -34,14 +34,15 @@ export default function AdvancedPanel() {
|
|||
return (
|
||||
<div className="mb-1 flex w-full flex-col gap-4 text-sm">
|
||||
<header className="grid grid-cols-[auto_1fr_auto] items-center gap-2 pt-1">
|
||||
<button
|
||||
type="button"
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
onClick={() => setActivePanel(Panel.builder)}
|
||||
aria-label={localize('com_ui_back_to_builder')}
|
||||
className="inline-flex h-10 w-10 flex-shrink-0 items-center justify-center rounded-xl border border-border-light text-text-secondary transition-colors hover:bg-surface-secondary hover:text-text-primary focus:outline-none focus-visible:ring-2 focus-visible:ring-ring-primary"
|
||||
className="h-10 w-10 flex-shrink-0 rounded-xl border border-border-light text-text-secondary hover:bg-surface-secondary hover:text-text-primary focus:outline-none focus-visible:ring-2 focus-visible:ring-text-primary"
|
||||
>
|
||||
<ChevronLeft className="h-5 w-5" strokeWidth={1.75} aria-hidden="true" />
|
||||
</button>
|
||||
</Button>
|
||||
<h2 className="text-center text-base font-semibold text-text-primary">
|
||||
{localize('com_ui_advanced_settings')}
|
||||
</h2>
|
||||
|
|
@ -59,23 +60,27 @@ export default function AdvancedPanel() {
|
|||
{currentAgentId && (
|
||||
<div className="flex items-center justify-between gap-2 border-t border-border-light pt-3">
|
||||
<span className={sectionLabelClass}>{localize('com_ui_agent_id')}</span>
|
||||
<button
|
||||
type="button"
|
||||
onClick={handleCopyAgentId}
|
||||
title={currentAgentId}
|
||||
aria-label={localize('com_ui_agent_id_copy')}
|
||||
className="inline-flex items-center gap-1.5 rounded-lg px-2 py-1 text-text-secondary transition-colors hover:bg-surface-secondary hover:text-text-primary focus:outline-none focus-visible:ring-2 focus-visible:ring-ring-primary"
|
||||
>
|
||||
<code className="max-w-[150px] truncate font-mono text-xs">{currentAgentId}</code>
|
||||
<span className="t-icon-swap" data-state={copied ? 'b' : 'a'} aria-hidden="true">
|
||||
<span className="t-icon" data-icon="a">
|
||||
<Copy className="h-3.5 w-3.5" aria-hidden="true" />
|
||||
</span>
|
||||
<span className="t-icon" data-icon="b">
|
||||
<Check className="h-3.5 w-3.5 text-green-500" aria-hidden="true" />
|
||||
</span>
|
||||
</span>
|
||||
</button>
|
||||
<TooltipAnchor
|
||||
description={currentAgentId}
|
||||
render={
|
||||
<Button
|
||||
variant="ghost"
|
||||
onClick={handleCopyAgentId}
|
||||
aria-label={localize('com_ui_agent_id_copy')}
|
||||
className="h-auto gap-1.5 rounded-lg px-2 py-1 text-text-secondary hover:bg-surface-secondary hover:text-text-primary focus:outline-none focus-visible:ring-2 focus-visible:ring-text-primary"
|
||||
>
|
||||
<code className="max-w-[150px] truncate font-mono text-xs">{currentAgentId}</code>
|
||||
<span className="t-icon-swap" data-state={copied ? 'b' : 'a'} aria-hidden="true">
|
||||
<span className="t-icon" data-icon="a">
|
||||
<Copy className="h-3.5 w-3.5" aria-hidden="true" />
|
||||
</span>
|
||||
<span className="t-icon" data-icon="b">
|
||||
<Check className="h-3.5 w-3.5 text-green-500" aria-hidden="true" />
|
||||
</span>
|
||||
</span>
|
||||
</Button>
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import React, { useState, useMemo, useEffect } from 'react';
|
||||
import { Waypoints, ChevronDown } from 'lucide-react';
|
||||
import { Label, Input, Textarea } from '@librechat/client';
|
||||
import { Button, Label, Input, Textarea } from '@librechat/client';
|
||||
import type { ControllerRenderProps } from 'react-hook-form';
|
||||
import type { GraphEdge } from 'librechat-data-provider';
|
||||
import type { AgentForm } from '~/common';
|
||||
|
|
@ -118,9 +118,10 @@ const AgentHandoffs: React.FC<AgentHandoffsProps> = ({ field, currentAgentId })
|
|||
icon={agentIcon(getAgent(targetAgentId))}
|
||||
ariaLabel={localize('com_ui_agent_var', { 0: localize('com_ui_select') })}
|
||||
/>
|
||||
<button
|
||||
type="button"
|
||||
className="flex-shrink-0 rounded-lg p-1 text-text-secondary transition hover:bg-surface-secondary hover:text-text-primary focus:outline-none focus-visible:ring-2 focus-visible:ring-ring-primary"
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
className="size-auto flex-shrink-0 rounded-lg p-1 text-text-secondary hover:bg-surface-secondary hover:text-text-primary"
|
||||
onClick={() => toggleExpanded(idx)}
|
||||
aria-expanded={isExpanded}
|
||||
aria-label={localize(isExpanded ? 'com_ui_collapse' : 'com_ui_expand')}
|
||||
|
|
@ -130,7 +131,7 @@ const AgentHandoffs: React.FC<AgentHandoffsProps> = ({ field, currentAgentId })
|
|||
className={`transition-transform ${isExpanded ? 'rotate-180' : ''}`}
|
||||
aria-hidden="true"
|
||||
/>
|
||||
</button>
|
||||
</Button>
|
||||
</AgentRow>
|
||||
|
||||
{isExpanded && (
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { useMemo } from 'react';
|
||||
import { X, PlusCircle } from 'lucide-react';
|
||||
import { ControlCombobox } from '@librechat/client';
|
||||
import { EModelEndpoint } from 'librechat-data-provider';
|
||||
import { Button, ControlCombobox } from '@librechat/client';
|
||||
import type { Agent, TMessage } from 'librechat-data-provider';
|
||||
import type { ReactNode } from 'react';
|
||||
import type { OptionWithIcon } from '~/common';
|
||||
|
|
@ -83,7 +83,7 @@ export function AddAgentSelect({ options, onSelect, placeholder, ariaLabel }: Ad
|
|||
selectPlaceholder={placeholder}
|
||||
searchPlaceholder={localize('com_ui_agent_var', { 0: localize('com_ui_search') })}
|
||||
items={options}
|
||||
className="h-9 w-full border-dashed border-border-heavy text-center text-text-secondary hover:text-text-primary"
|
||||
className="h-9 w-full border-dashed border-border-light text-center text-text-secondary hover:text-text-primary"
|
||||
containerClassName="px-0"
|
||||
SelectIcon={<PlusCircle size={16} className="text-text-secondary" />}
|
||||
/>
|
||||
|
|
@ -134,14 +134,15 @@ interface RemoveButtonProps {
|
|||
/** Ghost remove (×) button shared by agent rows. */
|
||||
export function RemoveButton({ onClick, label }: RemoveButtonProps) {
|
||||
return (
|
||||
<button
|
||||
type="button"
|
||||
className="flex-shrink-0 rounded-lg p-1 text-text-secondary transition hover:bg-surface-secondary hover:text-text-primary focus:outline-none focus-visible:ring-2 focus-visible:ring-ring-primary"
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
className="size-auto flex-shrink-0 p-1 text-text-secondary hover:bg-surface-secondary hover:text-text-primary"
|
||||
onClick={onClick}
|
||||
aria-label={label}
|
||||
>
|
||||
<X size={16} aria-hidden="true" />
|
||||
</button>
|
||||
</Button>
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { useFormContext, Controller } from 'react-hook-form';
|
||||
import { Input, HoverCard, HoverCardPortal, HoverCardContent } from '@librechat/client';
|
||||
import { Input, Label, HoverCard, HoverCardPortal, HoverCardContent } from '@librechat/client';
|
||||
import type { AgentForm } from '~/common';
|
||||
import { useLocalize } from '~/hooks';
|
||||
import { InfoTrigger } from './ui';
|
||||
|
|
@ -13,9 +13,9 @@ export default function MaxAgentSteps() {
|
|||
<HoverCard openDelay={50}>
|
||||
<div className="flex flex-col gap-1.5">
|
||||
<div className="flex items-center gap-1.5">
|
||||
<label htmlFor="recursion_limit" className="text-[13px] font-medium text-text-primary">
|
||||
<Label htmlFor="recursion_limit" className="w-auto text-[13px] font-medium">
|
||||
{localize('com_ui_agent_recursion_limit')}
|
||||
</label>
|
||||
</Label>
|
||||
<InfoTrigger />
|
||||
</div>
|
||||
<Controller
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import {
|
||||
Button,
|
||||
Switch,
|
||||
HoverCard,
|
||||
CircleHelpIcon,
|
||||
|
|
@ -43,13 +44,13 @@ export function InfoTrigger() {
|
|||
const localize = useLocalize();
|
||||
return (
|
||||
<HoverCardTrigger asChild>
|
||||
<button
|
||||
type="button"
|
||||
<Button
|
||||
variant="ghost"
|
||||
aria-label={localize('com_ui_more_info')}
|
||||
className="flex h-4 w-4 flex-shrink-0 items-center justify-center rounded text-text-tertiary transition-colors hover:text-text-secondary focus:outline-none focus-visible:ring-2 focus-visible:ring-ring-primary"
|
||||
className="flex h-4 w-4 flex-shrink-0 items-center justify-center rounded p-0 text-text-tertiary transition-colors hover:bg-transparent hover:text-text-secondary focus:outline-none focus-visible:ring-2 focus-visible:ring-text-primary"
|
||||
>
|
||||
<CircleHelpIcon className="h-3.5 w-3.5" aria-hidden={true} />
|
||||
</button>
|
||||
</Button>
|
||||
</HoverCardTrigger>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -82,7 +82,7 @@ function Avatar({ avatar }: { avatar: AgentAvatar | null }) {
|
|||
trigger={
|
||||
<button
|
||||
type="button"
|
||||
className="h-14 w-14 overflow-hidden rounded-full outline-none ring-offset-0 transition-shadow focus:outline-none focus-visible:ring-2 focus-visible:ring-ring"
|
||||
className="h-14 w-14 overflow-hidden rounded-full outline-none ring-offset-0 transition-shadow focus:outline-none focus-visible:ring-2 focus-visible:ring-text-primary"
|
||||
aria-label={localize('com_ui_upload_agent_avatar_label')}
|
||||
>
|
||||
<span
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { Input } from '@librechat/client';
|
||||
import { Input, Label } from '@librechat/client';
|
||||
import { Controller, useWatch, useFormContext } from 'react-hook-form';
|
||||
import { EModelEndpoint, getEndpointField } from 'librechat-data-provider';
|
||||
import type { AgentForm, IconComponentTypes } from '~/common';
|
||||
|
|
@ -106,12 +106,12 @@ export default function AgentConfig() {
|
|||
{/* MODEL + CATEGORY — balanced 2-column grid */}
|
||||
<div className="mb-3 grid grid-cols-2 gap-2">
|
||||
<div className="flex min-w-0 flex-col">
|
||||
<label
|
||||
<Label
|
||||
className="mb-1 block text-[11px] font-medium uppercase tracking-wide text-text-secondary"
|
||||
htmlFor="provider"
|
||||
>
|
||||
{localize('com_ui_model')} <span className="text-red-500">*</span>
|
||||
</label>
|
||||
</Label>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setActivePanel(Panel.model)}
|
||||
|
|
@ -139,12 +139,12 @@ export default function AgentConfig() {
|
|||
</button>
|
||||
</div>
|
||||
<div className="flex flex-col">
|
||||
<label
|
||||
<Label
|
||||
className="mb-1 block text-[11px] font-medium uppercase tracking-wide text-text-secondary"
|
||||
htmlFor="category-selector"
|
||||
>
|
||||
{localize('com_ui_category')} <span className="text-red-500">*</span>
|
||||
</label>
|
||||
</Label>
|
||||
<AgentCategorySelector className="w-full rounded-lg" />
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -164,9 +164,9 @@ export default function AgentConfig() {
|
|||
|
||||
{/* SUPPORT CONTACT */}
|
||||
<div className="mb-3 flex flex-col">
|
||||
<label className="mb-1 block text-[11px] font-medium uppercase tracking-wide text-text-secondary">
|
||||
<Label className="mb-1 block text-[11px] font-medium uppercase tracking-wide text-text-secondary">
|
||||
{localize('com_ui_support_contact')}
|
||||
</label>
|
||||
</Label>
|
||||
<div className="space-y-2">
|
||||
<Controller
|
||||
name="support_contact.name"
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { Globe } from 'lucide-react';
|
||||
import { Spinner } from '@librechat/client';
|
||||
import { Button, Spinner } from '@librechat/client';
|
||||
import { useWatch, useFormContext } from 'react-hook-form';
|
||||
import {
|
||||
SystemRoles,
|
||||
|
|
@ -114,26 +114,29 @@ export default function AgentFooter({
|
|||
resourceName={agent?.name ?? ''}
|
||||
resourceType={ResourceType.REMOTE_AGENT}
|
||||
>
|
||||
<button
|
||||
<Button
|
||||
type="button"
|
||||
className="btn btn-neutral border-token-border-light h-9 px-3"
|
||||
variant="outline"
|
||||
aria-label={localize('com_ui_remote_access')}
|
||||
title={localize('com_ui_remote_access')}
|
||||
className="h-9 w-auto px-3"
|
||||
>
|
||||
<Globe className="h-4 w-4" aria-hidden="true" />
|
||||
</button>
|
||||
</Button>
|
||||
</GenericGrantAccessDialog>
|
||||
)}
|
||||
{(agent?.author === user?.id || user?.role === SystemRoles.ADMIN || canEditThisAgent) &&
|
||||
!permissionsLoading && <DuplicateAgent agent_id={agent_id} />}
|
||||
{/* Submit Button */}
|
||||
<button
|
||||
className="btn btn-primary focus:shadow-outline flex h-9 w-full items-center justify-center px-4 py-2 font-semibold text-white hover:bg-green-600 focus:border-green-500"
|
||||
<Button
|
||||
variant="submit"
|
||||
className="h-9 w-full px-4 py-2 font-semibold"
|
||||
type="submit"
|
||||
disabled={isSaving}
|
||||
aria-busy={isSaving}
|
||||
>
|
||||
{renderSaveButton()}
|
||||
</button>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import { Wrench } from 'lucide-react';
|
|||
import { useFormContext } from 'react-hook-form';
|
||||
import { useUpdateUserPluginsMutation } from 'librechat-data-provider/react-query';
|
||||
import {
|
||||
Button,
|
||||
OGDialog,
|
||||
TrashIcon,
|
||||
CircleHelpIcon,
|
||||
|
|
@ -47,12 +48,15 @@ export default function AgentTool({
|
|||
{ pluginKey: toolId, action: 'uninstall', auth: {}, isEntityTool: true },
|
||||
{
|
||||
onError: (error: unknown) => {
|
||||
showToast({ message: `Error while deleting the tool: ${error}`, status: 'error' });
|
||||
showToast({
|
||||
message: localize('com_ui_delete_tool_error_var', { 0: String(error) }),
|
||||
status: 'error',
|
||||
});
|
||||
},
|
||||
onSuccess: () => {
|
||||
const remainingToolIds = getValues('tools')?.filter((id: string) => id !== toolId);
|
||||
setValue('tools', remainingToolIds);
|
||||
showToast({ message: 'Tool deleted successfully', status: 'success' });
|
||||
showToast({ message: localize('com_ui_delete_tool_success'), status: 'success' });
|
||||
},
|
||||
},
|
||||
);
|
||||
|
|
@ -98,21 +102,20 @@ export default function AgentTool({
|
|||
</div>
|
||||
|
||||
<OGDialogTrigger asChild>
|
||||
<button
|
||||
type="button"
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
className={cn(
|
||||
'flex h-7 w-7 items-center justify-center rounded transition-all duration-200',
|
||||
'hover:bg-gray-200 dark:hover:bg-gray-700',
|
||||
'focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-1',
|
||||
'focus:opacity-100',
|
||||
'h-7 w-7 rounded transition-all duration-200 hover:bg-surface-hover',
|
||||
'focus:opacity-100 focus-visible:opacity-100',
|
||||
isHovering || isFocused ? 'opacity-100' : 'pointer-events-none opacity-0',
|
||||
)}
|
||||
aria-label={`Delete ${currentTool.name}`}
|
||||
aria-label={localize('com_ui_delete_var', { 0: currentTool.name })}
|
||||
tabIndex={0}
|
||||
onFocus={() => setIsFocused(true)}
|
||||
>
|
||||
<TrashIcon className="h-4 w-4" />
|
||||
</button>
|
||||
</Button>
|
||||
</OGDialogTrigger>
|
||||
</div>
|
||||
<OGDialogTemplate
|
||||
|
|
@ -137,8 +140,7 @@ export default function AgentTool({
|
|||
}
|
||||
selection={{
|
||||
selectHandler: () => removeTool(tool),
|
||||
selectClasses:
|
||||
'bg-red-700 hover:bg-red-800 dark:bg-red-600 dark:hover:bg-red-800 text-white',
|
||||
selectClasses: 'bg-surface-destructive hover:bg-surface-destructive-hover text-white',
|
||||
selectText: localize('com_ui_delete'),
|
||||
}}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -94,7 +94,7 @@ function DeleteButton({
|
|||
title={localize('com_ui_delete_agent')}
|
||||
type="button"
|
||||
>
|
||||
<div className="flex w-full items-center justify-center gap-2 text-red-500">
|
||||
<div className="flex w-full items-center justify-center gap-2 text-text-destructive">
|
||||
<TrashIcon />
|
||||
</div>
|
||||
</Button>
|
||||
|
|
@ -115,7 +115,7 @@ function DeleteButton({
|
|||
}
|
||||
selection={{
|
||||
selectHandler: () => deleteAgent.mutate({ agent_id }),
|
||||
selectClasses: 'bg-red-600 hover:bg-red-700 dark:hover:bg-red-800 text-white',
|
||||
selectClasses: 'bg-surface-destructive hover:bg-surface-destructive-hover text-white',
|
||||
selectText: localize('com_ui_delete'),
|
||||
}}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { CopyPlus } from 'lucide-react';
|
||||
import { useToastContext, Button } from '@librechat/client';
|
||||
import { useToastContext, TooltipAnchor, Button } from '@librechat/client';
|
||||
import { useDuplicateAgentMutation } from '~/data-provider';
|
||||
import { isEphemeralAgent } from '~/common';
|
||||
import { useLocalize } from '~/hooks';
|
||||
|
|
@ -33,17 +33,22 @@ export default function DuplicateAgent({ agent_id }: { agent_id: string }) {
|
|||
};
|
||||
|
||||
return (
|
||||
<Button
|
||||
size="sm"
|
||||
variant="outline"
|
||||
aria-label={localize('com_ui_duplicate_agent')}
|
||||
title={localize('com_ui_duplicate_agent')}
|
||||
type="button"
|
||||
onClick={handleDuplicate}
|
||||
>
|
||||
<div className="flex w-full items-center justify-center gap-2 text-primary">
|
||||
<CopyPlus className="size-4" />
|
||||
</div>
|
||||
</Button>
|
||||
<TooltipAnchor
|
||||
description={localize('com_ui_duplicate_agent')}
|
||||
side="top"
|
||||
render={
|
||||
<Button
|
||||
size="sm"
|
||||
variant="outline"
|
||||
aria-label={localize('com_ui_duplicate_agent')}
|
||||
type="button"
|
||||
onClick={handleDuplicate}
|
||||
>
|
||||
<div className="flex w-full items-center justify-center gap-2 text-text-primary">
|
||||
<CopyPlus className="size-4" />
|
||||
</div>
|
||||
</Button>
|
||||
}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import { memo, useMemo, useRef, useState } from 'react';
|
|||
import * as Ariakit from '@ariakit/react';
|
||||
import { Folder, Plus, Info } from 'lucide-react';
|
||||
import { EModelEndpoint, EToolResources } from 'librechat-data-provider';
|
||||
import { DropdownPopup, SharePointIcon, TooltipAnchor } from '@librechat/client';
|
||||
import { Button, DropdownPopup, SharePointIcon, TooltipAnchor } from '@librechat/client';
|
||||
import type { ExtendedFile } from '~/common';
|
||||
import { useSharePointFileHandlingNoChatContext } from '~/hooks/Files/useSharePointFileHandling';
|
||||
import { useFileHandlingNoChatContext } from '~/hooks/Files/useFileHandling';
|
||||
|
|
@ -125,8 +125,8 @@ function FileContext({
|
|||
unmountOnHide={true}
|
||||
/>
|
||||
) : (
|
||||
<button
|
||||
type="button"
|
||||
<Button
|
||||
variant="ghost"
|
||||
disabled={disabledUploadButton}
|
||||
aria-label={addLabel}
|
||||
className={addButtonClassName}
|
||||
|
|
@ -134,7 +134,7 @@ function FileContext({
|
|||
>
|
||||
<Plus className="h-3.5 w-3.5" strokeWidth={1.75} aria-hidden="true" />
|
||||
{localize('com_ui_add')}
|
||||
</button>
|
||||
</Button>
|
||||
);
|
||||
|
||||
return (
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { Checkbox } from '@librechat/client';
|
||||
import { Checkbox, Label } from '@librechat/client';
|
||||
import { Capabilities } from 'librechat-data-provider';
|
||||
import { useFormContext, Controller } from 'react-hook-form';
|
||||
import type { AssistantForm } from '~/common';
|
||||
|
|
@ -25,9 +25,9 @@ export default function ImageVision() {
|
|||
/>
|
||||
)}
|
||||
/>
|
||||
<label
|
||||
<Label
|
||||
id="image-vision-label"
|
||||
className="form-check-label text-token-text-primary w-full cursor-pointer"
|
||||
className="cursor-pointer"
|
||||
htmlFor={Capabilities.image_vision}
|
||||
onClick={() =>
|
||||
setValue(Capabilities.image_vision, !getValues(Capabilities.image_vision), {
|
||||
|
|
@ -36,7 +36,7 @@ export default function ImageVision() {
|
|||
}
|
||||
>
|
||||
<div className="flex items-center">{localize('com_assistants_image_vision')}</div>
|
||||
</label>
|
||||
</Label>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,21 +4,20 @@ import { PlusCircle, Maximize2 } from 'lucide-react';
|
|||
import { specialVariables } from 'librechat-data-provider';
|
||||
import { Controller, useFormContext } from 'react-hook-form';
|
||||
import {
|
||||
Label,
|
||||
Button,
|
||||
DropdownPopup,
|
||||
OGDialog,
|
||||
Textarea,
|
||||
DropdownPopup,
|
||||
OGDialogClose,
|
||||
OGDialogContent,
|
||||
OGDialogHeader,
|
||||
TooltipAnchor,
|
||||
OGDialogTitle,
|
||||
OGDialogHeader,
|
||||
OGDialogContent,
|
||||
} from '@librechat/client';
|
||||
import type { TSpecialVarLabel } from 'librechat-data-provider';
|
||||
import type { AgentForm } from '~/common';
|
||||
import { useLocalize } from '~/hooks';
|
||||
import { cn } from '~/utils';
|
||||
|
||||
const textareaClass =
|
||||
'lc-field flex w-full rounded-lg border border-border-light bg-surface-secondary px-3 py-2 text-text-primary placeholder:text-text-secondary focus-visible:outline-none focus-visible:border-border-medium focus-visible:ring-2 focus-visible:ring-ring-primary disabled:cursor-not-allowed disabled:opacity-50';
|
||||
|
||||
interface VariableOption {
|
||||
label: TSpecialVarLabel;
|
||||
|
|
@ -58,12 +57,12 @@ export default function Instructions() {
|
|||
return (
|
||||
<div className="mb-3 flex flex-col">
|
||||
<div className="mb-1 flex items-center justify-between">
|
||||
<label
|
||||
<Label
|
||||
className="block text-[11px] font-medium uppercase tracking-wide text-text-secondary"
|
||||
htmlFor="instructions"
|
||||
>
|
||||
{localize('com_ui_instructions')}
|
||||
</label>
|
||||
</Label>
|
||||
<div className="flex items-center gap-0.5">
|
||||
<DropdownPopup
|
||||
portal={true}
|
||||
|
|
@ -86,15 +85,19 @@ export default function Instructions() {
|
|||
menuId={menuId}
|
||||
className="pointer-events-auto z-30"
|
||||
/>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setIsDialogOpen(true)}
|
||||
aria-label={localize('com_ui_expand_editor')}
|
||||
title={localize('com_ui_expand_editor')}
|
||||
className="inline-flex h-7 w-7 items-center justify-center rounded-lg text-text-secondary transition-colors hover:bg-surface-secondary hover:text-text-primary focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring-primary"
|
||||
>
|
||||
<Maximize2 className="h-4 w-4" strokeWidth={1.75} aria-hidden={true} />
|
||||
</button>
|
||||
<TooltipAnchor
|
||||
description={localize('com_ui_expand_editor')}
|
||||
render={
|
||||
<Button
|
||||
variant="ghost"
|
||||
onClick={() => setIsDialogOpen(true)}
|
||||
aria-label={localize('com_ui_expand_editor')}
|
||||
className="h-7 w-7 p-0 text-text-secondary hover:bg-surface-secondary hover:text-text-primary"
|
||||
>
|
||||
<Maximize2 className="h-4 w-4" strokeWidth={1.75} aria-hidden={true} />
|
||||
</Button>
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<Controller
|
||||
|
|
@ -102,10 +105,10 @@ export default function Instructions() {
|
|||
control={control}
|
||||
render={({ field, fieldState: { error } }) => (
|
||||
<>
|
||||
<textarea
|
||||
<Textarea
|
||||
{...field}
|
||||
value={field.value ?? ''}
|
||||
className={cn(textareaClass, 'min-h-[88px] resize-y text-sm')}
|
||||
className="min-h-[88px] resize-y"
|
||||
id="instructions"
|
||||
placeholder={localize('com_agents_instructions_placeholder')}
|
||||
rows={3}
|
||||
|
|
@ -115,7 +118,7 @@ export default function Instructions() {
|
|||
/>
|
||||
{error && (
|
||||
<span
|
||||
className="mt-1 text-xs text-red-500 transition duration-300 ease-in-out"
|
||||
className="mt-1 text-xs text-text-destructive transition duration-300 ease-in-out"
|
||||
role="alert"
|
||||
>
|
||||
{localize('com_ui_field_required')}
|
||||
|
|
@ -139,13 +142,10 @@ export default function Instructions() {
|
|||
name="instructions"
|
||||
control={control}
|
||||
render={({ field }) => (
|
||||
<textarea
|
||||
<Textarea
|
||||
{...field}
|
||||
value={field.value ?? ''}
|
||||
className={cn(
|
||||
textareaClass,
|
||||
'min-h-0 flex-1 resize-none text-base leading-relaxed',
|
||||
)}
|
||||
className="min-h-0 flex-1 resize-none text-base leading-relaxed"
|
||||
placeholder={localize('com_agents_instructions_placeholder')}
|
||||
aria-label={localize('com_ui_instructions')}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { useState, useEffect, useRef } from 'react';
|
||||
import { SquirclePlusIcon } from '@librechat/client';
|
||||
import { Button, SquirclePlusIcon } from '@librechat/client';
|
||||
import { useLocalize } from '~/hooks';
|
||||
|
||||
interface MCPIconProps {
|
||||
|
|
@ -27,22 +27,13 @@ export default function MCPIcon({ icon, onIconChange }: MCPIconProps) {
|
|||
}
|
||||
};
|
||||
|
||||
const handleKeyDown = (e: React.KeyboardEvent) => {
|
||||
if (e.key === 'Enter' || e.key === ' ') {
|
||||
e.preventDefault();
|
||||
handleClick();
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="flex items-center gap-4">
|
||||
<div
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
<Button
|
||||
variant="ghost"
|
||||
onClick={handleClick}
|
||||
onKeyDown={handleKeyDown}
|
||||
aria-label={localize('com_ui_upload_icon')}
|
||||
className="bg-token-surface-secondary dark:bg-token-surface-tertiary border-token-border-medium flex h-16 w-16 shrink-0 cursor-pointer items-center justify-center rounded-xl border-2 border-dashed focus:outline-none focus-visible:ring-2 focus-visible:ring-border-heavy"
|
||||
className="flex h-16 w-16 shrink-0 items-center justify-center rounded-xl border-2 border-dashed border-border-medium bg-surface-secondary p-0 hover:bg-surface-hover"
|
||||
>
|
||||
{previewUrl ? (
|
||||
<img
|
||||
|
|
@ -55,7 +46,7 @@ export default function MCPIcon({ icon, onIconChange }: MCPIconProps) {
|
|||
) : (
|
||||
<SquirclePlusIcon />
|
||||
)}
|
||||
</div>
|
||||
</Button>
|
||||
<div className="flex flex-col gap-1">
|
||||
<span className="token-text-secondary text-sm">
|
||||
{localize('com_ui_icon')} {localize('com_ui_optional')}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { useState } from 'react';
|
||||
import { TooltipAnchor } from '@librechat/client';
|
||||
import { Check, Clock, Code2, Info } from 'lucide-react';
|
||||
import { Button, TooltipAnchor } from '@librechat/client';
|
||||
import type { AgentToolType } from 'librechat-data-provider';
|
||||
import { useLocalize } from '~/hooks';
|
||||
import { cn } from '~/utils';
|
||||
|
|
@ -17,8 +17,7 @@ interface MCPToolItemProps {
|
|||
onToggleProgrammatic: () => void;
|
||||
}
|
||||
|
||||
const iconButton =
|
||||
'flex size-6 items-center justify-center rounded-md transition-colors hover:bg-surface-hover focus:outline-none focus-visible:ring-2 focus-visible:ring-ring-primary';
|
||||
const iconButton = 'size-6 rounded-md';
|
||||
|
||||
export default function MCPToolItem({
|
||||
tool,
|
||||
|
|
@ -69,8 +68,8 @@ export default function MCPToolItem({
|
|||
description={localize('com_ui_mcp_click_to_defer')}
|
||||
side="top"
|
||||
render={
|
||||
<button
|
||||
type="button"
|
||||
<Button
|
||||
variant="ghost"
|
||||
onClick={onToggleDefer}
|
||||
aria-pressed={isDeferred}
|
||||
aria-label={localize('com_ui_mcp_defer_loading')}
|
||||
|
|
@ -80,7 +79,7 @@ export default function MCPToolItem({
|
|||
)}
|
||||
>
|
||||
<Clock className="size-4" aria-hidden="true" />
|
||||
</button>
|
||||
</Button>
|
||||
}
|
||||
/>
|
||||
)}
|
||||
|
|
@ -89,8 +88,8 @@ export default function MCPToolItem({
|
|||
description={localize('com_ui_mcp_click_to_programmatic')}
|
||||
side="top"
|
||||
render={
|
||||
<button
|
||||
type="button"
|
||||
<Button
|
||||
variant="ghost"
|
||||
onClick={onToggleProgrammatic}
|
||||
aria-pressed={isProgrammatic}
|
||||
aria-label={localize('com_ui_mcp_programmatic')}
|
||||
|
|
@ -102,12 +101,12 @@ export default function MCPToolItem({
|
|||
)}
|
||||
>
|
||||
<Code2 className="size-4" aria-hidden="true" />
|
||||
</button>
|
||||
</Button>
|
||||
}
|
||||
/>
|
||||
)}
|
||||
<button
|
||||
type="button"
|
||||
<Button
|
||||
variant="ghost"
|
||||
onClick={() => setExpanded((value) => !value)}
|
||||
aria-expanded={expanded}
|
||||
aria-controls={detailsId}
|
||||
|
|
@ -118,7 +117,7 @@ export default function MCPToolItem({
|
|||
)}
|
||||
>
|
||||
<Info className="size-4" aria-hidden="true" />
|
||||
</button>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
{/* Auto-height reveal via grid-template-rows 0fr -> 1fr so the panel — and
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import { memo } from 'react';
|
|||
import { AgentCapabilities } from 'librechat-data-provider';
|
||||
import { useFormContext, Controller } from 'react-hook-form';
|
||||
import {
|
||||
Button,
|
||||
Checkbox,
|
||||
HoverCard,
|
||||
HoverCardContent,
|
||||
|
|
@ -44,13 +45,13 @@ function Memory() {
|
|||
{localize('com_agents_enable_memory')}
|
||||
</label>
|
||||
<HoverCardTrigger asChild className="ml-2">
|
||||
<button
|
||||
type="button"
|
||||
className="inline-flex items-center"
|
||||
<Button
|
||||
variant="ghost"
|
||||
aria-label={localize('com_agents_memory_info')}
|
||||
className="inline-flex h-4 w-4 items-center justify-center rounded p-0 text-text-tertiary hover:bg-transparent"
|
||||
>
|
||||
<CircleHelpIcon className="h-4 w-4 text-text-tertiary" />
|
||||
</button>
|
||||
<CircleHelpIcon className="h-4 w-4" aria-hidden={true} />
|
||||
</Button>
|
||||
</HoverCardTrigger>
|
||||
<HoverCardPortal>
|
||||
<HoverCardContent side={ESide.Top} className="w-80">
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import React, { useMemo, useEffect } from 'react';
|
||||
import keyBy from 'lodash/keyBy';
|
||||
import { ControlCombobox } from '@librechat/client';
|
||||
import { ChevronLeft, RotateCcw } from 'lucide-react';
|
||||
import { Button, ControlCombobox } from '@librechat/client';
|
||||
import { useFormContext, useWatch, Controller } from 'react-hook-form';
|
||||
import {
|
||||
alternateName,
|
||||
|
|
@ -105,14 +105,15 @@ export default function ModelPanel({
|
|||
return (
|
||||
<div className="mb-1 flex w-full flex-col gap-3 text-sm">
|
||||
<header className="grid grid-cols-[auto_1fr_auto] items-center gap-2 pt-1">
|
||||
<button
|
||||
type="button"
|
||||
<Button
|
||||
variant="outline"
|
||||
size="icon"
|
||||
onClick={() => setActivePanel(Panel.builder)}
|
||||
aria-label={localize('com_ui_back_to_builder')}
|
||||
className="inline-flex h-10 w-10 flex-shrink-0 items-center justify-center rounded-xl border border-border-light text-text-secondary transition-colors hover:bg-surface-secondary hover:text-text-primary focus:outline-none focus-visible:ring-2 focus-visible:ring-ring-primary"
|
||||
className="h-10 w-10 flex-shrink-0 rounded-xl text-text-secondary hover:bg-surface-secondary hover:text-text-primary"
|
||||
>
|
||||
<ChevronLeft className="h-5 w-5" strokeWidth={1.75} aria-hidden="true" />
|
||||
</button>
|
||||
</Button>
|
||||
<h2 className="text-center text-base font-semibold text-text-primary">
|
||||
{localize('com_ui_model_parameters')}
|
||||
</h2>
|
||||
|
|
@ -250,14 +251,14 @@ export default function ModelPanel({
|
|||
</div>
|
||||
)}
|
||||
{/* Reset Parameters Button */}
|
||||
<button
|
||||
type="button"
|
||||
<Button
|
||||
variant="outline"
|
||||
onClick={handleResetParameters}
|
||||
className="mt-2 inline-flex h-9 w-full items-center justify-center gap-2 rounded-xl border border-border-light bg-transparent px-4 text-sm font-medium text-text-secondary transition-colors hover:bg-surface-secondary hover:text-text-primary focus:outline-none focus-visible:ring-2 focus-visible:ring-ring-primary"
|
||||
className="mt-2 h-9 w-full rounded-xl px-4 font-medium text-text-secondary hover:bg-surface-secondary hover:text-text-primary"
|
||||
>
|
||||
<RotateCcw className="h-4 w-4" strokeWidth={1.75} aria-hidden="true" />
|
||||
{localize('com_ui_reset_var', { 0: localize('com_ui_model_parameters') })}
|
||||
</button>
|
||||
</Button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,8 +7,8 @@ import {
|
|||
ScraperProviders,
|
||||
SearchCategories,
|
||||
} from 'librechat-data-provider';
|
||||
import type { SearchApiKeyFormData } from '~/hooks/Plugins/useAuthSearchTool';
|
||||
import type { UseFormRegister, UseFormHandleSubmit } from 'react-hook-form';
|
||||
import type { SearchApiKeyFormData } from '~/hooks/Plugins/useAuthSearchTool';
|
||||
import InputSection, { type DropdownOption } from './InputSection';
|
||||
import { useGetStartupConfig } from '~/data-provider';
|
||||
import { useLocalize } from '~/hooks';
|
||||
|
|
@ -273,16 +273,12 @@ export default function ApiKeyDialog({
|
|||
}
|
||||
selection={{
|
||||
selectHandler: handleSubmit(onSubmit),
|
||||
selectClasses: 'bg-green-500 hover:bg-green-600 text-white',
|
||||
selectClasses: 'bg-surface-submit hover:bg-surface-submit-hover text-white',
|
||||
selectText: localize('com_ui_save'),
|
||||
}}
|
||||
buttons={
|
||||
isToolAuthenticated && (
|
||||
<Button
|
||||
onClick={onRevoke}
|
||||
className="bg-red-500 text-white hover:bg-red-600"
|
||||
aria-label={localize('com_ui_revoke')}
|
||||
>
|
||||
<Button variant="destructive" onClick={onRevoke} aria-label={localize('com_ui_revoke')}>
|
||||
{localize('com_ui_revoke')}
|
||||
</Button>
|
||||
)
|
||||
|
|
|
|||
|
|
@ -132,7 +132,7 @@ export default function ActionEditor({
|
|||
});
|
||||
},
|
||||
selectClasses:
|
||||
'bg-red-700 dark:bg-red-600 hover:bg-red-800 dark:hover:bg-red-800 transition-color duration-200 text-white',
|
||||
'bg-surface-destructive text-white transition-colors duration-200 hover:bg-surface-destructive-hover',
|
||||
selectText: localize('com_ui_delete'),
|
||||
}}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -251,8 +251,9 @@ export default function McpSection({ item }: Props) {
|
|||
}
|
||||
side="top"
|
||||
render={
|
||||
<button
|
||||
type="button"
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
onClick={() => toggleDeferAll(tools)}
|
||||
aria-pressed={allDeferred}
|
||||
aria-label={
|
||||
|
|
@ -261,15 +262,14 @@ export default function McpSection({ item }: Props) {
|
|||
: localize('com_ui_mcp_defer_all')
|
||||
}
|
||||
className={cn(
|
||||
'flex size-7 items-center justify-center rounded-md transition-colors',
|
||||
'hover:bg-surface-hover focus:outline-none focus-visible:ring-2 focus-visible:ring-ring-primary',
|
||||
'size-7 rounded-md',
|
||||
allDeferred
|
||||
? 'text-amber-600 dark:text-amber-500'
|
||||
: 'text-text-secondary hover:text-text-primary',
|
||||
)}
|
||||
>
|
||||
<Clock className="size-4" aria-hidden="true" />
|
||||
</button>
|
||||
</Button>
|
||||
}
|
||||
/>
|
||||
)}
|
||||
|
|
@ -282,8 +282,9 @@ export default function McpSection({ item }: Props) {
|
|||
}
|
||||
side="top"
|
||||
render={
|
||||
<button
|
||||
type="button"
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
onClick={() => toggleProgrammaticAll(tools)}
|
||||
aria-pressed={allProgrammatic}
|
||||
aria-label={
|
||||
|
|
@ -292,15 +293,14 @@ export default function McpSection({ item }: Props) {
|
|||
: localize('com_ui_mcp_programmatic_all')
|
||||
}
|
||||
className={cn(
|
||||
'flex size-7 items-center justify-center rounded-md transition-colors',
|
||||
'hover:bg-surface-hover focus:outline-none focus-visible:ring-2 focus-visible:ring-ring-primary',
|
||||
'size-7 rounded-md',
|
||||
allProgrammatic
|
||||
? 'text-violet-600 dark:text-violet-500'
|
||||
: 'text-text-secondary hover:text-text-primary',
|
||||
)}
|
||||
>
|
||||
<Code2 className="size-4" aria-hidden="true" />
|
||||
</button>
|
||||
</Button>
|
||||
}
|
||||
/>
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { useState } from 'react';
|
||||
import { CheckCircle2 } from 'lucide-react';
|
||||
import { useFormContext } from 'react-hook-form';
|
||||
import { useToastContext } from '@librechat/client';
|
||||
import { Button, useToastContext } from '@librechat/client';
|
||||
import { useUpdateUserPluginsMutation } from 'librechat-data-provider/react-query';
|
||||
import type { TError, TPluginAction } from 'librechat-data-provider';
|
||||
import type { ToolItem } from '../../items/types';
|
||||
|
|
@ -74,13 +74,13 @@ export default function ToolSection({ item }: Props) {
|
|||
<CheckCircle2 className="size-4 text-emerald-500" aria-hidden="true" />
|
||||
{localize('com_ui_tools_info_configured')}
|
||||
</span>
|
||||
<button
|
||||
type="button"
|
||||
<Button
|
||||
variant="ghost"
|
||||
onClick={() => setEditing(true)}
|
||||
className="rounded-md px-2 py-1 text-xs font-medium text-text-secondary transition-colors hover:bg-surface-hover hover:text-text-primary focus:outline-none focus-visible:ring-2 focus-visible:ring-ring-primary"
|
||||
className="h-auto rounded-md px-2 py-1 text-xs font-medium text-text-secondary"
|
||||
>
|
||||
{localize('com_ui_edit')}
|
||||
</button>
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
{showForm && (
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import { PermissionTypes, Permissions } from 'librechat-data-provider';
|
|||
import {
|
||||
Radio,
|
||||
Input,
|
||||
Label,
|
||||
Button,
|
||||
OGDialog,
|
||||
OGDialogTitle,
|
||||
|
|
@ -193,9 +194,9 @@ export default function SkillsDialog({ open, onOpenChange, agentId }: SkillsDial
|
|||
/>
|
||||
</div>
|
||||
<CategoryFilter options={categoryOptions} value={category} onChange={setCategory} />
|
||||
<label id="skills-view-label" className="sr-only">
|
||||
<Label id="skills-view-label" className="sr-only">
|
||||
{localize('com_ui_skills_filter')}
|
||||
</label>
|
||||
</Label>
|
||||
<Radio
|
||||
options={viewOptions}
|
||||
value={view}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import { memo, useState } from 'react';
|
||||
import { Button } from '@librechat/client';
|
||||
import { Info, Settings, X } from 'lucide-react';
|
||||
import type { TranslationKeys } from '~/hooks/useLocalize';
|
||||
import type { AgentItem } from './items/types';
|
||||
|
|
@ -78,32 +79,30 @@ function ToolRowImpl({ item, onInfo, onRemove }: Props) {
|
|||
'group-focus-within:opacity-100 group-hover:opacity-100',
|
||||
)}
|
||||
>
|
||||
<button
|
||||
type="button"
|
||||
<Button
|
||||
variant="ghost"
|
||||
onClick={() => onInfo(item)}
|
||||
aria-label={
|
||||
configurable ? localize('com_ui_tools_configure') : localize('com_ui_tools_info')
|
||||
}
|
||||
className={cn(
|
||||
'flex size-6 items-center justify-center rounded-md text-text-secondary',
|
||||
'hover:bg-surface-hover hover:text-text-primary',
|
||||
'focus:outline-none focus-visible:opacity-100 focus-visible:ring-2 focus-visible:ring-ring-primary',
|
||||
'size-6 rounded-md p-0 text-text-secondary',
|
||||
'hover:text-text-primary focus-visible:opacity-100',
|
||||
)}
|
||||
>
|
||||
<DetailIcon className="size-3.5" aria-hidden="true" />
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
</Button>
|
||||
<Button
|
||||
variant="ghost"
|
||||
onClick={() => onRemove(item)}
|
||||
aria-label={localize('com_ui_tools_remove')}
|
||||
className={cn(
|
||||
'flex size-6 items-center justify-center rounded-md text-text-secondary',
|
||||
'hover:bg-surface-hover hover:text-text-primary',
|
||||
'focus:outline-none focus-visible:opacity-100 focus-visible:ring-2 focus-visible:ring-ring-primary',
|
||||
'size-6 rounded-md p-0 text-text-secondary',
|
||||
'hover:text-text-primary focus-visible:opacity-100',
|
||||
)}
|
||||
>
|
||||
<X className="size-3.5" aria-hidden="true" />
|
||||
</button>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -340,7 +340,7 @@ export default function ToolsSection({ agentId }: Props) {
|
|||
selection={{
|
||||
selectHandler: confirmActionRemoval,
|
||||
selectClasses:
|
||||
'bg-red-700 dark:bg-red-600 hover:bg-red-800 dark:hover:bg-red-800 transition-color duration-200 text-white',
|
||||
'bg-surface-destructive hover:bg-surface-destructive-hover transition-colors duration-200 text-white',
|
||||
selectText: localize('com_ui_delete'),
|
||||
}}
|
||||
/>
|
||||
|
|
@ -365,7 +365,7 @@ export default function ToolsSection({ agentId }: Props) {
|
|||
selection={{
|
||||
selectHandler: confirmMcpRemoval,
|
||||
selectClasses:
|
||||
'bg-red-700 dark:bg-red-600 hover:bg-red-800 dark:hover:bg-red-800 transition-color duration-200 text-white',
|
||||
'bg-surface-destructive hover:bg-surface-destructive-hover transition-colors duration-200 text-white',
|
||||
selectText: localize('com_ui_delete'),
|
||||
}}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -70,6 +70,16 @@ jest.mock('../ItemDialog/ItemDialog', () => ({
|
|||
|
||||
jest.mock('@librechat/client', () => ({
|
||||
useToastContext: () => ({ showToast: jest.fn() }),
|
||||
Button: ({
|
||||
children,
|
||||
variant: _variant,
|
||||
size: _size,
|
||||
...rest
|
||||
}: React.ComponentProps<'button'> & { variant?: string; size?: string }) => (
|
||||
<button type="button" {...rest}>
|
||||
{children}
|
||||
</button>
|
||||
),
|
||||
Label: ({ children }: { children?: React.ReactNode }) => <span>{children}</span>,
|
||||
OGDialog: ({ open, children }: { open?: boolean; children?: React.ReactNode }) =>
|
||||
open ? <div>{children}</div> : null,
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import { History } from 'lucide-react';
|
||||
import { Button } from '@librechat/client';
|
||||
import { useLocalize } from '~/hooks';
|
||||
import { Panel } from '~/common';
|
||||
|
||||
|
|
@ -10,15 +11,15 @@ const VersionButton = ({ setActivePanel }: VersionButtonProps) => {
|
|||
const localize = useLocalize();
|
||||
|
||||
return (
|
||||
<button
|
||||
type="button"
|
||||
<Button
|
||||
variant="subtle"
|
||||
onClick={() => setActivePanel(Panel.version)}
|
||||
aria-label={localize('com_ui_agent_version')}
|
||||
className="inline-flex h-9 w-full items-center justify-center gap-2 rounded-xl border border-border-light bg-transparent px-3 text-sm font-medium text-text-primary transition-colors hover:bg-surface-secondary focus:outline-none focus-visible:ring-2 focus-visible:ring-ring-primary"
|
||||
className="h-9 w-full px-3"
|
||||
>
|
||||
<History className="h-4 w-4" strokeWidth={1.75} aria-hidden="true" />
|
||||
{localize('com_ui_agent_version')}
|
||||
</button>
|
||||
</Button>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -24,9 +24,9 @@ function EmptyState({
|
|||
const iconWrapBase = 'mb-3 flex h-12 w-12 items-center justify-center rounded-full border';
|
||||
const iconWrapTone =
|
||||
tone === 'danger'
|
||||
? 'border-red-200 bg-red-50 text-red-500 dark:border-red-900/50 dark:bg-red-950/30 dark:text-red-400'
|
||||
? 'border-status-error-border bg-status-error-subtle text-text-destructive'
|
||||
: 'border-border-light bg-surface-secondary text-text-secondary';
|
||||
const textTone = tone === 'danger' ? 'text-red-600 dark:text-red-400' : 'text-text-secondary';
|
||||
const textTone = tone === 'danger' ? 'text-text-destructive' : 'text-text-secondary';
|
||||
|
||||
return (
|
||||
<div className="flex flex-col items-center justify-center px-4 py-12 text-center">
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import { formatDistanceToNow } from 'date-fns';
|
|||
import { Check, RotateCcw, Circle } from 'lucide-react';
|
||||
import {
|
||||
Label,
|
||||
Button,
|
||||
OGDialog,
|
||||
OGDialogTrigger,
|
||||
OGDialogTemplate,
|
||||
|
|
@ -159,13 +160,14 @@ export default function VersionItem({
|
|||
description={localize('com_ui_agent_version_restore')}
|
||||
side="left"
|
||||
render={
|
||||
<button
|
||||
type="button"
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
aria-label={localize('com_ui_agent_version_restore')}
|
||||
className="inline-flex h-7 w-7 flex-shrink-0 items-center justify-center rounded-lg border border-border-light text-text-secondary opacity-0 transition-all hover:border-border-medium hover:bg-surface-hover hover:text-text-primary focus:outline-none focus-visible:opacity-100 focus-visible:ring-2 focus-visible:ring-ring-primary group-hover:opacity-100"
|
||||
className="size-7 flex-shrink-0 rounded-lg border border-border-light text-text-secondary opacity-0 transition-all hover:border-border-medium focus:outline-none focus-visible:opacity-100 group-hover:opacity-100"
|
||||
>
|
||||
<RotateCcw className="h-3.5 w-3.5" strokeWidth={1.75} aria-hidden="true" />
|
||||
</button>
|
||||
</Button>
|
||||
}
|
||||
/>
|
||||
</OGDialogTrigger>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { useCallback, useMemo } from 'react';
|
||||
import { ChevronLeft } from 'lucide-react';
|
||||
import { useToastContext } from '@librechat/client';
|
||||
import { Button, useToastContext } from '@librechat/client';
|
||||
import type { AgentWithVersions, VersionContext, VersionRecord } from './types';
|
||||
import {
|
||||
useGetAgentVersionsQuery,
|
||||
|
|
@ -141,14 +141,15 @@ export default function VersionPanel() {
|
|||
return (
|
||||
<div className="scrollbar-gutter-stable h-full min-h-[40vh] overflow-auto pb-12 text-sm">
|
||||
<header className="grid grid-cols-[auto_1fr_auto] items-center gap-2 px-2 pb-2 pt-1">
|
||||
<button
|
||||
type="button"
|
||||
<Button
|
||||
variant="subtle"
|
||||
size="icon"
|
||||
onClick={() => setActivePanel(Panel.builder)}
|
||||
aria-label={localize('com_ui_back_to_builder')}
|
||||
className="inline-flex h-10 w-10 flex-shrink-0 items-center justify-center rounded-xl border border-border-light text-text-secondary transition-colors hover:bg-surface-secondary hover:text-text-primary focus:outline-none focus-visible:ring-2 focus-visible:ring-ring-primary"
|
||||
className="flex-shrink-0 text-text-secondary hover:text-text-primary"
|
||||
>
|
||||
<ChevronLeft className="h-5 w-5" strokeWidth={1.75} aria-hidden="true" />
|
||||
</button>
|
||||
</Button>
|
||||
<div className="flex flex-col items-center">
|
||||
<h2 className="text-base font-semibold text-text-primary">
|
||||
{localize('com_ui_agent_version_history')}
|
||||
|
|
|
|||
|
|
@ -27,6 +27,8 @@ jest.mock('@librechat/client', () => {
|
|||
const React = jest.requireActual('react');
|
||||
return {
|
||||
Label: ({ children, ...rest }: any) => React.createElement('label', rest, children),
|
||||
Button: ({ children, variant: _variant, size: _size, ...rest }: any) =>
|
||||
React.createElement('button', rest, children),
|
||||
TooltipAnchor: ({ render }: { render: React.ReactNode }) => render,
|
||||
OGDialog: ({ children }: any) => React.createElement(React.Fragment, null, children),
|
||||
OGDialogTrigger: ({ children }: any) => children,
|
||||
|
|
|
|||
|
|
@ -157,6 +157,14 @@ jest.mock('../DuplicateAgent', () => ({
|
|||
|
||||
jest.mock('@librechat/client', () => ({
|
||||
Spinner: () => <div data-testid="spinner" />,
|
||||
Button: ({
|
||||
children,
|
||||
variant: _variant,
|
||||
size: _size,
|
||||
...props
|
||||
}: React.ComponentProps<'button'> & { variant?: string; size?: string }) => (
|
||||
<button {...props}>{children}</button>
|
||||
),
|
||||
}));
|
||||
|
||||
jest.mock('~/components/Sharing', () => ({
|
||||
|
|
|
|||
|
|
@ -56,6 +56,14 @@ jest.mock('@ariakit/react', () => ({
|
|||
}));
|
||||
|
||||
jest.mock('@librechat/client', () => ({
|
||||
Button: ({
|
||||
children,
|
||||
variant: _variant,
|
||||
size: _size,
|
||||
...props
|
||||
}: React.ComponentProps<'button'> & { variant?: string; size?: string }) => (
|
||||
<button {...props}>{children}</button>
|
||||
),
|
||||
SharePointIcon: () => <span />,
|
||||
DropdownPopup: () => null,
|
||||
TooltipAnchor: ({ render }: { render: React.ReactElement }) => render,
|
||||
|
|
|
|||
|
|
@ -9,6 +9,14 @@ jest.mock('~/hooks', () => ({
|
|||
|
||||
jest.mock('@librechat/client', () => ({
|
||||
TooltipAnchor: ({ render }: { render: React.ReactElement }) => render,
|
||||
Button: ({
|
||||
children,
|
||||
variant: _variant,
|
||||
size: _size,
|
||||
...props
|
||||
}: React.ComponentProps<'button'> & { variant?: string; size?: string }) => (
|
||||
<button {...props}>{children}</button>
|
||||
),
|
||||
}));
|
||||
|
||||
const tool = {
|
||||
|
|
|
|||
|
|
@ -1091,7 +1091,10 @@
|
|||
"com_ui_delete_tool": "Delete Tool",
|
||||
"com_ui_delete_tool_confirm": "Are you sure you want to delete this tool?",
|
||||
"com_ui_delete_tool_error": "Error removing the tool's saved credentials.",
|
||||
"com_ui_delete_tool_error_var": "Error while deleting the tool: {{0}}",
|
||||
"com_ui_delete_tool_save_reminder": "Tool removed. Save the agent to apply changes.",
|
||||
"com_ui_delete_tool_success": "Tool deleted successfully",
|
||||
"com_ui_delete_var": "Delete {{0}}",
|
||||
"com_ui_deleted": "Deleted",
|
||||
"com_ui_deleting": "Deleting...",
|
||||
"com_ui_deleting_file": "Deleting file...",
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue