feat(KB-069): add Archive All Done feature
- Add archiveAllDone method to TaskStore with filtering and batch archive - Add POST /tasks/archive-all-done API endpoint with tests - Add useTasks hook support and API function for archiveAllDone - Add Archive All button to done column header in Board UI - Wire up onArchiveAllDone through Board component hierarchy
This commit is contained in:
@@ -705,6 +705,63 @@ describe("POST /tasks/:id/unarchive", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("POST /tasks/archive-all-done", () => {
|
||||
let store: TaskStore;
|
||||
|
||||
beforeEach(() => {
|
||||
store = createMockStore({
|
||||
archiveAllDone: vi.fn(),
|
||||
});
|
||||
});
|
||||
|
||||
function buildApp() {
|
||||
const app = express();
|
||||
app.use(express.json());
|
||||
app.use("/api", createApiRoutes(store));
|
||||
return app;
|
||||
}
|
||||
|
||||
it("archives all done tasks and returns the archived array", async () => {
|
||||
const archivedTasks = [
|
||||
{ ...FAKE_TASK_DETAIL, id: "KB-001", column: "archived" },
|
||||
{ ...FAKE_TASK_DETAIL, id: "KB-002", column: "archived" },
|
||||
];
|
||||
(store.archiveAllDone as ReturnType<typeof vi.fn>).mockResolvedValue(archivedTasks);
|
||||
|
||||
const res = await REQUEST(buildApp(), "POST", "/api/tasks/archive-all-done", JSON.stringify({}), {
|
||||
"Content-Type": "application/json",
|
||||
});
|
||||
|
||||
expect(res.status).toBe(200);
|
||||
expect(res.body.archived).toHaveLength(2);
|
||||
expect(res.body.archived[0].column).toBe("archived");
|
||||
expect(res.body.archived[1].column).toBe("archived");
|
||||
expect(store.archiveAllDone).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("returns empty array when no done tasks exist", async () => {
|
||||
(store.archiveAllDone as ReturnType<typeof vi.fn>).mockResolvedValue([]);
|
||||
|
||||
const res = await REQUEST(buildApp(), "POST", "/api/tasks/archive-all-done", JSON.stringify({}), {
|
||||
"Content-Type": "application/json",
|
||||
});
|
||||
|
||||
expect(res.status).toBe(200);
|
||||
expect(res.body.archived).toEqual([]);
|
||||
});
|
||||
|
||||
it("returns 500 on unexpected errors", async () => {
|
||||
(store.archiveAllDone as ReturnType<typeof vi.fn>).mockRejectedValue(new Error("Database error"));
|
||||
|
||||
const res = await REQUEST(buildApp(), "POST", "/api/tasks/archive-all-done", JSON.stringify({}), {
|
||||
"Content-Type": "application/json",
|
||||
});
|
||||
|
||||
expect(res.status).toBe(500);
|
||||
expect(res.body.error).toContain("Database error");
|
||||
});
|
||||
});
|
||||
|
||||
describe("PATCH /tasks/:id", () => {
|
||||
let store: TaskStore;
|
||||
|
||||
|
||||
@@ -790,6 +790,16 @@ export function createApiRoutes(store: TaskStore, options?: ServerOptions): Rout
|
||||
}
|
||||
});
|
||||
|
||||
// Archive all done tasks
|
||||
router.post("/tasks/archive-all-done", async (req, res) => {
|
||||
try {
|
||||
const archived = await store.archiveAllDone();
|
||||
res.json({ archived });
|
||||
} catch (err: any) {
|
||||
res.status(500).json({ error: err.message });
|
||||
}
|
||||
});
|
||||
|
||||
// Upload attachment
|
||||
router.post("/tasks/:id/attachments", upload.single("file"), async (req, res) => {
|
||||
try {
|
||||
|
||||
Reference in New Issue
Block a user