add hook detail page

This commit is contained in:
DennisYu07 2026-03-24 18:08:15 +08:00
parent 247e8b8742
commit a0b3cc3268
12 changed files with 689 additions and 17 deletions

View file

@ -0,0 +1,179 @@
/**
* @license
* Copyright 2026 Qwen Team
* SPDX-License-Identifier: Apache-2.0
*/
import { Box, Text } from 'ink';
import { theme } from '../../semantic-colors.js';
import { useKeypress } from '../../hooks/useKeypress.js';
import { useTerminalSize } from '../../hooks/useTerminalSize.js';
import type { HookConfigDisplayInfo, HookEventDisplayInfo } from './types.js';
import { HooksConfigSource } from '@qwen-code/qwen-code-core';
import { t } from '../../../i18n/index.js';
interface HookConfigDetailStepProps {
hookEvent: HookEventDisplayInfo;
hookConfig: HookConfigDisplayInfo;
onBack: () => void;
}
export function HookConfigDetailStep({
hookEvent,
hookConfig,
onBack,
}: HookConfigDetailStepProps): React.JSX.Element {
const { columns: terminalWidth } = useTerminalSize();
useKeypress(
(key) => {
if (key.name === 'escape') {
onBack();
}
},
{ isActive: true },
);
// Get source display
const getSourceDisplay = (): string => {
switch (hookConfig.source) {
case HooksConfigSource.Project:
return t('Local Settings');
case HooksConfigSource.User:
return t('User Settings');
case HooksConfigSource.System:
return t('System Settings');
case HooksConfigSource.Extensions:
return t('Extensions');
default:
return hookConfig.source;
}
};
// Check if this is from an extension
const isFromExtension = hookConfig.source === HooksConfigSource.Extensions;
// Get hook type display
const getHookTypeDisplay = (): string => {
switch (hookConfig.config.type) {
case 'command':
return 'command';
default:
return hookConfig.config.type;
}
};
// Get command to display
const getCommand = (): string => {
if (hookConfig.config.type === 'command') {
return hookConfig.config.command;
}
return '';
};
// Calculate box width for command display
const commandBoxWidth = Math.min(terminalWidth - 6, 80);
// Label width for alignment (Extension: is the longest label)
const labelWidth = 12;
return (
<Box flexDirection="column" paddingX={1}>
{/* Title */}
<Box marginBottom={1}>
<Text bold color={theme.text.primary}>
{t('Hook details')}
</Text>
</Box>
{/* Event */}
<Box>
<Box width={labelWidth}>
<Text color={theme.text.secondary}>{t('Event:')}</Text>
</Box>
<Text color={theme.text.primary}>{hookEvent.event}</Text>
</Box>
{/* Type */}
<Box>
<Box width={labelWidth}>
<Text color={theme.text.secondary}>{t('Type:')}</Text>
</Box>
<Text color={theme.text.primary}>{getHookTypeDisplay()}</Text>
</Box>
{/* Source */}
<Box>
<Box width={labelWidth}>
<Text color={theme.text.secondary}>{t('Source:')}</Text>
</Box>
<Text color={theme.text.primary}>{getSourceDisplay()}</Text>
{hookConfig.sourcePath && (
<Text color={theme.text.secondary}> ({hookConfig.sourcePath})</Text>
)}
</Box>
{/* Extension name (only for extensions) */}
{isFromExtension && hookConfig.sourceDisplay && (
<Box>
<Box width={labelWidth}>
<Text color={theme.text.secondary}>{t('Extension:')}</Text>
</Box>
<Text color={theme.text.primary}>{hookConfig.sourceDisplay}</Text>
</Box>
)}
{/* Name (if exists) */}
{hookConfig.config.name && (
<Box>
<Box width={labelWidth}>
<Text color={theme.text.secondary}>{t('Name:')}</Text>
</Box>
<Text color={theme.text.primary}>{hookConfig.config.name}</Text>
</Box>
)}
{/* Description (if exists) */}
{hookConfig.config.description && (
<Box>
<Box width={labelWidth}>
<Text color={theme.text.secondary}>{t('Desc:')}</Text>
</Box>
<Text color={theme.text.primary}>
{hookConfig.config.description}
</Text>
</Box>
)}
{/* Command */}
<Box marginTop={1}>
<Text color={theme.text.secondary}>{t('Command:')}</Text>
</Box>
{/* Command box */}
<Box
flexDirection="column"
borderStyle="round"
borderColor={theme.border.default}
paddingX={1}
width={commandBoxWidth}
>
<Text color={theme.text.primary}>{getCommand()}</Text>
</Box>
{/* Help text */}
<Box marginTop={1}>
<Text color={theme.text.secondary}>
{t(
'To modify or remove this hook, edit settings.json directly or ask Qwen to help.',
)}
</Text>
</Box>
{/* Footer hint */}
<Box marginTop={1}>
<Text color={theme.text.secondary}>{t('Esc to go back')}</Text>
</Box>
</Box>
);
}