fix(ui): pin dock rows, verb labels on live tools, dedupe reject
Auto placement floated the new docks to the top of the main pane; every dock now owns an explicit grid row (and the layout regression guards them). Live tool rows use the streamed kind verb like persisted rows, and the approval card's fallback reject is omitted when the request already carries a reject option.
This commit is contained in:
@@ -666,7 +666,7 @@ function renderLiveTurn(): void {
|
||||
const label = row.querySelector<HTMLElement>('summary strong')
|
||||
if (label !== null) label.textContent = tool.title
|
||||
const statusEl = row.querySelector<HTMLElement>('summary span')
|
||||
if (statusEl !== null) statusEl.textContent = tool.status === 'failed' ? t('chat.toolFailed') : t('chat.toolUse')
|
||||
if (statusEl !== null) statusEl.textContent = tool.status === 'failed' ? t('chat.toolFailed') : verbForKind(state.liveToolMeta.get(tool.callId)?.kind)
|
||||
const body = row.querySelector<HTMLElement>('.activity-body pre')
|
||||
if (body !== null) body.textContent = tool.detail
|
||||
row.classList.toggle('failed', tool.status === 'failed')
|
||||
@@ -1088,7 +1088,7 @@ function renderInteractionDock(): void {
|
||||
<div class="interaction-actions">
|
||||
${request.kind === 'elicitation' ? `<button type="button" class="allow" data-respond-accept="${escapeHtml(request.id)}">${escapeHtml(t('interaction.accept'))}</button>` : ''}
|
||||
${request.options.map(option => `<button type="button" class="${option.kind.startsWith('allow') ? 'allow' : 'reject'}" data-respond-option="${escapeHtml(option.optionId)}" data-respond-id="${escapeHtml(request.id)}">${escapeHtml(option.name)}</button>`).join('')}
|
||||
<button type="button" data-respond-cancel="${escapeHtml(request.id)}">${escapeHtml(t('interaction.dismiss'))}</button>
|
||||
${request.options.some(option => option.kind.startsWith('reject')) ? '' : `<button type="button" data-respond-cancel="${escapeHtml(request.id)}">${escapeHtml(t('interaction.dismiss'))}</button>`}
|
||||
</div>
|
||||
</section>
|
||||
`).join('')
|
||||
@@ -1170,7 +1170,10 @@ function liveToolTitle(target: TraceTarget): string | undefined {
|
||||
|
||||
/** Verb label for a tool row: the streamed ACP kind beats the generic noun. */
|
||||
function toolVerbLabel(target: TraceTarget): string {
|
||||
const kind = liveToolMetaOf(target).kind
|
||||
return verbForKind(liveToolMetaOf(target).kind)
|
||||
}
|
||||
|
||||
function verbForKind(kind: string | undefined): string {
|
||||
if (kind === 'read') return t('kind.verb.read')
|
||||
if (kind === 'edit') return t('kind.verb.edit')
|
||||
if (kind === 'delete') return t('kind.verb.delete')
|
||||
|
||||
@@ -391,7 +391,8 @@ kbd {
|
||||
display: grid;
|
||||
min-width: 0;
|
||||
min-height: 0;
|
||||
grid-template-rows: 58px auto minmax(0, 1fr) auto;
|
||||
/* topbar / notice / canvas / interaction / queue / plan / composer */
|
||||
grid-template-rows: 58px auto minmax(0, 1fr) auto auto auto auto;
|
||||
background: var(--paper);
|
||||
}
|
||||
|
||||
@@ -408,10 +409,22 @@ kbd {
|
||||
grid-row: 3;
|
||||
}
|
||||
|
||||
.composer {
|
||||
#interactionDock {
|
||||
grid-row: 4;
|
||||
}
|
||||
|
||||
#queueDock {
|
||||
grid-row: 5;
|
||||
}
|
||||
|
||||
#planDock {
|
||||
grid-row: 6;
|
||||
}
|
||||
|
||||
.composer {
|
||||
grid-row: 7;
|
||||
}
|
||||
|
||||
.topbar {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(220px, 1fr) auto auto;
|
||||
|
||||
@@ -41,10 +41,15 @@ describe('desktop live content', () => {
|
||||
})
|
||||
|
||||
describe('desktop shell layout', () => {
|
||||
it('pins the composer to its intrinsic bottom row', async () => {
|
||||
it('pins the docks and composer to their explicit bottom rows', async () => {
|
||||
const css = await readFile(new URL('../src/styles.css', import.meta.url), 'utf8')
|
||||
expect(css).toMatch(/\.session-canvas,\s*\.module-canvas\s*{\s*grid-row: 3;/)
|
||||
expect(css).toMatch(/\.composer\s*{\s*grid-row: 4;/)
|
||||
// Every dock needs an explicit row: auto placement once floated the queue
|
||||
// to the top of the main pane.
|
||||
expect(css).toMatch(/#interactionDock\s*{\s*grid-row: 4;/)
|
||||
expect(css).toMatch(/#queueDock\s*{\s*grid-row: 5;/)
|
||||
expect(css).toMatch(/#planDock\s*{\s*grid-row: 6;/)
|
||||
expect(css).toMatch(/\.composer\s*{\s*grid-row: 7;/)
|
||||
})
|
||||
|
||||
it('does not launch Electron after a strict-port Vite failure', async () => {
|
||||
|
||||
Reference in New Issue
Block a user