fix(projects): preserve legacy placement identity

This commit is contained in:
Mohamed Boudra
2026-07-29 11:28:32 +00:00
parent ad0939dfbb
commit 8c89592bb3
4 changed files with 24 additions and 8 deletions

View File

@@ -216,6 +216,14 @@ describe("projects settings routes", () => {
expect(decodeURIComponent(segment)).toBe(projectKey);
});
it("preserves whitespace in opaque project keys", () => {
const projectKey = "host:6:host-a:project:10:/repo/foo ";
const route = buildProjectSettingsRoute(projectKey);
const segment = route.slice("/settings/projects/".length);
expect(decodeURIComponent(segment)).toBe(projectKey);
});
it("keeps an already-decoded opaque project key unchanged", () => {
const projectKey = "remote:github.com/acme/app#subdir:packages/my%20app";
expect(normalizeProjectSettingsRouteKey(projectKey)).toBe(projectKey);

View File

@@ -567,11 +567,10 @@ export function buildProjectsSettingsRoute() {
}
export function buildProjectSettingsRoute(projectKey: string) {
const normalized = trimNonEmpty(projectKey);
if (!normalized) {
if (!projectKey.trim()) {
throw new Error("buildProjectSettingsRoute requires a non-empty projectKey");
}
return `/settings/projects/${encodeSegment(normalized)}` as const;
return `/settings/projects/${encodeSegment(projectKey)}` as const;
}
export function normalizeProjectSettingsRouteKey(value: string | string[] | undefined): string {

View File

@@ -3417,7 +3417,7 @@ describe("session workspace descriptors", () => {
const messages: unknown[] = [];
const workspace = {
workspaceId: "ws-gh",
projectId: "remote:github.com/acme/app",
projectId: "prj_app",
cwd: "/repo/app",
kind: "local_checkout" as const,
displayName: "app",
@@ -3425,7 +3425,8 @@ describe("session workspace descriptors", () => {
archivedAt: null,
};
const project = {
projectId: "remote:github.com/acme/app",
projectId: "prj_app",
projectKey: "remote:github.com/acme/app",
rootPath: "/repo/app",
kind: "git" as const,
displayName: "acme/app",
@@ -3436,7 +3437,10 @@ describe("session workspace descriptors", () => {
const session = createSessionForTest({
messages,
workspaceRegistry: { get: vi.fn(), list: vi.fn().mockResolvedValue([workspace]) },
projectRegistry: { list: vi.fn().mockResolvedValue([project]), get: vi.fn() },
projectRegistry: {
list: vi.fn().mockResolvedValue([project]),
get: vi.fn().mockResolvedValue(project),
},
workspaceGitService: {
getSnapshot: vi.fn(),
peekSnapshot: vi.fn(() =>
@@ -3465,8 +3469,10 @@ describe("session workspace descriptors", () => {
entries: [
expect.objectContaining({
id: "ws-gh",
projectId: "prj_app",
projectKey: "remote:github.com/acme/app",
project: expect.objectContaining({
projectKey: "remote:github.com/acme/app",
projectKey: "prj_app",
projectName: "acme/app",
workspaceName: "app",
checkout: expect.objectContaining({

View File

@@ -1691,7 +1691,7 @@ export class Session {
fallbackWorktreeRoot: snapshot?.git.repoRoot,
});
return {
projectKey: project.projectKey ?? project.projectId,
projectKey: project.projectId,
projectName: resolveProjectDisplayName(project),
workspaceName: resolveWorkspaceDisplayName(workspace),
checkout,
@@ -4206,6 +4206,9 @@ export class Session {
return {
id: workspace.workspaceId,
projectId: workspace.projectId,
...(resolvedProjectRecord?.projectKey
? { projectKey: resolvedProjectRecord.projectKey }
: {}),
projectDisplayName: resolvedProjectRecord
? resolveProjectDisplayName(resolvedProjectRecord)
: workspace.projectId,