fix(browser-preview): hide the chip identity row below 24rem instead of clipping it, ellipsize the host badge, catalog the new i18n keys (STA-5758)

CI's preview pane leaves the chip ~40px: no truncation shows anything
there, so the Workspace-file label and host badge now hide whole below a
24rem container threshold sized so that visible implies contained. The
badge text gains an inner text box — text directly inside the flex pill
clipped both ends with no ellipsis. The e2e geometry oracle asserts
containment when the row shows and the threshold when it does not.

verify:localization-catalog: the hardening's new preview keys (and the
renamed allowDirectory) join en.json via sync:localization-catalog.
This commit is contained in:
Jinwoo-H
2026-08-28 00:28:39 -04:00
parent eff1ce8a8f
commit ff14b2588f
3 changed files with 37 additions and 17 deletions
@@ -35,7 +35,7 @@ export function DocPreviewDocumentChip({
type="button"
onClick={() => void copyText()}
aria-label={copied ? copiedLabel : copyLabel}
className="flex min-w-0 flex-1 items-center gap-2 overflow-hidden rounded-xl border border-border bg-background px-3 py-1 text-left shadow-sm hover:bg-accent/40 focus-visible:ring-[3px] focus-visible:ring-ring/50 focus-visible:outline-none"
className="@container flex min-w-0 flex-1 items-center gap-2 overflow-hidden rounded-xl border border-border bg-background px-3 py-1 text-left shadow-sm hover:bg-accent/40 focus-visible:ring-[3px] focus-visible:ring-ring/50 focus-visible:outline-none"
>
{copied ? (
<Check className="size-4 shrink-0 text-muted-foreground" />
@@ -47,19 +47,21 @@ export function DocPreviewDocumentChip({
<span className="text-muted-foreground">{identity.directoryPrefix}</span>
<span className="text-foreground">{identity.fileName}</span>
</span>
{/* Why everything here can shrink: a fixed-width child of a squeezed flex row overflows
its parent's layout box even under overflow-hidden, and this row sits beside a path
that can be arbitrarily long in an arbitrarily narrow pane. */}
<span className="hidden min-w-0 items-center gap-1.5 text-xs text-muted-foreground sm:flex">
<span className="min-w-0 truncate">
{/* Below 24rem of chip width this row hides whole rather than clipping into slivers —
384px is what icon + label + a capped badge + a readable path stub need, so visible
implies contained. The tooltip keeps the full identity either way. */}
<span className="hidden shrink-0 items-center gap-1.5 text-xs text-muted-foreground @[24rem]:flex">
<span className="shrink-0">
{translate(
'auto.components.editor.HtmlDocPreview.workspaceFileChipLabel',
'Workspace file'
)}
</span>
{identity.hostLabel ? (
<Badge variant="secondary" className="min-w-0 max-w-40 shrink truncate font-normal">
{identity.hostLabel}
<Badge variant="secondary" className="min-w-0 max-w-40 shrink font-normal">
{/* Why the inner span: text directly inside the flex pill clips both ends with no
ellipsis — text-overflow needs a non-flex text box. */}
<span className="min-w-0 truncate">{identity.hostLabel}</span>
</Badge>
) : null}
</span>
+12 -1
View File
@@ -14811,7 +14811,11 @@
"openExternallyControl": "Open with default app",
"copyDocumentRelativePathControl": "Copy relative path",
"openExternallyUnknownHostError": "Can't open '{{value0}}': the host that owns it is no longer known.",
"downloadBlockedNotice": "Downloads are disabled in document previews."
"downloadBlockedNotice": "Downloads are disabled in document previews.",
"directoryAuthorizationFailed": "Could not allow access to this directory.",
"directoryAccessRequest": "This preview wants to read files in {{path}}.",
"dismissAccessRequest": "Dismiss",
"allowDirectory": "Allow folder"
}
},
"diff": {
@@ -16355,6 +16359,13 @@
"description": "Nests this workspace under another in the sidebar. Does not change the base branch.",
"searchPlaceholder": "Search workspaces...",
"noMatches": "No matches."
},
"browserPane": {
"workspaceDoc": {
"externalLinkTitle": "Open link to {{host}}?",
"externalLinkConfirm": "Open link",
"externalLinkCancel": "Cancel"
}
}
},
"i18n": {
@@ -289,16 +289,23 @@ test('renders a paired HTML doc as a document browser tab while the host gains n
const pathChip = page.getByRole('button', { name: 'Copy file path', exact: true })
await expect(pathChip).toBeVisible({ timeout: 30_000 })
await expect(pathChip).toContainText(FIXTURE_NAME)
// Below 24rem of chip width the identity row hides whole instead of clipping into slivers;
// when it shows, the badge must sit inside the chip's own layout box. Which arm runs depends
// on how much width this platform's toolbar leaves the chip — both are the contract.
const hostBadge = pathChip.locator('[data-slot="badge"]')
const [pathChipBox, hostBadgeBox] = await Promise.all([
pathChip.boundingBox(),
hostBadge.boundingBox()
])
const pathChipBox = await pathChip.boundingBox()
expect(pathChipBox).not.toBeNull()
expect(hostBadgeBox).not.toBeNull()
expect((hostBadgeBox?.x ?? 0) + (hostBadgeBox?.width ?? 0)).toBeLessThanOrEqual(
(pathChipBox?.x ?? 0) + (pathChipBox?.width ?? 0) + 0.5
)
if (await hostBadge.isVisible()) {
const hostBadgeBox = await hostBadge.boundingBox()
expect(hostBadgeBox).not.toBeNull()
expect((hostBadgeBox?.x ?? 0) + (hostBadgeBox?.width ?? 0)).toBeLessThanOrEqual(
(pathChipBox?.x ?? 0) + (pathChipBox?.width ?? 0) + 0.5
)
} else {
// A chip too narrow for the identity row hides it whole; a wide one must show it. 26rem of
// border-box width clears the 24rem content-box container threshold plus padding.
expect(pathChipBox?.width ?? 0).toBeLessThan(416)
}
await expect(page.locator(`[data-tab-group-body-id="${sourceGroupId}"]`)).toBeVisible()
await expect(page.locator(`[data-tab-group-body-id="${previewRow.groupId}"]`)).toBeVisible()