mirror of
https://github.com/danny-avila/LibreChat.git
synced 2026-08-04 14:57:42 +00:00
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:
parent
53269ddf4f
commit
fc5d3bc949
30 changed files with 118 additions and 162 deletions
|
|
@ -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}`}
|
||||
>
|
||||
|
|
|
|||
|
|
@ -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')}
|
||||
|
|
|
|||
|
|
@ -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" />
|
||||
</>
|
||||
|
|
|
|||
|
|
@ -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">
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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 && (
|
||||
<>
|
||||
|
|
|
|||
|
|
@ -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)}
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -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');
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -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',
|
||||
)}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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" />
|
||||
|
|
|
|||
|
|
@ -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="" />
|
||||
|
|
|
|||
|
|
@ -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" />
|
||||
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" />
|
||||
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" />
|
||||
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" />
|
||||
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" />
|
||||
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');
|
||||
}}
|
||||
|
|
|
|||
|
|
@ -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" />
|
||||
<span className="text-nowrap">Upload New File</span>
|
||||
</Button>
|
||||
|
|
|
|||
|
|
@ -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');
|
||||
}}
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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" />
|
||||
<span className="text-nowrap">Add Store</span>
|
||||
</Button>
|
||||
|
|
|
|||
|
|
@ -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" />
|
||||
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" />
|
||||
Usage this 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>
|
||||
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" />
|
||||
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" />
|
||||
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" />
|
||||
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" />
|
||||
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" />
|
||||
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" />
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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">
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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'),
|
||||
}}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -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';
|
||||
|
||||
|
|
|
|||
|
|
@ -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';
|
||||
|
|
|
|||
|
|
@ -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?",
|
||||
|
|
|
|||
|
|
@ -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 };
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue