diff --git a/client/components/sidebar/sidebar.jade b/client/components/sidebar/sidebar.jade index fdc4e6b07..662c84ad8 100644 --- a/client/components/sidebar/sidebar.jade +++ b/client/components/sidebar/sidebar.jade @@ -537,6 +537,12 @@ template(name="archiveBoardPopup") | 📦 | {{_ 'archive'}} +template(name="deleteDuplicateListsPopup") + p {{_ 'delete-duplicate-lists-confirm'}} + button.js-confirm.negate.full(type="submit") + | 🗑️ + | {{_ 'delete'}} + template(name="outgoingWebhooksPopup") each integrations form.integration-form @@ -621,6 +627,10 @@ template(name="boardMenuPopup") if currentUser.isBoardAdmin hr ul.pop-over-list + li + a.js-delete-duplicate-lists + | 🗑️ + | {{_ 'delete-duplicate-lists'}} li a.js-archive-board | ➡️📦 diff --git a/client/components/sidebar/sidebar.js b/client/components/sidebar/sidebar.js index 3d507ff8c..18f271691 100644 --- a/client/components/sidebar/sidebar.js +++ b/client/components/sidebar/sidebar.js @@ -275,6 +275,45 @@ Template.boardMenuPopup.events({ 'click .js-change-background-image': Popup.open('boardChangeBackgroundImage'), 'click .js-board-info-on-my-boards': Popup.open('boardInfoOnMyBoards'), 'click .js-change-language': Popup.open('changeLanguage'), + 'click .js-delete-duplicate-lists': Popup.afterConfirm('deleteDuplicateLists', function() { + const currentBoard = Utils.getCurrentBoard(); + if (!currentBoard) return; + + // Get all lists in the current board + const allLists = ReactiveCache.getLists({ boardId: currentBoard._id, archived: false }); + + // Group lists by title to find duplicates + const listsByTitle = {}; + allLists.forEach(list => { + if (!listsByTitle[list.title]) { + listsByTitle[list.title] = []; + } + listsByTitle[list.title].push(list); + }); + + // Find and delete duplicate lists that have no cards + let deletedCount = 0; + Object.keys(listsByTitle).forEach(title => { + const listsWithSameTitle = listsByTitle[title]; + if (listsWithSameTitle.length > 1) { + // Keep the first list, delete the rest if they have no cards + for (let i = 1; i < listsWithSameTitle.length; i++) { + const list = listsWithSameTitle[i]; + const cardsInList = ReactiveCache.getCards({ listId: list._id, archived: false }); + + if (cardsInList.length === 0) { + Lists.remove(list._id); + deletedCount++; + } + } + } + }); + + // Show notification + if (deletedCount > 0) { + // You could add a toast notification here if available + } + }), 'click .js-archive-board ': Popup.afterConfirm('archiveBoard', function() { const currentBoard = Utils.getCurrentBoard(); currentBoard.archive(); diff --git a/imports/i18n/data/en.i18n.json b/imports/i18n/data/en.i18n.json index bcdd00061..eef27e1fe 100644 --- a/imports/i18n/data/en.i18n.json +++ b/imports/i18n/data/en.i18n.json @@ -755,6 +755,8 @@ "delete-board-confirm-popup": "All lists, cards, labels, and activities will be deleted and you won't be able to recover the board contents. There is no undo.", "boardDeletePopup-title": "Delete Board?", "delete-board": "Delete Board", + "delete-duplicate-lists": "Delete Duplicate Lists", + "delete-duplicate-lists-confirm": "Are you sure? This will delete all duplicate lists that have the same name and contain no cards.", "default-subtasks-board": "Subtasks for __board__ board", "default": "Default", "defaultdefault": "Default",