fix: scope all git, activity, webhook, and summarize-title routes to correct project store

- Fix 30 git routes to use getScopedStore(req) instead of global store
- Fix activity GET/DELETE routes to use scoped store
- Fix POST /api/github/webhooks to use scoped store for badge updates
- Fix POST /api/ai/summarize-title to use scoped store for settings
- Fix GET /api/git/worktrees to use scoped store for task listing
- Add projectId parameter to all git and activity frontend API functions
- Update useActivityLog hook to pass projectId through

Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
This commit is contained in:
gsxdsm
2026-04-12 17:55:07 -07:00
parent 860d3c29fe
commit 9d2f61501b
9 changed files with 500 additions and 129 deletions

View File

@@ -144,4 +144,48 @@ describe("NodeCard", () => {
fireEvent.click(screen.getByLabelText("Confirm remove node"));
expect(onRemove).toHaveBeenCalledWith(node.id);
});
it("local node counts include unassigned projects", () => {
const localNode = makeNode({ id: "local-1", type: "local" });
const projects = [
makeProject({ id: "proj-1", nodeId: "local-1" }), // explicitly assigned
makeProject({ id: "proj-2", nodeId: undefined }), // unassigned - runs on local
makeProject({ id: "proj-3", nodeId: "remote-1" }), // assigned to remote - not counted
];
render(
<NodeCard
node={localNode}
projects={projects}
onHealthCheck={vi.fn()}
onEdit={vi.fn()}
onRemove={vi.fn()}
/>
);
// Local node should show 2 projects (explicitly assigned + unassigned)
expect(screen.getByText("2")).toBeDefined();
});
it("remote node counts exclude unassigned projects", () => {
const remoteNode = makeNode({ id: "remote-1", type: "remote" });
const projects = [
makeProject({ id: "proj-1", nodeId: "remote-1" }), // explicitly assigned
makeProject({ id: "proj-2", nodeId: undefined }), // unassigned - NOT counted for remote
makeProject({ id: "proj-3", nodeId: "local-1" }), // assigned to local - not counted
];
render(
<NodeCard
node={remoteNode}
projects={projects}
onHealthCheck={vi.fn()}
onEdit={vi.fn()}
onRemove={vi.fn()}
/>
);
// Remote node should show only 1 project (explicitly assigned only)
expect(screen.getByText("1")).toBeDefined();
});
});

View File

@@ -148,4 +148,33 @@ describe("NodesView", () => {
fireEvent.click(nodeCard!);
expect(screen.getByRole("dialog", { name: "Node details for Detail Node" })).toBeDefined();
});
it("local node project count includes unassigned projects in detail modal", () => {
mockUseProjects.mockReturnValue({
projects: [
makeProject({ id: "proj-1", nodeId: "node-1" }), // explicitly assigned
makeProject({ id: "proj-2", nodeId: undefined }), // unassigned - runs on local
],
loading: false,
error: null,
refresh: vi.fn().mockResolvedValue(undefined),
register: vi.fn(),
update: vi.fn(),
unregister: vi.fn(),
});
mockUseNodes.mockReturnValue(makeUseNodesResult({
nodes: [makeNode({ id: "node-1", name: "Local Node", type: "local" })],
}));
render(<NodesView addToast={vi.fn()} />);
// Click on the node card to open detail modal
const nodeCard = document.querySelector(".node-card");
expect(nodeCard).toBeInTheDocument();
fireEvent.click(nodeCard!);
// Modal should show "Projects (2)" - including the unassigned project
expect(screen.getByText("Projects (2)")).toBeDefined();
});
});