Files
wekan/models/lib/subtaskCopy.js
T
Lauri Ojansivu 3847157753 Fix #3185: copying a card (or template) now copies its subtasks' checklists
When a card was copied — including generating a card from a template — each
subtask was inserted as a bare card document. The parent card's checklists were
copied, but the subtasks' checklists (and their items) were never copied, so
the new card's subtasks came out empty.

Card.copy() now copies each subtask's checklists (via Checklist.copy, which also
copies the checklist items) onto the newly inserted subtask. The subtask copy
document is built by a Meteor-free helper models/lib/subtaskCopy.js
(buildCopiedSubtaskFields — re-homes the subtask under the new parent and onto
the destination board; subtaskCopyChildKinds declares 'checklists' must be
reproduced), unit tested (positive + negative) in tests/subtaskCopy.test.cjs.

Thanks to ramses345 and xet7.
2026-07-09 09:45:53 +03:00

33 lines
1.4 KiB
JavaScript

'use strict';
// #3185 "Template with subtasks and checklists". When a card is copied (e.g.
// generating a card from a template), each subtask was inserted as a BARE card
// document — its checklists (and their items) were never copied, so the new
// card's subtasks came out empty. The parent card's own checklists were copied,
// but the per-subtask copy skipped them.
//
// buildCopiedSubtaskFields() builds the card document for a copied subtask
// (re-homed under the new parent and onto the destination board), and
// subtaskCopyChildKinds() declares the child records a subtask copy must also
// reproduce — 'checklists' being the one that was missing in #3185. Meteor-free
// so the re-homing and the copy contract are unit tested; the caller then runs
// Checklist.copy() for each kind.
function buildCopiedSubtaskFields(subtask, { newParentId, boardId, swimlaneId, listId } = {}) {
const fields = Object.assign({}, subtask);
delete fields._id;
fields.parentId = newParentId;
fields.boardId = boardId;
fields.swimlaneId = swimlaneId;
fields.listId = listId;
return fields;
}
// The child-record kinds a full subtask copy must reproduce. Guards #3185: a
// subtask copy that reproduces only the card (this list empty / missing
// 'checklists') is the regression.
function subtaskCopyChildKinds() {
return ['checklists'];
}
module.exports = { buildCopiedSubtaskFields, subtaskCopyChildKinds };