fix(gui-plugins): correct WSL radio alignment (#53676)

Co-authored-by: Luke Parker <10430890+Hona@users.noreply.github.com>
This commit is contained in:
犬夢
2026-11-07 00:10:39 +08:00
committed by GitHub
Unverified
parent fe659c246f
commit 4873a93ea4
4 changed files with 115 additions and 8 deletions
@@ -1,11 +1,91 @@
import { base64Encode } from "@opencode/util/encode"
import { expect, test } from "@playwright/test"
import { expect, test, type Locator } from "@playwright/test"
import { NO_PROVIDER, REMOTE_SERVER, SERVER, holdRoute, project, provider, session } from "../utils/app"
import { mockOpenCodeServer, mockServers } from "../utils/mock-server"
import { expectSessionTitle } from "../utils/waits"
test.use({ viewport: { width: 1280, height: 900 } })
test("WSL distribution radios stay inset and aligned in both add-server lists", async ({ page }) => {
await mockOpenCodeServer(page, {
directory: "/repo",
project: project({ id: "proj_wsl_alignment", directory: "/repo", name: "WSL project" }),
provider: NO_PROVIDER,
sessions: [],
pageMessages: () => ({ items: [] }),
})
await page.goto(
`/e2e/utils/settings-wsl.html?${new URLSearchParams({
server: SERVER,
mode: "ready",
distros: "Ubuntu-24.04,AlmaLinux-9,Debian-WSL1",
})}`,
)
const settings = page.getByTestId("settings-screen")
await settings.getByRole("tab", { name: "Servers", exact: true }).click()
await expect(settings.getByRole("region", { name: "Ubuntu", exact: true })).toHaveCount(1)
await settings.getByRole("button", { name: "Add server", exact: true }).press("Enter")
await page.getByRole("menuitem", { name: "Add WSL server", exact: true }).click()
const dialog = page.getByRole("dialog")
const ubuntu = dialog.getByRole("radio", { name: "Ubuntu-24.04 OpenCode not installed", exact: true })
const alma = dialog.getByRole("radio", { name: "AlmaLinux-9 OpenCode not installed", exact: true })
await expect(ubuntu).toBeEnabled()
await expect(dialog.getByText("OpenCode not installed", { exact: true })).toHaveCount(2)
await expect(dialog.getByRole("radio", { name: "Debian-WSL1 Unsupported · Use WSL 2", exact: true })).toBeDisabled()
await expectDistroLayout(dialog)
await dialog
.locator('[data-slot="radio-v2-item-label"]')
.filter({ has: page.getByText("AlmaLinux-9", { exact: true }) })
.click()
await expect(alma).toBeChecked()
await alma.press("ArrowUp")
await expect(ubuntu).toBeChecked()
await expect(ubuntu).toBeFocused()
await expectDistroLayout(dialog)
await dialog.getByRole("button", { name: /Need another distro/ }).click()
await expect(dialog.getByRole("heading", { name: "Install distro", exact: true })).toBeVisible()
await expect(dialog.getByRole("radio", { name: "Debian", exact: true })).toBeChecked()
await expectDistroLayout(dialog)
await dialog
.locator('[data-slot="radio-v2-item-label"]')
.filter({ has: page.getByText("FedoraLinux-43", { exact: true }) })
.click()
await expect(dialog.getByRole("radio", { name: "FedoraLinux-43", exact: true })).toBeChecked()
await expectDistroLayout(dialog)
})
async function expectDistroLayout(dialog: Locator) {
// Keep the visible control inside its row and aligned with its label, including disabled rows,
// and keep rows flush so every divider sits the same distance from the content below it.
await expect
.poll(() =>
dialog.locator(".settings-wsl-distro-row").evaluateAll((rows) =>
rows.every((row, index) => {
const previous = rows[index - 1]?.getBoundingClientRect()
if (previous && Math.abs(row.getBoundingClientRect().top - previous.bottom) > 1) return false
const control = row.querySelector('[data-slot="radio-v2-item-control"]')
const label = row.querySelector('[data-slot="radio-v2-item-label-text"]')
if (!control || !label) return false
const bounds = row.getBoundingClientRect()
const circle = control.getBoundingClientRect()
const text = label.getBoundingClientRect()
return (
circle.left - bounds.left >= 8 &&
circle.top - bounds.top >= 8 &&
circle.bottom < bounds.bottom &&
circle.right < text.left &&
Math.abs(circle.top + circle.height / 2 - (text.top + text.height / 2)) <= 4
)
}),
),
)
.toBe(true)
}
for (const mode of ["failed", "stopped", "ready"] as const) {
test(`manages a ${mode} configured WSL server from the Servers page`, async ({ page }) => {
await mockOpenCodeServer(page, {
@@ -29,6 +29,10 @@ export function mount(input: {
ssh?: string | null
storage?: string | null
hold?: string | null
/** Comma-separated installed distributions for the add-server dialog. */
distros?: string | null
/** Holds the distribution refresh job while inspecting disabled dialog controls. */
busy?: string | null
/** Enables the updater Ipc; check and install reject with this message, which may be empty. */
updater?: string | null
}) {
@@ -40,6 +44,7 @@ export function mount(input: {
const endpoint = { url: input.wsl ?? input.server }
const ready = () => ({ kind: "ready" as const, url: endpoint.url, password: null })
const held = Promise.withResolvers<void>()
const distros = input.distros?.split(",").filter(Boolean) ?? []
const storage = (name?: string) => {
const item = (key: string) => (name ? `${name}:${key}` : key)
@@ -82,11 +87,18 @@ export function mount(input: {
},
state: {
runtime: { available: true, version: "2", error: null },
installed: [],
online: [],
distroProbes: {},
installed: distros.map((name) => ({ name, version: name === "Debian-WSL1" ? 1 : 2, isDefault: false })),
online: distros.length
? ["Debian", "FedoraLinux-43", "openSUSE-Tumbleweed", "OracleLinux_9_1", "kali-linux"].map((name) => ({
name,
label: name,
}))
: [],
distroProbes: Object.fromEntries(
distros.map((name) => [name, { name, canExecute: true, hasBash: true, hasCurl: true, error: null }]),
),
pendingRestart: false,
hostJob: "idle",
hostJob: input.busy ? "busy" : "idle",
distroJobs: {},
servers: [
{
@@ -101,6 +113,19 @@ export function mount(input: {
},
],
opencodeChecks: {
...Object.fromEntries(
distros.map((name) => [
name,
{
distro: name,
resolvedPath: null,
version: null,
expectedVersion: "current",
matchesDesktop: null,
error: null,
},
]),
),
Ubuntu: {
distro: "Ubuntu",
resolvedPath: "/usr/bin/opencode",
+2
View File
@@ -18,6 +18,8 @@
ssh: query.get("ssh"),
storage: query.get("storage"),
hold: query.get("hold"),
distros: query.get("distros"),
busy: query.get("busy"),
updater: query.get("updater"),
})
</script>
+3 -3
View File
@@ -187,12 +187,12 @@
width: 100%;
}
.settings-wsl-distro-group [data-slot="radio-v2-items"] {
.settings-wsl-distro-group[data-component="radio-v2"] [data-slot="radio-v2-items"] {
width: 100%;
gap: 0;
}
.settings-wsl-distro-row {
.settings-wsl-distro-row[data-slot="radio-v2-item"] {
box-sizing: border-box;
width: 100%;
min-height: 62px;
@@ -375,7 +375,7 @@
width: 100%;
}
.settings-wsl-catalog-row {
.settings-wsl-catalog-row[data-slot="radio-v2-item"] {
min-height: 48px;
}