When opening board, migrate from Shared Lists to Per-Swimlane Lists.

Thanks to xet7 !

Fixes #5952
This commit is contained in:
Lauri Ojansivu 2025-10-20 00:22:26 +03:00
parent 48b645ee1e
commit 1e6252de7f
8 changed files with 112 additions and 219 deletions

View file

@ -112,6 +112,9 @@ BlazeComponent.extendComponent({
}
}
// Convert shared lists to per-swimlane lists if needed
await this.convertSharedListsToPerSwimlane(boardId);
// Start attachment migration in background if needed
this.startAttachmentMigrationIfNeeded(boardId);
} catch (error) {
@ -139,6 +142,100 @@ BlazeComponent.extendComponent({
}
},
async convertSharedListsToPerSwimlane(boardId) {
try {
const board = ReactiveCache.getBoard(boardId);
if (!board) return;
// Check if board has already been processed for shared lists conversion
if (board.hasSharedListsConverted) {
if (process.env.DEBUG === 'true') {
console.log(`Board ${boardId} has already been processed for shared lists conversion`);
}
return;
}
// Get all lists for this board
const allLists = board.lists();
const swimlanes = board.swimlanes();
if (swimlanes.length === 0) {
if (process.env.DEBUG === 'true') {
console.log(`Board ${boardId} has no swimlanes, skipping shared lists conversion`);
}
return;
}
// Find shared lists (lists with empty swimlaneId or null swimlaneId)
const sharedLists = allLists.filter(list => !list.swimlaneId || list.swimlaneId === '');
if (sharedLists.length === 0) {
if (process.env.DEBUG === 'true') {
console.log(`Board ${boardId} has no shared lists to convert`);
}
// Mark as processed even if no shared lists
Meteor.call('boards.update', boardId, { $set: { hasSharedListsConverted: true } });
return;
}
if (process.env.DEBUG === 'true') {
console.log(`Converting ${sharedLists.length} shared lists to per-swimlane lists for board ${boardId}`);
}
// Convert each shared list to per-swimlane lists
for (const sharedList of sharedLists) {
// Create a copy of the list for each swimlane
for (const swimlane of swimlanes) {
// Check if this list already exists in this swimlane
const existingList = Lists.findOne({
boardId: boardId,
swimlaneId: swimlane._id,
title: sharedList.title
});
if (!existingList) {
// Create a new list in this swimlane
const newListData = {
title: sharedList.title,
boardId: boardId,
swimlaneId: swimlane._id,
sort: sharedList.sort || 0,
archived: sharedList.archived || false,
createdAt: new Date(),
modifiedAt: new Date()
};
// Copy other properties if they exist
if (sharedList.color) newListData.color = sharedList.color;
if (sharedList.wipLimit) newListData.wipLimit = sharedList.wipLimit;
if (sharedList.wipLimitEnabled) newListData.wipLimitEnabled = sharedList.wipLimitEnabled;
if (sharedList.wipLimitSoft) newListData.wipLimitSoft = sharedList.wipLimitSoft;
Lists.insert(newListData);
}
}
// Archive or remove the original shared list
Lists.update(sharedList._id, {
$set: {
archived: true,
modifiedAt: new Date()
}
});
}
// Mark board as processed
Meteor.call('boards.update', boardId, { $set: { hasSharedListsConverted: true } });
if (process.env.DEBUG === 'true') {
console.log(`Successfully converted ${sharedLists.length} shared lists to per-swimlane lists for board ${boardId}`);
}
} catch (error) {
console.error('Error converting shared lists to per-swimlane:', error);
}
},
async startAttachmentMigrationIfNeeded(boardId) {
try {
// Check if board has already been migrated

View file

@ -130,11 +130,6 @@ template(name="boardHeaderBar")
a.board-header-btn-close.js-multiselection-reset(title="{{_ 'filter-clear'}}")
| ❌
if currentUser.isBoardAdmin
a.board-header-btn.js-restore-legacy-lists(title="{{_ 'restore-legacy-lists'}}")
| 🔄
| {{_ 'legacy-lists'}}
.separator
a.board-header-btn.js-toggle-sidebar(title="{{_ 'sidebar-open'}} {{_ 'or'}} {{_ 'sidebar-close'}}")
| ☰

View file

@ -152,32 +152,10 @@ BlazeComponent.extendComponent({
'click .js-log-in'() {
FlowRouter.go('atSignIn');
},
'click .js-restore-legacy-lists'() {
this.restoreLegacyLists();
},
},
];
},
restoreLegacyLists() {
// Show confirmation dialog
if (confirm('Are you sure you want to restore legacy lists to their original shared state? This will make them appear in all swimlanes.')) {
// Call cron method to restore legacy lists
Meteor.call('cron.triggerRestoreLegacyLists', (error, result) => {
if (error) {
console.error('Error restoring legacy lists:', error);
alert(`Error: ${error.message}`);
} else {
console.log('Successfully triggered restore legacy lists migration:', result);
alert(`Migration triggered successfully. Job ID: ${result.jobId}`);
// Refresh the board to show the restored lists
setTimeout(() => {
window.location.reload();
}, 2000);
}
});
}
},
}).register('boardHeaderBar');
Template.boardHeaderBar.helpers({