fix(session-ui): align provider error icon with first line (#52859)

Co-authored-by: iamdavidhill <1879069+iamdavidhill@users.noreply.github.com>
Co-authored-by: LukeParkerDev <10430890+Hona@users.noreply.github.com>
This commit is contained in:
opencode-agent[bot]
2026-10-06 13:07:18 +10:00
committed by GitHub
Unverified
parent bd55d4895f
commit 9daf46b327
3 changed files with 79 additions and 1 deletions
@@ -60,6 +60,30 @@ story("aligns the retry icon with the error label", async ({ mount }) => {
expect(iconY).toBe(labelY)
})
story("centers the error icon on the first line of short and wrapped errors", async ({ mount }) => {
const timeline = await mount("current-session-error-card--provider-errors")
const cards = timeline.locator('[data-kind="session-error-card"]')
await expect(cards).toHaveCount(2)
const geometry = await cards.evaluateAll((elements) =>
elements.map((card) => {
const icon = card.querySelector('[data-slot="icon-svg"]')!.getBoundingClientRect()
const message = card.querySelector('[data-slot="icon-svg"] + div')!
const line = parseFloat(getComputedStyle(message).lineHeight)
const box = message.getBoundingClientRect()
return {
lines: Math.round(box.height / line),
offset: icon.top + icon.height / 2 - (box.top + line / 2),
}
}),
)
expect(geometry.map((card) => card.lines > 1)).toEqual([false, true])
geometry.forEach((card) => expect(card.offset).toBeCloseTo(0, 0))
})
// Moved from packages/app/e2e/regression/session-timeline-context-state.spec.ts
story("preserves a collapsed context group through count and status updates", async ({ mount }) => {
const timeline = await mount("current-session-research-agents--agent-research", { args: { scenario: "exploration" } })
@@ -25,7 +25,7 @@ export function SessionErrorMessage(props: { message: string }) {
export function SessionError(props: { message: string }) {
return (
<Card variant="error" class="error-card" data-kind="session-error-card">
<div class="flex w-full min-w-0 items-center gap-2">
<div class="flex w-full min-w-0 items-start gap-2">
<Icon name="outline-hexagonal-warning" class="shrink-0 text-v2-state-fg-danger" />
<div class="min-w-0">
<SessionErrorMessage message={props.message} />
@@ -0,0 +1,54 @@
import type { SessionDocument } from "../document"
import { CURRENT_SESSION_ID, STORY_MODEL, STORY_TIME, thinkingDocument } from "../storybook/current-session-fixtures"
import { CurrentSessionTimelineStory } from "../storybook/current-session-story"
import { SessionTimeline } from "./session-timeline"
export default {
title: "OpenCode/Conversation/Error card",
id: "current-session-error-card",
component: SessionTimeline,
parameters: { layout: "fullscreen" },
}
const document = {
sessionID: CURRENT_SESSION_ID,
messages: [
...thinkingDocument.messages,
{
id: "msg_story_error_short",
type: "assistant",
agent: "build",
model: STORY_MODEL,
content: [],
error: { type: "provider.content-filter", message: "Provider blocked the response: Request declined." },
time: { created: STORY_TIME + 33_000, completed: STORY_TIME + 34_000 },
},
{ id: "msg_story_error_retry", type: "user", text: "Try again.", time: { created: STORY_TIME + 34_500 } },
{
id: "msg_story_error_long",
type: "assistant",
agent: "build",
model: STORY_MODEL,
content: [],
error: {
type: "provider.content-filter",
message:
"Provider blocked the response: This request could not be completed. Check the provider's documentation for the applicable policy, then try a different approach or model.",
},
time: { created: STORY_TIME + 35_000, completed: STORY_TIME + 36_000 },
},
],
status: { type: "idle" },
diffs: [],
} satisfies SessionDocument
export const ProviderErrors = {
render: () => (
<CurrentSessionTimelineStory
title="Provider errors"
description="Short and wrapped provider errors in the production timeline."
document={document}
width="480px"
/>
),
}