mirror of
https://github.com/getpaseo/paseo.git
synced 2026-11-06 08:24:46 +00:00
fix(plugins): New workspace commands work from mount effects, and branch and base ref match what creation uses
A command called from a New workspace item's mount effect rejected because the setup model only received its inputs and the pickers' handlers from a passive effect on the screen, which runs after a child's. The model now takes its inputs at construction, picks the base and isolation itself, and is refreshed in a layout effect; the screen supplies the side effects of a pick (the PR attachment, the remembered isolation) as listeners. The branch a plugin sets was dropped when no base was resolved, such as on a detached HEAD, because it was sent only for an explicit branch-off. It now applies whenever the worktree cuts a new branch, decided in one place that mirrors the daemon. baseRef.name was the display-shortened branch name, so setting back what was read based the worktree on the local branch instead of the origin one. It is now the exact ref creation uses, and host and baseRef are frozen like project and metadata.
This commit is contained in:
@@ -0,0 +1,61 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import {
|
||||
buildBranchPickerItems,
|
||||
pickerItemToCheckoutRequest,
|
||||
type PickerItem,
|
||||
} from "@/screens/new-workspace-picker-item";
|
||||
import { createNewWorkspaceSetup } from "@/screens/new-workspace/setup-model";
|
||||
import { toPluginNewWorkspace } from "./model";
|
||||
|
||||
const HOST = { id: "host", label: "Host" } as Parameters<typeof toPluginNewWorkspace>[0]["host"];
|
||||
|
||||
function viewOf(baseItem: PickerItem) {
|
||||
return {
|
||||
project: { id: "p", name: "repo" },
|
||||
isolation: "worktree" as const,
|
||||
baseItem,
|
||||
branch: null,
|
||||
metadata: {},
|
||||
locked: false,
|
||||
};
|
||||
}
|
||||
|
||||
describe("the base ref a plugin reads", () => {
|
||||
it("names the exact ref creation uses, so setting it back picks the same base", async () => {
|
||||
// `release` exists locally and on origin, and the two have diverged.
|
||||
const rows = buildBranchPickerItems([
|
||||
{
|
||||
name: "release",
|
||||
committerDate: 0,
|
||||
hasLocal: true,
|
||||
hasRemote: true,
|
||||
localAhead: 2,
|
||||
localBehind: 1,
|
||||
},
|
||||
]);
|
||||
const origin = rows.find((row) => row.kind === "branch" && row.refName.includes("remotes"));
|
||||
if (!origin) throw new Error("expected an origin row");
|
||||
|
||||
const setup = createNewWorkspaceSetup({
|
||||
locked: false,
|
||||
project: { id: "p", name: "repo" },
|
||||
canCreateWorktree: true,
|
||||
supportsMetadata: true,
|
||||
});
|
||||
const chosen: PickerItem[] = [];
|
||||
setup.onBaseChosen((item) => chosen.push(item));
|
||||
const read = toPluginNewWorkspace({
|
||||
host: HOST,
|
||||
view: viewOf(origin),
|
||||
commands: setup.commands,
|
||||
});
|
||||
|
||||
expect(read.baseRef).toEqual({ type: "branch", name: "refs/remotes/origin/release" });
|
||||
if (read.baseRef?.type !== "branch") throw new Error("expected a branch");
|
||||
await read.setBaseRef(read.baseRef);
|
||||
|
||||
expect(pickerItemToCheckoutRequest(chosen[0] ?? null)).toEqual(
|
||||
pickerItemToCheckoutRequest(origin),
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { JsonValue } from "@getpaseo/protocol/agent-types";
|
||||
import type { PluginHostProps, PluginNewWorkspace } from "@getpaseo/plugin/client";
|
||||
import { branchNameFromRef, type PickerItem } from "@/screens/new-workspace-picker-item";
|
||||
import type { PickerItem } from "@/screens/new-workspace-picker-item";
|
||||
import type { SetupCommands } from "@/screens/new-workspace/setup-model";
|
||||
import { cloneAndFreeze } from "../freeze";
|
||||
|
||||
@@ -15,10 +15,11 @@ export interface NewWorkspaceView {
|
||||
locked: boolean;
|
||||
}
|
||||
|
||||
/** `name` is the exact ref creation uses, so a plugin can set back what it read. */
|
||||
function toBaseRef(item: PickerItem | null): PluginNewWorkspace["baseRef"] {
|
||||
if (!item) return null;
|
||||
return item.kind === "branch"
|
||||
? { type: "branch", name: branchNameFromRef(item.refName) }
|
||||
? { type: "branch", name: item.refName }
|
||||
: { type: "change-request", number: item.item.number };
|
||||
}
|
||||
|
||||
@@ -29,10 +30,10 @@ export function toPluginNewWorkspace(input: {
|
||||
}): PluginNewWorkspace {
|
||||
const { host, view, commands } = input;
|
||||
return {
|
||||
host: { id: host.id, label: host.label },
|
||||
host: cloneAndFreeze({ id: host.id, label: host.label }),
|
||||
project: cloneAndFreeze(view.project),
|
||||
isolation: view.isolation,
|
||||
baseRef: toBaseRef(view.baseItem),
|
||||
baseRef: cloneAndFreeze(toBaseRef(view.baseItem)),
|
||||
branch: view.branch,
|
||||
metadata: cloneAndFreeze(view.metadata),
|
||||
...commands,
|
||||
|
||||
Reference in New Issue
Block a user