| import React, { memo, useCallback } from 'react'; |
| import { MultiSelect, MCPIcon } from '@librechat/client'; |
| import MCPServerStatusIcon from '~/components/MCP/MCPServerStatusIcon'; |
| import MCPConfigDialog from '~/components/MCP/MCPConfigDialog'; |
| import { useBadgeRowContext } from '~/Providers'; |
|
|
| function MCPSelectContent() { |
| const { conversationId, mcpServerManager } = useBadgeRowContext(); |
| const { |
| localize, |
| isPinned, |
| mcpValues, |
| isInitializing, |
| placeholderText, |
| configuredServers, |
| batchToggleServers, |
| getConfigDialogProps, |
| getServerStatusIconProps, |
| } = mcpServerManager; |
|
|
| const renderSelectedValues = useCallback( |
| (values: string[], placeholder?: string) => { |
| if (values.length === 0) { |
| return placeholder || localize('com_ui_select') + '...'; |
| } |
| if (values.length === 1) { |
| return values[0]; |
| } |
| return localize('com_ui_x_selected', { 0: values.length }); |
| }, |
| [localize], |
| ); |
|
|
| const renderItemContent = useCallback( |
| (serverName: string, defaultContent: React.ReactNode) => { |
| const statusIconProps = getServerStatusIconProps(serverName); |
| const isServerInitializing = isInitializing(serverName); |
|
|
| |
| |
| |
| |
| const mainContentWrapper = ( |
| <button |
| type="button" |
| className={`flex flex-grow items-center rounded bg-transparent p-0 text-left transition-colors focus:outline-none ${ |
| isServerInitializing ? 'opacity-50' : '' |
| }`} |
| tabIndex={0} |
| disabled={isServerInitializing} |
| > |
| {defaultContent} |
| </button> |
| ); |
|
|
| const statusIcon = statusIconProps && <MCPServerStatusIcon {...statusIconProps} />; |
|
|
| if (statusIcon) { |
| return ( |
| <div className="flex w-full items-center justify-between"> |
| {mainContentWrapper} |
| <div className="ml-2 flex items-center">{statusIcon}</div> |
| </div> |
| ); |
| } |
|
|
| return mainContentWrapper; |
| }, |
| [getServerStatusIconProps, isInitializing], |
| ); |
|
|
| if (!isPinned && mcpValues?.length === 0) { |
| return null; |
| } |
|
|
| const configDialogProps = getConfigDialogProps(); |
|
|
| return ( |
| <> |
| <MultiSelect |
| items={configuredServers} |
| selectedValues={mcpValues ?? []} |
| setSelectedValues={batchToggleServers} |
| renderSelectedValues={renderSelectedValues} |
| renderItemContent={renderItemContent} |
| placeholder={placeholderText} |
| popoverClassName="min-w-fit" |
| className="badge-icon min-w-fit" |
| selectIcon={<MCPIcon className="icon-md text-text-primary" />} |
| selectItemsClassName="border border-blue-600/50 bg-blue-500/10 hover:bg-blue-700/10" |
| selectClassName="group relative inline-flex items-center justify-center md:justify-start gap-1.5 rounded-full border border-border-medium text-sm font-medium transition-all md:w-full size-9 p-2 md:p-3 bg-transparent shadow-sm hover:bg-surface-hover hover:shadow-md active:shadow-inner" |
| /> |
| {configDialogProps && ( |
| <MCPConfigDialog {...configDialogProps} conversationId={conversationId} /> |
| )} |
| </> |
| ); |
| } |
|
|
| function MCPSelect() { |
| const { mcpServerManager } = useBadgeRowContext(); |
| const { configuredServers } = mcpServerManager; |
|
|
| if (!configuredServers || configuredServers.length === 0) { |
| return null; |
| } |
|
|
| return <MCPSelectContent />; |
| } |
|
|
| export default memo(MCPSelect); |
|
|