Fix duplicated lists.

Thanks to xet7 !

Fixes #5952
This commit is contained in:
Lauri Ojansivu 2025-10-21 15:14:01 +03:00
parent c7bbe47221
commit b6e7b258e0
5 changed files with 667 additions and 29 deletions

View file

@ -56,10 +56,15 @@ BlazeComponent.extendComponent({
const swimlanes = board.swimlanes();
if (swimlanes.length === 0) {
const swimlaneId = Swimlanes.insert({
title: 'Default',
boardId: boardId,
});
// Check if any swimlane exists in the database to avoid race conditions
const existingSwimlanes = ReactiveCache.getSwimlanes({ boardId });
if (existingSwimlanes.length === 0) {
const swimlaneId = Swimlanes.insert({
title: 'Default',
boardId: boardId,
});
console.log(`Created default swimlane ${swimlaneId} for board ${boardId}`);
}
this._swimlaneCreated.add(boardId);
} else {
this._swimlaneCreated.add(boardId);
@ -197,28 +202,41 @@ BlazeComponent.extendComponent({
});
if (!existingList) {
// Create a new list in this swimlane
const newListData = {
title: sharedList.title,
// Double-check to avoid race conditions
const doubleCheckList = ReactiveCache.getList({
boardId: boardId,
swimlaneId: swimlane._id,
sort: sharedList.sort || 0,
archived: sharedList.archived || false, // Preserve archived state from original list
createdAt: new Date(),
modifiedAt: new Date()
};
title: sharedList.title
});
// 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;
if (!doubleCheckList) {
// 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, // Preserve archived state from original list
createdAt: new Date(),
modifiedAt: new Date()
};
Lists.insert(newListData);
if (process.env.DEBUG === 'true') {
const archivedStatus = sharedList.archived ? ' (archived)' : ' (active)';
console.log(`Created list "${sharedList.title}"${archivedStatus} for swimlane ${swimlane.title || swimlane._id}`);
// 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);
if (process.env.DEBUG === 'true') {
const archivedStatus = sharedList.archived ? ' (archived)' : ' (active)';
console.log(`Created list "${sharedList.title}"${archivedStatus} for swimlane ${swimlane.title || swimlane._id}`);
}
} else {
if (process.env.DEBUG === 'true') {
console.log(`List "${sharedList.title}" already exists in swimlane ${swimlane.title || swimlane._id} (double-check), skipping`);
}
}
} else {
if (process.env.DEBUG === 'true') {

View file

@ -0,0 +1,93 @@
import { Meteor } from 'meteor/meteor';
/**
* Client-side interface for fixing duplicate lists
*/
export const fixDuplicateLists = {
/**
* Get a report of all boards with duplicate lists/swimlanes
*/
async getReport() {
try {
const result = await Meteor.callAsync('fixDuplicateLists.getReport');
return result;
} catch (error) {
console.error('Error getting duplicate lists report:', error);
throw error;
}
},
/**
* Fix duplicate lists for a specific board
*/
async fixBoard(boardId) {
try {
const result = await Meteor.callAsync('fixDuplicateLists.fixBoard', boardId);
console.log(`Fixed duplicate lists for board ${boardId}:`, result);
return result;
} catch (error) {
console.error(`Error fixing board ${boardId}:`, error);
throw error;
}
},
/**
* Fix duplicate lists for all boards
*/
async fixAllBoards() {
try {
console.log('Starting fix for all boards...');
const result = await Meteor.callAsync('fixDuplicateLists.fixAllBoards');
console.log('Fix completed:', result);
return result;
} catch (error) {
console.error('Error fixing all boards:', error);
throw error;
}
},
/**
* Interactive fix with user confirmation
*/
async interactiveFix() {
try {
// Get report first
console.log('Getting duplicate lists report...');
const report = await this.getReport();
if (report.boardsWithDuplicates === 0) {
console.log('No duplicate lists found!');
return { message: 'No duplicate lists found!' };
}
console.log(`Found ${report.boardsWithDuplicates} boards with duplicate lists:`);
report.report.forEach(board => {
console.log(`- Board "${board.boardTitle}" (${board.boardId}): ${board.duplicateSwimlanes} duplicate swimlanes, ${board.duplicateLists} duplicate lists`);
});
// Ask for confirmation
const confirmed = confirm(
`Found ${report.boardsWithDuplicates} boards with duplicate lists. ` +
`This will fix ${report.report.reduce((sum, board) => sum + board.duplicateSwimlanes + board.duplicateLists, 0)} duplicates. ` +
'Continue?'
);
if (!confirmed) {
return { message: 'Fix cancelled by user' };
}
// Perform the fix
const result = await this.fixAllBoards();
return result;
} catch (error) {
console.error('Error in interactive fix:', error);
throw error;
}
}
};
// Make it available globally for console access
if (typeof window !== 'undefined') {
window.fixDuplicateLists = fixDuplicateLists;
}