feat(lanes): move the lane's git section into the Changes panel
- The branch line, the uncommitted-files hover panel and the git action row (fetch/pull/push/branch) move from the lane card to the top of the Changes panel (new LaneGitHeader.tsx); the card has no git row now. - Header and panel share one git-facts read: stage/unstage/discard/commit and Refresh re-read it, and a git bar action re-reads the diff, the history and the file tree. - The git bar no longer commits: the panel's staged-only box is the one commit path. Orphaned gitBar.commit*/cancel strings removed (en, vi). - "New lane here" is wired from Workspace to the panel.
This commit is contained in:
@@ -20,6 +20,8 @@ import type { LaneChanges } from "../../../lib/types";
|
||||
vi.mock("../../../lib/api", () => ({
|
||||
api: {
|
||||
lanes: {
|
||||
git: vi.fn(),
|
||||
gitBranches: vi.fn(),
|
||||
changes: vi.fn(),
|
||||
gitAction: vi.fn(),
|
||||
gitLog: vi.fn(),
|
||||
@@ -77,6 +79,7 @@ function changes(over: Partial<Extract<LaneChanges, { available: true }>> = {}):
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
vi.mocked(api.lanes.git).mockReset().mockResolvedValue({ available: false });
|
||||
vi.mocked(api.lanes.changes).mockReset();
|
||||
vi.mocked(api.lanes.changes).mockResolvedValue(changes());
|
||||
vi.mocked(api.lanes.gitAction).mockReset();
|
||||
@@ -213,6 +216,73 @@ describe("LaneChangesPanel", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("heads the panel with the lane's git line, and a stage re-reads it", async () => {
|
||||
vi.mocked(api.lanes.git).mockResolvedValue({
|
||||
available: true,
|
||||
branch: "feat/thing",
|
||||
head: "9b3e74a",
|
||||
subject: "wip",
|
||||
dirty: 2,
|
||||
untracked: 1,
|
||||
files: [],
|
||||
hasRemote: false,
|
||||
upstream: null,
|
||||
ahead: null,
|
||||
behind: null,
|
||||
});
|
||||
const user = userEvent.setup();
|
||||
render(<LaneChangesPanel laneId={7} />);
|
||||
expect(await screen.findByTestId("lane-git")).toHaveTextContent("feat/thing");
|
||||
expect(screen.getByTestId("lane-git-bar")).toBeInTheDocument();
|
||||
expect(api.lanes.git).toHaveBeenCalledTimes(1);
|
||||
|
||||
const [stage] = screen.getAllByRole("button", { name: "Stage this file" });
|
||||
await user.click(stage!);
|
||||
// The header's counts moved with the index: waiting out its 30s poll
|
||||
// would leave them wrong beside the list that just changed.
|
||||
await waitFor(() => expect(api.lanes.git).toHaveBeenCalledTimes(2));
|
||||
});
|
||||
|
||||
it("re-reads the diff after a git bar action", async () => {
|
||||
vi.mocked(api.lanes.git).mockResolvedValue({
|
||||
available: true,
|
||||
branch: "feat/thing",
|
||||
head: "9b3e74a",
|
||||
subject: "wip",
|
||||
dirty: 0,
|
||||
untracked: 0,
|
||||
files: [],
|
||||
hasRemote: true,
|
||||
upstream: "origin/feat/thing",
|
||||
ahead: 0,
|
||||
behind: 1,
|
||||
});
|
||||
const user = userEvent.setup();
|
||||
render(<LaneChangesPanel laneId={7} />);
|
||||
await screen.findByTestId("lane-git-bar");
|
||||
const before = vi.mocked(api.lanes.changes).mock.calls.length;
|
||||
|
||||
await user.click(screen.getByRole("button", { name: /Pull/ }));
|
||||
expect(api.lanes.gitAction).toHaveBeenCalledWith(7, "pull", {});
|
||||
// A pull rewrites the working tree the list below describes.
|
||||
await waitFor(() =>
|
||||
expect(vi.mocked(api.lanes.changes).mock.calls.length).toBeGreaterThan(before)
|
||||
);
|
||||
});
|
||||
|
||||
it("re-reads history too when Refresh is pressed there", async () => {
|
||||
const user = userEvent.setup();
|
||||
render(<LaneChangesPanel laneId={7} />);
|
||||
await screen.findByTestId("lane-changes-overview");
|
||||
await user.click(screen.getByRole("button", { name: "History" }));
|
||||
await screen.findByText("feat: the commit");
|
||||
vi.mocked(api.lanes.gitLog).mockClear();
|
||||
|
||||
await user.click(screen.getByRole("button", { name: "Refresh" }));
|
||||
// A pull or a switch from the git bar moves the commit list as well.
|
||||
await waitFor(() => expect(api.lanes.gitLog).toHaveBeenCalledTimes(1));
|
||||
});
|
||||
|
||||
it("needs two clicks to discard, and only the second one reaches the server", async () => {
|
||||
const user = userEvent.setup();
|
||||
render(<LaneChangesPanel laneId={7} />);
|
||||
|
||||
Reference in New Issue
Block a user