feat: project settings page with paseo.json editor

Adds a Projects settings flow for inspecting and editing per-project
paseo.json (worktree setup/teardown, scripts, terminals) directly from the
app. Reads/writes go through new daemon RPCs with revision-based optimistic
concurrency, and the screen always keeps its header and host picker visible
so a hung host doesn't trap the user.
This commit is contained in:
Mohamed Boudra
2026-04-26 11:37:47 +07:00
parent 18903bcecb
commit 219050a7ab
36 changed files with 6447 additions and 81 deletions
@@ -4,6 +4,8 @@ import {
buildHostRootRoute,
buildHostWorkspaceOpenRoute,
buildHostWorkspaceRoute,
buildProjectSettingsRoute,
buildProjectsSettingsRoute,
decodeFilePathFromPathSegment,
decodeWorkspaceIdFromPathSegment,
encodeFilePathForPathSegment,
@@ -133,3 +135,28 @@ describe("workspace route parsing", () => {
expect(decodeWorkspaceIdFromPathSegment(encoded)).toBe("team/setup:id#1");
});
});
describe("projects settings routes", () => {
it("buildProjectsSettingsRoute returns /settings/projects", () => {
expect(buildProjectsSettingsRoute()).toBe("/settings/projects");
});
it("buildProjectSettingsRoute encodes a remote project key as a single segment", () => {
expect(buildProjectSettingsRoute("remote:github.com/acme/app")).toBe(
"/settings/projects/remote%3Agithub.com%2Facme%2Fapp",
);
});
it("buildProjectSettingsRoute encodes a local repo-root key", () => {
expect(buildProjectSettingsRoute("/Users/me/dev/paseo")).toBe(
"/settings/projects/%2FUsers%2Fme%2Fdev%2Fpaseo",
);
});
it("project keys round-trip through decodeURIComponent", () => {
const projectKey = "remote:github.com/acme/app";
const route = buildProjectSettingsRoute(projectKey);
const segment = route.slice("/settings/projects/".length);
expect(decodeURIComponent(segment)).toBe(projectKey);
});
});