fix: match Code microphone and send button order
This commit is contained in:
1 parent
f61efaf046
commit
ddb942f944
4 files changed
+13
-2
No files matched your search
@@ -26,7 +26,7 @@
|
|||||||
|
|
||||||
## Verification
|
## Verification
|
||||||
|
|
||||||
- Current-baseline 253 related regression tests passed (11 files), 28 voice tests including StrictMode passed, and 31 new upload/lifecycle tests passed: 312 disjoint cases. Final typecheck, focused lint (0 errors; two existing CloudChat warnings), full Renderer/Main/Preload/utility Vite build and project-docs/diff gates passed. Independent review has no open blocker. 17 disjoint Electron scenarios passed: 12 in first run plus 5 targeted reruns after updating inherited timestamp/recovery assertions to the exact current trial contract. Published voice fixture validates WAV transcription, latest-draft append, no automatic prompts, 32px buttons and multi-line growth; layout covers narrow/wide windows, long messages, attachments and stream/stop. Voice screenshot visually inspected by root and QA. Fixture audio never accesses the real microphone or paid provider. Real microphone/provider transcription remains distinct from fixture validation.
|
- Current-baseline 253 related regression tests passed (11 files), 28 voice tests including StrictMode passed, and 31 new upload/lifecycle tests passed: 312 disjoint cases. Final typecheck, focused lint (0 errors; two existing CloudChat warnings), full Renderer/Main/Preload/utility Vite build and project-docs/diff gates passed. Independent review has no open blocker. 17 disjoint Electron scenarios passed: 12 in first run plus 5 targeted reruns after updating inherited timestamp/recovery assertions to the exact current trial contract. Published voice fixture validates WAV transcription, latest-draft append, no automatic prompts, 32px buttons and multi-line growth; layout covers narrow/wide windows, long messages, attachments and stream/stop. Voice screenshot visually inspected by root and QA. Final comparison moved the microphone beside send on the right, matching Code; a fresh full build/typecheck and two targeted Electron reruns passed, including 4px adjacency and 375px layout. Fixture audio never accesses the real microphone or paid provider. Real microphone/provider transcription remains distinct from fixture validation.
|
||||||
|
|
||||||
## Follow-ups
|
## Follow-ups
|
||||||
|
|
||||||
|
|||||||
@@ -441,7 +441,6 @@ export function CloudChat({ slug, previewRevision: latestRevision, initialThread
|
|||||||
headerTarget={attachmentHeader === undefined ? localAttachmentHeader : attachmentHeader} activeView={activeView}
|
headerTarget={attachmentHeader === undefined ? localAttachmentHeader : attachmentHeader} activeView={activeView}
|
||||||
deliveryHistory={history}
|
deliveryHistory={history}
|
||||||
filesRevision={`${history?.messages.at(-1)?.id ?? ''}:${history?.run?.agent_run_id ?? ''}:${history?.run?.status ?? ''}`}
|
filesRevision={`${history?.messages.at(-1)?.id ?? ''}:${history?.run?.agent_run_id ?? ''}:${history?.run?.status ?? ''}`}
|
||||||
actions={<ComposerVoiceButton voiceInput={voiceInput} />}
|
|
||||||
onBusy={setAttachmentBusy} disabled={!editable || running || voicePending} ensureThread={async () => {
|
onBusy={setAttachmentBusy} disabled={!editable || running || voicePending} ensureThread={async () => {
|
||||||
if (thread) return thread.thread_id;
|
if (thread) return thread.thread_id;
|
||||||
const expectedGeneration = generation.current;
|
const expectedGeneration = generation.current;
|
||||||
@@ -452,8 +451,11 @@ export function CloudChat({ slug, previewRevision: latestRevision, initialThread
|
|||||||
return created.thread_id;
|
return created.thread_id;
|
||||||
}} footer={<>
|
}} footer={<>
|
||||||
<span className="agent-chat-keyboard-hint">Enter 发送 · Shift + Enter 换行</span>
|
<span className="agent-chat-keyboard-hint">Enter 发送 · Shift + Enter 换行</span>
|
||||||
|
<div className="agent-chat-composer-controls">
|
||||||
|
<ComposerVoiceButton voiceInput={voiceInput} />
|
||||||
{running ? <Button className="agent-chat-stop agent-chat-submit" size="icon" variant="outline" disabled={busy} onClick={() => void cancel()} type="button" aria-label="停止" title="停止"><Square className="h-3.5 w-3.5 fill-current" /></Button>
|
{running ? <Button className="agent-chat-stop agent-chat-submit" size="icon" variant="outline" disabled={busy} onClick={() => void cancel()} type="button" aria-label="停止" title="停止"><Square className="h-3.5 w-3.5 fill-current" /></Button>
|
||||||
: <Button className="agent-chat-send agent-chat-submit" size="icon" type="submit" aria-label={busy ? '正在提交' : intent ? '重试本次发送' : '发送'} title={intent ? '重试本次发送' : '发送'} disabled={!canSend}>{busy ? <LoaderCircle className="h-4 w-4 animate-spin" /> : <ArrowUp className="h-4 w-4" />}</Button>}
|
: <Button className="agent-chat-send agent-chat-submit" size="icon" type="submit" aria-label={busy ? '正在提交' : intent ? '重试本次发送' : '发送'} title={intent ? '重试本次发送' : '发送'} disabled={!canSend}>{busy ? <LoaderCircle className="h-4 w-4 animate-spin" /> : <ArrowUp className="h-4 w-4" />}</Button>}
|
||||||
|
</div>
|
||||||
</>}>
|
</>}>
|
||||||
<Textarea aria-label="消息" className="agent-chat-input resize-none border-0 shadow-none focus-visible:ring-0" maxLength={32000}
|
<Textarea aria-label="消息" className="agent-chat-input resize-none border-0 shadow-none focus-visible:ring-0" maxLength={32000}
|
||||||
rows={Math.min(6, Math.max(1, query.split('\n').length))}
|
rows={Math.min(6, Math.max(1, query.split('\n').length))}
|
||||||
|
|||||||
@@ -146,6 +146,7 @@
|
|||||||
.agent-chat-composer .agent-attachment-add:hover:not(:disabled) { background: hsl(var(--surface-subtle)); }
|
.agent-chat-composer .agent-attachment-add:hover:not(:disabled) { background: hsl(var(--surface-subtle)); }
|
||||||
.agent-chat-composer .agent-attachment-add > svg { width: 16px; height: 16px; }
|
.agent-chat-composer .agent-attachment-add > svg { width: 16px; height: 16px; }
|
||||||
.agent-attachment-toolbar .agent-chat-keyboard-hint { margin-left: auto; }
|
.agent-attachment-toolbar .agent-chat-keyboard-hint { margin-left: auto; }
|
||||||
|
.agent-chat-composer-controls { display: flex; min-width: 0; flex-shrink: 0; align-items: center; gap: 4px; margin-left: auto; }
|
||||||
.agent-attachment-toolbar > :is(.agent-chat-send, .agent-chat-stop, .agent-chat-submit) { margin-left: auto; }
|
.agent-attachment-toolbar > :is(.agent-chat-send, .agent-chat-stop, .agent-chat-submit) { margin-left: auto; }
|
||||||
.agent-attachment-toolbar .agent-chat-keyboard-hint + :is(.agent-chat-send, .agent-chat-stop, .agent-chat-submit) { margin-left: 4px; }
|
.agent-attachment-toolbar .agent-chat-keyboard-hint + :is(.agent-chat-send, .agent-chat-stop, .agent-chat-submit) { margin-left: 4px; }
|
||||||
.agent-chat-composer .agent-attachment-selected { gap: 8px; margin-bottom: 8px; padding-inline: 4px; }
|
.agent-chat-composer .agent-attachment-selected { gap: 8px; margin-bottom: 8px; padding-inline: 4px; }
|
||||||
|
|||||||
@@ -359,6 +359,14 @@ test('personal cloud Agent identity, configuration and separate published chat i
|
|||||||
expect(sendGeometry.width).toBe(32);
|
expect(sendGeometry.width).toBe(32);
|
||||||
expect(sendGeometry.height).toBe(32);
|
expect(sendGeometry.height).toBe(32);
|
||||||
expect(sendGeometry.radius).toBeGreaterThanOrEqual(sendGeometry.width / 2);
|
expect(sendGeometry.radius).toBeGreaterThanOrEqual(sendGeometry.width / 2);
|
||||||
|
const toolbarPositions = await voiceComposer.locator('[aria-label="添加文件或图片"], [aria-label="语音输入"], [aria-label="发送"]').evaluateAll(elements =>
|
||||||
|
Object.fromEntries(elements.map(element => {
|
||||||
|
const bounds = element.getBoundingClientRect();
|
||||||
|
return [element.getAttribute('aria-label'), { left: bounds.left, right: bounds.right }];
|
||||||
|
})));
|
||||||
|
expect(toolbarPositions['语音输入'].left).toBeGreaterThan(toolbarPositions['添加文件或图片'].right);
|
||||||
|
expect(toolbarPositions['发送'].left).toBeGreaterThan(toolbarPositions['语音输入'].right);
|
||||||
|
expect(toolbarPositions['发送'].left - toolbarPositions['语音输入'].right).toBeCloseTo(4, 1);
|
||||||
await voiceDraft.fill('原来的想法');
|
await voiceDraft.fill('原来的想法');
|
||||||
await voiceComposer.getByRole('button', { name: '语音输入', exact: true }).click();
|
await voiceComposer.getByRole('button', { name: '语音输入', exact: true }).click();
|
||||||
await expect(voiceComposer.getByRole('button', { name: '停止语音输入' })).toBeVisible();
|
await expect(voiceComposer.getByRole('button', { name: '停止语音输入' })).toBeVisible();
|
||||||
|
|||||||
Reference in new issue
Block a user