Keep New workspace metadata inside the composer (#3050)
Allow desktop metadata controls to shrink so long host and starting-ref labels truncate without crossing the composer rail. Adds a real-browser regression for the combined long-label case.
This commit is contained in:
@@ -0,0 +1,87 @@
|
|||||||
|
import { expect, test } from "../support/fixtures";
|
||||||
|
import { gotoAppShell } from "../support/helpers/app";
|
||||||
|
import { getE2EDaemonPort } from "../support/helpers/daemon-port";
|
||||||
|
import {
|
||||||
|
openNewWorkspaceComposer,
|
||||||
|
openStartingRefPicker,
|
||||||
|
selectBranchInPicker,
|
||||||
|
selectWorkspaceIsolation,
|
||||||
|
} from "../support/helpers/new-workspace";
|
||||||
|
import { seedWorkspace, type SeededWorkspace } from "../support/helpers/seed-client";
|
||||||
|
import { getServerId } from "../support/helpers/server-id";
|
||||||
|
import { seedSavedSettingsHosts } from "../support/helpers/settings";
|
||||||
|
import { waitForSidebarHydration } from "../support/helpers/workspace-ui";
|
||||||
|
|
||||||
|
const LONG_HOST_NAME =
|
||||||
|
"development-macbook-pro.local-connected-through-a-very-long-private-hostname";
|
||||||
|
const LONG_BRANCH_NAME =
|
||||||
|
"feat/app/add-amoled-theme-with-a-very-long-pull-request-and-branch-description";
|
||||||
|
|
||||||
|
function measureControlRightEdges(controls: HTMLElement[]) {
|
||||||
|
const measurements: Array<{ label: string | null; right: number }> = [];
|
||||||
|
for (const control of controls) {
|
||||||
|
const rect = control.getBoundingClientRect();
|
||||||
|
measurements.push({ label: control.getAttribute("aria-label"), right: rect.right });
|
||||||
|
}
|
||||||
|
return measurements;
|
||||||
|
}
|
||||||
|
|
||||||
|
test.describe("New workspace metadata row layout", () => {
|
||||||
|
let workspace: SeededWorkspace;
|
||||||
|
|
||||||
|
test.beforeEach(async () => {
|
||||||
|
workspace = await seedWorkspace({
|
||||||
|
repoPrefix: "new-workspace-layout-",
|
||||||
|
repo: { branches: [LONG_BRANCH_NAME] },
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test.afterEach(async () => {
|
||||||
|
await workspace?.cleanup();
|
||||||
|
});
|
||||||
|
|
||||||
|
test("long host and branch names stay inside the composer's right rail", async ({ page }) => {
|
||||||
|
await page.setViewportSize({ width: 2048, height: 878 });
|
||||||
|
await seedSavedSettingsHosts(page, [
|
||||||
|
{
|
||||||
|
serverId: getServerId(),
|
||||||
|
label: LONG_HOST_NAME,
|
||||||
|
endpoint: `127.0.0.1:${getE2EDaemonPort()}`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
serverId: "srv_e2e_layout_offline",
|
||||||
|
label: "Offline host",
|
||||||
|
endpoint: "127.0.0.1:9",
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
await gotoAppShell(page);
|
||||||
|
await waitForSidebarHydration(page);
|
||||||
|
await openNewWorkspaceComposer(page, {
|
||||||
|
projectKey: workspace.projectKey,
|
||||||
|
projectDisplayName: workspace.projectDisplayName,
|
||||||
|
});
|
||||||
|
await selectWorkspaceIsolation(page, "worktree");
|
||||||
|
await openStartingRefPicker(page);
|
||||||
|
await selectBranchInPicker(page, LONG_BRANCH_NAME);
|
||||||
|
|
||||||
|
const composer = page.locator('[data-testid="message-input-root"]:visible');
|
||||||
|
const metadataRow = page.getByTestId("new-workspace-ref-picker-row");
|
||||||
|
await expect(composer).toBeVisible();
|
||||||
|
await expect(metadataRow).toBeVisible();
|
||||||
|
|
||||||
|
const [composerBox, controlBoxes] = await Promise.all([
|
||||||
|
composer.boundingBox(),
|
||||||
|
metadataRow.getByRole("button").evaluateAll(measureControlRightEdges),
|
||||||
|
]);
|
||||||
|
expect(composerBox).not.toBeNull();
|
||||||
|
const composerRightRail = composerBox!.x + composerBox!.width;
|
||||||
|
|
||||||
|
for (const control of controlBoxes) {
|
||||||
|
expect(
|
||||||
|
control.right,
|
||||||
|
`${control.label ?? "Metadata control"} crossed the composer rail`,
|
||||||
|
).toBeLessThanOrEqual(composerRightRail + 1);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -1350,8 +1350,10 @@ function useNewWorkspaceFormStack(input: NewWorkspaceFormStackInput): ReactEleme
|
|||||||
[isPending],
|
[isPending],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const desktopControlStyle = isCompact ? undefined : styles.desktopControl;
|
||||||
|
|
||||||
const projectControl = (
|
const projectControl = (
|
||||||
<View>
|
<View style={desktopControlStyle}>
|
||||||
<ProjectPickerTrigger
|
<ProjectPickerTrigger
|
||||||
pickerAnchorRef={project.anchorRef}
|
pickerAnchorRef={project.anchorRef}
|
||||||
onPress={project.open}
|
onPress={project.open}
|
||||||
@@ -1388,7 +1390,7 @@ function useNewWorkspaceFormStack(input: NewWorkspaceFormStackInput): ReactEleme
|
|||||||
);
|
);
|
||||||
|
|
||||||
const hostControl = showHostControl ? (
|
const hostControl = showHostControl ? (
|
||||||
<View>
|
<View style={desktopControlStyle}>
|
||||||
<HostPicker
|
<HostPicker
|
||||||
hosts={host.allHosts}
|
hosts={host.allHosts}
|
||||||
value={host.selectedServerId}
|
value={host.selectedServerId}
|
||||||
@@ -1431,7 +1433,7 @@ function useNewWorkspaceFormStack(input: NewWorkspaceFormStackInput): ReactEleme
|
|||||||
) : null;
|
) : null;
|
||||||
|
|
||||||
const isolationControl = isolation.canCreateWorktree ? (
|
const isolationControl = isolation.canCreateWorktree ? (
|
||||||
<View>
|
<View style={desktopControlStyle}>
|
||||||
<IsolationPickerTrigger
|
<IsolationPickerTrigger
|
||||||
pickerAnchorRef={isolation.anchorRef}
|
pickerAnchorRef={isolation.anchorRef}
|
||||||
onPress={isolation.open}
|
onPress={isolation.open}
|
||||||
@@ -1458,7 +1460,7 @@ function useNewWorkspaceFormStack(input: NewWorkspaceFormStackInput): ReactEleme
|
|||||||
) : null;
|
) : null;
|
||||||
|
|
||||||
const baseControl = base.showRefPicker ? (
|
const baseControl = base.showRefPicker ? (
|
||||||
<View>
|
<View style={desktopControlStyle}>
|
||||||
<RefPickerTrigger
|
<RefPickerTrigger
|
||||||
pickerAnchorRef={base.anchorRef}
|
pickerAnchorRef={base.anchorRef}
|
||||||
onPress={base.open}
|
onPress={base.open}
|
||||||
@@ -2392,6 +2394,10 @@ const styles = StyleSheet.create((theme) => ({
|
|||||||
paddingRight: theme.spacing[4],
|
paddingRight: theme.spacing[4],
|
||||||
gap: theme.spacing[2],
|
gap: theme.spacing[2],
|
||||||
},
|
},
|
||||||
|
desktopControl: {
|
||||||
|
minWidth: 0,
|
||||||
|
flexShrink: 1,
|
||||||
|
},
|
||||||
// The row's left inset matches the heading's text x (composerTitleContainer
|
// The row's left inset matches the heading's text x (composerTitleContainer
|
||||||
// paddingLeft) so the control aligns with the "New workspace" glyph. The badge
|
// paddingLeft) so the control aligns with the "New workspace" glyph. The badge
|
||||||
// adds its own left padding, so the row inset is reduced by that amount.
|
// adds its own left padding, so the row inset is reduced by that amount.
|
||||||
|
|||||||
Reference in New Issue
Block a user