mirror of
https://github.com/QwenLM/qwen-code.git
synced 2026-04-30 20:50:34 +00:00
fix list align
This commit is contained in:
parent
fae195eaa8
commit
892fe4f706
4 changed files with 88 additions and 65 deletions
|
|
@ -407,7 +407,9 @@ export const MCPManagementDialog: React.FC<MCPManagementDialogProps> = ({
|
|||
|
||||
return (
|
||||
<Box>
|
||||
<Text bold>{headerText}</Text>
|
||||
<Text color={theme.text.accent} bold>
|
||||
{headerText}
|
||||
</Text>
|
||||
</Box>
|
||||
);
|
||||
}, [getCurrentStep, selectedServer, selectedTool]);
|
||||
|
|
@ -415,11 +417,7 @@ export const MCPManagementDialog: React.FC<MCPManagementDialogProps> = ({
|
|||
// Render step content
|
||||
const renderStepContent = useCallback(() => {
|
||||
if (isLoading) {
|
||||
return (
|
||||
<Box>
|
||||
<Text color={theme.text.secondary}>{t('Loading...')}</Text>
|
||||
</Box>
|
||||
);
|
||||
return <Text color={theme.text.secondary}>{t('Loading...')}</Text>;
|
||||
}
|
||||
|
||||
const currentStep = getCurrentStep();
|
||||
|
|
|
|||
|
|
@ -17,6 +17,9 @@ import {
|
|||
formatServerCommand,
|
||||
} from '../utils.js';
|
||||
|
||||
// 标签列宽度
|
||||
const LABEL_WIDTH = 15;
|
||||
|
||||
type ServerAction = 'view-tools' | 'reconnect' | 'toggle-disable';
|
||||
|
||||
export const ServerDetailStep: React.FC<ServerDetailStepProps> = ({
|
||||
|
|
@ -91,8 +94,10 @@ export const ServerDetailStep: React.FC<ServerDetailStepProps> = ({
|
|||
{/* 服务器详情 */}
|
||||
<Box flexDirection="column">
|
||||
<Box>
|
||||
<Text color={theme.text.primary}>{t('Status:')}</Text>
|
||||
<Box marginLeft={2}>
|
||||
<Box width={LABEL_WIDTH}>
|
||||
<Text color={theme.text.primary}>{t('Status:')}</Text>
|
||||
</Box>
|
||||
<Box>
|
||||
<Text
|
||||
color={
|
||||
statusColor === 'green'
|
||||
|
|
@ -110,9 +115,11 @@ export const ServerDetailStep: React.FC<ServerDetailStepProps> = ({
|
|||
</Box>
|
||||
</Box>
|
||||
|
||||
<Box marginTop={1}>
|
||||
<Text color={theme.text.primary}>{t('Source:')}</Text>
|
||||
<Box marginLeft={2}>
|
||||
<Box>
|
||||
<Box width={LABEL_WIDTH}>
|
||||
<Text color={theme.text.primary}>{t('Source:')}</Text>
|
||||
</Box>
|
||||
<Box>
|
||||
<Text color={theme.text.secondary}>
|
||||
{server.scope === 'user'
|
||||
? t('User Settings')
|
||||
|
|
@ -123,25 +130,31 @@ export const ServerDetailStep: React.FC<ServerDetailStepProps> = ({
|
|||
</Box>
|
||||
</Box>
|
||||
|
||||
<Box marginTop={1}>
|
||||
<Text color={theme.text.primary}>{t('Command:')}</Text>
|
||||
<Box marginLeft={2}>
|
||||
<Box>
|
||||
<Box width={LABEL_WIDTH}>
|
||||
<Text color={theme.text.primary}>{t('Command:')}</Text>
|
||||
</Box>
|
||||
<Box>
|
||||
<Text wrap="truncate">{formatServerCommand(server)}</Text>
|
||||
</Box>
|
||||
</Box>
|
||||
|
||||
{server.config.cwd && (
|
||||
<Box marginTop={1}>
|
||||
<Text color={theme.text.primary}>{t('Working Directory:')}</Text>
|
||||
<Box marginLeft={2}>
|
||||
<Box>
|
||||
<Box width={LABEL_WIDTH}>
|
||||
<Text color={theme.text.primary}>{t('Working Directory:')}</Text>
|
||||
</Box>
|
||||
<Box>
|
||||
<Text wrap="truncate">{server.config.cwd}</Text>
|
||||
</Box>
|
||||
</Box>
|
||||
)}
|
||||
|
||||
<Box marginTop={1}>
|
||||
<Text color={theme.text.primary}>{t('Capabilities:')}</Text>
|
||||
<Box marginLeft={2}>
|
||||
<Box>
|
||||
<Box width={LABEL_WIDTH}>
|
||||
<Text color={theme.text.primary}>{t('Capabilities:')}</Text>
|
||||
</Box>
|
||||
<Box>
|
||||
<Text>
|
||||
{server.toolCount > 0 ? t('tools') : ''}
|
||||
{server.toolCount > 0 && server.promptCount > 0 ? ', ' : ''}
|
||||
|
|
@ -150,9 +163,11 @@ export const ServerDetailStep: React.FC<ServerDetailStepProps> = ({
|
|||
</Box>
|
||||
</Box>
|
||||
|
||||
<Box marginTop={1}>
|
||||
<Text color={theme.text.primary}>{t('Tools:')}</Text>
|
||||
<Box marginLeft={2}>
|
||||
<Box>
|
||||
<Box width={LABEL_WIDTH}>
|
||||
<Text color={theme.text.primary}>{t('Tools:')}</Text>
|
||||
</Box>
|
||||
<Box>
|
||||
<Text>
|
||||
{server.toolCount}{' '}
|
||||
{server.toolCount === 1 ? t('tool') : t('tools')}
|
||||
|
|
@ -168,9 +183,11 @@ export const ServerDetailStep: React.FC<ServerDetailStepProps> = ({
|
|||
</Box>
|
||||
|
||||
{server.errorMessage && (
|
||||
<Box marginTop={1}>
|
||||
<Text color={theme.status.error}>{t('Error:')}</Text>
|
||||
<Box marginLeft={2}>
|
||||
<Box>
|
||||
<Box width={LABEL_WIDTH}>
|
||||
<Text color={theme.status.error}>{t('Error:')}</Text>
|
||||
</Box>
|
||||
<Box>
|
||||
<Text color={theme.status.error} wrap="wrap">
|
||||
{server.errorMessage}
|
||||
</Text>
|
||||
|
|
@ -180,7 +197,7 @@ export const ServerDetailStep: React.FC<ServerDetailStepProps> = ({
|
|||
</Box>
|
||||
|
||||
{/* 操作列表 */}
|
||||
<Box marginTop={1}>
|
||||
<Box>
|
||||
<RadioButtonSelect<ServerAction>
|
||||
items={actions}
|
||||
onHighlight={(value: ServerAction) => setSelectedAction(value)}
|
||||
|
|
|
|||
|
|
@ -27,6 +27,14 @@ export const ServerListStep: React.FC<ServerListStepProps> = ({
|
|||
[servers],
|
||||
);
|
||||
|
||||
// 动态计算服务器名称列的最大宽度(基于实际内容)
|
||||
const serverNameWidth = useMemo(() => {
|
||||
if (servers.length === 0) return 20;
|
||||
const maxLength = Math.max(...servers.map((s) => s.name.length));
|
||||
// 最小 20,最大 35,留一些余量
|
||||
return Math.min(Math.max(maxLength + 2, 20), 35);
|
||||
}, [servers]);
|
||||
|
||||
// 计算扁平化的服务器列表用于导航
|
||||
const flatServers = useMemo(() => {
|
||||
const result: MCPServerDisplayInfo[] = [];
|
||||
|
|
@ -119,13 +127,19 @@ export const ServerListStep: React.FC<ServerListStepProps> = ({
|
|||
{isSelected ? '❯' : ' '}
|
||||
</Text>
|
||||
</Box>
|
||||
<Text
|
||||
color={isSelected ? theme.text.accent : theme.text.primary}
|
||||
wrap="truncate"
|
||||
>
|
||||
{server.name}
|
||||
</Text>
|
||||
{/* 服务器名称 - 固定宽度 */}
|
||||
<Box width={serverNameWidth}>
|
||||
<Text
|
||||
color={
|
||||
isSelected ? theme.text.accent : theme.text.primary
|
||||
}
|
||||
wrap="truncate"
|
||||
>
|
||||
{server.name}
|
||||
</Text>
|
||||
</Box>
|
||||
<Text color={theme.text.secondary}> · </Text>
|
||||
{/* 状态图标和文本 */}
|
||||
<Text
|
||||
color={
|
||||
statusColor === 'green'
|
||||
|
|
@ -135,19 +149,7 @@ export const ServerListStep: React.FC<ServerListStepProps> = ({
|
|||
: theme.status.error
|
||||
}
|
||||
>
|
||||
{getStatusIcon(server.status)}
|
||||
</Text>
|
||||
<Text
|
||||
color={
|
||||
statusColor === 'green'
|
||||
? theme.status.success
|
||||
: statusColor === 'yellow'
|
||||
? theme.status.warning
|
||||
: theme.status.error
|
||||
}
|
||||
>
|
||||
{' '}
|
||||
{t(server.status)}
|
||||
{getStatusIcon(server.status)} {t(server.status)}
|
||||
</Text>
|
||||
{/* 显示 Scope 和禁用状态 */}
|
||||
<Text color={theme.text.secondary}> [{server.scope}]</Text>
|
||||
|
|
@ -172,7 +174,7 @@ export const ServerListStep: React.FC<ServerListStepProps> = ({
|
|||
|
||||
{/* 提示信息 */}
|
||||
{servers.some((s) => s.status === 'disconnected') && (
|
||||
<Box marginTop={1}>
|
||||
<Box>
|
||||
<Text color={theme.status.warning}>
|
||||
※ {t('Run qwen --debug to see error logs')}
|
||||
</Text>
|
||||
|
|
|
|||
|
|
@ -20,6 +20,14 @@ export const ToolListStep: React.FC<ToolListStepProps> = ({
|
|||
}) => {
|
||||
const [selectedIndex, setSelectedIndex] = useState(0);
|
||||
|
||||
// 动态计算工具名称列的最大宽度(基于实际内容)
|
||||
const toolNameWidth = useMemo(() => {
|
||||
if (tools.length === 0) return 30;
|
||||
const maxLength = Math.max(...tools.map((t) => t.name.length));
|
||||
// 最小 30,最大 50,留一些余量
|
||||
return Math.min(Math.max(maxLength + 2, 30), 50);
|
||||
}, [tools]);
|
||||
|
||||
// 计算可视区域的起始索引(滚动窗口)
|
||||
const scrollOffset = useMemo(() => {
|
||||
if (tools.length <= VISIBLE_TOOLS_COUNT) {
|
||||
|
|
@ -97,6 +105,7 @@ export const ToolListStep: React.FC<ToolListStepProps> = ({
|
|||
|
||||
return (
|
||||
<Box key={tool.name}>
|
||||
{/* 选择器和序号 */}
|
||||
<Box minWidth={4}>
|
||||
<Text
|
||||
color={isSelected ? theme.text.accent : theme.text.primary}
|
||||
|
|
@ -105,28 +114,25 @@ export const ToolListStep: React.FC<ToolListStepProps> = ({
|
|||
</Text>
|
||||
<Text color={theme.text.secondary}>{actualIndex + 1}.</Text>
|
||||
</Box>
|
||||
<Text
|
||||
color={isSelected ? theme.text.accent : theme.text.primary}
|
||||
wrap="truncate"
|
||||
>
|
||||
{tool.name}
|
||||
</Text>
|
||||
{/* 工具名称 - 固定宽度 */}
|
||||
<Box width={toolNameWidth}>
|
||||
<Text
|
||||
color={isSelected ? theme.text.accent : theme.text.primary}
|
||||
wrap="truncate"
|
||||
>
|
||||
{tool.name}
|
||||
</Text>
|
||||
</Box>
|
||||
{/* 显示无效工具警告 */}
|
||||
{!tool.isValid && (
|
||||
<>
|
||||
<Text color={theme.text.secondary}> </Text>
|
||||
<Text color={theme.status.warning}>
|
||||
{t('invalid: {{reason}}', {
|
||||
reason: tool.invalidReason || t('unknown'),
|
||||
})}
|
||||
</Text>
|
||||
</>
|
||||
<Text color={theme.status.warning}>
|
||||
{t('invalid: {{reason}}', {
|
||||
reason: tool.invalidReason || t('unknown'),
|
||||
})}
|
||||
</Text>
|
||||
)}
|
||||
{annotations && tool.isValid && (
|
||||
<>
|
||||
<Text color={theme.text.secondary}> </Text>
|
||||
<Text color={theme.text.secondary}>{annotations}</Text>
|
||||
</>
|
||||
<Text color={theme.text.secondary}>{annotations}</Text>
|
||||
)}
|
||||
</Box>
|
||||
);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue