mirror of
https://github.com/danny-avila/LibreChat.git
synced 2026-01-11 21:18:51 +01:00
* 🗑️ chore: Remove unused Legacy Provider clients and related helpers * Deleted OpenAIClient and GoogleClient files along with their associated tests. * Removed references to these clients in the clients index file. * Cleaned up typedefs by removing the OpenAISpecClient export. * Updated chat controllers to use the OpenAI SDK directly instead of the removed client classes. * chore/remove-openapi-specs * 🗑️ chore: Remove unused mergeSort and misc utility functions * Deleted mergeSort.js and misc.js files as they are no longer needed. * Removed references to cleanUpPrimaryKeyValue in messages.js and adjusted related logic. * Updated mongoMeili.ts to eliminate local implementations of removed functions. * chore: remove legacy endpoints * chore: remove all plugins endpoint related code * chore: remove unused prompt handling code and clean up imports * Deleted handleInputs.js and instructions.js files as they are no longer needed. * Removed references to these files in the prompts index.js. * Updated docker-compose.yml to simplify reverse proxy configuration. * chore: remove unused LightningIcon import from Icons.tsx * chore: clean up translation.json by removing deprecated and unused keys * chore: update Jest configuration and remove unused mock file * Simplified the setupFiles array in jest.config.js by removing the fetchEventSource mock. * Deleted the fetchEventSource.js mock file as it is no longer needed. * fix: simplify endpoint type check in Landing and ConversationStarters components * Updated the endpoint type check to use strict equality for better clarity and performance. * Ensured consistency in the handling of the azureOpenAI endpoint across both components. * chore: remove unused dependencies from package.json and package-lock.json * chore: remove legacy EditController, associated routes and imports * chore: update banResponse logic to refine request handling for banned users * chore: remove unused validateEndpoint middleware and its references * chore: remove unused 'res' parameter from initializeClient in multiple endpoint files * chore: remove unused 'isSmallScreen' prop from BookmarkNav and NewChat components; clean up imports in ArchivedChatsTable and useSetIndexOptions hooks; enhance localization in PromptVersions * chore: remove unused import of Constants and TMessage from MobileNav; retain only necessary QueryKeys import * chore: remove unused TResPlugin type and related references; clean up imports in types and schemas
192 lines
5.6 KiB
TypeScript
192 lines
5.6 KiB
TypeScript
import React from 'react';
|
|
import { format } from 'date-fns';
|
|
import { Layers3, Crown, Zap } from 'lucide-react';
|
|
import { Tag, TooltipAnchor, Label } from '@librechat/client';
|
|
import type { TPrompt, TPromptGroup } from 'librechat-data-provider';
|
|
import { useLocalize } from '~/hooks';
|
|
import { cn } from '~/utils';
|
|
|
|
const CombinedStatusIcon = ({ description }: { description: string }) => (
|
|
<TooltipAnchor
|
|
description={description}
|
|
aria-label={description}
|
|
render={
|
|
<div className="flex items-center justify-center">
|
|
<Crown className="h-4 w-4 text-amber-500" />
|
|
</div>
|
|
}
|
|
></TooltipAnchor>
|
|
);
|
|
|
|
const VersionTags = ({ tags }: { tags: string[] }) => {
|
|
const localize = useLocalize();
|
|
const isLatestAndProduction = tags.includes('latest') && tags.includes('production');
|
|
|
|
if (isLatestAndProduction) {
|
|
return (
|
|
<span className="absolute bottom-3 right-3">
|
|
<CombinedStatusIcon description={localize('com_ui_latest_production_version')} />
|
|
</span>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<span className="flex gap-1 text-sm">
|
|
{tags.map((tag, i) => (
|
|
<TooltipAnchor
|
|
description={
|
|
tag === 'production'
|
|
? localize('com_ui_currently_production')
|
|
: localize('com_ui_latest_version')
|
|
}
|
|
key={`${tag}-${i}`}
|
|
aria-label={
|
|
tag === 'production'
|
|
? localize('com_ui_currently_production')
|
|
: localize('com_ui_latest_version')
|
|
}
|
|
render={
|
|
<Tag
|
|
label={tag}
|
|
className={cn(
|
|
'w-24 justify-center border border-transparent',
|
|
tag === 'production'
|
|
? 'bg-green-100 text-green-700 dark:border-green-400 dark:bg-transparent dark:text-green-400'
|
|
: 'bg-blue-100 text-blue-700 dark:border-blue-400 dark:bg-transparent dark:text-blue-400',
|
|
)}
|
|
labelClassName="flex items-center m-0 justify-center gap-1"
|
|
LabelNode={(() => {
|
|
if (tag === 'production') {
|
|
return (
|
|
<div className="flex items-center">
|
|
<span className="slow-pulse size-2 rounded-full bg-green-400" />
|
|
</div>
|
|
);
|
|
}
|
|
if (tag === 'latest') {
|
|
return (
|
|
<div className="flex items-center">
|
|
<Zap className="size-4" />
|
|
</div>
|
|
);
|
|
}
|
|
return null;
|
|
})()}
|
|
/>
|
|
}
|
|
></TooltipAnchor>
|
|
))}
|
|
</span>
|
|
);
|
|
};
|
|
|
|
const VersionCard = ({
|
|
prompt,
|
|
index,
|
|
isSelected,
|
|
totalVersions,
|
|
onClick,
|
|
authorName,
|
|
tags,
|
|
}: {
|
|
prompt: TPrompt;
|
|
index: number;
|
|
isSelected: boolean;
|
|
totalVersions: number;
|
|
onClick: () => void;
|
|
authorName?: string;
|
|
tags: string[];
|
|
}) => {
|
|
const localize = useLocalize();
|
|
|
|
return (
|
|
<button
|
|
type="button"
|
|
className={cn(
|
|
'group relative w-full rounded-lg border border-border-light p-4 transition-all duration-300',
|
|
isSelected
|
|
? 'bg-surface-secondary shadow-xl ring-2 ring-gray-400'
|
|
: 'bg-surface-primary shadow-sm hover:bg-surface-secondary',
|
|
)}
|
|
onClick={onClick}
|
|
aria-selected={isSelected}
|
|
role="tab"
|
|
aria-label={localize('com_ui_version_var', { 0: `${totalVersions - index}` })}
|
|
>
|
|
<div className="flex flex-col gap-2">
|
|
<div className="flex items-start justify-between lg:flex-col xl:flex-row">
|
|
<h3 className="font-bold text-text-primary">
|
|
{localize('com_ui_version_var', { 0: `${totalVersions - index}` })}
|
|
</h3>
|
|
<time className="text-xs text-text-secondary" dateTime={prompt.createdAt}>
|
|
{format(new Date(prompt.createdAt), 'yyyy-MM-dd HH:mm')}
|
|
</time>
|
|
</div>
|
|
|
|
<div className="flex items-center gap-1 lg:flex-col xl:flex-row">
|
|
{authorName && (
|
|
<Label className="text-left text-xs text-text-secondary">
|
|
{localize('com_ui_by_author', { 0: authorName })}
|
|
</Label>
|
|
)}
|
|
|
|
{tags.length > 0 && <VersionTags tags={tags} />}
|
|
</div>
|
|
</div>
|
|
</button>
|
|
);
|
|
};
|
|
|
|
const PromptVersions = ({
|
|
prompts,
|
|
group,
|
|
selectionIndex,
|
|
setSelectionIndex,
|
|
}: {
|
|
prompts: TPrompt[];
|
|
group?: TPromptGroup;
|
|
selectionIndex: number;
|
|
setSelectionIndex: React.Dispatch<React.SetStateAction<number>>;
|
|
}) => {
|
|
const localize = useLocalize();
|
|
|
|
return (
|
|
<section className="my-6" aria-label="Prompt Versions">
|
|
<header className="mb-6">
|
|
<h2 className="flex items-center gap-2 text-base font-semibold text-text-primary">
|
|
<Layers3 className="h-5 w-5 text-green-500" />
|
|
{localize('com_ui_versions')}
|
|
</h2>
|
|
</header>
|
|
|
|
<div className="flex flex-col gap-3" role="tablist" aria-label="Version history">
|
|
{prompts.map((prompt: TPrompt, index: number) => {
|
|
const tags: string[] = [];
|
|
|
|
if (index === 0) {
|
|
tags.push('latest');
|
|
}
|
|
|
|
if (prompt._id === group?.productionId) {
|
|
tags.push('production');
|
|
}
|
|
|
|
return (
|
|
<VersionCard
|
|
key={prompt._id}
|
|
prompt={prompt}
|
|
index={index}
|
|
isSelected={index === selectionIndex}
|
|
totalVersions={prompts.length}
|
|
onClick={() => setSelectionIndex(index)}
|
|
authorName={group?.authorName}
|
|
tags={tags}
|
|
/>
|
|
);
|
|
})}
|
|
</div>
|
|
</section>
|
|
);
|
|
};
|
|
|
|
export default PromptVersions;
|