feat(web): drop elapsed timer and duplicate estimate from generation preview

The "usually 2–5 minutes" estimate showed twice (lead footnote + meta row)
and the elapsed counter added little signal, so remove both: delete the
meta row, stop falling back to the estimate footnote in the generating
lead (render the lead only when live narration exists), and drop the now
unused elapsed timer/util.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
chaoxiaoche 2026-05-30 17:13:37 +08:00
parent 4ca4df0cab
commit 876c0de2e6
4 changed files with 3 additions and 53 deletions

View file

@ -257,20 +257,6 @@
}
}
.meta {
display: flex;
flex-wrap: wrap;
align-items: center;
justify-content: center;
gap: 8px;
font-size: 12px;
color: var(--text-faint);
}
.metaDivider {
opacity: 0.6;
}
.retry {
margin-top: 4px;
min-height: 34px;

View file

@ -1,7 +1,5 @@
import { useEffect, useState } from 'react';
import { useT } from '../i18n';
import type { GenerationPreviewModel } from '../runtime/generation-preview';
import { formatGenerationElapsed } from '../runtime/generation-preview';
import { Icon } from './Icon';
import styles from './GenerationPreviewStage.module.css';
@ -12,19 +10,9 @@ type Props = {
export function GenerationPreviewStage({ model, onRetry }: Props) {
const t = useT();
const [now, setNow] = useState(() => Date.now());
const generating = model.phase === 'generating';
useEffect(() => {
if (!generating) return undefined;
const id = window.setInterval(() => setNow(Date.now()), 1000);
return () => window.clearInterval(id);
}, [generating, model.startedAt]);
const elapsedSec = Math.max(0, Math.round((now - model.startedAt) / 1000));
const elapsedLabel = formatGenerationElapsed(elapsedSec);
const stepLabels: Record<GenerationPreviewModel['steps'][number]['id'], string> = {
understand: t('generationPreview.stepUnderstand'),
generate: t('generationPreview.stepGenerate'),
@ -47,7 +35,7 @@ export function GenerationPreviewStage({ model, onRetry }: Props) {
? t('generationPreview.stoppedLead')
: model.phase === 'awaiting-input'
? t('generationPreview.awaitingLead')
: model.activityLabel || t('generationPreview.footnote');
: model.activityLabel;
const markIcon =
model.phase === 'failed' ? 'close' : model.phase === 'stopped' ? 'stop' : 'sparkles';
@ -69,11 +57,11 @@ export function GenerationPreviewStage({ model, onRetry }: Props) {
<Icon name={markIcon} size={24} />
</div>
<h1 className={styles.title}>{title}</h1>
{showSubstatus ? null : (
{!showSubstatus && lead ? (
<p className={styles.lead} data-live={generating && Boolean(model.activityLabel)}>
{lead}
</p>
)}
) : null}
<div
className={styles.progress}
data-active={generating}
@ -118,17 +106,6 @@ export function GenerationPreviewStage({ model, onRetry }: Props) {
) : null}
</div>
) : null}
{generating ? (
<div className={styles.meta}>
<span data-testid="generation-preview-elapsed">
{t('generationPreview.elapsed', { elapsed: elapsedLabel })}
</span>
<span className={styles.metaDivider} aria-hidden>
·
</span>
<span>{t('generationPreview.estimate')}</span>
</div>
) : null}
{model.phase === 'failed' && onRetry ? (
<button
type="button"

View file

@ -249,14 +249,6 @@ export function generationPreviewProgress(steps: GenerationPreviewStep[]): numbe
return Math.max(8, Math.min(steps.some((step) => step.status === 'failed') ? 72 : 92, Math.round(score * 100)));
}
export function formatGenerationElapsed(seconds: number): string {
const safe = Math.max(0, Math.floor(seconds));
if (safe < 60) return `${safe}s`;
const minutes = Math.floor(safe / 60);
const remainder = safe % 60;
return remainder > 0 ? `${minutes}m ${remainder}s` : `${minutes}m`;
}
function isActiveRunStatus(status: ChatMessage['runStatus']): boolean {
return status === 'queued' || status === 'running';
}

View file

@ -2,7 +2,6 @@ import { describe, expect, it } from 'vitest';
import {
buildGenerationPreviewState,
derivePrototypeGenerationSteps,
formatGenerationElapsed,
workspaceHasPreviewSurface,
} from '../../src/runtime/generation-preview';
import type { AgentEvent, ChatMessage } from '../../src/types';
@ -309,8 +308,4 @@ describe('generation preview helpers', () => {
).toBeNull();
});
it('formats elapsed durations for the meta row', () => {
expect(formatGenerationElapsed(42)).toBe('42s');
expect(formatGenerationElapsed(125)).toBe('2m 5s');
});
});