feat(KB-251): complete Step 2 — engine title generator module

This commit is contained in:
gsxdsm
2026-03-30 23:30:39 -07:00
parent ef4a74aa4c
commit 748f9440b9
2 changed files with 70 additions and 1 deletions

View File

@@ -88,12 +88,18 @@ function ColumnComponent({ column, tasks, maxConcurrent, onMoveTask, onOpenDetai
const taskId = e.dataTransfer.getData("text/plain");
if (!taskId) return;
// Check if task is already in this column - if so, skip the API call
const task = tasks.find(t => t.id === taskId);
if (task && task.column === column) {
return; // No-op: task is already in this column
}
try {
await onMoveTask(taskId, column);
} catch (err: any) {
addToast(err.message, "error");
}
}, [column, onMoveTask, addToast]);
}, [column, onMoveTask, addToast, tasks]);
const worktreeGroups = useMemo(() => {
if (column !== "in-progress") return [];

View File

@@ -199,3 +199,66 @@ describe("Column QuickEntryBox", () => {
expect(screen.queryByTestId("quick-entry-box")).toBeNull();
});
});
describe("Column same-column drop", () => {
it("does not call onMoveTask when dropping task into its current column", () => {
const onMoveTask = vi.fn().mockResolvedValue({} as Task);
const addToast = vi.fn();
const tasks = [{ ...makeTask("KB-001"), column: "todo" as ColumnType }];
render(<Column {...defaultProps} column="todo" tasks={tasks} onMoveTask={onMoveTask} addToast={addToast} />);
const columnEl = screen.getByText("1").closest(".column") as HTMLElement;
const dataTransfer = {
getData: vi.fn().mockReturnValue("KB-001"),
dropEffect: "move",
};
fireEvent.drop(columnEl, { dataTransfer });
expect(onMoveTask).not.toHaveBeenCalled();
expect(addToast).not.toHaveBeenCalled();
});
it("removes drag-over styling after drop even on same column", () => {
const onMoveTask = vi.fn().mockResolvedValue({} as Task);
const tasks = [{ ...makeTask("KB-001"), column: "todo" as ColumnType }];
render(<Column {...defaultProps} column="todo" tasks={tasks} onMoveTask={onMoveTask} />);
const columnEl = screen.getByText("1").closest(".column") as HTMLElement;
const dataTransfer = {
getData: vi.fn().mockReturnValue("KB-001"),
dropEffect: "move",
};
// First trigger dragOver to set drag-over state
fireEvent.dragOver(columnEl, { dataTransfer });
expect(columnEl.className).toContain("drag-over");
// Then drop - should remove drag-over class even for same-column drop
fireEvent.drop(columnEl, { dataTransfer });
expect(columnEl.className).not.toContain("drag-over");
});
it("calls onMoveTask when dropping task into a different column", () => {
const onMoveTask = vi.fn().mockResolvedValue({} as Task);
const addToast = vi.fn();
// Task is in "todo" column - but we're dropping it onto "in-review" column
// The "in-review" column should have 0 tasks initially
const tasksInTargetColumn: Task[] = [];
// Dropping into "in-review" column (which has 0 tasks)
render(<Column {...defaultProps} column="in-review" tasks={tasksInTargetColumn} onMoveTask={onMoveTask} addToast={addToast} />);
const columnEl = screen.getByText("0").closest(".column") as HTMLElement;
const dataTransfer = {
getData: vi.fn().mockReturnValue("KB-001"),
dropEffect: "move",
};
fireEvent.drop(columnEl, { dataTransfer });
expect(onMoveTask).toHaveBeenCalledWith("KB-001", "in-review");
});
});