fix(composer): show only approval card during authorization

This commit is contained in:
Codex committed 2026-10-21 16:04:52 +09:00
1 parent b4757dd843
commit 4a7f17961d
4 files changed
+32 -34

No files matched your search

@@ -146,24 +146,10 @@ export function readReferenceUris(transfer: Pick<DataTransfer, 'getData'>): stri
return transfer.getData('text/uri-list').split(/\r\n?|\n/).filter((value) => value.trim() && !value.startsWith('#'))
}
/** Keyed by request identity so a late cancellation result cannot affect its successor. */
function ApprovalComposerSurface({ children, onStop }: { children: ReactNode; onStop?: () => void | Promise<void> }): React.JSX.Element {
const [error, setError] = useState<string | null>(null)
const [busy, setBusy] = useState(false)
const busyRef = useRef(false)
const mounted = useRef(true)
useEffect(() => { mounted.current = true; return () => { mounted.current = false } }, [])
/** Keep each approval subtree scoped to its request identity. */
function ApprovalComposerSurface({ children }: { children: ReactNode }): React.JSX.Element {
return <div className="conversation-input-area__approval" data-composer-approval="true">
{children}
{onStop && <button type="button" className="wb-composer__approval-stop" aria-label="停止当前运行" disabled={busy} onClick={async () => {
if (busyRef.current) return
busyRef.current = true
setBusy(true)
setError(null)
try { await onStop() } catch (reason) { if (mounted.current) setError(errorText(reason)) }
finally { if (mounted.current) { busyRef.current = false; setBusy(false) } }
}}>停止当前运行</button>}
{error && <div className="wb-composer__error" role="alert">{error}</div>}
</div>
}
@@ -556,7 +542,7 @@ export function ComposerControls({
}
}}
>
{approvalTakeover && <ApprovalComposerSurface key={approvalKey ?? sessionId} onStop={onStop}>{approvalSlot}</ApprovalComposerSurface>}
{approvalTakeover && <ApprovalComposerSurface key={approvalKey ?? sessionId}>{approvalSlot}</ApprovalComposerSurface>}
{!approvalTakeover && floatingSlot && <div className="conversation-input-area__custom-floating">{floatingSlot}</div>}
<div ref={inputStackRef} hidden={approvalTakeover} inert={approvalTakeover} aria-hidden={approvalTakeover || undefined}
onFocusCapture={event => { if (approvalTakeover) { event.stopPropagation(); (event.target as HTMLElement).blur() } }}
@@ -550,4 +550,3 @@
/* B03: approval owns the bottom surface; keep draft state mounted, never visible/focusable. */
.wb-composer .conversation-input-area__input-stack[hidden] { display: none; }
.conversation-input-area__approval { width: 100%; min-width: 0; }
.wb-composer__approval-stop { display: block; margin: var(--yc-space-3) 0 0 auto; cursor: pointer; }
@@ -137,7 +137,7 @@ function panelId(value: ComposerInteractionSnapshot | ComposerNoticeSnapshot | C
* data.
* 4. Tasks move into the queue header when the queue is visible, otherwise
* they stay in the unified stack above the editor.
* 5. The running generation keeps its stop action reachable in every state.
* 5. Running state keeps its stop action semantics; approval takeover hides the normal toolbar and renders only the approval card.
*/
export function composeComposer(input: ComposerCompositionInput = {}): ComposerComposition {
const interaction = isActiveComposerInteraction(input.interaction) ? input.interaction : null