fix: resolve ESLint and frontend test failures

- Format with prettier (Alert, MCPStatusBadge, ApiKeys, Memory, etc.) after
  --no-verify commits skipped the hook
- Localize the 'Or' auth divider (com_auth_or) instead of a bare literal
- Drop dead InvocationModePicker imports in Skill forms; fix VerifyEmail
  unused arg + useEffect deps
- Revert out-of-scope color edits in legacy Files/VectorStore views that
  carried pre-existing untranslated-string lint debt
- Update Memory tests to assert status-* tokens (text-status-error,
  bg-status-error-subtle) instead of the old hardcoded red classes
This commit is contained in:
Marco Beretta 2026-06-22 17:52:54 +02:00
parent 53269ddf4f
commit fc5d3bc949
No known key found for this signature in database
GPG key ID: D918033D8E74CC11
30 changed files with 118 additions and 162 deletions

View file

@ -208,11 +208,7 @@ export const ErrorDisplay: React.FC<ErrorDisplayProps> = ({ error, onRetry, cont
<h3 className="text-lg font-semibold text-text-primary" id="error-title">
{title}
</h3>
<p
className="text-text-secondary"
id="error-message"
aria-describedby="error-title"
>
<p className="text-text-secondary" id="error-message" aria-describedby="error-title">
{message}
</p>
<p
@ -232,9 +228,7 @@ export const ErrorDisplay: React.FC<ErrorDisplayProps> = ({ error, onRetry, cont
onClick={onRetry}
variant="outline"
size="sm"
className={cn(
'border-status-error text-status-error hover:bg-status-error-subtle',
)}
className={cn('border-status-error text-status-error hover:bg-status-error-subtle')}
aria-describedby="error-message error-suggestion"
aria-label={`Retry action. ${message}`}
>

View file

@ -39,7 +39,10 @@ function AuthLayout({
<div className="mx-auto sm:max-w-sm">
<ErrorMessage>
{localize('com_auth_error_invalid_reset_token')}{' '}
<a className="font-semibold text-accent-primary hover:underline" href="/forgot-password">
<a
className="font-semibold text-accent-primary hover:underline"
href="/forgot-password"
>
{localize('com_auth_click_here')}
</a>{' '}
{localize('com_auth_to_try_again')}

View file

@ -123,7 +123,9 @@ function SocialLoginRender({
{startupConfig.emailLoginEnabled && (
<>
<div className="relative mt-6 flex w-full items-center justify-center border border-t border-border-medium uppercase">
<div className="absolute bg-surface-primary px-3 text-xs text-text-primary">Or</div>
<div className="absolute bg-surface-primary px-3 text-xs text-text-primary">
{localize('com_auth_or')}
</div>
</div>
<div className="mt-8" />
</>

View file

@ -36,7 +36,7 @@ function RequestPasswordReset() {
setVerificationStatus(true);
countdownRedirect();
},
onError: (error: unknown) => {
onError: (_error: unknown) => {
setHeaderText(localize('com_auth_email_verification_failed') + ' 😢');
setShowResendLink(true);
setVerificationStatus(true);
@ -74,7 +74,7 @@ function RequestPasswordReset() {
setShowResendLink(true);
setVerificationStatus(true);
}
}, [token, email, verificationStatus, verifyEmailMutation]);
}, [token, email, verificationStatus, verifyEmailMutation, localize]);
const VerificationSuccess = () => (
<div className="flex flex-col items-center justify-center">

View file

@ -2,22 +2,22 @@ import { DotsIcon, TrashIcon } from '@librechat/client';
export default function Template() {
return (
<div className="max-h-[28rem] overflow-y-auto rounded-md border border-border-light">
<div className="max-h-[28rem] overflow-y-auto rounded-md border border-black/10 dark:border-white/10">
<table className="w-full border-separate border-spacing-0">
<thead>
<tr>
<th className="sticky top-0 rounded-t border-b border-border-light bg-surface-primary px-4 py-2 text-left font-medium text-text-primary">
<th className="sticky top-0 rounded-t border-b border-black/10 bg-white px-4 py-2 text-left font-medium text-gray-700 dark:border-white/10 dark:bg-gray-900 dark:text-gray-100">
Name
</th>
<th className="sticky top-0 rounded-t border-b border-border-light bg-surface-primary px-4 py-2 text-left font-medium text-text-primary">
<th className="sticky top-0 rounded-t border-b border-black/10 bg-white px-4 py-2 text-left font-medium text-gray-700 dark:border-white/10 dark:bg-gray-900 dark:text-gray-100">
Date
</th>
<th className="sticky top-0 rounded-t border-b border-border-light bg-surface-primary px-4 py-2 text-left font-medium text-text-primary">
<th className="sticky top-0 rounded-t border-b border-black/10 bg-white px-4 py-2 text-left font-medium text-gray-700 dark:border-white/10 dark:bg-gray-900 dark:text-gray-100">
Size
</th>
<th className="sticky top-0 rounded-t border-b border-border-light bg-surface-primary px-4 py-2 text-right font-medium text-text-primary">
<th className="sticky top-0 rounded-t border-b border-black/10 bg-white px-4 py-2 text-right font-medium text-gray-700 dark:border-white/10 dark:bg-gray-900 dark:text-gray-100">
<button
className="text-text-secondary hover:text-text-primary radix-state-open:text-text-primary"
className="text-gray-500 hover:text-gray-600 radix-state-open:text-gray-600 dark:hover:text-gray-400 dark:radix-state-open:text-gray-400"
type="button"
id="radix-:r67:"
aria-haspopup="menu"
@ -31,18 +31,18 @@ export default function Template() {
</thead>
<tbody>
<tr className="">
<td className="border-b border-border-light text-left text-text-secondary [tr:last-child_&]:border-b-0">
<td className="border-b border-black/10 text-left text-gray-600 dark:border-white/10 dark:text-gray-300 [tr:last-child_&]:border-b-0">
<div className="px-4 py-2 [tr[data-disabled=true]_&]:opacity-50">
File Transfer: Node to FastAPI
</div>
</td>
<td className="border-b border-border-light text-left text-text-secondary [tr:last-child_&]:border-b-0">
<td className="border-b border-black/10 text-left text-gray-600 dark:border-white/10 dark:text-gray-300 [tr:last-child_&]:border-b-0">
<div className="px-4 py-2 [tr[data-disabled=true]_&]:opacity-50">June 11, 2023</div>
</td>
<td className="border-b border-border-light text-left text-text-secondary [tr:last-child_&]:border-b-0">
<td className="border-b border-black/10 text-left text-gray-600 dark:border-white/10 dark:text-gray-300 [tr:last-child_&]:border-b-0">
<div className="px-4 py-2 [tr[data-disabled=true]_&]:opacity-50">11 mb</div>
</td>
<td className="border-b border-border-light text-left text-text-secondary [tr:last-child_&]:border-b-0">
<td className="border-b border-black/10 text-left text-gray-600 dark:border-white/10 dark:text-gray-300 [tr:last-child_&]:border-b-0">
<div className="px-4 py-2 [tr[data-disabled=true]_&]:opacity-50">
<div className="flex items-center justify-end gap-2">
<span className="" data-state="closed">
@ -51,7 +51,7 @@ export default function Template() {
target="_blank"
rel="noreferrer"
aria-label="View source chat"
className="text-text-secondary hover:text-text-primary"
className="text-gray-500 hover:text-gray-600 dark:hover:text-gray-400"
>
<svg
stroke="currentColor"
@ -72,7 +72,7 @@ export default function Template() {
<span className="" data-state="closed">
<button
aria-label="Delete shared link"
className="text-text-secondary hover:text-text-primary"
className="text-gray-500 hover:text-gray-600 dark:hover:text-gray-400"
>
<TrashIcon />
</button>

View file

@ -199,7 +199,10 @@ export function SearchResults({ results, localize, searchValue }: SearchResultsP
<span>{modelName}</span>
</div>
{isGlobal && (
<EarthIcon className="ml-auto size-4 text-accent-primary" aria-hidden="true" />
<EarthIcon
className="ml-auto size-4 text-accent-primary"
aria-hidden="true"
/>
)}
{isModelSelected && (
<>

View file

@ -88,9 +88,7 @@ export default function MemoryArtifacts({ attachments }: { attachments?: TAttach
<button
className={cn(
'outline-hidden my-1 flex items-center gap-1 text-sm font-semibold transition-colors',
hasErrors
? 'text-status-error'
: 'text-text-secondary-alt hover:text-text-primary',
hasErrors ? 'text-status-error' : 'text-text-secondary-alt hover:text-text-primary',
)}
type="button"
onClick={() => setShowInfo((prev) => !prev)}

View file

@ -100,9 +100,7 @@ export default function ProgressText({
{icon}
<span className={cn(showShimmer ? 'shimmer' : '', 'font-medium')}>{text}</span>
{subtitle && <span className="font-normal text-text-secondary">{subtitle}</span>}
{errorSuffix && (
<span className="font-normal text-status-error"> {errorSuffix}</span>
)}
{errorSuffix && <span className="font-normal text-status-error"> {errorSuffix}</span>}
{hasInput && (
<ChevronDown
className={cn(

View file

@ -54,10 +54,7 @@ describe('MemoryArtifacts', () => {
render(<MemoryArtifacts attachments={attachments} />);
const button = screen.getByRole('button');
expect(button).toHaveClass('text-red-500');
expect(button).toHaveClass('hover:text-red-600');
expect(button).toHaveClass('dark:text-red-400');
expect(button).toHaveClass('dark:hover:text-red-500');
expect(button).toHaveClass('text-status-error');
});
test('displays normal styling when no errors present', () => {
@ -71,7 +68,7 @@ describe('MemoryArtifacts', () => {
const button = screen.getByRole('button');
expect(button).toHaveClass('text-text-secondary-alt');
expect(button).toHaveClass('hover:text-text-primary');
expect(button).not.toHaveClass('text-red-500');
expect(button).not.toHaveClass('text-status-error');
});
test('displays error message when errors are present', () => {
@ -121,7 +118,7 @@ describe('MemoryArtifacts', () => {
render(<MemoryArtifacts attachments={attachments} />);
const button = screen.getByRole('button');
expect(button).toHaveClass('text-red-500');
expect(button).toHaveClass('text-status-error');
expect(screen.getByText('Memory Error')).toBeInTheDocument();
});
});
@ -190,7 +187,7 @@ describe('MemoryArtifacts', () => {
render(<MemoryArtifacts attachments={attachments} />);
const button = screen.getByRole('button');
expect(button).toHaveClass('text-red-500');
expect(button).toHaveClass('text-status-error');
expect(screen.getByText('Memory Error')).toBeInTheDocument();
});
});

View file

@ -114,15 +114,12 @@ describe('MemoryInfo', () => {
const errorMessage = screen.getByText(
'Cannot save - would exceed limit by 50 tokens. Delete existing memories to make space.',
);
const errorContainer = errorMessage.closest('div');
const errorContainer = errorMessage.closest('[role="alert"]');
expect(errorContainer).toHaveClass('rounded-md');
expect(errorContainer).toHaveClass('bg-red-50');
expect(errorContainer).toHaveClass('bg-status-error-subtle');
expect(errorContainer).toHaveClass('text-status-error');
expect(errorContainer).toHaveClass('border-status-error-border');
expect(errorContainer).toHaveClass('p-3');
expect(errorContainer).toHaveClass('text-sm');
expect(errorContainer).toHaveClass('text-red-800');
expect(errorContainer).toHaveClass('dark:bg-red-900/20');
expect(errorContainer).toHaveClass('dark:text-red-400');
});
});

View file

@ -302,7 +302,7 @@ export default function Settings({
className={cn(
defaultTextProps,
optionText,
'flex rounded-md bg-transparent py-2 text-xs focus:outline-none focus:ring-2 focus:ring-ring-primary focus:ring-offset-2 border-border-light',
'flex rounded-md border-border-light bg-transparent py-2 text-xs focus:outline-none focus:ring-2 focus:ring-ring-primary focus:ring-offset-2',
'pointer-events-none max-h-5 w-12 border-0 group-hover/temp:border-border-light',
)}
/>

View file

@ -7,7 +7,7 @@ const FileDashboardView = () => {
const params = useParams();
const navigate = useNavigate();
return (
<div className="bg-surface-primary p-0 lg:p-7">
<div className="bg-[#f9f9f9] p-0 lg:p-7">
<div className="ml-3 mt-3 flex flex-row justify-between">
{params.vectorStoreId && (
<Button
@ -22,7 +22,7 @@ const FileDashboardView = () => {
</Button>
)}
</div>
<div className="flex h-screen max-w-full flex-row divide-x bg-surface-primary">
<div className="flex h-screen max-w-full flex-row divide-x bg-[#f9f9f9]">
<div className={`w-full lg:w-1/3 ${params.vectorStoreId ? 'hidden lg:block' : ''}`}>
<VectorStoreSidePanel />
</div>

View file

@ -10,18 +10,18 @@ type FileListItemProps = {
export default function FileListItem({ file, deleteFile, width = '400px' }: FileListItemProps) {
return (
<div className="w-100 my-3 mr-2 flex cursor-pointer flex-row rounded-md border border-0 bg-surface-secondary p-4 transition duration-300 ease-in-out hover:bg-surface-hover">
<div className="w-100 my-3 mr-2 flex cursor-pointer flex-row rounded-md border border-0 bg-white p-4 transition duration-300 ease-in-out hover:bg-slate-200">
<div className="flex w-1/2 flex-col justify-around align-middle">
<strong>{file.filename}</strong>
<p className="text-sm text-text-tertiary">{file.object}</p>
<p className="text-sm text-gray-500">{file.object}</p>
</div>
<div className="w-2/6 text-text-tertiary">
<div className="w-2/6 text-gray-500">
<p>({file.bytes / 1000}KB)</p>
<p className="text-sm">{file.createdAt?.toString()}</p>
</div>
<div className="flex w-1/6 justify-around">
<Button
className="my-0 ml-3 bg-transparent p-0 text-text-destructive hover:bg-surface-hover"
className="my-0 ml-3 bg-transparent p-0 text-[#666666] hover:bg-slate-200"
onClick={() => deleteFile(file._id)}
>
<TrashIcon className="m-0 p-0" />

View file

@ -22,7 +22,7 @@ export default function FileListItem2({
onClick={() => {
navigate('file_id_abcdef');
}}
className="w-100 mt-2 flex h-fit cursor-pointer flex-row rounded-md border border-0 bg-surface-secondary p-4 transition duration-300 ease-in-out hover:bg-surface-hover"
className="w-100 mt-2 flex h-fit cursor-pointer flex-row rounded-md border border-0 bg-white p-4 transition duration-300 ease-in-out hover:bg-slate-200"
>
<div className="flex w-10/12 flex-col justify-around md:flex-row">
<div className="flex w-2/5 flex-row">
@ -31,7 +31,7 @@ export default function FileListItem2({
</div>
<div className="w-3/4 content-center">{file.filename}</div>
</div>
<div className="flex w-fit flex-row flex-wrap text-text-tertiary md:w-3/5">
<div className="flex w-fit flex-row flex-wrap text-gray-500 md:w-3/5">
{attachedVectorStores.map((vectorStore, index) => {
if (index === 4) {
return (
@ -60,11 +60,11 @@ export default function FileListItem2({
</div>
</div>
<div className="mr-0 flex w-2/12 flex-col items-center justify-evenly sm:mr-4 md:flex-row">
<Button className="w-min content-center bg-transparent text-text-tertiary hover:bg-surface-hover">
<Button className="w-min content-center bg-transparent text-gray-500 hover:bg-slate-200">
<DotsIcon className="text-grey-100" />
</Button>
<Button
className="w-min bg-transparent text-text-destructive hover:bg-surface-hover"
className="w-min bg-transparent text-[#666666] hover:bg-slate-200"
onClick={() => deleteFile(file._id)}
>
<TrashIcon className="" />

View file

@ -44,7 +44,7 @@ export default function FilePreview() {
const params = useParams();
return (
<div className="m-3 bg-surface-primary p-2 sm:p-4 md:p-6 lg:p-10">
<div className="m-3 bg-white p-2 sm:p-4 md:p-6 lg:p-10">
<div className="flex flex-col justify-between md:flex-row">
<div className="flex flex-col">
<b className="hidden text-sm md:text-base lg:block lg:text-lg">FILE</b>
@ -73,18 +73,18 @@ export default function FilePreview() {
<div className="mt-3 flex flex-col">
<div className="flex flex-row">
<span className="flex w-1/2 flex-row items-center sm:w-1/4 md:w-2/5">
<InfoIcon className="size-4 text-text-tertiary" />
<InfoIcon className="size-4 text-gray-500" />
&nbsp; File ID
</span>
<span className="w-1/2 text-text-tertiary sm:w-3/4 md:w-3/5">{file._id}</span>
<span className="w-1/2 text-gray-500 sm:w-3/4 md:w-3/5">{file._id}</span>
</div>
<div className="mt-3 flex flex-row">
<span className="flex w-1/2 flex-row items-center sm:w-1/4 md:w-2/5">
<CircleIcon className="m-0 size-4 p-0 text-text-tertiary" />
<CircleIcon className="m-0 size-4 p-0 text-gray-500" />
&nbsp; Status
</span>
<div className="w-1/2 sm:w-3/4 md:w-3/5">
<span className="flex w-20 flex-row items-center justify-evenly rounded-full bg-status-success-subtle p-1 text-status-success">
<span className="flex w-20 flex-row items-center justify-evenly rounded-full bg-[#f2f8ec] p-1 text-[#91c561]">
<CheckMark className="m-0 p-0" />
<div>{file.object}</div>
</span>
@ -92,24 +92,24 @@ export default function FilePreview() {
</div>
<div className="mt-3 flex flex-row">
<span className="flex w-1/2 flex-row items-center sm:w-1/4 md:w-2/5">
<Clock3Icon className="m-0 size-4 p-0 text-text-tertiary" />
<Clock3Icon className="m-0 size-4 p-0 text-gray-500" />
&nbsp; Purpose
</span>
<span className="w-1/2 text-text-tertiary sm:w-3/4 md:w-3/5">{file.message}</span>
<span className="w-1/2 text-gray-500 sm:w-3/4 md:w-3/5">{file.message}</span>
</div>
<div className="mt-3 flex flex-row">
<span className="flex w-1/2 flex-row items-center sm:w-1/4 md:w-2/5">
<Clock3Icon className="m-0 size-4 p-0 text-text-tertiary" />
<Clock3Icon className="m-0 size-4 p-0 text-gray-500" />
&nbsp; Size
</span>
<span className="w-1/2 text-text-tertiary sm:w-3/4 md:w-3/5">{file.bytes}</span>
<span className="w-1/2 text-gray-500 sm:w-3/4 md:w-3/5">{file.bytes}</span>
</div>
<div className="mt-3 flex flex-row">
<span className="flex w-1/2 flex-row items-center sm:w-1/4 md:w-2/5">
<Clock3Icon className="m-0 size-4 p-0 text-text-tertiary" />
<Clock3Icon className="m-0 size-4 p-0 text-gray-500" />
&nbsp; Created At
</span>
<span className="w-1/2 text-text-tertiary sm:w-3/4 md:w-3/5">
<span className="w-1/2 text-gray-500 sm:w-3/4 md:w-3/5">
{file.createdAt?.toString()}
</span>
</div>
@ -133,7 +133,7 @@ export default function FilePreview() {
<div className="flex w-3/5 flex-row md:w-1/2 xl:w-1/3">
<div className="content-center text-nowrap">{vectors.created_at.toString()}</div>
<Button
className="m-0 ml-3 h-full bg-transparent p-0 text-text-destructive hover:bg-surface-hover"
className="m-0 ml-3 h-full bg-transparent p-0 text-[#666666] hover:bg-slate-200"
onClick={() => {
console.log('Remove from vector store');
}}
@ -161,7 +161,7 @@ export default function FilePreview() {
<div className="flex w-3/5 flex-row md:w-1/2 xl:w-1/3">
<div className="content-center text-nowrap">{thread.createdAt}</div>
<Button
className="m-0 ml-3 h-full bg-transparent p-0 text-text-destructive hover:bg-surface-hover"
className="m-0 ml-3 h-full bg-transparent p-0 text-[#666666] hover:bg-slate-200"
onClick={() => {
console.log('Remove from thread');
}}

View file

@ -9,7 +9,7 @@ type UploadFileProps = {
export default function UploadFileButton({ onClick }: UploadFileProps) {
return (
<div className="w-full">
<Button className="w-full bg-surface-inverted px-3 text-text-inverted" onClick={onClick}>
<Button className="w-full bg-black px-3 text-white" onClick={onClick}>
<PlusIcon className="h-4 w-4 font-bold" />
&nbsp; <span className="text-nowrap">Upload New File</span>
</Button>

View file

@ -18,11 +18,11 @@ const UploadFileModal = ({ open, onOpenChange }) => {
<Dialog open={open} onOpenChange={onOpenChange}>
<DialogContent
className={cn(
'w-11/12 overflow-x-auto bg-surface-dialog p-3 text-text-primary shadow-2xl lg:w-2/3 xl:w-2/5',
'w-11/12 overflow-x-auto p-3 shadow-2xl dark:bg-gray-700 dark:text-white lg:w-2/3 xl:w-2/5',
)}
>
<DialogHeader>
<DialogTitle className="text-lg font-medium leading-6 text-text-primary">
<DialogTitle className="text-lg font-medium leading-6 text-gray-900 dark:text-gray-200">
Upoad a File
</DialogTitle>
</DialogHeader>
@ -33,7 +33,7 @@ const UploadFileModal = ({ open, onOpenChange }) => {
</div>
<div className="flex w-full flex-col text-center sm:w-4/5 sm:text-left">
<div className="italic">Please upload square file, size less than 100KB</div>
<div className="mt-4 flex w-full flex-row items-center bg-surface-secondary p-2">
<div className="mt-4 flex w-full flex-row items-center bg-[#f9f9f9] p-2">
<div className="w-1/2 sm:w-1/3">
<Button>Choose File</Button>
</div>
@ -43,15 +43,13 @@ const UploadFileModal = ({ open, onOpenChange }) => {
</div>
<div className="mt-3 flex w-full flex-col">
<label htmlFor="name">Name</label>
<label className="hidden text-text-secondary sm:block">
The name of the uploaded file
</label>
<label className="hidden text-[#808080] sm:block">The name of the uploaded file</label>
<Input type="text" id="name" name="name" placeholder="Name" />
</div>
<div className="mt-3 flex w-full flex-col">
<label htmlFor="purpose">Purpose</label>
<label className="hidden text-text-secondary sm:block">
<label className="hidden text-[#808080] sm:block">
The purpose of the uploaded file
</label>
<Input type="text" id="purpose" name="purpose" placeholder="Purpose" />
@ -63,7 +61,7 @@ const UploadFileModal = ({ open, onOpenChange }) => {
</div>
<div className="flex w-full flex-row justify-evenly sm:w-1/3">
<Button
className="mr-3 w-full rounded-md border border-border-medium bg-surface-secondary p-0 text-text-primary hover:bg-surface-hover"
className="mr-3 w-full rounded-md border border-black bg-white p-0 text-black hover:bg-white"
onClick={() => {
onOpenChange(false);
}}
@ -71,7 +69,7 @@ const UploadFileModal = ({ open, onOpenChange }) => {
Cancel
</Button>
<Button
className="w-full rounded-md border border-border-xheavy bg-surface-inverted p-0 text-text-inverted"
className="w-full rounded-md border border-black bg-black p-0 text-white"
onClick={() => {
console.log('upload file');
}}

View file

@ -18,7 +18,7 @@ export default function FilesSectionSelector() {
const lightButton = { backgroundColor: '#f9f9f9', color: 'black' };
return (
<div className="flex h-12 w-52 flex-row justify-center rounded border bg-surface-secondary p-1">
<div className="flex h-12 w-52 flex-row justify-center rounded border bg-white p-1">
<div className="flex w-2/3 items-center pr-1">
<Button
className="w-full rounded rounded-lg border"

View file

@ -9,7 +9,7 @@ type VectorStoreButtonProps = {
export default function VectorStoreButton({ onClick }: VectorStoreButtonProps) {
return (
<div className="w-full">
<Button className="w-full bg-surface-inverted p-0 text-text-inverted" onClick={onClick}>
<Button className="w-full bg-black p-0 text-white" onClick={onClick}>
<PlusIcon className="h-4 w-4 font-bold" />
&nbsp; <span className="text-nowrap">Add Store</span>
</Button>

View file

@ -98,7 +98,7 @@ export default function VectorStorePreview() {
const params = useParams();
return (
<div className="m-3 ml-1 mr-7 bg-surface-primary p-2 sm:p-4 md:p-6 lg:p-10">
<div className="m-3 ml-1 mr-7 bg-white p-2 sm:p-4 md:p-6 lg:p-10">
<div className="flex flex-col justify-between md:flex-row">
<div className="flex flex-col">
<b className="hidden text-base md:text-lg lg:block lg:text-xl">VECTOR STORE</b>
@ -127,59 +127,57 @@ export default function VectorStorePreview() {
<div className="mt-3 flex flex-col">
<div className="flex flex-row">
<span className="flex w-1/2 flex-row items-center md:w-2/5">
<InfoIcon className="text-base text-text-tertiary md:text-lg lg:text-xl" />
<InfoIcon className="text-base text-gray-500 md:text-lg lg:text-xl" />
&nbsp; ID
</span>
<span className="w-1/2 break-words text-text-tertiary md:w-3/5">{vectorStore._id}</span>
<span className="w-1/2 break-words text-gray-500 md:w-3/5">{vectorStore._id}</span>
</div>
<div className="mt-3 flex flex-row">
<span className="flex w-1/2 flex-row items-center md:w-2/5">
<BarChart4Icon className="text-base text-text-tertiary md:text-lg lg:text-xl" />
<BarChart4Icon className="text-base text-gray-500 md:text-lg lg:text-xl" />
&nbsp;Usage this &nbsp;month
</span>
<div className="w-1/2 md:w-3/5">
<p className="text-text-tertiary">
<span className="text-status-success">0 KB hours</span>
<p className="text-gray-500">
<span className="text-[#91c561]">0 KB hours</span>
&nbsp; Free until end of 2024
</p>
</div>
</div>
<div className="mt-3 flex flex-row">
<span className="flex w-1/2 flex-row items-center md:w-2/5">
<InfoIcon className="text-base text-text-tertiary md:text-lg lg:text-xl" />
<InfoIcon className="text-base text-gray-500 md:text-lg lg:text-xl" />
&nbsp;Size
</span>
<span className="w-1/2 text-text-tertiary md:w-3/5">{vectorStore.bytes} bytes</span>
<span className="w-1/2 text-gray-500 md:w-3/5">{vectorStore.bytes} bytes</span>
</div>
<div className="mt-3 flex flex-row">
<span className="flex w-1/2 flex-row items-center md:w-2/5">
<Clock3 className="text-base text-text-tertiary md:text-lg lg:text-xl" />
<Clock3 className="text-base text-gray-500 md:text-lg lg:text-xl" />
&nbsp;Last active
</span>
<span className="w-1/2 text-text-tertiary md:w-3/5">{vectorStore.lastActive}</span>
<span className="w-1/2 text-gray-500 md:w-3/5">{vectorStore.lastActive}</span>
</div>
<div className="mt-3 flex flex-row">
<span className="flex w-1/2 flex-row items-center md:w-2/5">
<InfoIcon className="text-base text-text-tertiary md:text-lg lg:text-xl" />
<InfoIcon className="text-base text-gray-500 md:text-lg lg:text-xl" />
&nbsp;Expiration policy
</span>
<span className="w-1/2 text-text-tertiary md:w-3/5">{vectorStore.expirationPolicy}</span>
<span className="w-1/2 text-gray-500 md:w-3/5">{vectorStore.expirationPolicy}</span>
</div>
<div className="mt-3 flex flex-row">
<span className="flex w-1/2 flex-row items-center md:w-2/5">
<FileClock className="text-base text-text-tertiary md:text-lg lg:text-xl" />
<FileClock className="text-base text-gray-500 md:text-lg lg:text-xl" />
&nbsp;Expires
</span>
<span className="w-1/2 text-text-tertiary md:w-3/5">{vectorStore.expires}</span>
<span className="w-1/2 text-gray-500 md:w-3/5">{vectorStore.expires}</span>
</div>
<div className="mt-3 flex flex-row">
<span className="flex w-1/2 flex-row items-center md:w-2/5">
<Clock3 className="text-base text-text-tertiary md:text-lg lg:text-xl" />
<Clock3 className="text-base text-gray-500 md:text-lg lg:text-xl" />
&nbsp;Created At
</span>
<span className="w-1/2 text-text-tertiary md:w-3/5">
{vectorStore.createdAt.toString()}
</span>
<span className="w-1/2 text-gray-500 md:w-3/5">{vectorStore.createdAt.toString()}</span>
</div>
</div>
@ -202,7 +200,7 @@ export default function VectorStorePreview() {
<div className="flex w-1/2 flex-row lg:w-1/3">
<div className="content-center text-nowrap">{file.createdAt?.toString()}</div>
<Button
className="my-0 ml-3 h-min bg-transparent p-0 text-text-destructive hover:bg-surface-hover"
className="my-0 ml-3 h-min bg-transparent p-0 text-[#666666] hover:bg-slate-200"
onClick={() => console.log('click')}
>
<TrashIcon className="m-0 p-0" />

View file

@ -8,7 +8,7 @@ export default function VectorStoreView() {
const params = useParams();
const navigate = useNavigate();
return (
<div className="max-h-[100vh] bg-surface-primary p-0 lg:p-7">
<div className="max-h-[100vh] bg-[#f9f9f9] p-0 lg:p-7">
<div className="m-4 flex max-h-[10vh] w-full flex-row justify-between md:m-2">
<FilesSectionSelector />
<Button

View file

@ -187,9 +187,7 @@ const Mermaid: React.FC<MermaidProps> = memo(({ children, id, theme }) => {
{localize('com_ui_retry')}
</button>
</div>
<pre className="overflow-auto text-xs text-text-destructive">
{error.message}
</pre>
<pre className="overflow-auto text-xs text-text-destructive">{error.message}</pre>
{showCode && (
<div className="mt-4 border-t border-border-light pt-4">
<div className="mb-2 text-xs text-text-secondary">

View file

@ -63,11 +63,7 @@ export default function Create({ onCreated, onCancel }: CreateProps) {
placeholder={localize('com_ui_api_key_name_placeholder')}
/>
{nameError && (
<p
id="api-key-name-error"
role="alert"
className="text-xs text-text-destructive"
>
<p id="api-key-name-error" role="alert" className="text-xs text-text-destructive">
{localize('com_ui_api_key_name_required')}
</p>
)}

View file

@ -18,13 +18,8 @@ export default function Reveal({ createdKey, onDone }: RevealProps) {
return (
<div className="min-w-0 space-y-4">
<div className="flex gap-2.5 rounded-lg border border-status-warning-border bg-status-warning-subtle p-3">
<TriangleAlert
className="mt-0.5 h-4 w-4 shrink-0 text-text-warning"
aria-hidden="true"
/>
<p className="text-sm text-text-warning">
{localize('com_ui_api_key_warning')}
</p>
<TriangleAlert className="mt-0.5 h-4 w-4 shrink-0 text-text-warning" aria-hidden="true" />
<p className="text-sm text-text-warning">{localize('com_ui_api_key_warning')}</p>
</div>
<div className="space-y-2">
<Label htmlFor="reveal-api-key">{localize('com_ui_your_api_key')}</Label>

View file

@ -38,10 +38,7 @@ export default function MCPStatusBadge({
<div
role="status"
aria-live="polite"
className={cn(
badgeBaseClass,
'bg-status-info-subtle text-status-info',
)}
className={cn(badgeBaseClass, 'bg-status-info-subtle text-status-info')}
>
<Spinner className="size-3" />
<span>{localize('com_nav_mcp_status_initializing')}</span>
@ -61,10 +58,7 @@ export default function MCPStatusBadge({
<div
role="status"
aria-live="polite"
className={cn(
badgeBaseClass,
'bg-status-info-subtle text-status-info',
)}
className={cn(badgeBaseClass, 'bg-status-info-subtle text-status-info')}
>
<Spinner className="size-3" />
<span>{localize('com_nav_mcp_status_connecting')}</span>
@ -79,10 +73,7 @@ export default function MCPStatusBadge({
return (
<div
role="status"
className={cn(
badgeBaseClass,
'bg-status-warning-subtle text-status-warning',
)}
className={cn(badgeBaseClass, 'bg-status-warning-subtle text-status-warning')}
>
<PlugZap className="size-3" aria-hidden="true" />
<span>{localize('com_nav_mcp_status_needs_auth')}</span>
@ -93,10 +84,7 @@ export default function MCPStatusBadge({
return (
<div
role="status"
className={cn(
badgeBaseClass,
'bg-status-neutral-subtle text-status-neutral',
)}
className={cn(badgeBaseClass, 'bg-status-neutral-subtle text-status-neutral')}
>
<span>{localize('com_nav_mcp_status_disconnected')}</span>
</div>
@ -106,10 +94,7 @@ export default function MCPStatusBadge({
// Error state - red
if (connectionState === 'error') {
return (
<div
role="status"
className={cn(badgeBaseClass, 'bg-status-error-subtle text-status-error')}
>
<div role="status" className={cn(badgeBaseClass, 'bg-status-error-subtle text-status-error')}>
<span>{localize('com_nav_mcp_status_error')}</span>
</div>
);
@ -120,10 +105,7 @@ export default function MCPStatusBadge({
return (
<div
role="status"
className={cn(
badgeBaseClass,
'bg-status-success-subtle text-status-success',
)}
className={cn(badgeBaseClass, 'bg-status-success-subtle text-status-success')}
>
<Check className="size-3" aria-hidden="true" />
<span>{localize('com_nav_mcp_status_connected')}</span>

View file

@ -116,8 +116,7 @@ export default function MemoryCardActions({ memory }: MemoryCardActionsProps) {
}
selection={{
selectHandler: confirmDelete,
selectClasses:
'bg-surface-destructive text-white hover:bg-surface-destructive-hover',
selectClasses: 'bg-surface-destructive text-white hover:bg-surface-destructive-hover',
selectText: localize('com_ui_delete'),
}}
/>

View file

@ -13,7 +13,6 @@ import type { TSkill, TCreateSkill, TSkillWarning } from 'librechat-data-provide
import { useCreateSkillMutation } from '~/data-provider';
import { useLocalize } from '~/hooks';
import SkillContentEditor from './SkillContentEditor';
import InvocationModePicker from './InvocationModePicker';
import CategorySelector from './CategorySelector';
import { cn } from '~/utils';

View file

@ -13,7 +13,6 @@ import type { TSkill, TSkillWarning, TUpdateSkillPayload } from 'librechat-data-
import { useGetSkillQuery, useUpdateSkillMutation } from '~/data-provider';
import { useLocalize, useSkillPermissions } from '~/hooks';
import SkillContentEditor from './SkillContentEditor';
import InvocationModePicker from './InvocationModePicker';
import CategorySelector from './CategorySelector';
import DeleteSkill from '../dialogs/DeleteSkill';
import { ShareSkill } from '../buttons';

View file

@ -194,6 +194,7 @@
"com_auth_name_min_length": "Name must be at least 3 characters",
"com_auth_name_required": "Name is required",
"com_auth_no_account": "Don't have an account?",
"com_auth_or": "Or",
"com_auth_password": "Password",
"com_auth_password_confirm": "Confirm password",
"com_auth_password_forgot": "Forgot Password?",

View file

@ -42,24 +42,23 @@ export interface AlertProps
icon?: React.ReactNode | false;
}
const Alert: React.ForwardRefExoticComponent<
AlertProps & React.RefAttributes<HTMLDivElement>
> = React.forwardRef<HTMLDivElement, AlertProps>(
({ className, variant = 'info', icon, role = 'alert', children, ...props }, ref) => {
const resolvedVariant = (variant ?? 'info') as AlertVariant;
const DefaultIcon = defaultIcons[resolvedVariant];
return (
<div ref={ref} role={role} className={cn(alertVariants({ variant }), className)} {...props}>
{icon !== false && (
<span className="mt-0.5 shrink-0" aria-hidden="true">
{icon ?? <DefaultIcon className="size-4" />}
</span>
)}
<div className="min-w-0 flex-1">{children}</div>
</div>
);
},
);
const Alert: React.ForwardRefExoticComponent<AlertProps & React.RefAttributes<HTMLDivElement>> =
React.forwardRef<HTMLDivElement, AlertProps>(
({ className, variant = 'info', icon, role = 'alert', children, ...props }, ref) => {
const resolvedVariant = (variant ?? 'info') as AlertVariant;
const DefaultIcon = defaultIcons[resolvedVariant];
return (
<div ref={ref} role={role} className={cn(alertVariants({ variant }), className)} {...props}>
{icon !== false && (
<span className="mt-0.5 shrink-0" aria-hidden="true">
{icon ?? <DefaultIcon className="size-4" />}
</span>
)}
<div className="min-w-0 flex-1">{children}</div>
</div>
);
},
);
Alert.displayName = 'Alert';
export { Alert, alertVariants };