fix(web-shell): prevent artifact card overlap on narrow screens (#15300)

Co-authored-by: 钉萁 <[email protected]>
This commit is contained in:
ytahdnand钉萁 authored and GitHub committed 2026-10-23 03:51:17 +00:00
1 parent 23ddc5abb2
commit c5f317548b
3 files changed
+96 -1

No files matched your search

@@ -5,6 +5,7 @@
}
.card {
container-type: inline-size;
border: 1px solid var(--border);
border-radius: 8px;
background: var(--background);
@@ -212,5 +213,18 @@
.artifactMeta {
color: var(--muted-foreground);
font-size: 13px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
@container (max-width: 420px) {
.artifactSummary {
grid-template-columns: 36px minmax(0, 1fr);
}
.artifactSummary .actions {
grid-column: 2;
justify-self: end;
}
}
@@ -488,7 +488,7 @@ function ArtifactCard({
);
return (
<div className={styles.card}>
<div className={styles.summary}>
<div className={`${styles.summary} ${styles.artifactSummary}`}>
<span className={styles.icon} aria-hidden="true">
<ArtifactIcon artifact={artifact} className={styles.iconSvg} />
</span>
@@ -0,0 +1,81 @@
import { expect, test } from '@playwright/test';
import {
assistantTextEvent,
createWebShellDaemonScenario,
installMockDaemon,
toolCallEvent,
turnCompleteEvent,
userTextEvent,
} from './utils/mockDaemon';
for (const language of ['en', 'zh-CN']) {
test(`artifact text stays clear of its actions on narrow screens (${language})`, async ({
page,
}, testInfo) => {
const scenario = createWebShellDaemonScenario({
capabilities: { features: ['session_events', 'session_artifacts'] },
events: [
userTextEvent('Create Markdown artifacts.', { id: 1 }),
toolCallEvent('make-artifacts', 'Artifact', {}, { id: 2 }),
assistantTextEvent('Artifacts ready.', { id: 3 }),
turnCompleteEvent('done', { id: 4 }),
],
artifacts: [
'fy27b14-ui-feature-testset.md',
`${'long-filename-'.repeat(12)}.md`,
'short.md',
].map((name, index) => ({
id: `artifact-${index}`,
title: name,
kind: 'file',
storage: 'workspace',
source: 'tool',
status: index === 2 ? 'available' : 'changed',
workspacePath: name,
mimeType: 'text/markdown',
sizeBytes: 12083,
retention: 'ephemeral',
clientRetained: false,
toolCallId: 'make-artifacts',
toolName: 'Artifact',
createdAt: '2026-10-22T00:00:00Z',
updatedAt: '2026-10-22T00:00:00Z',
})),
});
await installMockDaemon(page, scenario, {
baseURL: String(testInfo.project.use.baseURL),
});
await page.goto(`/session/${scenario.sessionId}?lang=${language}`);
const infos = page.locator(
'[data-web-shell-message-list] [class*="artifactInfo"]',
);
await expect(infos).toHaveCount(3);
for (const width of [320, 375, 390, 768, 1280]) {
await page.setViewportSize({ width, height: 900 });
for (const info of await infos.all()) {
const summary = info.locator('..');
const actions = summary.locator('[class*="actions"]');
await expect(actions.getByRole('button')).toHaveCount(2);
const actionBounds = await actions.boundingBox();
const cardBounds = await summary.boundingBox();
expect(actionBounds).not.toBeNull();
expect(cardBounds).not.toBeNull();
expect(actionBounds!.x + actionBounds!.width).toBeLessThanOrEqual(
cardBounds!.x + cardBounds!.width,
);
for (const text of await info.locator(':scope > div').all()) {
const bounds = await text.boundingBox();
expect(bounds).not.toBeNull();
expect(bounds!.width).toBeGreaterThan(0);
expect(
bounds!.x + bounds!.width <= actionBounds!.x ||
bounds!.y + bounds!.height <= actionBounds!.y,
).toBe(true);
await expect(text).toHaveCSS('overflow-x', 'hidden');
await expect(text).toHaveCSS('text-overflow', 'ellipsis');
}
}
}
});
}