| import React from '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'; |
|
|
| let localize: ReturnType<typeof useLocalize>; |
|
|
| interface StatusIconProps { |
| serverName: string; |
| onConfigClick: (e: React.MouseEvent) => void; |
| } |
|
|
| interface InitializingStatusProps extends StatusIconProps { |
| onCancel: (e: React.MouseEvent) => void; |
| canCancel: boolean; |
| } |
|
|
| interface MCPServerStatusIconProps { |
| serverName: string; |
| serverStatus?: MCPServerStatus; |
| tool?: TPlugin; |
| onConfigClick: (e: React.MouseEvent) => void; |
| isInitializing: boolean; |
| canCancel: boolean; |
| onCancel: (e: React.MouseEvent) => void; |
| hasCustomUserVars?: boolean; |
| } |
|
|
| |
| |
| |
| export default function MCPServerStatusIcon({ |
| serverName, |
| serverStatus, |
| tool, |
| onConfigClick, |
| isInitializing, |
| canCancel, |
| onCancel, |
| hasCustomUserVars = false, |
| }: MCPServerStatusIconProps) { |
| localize = useLocalize(); |
| if (isInitializing) { |
| return ( |
| <InitializingStatusIcon |
| serverName={serverName} |
| onConfigClick={onConfigClick} |
| onCancel={onCancel} |
| canCancel={canCancel} |
| /> |
| ); |
| } |
|
|
| if (!serverStatus) { |
| return null; |
| } |
|
|
| const { connectionState, requiresOAuth } = serverStatus; |
|
|
| if (connectionState === 'connecting') { |
| return <ConnectingStatusIcon serverName={serverName} onConfigClick={onConfigClick} />; |
| } |
|
|
| if (connectionState === 'disconnected') { |
| if (requiresOAuth) { |
| return <DisconnectedOAuthStatusIcon serverName={serverName} onConfigClick={onConfigClick} />; |
| } |
| return <DisconnectedStatusIcon serverName={serverName} onConfigClick={onConfigClick} />; |
| } |
|
|
| if (connectionState === 'error') { |
| return <ErrorStatusIcon serverName={serverName} onConfigClick={onConfigClick} />; |
| } |
|
|
| if (connectionState === 'connected') { |
| |
| if (hasCustomUserVars) { |
| const isAuthenticated = tool?.authenticated || requiresOAuth; |
| return ( |
| <AuthenticatedStatusIcon |
| serverName={serverName} |
| onConfigClick={onConfigClick} |
| isAuthenticated={isAuthenticated} |
| /> |
| ); |
| } |
| return null; |
| } |
|
|
| return null; |
| } |
|
|
| function InitializingStatusIcon({ serverName, onCancel, canCancel }: InitializingStatusProps) { |
| if (canCancel) { |
| return ( |
| <button |
| type="button" |
| onClick={onCancel} |
| 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="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> |
| ); |
| } |
|
|
| return ( |
| <div className="flex h-6 w-6 items-center justify-center rounded p-1"> |
| <Spinner |
| className="h-4 w-4" |
| aria-label={localize('com_nav_mcp_status_connecting', { 0: serverName })} |
| /> |
| </div> |
| ); |
| } |
|
|
| function ConnectingStatusIcon({ serverName }: StatusIconProps) { |
| return ( |
| <div className="flex h-6 w-6 items-center justify-center rounded p-1"> |
| <Spinner |
| className="h-4 w-4" |
| aria-label={localize('com_nav_mcp_status_connecting', { 0: serverName })} |
| /> |
| </div> |
| ); |
| } |
|
|
| function DisconnectedOAuthStatusIcon({ serverName, onConfigClick }: StatusIconProps) { |
| return ( |
| <button |
| type="button" |
| onClick={onConfigClick} |
| className="flex h-6 w-6 items-center justify-center rounded p-1 hover:bg-surface-secondary" |
| aria-label={localize('com_nav_mcp_configure_server', { 0: serverName })} |
| > |
| <KeyRound className="h-4 w-4 text-amber-500" /> |
| </button> |
| ); |
| } |
|
|
| function DisconnectedStatusIcon({ serverName, onConfigClick }: StatusIconProps) { |
| return ( |
| <button |
| type="button" |
| onClick={onConfigClick} |
| className="flex h-6 w-6 items-center justify-center rounded p-1 hover:bg-surface-secondary" |
| aria-label={localize('com_nav_mcp_configure_server', { 0: serverName })} |
| > |
| <PlugZap className="h-4 w-4 text-orange-500" /> |
| </button> |
| ); |
| } |
|
|
| function ErrorStatusIcon({ serverName, onConfigClick }: StatusIconProps) { |
| return ( |
| <button |
| type="button" |
| onClick={onConfigClick} |
| className="flex h-6 w-6 items-center justify-center rounded p-1 hover:bg-surface-secondary" |
| aria-label={localize('com_nav_mcp_configure_server', { 0: serverName })} |
| > |
| <AlertTriangle className="h-4 w-4 text-red-500" /> |
| </button> |
| ); |
| } |
|
|
| interface AuthenticatedStatusProps extends StatusIconProps { |
| isAuthenticated: boolean; |
| } |
|
|
| function AuthenticatedStatusIcon({ |
| serverName, |
| onConfigClick, |
| isAuthenticated, |
| }: AuthenticatedStatusProps) { |
| return ( |
| <button |
| type="button" |
| onClick={onConfigClick} |
| className="flex h-6 w-6 items-center justify-center rounded p-1 hover:bg-surface-secondary" |
| aria-label={localize('com_nav_mcp_configure_server', { 0: serverName })} |
| > |
| <SettingsIcon className={`h-4 w-4 ${isAuthenticated ? 'text-green-500' : 'text-gray-400'}`} /> |
| </button> |
| ); |
| } |
|
|