diff options
author | Maxime Quandalle <maxime@quandalle.com> | 2015-08-23 11:09:48 +0200 |
---|---|---|
committer | Maxime Quandalle <maxime@quandalle.com> | 2015-08-26 19:59:44 +0200 |
commit | 48ac8b026ffdf8b3823c573e5693dcf1765383e2 (patch) | |
tree | 832576fddbcdef9810b206f1ee86469702497806 | |
parent | 9faaf07e0257f622abcaa365408fa836a1cbdea8 (diff) | |
download | wekan-48ac8b026ffdf8b3823c573e5693dcf1765383e2.tar.gz wekan-48ac8b026ffdf8b3823c573e5693dcf1765383e2.tar.bz2 wekan-48ac8b026ffdf8b3823c573e5693dcf1765383e2.zip |
Implement board archive and restoration
32 files changed, 138 insertions, 42 deletions
@@ -28,7 +28,7 @@ This release continues the implementation of basic features of a “kanban” software, especially: * Basic card attachments. If the attached file is an image we generate and - displayed a thumbnail that can be used as a card “cover” (visible in the board + display a thumbnail that can be used as a card “cover” (visible in the board general view); * User names mentions and auto-completion in card description and comments (though we don’t have any notification system for now, making this feature a diff --git a/client/components/boards/boardArchive.jade b/client/components/boards/boardArchive.jade new file mode 100644 index 00000000..d659d0cc --- /dev/null +++ b/client/components/boards/boardArchive.jade @@ -0,0 +1,12 @@ +template(name="archivedBoards") + h2 Archived boards + + ul.archived-lists + each archivedBoards + li.archived-lists-item + button.js-restore-board + i.fa.fa-undo + | Restore board + = title + else + li.no-items-message No archived board. diff --git a/client/components/boards/boardArchive.js b/client/components/boards/boardArchive.js new file mode 100644 index 00000000..1ce1a593 --- /dev/null +++ b/client/components/boards/boardArchive.js @@ -0,0 +1,35 @@ +Template.headerTitle.events({ + 'click .js-open-archived-board': function() { + Modal.open('archivedBoards') + } +}) + +BlazeComponent.extendComponent({ + template() { + return 'archivedBoards'; + }, + + onCreated() { + this.subscribe('archivedBoards') + }, + + archivedBoards() { + return Boards.find({ archived: true }, { + sort: ['title'] + }) + }, + + events() { + return [{ + 'click .js-restore-board': function() { + let boardId = this.currentData()._id + Boards.update(boardId, { + $set: { + archived: false + } + }) + Utils.goBoardId(boardId) + } + }] + }, +}).register('archivedBoards') diff --git a/client/components/boards/boardBody.jade b/client/components/boards/boardBody.jade index 6598dea9..25c8f6d8 100644 --- a/client/components/boards/boardBody.jade +++ b/client/components/boards/boardBody.jade @@ -3,6 +3,7 @@ template(name="board") if currentBoard +boardBody else + //- XXX We need a better error message in case the board has been archived +message(label="board-no-found") else +spinner diff --git a/client/components/boards/boardHeader.jade b/client/components/boards/boardHeader.jade index f6ef59c3..4773e3bb 100644 --- a/client/components/boards/boardHeader.jade +++ b/client/components/boards/boardHeader.jade @@ -60,7 +60,7 @@ template(name="boardMenuPopup") if currentUser.isBoardAdmin hr ul.pop-over-list - li: a Close Board… + li: a.js-archive-board Archive Board… template(name="boardVisibilityList") ul.pop-over-list @@ -120,6 +120,6 @@ template(name="boardChangeTitlePopup") input.js-board-name(type="text" value="{{title}}" autofocus) input.primary.wide(type="submit" value="{{_ 'rename'}}") -template(name="closeBoardPopup") +template(name="archiveBoardPopup") p {{_ 'close-board-pop'}} button.js-confirm.negate.full(type="submit") {{_ 'close'}} diff --git a/client/components/boards/boardHeader.js b/client/components/boards/boardHeader.js index efe6b5ef..19103f98 100644 --- a/client/components/boards/boardHeader.js +++ b/client/components/boards/boardHeader.js @@ -5,7 +5,14 @@ Template.boardMenuPopup.events({ Popup.close(); }, 'click .js-change-board-color': Popup.open('boardChangeColor'), - 'click .js-change-language': Popup.open('setLanguage') + 'click .js-change-language': Popup.open('setLanguage'), + 'click .js-archive-board ': Popup.afterConfirm('archiveBoard', function() { + var boardId = Session.get('currentBoard'); + Boards.update(boardId, { $set: { archived: true }}); + // XXX We should have some kind of notification on top of the page to + // confirm that the board was successfully archived. + FlowRouter.go('home'); + }) }); Template.boardChangeTitlePopup.events({ diff --git a/client/components/boards/boardList.jade b/client/components/boards/boardList.jade index a6895cc8..4a73ed48 100644 --- a/client/components/boards/boardList.jade +++ b/client/components/boards/boardList.jade @@ -1,15 +1,16 @@ template(name="boardList") - if boards.count - ul.board-list.clearfix - each boards - li(class="{{#if isStarred}}starred{{/if}}" class=colorClass) - a.js-open-board(href="{{pathFor 'board' id=_id slug=slug}}") - span.details - span.board-list-item-name= title - i.fa.js-star-board( - class="fa-star{{#if isStarred}} is-star-active{{else}}-o{{/if}}" - title="{{_ 'star-board-title'}}") - else - ul.board-list.clearfix - li.js-add-board - a.label {{_ 'add-board'}} + .wrapper + if boards.count + ul.board-list.clearfix + each boards + li(class="{{#if isStarred}}starred{{/if}}" class=colorClass) + a.js-open-board(href="{{pathFor 'board' id=_id slug=slug}}") + span.details + span.board-list-item-name= title + i.fa.js-star-board( + class="fa-star{{#if isStarred}} is-star-active{{else}}-o{{/if}}" + title="{{_ 'star-board-title'}}") + else + ul.board-list.clearfix + li.js-add-board + a.label {{_ 'add-board'}} diff --git a/client/components/boards/boardList.js b/client/components/boards/boardList.js index e86d16ab..cf6b727c 100644 --- a/client/components/boards/boardList.js +++ b/client/components/boards/boardList.js @@ -4,7 +4,7 @@ BlazeComponent.extendComponent({ }, boards: function() { - return Boards.find({}, { + return Boards.find({ archived: false }, { sort: ['title'] }); }, diff --git a/client/components/boards/boardList.styl b/client/components/boards/boardList.styl index af66a1a2..8e296028 100644 --- a/client/components/boards/boardList.styl +++ b/client/components/boards/boardList.styl @@ -1,6 +1,7 @@ +$spaceBetweenTiles = 16px + .board-list - margin: 25px auto - width: 1200px + margin: $spaceBetweenTiles ($spaceBetweenTiles/-2) 0 li float: left @@ -24,7 +25,7 @@ font-weight: 700 min-height: 18px padding: 8px 12px 8px 12px - margin: 0 16px 16px 0 + margin: 0 ($spaceBetweenTiles/2) $spaceBetweenTiles position: relative text-decoration: none diff --git a/client/components/main/header.jade b/client/components/main/header.jade index 1185da85..da7999cf 100644 --- a/client/components/main/header.jade +++ b/client/components/main/header.jade @@ -31,7 +31,7 @@ template(name="header") The main bar is a colorful bar that provide all the meta-data for the current page. This bar is contextual based. If the user is not connected we display "sign in" and "log in" buttons. - #header-main-bar + #header-main-bar(class="{{#if wrappedHeader}}wrapper{{/if}}") if $.Session.get 'currentBoard' +headerBoard else @@ -39,3 +39,7 @@ template(name="header") template(name="headerTitle") h1 LibreBoard + .board-header-btns.right + a.board-header-btn.js-open-archived-board + i.fa.fa-archive + span Archives diff --git a/client/components/main/header.js b/client/components/main/header.js index 2a545309..864f889d 100644 --- a/client/components/main/header.js +++ b/client/components/main/header.js @@ -2,6 +2,12 @@ Template.header.helpers({ // Reactively set the color of the page from the color of the current board. headerTemplate: function() { return 'headerBoard'; + }, + + wrappedHeader: function() { + var unwrapedRoutes = ['board', 'card']; + var currentRouteName = FlowRouter.getRouteName(); + return unwrapedRoutes.indexOf(currentRouteName) === -1; } }); diff --git a/client/components/main/header.styl b/client/components/main/header.styl index 1840becb..e31f0992 100644 --- a/client/components/main/header.styl +++ b/client/components/main/header.styl @@ -106,6 +106,8 @@ margin: 0 10px + span + display: inline-block + margin-top: 1px margin-right: 10px .board-header-btn-close diff --git a/client/components/main/layouts.styl b/client/components/main/layouts.styl index 42a70310..f3d9bfe9 100644 --- a/client/components/main/layouts.styl +++ b/client/components/main/layouts.styl @@ -42,6 +42,7 @@ body width: 660px min-height: 160px margin: 42px auto + padding: 12px border-radius: 4px background: darken(white, 13%) z-index: 110 @@ -49,7 +50,6 @@ body .modal-close-btn display: block float: right - margin: 12px font-size: 24px h1 @@ -206,6 +206,10 @@ dd margin-bottom: 0 padding-bottom: 0 +.wrapper + max-width: 1200px + margin: 0 auto + .relative position: relative diff --git a/client/lib/modal.js b/client/lib/modal.js index 04a9b8b2..492f6595 100644 --- a/client/lib/modal.js +++ b/client/lib/modal.js @@ -1,6 +1,6 @@ const closedValue = null -Modal = new class { +window.Modal = new class { constructor() { this._currentModal = new ReactiveVar(closedValue) } diff --git a/collections/users.js b/collections/users.js index 043f93e5..28b63ba7 100644 --- a/collections/users.js +++ b/collections/users.js @@ -14,7 +14,7 @@ Users.helpers({ }, starredBoards: function() { var starredBoardIds = this.profile.starredBoards || []; - return Boards.find({_id: {$in: starredBoardIds}}); + return Boards.find({archived: false, _id: {$in: starredBoardIds}}); }, hasStarred: function(boardId) { var starredBoardIds = this.profile.starredBoards || []; diff --git a/i18n/ar.i18n.json b/i18n/ar.i18n.json index 36df959b..811d9885 100644 --- a/i18n/ar.i18n.json +++ b/i18n/ar.i18n.json @@ -159,7 +159,7 @@ "boardChangeTitlePopup-title": "Rename Board", "boardChangeVisibilityPopup-title": "Change Visibility", "addMemberPopup-title": "Members", - "closeBoardPopup-title": "Close Board?", + "archiveBoardPopup-title": "Close Board?", "removeMemberPopup-title": "Remove Member?", "createBoardPopup-title": "Create Board", "listActionPopup-title": "List Actions", diff --git a/i18n/br.i18n.json b/i18n/br.i18n.json index cb2ab531..5d1b20d7 100644 --- a/i18n/br.i18n.json +++ b/i18n/br.i18n.json @@ -159,7 +159,7 @@ "boardChangeTitlePopup-title": "Renomear Quadro", "boardChangeVisibilityPopup-title": "Alterar Visibilidade", "addMemberPopup-title": "Membros", - "closeBoardPopup-title": "Fechar Quadro?", + "archiveBoardPopup-title": "Fechar Quadro?", "removeMemberPopup-title": "Remover Membro?", "createBoardPopup-title": "Criar Quadro", "listActionPopup-title": "Listar Ações", diff --git a/i18n/cm.i18n.json b/i18n/cm.i18n.json index 4bef035a..e43f213c 100644 --- a/i18n/cm.i18n.json +++ b/i18n/cm.i18n.json @@ -159,7 +159,7 @@ "boardChangeTitlePopup-title": "Rename Board", "boardChangeVisibilityPopup-title": "Change Visibility", "addMemberPopup-title": "Members", - "closeBoardPopup-title": "Close Board?", + "archiveBoardPopup-title": "Close Board?", "removeMemberPopup-title": "Remove Member?", "createBoardPopup-title": "Create Board", "listActionPopup-title": "List Actions", diff --git a/i18n/cn.i18n.json b/i18n/cn.i18n.json index 36817b2d..2c4867d5 100644 --- a/i18n/cn.i18n.json +++ b/i18n/cn.i18n.json @@ -159,7 +159,7 @@ "boardChangeTitlePopup-title": "重命名看板", "boardChangeVisibilityPopup-title": "更改可视级别", "addMemberPopup-title": "成员", - "closeBoardPopup-title": "关闭看板?", + "archiveBoardPopup-title": "关闭看板?", "removeMemberPopup-title": "删除成员?", "createBoardPopup-title": "创建看板", "listActionPopup-title": "列出动作", diff --git a/i18n/cs.i18n.json b/i18n/cs.i18n.json index 1943ac6e..7b5b1f7d 100644 --- a/i18n/cs.i18n.json +++ b/i18n/cs.i18n.json @@ -159,7 +159,7 @@ "boardChangeTitlePopup-title": "Rename Board", "boardChangeVisibilityPopup-title": "Change Visibility", "addMemberPopup-title": "Members", - "closeBoardPopup-title": "Close Board?", + "archiveBoardPopup-title": "Close Board?", "removeMemberPopup-title": "Remove Member?", "createBoardPopup-title": "Create Board", "listActionPopup-title": "List Actions", diff --git a/i18n/de.i18n.json b/i18n/de.i18n.json index 6eaf7089..76fbfef4 100644 --- a/i18n/de.i18n.json +++ b/i18n/de.i18n.json @@ -159,7 +159,7 @@ "boardChangeTitlePopup-title": "Bord umbenennen", "boardChangeVisibilityPopup-title": "Ändere Sichbarkeit", "addMemberPopup-title": "Nutzer", - "closeBoardPopup-title": "Schliese Bord?", + "archiveBoardPopup-title": "Schliese Bord?", "removeMemberPopup-title": "Entferne Nutzer?", "createBoardPopup-title": "Erstelle ein Bord", "listActionPopup-title": "Liste von Aktionen", diff --git a/i18n/en.i18n.json b/i18n/en.i18n.json index e74e8714..e99d8ec0 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -171,7 +171,7 @@ "boardChangeTitlePopup-title": "Rename Board", "boardChangeVisibilityPopup-title": "Change Visibility", "addMemberPopup-title": "Members", - "closeBoardPopup-title": "Close Board?", + "archiveBoardPopup-title": "Close Board?", "removeMemberPopup-title": "Remove Member?", "createBoardPopup-title": "Create Board", "listActionPopup-title": "List Actions", diff --git a/i18n/es.i18n.json b/i18n/es.i18n.json index f0e465f0..8b9e8a3a 100644 --- a/i18n/es.i18n.json +++ b/i18n/es.i18n.json @@ -159,7 +159,7 @@ "boardChangeTitlePopup-title": "Renombrar tablero", "boardChangeVisibilityPopup-title": "Cambiar visibilidad", "addMemberPopup-title": "Miembros", - "closeBoardPopup-title": "Cerrar el tablero", + "archiveBoardPopup-title": "Cerrar el tablero", "removeMemberPopup-title": "¿Eliminar miembro?", "createBoardPopup-title": "Crear tablero", "listActionPopup-title": "Acciones de la lista", diff --git a/i18n/fi.i18n.json b/i18n/fi.i18n.json index 2643d7ee..e95139f2 100644 --- a/i18n/fi.i18n.json +++ b/i18n/fi.i18n.json @@ -159,7 +159,7 @@ "boardChangeTitlePopup-title": "Nimeä taulu uudelleen", "boardChangeVisibilityPopup-title": "Vaihda näkyvyyttä", "addMemberPopup-title": "Jäsenet", - "closeBoardPopup-title": "Sulje taulu?", + "archiveBoardPopup-title": "Sulje taulu?", "removeMemberPopup-title": "Poista jäsen?", "createBoardPopup-title": "Luo taulu", "listActionPopup-title": "Listaa toimet", diff --git a/i18n/fr.i18n.json b/i18n/fr.i18n.json index 42072682..584b9eef 100644 --- a/i18n/fr.i18n.json +++ b/i18n/fr.i18n.json @@ -159,7 +159,7 @@ "boardChangeTitlePopup-title": "Renommer le tableau", "boardChangeVisibilityPopup-title": "Changer la visibilité", "addMemberPopup-title": "Membres", - "closeBoardPopup-title": "Fermer le tableau ?", + "archiveBoardPopup-title": "Fermer le tableau ?", "removeMemberPopup-title": "Supprimer le membre ?", "createBoardPopup-title": "Créer un tableau", "listActionPopup-title": "Liste des actions", diff --git a/i18n/hk.i18n.json b/i18n/hk.i18n.json index e79f152b..86a7db30 100644 --- a/i18n/hk.i18n.json +++ b/i18n/hk.i18n.json @@ -159,7 +159,7 @@ "boardChangeTitlePopup-title": "Rename Board", "boardChangeVisibilityPopup-title": "Change Visibility", "addMemberPopup-title": "Members", - "closeBoardPopup-title": "Close Board?", + "archiveBoardPopup-title": "Close Board?", "removeMemberPopup-title": "Remove Member?", "createBoardPopup-title": "Create Board", "listActionPopup-title": "List Actions", diff --git a/i18n/id.i18n.json b/i18n/id.i18n.json index e79f152b..86a7db30 100644 --- a/i18n/id.i18n.json +++ b/i18n/id.i18n.json @@ -159,7 +159,7 @@ "boardChangeTitlePopup-title": "Rename Board", "boardChangeVisibilityPopup-title": "Change Visibility", "addMemberPopup-title": "Members", - "closeBoardPopup-title": "Close Board?", + "archiveBoardPopup-title": "Close Board?", "removeMemberPopup-title": "Remove Member?", "createBoardPopup-title": "Create Board", "listActionPopup-title": "List Actions", diff --git a/i18n/ja.i18n.json b/i18n/ja.i18n.json index dad05450..37650e60 100644 --- a/i18n/ja.i18n.json +++ b/i18n/ja.i18n.json @@ -159,7 +159,7 @@ "boardChangeTitlePopup-title": "ボード名の変更", "boardChangeVisibilityPopup-title": "公開範囲の変更", "addMemberPopup-title": "メンバー", - "closeBoardPopup-title": "ボードを閉じますか?", + "archiveBoardPopup-title": "ボードを閉じますか?", "removeMemberPopup-title": "メンバーを外しますか?", "createBoardPopup-title": "ボードの作成", "listActionPopup-title": "操作一覧", diff --git a/i18n/ko.i18n.json b/i18n/ko.i18n.json index fbf3c621..c7698f27 100644 --- a/i18n/ko.i18n.json +++ b/i18n/ko.i18n.json @@ -159,7 +159,7 @@ "boardChangeTitlePopup-title": "보드 이름 바꾸기", "boardChangeVisibilityPopup-title": "표시 여부 변경", "addMemberPopup-title": "멤버", - "closeBoardPopup-title": "보드를 닫습니까?", + "archiveBoardPopup-title": "보드를 닫습니까?", "removeMemberPopup-title": "멤버를 제거합니까?", "createBoardPopup-title": "보드 생성", "listActionPopup-title": "동작 목록", diff --git a/i18n/ru.i18n.json b/i18n/ru.i18n.json index 7139323e..8158c43c 100644 --- a/i18n/ru.i18n.json +++ b/i18n/ru.i18n.json @@ -159,7 +159,7 @@ "boardChangeTitlePopup-title": "Переименовать доску", "boardChangeVisibilityPopup-title": "Изменить настройки видимости", "addMemberPopup-title": "Участники", - "closeBoardPopup-title": "Закрыть доску?", + "archiveBoardPopup-title": "Закрыть доску?", "removeMemberPopup-title": "Удалить участника?", "createBoardPopup-title": "Создать доску", "listActionPopup-title": "Список действий", diff --git a/i18n/tr.i18n.json b/i18n/tr.i18n.json index 117ead57..9f910095 100644 --- a/i18n/tr.i18n.json +++ b/i18n/tr.i18n.json @@ -159,7 +159,7 @@ "boardChangeTitlePopup-title": "Pano Adı Değiştirme", "boardChangeVisibilityPopup-title": "Görünebilirliği Değiştir", "addMemberPopup-title": "Üyeler", - "closeBoardPopup-title": "Pano Kapatılsın mı?", + "archiveBoardPopup-title": "Pano Kapatılsın mı?", "removeMemberPopup-title": "Üyeyi Çıkarmak mı?", "createBoardPopup-title": "Pano Oluşturma", "listActionPopup-title": "Liste İşlemleri", diff --git a/server/publications/boards.js b/server/publications/boards.js index 15825952..3f4f8e73 100644 --- a/server/publications/boards.js +++ b/server/publications/boards.js @@ -22,6 +22,7 @@ Meteor.publish('boards', function() { }, { fields: { _id: 1, + archived: 1, slug: 1, title: 1, color: 1, @@ -30,6 +31,28 @@ Meteor.publish('boards', function() { }); }); +Meteor.publish('archivedBoards', function() { + if (! Match.test(this.userId, String)) + return []; + + return Boards.find({ + archived: true, + members: { + $elemMatch: { + userId: this.userId, + isAdmin: true + } + } + }, { + fields: { + _id: 1, + archived: 1, + slug: 1, + title: 1 + } + }) +}); + Meteor.publishComposite('board', function(boardId) { check(boardId, String); return { |