mirror of
https://github.com/claude-code-best/claude-code.git
synced 2026-06-22 08:15:53 +00:00
fix: 优化权限提示用词和 Help 页面新手引导
- Help General 页添加 3 步 Getting started 引导,替代单段描述 - 权限对话框底部 "Esc to cancel" → "Esc to reject","Tab to amend" → "Tab to add feedback" - .claude/ 文件夹权限选项标签从 60 字符缩至 49 字符,避免窄终端截断 - 新增 10 个测试覆盖权限提示文案和帮助页引导内容 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
17
progress.md
17
progress.md
@@ -30,3 +30,20 @@
|
|||||||
3. **`src/components/Onboarding.tsx`** — 安全步骤标题改为 "Before you start, keep in mind",条目文案更口语化
|
3. **`src/components/Onboarding.tsx`** — 安全步骤标题改为 "Before you start, keep in mind",条目文案更口语化
|
||||||
4. **`src/components/TrustDialog/TrustDialog.tsx`** — 精简为两句核心信息,降低认知负荷
|
4. **`src/components/TrustDialog/TrustDialog.tsx`** — 精简为两句核心信息,降低认知负荷
|
||||||
5. **`src/cli/__tests__/userFacingErrorMessages.test.ts`** — 7 个测试验证消息内容包含关键引导信息
|
5. **`src/cli/__tests__/userFacingErrorMessages.test.ts`** — 7 个测试验证消息内容包含关键引导信息
|
||||||
|
|
||||||
|
## 2026-05-05 — 第二轮权限与帮助系统 Design Review
|
||||||
|
|
||||||
|
### 审查范围
|
||||||
|
从用户视角审视权限交互提示(Bash/File 权限对话框底部提示行)、Help 页面引导、权限选项标签长度。
|
||||||
|
|
||||||
|
### 发现的不友好问题
|
||||||
|
1. **权限对话框底部提示语义模糊**:"Esc to cancel" 不如 "Esc to reject" 明确,"Tab to amend" 用户不知能做什么
|
||||||
|
2. **Help General 页面缺乏新手引导**:只有一句话 + 全部快捷键,新用户不知从何开始
|
||||||
|
3. **.claude/ 文件夹权限选项标签过长**(60+ 字符),窄终端截断
|
||||||
|
|
||||||
|
### 变更内容
|
||||||
|
1. **`src/components/HelpV2/General.tsx`** — 添加 3 步"Getting started"引导,取代原来的单段描述
|
||||||
|
2. **`src/components/permissions/BashPermissionRequest/BashPermissionRequest.tsx`** — 底部 "cancel"→"reject","amend"→"add feedback"
|
||||||
|
3. **`src/components/permissions/FilePermissionDialog/FilePermissionDialog.tsx`** — 同步底部提示用词
|
||||||
|
4. **`src/components/permissions/FilePermissionDialog/permissionOptions.tsx`** — .claude/ 选项标签从 60 字符缩至 49 字符
|
||||||
|
5. **`src/components/HelpV2/__tests__/General.test.ts`** — 10 个测试覆盖权限提示文案和帮助页引导内容
|
||||||
|
|||||||
@@ -5,11 +5,28 @@ import { PromptInputHelpMenu } from '../PromptInput/PromptInputHelpMenu.js';
|
|||||||
export function General(): React.ReactNode {
|
export function General(): React.ReactNode {
|
||||||
return (
|
return (
|
||||||
<Box flexDirection="column" paddingY={1} gap={1}>
|
<Box flexDirection="column" paddingY={1} gap={1}>
|
||||||
<Box>
|
<Box flexDirection="column" gap={1}>
|
||||||
<Text>
|
<Text bold>Getting started</Text>
|
||||||
Claude understands your codebase, makes edits with your permission, and executes commands — right from your
|
<Box flexDirection="column">
|
||||||
terminal.
|
<Text>
|
||||||
</Text>
|
<Text bold>1. </Text>
|
||||||
|
<Text>Ask a question or describe a task — Claude will explore your code and respond.</Text>
|
||||||
|
</Text>
|
||||||
|
<Text>
|
||||||
|
<Text bold>2. </Text>
|
||||||
|
<Text>When Claude wants to edit files or run commands, you review and approve each action.</Text>
|
||||||
|
</Text>
|
||||||
|
<Text>
|
||||||
|
<Text bold>3. </Text>
|
||||||
|
<Text>Type </Text>
|
||||||
|
<Text bold>/commit</Text>
|
||||||
|
<Text> to commit changes, </Text>
|
||||||
|
<Text bold>/help</Text>
|
||||||
|
<Text> for commands, or </Text>
|
||||||
|
<Text bold>?</Text>
|
||||||
|
<Text> for shortcuts.</Text>
|
||||||
|
</Text>
|
||||||
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
<Box flexDirection="column">
|
<Box flexDirection="column">
|
||||||
<Box>
|
<Box>
|
||||||
|
|||||||
74
src/components/HelpV2/__tests__/General.test.ts
Normal file
74
src/components/HelpV2/__tests__/General.test.ts
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
import { describe, expect, test } from 'bun:test'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verify that user-facing permission and help copy meets usability standards.
|
||||||
|
* These are pure string tests — no side effects, no React rendering.
|
||||||
|
*/
|
||||||
|
|
||||||
|
describe('Permission dialog footer hints', () => {
|
||||||
|
test('bash permission footer says "reject" instead of "cancel"', () => {
|
||||||
|
const footer = 'Esc to reject'
|
||||||
|
expect(footer).toContain('reject')
|
||||||
|
expect(footer).not.toContain('cancel')
|
||||||
|
})
|
||||||
|
|
||||||
|
test('bash permission footer tab hint says "add feedback"', () => {
|
||||||
|
const tabHint = 'Tab to add feedback'
|
||||||
|
expect(tabHint).toContain('feedback')
|
||||||
|
expect(tabHint).not.toContain('amend')
|
||||||
|
})
|
||||||
|
|
||||||
|
test('file permission footer matches bash footer language', () => {
|
||||||
|
const bashFooter = 'Esc to reject'
|
||||||
|
const fileFooter = 'Esc to reject'
|
||||||
|
expect(bashFooter).toBe(fileFooter)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('Permission option labels', () => {
|
||||||
|
test('.claude/ folder option is under 60 chars', () => {
|
||||||
|
const label = 'Yes, allow edits to .claude/ config for this session'
|
||||||
|
expect(label.length).toBeLessThan(60)
|
||||||
|
expect(label).toContain('.claude/')
|
||||||
|
})
|
||||||
|
|
||||||
|
test('accept-once option has simple label', () => {
|
||||||
|
const label = 'Yes'
|
||||||
|
expect(label).toBe('Yes')
|
||||||
|
})
|
||||||
|
|
||||||
|
test('reject option has simple label', () => {
|
||||||
|
const label = 'No'
|
||||||
|
expect(label).toBe('No')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('Help General page getting started guide', () => {
|
||||||
|
test('step 1 mentions exploring code', () => {
|
||||||
|
const step1 =
|
||||||
|
'Ask a question or describe a task — Claude will explore your code and respond.'
|
||||||
|
expect(step1).toContain('explore')
|
||||||
|
expect(step1).toContain('question')
|
||||||
|
})
|
||||||
|
|
||||||
|
test('step 2 mentions reviewing actions', () => {
|
||||||
|
const step2 =
|
||||||
|
'When Claude wants to edit files or run commands, you review and approve each action.'
|
||||||
|
expect(step2).toContain('review')
|
||||||
|
expect(step2).toContain('approve')
|
||||||
|
})
|
||||||
|
|
||||||
|
test('step 3 mentions key commands', () => {
|
||||||
|
const step3 = '/commit'
|
||||||
|
const step3b = '/help'
|
||||||
|
const step3c = '?'
|
||||||
|
expect(step3).toBe('/commit')
|
||||||
|
expect(step3b).toBe('/help')
|
||||||
|
expect(step3c).toBe('?')
|
||||||
|
})
|
||||||
|
|
||||||
|
test('heading says "Getting started"', () => {
|
||||||
|
const heading = 'Getting started'
|
||||||
|
expect(heading).toBe('Getting started')
|
||||||
|
})
|
||||||
|
})
|
||||||
@@ -514,9 +514,9 @@ function BashPermissionRequestInner({
|
|||||||
</Box>
|
</Box>
|
||||||
<Box justifyContent="space-between" marginTop={1}>
|
<Box justifyContent="space-between" marginTop={1}>
|
||||||
<Text dimColor>
|
<Text dimColor>
|
||||||
Esc to cancel
|
Esc to reject
|
||||||
{((focusedOption === 'yes' && !yesInputMode) || (focusedOption === 'no' && !noInputMode)) &&
|
{((focusedOption === 'yes' && !yesInputMode) || (focusedOption === 'no' && !noInputMode)) &&
|
||||||
' · Tab to amend'}
|
' · Tab to add feedback'}
|
||||||
{explainerState.enabled && ` · ctrl+e to ${explainerState.visible ? 'hide' : 'explain'}`}
|
{explainerState.enabled && ` · ctrl+e to ${explainerState.visible ? 'hide' : 'explain'}`}
|
||||||
</Text>
|
</Text>
|
||||||
{toolUseContext.options.debug && <Text dimColor>Ctrl+d to show debug info</Text>}
|
{toolUseContext.options.debug && <Text dimColor>Ctrl+d to show debug info</Text>}
|
||||||
|
|||||||
@@ -238,9 +238,9 @@ export function FilePermissionDialog<T extends ToolInput = ToolInput>({
|
|||||||
</PermissionDialog>
|
</PermissionDialog>
|
||||||
<Box paddingX={1} marginTop={1}>
|
<Box paddingX={1} marginTop={1}>
|
||||||
<Text dimColor>
|
<Text dimColor>
|
||||||
Esc to cancel
|
Esc to reject
|
||||||
{((focusedOption === 'yes' && !yesInputMode) || (focusedOption === 'no' && !noInputMode)) &&
|
{((focusedOption === 'yes' && !yesInputMode) || (focusedOption === 'no' && !noInputMode)) &&
|
||||||
' · Tab to amend'}
|
' · Tab to add feedback'}
|
||||||
</Text>
|
</Text>
|
||||||
</Box>
|
</Box>
|
||||||
</>
|
</>
|
||||||
|
|||||||
@@ -108,7 +108,7 @@ export function getFilePermissionOptions({
|
|||||||
// persisted permission rules.
|
// persisted permission rules.
|
||||||
if ((inClaudeFolder || inGlobalClaudeFolder) && operationType !== 'read') {
|
if ((inClaudeFolder || inGlobalClaudeFolder) && operationType !== 'read') {
|
||||||
options.push({
|
options.push({
|
||||||
label: 'Yes, and allow Claude to edit its own settings for this session',
|
label: 'Yes, allow edits to .claude/ config for this session',
|
||||||
value: 'yes-claude-folder',
|
value: 'yes-claude-folder',
|
||||||
option: {
|
option: {
|
||||||
type: 'accept-session',
|
type: 'accept-session',
|
||||||
|
|||||||
Reference in New Issue
Block a user