Keep selected projects when switching hosts (#2700)

* fix(app): preserve project selection across hosts

Rendered project identity and persisted equivalence were conflated after duplicate-project handling. Keep them separate so host changes resolve selectable equivalents deterministically without resetting legacy sidebar identity.

* fix(app): restore selected clone after host round trip

Keep manual origin and current destination placements separately so switching back restores the chosen checkout while archive gaps preserve the active host selection.

* fix(app): key status icons by project view

* fix(app): preserve origin during archive gaps
This commit is contained in:
Mohamed Boudra
2026-07-31 15:42:08 +02:00
committed by GitHub
parent 87ef631ac4
commit 99eca19a76
56 changed files with 1234 additions and 428 deletions
@@ -7,6 +7,7 @@ import {
} from "./helpers/schedule-fake-host";
import { seedWorkspace, type SeededWorkspace } from "./helpers/seed-client";
import { getServerId } from "./helpers/server-id";
import { projectEquivalenceViewKey } from "./helpers/project-view-key";
import { escapeRegex } from "./helpers/regex";
import { expectNoTruncation } from "./helpers/no-truncation";
import { expectSettled, expectStableHeight } from "./helpers/settled";
@@ -205,7 +206,9 @@ test.describe("Schedules project target", () => {
await expect(formSheet.getByText("Cron", { exact: true })).toHaveCount(0);
await page.getByRole("button", { name: /select project/i }).click();
await page.getByTestId(`schedule-project-option-${workspace.projectKey}`).click();
await page
.getByTestId(`schedule-project-option-${projectEquivalenceViewKey(workspace.projectKey)}`)
.click();
const projectTrigger = page.getByTestId("schedule-project-trigger");
await expect(projectTrigger).toContainText(workspace.projectDisplayName);
await expectSettled(projectTrigger);
@@ -315,7 +318,9 @@ test.describe("Schedules project target", () => {
await expectSettled(hostTrigger);
await projectTrigger.click();
await page.getByTestId(`schedule-project-option-${workspace.projectKey}`).click();
await page
.getByTestId(`schedule-project-option-${projectEquivalenceViewKey(workspace.projectKey)}`)
.click();
await expect(projectTrigger).toContainText(workspace.projectDisplayName);
await expectSettled(projectTrigger);
@@ -337,7 +342,9 @@ test.describe("Schedules project target", () => {
await expectSettled(projectTrigger);
await projectTrigger.click();
await page.getByTestId(`schedule-project-option-${fakeHost.projectKey}`).click();
await page
.getByTestId(`schedule-project-option-${projectEquivalenceViewKey(fakeHost.projectKey)}`)
.click();
await expect(projectTrigger).toContainText(fakeHost.projectDisplayName);
await expectSettled(projectTrigger);
await expect(modelTrigger).toContainText(/select model/i);
@@ -363,7 +370,9 @@ test.describe("Schedules project target", () => {
await page.getByTestId("schedules-empty-new").click();
await page.getByRole("button", { name: /select project/i }).click();
await page.getByTestId(`schedule-project-option-${workspace.projectKey}`).click();
await page
.getByTestId(`schedule-project-option-${projectEquivalenceViewKey(workspace.projectKey)}`)
.click();
await selectModelByLabel(page, "Ten second stream");
await expect(
page.getByText("Off keeps each run's workspace in the sidebar for inspection."),