mirror of
https://github.com/danny-avila/LibreChat.git
synced 2025-12-17 17:00:15 +01: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,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>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue