mirror of
https://github.com/QwenLM/qwen-code.git
synced 2026-04-30 04:30:48 +00:00
refactor ui for qwen code hooks
This commit is contained in:
parent
38caa0b218
commit
b08154dbee
21 changed files with 972 additions and 357 deletions
109
packages/cli/src/ui/components/hooks/HooksListStep.tsx
Normal file
109
packages/cli/src/ui/components/hooks/HooksListStep.tsx
Normal file
|
|
@ -0,0 +1,109 @@
|
|||
/**
|
||||
* @license
|
||||
* Copyright 2026 Qwen Team
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import { useState } from 'react';
|
||||
import { Box, Text } from 'ink';
|
||||
import { theme } from '../../semantic-colors.js';
|
||||
import { useKeypress } from '../../hooks/useKeypress.js';
|
||||
import type { HookEventDisplayInfo } from './types.js';
|
||||
|
||||
interface HooksListStepProps {
|
||||
hooks: HookEventDisplayInfo[];
|
||||
onSelect: (index: number) => void;
|
||||
onCancel: () => void;
|
||||
}
|
||||
|
||||
export function HooksListStep({
|
||||
hooks,
|
||||
onSelect,
|
||||
onCancel,
|
||||
}: HooksListStepProps): React.JSX.Element {
|
||||
const [selectedIndex, setSelectedIndex] = useState(0);
|
||||
|
||||
useKeypress(
|
||||
(key) => {
|
||||
if (key.name === 'up') {
|
||||
setSelectedIndex((prev) => Math.max(0, prev - 1));
|
||||
} else if (key.name === 'down') {
|
||||
setSelectedIndex((prev) => Math.min(hooks.length - 1, prev + 1));
|
||||
} else if (key.name === 'return') {
|
||||
onSelect(selectedIndex);
|
||||
} else if (key.name === 'escape') {
|
||||
onCancel();
|
||||
}
|
||||
},
|
||||
{ isActive: true },
|
||||
);
|
||||
|
||||
if (hooks.length === 0) {
|
||||
return (
|
||||
<Box flexDirection="column" paddingX={1}>
|
||||
<Text color={theme.text.secondary}>No hook events found.</Text>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
// Calculate total configured hooks
|
||||
const totalConfigured = hooks.reduce(
|
||||
(sum, hook) => sum + hook.configs.length,
|
||||
0,
|
||||
);
|
||||
|
||||
return (
|
||||
<Box flexDirection="column" paddingX={1}>
|
||||
<Box marginBottom={1}>
|
||||
<Text bold color={theme.text.primary}>
|
||||
Hooks
|
||||
</Text>
|
||||
<Text color={theme.text.secondary}>
|
||||
{` · ${totalConfigured} hook${totalConfigured !== 1 ? 's' : ''} configured`}
|
||||
</Text>
|
||||
</Box>
|
||||
|
||||
<Box marginBottom={1}>
|
||||
<Text color={theme.text.secondary}>
|
||||
This menu is read-only. To add or modify hooks, edit settings.json
|
||||
directly or ask Qwen Code.
|
||||
</Text>
|
||||
</Box>
|
||||
|
||||
{hooks.map((hook, index) => {
|
||||
const isSelected = index === selectedIndex;
|
||||
const configCount = hook.configs.length;
|
||||
const maxDigits = String(hooks.length).length;
|
||||
const paddedIndex = String(index + 1).padStart(maxDigits);
|
||||
|
||||
return (
|
||||
<Box key={hook.event}>
|
||||
<Box minWidth={2}>
|
||||
<Text color={isSelected ? theme.text.accent : theme.text.primary}>
|
||||
{isSelected ? '❯' : ' '}
|
||||
</Text>
|
||||
</Box>
|
||||
<Box width={30}>
|
||||
<Text
|
||||
color={isSelected ? theme.text.accent : theme.text.primary}
|
||||
bold={isSelected}
|
||||
>
|
||||
{paddedIndex}. {hook.event}
|
||||
{configCount > 0 && (
|
||||
<Text color={theme.status.success}> ({configCount})</Text>
|
||||
)}
|
||||
</Text>
|
||||
</Box>
|
||||
<Text color={theme.text.secondary}>{hook.shortDescription}</Text>
|
||||
</Box>
|
||||
);
|
||||
})}
|
||||
|
||||
<Box marginTop={1}>
|
||||
<Text color={theme.text.secondary}>
|
||||
Enter to select · Esc to cancel
|
||||
</Text>
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue