mirror of
https://github.com/wekan/wekan.git
synced 2025-12-28 13:18:49 +01:00
Fix list view issues. Allow creation of boards from templates
This commit is contained in:
parent
13c2157e36
commit
dc7286a0ef
12 changed files with 122 additions and 35 deletions
|
|
@ -27,7 +27,7 @@ template(name="boardBody")
|
||||||
each currentBoard.swimlanes
|
each currentBoard.swimlanes
|
||||||
+swimlane(this)
|
+swimlane(this)
|
||||||
else if isViewLists
|
else if isViewLists
|
||||||
+listsGroup
|
+listsGroup(currentBoard)
|
||||||
else if isViewCalendar
|
else if isViewCalendar
|
||||||
+calendarView
|
+calendarView
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -277,7 +277,10 @@ template(name="createBoard")
|
||||||
input.primary.wide(type="submit" value="{{_ 'create'}}")
|
input.primary.wide(type="submit" value="{{_ 'create'}}")
|
||||||
span.quiet
|
span.quiet
|
||||||
| {{_ 'or'}}
|
| {{_ 'or'}}
|
||||||
a.js-import-board {{_ 'import-board'}}
|
a.js-import-board {{_ 'import'}}
|
||||||
|
span.quiet
|
||||||
|
| /
|
||||||
|
a.js-board-template {{_ 'template'}}
|
||||||
|
|
||||||
template(name="chooseBoardSource")
|
template(name="chooseBoardSource")
|
||||||
ul.pop-over-list
|
ul.pop-over-list
|
||||||
|
|
|
||||||
|
|
@ -304,6 +304,7 @@ const CreateBoard = BlazeComponent.extendComponent({
|
||||||
'click .js-import': Popup.open('boardImportBoard'),
|
'click .js-import': Popup.open('boardImportBoard'),
|
||||||
submit: this.onSubmit,
|
submit: this.onSubmit,
|
||||||
'click .js-import-board': Popup.open('chooseBoardSource'),
|
'click .js-import-board': Popup.open('chooseBoardSource'),
|
||||||
|
'click .js-board-template': Popup.open('searchElement'),
|
||||||
}];
|
}];
|
||||||
},
|
},
|
||||||
}).register('createBoardPopup');
|
}).register('createBoardPopup');
|
||||||
|
|
|
||||||
8
client/components/boards/miniboard.jade
Normal file
8
client/components/boards/miniboard.jade
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
template(name="miniboard")
|
||||||
|
.minicard(
|
||||||
|
class="minicard-{{colorClass}}")
|
||||||
|
.minicard-title
|
||||||
|
.handle
|
||||||
|
.fa.fa-arrows
|
||||||
|
+viewer
|
||||||
|
= title
|
||||||
|
|
@ -103,16 +103,23 @@ template(name="searchElementPopup")
|
||||||
input(type="text" name="searchTerm" placeholder="{{_ 'search-example'}}" autofocus)
|
input(type="text" name="searchTerm" placeholder="{{_ 'search-example'}}" autofocus)
|
||||||
.list-body.js-perfect-scrollbar.search-card-results
|
.list-body.js-perfect-scrollbar.search-card-results
|
||||||
.minicards.clearfix.js-minicards
|
.minicards.clearfix.js-minicards
|
||||||
each results
|
if isBoardTemplateSearch
|
||||||
if isListTemplateSearch
|
each results
|
||||||
|
a.minicard-wrapper.js-minicard
|
||||||
|
+miniboard(this)
|
||||||
|
if isListTemplateSearch
|
||||||
|
each results
|
||||||
a.minicard-wrapper.js-minicard
|
a.minicard-wrapper.js-minicard
|
||||||
+minilist(this)
|
+minilist(this)
|
||||||
if isSwimlaneTemplateSearch
|
if isSwimlaneTemplateSearch
|
||||||
|
each results
|
||||||
a.minicard-wrapper.js-minicard
|
a.minicard-wrapper.js-minicard
|
||||||
+miniswimlane(this)
|
+miniswimlane(this)
|
||||||
if isCardTemplateSearch
|
if isCardTemplateSearch
|
||||||
|
each results
|
||||||
a.minicard-wrapper.js-minicard
|
a.minicard-wrapper.js-minicard
|
||||||
+minicard(this)
|
+minicard(this)
|
||||||
unless isTemplateSearch
|
unless isTemplateSearch
|
||||||
|
each results
|
||||||
a.minicard-wrapper.js-minicard
|
a.minicard-wrapper.js-minicard
|
||||||
+minicard(this)
|
+minicard(this)
|
||||||
|
|
|
||||||
|
|
@ -527,7 +527,11 @@ BlazeComponent.extendComponent({
|
||||||
this.isCardTemplateSearch = $(Popup._getTopStack().openerElement).hasClass('js-card-template');
|
this.isCardTemplateSearch = $(Popup._getTopStack().openerElement).hasClass('js-card-template');
|
||||||
this.isListTemplateSearch = $(Popup._getTopStack().openerElement).hasClass('js-list-template');
|
this.isListTemplateSearch = $(Popup._getTopStack().openerElement).hasClass('js-list-template');
|
||||||
this.isSwimlaneTemplateSearch = $(Popup._getTopStack().openerElement).hasClass('js-open-add-swimlane-menu');
|
this.isSwimlaneTemplateSearch = $(Popup._getTopStack().openerElement).hasClass('js-open-add-swimlane-menu');
|
||||||
this.isTemplateSearch = this.isCardTemplateSearch || this.isListTemplateSearch || this.isSwimlaneTemplateSearch;
|
this.isBoardTemplateSearch = $(Popup._getTopStack().openerElement).hasClass('js-add-board');
|
||||||
|
this.isTemplateSearch = this.isCardTemplateSearch ||
|
||||||
|
this.isListTemplateSearch ||
|
||||||
|
this.isSwimlaneTemplateSearch ||
|
||||||
|
this.isBoardTemplateSearch;
|
||||||
let board = {};
|
let board = {};
|
||||||
if (this.isTemplateSearch) {
|
if (this.isTemplateSearch) {
|
||||||
board = Boards.findOne(Meteor.user().profile.templatesBoardId);
|
board = Boards.findOne(Meteor.user().profile.templatesBoardId);
|
||||||
|
|
@ -548,23 +552,26 @@ BlazeComponent.extendComponent({
|
||||||
subManager.subscribe('board', boardId);
|
subManager.subscribe('board', boardId);
|
||||||
this.selectedBoardId = new ReactiveVar(boardId);
|
this.selectedBoardId = new ReactiveVar(boardId);
|
||||||
|
|
||||||
this.boardId = Session.get('currentBoard');
|
if (!this.isBoardTemplateSearch) {
|
||||||
// In order to get current board info
|
this.boardId = Session.get('currentBoard');
|
||||||
subManager.subscribe('board', this.boardId);
|
// In order to get current board info
|
||||||
// List where to insert card
|
subManager.subscribe('board', this.boardId);
|
||||||
const list = $(Popup._getTopStack().openerElement).closest('.js-list');
|
this.swimlaneId = '';
|
||||||
this.listId = Blaze.getData(list[0])._id;
|
// Swimlane where to insert card
|
||||||
// Swimlane where to insert card
|
const swimlane = $(Popup._getTopStack().openerElement).parents('.js-swimlane');
|
||||||
const swimlane = $(Popup._getTopStack().openerElement).parents('.js-swimlane');
|
if (Meteor.user().profile.boardView === 'board-view-swimlanes')
|
||||||
this.swimlaneId = '';
|
this.swimlaneId = Blaze.getData(swimlane[0])._id;
|
||||||
if (Meteor.user().profile.boardView === 'board-view-swimlanes')
|
else
|
||||||
this.swimlaneId = Blaze.getData(swimlane[0])._id;
|
this.swimlaneId = Swimlanes.findOne({boardId: this.boardId})._id;
|
||||||
else
|
// List where to insert card
|
||||||
this.swimlaneId = Swimlanes.findOne({boardId: this.boardId})._id;
|
const list = $(Popup._getTopStack().openerElement).closest('.js-list');
|
||||||
|
this.listId = Blaze.getData(list[0])._id;
|
||||||
|
}
|
||||||
this.term = new ReactiveVar('');
|
this.term = new ReactiveVar('');
|
||||||
},
|
},
|
||||||
|
|
||||||
boards() {
|
boards() {
|
||||||
|
console.log('booom');
|
||||||
const boards = Boards.find({
|
const boards = Boards.find({
|
||||||
archived: false,
|
archived: false,
|
||||||
'members.userId': Meteor.userId(),
|
'members.userId': Meteor.userId(),
|
||||||
|
|
@ -587,6 +594,12 @@ BlazeComponent.extendComponent({
|
||||||
return board.searchLists(this.term.get());
|
return board.searchLists(this.term.get());
|
||||||
} else if (this.isSwimlaneTemplateSearch) {
|
} else if (this.isSwimlaneTemplateSearch) {
|
||||||
return board.searchSwimlanes(this.term.get());
|
return board.searchSwimlanes(this.term.get());
|
||||||
|
} else if (this.isBoardTemplateSearch) {
|
||||||
|
const boards = board.searchBoards(this.term.get());
|
||||||
|
boards.forEach((board) => {
|
||||||
|
subManager.subscribe('board', board.linkedId);
|
||||||
|
});
|
||||||
|
return boards;
|
||||||
} else {
|
} else {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
@ -605,11 +618,11 @@ BlazeComponent.extendComponent({
|
||||||
'click .js-minicard'(evt) {
|
'click .js-minicard'(evt) {
|
||||||
// 0. Common
|
// 0. Common
|
||||||
const element = Blaze.getData(evt.currentTarget);
|
const element = Blaze.getData(evt.currentTarget);
|
||||||
element.boardId = this.boardId;
|
|
||||||
let _id = '';
|
let _id = '';
|
||||||
if (!this.isTemplateSearch || this.isCardTemplateSearch) {
|
if (!this.isTemplateSearch || this.isCardTemplateSearch) {
|
||||||
// Card insertion
|
// Card insertion
|
||||||
// 1. Common
|
// 1. Common
|
||||||
|
element.boardId = this.boardId;
|
||||||
element.listId = this.listId;
|
element.listId = this.listId;
|
||||||
element.swimlaneId = this.swimlaneId;
|
element.swimlaneId = this.swimlaneId;
|
||||||
element.sort = Lists.findOne(this.listId).cards().count();
|
element.sort = Lists.findOne(this.listId).cards().count();
|
||||||
|
|
@ -620,7 +633,7 @@ BlazeComponent.extendComponent({
|
||||||
_id = element.copy();
|
_id = element.copy();
|
||||||
// 1.B Linked card
|
// 1.B Linked card
|
||||||
} else {
|
} else {
|
||||||
element._id = null;
|
delete element._id;
|
||||||
element.type = 'cardType-linkedCard';
|
element.type = 'cardType-linkedCard';
|
||||||
element.linkedId = element.linkedId || element._id;
|
element.linkedId = element.linkedId || element._id;
|
||||||
_id = Cards.insert(element);
|
_id = Cards.insert(element);
|
||||||
|
|
@ -628,14 +641,22 @@ BlazeComponent.extendComponent({
|
||||||
Filter.addException(_id);
|
Filter.addException(_id);
|
||||||
// List insertion
|
// List insertion
|
||||||
} else if (this.isListTemplateSearch) {
|
} else if (this.isListTemplateSearch) {
|
||||||
|
element.boardId = this.boardId;
|
||||||
element.sort = Swimlanes.findOne(this.swimlaneId).lists().count();
|
element.sort = Swimlanes.findOne(this.swimlaneId).lists().count();
|
||||||
element.type = 'list';
|
element.type = 'list';
|
||||||
element.swimlaneId = '';
|
|
||||||
_id = element.copy(this.swimlaneId);
|
_id = element.copy(this.swimlaneId);
|
||||||
} else if (this.isSwimlaneTemplateSearch) {
|
} else if (this.isSwimlaneTemplateSearch) {
|
||||||
|
element.boardId = this.boardId;
|
||||||
element.sort = Boards.findOne(this.boardId).swimlanes().count();
|
element.sort = Boards.findOne(this.boardId).swimlanes().count();
|
||||||
element.type = 'swimlalne';
|
element.type = 'swimlalne';
|
||||||
_id = element.copy();
|
_id = element.copy();
|
||||||
|
} else if (this.isBoardTemplateSearch) {
|
||||||
|
board = Boards.findOne(element.linkedId);
|
||||||
|
board.sort = Boards.find({archived: false}).count();
|
||||||
|
board.type = 'board';
|
||||||
|
delete board.slug;
|
||||||
|
delete board.members;
|
||||||
|
_id = board.copy();
|
||||||
}
|
}
|
||||||
Popup.close();
|
Popup.close();
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,10 @@ import sanitizeXss from 'xss';
|
||||||
const at = HTML.CharRef({html: '@', str: '@'});
|
const at = HTML.CharRef({html: '@', str: '@'});
|
||||||
Blaze.Template.registerHelper('mentions', new Template('mentions', function() {
|
Blaze.Template.registerHelper('mentions', new Template('mentions', function() {
|
||||||
const view = this;
|
const view = this;
|
||||||
|
let content = Blaze.toHTML(view.templateContentBlock);
|
||||||
const currentBoard = Boards.findOne(Session.get('currentBoard'));
|
const currentBoard = Boards.findOne(Session.get('currentBoard'));
|
||||||
|
if (!currentBoard)
|
||||||
|
return HTML.Raw(sanitizeXss(content));
|
||||||
const knowedUsers = currentBoard.members.map((member) => {
|
const knowedUsers = currentBoard.members.map((member) => {
|
||||||
const u = Users.findOne(member.userId);
|
const u = Users.findOne(member.userId);
|
||||||
if(u){
|
if(u){
|
||||||
|
|
@ -45,7 +48,6 @@ Blaze.Template.registerHelper('mentions', new Template('mentions', function() {
|
||||||
return member;
|
return member;
|
||||||
});
|
});
|
||||||
const mentionRegex = /\B@([\w.]*)/gi;
|
const mentionRegex = /\B@([\w.]*)/gi;
|
||||||
let content = Blaze.toHTML(view.templateContentBlock);
|
|
||||||
|
|
||||||
let currentMention;
|
let currentMention;
|
||||||
while ((currentMention = mentionRegex.exec(content)) !== null) {
|
while ((currentMention = mentionRegex.exec(content)) !== null) {
|
||||||
|
|
|
||||||
|
|
@ -315,6 +315,21 @@ Boards.attachSchema(new SimpleSchema({
|
||||||
|
|
||||||
|
|
||||||
Boards.helpers({
|
Boards.helpers({
|
||||||
|
copy() {
|
||||||
|
const oldId = this._id;
|
||||||
|
delete this._id;
|
||||||
|
const _id = Boards.insert(this);
|
||||||
|
|
||||||
|
// Copy all swimlanes in board
|
||||||
|
Swimlanes.find({
|
||||||
|
boardId: oldId,
|
||||||
|
archived: false,
|
||||||
|
}).forEach((swimlane) => {
|
||||||
|
swimlane.type = 'swimlane';
|
||||||
|
swimlane.boardId = _id;
|
||||||
|
swimlane.copy(oldId);
|
||||||
|
});
|
||||||
|
},
|
||||||
/**
|
/**
|
||||||
* Is supplied user authorized to view this board?
|
* Is supplied user authorized to view this board?
|
||||||
*/
|
*/
|
||||||
|
|
@ -463,6 +478,27 @@ Boards.helpers({
|
||||||
return _id;
|
return _id;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
searchBoards(term) {
|
||||||
|
check(term, Match.OneOf(String, null, undefined));
|
||||||
|
|
||||||
|
const query = { boardId: this._id };
|
||||||
|
query.type = 'cardType-linkedBoard';
|
||||||
|
query.archived = false;
|
||||||
|
|
||||||
|
const projection = { limit: 10, sort: { createdAt: -1 } };
|
||||||
|
|
||||||
|
if (term) {
|
||||||
|
const regex = new RegExp(term, 'i');
|
||||||
|
|
||||||
|
query.$or = [
|
||||||
|
{ title: regex },
|
||||||
|
{ description: regex },
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
return Cards.find(query, projection);
|
||||||
|
},
|
||||||
|
|
||||||
searchSwimlanes(term) {
|
searchSwimlanes(term) {
|
||||||
check(term, Match.OneOf(String, null, undefined));
|
check(term, Match.OneOf(String, null, undefined));
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -69,7 +69,7 @@ CardComments.allow({
|
||||||
CardComments.helpers({
|
CardComments.helpers({
|
||||||
copy(newCardId) {
|
copy(newCardId) {
|
||||||
this.cardId = newCardId;
|
this.cardId = newCardId;
|
||||||
this._id = null;
|
delete this._id;
|
||||||
CardComments.insert(this);
|
CardComments.insert(this);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -274,7 +274,7 @@ Cards.allow({
|
||||||
Cards.helpers({
|
Cards.helpers({
|
||||||
copy() {
|
copy() {
|
||||||
const oldId = this._id;
|
const oldId = this._id;
|
||||||
this._id = null;
|
delete this._id;
|
||||||
const _id = Cards.insert(this);
|
const _id = Cards.insert(this);
|
||||||
|
|
||||||
// copy checklists
|
// copy checklists
|
||||||
|
|
|
||||||
|
|
@ -139,20 +139,24 @@ Lists.allow({
|
||||||
Lists.helpers({
|
Lists.helpers({
|
||||||
copy(swimlaneId) {
|
copy(swimlaneId) {
|
||||||
const oldId = this._id;
|
const oldId = this._id;
|
||||||
|
const oldSwimlaneId = this.swimlaneId || null;
|
||||||
let _id = null;
|
let _id = null;
|
||||||
existingListWithSameName = Lists.findOne({
|
existingListWithSameName = Lists.findOne({
|
||||||
boardId: this.boardId,
|
boardId: this.boardId,
|
||||||
title: this.title,
|
title: this.title,
|
||||||
|
archived: false,
|
||||||
});
|
});
|
||||||
if (existingListWithSameName) {
|
if (existingListWithSameName) {
|
||||||
_id = existingListWithSameName._id;
|
_id = existingListWithSameName._id;
|
||||||
} else {
|
} else {
|
||||||
this._id = null;
|
delete this._id;
|
||||||
|
delete this.swimlaneId;
|
||||||
_id = Lists.insert(this);
|
_id = Lists.insert(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy all cards in list
|
// Copy all cards in list
|
||||||
Cards.find({
|
Cards.find({
|
||||||
|
swimlaneId: oldSwimlaneId,
|
||||||
listId: oldId,
|
listId: oldId,
|
||||||
archived: false,
|
archived: false,
|
||||||
}).forEach((card) => {
|
}).forEach((card) => {
|
||||||
|
|
|
||||||
|
|
@ -101,18 +101,23 @@ Swimlanes.allow({
|
||||||
});
|
});
|
||||||
|
|
||||||
Swimlanes.helpers({
|
Swimlanes.helpers({
|
||||||
copy() {
|
copy(oldBoardId) {
|
||||||
const oldId = this._id;
|
const oldId = this._id;
|
||||||
this._id = null;
|
delete this._id;
|
||||||
const _id = Swimlanes.insert(this);
|
const _id = Swimlanes.insert(this);
|
||||||
|
|
||||||
// Copy all lists in swimlane
|
const query = {
|
||||||
Lists.find({
|
swimlaneId: {$in: [oldId, '']},
|
||||||
swimlaneId: oldId,
|
|
||||||
archived: false,
|
archived: false,
|
||||||
}).forEach((list) => {
|
};
|
||||||
|
if (oldBoardId) {
|
||||||
|
query.boardId = oldBoardId;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy all lists in swimlane
|
||||||
|
Lists.find(query).forEach((list) => {
|
||||||
list.type = 'list';
|
list.type = 'list';
|
||||||
list.swimlaneId = '';
|
list.swimlaneId = oldId;
|
||||||
list.boardId = this.boardId;
|
list.boardId = this.boardId;
|
||||||
list.copy(_id);
|
list.copy(_id);
|
||||||
});
|
});
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue