mirror of
https://github.com/danny-avila/LibreChat.git
synced 2025-09-21 21:50:49 +02:00
🔨 style: Improve MCP UI (#8745)
* refactor: Enhance MCP components with improved UI elements and localization updates * refactor: Clean up MCP components by removing unused imports and improving layout * refactor: Update server status badge styling for improved UI consistency * refactor: Move group up a level so 'X' and background highlight occur at same time for cancellation button * refactor: Remove unused translation keys from the localization file --------- Co-authored-by: Dustin Healy <dustinhealy1@gmail.com>
This commit is contained in:
parent
19a8f5c545
commit
09659c1040
9 changed files with 113 additions and 173 deletions
|
@ -1,6 +1,6 @@
|
|||
import React, { useMemo } from 'react';
|
||||
import { useForm, Controller } from 'react-hook-form';
|
||||
import { Input, Label, Button } from '@librechat/client';
|
||||
import { Input, Label, Button, TooltipAnchor, CircleHelpIcon } from '@librechat/client';
|
||||
import { useMCPAuthValuesQuery } from '~/data-provider/Tools/queries';
|
||||
import { useLocalize } from '~/hooks';
|
||||
|
||||
|
@ -31,16 +31,24 @@ function AuthField({ name, config, hasValue, control, errors }: AuthFieldProps)
|
|||
return (
|
||||
<div className="space-y-2">
|
||||
<div className="flex items-center justify-between">
|
||||
<Label htmlFor={name} className="text-sm font-medium">
|
||||
{config.title}
|
||||
</Label>
|
||||
<TooltipAnchor
|
||||
description={config.description || ''}
|
||||
render={
|
||||
<div className="flex items-center gap-2">
|
||||
<Label htmlFor={name} className="text-sm font-medium">
|
||||
{config.title}
|
||||
</Label>
|
||||
<CircleHelpIcon className="h-5 w-5 text-text-tertiary" />
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
{hasValue ? (
|
||||
<div className="flex min-w-fit items-center gap-2 whitespace-nowrap rounded-full border border-border-medium px-2 py-0.5 text-xs font-medium text-text-secondary">
|
||||
<div className="flex min-w-fit items-center gap-2 whitespace-nowrap rounded-full border border-border-light px-2 py-0.5 text-xs font-medium text-text-secondary">
|
||||
<div className="h-1.5 w-1.5 rounded-full bg-green-500" />
|
||||
<span>{localize('com_ui_set')}</span>
|
||||
</div>
|
||||
) : (
|
||||
<div className="flex min-w-fit items-center gap-2 whitespace-nowrap rounded-full border border-border-medium px-2 py-0.5 text-xs font-medium text-text-secondary">
|
||||
<div className="flex min-w-fit items-center gap-2 whitespace-nowrap rounded-full border border-border-light px-2 py-0.5 text-xs font-medium text-text-secondary">
|
||||
<div className="h-1.5 w-1.5 rounded-full border border-border-medium" />
|
||||
<span>{localize('com_ui_unset')}</span>
|
||||
</div>
|
||||
|
@ -60,16 +68,10 @@ function AuthField({ name, config, hasValue, control, errors }: AuthFieldProps)
|
|||
? localize('com_ui_mcp_update_var', { 0: config.title })
|
||||
: localize('com_ui_mcp_enter_var', { 0: config.title })
|
||||
}
|
||||
className="w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 dark:border-gray-600 dark:bg-gray-700 dark:text-white sm:text-sm"
|
||||
className="w-full shadow-sm sm:text-sm"
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
{config.description && (
|
||||
<p
|
||||
className="text-xs text-text-secondary [&_a]:text-blue-500 [&_a]:hover:text-blue-600 dark:[&_a]:text-blue-400 dark:[&_a]:hover:text-blue-300"
|
||||
dangerouslySetInnerHTML={{ __html: config.description }}
|
||||
/>
|
||||
)}
|
||||
{errors[name] && <p className="text-xs text-red-500">{errors[name]?.message}</p>}
|
||||
</div>
|
||||
);
|
||||
|
@ -114,15 +116,11 @@ export default function CustomUserVarsSection({
|
|||
};
|
||||
|
||||
if (!fields || Object.keys(fields).length === 0) {
|
||||
return (
|
||||
<div className="p-4 text-center text-sm text-gray-500">
|
||||
{localize('com_sidepanel_mcp_no_custom_vars', { '0': serverName })}
|
||||
</div>
|
||||
);
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="space-y-4">
|
||||
<div className="flex-1 space-y-4">
|
||||
<form onSubmit={handleSubmit(onFormSubmit)} className="space-y-4">
|
||||
{Object.entries(fields).map(([key, config]) => {
|
||||
const hasValue = authValuesData?.authValueFlags?.[key] || false;
|
||||
|
@ -140,21 +138,11 @@ export default function CustomUserVarsSection({
|
|||
})}
|
||||
</form>
|
||||
|
||||
<div className="flex justify-end gap-2 pt-2">
|
||||
<Button
|
||||
onClick={handleRevokeClick}
|
||||
className="bg-red-600 text-white hover:bg-red-700 dark:hover:bg-red-800"
|
||||
disabled={isSubmitting}
|
||||
size="sm"
|
||||
>
|
||||
<div className="flex justify-end gap-2">
|
||||
<Button onClick={handleRevokeClick} variant="destructive" disabled={isSubmitting}>
|
||||
{localize('com_ui_revoke')}
|
||||
</Button>
|
||||
<Button
|
||||
onClick={handleSubmit(onFormSubmit)}
|
||||
className="bg-green-500 text-white hover:bg-green-600"
|
||||
disabled={isSubmitting}
|
||||
size="sm"
|
||||
>
|
||||
<Button onClick={handleSubmit(onFormSubmit)} variant="submit" disabled={isSubmitting}>
|
||||
{isSubmitting ? localize('com_ui_saving') : localize('com_ui_save')}
|
||||
</Button>
|
||||
</div>
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
import React from 'react';
|
||||
import { Loader2, KeyRound, PlugZap, AlertTriangle } from 'lucide-react';
|
||||
import { KeyRound, PlugZap, AlertTriangle } from 'lucide-react';
|
||||
import {
|
||||
Spinner,
|
||||
OGDialog,
|
||||
OGDialogTitle,
|
||||
OGDialogHeader,
|
||||
OGDialogContent,
|
||||
OGDialogDescription,
|
||||
} from '@librechat/client';
|
||||
import type { MCPServerStatus } from 'librechat-data-provider';
|
||||
import ServerInitializationSection from './ServerInitializationSection';
|
||||
|
@ -45,9 +45,6 @@ export default function MCPConfigDialog({
|
|||
const dialogTitle = hasFields
|
||||
? localize('com_ui_configure_mcp_variables_for', { 0: serverName })
|
||||
: `${serverName} MCP Server`;
|
||||
const dialogDescription = hasFields
|
||||
? localize('com_ui_mcp_dialog_desc')
|
||||
: `Manage connection and settings for the ${serverName} MCP server.`;
|
||||
|
||||
// Helper function to render status badge based on connection state
|
||||
const renderStatusBadge = () => {
|
||||
|
@ -60,7 +57,7 @@ export default function MCPConfigDialog({
|
|||
if (connectionState === 'connecting') {
|
||||
return (
|
||||
<div className="flex items-center gap-2 rounded-full bg-blue-50 px-2 py-0.5 text-xs font-medium text-blue-600 dark:bg-blue-950 dark:text-blue-400">
|
||||
<Loader2 className="h-3 w-3 animate-spin" />
|
||||
<Spinner className="h-3 w-3" />
|
||||
<span>{localize('com_ui_connecting')}</span>
|
||||
</div>
|
||||
);
|
||||
|
@ -107,26 +104,24 @@ export default function MCPConfigDialog({
|
|||
|
||||
return (
|
||||
<OGDialog open={isOpen} onOpenChange={onOpenChange}>
|
||||
<OGDialogContent className="flex max-h-[90vh] w-full max-w-md flex-col">
|
||||
<OGDialogContent className="flex max-h-screen w-11/12 max-w-lg flex-col space-y-2">
|
||||
<OGDialogHeader>
|
||||
<div className="flex items-center gap-3">
|
||||
<OGDialogTitle>{dialogTitle}</OGDialogTitle>
|
||||
<OGDialogTitle className="text-xl">
|
||||
{dialogTitle.charAt(0).toUpperCase() + dialogTitle.slice(1)}
|
||||
</OGDialogTitle>
|
||||
{renderStatusBadge()}
|
||||
</div>
|
||||
<OGDialogDescription>{dialogDescription}</OGDialogDescription>
|
||||
</OGDialogHeader>
|
||||
|
||||
{/* Content */}
|
||||
<div className="flex-1 overflow-y-auto p-6">
|
||||
{/* Custom User Variables Section */}
|
||||
<CustomUserVarsSection
|
||||
serverName={serverName}
|
||||
fields={fieldsSchema}
|
||||
onSave={onSave}
|
||||
onRevoke={onRevoke || (() => {})}
|
||||
isSubmitting={isSubmitting}
|
||||
/>
|
||||
</div>
|
||||
{/* Custom User Variables Section */}
|
||||
<CustomUserVarsSection
|
||||
serverName={serverName}
|
||||
fields={fieldsSchema}
|
||||
onSave={onSave}
|
||||
onRevoke={onRevoke || (() => {})}
|
||||
isSubmitting={isSubmitting}
|
||||
/>
|
||||
|
||||
{/* Server Initialization Section */}
|
||||
<ServerInitializationSection
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import React from 'react';
|
||||
import { SettingsIcon, AlertTriangle, Loader2, KeyRound, PlugZap, X } from 'lucide-react';
|
||||
import { Spinner } from '@librechat/client';
|
||||
import { SettingsIcon, AlertTriangle, KeyRound, PlugZap, X } from 'lucide-react';
|
||||
import type { MCPServerStatus, TPlugin } from 'librechat-data-provider';
|
||||
import { useLocalize } from '~/hooks';
|
||||
|
||||
|
@ -96,12 +97,12 @@ function InitializingStatusIcon({ serverName, onCancel, canCancel }: Initializin
|
|||
<button
|
||||
type="button"
|
||||
onClick={onCancel}
|
||||
className="flex h-6 w-6 items-center justify-center rounded p-1 hover:bg-red-100 dark:hover:bg-red-900/20"
|
||||
className="group flex h-6 w-6 items-center justify-center rounded p-1 hover:bg-red-100 dark:hover:bg-red-900/20"
|
||||
aria-label={localize('com_ui_cancel')}
|
||||
title={localize('com_ui_cancel')}
|
||||
>
|
||||
<div className="group relative h-4 w-4">
|
||||
<Loader2 className="h-4 w-4 animate-spin text-blue-500 group-hover:opacity-0" />
|
||||
<div className="relative h-4 w-4">
|
||||
<Spinner className="h-4 w-4 group-hover:opacity-0" />
|
||||
<X className="absolute inset-0 h-4 w-4 text-red-500 opacity-0 group-hover:opacity-100" />
|
||||
</div>
|
||||
</button>
|
||||
|
@ -110,8 +111,8 @@ function InitializingStatusIcon({ serverName, onCancel, canCancel }: Initializin
|
|||
|
||||
return (
|
||||
<div className="flex h-6 w-6 items-center justify-center rounded p-1">
|
||||
<Loader2
|
||||
className="h-4 w-4 animate-spin text-blue-500"
|
||||
<Spinner
|
||||
className="h-4 w-4"
|
||||
aria-label={localize('com_nav_mcp_status_connecting', { 0: serverName })}
|
||||
/>
|
||||
</div>
|
||||
|
@ -121,8 +122,8 @@ function InitializingStatusIcon({ serverName, onCancel, canCancel }: Initializin
|
|||
function ConnectingStatusIcon({ serverName }: StatusIconProps) {
|
||||
return (
|
||||
<div className="flex h-6 w-6 items-center justify-center rounded p-1">
|
||||
<Loader2
|
||||
className="h-4 w-4 animate-spin text-blue-500"
|
||||
<Spinner
|
||||
className="h-4 w-4"
|
||||
aria-label={localize('com_nav_mcp_status_connecting', { 0: serverName })}
|
||||
/>
|
||||
</div>
|
||||
|
|
|
@ -1,23 +1,24 @@
|
|||
import React, { useCallback } from 'react';
|
||||
import { Button } from '@librechat/client';
|
||||
import { RefreshCw, Link } from 'lucide-react';
|
||||
import React from 'react';
|
||||
import { RefreshCw } from 'lucide-react';
|
||||
import { Button, Spinner } from '@librechat/client';
|
||||
import { useMCPServerManager } from '~/hooks/MCP/useMCPServerManager';
|
||||
import { useLocalize } from '~/hooks';
|
||||
|
||||
interface ServerInitializationSectionProps {
|
||||
sidePanel?: boolean;
|
||||
serverName: string;
|
||||
requiresOAuth: boolean;
|
||||
hasCustomUserVars?: boolean;
|
||||
}
|
||||
|
||||
export default function ServerInitializationSection({
|
||||
sidePanel = false,
|
||||
serverName,
|
||||
requiresOAuth,
|
||||
hasCustomUserVars = false,
|
||||
}: ServerInitializationSectionProps) {
|
||||
const localize = useLocalize();
|
||||
|
||||
// Use the centralized server manager instead of the old initialization hook so we can handle multiple oauth flows at once
|
||||
const {
|
||||
initializeServer,
|
||||
connectionStatus,
|
||||
|
@ -33,99 +34,66 @@ export default function ServerInitializationSection({
|
|||
const isServerInitializing = isInitializing(serverName);
|
||||
const serverOAuthUrl = getOAuthUrl(serverName);
|
||||
|
||||
const handleInitializeClick = useCallback(() => {
|
||||
initializeServer(serverName, false);
|
||||
}, [initializeServer, serverName]);
|
||||
const shouldShowReinit = isConnected && (requiresOAuth || hasCustomUserVars);
|
||||
const shouldShowInit = !isConnected && !serverOAuthUrl;
|
||||
|
||||
const handleCancelClick = useCallback(() => {
|
||||
cancelOAuthFlow(serverName);
|
||||
}, [cancelOAuthFlow, serverName]);
|
||||
|
||||
if (isConnected && (requiresOAuth || hasCustomUserVars)) {
|
||||
return (
|
||||
<div className="flex justify-start">
|
||||
<button
|
||||
onClick={handleInitializeClick}
|
||||
disabled={isServerInitializing}
|
||||
className="flex items-center gap-1 text-xs text-gray-400 hover:text-gray-600 disabled:opacity-50 dark:text-gray-500 dark:hover:text-gray-400"
|
||||
>
|
||||
<RefreshCw className={`h-3 w-3 ${isServerInitializing ? 'animate-spin' : ''}`} />
|
||||
{isServerInitializing ? localize('com_ui_loading') : localize('com_ui_reinitialize')}
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (isConnected) {
|
||||
if (!shouldShowReinit && !shouldShowInit && !serverOAuthUrl) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="rounded-lg border border-amber-200 bg-amber-50 p-4 dark:border-amber-700 dark:bg-amber-900/20">
|
||||
<div className="flex items-center justify-between">
|
||||
if (serverOAuthUrl) {
|
||||
return (
|
||||
<>
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="text-sm font-medium text-amber-800 dark:text-amber-200">
|
||||
{requiresOAuth
|
||||
? localize('com_ui_mcp_not_authenticated', { 0: serverName })
|
||||
: localize('com_ui_mcp_not_initialized', { 0: serverName })}
|
||||
</span>
|
||||
</div>
|
||||
{/* Only show authenticate button when OAuth URL is not present */}
|
||||
{!serverOAuthUrl && (
|
||||
<Button
|
||||
onClick={handleInitializeClick}
|
||||
disabled={isServerInitializing}
|
||||
className="btn btn-primary focus:shadow-outline flex w-full items-center justify-center px-4 py-2 font-semibold text-white hover:bg-green-600 focus:border-green-500"
|
||||
onClick={() => cancelOAuthFlow(serverName)}
|
||||
disabled={!canCancel}
|
||||
variant="outline"
|
||||
title={!canCancel ? 'disabled' : undefined}
|
||||
>
|
||||
{isServerInitializing ? (
|
||||
<>
|
||||
<RefreshCw className="h-4 w-4 animate-spin" />
|
||||
{localize('com_ui_loading')}
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<RefreshCw className="h-4 w-4" />
|
||||
{requiresOAuth
|
||||
? localize('com_ui_authenticate')
|
||||
: localize('com_ui_mcp_initialize')}
|
||||
</>
|
||||
)}
|
||||
{localize('com_ui_cancel')}
|
||||
</Button>
|
||||
<Button
|
||||
variant="submit"
|
||||
onClick={() => window.open(serverOAuthUrl, '_blank', 'noopener,noreferrer')}
|
||||
className="flex-1"
|
||||
>
|
||||
{localize('com_ui_continue_oauth')}
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* OAuth URL display */}
|
||||
{serverOAuthUrl && (
|
||||
<div className="mt-4 rounded-lg border border-blue-200 bg-blue-50 p-3 dark:border-blue-700 dark:bg-blue-900/20">
|
||||
<div className="mb-2 flex items-center gap-2">
|
||||
<div className="flex h-4 w-4 items-center justify-center rounded-full bg-blue-500">
|
||||
<Link className="h-2.5 w-2.5 text-white" />
|
||||
</div>
|
||||
<span className="text-sm font-medium text-blue-700 dark:text-blue-300">
|
||||
{localize('com_ui_auth_url')}
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<Button
|
||||
onClick={() => window.open(serverOAuthUrl, '_blank', 'noopener,noreferrer')}
|
||||
className="flex-1 bg-green-600 text-white hover:bg-green-700 dark:hover:bg-green-800"
|
||||
>
|
||||
{localize('com_ui_continue_oauth')}
|
||||
</Button>
|
||||
<Button
|
||||
onClick={handleCancelClick}
|
||||
disabled={!canCancel}
|
||||
className="bg-gray-200 text-gray-700 hover:bg-gray-300 disabled:cursor-not-allowed disabled:opacity-50 dark:bg-gray-700 dark:text-gray-200 dark:hover:bg-gray-600"
|
||||
title={!canCancel ? 'disabled' : undefined}
|
||||
>
|
||||
{localize('com_ui_cancel')}
|
||||
</Button>
|
||||
</div>
|
||||
<p className="mt-2 text-xs text-blue-600 dark:text-blue-400">
|
||||
{localize('com_ui_oauth_flow_desc')}
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
// Unified button rendering
|
||||
const isReinit = shouldShowReinit;
|
||||
const outerClass = isReinit ? 'flex justify-start' : 'flex justify-end';
|
||||
const buttonVariant = isReinit ? undefined : 'default';
|
||||
const buttonText = isServerInitializing
|
||||
? localize('com_ui_loading')
|
||||
: isReinit
|
||||
? localize('com_ui_reinitialize')
|
||||
: requiresOAuth
|
||||
? localize('com_ui_authenticate')
|
||||
: localize('com_ui_mcp_initialize');
|
||||
const icon = isServerInitializing ? (
|
||||
<Spinner className="h-4 w-4" />
|
||||
) : (
|
||||
<RefreshCw className="h-4 w-4" />
|
||||
);
|
||||
|
||||
return (
|
||||
<div className={outerClass}>
|
||||
<Button
|
||||
variant={buttonVariant}
|
||||
onClick={() => initializeServer(serverName, false)}
|
||||
disabled={isServerInitializing}
|
||||
size={sidePanel ? 'sm' : 'default'}
|
||||
className="w-full"
|
||||
>
|
||||
{icon}
|
||||
{buttonText}
|
||||
</Button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -6,8 +6,8 @@ import { Constants, QueryKeys } from 'librechat-data-provider';
|
|||
import { useUpdateUserPluginsMutation } from 'librechat-data-provider/react-query';
|
||||
import type { TUpdateUserPlugins } from 'librechat-data-provider';
|
||||
import ServerInitializationSection from '~/components/MCP/ServerInitializationSection';
|
||||
import CustomUserVarsSection from '~/components/MCP/CustomUserVarsSection';
|
||||
import { useMCPConnectionStatusQuery } from '~/data-provider/Tools/queries';
|
||||
import CustomUserVarsSection from '~/components/MCP/CustomUserVarsSection';
|
||||
import BadgeRowProvider from '~/Providers/BadgeRowContext';
|
||||
import { useGetStartupConfig } from '~/data-provider';
|
||||
import MCPPanelSkeleton from './MCPPanelSkeleton';
|
||||
|
@ -127,20 +127,12 @@ function MCPPanelContent() {
|
|||
const serverStatus = connectionStatus[selectedServerNameForEditing];
|
||||
|
||||
return (
|
||||
<div className="h-auto max-w-full overflow-x-hidden p-3">
|
||||
<Button
|
||||
variant="outline"
|
||||
onClick={handleGoBackToList}
|
||||
className="mb-3 flex items-center px-3 py-2 text-sm"
|
||||
>
|
||||
<div className="h-auto max-w-full space-y-4 overflow-x-hidden py-2">
|
||||
<Button variant="outline" onClick={handleGoBackToList} size="sm">
|
||||
<ChevronLeft className="mr-1 h-4 w-4" />
|
||||
{localize('com_ui_back')}
|
||||
</Button>
|
||||
|
||||
<h3 className="mb-3 text-lg font-medium">
|
||||
{localize('com_sidepanel_mcp_variables_for', { '0': serverBeingEdited.serverName })}
|
||||
</h3>
|
||||
|
||||
<div className="mb-4">
|
||||
<CustomUserVarsSection
|
||||
serverName={selectedServerNameForEditing}
|
||||
|
@ -160,6 +152,7 @@ function MCPPanelContent() {
|
|||
</div>
|
||||
|
||||
<ServerInitializationSection
|
||||
sidePanel={true}
|
||||
serverName={selectedServerNameForEditing}
|
||||
requiresOAuth={serverStatus?.requiresOAuth || false}
|
||||
hasCustomUserVars={
|
||||
|
@ -172,7 +165,7 @@ function MCPPanelContent() {
|
|||
} else {
|
||||
// Server List View
|
||||
return (
|
||||
<div className="h-auto max-w-full overflow-x-hidden p-3">
|
||||
<div className="h-auto max-w-full overflow-x-hidden py-2">
|
||||
<div className="space-y-2">
|
||||
{mcpServerDefinitions.map((server) => {
|
||||
const serverStatus = connectionStatus[server.serverName];
|
||||
|
@ -189,7 +182,7 @@ function MCPPanelContent() {
|
|||
<span>{server.serverName}</span>
|
||||
{serverStatus && (
|
||||
<span
|
||||
className={`rounded px-2 py-0.5 text-xs ${
|
||||
className={`rounded-xl px-2 py-0.5 text-xs ${
|
||||
isConnected
|
||||
? 'bg-green-100 text-green-700 dark:bg-green-900 dark:text-green-300'
|
||||
: 'bg-gray-100 text-gray-700 dark:bg-gray-800 dark:text-gray-300'
|
||||
|
|
|
@ -506,8 +506,6 @@
|
|||
"com_sidepanel_hide_panel": "Hide Panel",
|
||||
"com_sidepanel_manage_files": "Manage Files",
|
||||
"com_sidepanel_mcp_no_servers_with_vars": "No MCP servers with configurable variables.",
|
||||
"com_sidepanel_mcp_no_custom_vars": "No custom user variables set for {{0}}",
|
||||
"com_sidepanel_mcp_variables_for": "MCP Variables for {{0}}",
|
||||
"com_sidepanel_parameters": "Parameters",
|
||||
"com_sources_image_alt": "Search result image",
|
||||
"com_sources_more_sources": "+{{count}} sources",
|
||||
|
@ -850,13 +848,10 @@
|
|||
"com_ui_manage": "Manage",
|
||||
"com_ui_max_tags": "Maximum number allowed is {{0}}, using latest values.",
|
||||
"com_ui_mcp_authenticated_success": "MCP server '{{0}}' authenticated successfully",
|
||||
"com_ui_mcp_dialog_desc": "Please enter the necessary information below.",
|
||||
"com_ui_mcp_enter_var": "Enter value for {{0}}",
|
||||
"com_ui_mcp_init_failed": "Failed to initialize MCP server",
|
||||
"com_ui_mcp_initialize": "Initialize",
|
||||
"com_ui_mcp_initialized_success": "MCP server '{{0}}' initialized successfully",
|
||||
"com_ui_mcp_not_authenticated": "{{0}} not authenticated (OAuth Required)",
|
||||
"com_ui_mcp_not_initialized": "{{0}} not initialized",
|
||||
"com_ui_mcp_oauth_cancelled": "OAuth login cancelled for {{0}}",
|
||||
"com_ui_mcp_oauth_timeout": "OAuth login timed out for {{0}}",
|
||||
"com_ui_mcp_server_not_found": "Server not found.",
|
||||
|
@ -916,7 +911,6 @@
|
|||
"com_ui_oauth_error_missing_code": "Authorization code is missing. Please try again.",
|
||||
"com_ui_oauth_error_missing_state": "State parameter is missing. Please try again.",
|
||||
"com_ui_oauth_error_title": "Authentication Failed",
|
||||
"com_ui_oauth_flow_desc": "Complete the OAuth flow in the new window, then return here.",
|
||||
"com_ui_oauth_success_description": "Your authentication was successful. This window will close in",
|
||||
"com_ui_oauth_success_title": "Authentication Successful",
|
||||
"com_ui_of": "of",
|
||||
|
|
9
package-lock.json
generated
9
package-lock.json
generated
|
@ -28936,10 +28936,11 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@testing-library/react": {
|
||||
"version": "14.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@testing-library/react/-/react-14.2.1.tgz",
|
||||
"integrity": "sha512-sGdjws32ai5TLerhvzThYFbpnF9XtL65Cjf+gB0Dhr29BGqK+mAeN7SURSdu+eqgET4ANcWoC7FQpkaiGvBr+A==",
|
||||
"version": "14.3.1",
|
||||
"resolved": "https://registry.npmjs.org/@testing-library/react/-/react-14.3.1.tgz",
|
||||
"integrity": "sha512-H99XjUhWQw0lTgyMN05W3xQG1Nh4lq574D8keFf1dDoNTJgp66VbJozRaczoF+wsiaPJNt/TcnfpLGufGxSrZQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.12.5",
|
||||
"@testing-library/dom": "^9.0.0",
|
||||
|
@ -51506,7 +51507,7 @@
|
|||
},
|
||||
"packages/client": {
|
||||
"name": "@librechat/client",
|
||||
"version": "0.2.0",
|
||||
"version": "0.2.1",
|
||||
"devDependencies": {
|
||||
"@rollup/plugin-alias": "^5.1.0",
|
||||
"@rollup/plugin-commonjs": "^25.0.2",
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@librechat/client",
|
||||
"version": "0.2.0",
|
||||
"version": "0.2.1",
|
||||
"description": "React components for LibreChat",
|
||||
"main": "dist/index.js",
|
||||
"module": "dist/index.es.js",
|
||||
|
|
|
@ -121,7 +121,7 @@ const DialogDescription = React.forwardRef<
|
|||
>(({ className, ...props }, ref) => (
|
||||
<DialogPrimitive.Description
|
||||
ref={ref}
|
||||
className={cn('text-sm text-muted-foreground', className)}
|
||||
className={cn('text-sm text-text-secondary', className)}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue