mirror of
https://github.com/wekan/wekan.git
synced 2026-03-13 17:06:13 +01:00
Migrate rules, activities, and remaining components to Template
Convert all remaining BlazeComponent-based components to native Meteor Template pattern: activities, comments, all rules actions/triggers, swimlanes, users, gantt, import, and main utility components.
This commit is contained in:
parent
bae23f9ed8
commit
477e1c89e5
29 changed files with 2859 additions and 2894 deletions
|
|
@ -5,164 +5,158 @@ import { TAPi18n } from '/imports/i18n';
|
||||||
|
|
||||||
const activitiesPerPage = 500;
|
const activitiesPerPage = 500;
|
||||||
|
|
||||||
BlazeComponent.extendComponent({
|
Template.activities.onCreated(function () {
|
||||||
onCreated() {
|
// Register with sidebar so it can call loadNextPage on us
|
||||||
// XXX Should we use ReactiveNumber?
|
if (Sidebar) {
|
||||||
this.page = new ReactiveVar(1);
|
Sidebar.activitiesInstance = this;
|
||||||
this.loadNextPageLocked = false;
|
}
|
||||||
// TODO is sidebar always available? E.g. on small screens/mobile devices
|
|
||||||
const sidebar = Sidebar;
|
|
||||||
sidebar && sidebar.callFirstWith(null, 'resetNextPeak');
|
|
||||||
this.autorun(() => {
|
|
||||||
let mode = this.data()?.mode;
|
|
||||||
if (mode) {
|
|
||||||
const capitalizedMode = Utils.capitalize(mode);
|
|
||||||
let searchId;
|
|
||||||
const showActivities = this.showActivities();
|
|
||||||
if (mode === 'linkedcard' || mode === 'linkedboard') {
|
|
||||||
const currentCard = Utils.getCurrentCard();
|
|
||||||
searchId = currentCard.linkedId;
|
|
||||||
mode = mode.replace('linked', '');
|
|
||||||
} else if (mode === 'card') {
|
|
||||||
searchId = Utils.getCurrentCardId();
|
|
||||||
} else {
|
|
||||||
searchId = Session.get(`current${capitalizedMode}`);
|
|
||||||
}
|
|
||||||
const limit = this.page.get() * activitiesPerPage;
|
|
||||||
if (searchId === null) return;
|
|
||||||
|
|
||||||
this.subscribe('activities', mode, searchId, limit, showActivities, () => {
|
// XXX Should we use ReactiveNumber?
|
||||||
this.loadNextPageLocked = false;
|
this.page = new ReactiveVar(1);
|
||||||
|
this.loadNextPageLocked = false;
|
||||||
// TODO the guard can be removed as soon as the TODO above is resolved
|
this.loadNextPage = () => {
|
||||||
if (!sidebar) return;
|
|
||||||
// If the sibear peak hasn't increased, that mean that there are no more
|
|
||||||
// activities, and we can stop calling new subscriptions.
|
|
||||||
// XXX This is hacky! We need to know excatly and reactively how many
|
|
||||||
// activities there are, we probably want to denormalize this number
|
|
||||||
// dirrectly into card and board documents.
|
|
||||||
const nextPeakBefore = sidebar.callFirstWith(null, 'getNextPeak');
|
|
||||||
sidebar.calculateNextPeak();
|
|
||||||
const nextPeakAfter = sidebar.callFirstWith(null, 'getNextPeak');
|
|
||||||
if (nextPeakBefore === nextPeakAfter) {
|
|
||||||
sidebar.callFirstWith(null, 'resetNextPeak');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
loadNextPage() {
|
|
||||||
if (this.loadNextPageLocked === false) {
|
if (this.loadNextPageLocked === false) {
|
||||||
this.page.set(this.page.get() + 1);
|
this.page.set(this.page.get() + 1);
|
||||||
this.loadNextPageLocked = true;
|
this.loadNextPageLocked = true;
|
||||||
}
|
}
|
||||||
},
|
};
|
||||||
showActivities() {
|
|
||||||
let ret = false;
|
// TODO is sidebar always available? E.g. on small screens/mobile devices
|
||||||
let mode = this.data()?.mode;
|
const sidebar = Sidebar;
|
||||||
|
if (sidebar && sidebar.infiniteScrolling) {
|
||||||
|
sidebar.infiniteScrolling.resetNextPeak();
|
||||||
|
}
|
||||||
|
this.autorun(() => {
|
||||||
|
const data = Template.currentData();
|
||||||
|
let mode = data?.mode;
|
||||||
if (mode) {
|
if (mode) {
|
||||||
|
const capitalizedMode = Utils.capitalize(mode);
|
||||||
|
let searchId;
|
||||||
|
const showActivities = _showActivities(data);
|
||||||
if (mode === 'linkedcard' || mode === 'linkedboard') {
|
if (mode === 'linkedcard' || mode === 'linkedboard') {
|
||||||
const currentCard = Utils.getCurrentCard();
|
const currentCard = Utils.getCurrentCard();
|
||||||
ret = currentCard.showActivities ?? false;
|
searchId = currentCard.linkedId;
|
||||||
|
mode = mode.replace('linked', '');
|
||||||
} else if (mode === 'card') {
|
} else if (mode === 'card') {
|
||||||
ret = this.data()?.card?.showActivities ?? false;
|
searchId = Utils.getCurrentCardId();
|
||||||
} else {
|
} else {
|
||||||
ret = Utils.getCurrentBoard().showActivities ?? false;
|
searchId = Session.get(`current${capitalizedMode}`);
|
||||||
}
|
}
|
||||||
}
|
const limit = this.page.get() * activitiesPerPage;
|
||||||
return ret;
|
if (searchId === null) return;
|
||||||
},
|
|
||||||
activities() {
|
|
||||||
const ret = this.data().card.activities();
|
|
||||||
return ret;
|
|
||||||
},
|
|
||||||
}).register('activities');
|
|
||||||
|
|
||||||
BlazeComponent.extendComponent({
|
this.subscribe('activities', mode, searchId, limit, showActivities, () => {
|
||||||
|
this.loadNextPageLocked = false;
|
||||||
|
|
||||||
|
// TODO the guard can be removed as soon as the TODO above is resolved
|
||||||
|
if (!sidebar || !sidebar.infiniteScrolling) return;
|
||||||
|
// If the sidebar peak hasn't increased, that means that there are no more
|
||||||
|
// activities, and we can stop calling new subscriptions.
|
||||||
|
const nextPeakBefore = sidebar.infiniteScrolling.getNextPeak();
|
||||||
|
sidebar.calculateNextPeak();
|
||||||
|
const nextPeakAfter = sidebar.infiniteScrolling.getNextPeak();
|
||||||
|
if (nextPeakBefore === nextPeakAfter) {
|
||||||
|
sidebar.infiniteScrolling.resetNextPeak();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
function _showActivities(data) {
|
||||||
|
let ret = false;
|
||||||
|
let mode = data?.mode;
|
||||||
|
if (mode) {
|
||||||
|
if (mode === 'linkedcard' || mode === 'linkedboard') {
|
||||||
|
const currentCard = Utils.getCurrentCard();
|
||||||
|
ret = currentCard.showActivities ?? false;
|
||||||
|
} else if (mode === 'card') {
|
||||||
|
ret = data?.card?.showActivities ?? false;
|
||||||
|
} else {
|
||||||
|
ret = Utils.getCurrentBoard().showActivities ?? false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
Template.activities.helpers({
|
||||||
|
activities() {
|
||||||
|
return this.card.activities();
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
Template.activity.helpers({
|
||||||
checkItem() {
|
checkItem() {
|
||||||
const checkItemId = this.currentData().activity.checklistItemId;
|
const checkItemId = this.activity.checklistItemId;
|
||||||
const checkItem = ReactiveCache.getChecklistItem(checkItemId);
|
const checkItem = ReactiveCache.getChecklistItem(checkItemId);
|
||||||
return checkItem && checkItem.title;
|
return checkItem && checkItem.title;
|
||||||
},
|
},
|
||||||
|
|
||||||
boardLabelLink() {
|
boardLabelLink() {
|
||||||
const data = this.currentData();
|
|
||||||
const currentBoardId = Session.get('currentBoard');
|
const currentBoardId = Session.get('currentBoard');
|
||||||
if (data.mode !== 'board') {
|
if (this.mode !== 'board') {
|
||||||
// data.mode: card, linkedcard, linkedboard
|
return createBoardLink(this.activity.board(), this.activity.listName ? this.activity.listName : null);
|
||||||
return createBoardLink(data.activity.board(), data.activity.listName ? data.activity.listName : null);
|
|
||||||
}
|
}
|
||||||
else if (currentBoardId != data.activity.boardId) {
|
else if (currentBoardId != this.activity.boardId) {
|
||||||
// data.mode: board
|
return createBoardLink(this.activity.board(), this.activity.listName ? this.activity.listName : null);
|
||||||
// current activitie is linked
|
|
||||||
return createBoardLink(data.activity.board(), data.activity.listName ? data.activity.listName : null);
|
|
||||||
}
|
}
|
||||||
return TAPi18n.__('this-board');
|
return TAPi18n.__('this-board');
|
||||||
},
|
},
|
||||||
|
|
||||||
cardLabelLink() {
|
cardLabelLink() {
|
||||||
const data = this.currentData();
|
|
||||||
const currentBoardId = Session.get('currentBoard');
|
const currentBoardId = Session.get('currentBoard');
|
||||||
if (data.mode == 'card') {
|
if (this.mode == 'card') {
|
||||||
// data.mode: card
|
|
||||||
return TAPi18n.__('this-card');
|
return TAPi18n.__('this-card');
|
||||||
}
|
}
|
||||||
else if (data.mode !== 'board') {
|
else if (this.mode !== 'board') {
|
||||||
// data.mode: linkedcard, linkedboard
|
return createCardLink(this.activity.card(), null);
|
||||||
return createCardLink(data.activity.card(), null);
|
|
||||||
}
|
}
|
||||||
else if (currentBoardId != data.activity.boardId) {
|
else if (currentBoardId != this.activity.boardId) {
|
||||||
// data.mode: board
|
return createCardLink(this.activity.card(), this.activity.board().title);
|
||||||
// current activitie is linked
|
|
||||||
return createCardLink(data.activity.card(), data.activity.board().title);
|
|
||||||
}
|
}
|
||||||
return createCardLink(this.currentData().activity.card(), null);
|
return createCardLink(this.activity.card(), null);
|
||||||
},
|
},
|
||||||
|
|
||||||
cardLink() {
|
cardLink() {
|
||||||
const data = this.currentData();
|
|
||||||
const currentBoardId = Session.get('currentBoard');
|
const currentBoardId = Session.get('currentBoard');
|
||||||
if (data.mode !== 'board') {
|
if (this.mode !== 'board') {
|
||||||
// data.mode: card, linkedcard, linkedboard
|
return createCardLink(this.activity.card(), null);
|
||||||
return createCardLink(data.activity.card(), null);
|
|
||||||
}
|
}
|
||||||
else if (currentBoardId != data.activity.boardId) {
|
else if (currentBoardId != this.activity.boardId) {
|
||||||
// data.mode: board
|
return createCardLink(this.activity.card(), this.activity.board().title);
|
||||||
// current activitie is linked
|
|
||||||
return createCardLink(data.activity.card(), data.activity.board().title);
|
|
||||||
}
|
}
|
||||||
return createCardLink(this.currentData().activity.card(), null);
|
return createCardLink(this.activity.card(), null);
|
||||||
},
|
},
|
||||||
|
|
||||||
receivedDate() {
|
receivedDate() {
|
||||||
const receivedDate = this.currentData().activity.card();
|
const card = this.activity.card();
|
||||||
if (!receivedDate) return null;
|
if (!card) return null;
|
||||||
return receivedDate.receivedAt;
|
return card.receivedAt;
|
||||||
},
|
},
|
||||||
|
|
||||||
startDate() {
|
startDate() {
|
||||||
const startDate = this.currentData().activity.card();
|
const card = this.activity.card();
|
||||||
if (!startDate) return null;
|
if (!card) return null;
|
||||||
return startDate.startAt;
|
return card.startAt;
|
||||||
},
|
},
|
||||||
|
|
||||||
dueDate() {
|
dueDate() {
|
||||||
const dueDate = this.currentData().activity.card();
|
const card = this.activity.card();
|
||||||
if (!dueDate) return null;
|
if (!card) return null;
|
||||||
return dueDate.dueAt;
|
return card.dueAt;
|
||||||
},
|
},
|
||||||
|
|
||||||
endDate() {
|
endDate() {
|
||||||
const endDate = this.currentData().activity.card();
|
const card = this.activity.card();
|
||||||
if (!endDate) return null;
|
if (!card) return null;
|
||||||
return endDate.endAt;
|
return card.endAt;
|
||||||
},
|
},
|
||||||
|
|
||||||
lastLabel() {
|
lastLabel() {
|
||||||
const lastLabelId = this.currentData().activity.labelId;
|
const lastLabelId = this.activity.labelId;
|
||||||
if (!lastLabelId) return null;
|
if (!lastLabelId) return null;
|
||||||
const lastLabel = ReactiveCache.getBoard(
|
const lastLabel = ReactiveCache.getBoard(
|
||||||
this.currentData().activity.boardId,
|
this.activity.boardId,
|
||||||
).getLabelById(lastLabelId);
|
).getLabelById(lastLabelId);
|
||||||
if (lastLabel && (lastLabel.name === undefined || lastLabel.name === '')) {
|
if (lastLabel && (lastLabel.name === undefined || lastLabel.name === '')) {
|
||||||
return lastLabel.color;
|
return lastLabel.color;
|
||||||
|
|
@ -175,7 +169,7 @@ BlazeComponent.extendComponent({
|
||||||
|
|
||||||
lastCustomField() {
|
lastCustomField() {
|
||||||
const lastCustomField = ReactiveCache.getCustomField(
|
const lastCustomField = ReactiveCache.getCustomField(
|
||||||
this.currentData().activity.customFieldId,
|
this.activity.customFieldId,
|
||||||
);
|
);
|
||||||
if (!lastCustomField) return null;
|
if (!lastCustomField) return null;
|
||||||
return lastCustomField.name;
|
return lastCustomField.name;
|
||||||
|
|
@ -183,10 +177,10 @@ BlazeComponent.extendComponent({
|
||||||
|
|
||||||
lastCustomFieldValue() {
|
lastCustomFieldValue() {
|
||||||
const lastCustomField = ReactiveCache.getCustomField(
|
const lastCustomField = ReactiveCache.getCustomField(
|
||||||
this.currentData().activity.customFieldId,
|
this.activity.customFieldId,
|
||||||
);
|
);
|
||||||
if (!lastCustomField) return null;
|
if (!lastCustomField) return null;
|
||||||
const value = this.currentData().activity.value;
|
const value = this.activity.value;
|
||||||
if (
|
if (
|
||||||
lastCustomField.settings.dropdownItems &&
|
lastCustomField.settings.dropdownItems &&
|
||||||
lastCustomField.settings.dropdownItems.length > 0
|
lastCustomField.settings.dropdownItems.length > 0
|
||||||
|
|
@ -203,13 +197,13 @@ BlazeComponent.extendComponent({
|
||||||
},
|
},
|
||||||
|
|
||||||
listLabel() {
|
listLabel() {
|
||||||
const activity = this.currentData().activity;
|
const activity = this.activity;
|
||||||
const list = activity.list();
|
const list = activity.list();
|
||||||
return (list && list.title) || activity.title;
|
return (list && list.title) || activity.title;
|
||||||
},
|
},
|
||||||
|
|
||||||
sourceLink() {
|
sourceLink() {
|
||||||
const source = this.currentData().activity.source;
|
const source = this.activity.source;
|
||||||
if (source) {
|
if (source) {
|
||||||
if (source.url) {
|
if (source.url) {
|
||||||
return Blaze.toHTML(
|
return Blaze.toHTML(
|
||||||
|
|
@ -229,12 +223,12 @@ BlazeComponent.extendComponent({
|
||||||
|
|
||||||
memberLink() {
|
memberLink() {
|
||||||
return Blaze.toHTMLWithData(Template.memberName, {
|
return Blaze.toHTMLWithData(Template.memberName, {
|
||||||
user: this.currentData().activity.member(),
|
user: this.activity.member(),
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
attachmentLink() {
|
attachmentLink() {
|
||||||
const attachment = this.currentData().activity.attachment();
|
const attachment = this.activity.attachment();
|
||||||
// trying to display url before file is stored generates js errors
|
// trying to display url before file is stored generates js errors
|
||||||
return (
|
return (
|
||||||
(attachment &&
|
(attachment &&
|
||||||
|
|
@ -248,17 +242,16 @@ BlazeComponent.extendComponent({
|
||||||
sanitizeText(attachment.name),
|
sanitizeText(attachment.name),
|
||||||
),
|
),
|
||||||
)) ||
|
)) ||
|
||||||
sanitizeText(this.currentData().activity.attachmentName)
|
sanitizeText(this.activity.attachmentName)
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
||||||
customField() {
|
customField() {
|
||||||
const customField = this.currentData().activity.customField();
|
const customField = this.activity.customField();
|
||||||
if (!customField) return null;
|
if (!customField) return null;
|
||||||
return customField.name;
|
return customField.name;
|
||||||
},
|
},
|
||||||
|
});
|
||||||
}).register('activity');
|
|
||||||
|
|
||||||
Template.activity.helpers({
|
Template.activity.helpers({
|
||||||
sanitize(value) {
|
sanitize(value) {
|
||||||
|
|
|
||||||
|
|
@ -2,94 +2,79 @@ import { ReactiveCache } from '/imports/reactiveCache';
|
||||||
|
|
||||||
const commentFormIsOpen = new ReactiveVar(false);
|
const commentFormIsOpen = new ReactiveVar(false);
|
||||||
|
|
||||||
BlazeComponent.extendComponent({
|
Template.commentForm.onDestroyed(function () {
|
||||||
onDestroyed() {
|
commentFormIsOpen.set(false);
|
||||||
commentFormIsOpen.set(false);
|
$('.note-popover').hide();
|
||||||
$('.note-popover').hide();
|
});
|
||||||
},
|
|
||||||
|
|
||||||
|
Template.commentForm.helpers({
|
||||||
commentFormIsOpen() {
|
commentFormIsOpen() {
|
||||||
return commentFormIsOpen.get();
|
return commentFormIsOpen.get();
|
||||||
},
|
},
|
||||||
|
});
|
||||||
|
|
||||||
getInput() {
|
Template.commentForm.events({
|
||||||
return this.$('.js-new-comment-input');
|
'submit .js-new-comment-form'(evt, tpl) {
|
||||||
|
const input = tpl.$('.js-new-comment-input');
|
||||||
|
const text = input.val().trim();
|
||||||
|
const card = Template.currentData();
|
||||||
|
let boardId = card.boardId;
|
||||||
|
let cardId = card._id;
|
||||||
|
if (card.isLinkedCard()) {
|
||||||
|
boardId = ReactiveCache.getCard(card.linkedId).boardId;
|
||||||
|
cardId = card.linkedId;
|
||||||
|
} else if (card.isLinkedBoard()) {
|
||||||
|
boardId = card.linkedId;
|
||||||
|
}
|
||||||
|
if (text) {
|
||||||
|
CardComments.insert({
|
||||||
|
text,
|
||||||
|
boardId,
|
||||||
|
cardId,
|
||||||
|
});
|
||||||
|
resetCommentInput(input);
|
||||||
|
Tracker.flush();
|
||||||
|
autosize.update(input);
|
||||||
|
input.trigger('submitted');
|
||||||
|
}
|
||||||
|
evt.preventDefault();
|
||||||
},
|
},
|
||||||
|
// Pressing Ctrl+Enter should submit the form
|
||||||
events() {
|
'keydown form textarea'(evt, tpl) {
|
||||||
return [
|
if (evt.keyCode === 13 && (evt.metaKey || evt.ctrlKey)) {
|
||||||
{
|
tpl.find('button[type=submit]').click();
|
||||||
'submit .js-new-comment-form'(evt) {
|
}
|
||||||
const input = this.getInput();
|
|
||||||
const text = input.val().trim();
|
|
||||||
const card = this.currentData();
|
|
||||||
let boardId = card.boardId;
|
|
||||||
let cardId = card._id;
|
|
||||||
if (card.isLinkedCard()) {
|
|
||||||
boardId = ReactiveCache.getCard(card.linkedId).boardId;
|
|
||||||
cardId = card.linkedId;
|
|
||||||
} else if (card.isLinkedBoard()) {
|
|
||||||
boardId = card.linkedId;
|
|
||||||
}
|
|
||||||
if (text) {
|
|
||||||
CardComments.insert({
|
|
||||||
text,
|
|
||||||
boardId,
|
|
||||||
cardId,
|
|
||||||
});
|
|
||||||
resetCommentInput(input);
|
|
||||||
Tracker.flush();
|
|
||||||
autosize.update(input);
|
|
||||||
input.trigger('submitted');
|
|
||||||
}
|
|
||||||
evt.preventDefault();
|
|
||||||
},
|
|
||||||
// Pressing Ctrl+Enter should submit the form
|
|
||||||
'keydown form textarea'(evt) {
|
|
||||||
if (evt.keyCode === 13 && (evt.metaKey || evt.ctrlKey)) {
|
|
||||||
this.find('button[type=submit]').click();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
];
|
|
||||||
},
|
},
|
||||||
}).register('commentForm');
|
});
|
||||||
|
|
||||||
BlazeComponent.extendComponent({
|
Template.comments.helpers({
|
||||||
getComments() {
|
getComments() {
|
||||||
const data = this.data();
|
const data = Template.currentData();
|
||||||
if (!data || typeof data.comments !== 'function') return [];
|
if (!data || typeof data.comments !== 'function') return [];
|
||||||
return data.comments();
|
return data.comments();
|
||||||
},
|
},
|
||||||
}).register("comments");
|
});
|
||||||
|
|
||||||
BlazeComponent.extendComponent({
|
Template.comment.events({
|
||||||
events() {
|
'click .js-delete-comment': Popup.afterConfirm('deleteComment', function () {
|
||||||
return [
|
const commentId = this._id;
|
||||||
{
|
CardComments.remove(commentId);
|
||||||
'click .js-delete-comment': Popup.afterConfirm('deleteComment', () => {
|
Popup.back();
|
||||||
const commentId = this.data()._id;
|
}),
|
||||||
CardComments.remove(commentId);
|
'submit .js-edit-comment'(evt, tpl) {
|
||||||
Popup.back();
|
evt.preventDefault();
|
||||||
}),
|
const textarea = tpl.find('.js-edit-comment textarea,input[type=text]');
|
||||||
'submit .js-edit-comment'(evt) {
|
const commentText = textarea && textarea.value ? textarea.value.trim() : '';
|
||||||
evt.preventDefault();
|
const commentId = this._id;
|
||||||
const commentText = this.currentComponent()
|
if (commentText) {
|
||||||
.getValue()
|
CardComments.update(commentId, {
|
||||||
.trim();
|
$set: {
|
||||||
const commentId = this.data()._id;
|
text: commentText,
|
||||||
if (commentText) {
|
|
||||||
CardComments.update(commentId, {
|
|
||||||
$set: {
|
|
||||||
text: commentText,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
},
|
});
|
||||||
];
|
}
|
||||||
},
|
},
|
||||||
}).register("comment");
|
});
|
||||||
|
|
||||||
// XXX This should be a static method of the `commentForm` component
|
// XXX This should be a static method of the `commentForm` component
|
||||||
function resetCommentInput(input) {
|
function resetCommentInput(input) {
|
||||||
|
|
|
||||||
|
|
@ -1,69 +1,69 @@
|
||||||
import { BlazeComponent } from 'meteor/peerlibrary:blaze-components';
|
|
||||||
import { ReactiveVar } from 'meteor/reactive-var';
|
import { ReactiveVar } from 'meteor/reactive-var';
|
||||||
import { Meteor } from 'meteor/meteor';
|
import { Meteor } from 'meteor/meteor';
|
||||||
import { Template } from 'meteor/templating';
|
|
||||||
import './originalPosition.html';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Component to display original position information for swimlanes, lists, and cards
|
* Component to display original position information for swimlanes, lists, and cards
|
||||||
*/
|
*/
|
||||||
class OriginalPositionComponent extends BlazeComponent {
|
|
||||||
onCreated() {
|
|
||||||
super.onCreated();
|
|
||||||
this.originalPosition = new ReactiveVar(null);
|
|
||||||
this.isLoading = new ReactiveVar(false);
|
|
||||||
this.hasMoved = new ReactiveVar(false);
|
|
||||||
|
|
||||||
this.autorun(() => {
|
Template.originalPosition.onCreated(function () {
|
||||||
const data = this.data();
|
this.originalPosition = new ReactiveVar(null);
|
||||||
if (data && data.entityId && data.entityType) {
|
this.isLoading = new ReactiveVar(false);
|
||||||
this.loadOriginalPosition(data.entityId, data.entityType);
|
this.hasMoved = new ReactiveVar(false);
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
loadOriginalPosition(entityId, entityType) {
|
const tpl = this;
|
||||||
this.isLoading.set(true);
|
|
||||||
|
function loadOriginalPosition(entityId, entityType) {
|
||||||
|
tpl.isLoading.set(true);
|
||||||
|
|
||||||
const methodName = `positionHistory.get${entityType.charAt(0).toUpperCase() + entityType.slice(1)}OriginalPosition`;
|
const methodName = `positionHistory.get${entityType.charAt(0).toUpperCase() + entityType.slice(1)}OriginalPosition`;
|
||||||
|
|
||||||
Meteor.call(methodName, entityId, (error, result) => {
|
Meteor.call(methodName, entityId, (error, result) => {
|
||||||
this.isLoading.set(false);
|
tpl.isLoading.set(false);
|
||||||
if (error) {
|
if (error) {
|
||||||
console.error('Error loading original position:', error);
|
console.error('Error loading original position:', error);
|
||||||
this.originalPosition.set(null);
|
tpl.originalPosition.set(null);
|
||||||
} else {
|
} else {
|
||||||
this.originalPosition.set(result);
|
tpl.originalPosition.set(result);
|
||||||
|
|
||||||
// Check if the entity has moved
|
// Check if the entity has moved
|
||||||
const movedMethodName = `positionHistory.has${entityType.charAt(0).toUpperCase() + entityType.slice(1)}Moved`;
|
const movedMethodName = `positionHistory.has${entityType.charAt(0).toUpperCase() + entityType.slice(1)}Moved`;
|
||||||
Meteor.call(movedMethodName, entityId, (movedError, movedResult) => {
|
Meteor.call(movedMethodName, entityId, (movedError, movedResult) => {
|
||||||
if (!movedError) {
|
if (!movedError) {
|
||||||
this.hasMoved.set(movedResult);
|
tpl.hasMoved.set(movedResult);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.autorun(() => {
|
||||||
|
const data = Template.currentData();
|
||||||
|
if (data && data.entityId && data.entityType) {
|
||||||
|
loadOriginalPosition(data.entityId, data.entityType);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
Template.originalPosition.helpers({
|
||||||
getOriginalPosition() {
|
getOriginalPosition() {
|
||||||
return this.originalPosition.get();
|
return Template.instance().originalPosition.get();
|
||||||
}
|
},
|
||||||
|
|
||||||
isLoading() {
|
isLoading() {
|
||||||
return this.isLoading.get();
|
return Template.instance().isLoading.get();
|
||||||
}
|
},
|
||||||
|
|
||||||
hasMovedFromOriginal() {
|
hasMovedFromOriginal() {
|
||||||
return this.hasMoved.get();
|
return Template.instance().hasMoved.get();
|
||||||
}
|
},
|
||||||
|
|
||||||
getOriginalPositionDescription() {
|
getOriginalPositionDescription() {
|
||||||
const position = this.getOriginalPosition();
|
const position = Template.instance().originalPosition.get();
|
||||||
if (!position) return 'No original position data';
|
if (!position) return 'No original position data';
|
||||||
|
|
||||||
if (position.originalPosition) {
|
if (position.originalPosition) {
|
||||||
const entityType = this.data().entityType;
|
const data = Template.currentData();
|
||||||
|
const entityType = data.entityType;
|
||||||
let description = `Original position: ${position.originalPosition.sort || 0}`;
|
let description = `Original position: ${position.originalPosition.sort || 0}`;
|
||||||
|
|
||||||
if (entityType === 'list' && position.originalSwimlaneId) {
|
if (entityType === 'list' && position.originalSwimlaneId) {
|
||||||
|
|
@ -81,18 +81,14 @@ class OriginalPositionComponent extends BlazeComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
return 'No original position data';
|
return 'No original position data';
|
||||||
}
|
},
|
||||||
|
|
||||||
getOriginalTitle() {
|
getOriginalTitle() {
|
||||||
const position = this.getOriginalPosition();
|
const position = Template.instance().originalPosition.get();
|
||||||
return position ? position.originalTitle : '';
|
return position ? position.originalTitle : '';
|
||||||
}
|
},
|
||||||
|
|
||||||
showOriginalPosition() {
|
showOriginalPosition() {
|
||||||
return this.getOriginalPosition() !== null;
|
return Template.instance().originalPosition.get() !== null;
|
||||||
}
|
},
|
||||||
}
|
});
|
||||||
|
|
||||||
OriginalPositionComponent.register('originalPosition');
|
|
||||||
|
|
||||||
export default OriginalPositionComponent;
|
|
||||||
|
|
|
||||||
|
|
@ -1,34 +1,30 @@
|
||||||
BlazeComponent.extendComponent({
|
Template.ganttCard.onCreated(function () {
|
||||||
onCreated() {
|
// Provide the expected parent component properties for cardDetails
|
||||||
// Provide the expected parent component properties for cardDetails
|
this.showOverlay = new ReactiveVar(false);
|
||||||
this.showOverlay = new ReactiveVar(false);
|
this.mouseHasEnterCardDetails = false;
|
||||||
this.mouseHasEnterCardDetails = false;
|
});
|
||||||
},
|
|
||||||
|
|
||||||
|
Template.ganttCard.helpers({
|
||||||
selectedCard() {
|
selectedCard() {
|
||||||
// The selected card is now passed as a parameter to the component
|
// The selected card is now passed as a parameter to the component
|
||||||
return this.currentData();
|
return Template.currentData();
|
||||||
},
|
},
|
||||||
|
});
|
||||||
|
|
||||||
events() {
|
Template.ganttCard.events({
|
||||||
return [
|
'click .js-close-card-details'(event) {
|
||||||
{
|
event.preventDefault();
|
||||||
'click .js-close-card-details'(event) {
|
// Find the ganttView template instance and clear selectedCardId
|
||||||
event.preventDefault();
|
let view = Blaze.currentView;
|
||||||
// Find the ganttView template instance and clear selectedCardId
|
while (view) {
|
||||||
let view = Blaze.currentView;
|
if (view.templateInstance && view.templateInstance().selectedCardId) {
|
||||||
while (view) {
|
view.templateInstance().selectedCardId.set(null);
|
||||||
if (view.templateInstance && view.templateInstance().selectedCardId) {
|
break;
|
||||||
view.templateInstance().selectedCardId.set(null);
|
}
|
||||||
break;
|
view = view.parentView;
|
||||||
}
|
}
|
||||||
view = view.parentView;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
];
|
|
||||||
},
|
},
|
||||||
}).register('ganttCard');
|
});
|
||||||
|
|
||||||
// Add click handler to ganttView for card titles
|
// Add click handler to ganttView for card titles
|
||||||
Template.ganttView.events({
|
Template.ganttView.events({
|
||||||
|
|
|
||||||
|
|
@ -7,36 +7,63 @@ import getSlug from 'limax';
|
||||||
|
|
||||||
const Papa = require('papaparse');
|
const Papa = require('papaparse');
|
||||||
|
|
||||||
BlazeComponent.extendComponent({
|
Template.importHeaderBar.helpers({
|
||||||
title() {
|
title() {
|
||||||
return `import-board-title-${Session.get('importSource')}`;
|
return `import-board-title-${Session.get('importSource')}`;
|
||||||
},
|
},
|
||||||
}).register('importHeaderBar');
|
});
|
||||||
|
|
||||||
BlazeComponent.extendComponent({
|
// Helper to find the closest ancestor template instance by name
|
||||||
onCreated() {
|
function findParentTemplateInstance(childTemplateInstance, parentTemplateName) {
|
||||||
this.error = new ReactiveVar('');
|
let view = childTemplateInstance.view;
|
||||||
this.steps = ['importTextarea', 'importMapMembers'];
|
while (view) {
|
||||||
this._currentStepIndex = new ReactiveVar(0);
|
if (view.name === `Template.${parentTemplateName}` && view.templateInstance) {
|
||||||
this.importedData = new ReactiveVar();
|
return view.templateInstance();
|
||||||
this.membersToMap = new ReactiveVar([]);
|
}
|
||||||
this.importSource = Session.get('importSource');
|
view = view.parentView;
|
||||||
},
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
currentTemplate() {
|
function _prepareAdditionalData(dataObject) {
|
||||||
return this.steps[this._currentStepIndex.get()];
|
const importSource = Session.get('importSource');
|
||||||
},
|
let membersToMap;
|
||||||
|
switch (importSource) {
|
||||||
|
case 'trello':
|
||||||
|
membersToMap = trelloGetMembersToMap(dataObject);
|
||||||
|
break;
|
||||||
|
case 'wekan':
|
||||||
|
membersToMap = wekanGetMembersToMap(dataObject);
|
||||||
|
break;
|
||||||
|
case 'csv':
|
||||||
|
membersToMap = csvGetMembersToMap(dataObject);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return membersToMap;
|
||||||
|
}
|
||||||
|
|
||||||
nextStep() {
|
Template.import.onCreated(function () {
|
||||||
|
this.error = new ReactiveVar('');
|
||||||
|
this.steps = ['importTextarea', 'importMapMembers'];
|
||||||
|
this._currentStepIndex = new ReactiveVar(0);
|
||||||
|
this.importedData = new ReactiveVar();
|
||||||
|
this.membersToMap = new ReactiveVar([]);
|
||||||
|
this.importSource = Session.get('importSource');
|
||||||
|
|
||||||
|
this.nextStep = () => {
|
||||||
const nextStepIndex = this._currentStepIndex.get() + 1;
|
const nextStepIndex = this._currentStepIndex.get() + 1;
|
||||||
if (nextStepIndex >= this.steps.length) {
|
if (nextStepIndex >= this.steps.length) {
|
||||||
this.finishImport();
|
this.finishImport();
|
||||||
} else {
|
} else {
|
||||||
this._currentStepIndex.set(nextStepIndex);
|
this._currentStepIndex.set(nextStepIndex);
|
||||||
}
|
}
|
||||||
},
|
};
|
||||||
|
|
||||||
importData(evt, dataSource) {
|
this.setError = (error) => {
|
||||||
|
this.error.set(error);
|
||||||
|
};
|
||||||
|
|
||||||
|
this.importData = (evt, dataSource) => {
|
||||||
evt.preventDefault();
|
evt.preventDefault();
|
||||||
const input = this.find('.js-import-json').value;
|
const input = this.find('.js-import-json').value;
|
||||||
if (dataSource === 'csv') {
|
if (dataSource === 'csv') {
|
||||||
|
|
@ -44,7 +71,7 @@ BlazeComponent.extendComponent({
|
||||||
const ret = Papa.parse(csv);
|
const ret = Papa.parse(csv);
|
||||||
if (ret && ret.data && ret.data.length) this.importedData.set(ret.data);
|
if (ret && ret.data && ret.data.length) this.importedData.set(ret.data);
|
||||||
else throw new Meteor.Error('error-csv-schema');
|
else throw new Meteor.Error('error-csv-schema');
|
||||||
const membersToMap = this._prepareAdditionalData(ret.data);
|
const membersToMap = _prepareAdditionalData(ret.data);
|
||||||
this.membersToMap.set(membersToMap);
|
this.membersToMap.set(membersToMap);
|
||||||
this.nextStep();
|
this.nextStep();
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -52,7 +79,7 @@ BlazeComponent.extendComponent({
|
||||||
const dataObject = JSON.parse(input);
|
const dataObject = JSON.parse(input);
|
||||||
this.setError('');
|
this.setError('');
|
||||||
this.importedData.set(dataObject);
|
this.importedData.set(dataObject);
|
||||||
const membersToMap = this._prepareAdditionalData(dataObject);
|
const membersToMap = _prepareAdditionalData(dataObject);
|
||||||
// store members data and mapping in Session
|
// store members data and mapping in Session
|
||||||
// (we go deep and 2-way, so storing in data context is not a viable option)
|
// (we go deep and 2-way, so storing in data context is not a viable option)
|
||||||
this.membersToMap.set(membersToMap);
|
this.membersToMap.set(membersToMap);
|
||||||
|
|
@ -61,13 +88,9 @@ BlazeComponent.extendComponent({
|
||||||
this.setError('error-json-malformed');
|
this.setError('error-json-malformed');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
};
|
||||||
|
|
||||||
setError(error) {
|
this.finishImport = () => {
|
||||||
this.error.set(error);
|
|
||||||
},
|
|
||||||
|
|
||||||
finishImport() {
|
|
||||||
const additionalData = {};
|
const additionalData = {};
|
||||||
const membersMapping = this.membersToMap.get();
|
const membersMapping = this.membersToMap.get();
|
||||||
if (membersMapping) {
|
if (membersMapping) {
|
||||||
|
|
@ -95,44 +118,27 @@ BlazeComponent.extendComponent({
|
||||||
FlowRouter.go('board', {
|
FlowRouter.go('board', {
|
||||||
id: res,
|
id: res,
|
||||||
slug: title,
|
slug: title,
|
||||||
})
|
});
|
||||||
//Utils.goBoardId(res);
|
//Utils.goBoardId(res);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
},
|
};
|
||||||
|
});
|
||||||
|
|
||||||
_prepareAdditionalData(dataObject) {
|
Template.import.helpers({
|
||||||
const importSource = Session.get('importSource');
|
error() {
|
||||||
let membersToMap;
|
return Template.instance().error;
|
||||||
switch (importSource) {
|
|
||||||
case 'trello':
|
|
||||||
membersToMap = trelloGetMembersToMap(dataObject);
|
|
||||||
break;
|
|
||||||
case 'wekan':
|
|
||||||
membersToMap = wekanGetMembersToMap(dataObject);
|
|
||||||
break;
|
|
||||||
case 'csv':
|
|
||||||
membersToMap = csvGetMembersToMap(dataObject);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return membersToMap;
|
|
||||||
},
|
},
|
||||||
|
currentTemplate() {
|
||||||
_screenAdditionalData() {
|
return Template.instance().steps[Template.instance()._currentStepIndex.get()];
|
||||||
return 'mapMembers';
|
|
||||||
},
|
|
||||||
}).register('import');
|
|
||||||
|
|
||||||
BlazeComponent.extendComponent({
|
|
||||||
template() {
|
|
||||||
return 'importTextarea';
|
|
||||||
},
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
Template.importTextarea.helpers({
|
||||||
instruction() {
|
instruction() {
|
||||||
return `import-board-instruction-${Session.get('importSource')}`;
|
return `import-board-instruction-${Session.get('importSource')}`;
|
||||||
},
|
},
|
||||||
|
|
||||||
importPlaceHolder() {
|
importPlaceHolder() {
|
||||||
const importSource = Session.get('importSource');
|
const importSource = Session.get('importSource');
|
||||||
if (importSource === 'csv') {
|
if (importSource === 'csv') {
|
||||||
|
|
@ -141,81 +147,37 @@ BlazeComponent.extendComponent({
|
||||||
return 'import-json-placeholder';
|
return 'import-json-placeholder';
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
});
|
||||||
|
|
||||||
events() {
|
Template.importTextarea.events({
|
||||||
return [
|
submit(evt, tpl) {
|
||||||
{
|
const importTpl = findParentTemplateInstance(tpl, 'import');
|
||||||
submit(evt) {
|
if (importTpl) {
|
||||||
return this.parentComponent().importData(
|
return importTpl.importData(evt, Session.get('importSource'));
|
||||||
evt,
|
}
|
||||||
Session.get('importSource'),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
];
|
|
||||||
},
|
},
|
||||||
}).register('importTextarea');
|
});
|
||||||
|
|
||||||
BlazeComponent.extendComponent({
|
// Module-level reference so popup children can access importMapMembers methods
|
||||||
onCreated() {
|
let _importMapMembersTpl = null;
|
||||||
this.usersLoaded = new ReactiveVar(false);
|
|
||||||
|
|
||||||
this.autorun(() => {
|
Template.importMapMembers.onCreated(function () {
|
||||||
const handle = this.subscribe(
|
_importMapMembersTpl = this;
|
||||||
'user-miniprofile',
|
this.usersLoaded = new ReactiveVar(false);
|
||||||
this.members().map(member => {
|
|
||||||
return member.username;
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
Tracker.nonreactive(() => {
|
|
||||||
Tracker.autorun(() => {
|
|
||||||
if (
|
|
||||||
handle.ready() &&
|
|
||||||
!this.usersLoaded.get() &&
|
|
||||||
this.members().length
|
|
||||||
) {
|
|
||||||
this._refreshMembers(
|
|
||||||
this.members().map(member => {
|
|
||||||
if (!member.wekanId) {
|
|
||||||
let user = ReactiveCache.getUser({ username: member.username });
|
|
||||||
if (!user) {
|
|
||||||
user = ReactiveCache.getUser({ importUsernames: member.username });
|
|
||||||
}
|
|
||||||
if (user) {
|
|
||||||
// eslint-disable-next-line no-console
|
|
||||||
// console.log('found username:', user.username);
|
|
||||||
member.wekanId = user._id;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return member;
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
this.usersLoaded.set(handle.ready());
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
members() {
|
this.members = () => {
|
||||||
return this.parentComponent().membersToMap.get();
|
const importTpl = findParentTemplateInstance(this, 'import');
|
||||||
},
|
return importTpl ? importTpl.membersToMap.get() : [];
|
||||||
|
};
|
||||||
|
|
||||||
_refreshMembers(listOfMembers) {
|
this._refreshMembers = (listOfMembers) => {
|
||||||
return this.parentComponent().membersToMap.set(listOfMembers);
|
const importTpl = findParentTemplateInstance(this, 'import');
|
||||||
},
|
if (importTpl) {
|
||||||
|
importTpl.membersToMap.set(listOfMembers);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
this._setPropertyForMember = (property, value, memberId, unset = false) => {
|
||||||
* Will look into the list of members to import for the specified memberId,
|
|
||||||
* then set its property to the supplied value.
|
|
||||||
* If unset is true, it will remove the property from the rest of the list as well.
|
|
||||||
*
|
|
||||||
* use:
|
|
||||||
* - memberId = null to use selected member
|
|
||||||
* - value = null to unset a property
|
|
||||||
* - unset = true to ensure property is only set on 1 member at a time
|
|
||||||
*/
|
|
||||||
_setPropertyForMember(property, value, memberId, unset = false) {
|
|
||||||
const listOfMembers = this.members();
|
const listOfMembers = this.members();
|
||||||
let finder = null;
|
let finder = null;
|
||||||
if (memberId) {
|
if (memberId) {
|
||||||
|
|
@ -241,17 +203,13 @@ BlazeComponent.extendComponent({
|
||||||
});
|
});
|
||||||
// Session.get gives us a copy, we have to set it back so it sticks
|
// Session.get gives us a copy, we have to set it back so it sticks
|
||||||
this._refreshMembers(listOfMembers);
|
this._refreshMembers(listOfMembers);
|
||||||
},
|
};
|
||||||
|
|
||||||
setSelectedMember(memberId) {
|
this.setSelectedMember = (memberId) => {
|
||||||
return this._setPropertyForMember('selected', true, memberId, true);
|
return this._setPropertyForMember('selected', true, memberId, true);
|
||||||
},
|
};
|
||||||
|
|
||||||
/**
|
this.getMember = (memberId = null) => {
|
||||||
* returns the member with specified id,
|
|
||||||
* or the selected member if memberId is not specified
|
|
||||||
*/
|
|
||||||
getMember(memberId = null) {
|
|
||||||
const allMembers = this.members();
|
const allMembers = this.members();
|
||||||
let finder = null;
|
let finder = null;
|
||||||
if (memberId) {
|
if (memberId) {
|
||||||
|
|
@ -260,117 +218,154 @@ BlazeComponent.extendComponent({
|
||||||
finder = user => user.selected;
|
finder = user => user.selected;
|
||||||
}
|
}
|
||||||
return allMembers.find(finder);
|
return allMembers.find(finder);
|
||||||
},
|
};
|
||||||
|
|
||||||
mapSelectedMember(wekanId) {
|
this.mapSelectedMember = (wekanId) => {
|
||||||
return this._setPropertyForMember('wekanId', wekanId, null);
|
return this._setPropertyForMember('wekanId', wekanId, null);
|
||||||
},
|
};
|
||||||
|
|
||||||
unmapMember(memberId) {
|
this.unmapMember = (memberId) => {
|
||||||
return this._setPropertyForMember('wekanId', null, memberId);
|
return this._setPropertyForMember('wekanId', null, memberId);
|
||||||
},
|
};
|
||||||
|
|
||||||
onSubmit(evt) {
|
this.autorun(() => {
|
||||||
|
const handle = this.subscribe(
|
||||||
|
'user-miniprofile',
|
||||||
|
this.members().map(member => {
|
||||||
|
return member.username;
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
Tracker.nonreactive(() => {
|
||||||
|
Tracker.autorun(() => {
|
||||||
|
if (
|
||||||
|
handle.ready() &&
|
||||||
|
!this.usersLoaded.get() &&
|
||||||
|
this.members().length
|
||||||
|
) {
|
||||||
|
this._refreshMembers(
|
||||||
|
this.members().map(member => {
|
||||||
|
if (!member.wekanId) {
|
||||||
|
let user = ReactiveCache.getUser({ username: member.username });
|
||||||
|
if (!user) {
|
||||||
|
user = ReactiveCache.getUser({ importUsernames: member.username });
|
||||||
|
}
|
||||||
|
if (user) {
|
||||||
|
member.wekanId = user._id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return member;
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
this.usersLoaded.set(handle.ready());
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
Template.importMapMembers.onDestroyed(function () {
|
||||||
|
if (_importMapMembersTpl === this) {
|
||||||
|
_importMapMembersTpl = null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Template.importMapMembers.helpers({
|
||||||
|
usersLoaded() {
|
||||||
|
return Template.instance().usersLoaded;
|
||||||
|
},
|
||||||
|
members() {
|
||||||
|
return Template.instance().members();
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
Template.importMapMembers.events({
|
||||||
|
submit(evt, tpl) {
|
||||||
evt.preventDefault();
|
evt.preventDefault();
|
||||||
this.parentComponent().nextStep();
|
const importTpl = findParentTemplateInstance(tpl, 'import');
|
||||||
|
if (importTpl) {
|
||||||
|
importTpl.nextStep();
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
'click .js-select-member'(evt, tpl) {
|
||||||
events() {
|
const memberToMap = Template.currentData();
|
||||||
return [
|
if (memberToMap.wekan) {
|
||||||
{
|
// todo xxx ask for confirmation?
|
||||||
submit: this.onSubmit,
|
tpl.unmapMember(memberToMap.id);
|
||||||
'click .js-select-member'(evt) {
|
} else {
|
||||||
const memberToMap = this.currentData();
|
tpl.setSelectedMember(memberToMap.id);
|
||||||
if (memberToMap.wekan) {
|
Popup.open('importMapMembersAdd')(evt);
|
||||||
// todo xxx ask for confirmation?
|
}
|
||||||
this.unmapMember(memberToMap.id);
|
|
||||||
} else {
|
|
||||||
this.setSelectedMember(memberToMap.id);
|
|
||||||
Popup.open('importMapMembersAdd')(evt);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
];
|
|
||||||
},
|
},
|
||||||
}).register('importMapMembers');
|
});
|
||||||
|
|
||||||
BlazeComponent.extendComponent({
|
|
||||||
onRendered() {
|
|
||||||
this.find('.js-map-member input').focus();
|
|
||||||
},
|
|
||||||
|
|
||||||
onSelectUser() {
|
|
||||||
Popup.getOpenerComponent(5).mapSelectedMember(this.currentData().__originalId);
|
|
||||||
Popup.back();
|
|
||||||
},
|
|
||||||
|
|
||||||
events() {
|
|
||||||
return [
|
|
||||||
{
|
|
||||||
'click .js-select-import': this.onSelectUser,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
},
|
|
||||||
}).register('importMapMembersAddPopup');
|
|
||||||
|
|
||||||
// Global reactive variables for import member popup
|
// Global reactive variables for import member popup
|
||||||
const importMemberPopupState = {
|
const importMemberPopupState = {
|
||||||
searching: new ReactiveVar(false),
|
searching: new ReactiveVar(false),
|
||||||
searchResults: new ReactiveVar([]),
|
searchResults: new ReactiveVar([]),
|
||||||
noResults: new ReactiveVar(false),
|
noResults: new ReactiveVar(false),
|
||||||
searchTimeout: null
|
searchTimeout: null,
|
||||||
};
|
};
|
||||||
|
|
||||||
BlazeComponent.extendComponent({
|
Template.importMapMembersAddPopup.onCreated(function () {
|
||||||
onCreated() {
|
this.searching = importMemberPopupState.searching;
|
||||||
// Use global state
|
this.searchResults = importMemberPopupState.searchResults;
|
||||||
this.searching = importMemberPopupState.searching;
|
this.noResults = importMemberPopupState.noResults;
|
||||||
this.searchResults = importMemberPopupState.searchResults;
|
this.searchTimeout = null;
|
||||||
this.noResults = importMemberPopupState.noResults;
|
|
||||||
this.searchTimeout = importMemberPopupState.searchTimeout;
|
|
||||||
},
|
|
||||||
|
|
||||||
onRendered() {
|
this.searching.set(false);
|
||||||
this.find('.js-search-member-input').focus();
|
this.searchResults.set([]);
|
||||||
},
|
this.noResults.set(false);
|
||||||
|
});
|
||||||
|
|
||||||
performSearch(query) {
|
Template.importMapMembersAddPopup.onRendered(function () {
|
||||||
if (!query || query.length < 2) {
|
this.find('.js-search-member-input').focus();
|
||||||
this.searchResults.set([]);
|
});
|
||||||
this.noResults.set(false);
|
|
||||||
return;
|
Template.importMapMembersAddPopup.onDestroyed(function () {
|
||||||
|
if (this.searchTimeout) {
|
||||||
|
clearTimeout(this.searchTimeout);
|
||||||
|
}
|
||||||
|
this.searching.set(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
function importPerformSearch(tpl, query) {
|
||||||
|
if (!query || query.length < 2) {
|
||||||
|
tpl.searchResults.set([]);
|
||||||
|
tpl.noResults.set(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
tpl.searching.set(true);
|
||||||
|
tpl.noResults.set(false);
|
||||||
|
|
||||||
|
const results = UserSearchIndex.search(query, { limit: 20 }).fetch();
|
||||||
|
tpl.searchResults.set(results);
|
||||||
|
tpl.searching.set(false);
|
||||||
|
|
||||||
|
if (results.length === 0) {
|
||||||
|
tpl.noResults.set(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Template.importMapMembersAddPopup.events({
|
||||||
|
'click .js-select-import'(event, tpl) {
|
||||||
|
if (_importMapMembersTpl) {
|
||||||
|
_importMapMembersTpl.mapSelectedMember(Template.currentData().__originalId);
|
||||||
|
}
|
||||||
|
Popup.back();
|
||||||
|
},
|
||||||
|
'keyup .js-search-member-input'(event, tpl) {
|
||||||
|
const query = event.target.value.trim();
|
||||||
|
|
||||||
|
if (tpl.searchTimeout) {
|
||||||
|
clearTimeout(tpl.searchTimeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.searching.set(true);
|
tpl.searchTimeout = setTimeout(() => {
|
||||||
this.noResults.set(false);
|
importPerformSearch(tpl, query);
|
||||||
|
}, 300);
|
||||||
const results = UserSearchIndex.search(query, { limit: 20 }).fetch();
|
|
||||||
this.searchResults.set(results);
|
|
||||||
this.searching.set(false);
|
|
||||||
|
|
||||||
if (results.length === 0) {
|
|
||||||
this.noResults.set(true);
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
});
|
||||||
events() {
|
|
||||||
return [
|
|
||||||
{
|
|
||||||
'keyup .js-search-member-input'(event) {
|
|
||||||
const query = event.target.value.trim();
|
|
||||||
|
|
||||||
if (this.searchTimeout) {
|
|
||||||
clearTimeout(this.searchTimeout);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.searchTimeout = setTimeout(() => {
|
|
||||||
this.performSearch(query);
|
|
||||||
}, 300);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
];
|
|
||||||
},
|
|
||||||
}).register('importMapMembersAddPopupSearch');
|
|
||||||
|
|
||||||
Template.importMapMembersAddPopup.helpers({
|
Template.importMapMembersAddPopup.helpers({
|
||||||
searchResults() {
|
searchResults() {
|
||||||
|
|
@ -381,5 +376,5 @@ Template.importMapMembersAddPopup.helpers({
|
||||||
},
|
},
|
||||||
noResults() {
|
noResults() {
|
||||||
return importMemberPopupState.noResults;
|
return importMemberPopupState.noResults;
|
||||||
}
|
},
|
||||||
})
|
});
|
||||||
|
|
|
||||||
|
|
@ -18,21 +18,19 @@ const accessibilityHelpers = {
|
||||||
};
|
};
|
||||||
|
|
||||||
// Main accessibility page component
|
// Main accessibility page component
|
||||||
BlazeComponent.extendComponent({
|
Template.accessibility.onCreated(function () {
|
||||||
onCreated() {
|
this.error = new ReactiveVar('');
|
||||||
this.error = new ReactiveVar('');
|
this.loading = new ReactiveVar(false);
|
||||||
this.loading = new ReactiveVar(false);
|
|
||||||
|
|
||||||
Meteor.subscribe('setting');
|
Meteor.subscribe('setting');
|
||||||
Meteor.subscribe('accessibilitySettings');
|
Meteor.subscribe('accessibilitySettings');
|
||||||
},
|
});
|
||||||
...accessibilityHelpers
|
|
||||||
}).register('accessibility');
|
Template.accessibility.helpers(accessibilityHelpers);
|
||||||
|
|
||||||
// Header bar component
|
// Header bar component
|
||||||
BlazeComponent.extendComponent({
|
Template.accessibilityHeaderBar.onCreated(function () {
|
||||||
onCreated() {
|
Meteor.subscribe('accessibilitySettings');
|
||||||
Meteor.subscribe('accessibilitySettings');
|
});
|
||||||
},
|
|
||||||
...accessibilityHelpers
|
Template.accessibilityHeaderBar.helpers(accessibilityHelpers);
|
||||||
}).register('accessibilityHeaderBar');
|
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,57 @@
|
||||||
import { CardSearchPagedComponent } from '../../lib/cardSearch';
|
import { CardSearchPaged } from '../../lib/cardSearch';
|
||||||
|
|
||||||
BlazeComponent.extendComponent({}).register('brokenCardsHeaderBar');
|
Template.brokenCards.onCreated(function () {
|
||||||
|
const search = new CardSearchPaged(this);
|
||||||
|
this.search = search;
|
||||||
|
|
||||||
|
Meteor.subscribe('brokenCards', search.sessionId);
|
||||||
|
});
|
||||||
|
|
||||||
Template.brokenCards.helpers({
|
Template.brokenCards.helpers({
|
||||||
userId() {
|
userId() {
|
||||||
return Meteor.userId();
|
return Meteor.userId();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// Return ReactiveVars so jade can use .get pattern
|
||||||
|
searching() {
|
||||||
|
return Template.instance().search.searching;
|
||||||
|
},
|
||||||
|
hasResults() {
|
||||||
|
return Template.instance().search.hasResults;
|
||||||
|
},
|
||||||
|
hasQueryErrors() {
|
||||||
|
return Template.instance().search.hasQueryErrors;
|
||||||
|
},
|
||||||
|
errorMessages() {
|
||||||
|
return Template.instance().search.queryErrorMessages();
|
||||||
|
},
|
||||||
|
resultsCount() {
|
||||||
|
return Template.instance().search.resultsCount;
|
||||||
|
},
|
||||||
|
resultsHeading() {
|
||||||
|
return Template.instance().search.resultsHeading;
|
||||||
|
},
|
||||||
|
results() {
|
||||||
|
return Template.instance().search.results;
|
||||||
|
},
|
||||||
|
getSearchHref() {
|
||||||
|
return Template.instance().search.getSearchHref();
|
||||||
|
},
|
||||||
|
hasPreviousPage() {
|
||||||
|
return Template.instance().search.hasPreviousPage;
|
||||||
|
},
|
||||||
|
hasNextPage() {
|
||||||
|
return Template.instance().search.hasNextPage;
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
class BrokenCardsComponent extends CardSearchPagedComponent {
|
Template.brokenCards.events({
|
||||||
onCreated() {
|
'click .js-next-page'(evt, tpl) {
|
||||||
super.onCreated();
|
evt.preventDefault();
|
||||||
|
tpl.search.nextPage();
|
||||||
Meteor.subscribe('brokenCards', this.sessionId);
|
},
|
||||||
}
|
'click .js-previous-page'(evt, tpl) {
|
||||||
}
|
evt.preventDefault();
|
||||||
BrokenCardsComponent.register('brokenCards');
|
tpl.search.previousPage();
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,178 +1,37 @@
|
||||||
import { ReactiveCache } from '/imports/reactiveCache';
|
import { ReactiveCache } from '/imports/reactiveCache';
|
||||||
import { BlazeComponent } from 'meteor/peerlibrary:blaze-components';
|
|
||||||
import { TAPi18n } from '/imports/i18n';
|
import { TAPi18n } from '/imports/i18n';
|
||||||
|
|
||||||
// const subManager = new SubsManager();
|
// const subManager = new SubsManager();
|
||||||
|
|
||||||
BlazeComponent.extendComponent({
|
Template.dueCardsHeaderBar.helpers({
|
||||||
dueCardsView() {
|
dueCardsView() {
|
||||||
// eslint-disable-next-line no-console
|
// eslint-disable-next-line no-console
|
||||||
// console.log('sort:', Utils.dueCardsView());
|
// console.log('sort:', Utils.dueCardsView());
|
||||||
return Utils && Utils.dueCardsView ? Utils.dueCardsView() : 'me';
|
return Utils && Utils.dueCardsView ? Utils.dueCardsView() : 'me';
|
||||||
},
|
},
|
||||||
|
|
||||||
events() {
|
|
||||||
return [
|
|
||||||
{
|
|
||||||
'click .js-due-cards-view-change': Popup.open('dueCardsViewChange'),
|
|
||||||
},
|
|
||||||
];
|
|
||||||
},
|
|
||||||
}).register('dueCardsHeaderBar');
|
|
||||||
|
|
||||||
Template.dueCards.helpers({
|
|
||||||
userId() {
|
|
||||||
return Meteor.userId();
|
|
||||||
},
|
|
||||||
dueCardsList() {
|
|
||||||
const component = BlazeComponent.getComponentForElement(this.firstNode);
|
|
||||||
if (component && component.dueCardsList) {
|
|
||||||
return component.dueCardsList();
|
|
||||||
}
|
|
||||||
return [];
|
|
||||||
},
|
|
||||||
hasResults() {
|
|
||||||
const component = BlazeComponent.getComponentForElement(this.firstNode);
|
|
||||||
if (component && component.hasResults) {
|
|
||||||
return component.hasResults.get();
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
},
|
|
||||||
searching() {
|
|
||||||
const component = BlazeComponent.getComponentForElement(this.firstNode);
|
|
||||||
if (component && component.isLoading) {
|
|
||||||
return component.isLoading.get();
|
|
||||||
}
|
|
||||||
return true; // Show loading by default
|
|
||||||
},
|
|
||||||
hasQueryErrors() {
|
|
||||||
return false; // No longer using search, so always false
|
|
||||||
},
|
|
||||||
errorMessages() {
|
|
||||||
return []; // No longer using search, so always empty
|
|
||||||
},
|
|
||||||
cardsCount() {
|
|
||||||
const component = BlazeComponent.getComponentForElement(this.firstNode);
|
|
||||||
if (component && component.cardsCount) {
|
|
||||||
return component.cardsCount();
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
},
|
|
||||||
resultsText() {
|
|
||||||
const component = BlazeComponent.getComponentForElement(this.firstNode);
|
|
||||||
if (component && component.resultsText) {
|
|
||||||
return component.resultsText();
|
|
||||||
}
|
|
||||||
return '';
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
BlazeComponent.extendComponent({
|
Template.dueCardsHeaderBar.events({
|
||||||
events() {
|
'click .js-due-cards-view-change': Popup.open('dueCardsViewChange'),
|
||||||
return [
|
});
|
||||||
{
|
|
||||||
'click .js-due-cards-view-me'() {
|
|
||||||
if (Utils && Utils.setDueCardsView) {
|
|
||||||
Utils.setDueCardsView('me');
|
|
||||||
}
|
|
||||||
Popup.back();
|
|
||||||
},
|
|
||||||
|
|
||||||
'click .js-due-cards-view-all'() {
|
Template.dueCards.onCreated(function () {
|
||||||
if (Utils && Utils.setDueCardsView) {
|
this._cachedCards = null;
|
||||||
Utils.setDueCardsView('all');
|
this._cachedTimestamp = null;
|
||||||
}
|
this.subscriptionHandle = null;
|
||||||
Popup.back();
|
this.isLoading = new ReactiveVar(true);
|
||||||
},
|
this.hasResults = new ReactiveVar(false);
|
||||||
},
|
this.searching = new ReactiveVar(false);
|
||||||
];
|
|
||||||
},
|
|
||||||
}).register('dueCardsViewChangePopup');
|
|
||||||
|
|
||||||
class DueCardsComponent extends BlazeComponent {
|
const tpl = this;
|
||||||
onCreated() {
|
|
||||||
super.onCreated();
|
|
||||||
|
|
||||||
this._cachedCards = null;
|
function dueCardsView() {
|
||||||
this._cachedTimestamp = null;
|
|
||||||
this.subscriptionHandle = null;
|
|
||||||
this.isLoading = new ReactiveVar(true);
|
|
||||||
this.hasResults = new ReactiveVar(false);
|
|
||||||
this.searching = new ReactiveVar(false);
|
|
||||||
|
|
||||||
// Subscribe to the optimized due cards publication
|
|
||||||
this.autorun(() => {
|
|
||||||
const allUsers = this.dueCardsView() === 'all';
|
|
||||||
if (this.subscriptionHandle) {
|
|
||||||
this.subscriptionHandle.stop();
|
|
||||||
}
|
|
||||||
this.subscriptionHandle = Meteor.subscribe('dueCards', allUsers);
|
|
||||||
|
|
||||||
// Update loading state based on subscription
|
|
||||||
this.autorun(() => {
|
|
||||||
if (this.subscriptionHandle && this.subscriptionHandle.ready()) {
|
|
||||||
if (process.env.DEBUG === 'true') {
|
|
||||||
console.log('dueCards: subscription ready, loading data...');
|
|
||||||
}
|
|
||||||
this.isLoading.set(false);
|
|
||||||
const cards = this.dueCardsList();
|
|
||||||
this.hasResults.set(cards && cards.length > 0);
|
|
||||||
} else {
|
|
||||||
if (process.env.DEBUG === 'true') {
|
|
||||||
console.log('dueCards: subscription not ready, showing loading...');
|
|
||||||
}
|
|
||||||
this.isLoading.set(true);
|
|
||||||
this.hasResults.set(false);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
onDestroyed() {
|
|
||||||
super.onDestroyed();
|
|
||||||
if (this.subscriptionHandle) {
|
|
||||||
this.subscriptionHandle.stop();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
dueCardsView() {
|
|
||||||
// eslint-disable-next-line no-console
|
|
||||||
//console.log('sort:', Utils.dueCardsView());
|
|
||||||
return Utils && Utils.dueCardsView ? Utils.dueCardsView() : 'me';
|
return Utils && Utils.dueCardsView ? Utils.dueCardsView() : 'me';
|
||||||
}
|
}
|
||||||
|
|
||||||
sortByBoard() {
|
function dueCardsList() {
|
||||||
return this.dueCardsView() === 'board';
|
|
||||||
}
|
|
||||||
|
|
||||||
hasResults() {
|
|
||||||
return this.hasResults.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
cardsCount() {
|
|
||||||
const cards = this.dueCardsList();
|
|
||||||
return cards ? cards.length : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
resultsText() {
|
|
||||||
const count = this.cardsCount();
|
|
||||||
if (count === 1) {
|
|
||||||
return TAPi18n.__('one-card-found');
|
|
||||||
} else {
|
|
||||||
// Get the translated text and manually replace %s with the count
|
|
||||||
const baseText = TAPi18n.__('n-cards-found');
|
|
||||||
const result = baseText.replace('%s', count);
|
|
||||||
|
|
||||||
if (process.env.DEBUG === 'true') {
|
|
||||||
console.log('dueCards: base text:', baseText, 'count:', count, 'result:', result);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
dueCardsList() {
|
|
||||||
// Check if subscription is ready
|
// Check if subscription is ready
|
||||||
if (!this.subscriptionHandle || !this.subscriptionHandle.ready()) {
|
if (!tpl.subscriptionHandle || !tpl.subscriptionHandle.ready()) {
|
||||||
if (process.env.DEBUG === 'true') {
|
if (process.env.DEBUG === 'true') {
|
||||||
console.log('dueCards client: subscription not ready');
|
console.log('dueCards client: subscription not ready');
|
||||||
}
|
}
|
||||||
|
|
@ -180,11 +39,11 @@ class DueCardsComponent extends BlazeComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use cached results if available to avoid expensive re-sorting
|
// Use cached results if available to avoid expensive re-sorting
|
||||||
if (this._cachedCards && this._cachedTimestamp && (Date.now() - this._cachedTimestamp < 5000)) {
|
if (tpl._cachedCards && tpl._cachedTimestamp && (Date.now() - tpl._cachedTimestamp < 5000)) {
|
||||||
if (process.env.DEBUG === 'true') {
|
if (process.env.DEBUG === 'true') {
|
||||||
console.log('dueCards client: using cached results,', this._cachedCards.length, 'cards');
|
console.log('dueCards client: using cached results,', tpl._cachedCards.length, 'cards');
|
||||||
}
|
}
|
||||||
return this._cachedCards;
|
return tpl._cachedCards;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get cards directly from the subscription (already sorted by the publication)
|
// Get cards directly from the subscription (already sorted by the publication)
|
||||||
|
|
@ -208,7 +67,7 @@ class DueCardsComponent extends BlazeComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Filter cards based on user view preference
|
// Filter cards based on user view preference
|
||||||
const allUsers = this.dueCardsView() === 'all';
|
const allUsers = dueCardsView() === 'all';
|
||||||
const currentUser = ReactiveCache.getCurrentUser();
|
const currentUser = ReactiveCache.getCurrentUser();
|
||||||
let filteredCards = cards;
|
let filteredCards = cards;
|
||||||
|
|
||||||
|
|
@ -255,15 +114,106 @@ class DueCardsComponent extends BlazeComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cache the results for 5 seconds to avoid re-filtering on every render
|
// Cache the results for 5 seconds to avoid re-filtering on every render
|
||||||
this._cachedCards = filteredCards;
|
tpl._cachedCards = filteredCards;
|
||||||
this._cachedTimestamp = Date.now();
|
tpl._cachedTimestamp = Date.now();
|
||||||
|
|
||||||
// Update reactive variables
|
// Update reactive variables
|
||||||
this.hasResults.set(filteredCards && filteredCards.length > 0);
|
tpl.hasResults.set(filteredCards && filteredCards.length > 0);
|
||||||
this.isLoading.set(false);
|
tpl.isLoading.set(false);
|
||||||
|
|
||||||
return filteredCards;
|
return filteredCards;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
DueCardsComponent.register('dueCards');
|
// Store dueCardsList on the instance so helpers can call it
|
||||||
|
this.dueCardsList = dueCardsList;
|
||||||
|
this.dueCardsView = dueCardsView;
|
||||||
|
|
||||||
|
// Subscribe to the optimized due cards publication
|
||||||
|
this.autorun(() => {
|
||||||
|
const allUsers = dueCardsView() === 'all';
|
||||||
|
if (tpl.subscriptionHandle) {
|
||||||
|
tpl.subscriptionHandle.stop();
|
||||||
|
}
|
||||||
|
tpl.subscriptionHandle = Meteor.subscribe('dueCards', allUsers);
|
||||||
|
|
||||||
|
// Update loading state based on subscription
|
||||||
|
tpl.autorun(() => {
|
||||||
|
if (tpl.subscriptionHandle && tpl.subscriptionHandle.ready()) {
|
||||||
|
if (process.env.DEBUG === 'true') {
|
||||||
|
console.log('dueCards: subscription ready, loading data...');
|
||||||
|
}
|
||||||
|
tpl.isLoading.set(false);
|
||||||
|
const cards = dueCardsList();
|
||||||
|
tpl.hasResults.set(cards && cards.length > 0);
|
||||||
|
} else {
|
||||||
|
if (process.env.DEBUG === 'true') {
|
||||||
|
console.log('dueCards: subscription not ready, showing loading...');
|
||||||
|
}
|
||||||
|
tpl.isLoading.set(true);
|
||||||
|
tpl.hasResults.set(false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
Template.dueCards.onDestroyed(function () {
|
||||||
|
if (this.subscriptionHandle) {
|
||||||
|
this.subscriptionHandle.stop();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Template.dueCards.helpers({
|
||||||
|
userId() {
|
||||||
|
return Meteor.userId();
|
||||||
|
},
|
||||||
|
// Return ReactiveVar so jade can use .get pattern
|
||||||
|
searching() {
|
||||||
|
return Template.instance().isLoading;
|
||||||
|
},
|
||||||
|
hasResults() {
|
||||||
|
return Template.instance().hasResults;
|
||||||
|
},
|
||||||
|
hasQueryErrors() {
|
||||||
|
return new ReactiveVar(false);
|
||||||
|
},
|
||||||
|
errorMessages() {
|
||||||
|
return [];
|
||||||
|
},
|
||||||
|
dueCardsList() {
|
||||||
|
const tpl = Template.instance();
|
||||||
|
return tpl.dueCardsList ? tpl.dueCardsList() : [];
|
||||||
|
},
|
||||||
|
resultsText() {
|
||||||
|
const tpl = Template.instance();
|
||||||
|
const cards = tpl.dueCardsList ? tpl.dueCardsList() : [];
|
||||||
|
const count = cards ? cards.length : 0;
|
||||||
|
if (count === 1) {
|
||||||
|
return TAPi18n.__('one-card-found');
|
||||||
|
} else {
|
||||||
|
// Get the translated text and manually replace %s with the count
|
||||||
|
const baseText = TAPi18n.__('n-cards-found');
|
||||||
|
const result = baseText.replace('%s', count);
|
||||||
|
|
||||||
|
if (process.env.DEBUG === 'true') {
|
||||||
|
console.log('dueCards: base text:', baseText, 'count:', count, 'result:', result);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
Template.dueCardsViewChangePopup.events({
|
||||||
|
'click .js-due-cards-view-me'() {
|
||||||
|
if (Utils && Utils.setDueCardsView) {
|
||||||
|
Utils.setDueCardsView('me');
|
||||||
|
}
|
||||||
|
Popup.back();
|
||||||
|
},
|
||||||
|
|
||||||
|
'click .js-due-cards-view-all'() {
|
||||||
|
if (Utils && Utils.setDueCardsView) {
|
||||||
|
Utils.setDueCardsView('all');
|
||||||
|
}
|
||||||
|
Popup.back();
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
|
||||||
|
|
@ -19,8 +19,8 @@ const boardSpecialHandles = [
|
||||||
const specialHandleNames = specialHandles.map(m => m.username);
|
const specialHandleNames = specialHandles.map(m => m.username);
|
||||||
|
|
||||||
|
|
||||||
BlazeComponent.extendComponent({
|
Template.editor.onRendered(function () {
|
||||||
onRendered() {
|
const tpl = this;
|
||||||
// Start: Copy <pre> code https://github.com/wekan/wekan/issues/5149
|
// Start: Copy <pre> code https://github.com/wekan/wekan/issues/5149
|
||||||
// TODO: Try to make copyPre visible at Card Details after editing or closing editor or Card Details.
|
// TODO: Try to make copyPre visible at Card Details after editing or closing editor or Card Details.
|
||||||
// - Also this same TODO below at event, if someone gets it working.
|
// - Also this same TODO below at event, if someone gets it working.
|
||||||
|
|
@ -89,7 +89,7 @@ BlazeComponent.extendComponent({
|
||||||
];
|
];
|
||||||
|
|
||||||
const enableTextarea = function() {
|
const enableTextarea = function() {
|
||||||
const $textarea = this.$(textareaSelector);
|
const $textarea = tpl.$(textareaSelector);
|
||||||
autosize($textarea);
|
autosize($textarea);
|
||||||
$textarea.escapeableTextComplete(mentions);
|
$textarea.escapeableTextComplete(mentions);
|
||||||
};
|
};
|
||||||
|
|
@ -314,29 +314,25 @@ BlazeComponent.extendComponent({
|
||||||
enableTextarea();
|
enableTextarea();
|
||||||
}
|
}
|
||||||
enableTextarea();
|
enableTextarea();
|
||||||
},
|
});
|
||||||
events() {
|
|
||||||
return [
|
|
||||||
{
|
|
||||||
'click a.fa.fa-copy'(event) {
|
|
||||||
const $editor = this.$('textarea.editor');
|
|
||||||
const promise = Utils.copyTextToClipboard($editor[0].value);
|
|
||||||
|
|
||||||
const $tooltip = this.$('.copied-tooltip');
|
Template.editor.events({
|
||||||
Utils.showCopied(promise, $tooltip);
|
'click a.fa.fa-copy'(event, tpl) {
|
||||||
},
|
const $editor = tpl.$('textarea.editor');
|
||||||
'click a.fa.fa-brands.fa-markdown'(event) {
|
const promise = Utils.copyTextToClipboard($editor[0].value);
|
||||||
const $editor = this.$('textarea.editor');
|
|
||||||
$editor[0].value = converter.convert($editor[0].value);
|
const $tooltip = tpl.$('.copied-tooltip');
|
||||||
},
|
Utils.showCopied(promise, $tooltip);
|
||||||
// TODO: Try to make copyPre visible at Card Details after editing or closing editor or Card Details.
|
},
|
||||||
//'click .js-close-inlined-form'(event) {
|
'click a.fa.fa-brands.fa-markdown'(event, tpl) {
|
||||||
// Utils.copyPre();
|
const $editor = tpl.$('textarea.editor');
|
||||||
//},
|
$editor[0].value = converter.convert($editor[0].value);
|
||||||
}
|
},
|
||||||
]
|
// TODO: Try to make copyPre visible at Card Details after editing or closing editor or Card Details.
|
||||||
}
|
//'click .js-close-inlined-form'(event) {
|
||||||
}).register('editor');
|
// Utils.copyPre();
|
||||||
|
//},
|
||||||
|
});
|
||||||
|
|
||||||
import DOMPurify from 'dompurify';
|
import DOMPurify from 'dompurify';
|
||||||
import { sanitizeHTML } from '/imports/lib/secureDOMPurify';
|
import { sanitizeHTML } from '/imports/lib/secureDOMPurify';
|
||||||
|
|
|
||||||
|
|
@ -1,114 +1,154 @@
|
||||||
import { TAPi18n } from '/imports/i18n';
|
import { TAPi18n } from '/imports/i18n';
|
||||||
import { CardSearchPagedComponent } from '../../lib/cardSearch';
|
import { CardSearchPaged } from '../../lib/cardSearch';
|
||||||
import Boards from '../../../models/boards';
|
import Boards from '../../../models/boards';
|
||||||
import { Query, QueryErrors } from '../../../config/query-classes';
|
import { Query, QueryErrors } from '../../../config/query-classes';
|
||||||
|
|
||||||
// const subManager = new SubsManager();
|
// const subManager = new SubsManager();
|
||||||
|
|
||||||
BlazeComponent.extendComponent({
|
Template.globalSearchHeaderBar.events({
|
||||||
events() {
|
'click .js-due-cards-view-change': Popup.open('globalSearchViewChange'),
|
||||||
return [
|
});
|
||||||
{
|
|
||||||
'click .js-due-cards-view-change': Popup.open('globalSearchViewChange'),
|
Template.globalSearch.onCreated(function () {
|
||||||
},
|
const search = new CardSearchPaged(this);
|
||||||
];
|
this.search = search;
|
||||||
},
|
|
||||||
}).register('globalSearchHeaderBar');
|
this.myLists = new ReactiveVar([]);
|
||||||
|
this.myLabelNames = new ReactiveVar([]);
|
||||||
|
this.myBoardNames = new ReactiveVar([]);
|
||||||
|
this.parsingErrors = new QueryErrors();
|
||||||
|
this.queryParams = null;
|
||||||
|
|
||||||
|
Meteor.call('myLists', (err, data) => {
|
||||||
|
if (!err) {
|
||||||
|
this.myLists.set(data);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Meteor.call('myLabelNames', (err, data) => {
|
||||||
|
if (!err) {
|
||||||
|
this.myLabelNames.set(data);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Meteor.call('myBoardNames', (err, data) => {
|
||||||
|
if (!err) {
|
||||||
|
this.myBoardNames.set(data);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
Template.globalSearch.onRendered(function () {
|
||||||
|
Meteor.subscribe('setting');
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
|
//console.log('lang:', TAPi18n.getLanguage());
|
||||||
|
|
||||||
|
if (Session.get('globalQuery')) {
|
||||||
|
searchAllBoards(this, Session.get('globalQuery'));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
function searchAllBoards(tpl, queryText) {
|
||||||
|
const search = tpl.search;
|
||||||
|
|
||||||
|
queryText = queryText.trim();
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
|
//console.log('queryText:', queryText);
|
||||||
|
|
||||||
|
search.query.set(queryText);
|
||||||
|
|
||||||
|
search.resetSearch();
|
||||||
|
tpl.parsingErrors = new QueryErrors();
|
||||||
|
|
||||||
|
if (!queryText) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
search.searching.set(true);
|
||||||
|
|
||||||
|
const query = new Query();
|
||||||
|
query.buildParams(queryText);
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
|
// console.log('params:', query.getParams());
|
||||||
|
|
||||||
|
tpl.queryParams = query.getQueryParams().getParams();
|
||||||
|
|
||||||
|
if (query.hasErrors()) {
|
||||||
|
search.searching.set(false);
|
||||||
|
search.queryErrors = query.errors();
|
||||||
|
search.hasResults.set(true);
|
||||||
|
search.hasQueryErrors.set(true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
search.runGlobalSearch(query.getQueryParams());
|
||||||
|
}
|
||||||
|
|
||||||
|
function errorMessages(tpl) {
|
||||||
|
if (tpl.parsingErrors.hasErrors()) {
|
||||||
|
return tpl.parsingErrors.errorMessages();
|
||||||
|
}
|
||||||
|
return tpl.search.queryErrorMessages();
|
||||||
|
}
|
||||||
|
|
||||||
Template.globalSearch.helpers({
|
Template.globalSearch.helpers({
|
||||||
userId() {
|
userId() {
|
||||||
return Meteor.userId();
|
return Meteor.userId();
|
||||||
},
|
},
|
||||||
});
|
|
||||||
|
|
||||||
class GlobalSearchComponent extends CardSearchPagedComponent {
|
// Return ReactiveVars so jade can use .get pattern
|
||||||
onCreated() {
|
searching() {
|
||||||
super.onCreated();
|
return Template.instance().search.searching;
|
||||||
this.myLists = new ReactiveVar([]);
|
},
|
||||||
this.myLabelNames = new ReactiveVar([]);
|
hasResults() {
|
||||||
this.myBoardNames = new ReactiveVar([]);
|
return Template.instance().search.hasResults;
|
||||||
this.parsingErrors = new QueryErrors();
|
},
|
||||||
this.queryParams = null;
|
hasQueryErrors() {
|
||||||
|
return Template.instance().search.hasQueryErrors;
|
||||||
|
},
|
||||||
|
serverError() {
|
||||||
|
return Template.instance().search.serverError;
|
||||||
|
},
|
||||||
|
query() {
|
||||||
|
return Template.instance().search.query;
|
||||||
|
},
|
||||||
|
debug() {
|
||||||
|
return Template.instance().search.debug;
|
||||||
|
},
|
||||||
|
resultsHeading() {
|
||||||
|
return Template.instance().search.resultsHeading;
|
||||||
|
},
|
||||||
|
results() {
|
||||||
|
return Template.instance().search.results;
|
||||||
|
},
|
||||||
|
hasNextPage() {
|
||||||
|
return Template.instance().search.hasNextPage;
|
||||||
|
},
|
||||||
|
hasPreviousPage() {
|
||||||
|
return Template.instance().search.hasPreviousPage;
|
||||||
|
},
|
||||||
|
sessionData() {
|
||||||
|
return Template.instance().search.sessionData;
|
||||||
|
},
|
||||||
|
getSearchHref() {
|
||||||
|
return Template.instance().search.getSearchHref();
|
||||||
|
},
|
||||||
|
|
||||||
Meteor.call('myLists', (err, data) => {
|
myLists() {
|
||||||
if (!err) {
|
return Template.instance().myLists;
|
||||||
this.myLists.set(data);
|
},
|
||||||
}
|
myLabelNames() {
|
||||||
});
|
return Template.instance().myLabelNames;
|
||||||
|
},
|
||||||
Meteor.call('myLabelNames', (err, data) => {
|
myBoardNames() {
|
||||||
if (!err) {
|
return Template.instance().myBoardNames;
|
||||||
this.myLabelNames.set(data);
|
},
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
Meteor.call('myBoardNames', (err, data) => {
|
|
||||||
if (!err) {
|
|
||||||
this.myBoardNames.set(data);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
onRendered() {
|
|
||||||
Meteor.subscribe('setting');
|
|
||||||
|
|
||||||
// eslint-disable-next-line no-console
|
|
||||||
//console.log('lang:', TAPi18n.getLanguage());
|
|
||||||
|
|
||||||
if (Session.get('globalQuery')) {
|
|
||||||
this.searchAllBoards(Session.get('globalQuery'));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
resetSearch() {
|
|
||||||
super.resetSearch();
|
|
||||||
this.parsingErrors = new QueryErrors();
|
|
||||||
}
|
|
||||||
|
|
||||||
errorMessages() {
|
errorMessages() {
|
||||||
if (this.parsingErrors.hasErrors()) {
|
return errorMessages(Template.instance());
|
||||||
return this.parsingErrors.errorMessages();
|
},
|
||||||
}
|
|
||||||
return this.queryErrorMessages();
|
|
||||||
}
|
|
||||||
|
|
||||||
parsingErrorMessages() {
|
|
||||||
this.parsingErrors.errorMessages();
|
|
||||||
}
|
|
||||||
|
|
||||||
searchAllBoards(queryText) {
|
|
||||||
queryText = queryText.trim();
|
|
||||||
// eslint-disable-next-line no-console
|
|
||||||
//console.log('queryText:', queryText);
|
|
||||||
|
|
||||||
this.query.set(queryText);
|
|
||||||
|
|
||||||
this.resetSearch();
|
|
||||||
|
|
||||||
if (!queryText) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.searching.set(true);
|
|
||||||
|
|
||||||
const query = new Query();
|
|
||||||
query.buildParams(queryText);
|
|
||||||
|
|
||||||
// eslint-disable-next-line no-console
|
|
||||||
// console.log('params:', query.getParams());
|
|
||||||
|
|
||||||
this.queryParams = query.getQueryParams().getParams();
|
|
||||||
|
|
||||||
if (query.hasErrors()) {
|
|
||||||
this.searching.set(false);
|
|
||||||
this.queryErrors = query.errors();
|
|
||||||
this.hasResults.set(true);
|
|
||||||
this.hasQueryErrors.set(true);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.runGlobalSearch(query.getQueryParams());
|
|
||||||
}
|
|
||||||
|
|
||||||
searchInstructions() {
|
searchInstructions() {
|
||||||
const tags = {
|
const tags = {
|
||||||
|
|
@ -203,7 +243,7 @@ class GlobalSearchComponent extends CardSearchPagedComponent {
|
||||||
.replace(/\>\*/, '\>\`')
|
.replace(/\>\*/, '\>\`')
|
||||||
});
|
});
|
||||||
return text;
|
return text;
|
||||||
}
|
},
|
||||||
|
|
||||||
labelColors() {
|
labelColors() {
|
||||||
return Boards.simpleSchema()._schema['labels.$.color'].allowedValues.map(
|
return Boards.simpleSchema()._schema['labels.$.color'].allowedValues.map(
|
||||||
|
|
@ -211,89 +251,163 @@ class GlobalSearchComponent extends CardSearchPagedComponent {
|
||||||
return { color, name: TAPi18n.__(`color-${color}`) };
|
return { color, name: TAPi18n.__(`color-${color}`) };
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
},
|
||||||
|
});
|
||||||
|
|
||||||
events() {
|
Template.globalSearch.events({
|
||||||
return super.events().concat([
|
'submit .js-search-query-form'(evt, tpl) {
|
||||||
{
|
evt.preventDefault();
|
||||||
'submit .js-search-query-form'(evt) {
|
searchAllBoards(tpl, evt.target.searchQuery.value);
|
||||||
evt.preventDefault();
|
},
|
||||||
this.searchAllBoards(evt.target.searchQuery.value);
|
'click .js-label-color'(evt, tpl) {
|
||||||
},
|
evt.preventDefault();
|
||||||
'click .js-label-color'(evt) {
|
const input = document.getElementById('global-search-input');
|
||||||
evt.preventDefault();
|
tpl.search.query.set(
|
||||||
const input = document.getElementById('global-search-input');
|
`${input.value} ${TAPi18n.__('operator-label')}:"${
|
||||||
this.query.set(
|
evt.currentTarget.textContent
|
||||||
`${input.value} ${TAPi18n.__('operator-label')}:"${
|
}"`,
|
||||||
evt.currentTarget.textContent
|
);
|
||||||
}"`,
|
document.getElementById('global-search-input').focus();
|
||||||
);
|
},
|
||||||
document.getElementById('global-search-input').focus();
|
'click .js-copy-debug-selector'(evt) {
|
||||||
},
|
/* Get the text field */
|
||||||
'click .js-copy-debug-selector'(evt) {
|
const selector = document.getElementById("debug-selector");
|
||||||
/* Get the text field */
|
|
||||||
const selector = document.getElementById("debug-selector");
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
navigator.clipboard.writeText(selector.textContent);
|
navigator.clipboard.writeText(selector.textContent);
|
||||||
alert("Selector copied to clipboard");
|
alert("Selector copied to clipboard");
|
||||||
} catch(err) {
|
} catch(err) {
|
||||||
alert("Error copying text: " + err);
|
alert("Error copying text: " + err);
|
||||||
}
|
}
|
||||||
|
|
||||||
},
|
},
|
||||||
'click .js-copy-debug-projection'(evt) {
|
'click .js-copy-debug-projection'(evt) {
|
||||||
/* Get the text field */
|
/* Get the text field */
|
||||||
const projection = document.getElementById("debug-projection");
|
const projection = document.getElementById("debug-projection");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
navigator.clipboard.writeText(projection.textContent);
|
navigator.clipboard.writeText(projection.textContent);
|
||||||
alert("Projection copied to clipboard");
|
alert("Projection copied to clipboard");
|
||||||
} catch(err) {
|
} catch(err) {
|
||||||
alert("Error copying text: " + err);
|
alert("Error copying text: " + err);
|
||||||
}
|
}
|
||||||
|
|
||||||
},
|
},
|
||||||
'click .js-board-title'(evt) {
|
'click .js-board-title'(evt, tpl) {
|
||||||
evt.preventDefault();
|
evt.preventDefault();
|
||||||
const input = document.getElementById('global-search-input');
|
const input = document.getElementById('global-search-input');
|
||||||
this.query.set(
|
tpl.search.query.set(
|
||||||
`${input.value} ${TAPi18n.__('operator-board')}:"${
|
`${input.value} ${TAPi18n.__('operator-board')}:"${
|
||||||
evt.currentTarget.textContent
|
evt.currentTarget.textContent
|
||||||
}"`,
|
}"`,
|
||||||
);
|
);
|
||||||
document.getElementById('global-search-input').focus();
|
document.getElementById('global-search-input').focus();
|
||||||
},
|
},
|
||||||
'click .js-list-title'(evt) {
|
'click .js-list-title'(evt, tpl) {
|
||||||
evt.preventDefault();
|
evt.preventDefault();
|
||||||
const input = document.getElementById('global-search-input');
|
const input = document.getElementById('global-search-input');
|
||||||
this.query.set(
|
tpl.search.query.set(
|
||||||
`${input.value} ${TAPi18n.__('operator-list')}:"${
|
`${input.value} ${TAPi18n.__('operator-list')}:"${
|
||||||
evt.currentTarget.textContent
|
evt.currentTarget.textContent
|
||||||
}"`,
|
}"`,
|
||||||
);
|
);
|
||||||
document.getElementById('global-search-input').focus();
|
document.getElementById('global-search-input').focus();
|
||||||
},
|
},
|
||||||
'click .js-label-name'(evt) {
|
'click .js-label-name'(evt, tpl) {
|
||||||
evt.preventDefault();
|
evt.preventDefault();
|
||||||
const input = document.getElementById('global-search-input');
|
const input = document.getElementById('global-search-input');
|
||||||
this.query.set(
|
tpl.search.query.set(
|
||||||
`${input.value} ${TAPi18n.__('operator-label')}:"${
|
`${input.value} ${TAPi18n.__('operator-label')}:"${
|
||||||
evt.currentTarget.textContent
|
evt.currentTarget.textContent
|
||||||
}"`,
|
}"`,
|
||||||
);
|
);
|
||||||
document.getElementById('global-search-input').focus();
|
document.getElementById('global-search-input').focus();
|
||||||
},
|
},
|
||||||
'click .js-new-search'(evt) {
|
'click .js-new-search'(evt, tpl) {
|
||||||
evt.preventDefault();
|
evt.preventDefault();
|
||||||
const input = document.getElementById('global-search-input');
|
const input = document.getElementById('global-search-input');
|
||||||
input.value = '';
|
input.value = '';
|
||||||
this.query.set('');
|
tpl.search.query.set('');
|
||||||
this.hasResults.set(false);
|
tpl.search.hasResults.set(false);
|
||||||
},
|
},
|
||||||
},
|
'click .js-next-page'(evt, tpl) {
|
||||||
]);
|
evt.preventDefault();
|
||||||
}
|
tpl.search.nextPage();
|
||||||
}
|
},
|
||||||
|
'click .js-previous-page'(evt, tpl) {
|
||||||
|
evt.preventDefault();
|
||||||
|
tpl.search.previousPage();
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
GlobalSearchComponent.register('globalSearch');
|
// resultsPaged template helpers - this template is used by globalSearch, brokenCards, and brokenCardsReport.
|
||||||
|
// It receives the parent's data context (which includes reactive vars) via +resultsPaged(this).
|
||||||
|
// The jade accesses resultsHeading.get, results.get, getSearchHref, hasPreviousPage.get, hasNextPage.get
|
||||||
|
// directly on the data context, so we don't need helpers for those when the parent passes
|
||||||
|
// the right data context. However, we need to ensure the helpers exist for the template.
|
||||||
|
Template.resultsPaged.helpers({
|
||||||
|
resultsHeading() {
|
||||||
|
const data = Template.currentData();
|
||||||
|
if (data && data.resultsHeading) return data.resultsHeading;
|
||||||
|
// fallback: check parent template
|
||||||
|
const parentTpl = Template.instance().view.parentView.templateInstance && Template.instance().view.parentView.templateInstance();
|
||||||
|
if (parentTpl && parentTpl.search) return parentTpl.search.resultsHeading;
|
||||||
|
return new ReactiveVar('');
|
||||||
|
},
|
||||||
|
results() {
|
||||||
|
const data = Template.currentData();
|
||||||
|
if (data && data.results) return data.results;
|
||||||
|
const parentTpl = Template.instance().view.parentView.templateInstance && Template.instance().view.parentView.templateInstance();
|
||||||
|
if (parentTpl && parentTpl.search) return parentTpl.search.results;
|
||||||
|
return new ReactiveVar([]);
|
||||||
|
},
|
||||||
|
getSearchHref() {
|
||||||
|
const data = Template.currentData();
|
||||||
|
if (data && data.getSearchHref) return data.getSearchHref();
|
||||||
|
const parentTpl = Template.instance().view.parentView.templateInstance && Template.instance().view.parentView.templateInstance();
|
||||||
|
if (parentTpl && parentTpl.search) return parentTpl.search.getSearchHref();
|
||||||
|
return '';
|
||||||
|
},
|
||||||
|
hasPreviousPage() {
|
||||||
|
const data = Template.currentData();
|
||||||
|
if (data && data.hasPreviousPage) return data.hasPreviousPage;
|
||||||
|
const parentTpl = Template.instance().view.parentView.templateInstance && Template.instance().view.parentView.templateInstance();
|
||||||
|
if (parentTpl && parentTpl.search) return parentTpl.search.hasPreviousPage;
|
||||||
|
return new ReactiveVar(false);
|
||||||
|
},
|
||||||
|
hasNextPage() {
|
||||||
|
const data = Template.currentData();
|
||||||
|
if (data && data.hasNextPage) return data.hasNextPage;
|
||||||
|
const parentTpl = Template.instance().view.parentView.templateInstance && Template.instance().view.parentView.templateInstance();
|
||||||
|
if (parentTpl && parentTpl.search) return parentTpl.search.hasNextPage;
|
||||||
|
return new ReactiveVar(false);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
Template.resultsPaged.events({
|
||||||
|
'click .js-next-page'(evt) {
|
||||||
|
evt.preventDefault();
|
||||||
|
// Walk up to find the search instance
|
||||||
|
let view = Template.instance().view;
|
||||||
|
while (view) {
|
||||||
|
const tplInst = view.templateInstance && view.templateInstance();
|
||||||
|
if (tplInst && tplInst.search) {
|
||||||
|
tplInst.search.nextPage();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
view = view.parentView;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'click .js-previous-page'(evt) {
|
||||||
|
evt.preventDefault();
|
||||||
|
let view = Template.instance().view;
|
||||||
|
while (view) {
|
||||||
|
const tplInst = view.templateInstance && view.templateInstance();
|
||||||
|
if (tplInst && tplInst.search) {
|
||||||
|
tplInst.search.previousPage();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
view = view.parentView;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import { CardSearchPagedComponent } from '../../lib/cardSearch';
|
import { CardSearchPaged } from '../../lib/cardSearch';
|
||||||
|
|
||||||
BlazeComponent.extendComponent({
|
Template.myCardsHeaderBar.helpers({
|
||||||
myCardsSort() {
|
myCardsSort() {
|
||||||
// eslint-disable-next-line no-console
|
// eslint-disable-next-line no-console
|
||||||
// console.log('sort:', Utils.myCardsSort());
|
// console.log('sort:', Utils.myCardsSort());
|
||||||
|
|
@ -12,86 +12,69 @@ BlazeComponent.extendComponent({
|
||||||
// console.log('sort:', Utils.myCardsView());
|
// console.log('sort:', Utils.myCardsView());
|
||||||
return Utils.myCardsView();
|
return Utils.myCardsView();
|
||||||
},
|
},
|
||||||
|
});
|
||||||
|
|
||||||
events() {
|
Template.myCardsHeaderBar.events({
|
||||||
return [
|
'click .js-toggle-my-cards-choose-sort': Popup.open(
|
||||||
{
|
'myCardsSortChange',
|
||||||
'click .js-toggle-my-cards-choose-sort': Popup.open(
|
),
|
||||||
'myCardsSortChange',
|
'click .js-my-cards-view-change': Popup.open(
|
||||||
),
|
'myCardsViewChange'),
|
||||||
'click .js-my-cards-view-change': Popup.open(
|
});
|
||||||
'myCardsViewChange'),
|
|
||||||
},
|
Template.myCards.onCreated(function () {
|
||||||
];
|
const search = new CardSearchPaged(this);
|
||||||
},
|
this.search = search;
|
||||||
}).register('myCardsHeaderBar');
|
|
||||||
|
// Override getSubscription for myCards
|
||||||
|
search.getSubscription = function (queryParams) {
|
||||||
|
return Meteor.subscribe(
|
||||||
|
'myCards',
|
||||||
|
search.sessionId,
|
||||||
|
search.subscriptionCallbacks,
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
search.runGlobalSearch(null);
|
||||||
|
Meteor.subscribe('setting');
|
||||||
|
});
|
||||||
|
|
||||||
Template.myCards.helpers({
|
Template.myCards.helpers({
|
||||||
userId() {
|
userId() {
|
||||||
return Meteor.userId();
|
return Meteor.userId();
|
||||||
},
|
},
|
||||||
});
|
|
||||||
|
|
||||||
BlazeComponent.extendComponent({
|
// Return ReactiveVar so jade can use .get pattern
|
||||||
events() {
|
searching() {
|
||||||
return [
|
return Template.instance().search.searching;
|
||||||
{
|
|
||||||
'click .js-my-cards-view-boards'() {
|
|
||||||
Utils.setMyCardsView('boards');
|
|
||||||
Popup.back();
|
|
||||||
},
|
|
||||||
|
|
||||||
'click .js-my-cards-view-table'() {
|
|
||||||
Utils.setMyCardsView('table');
|
|
||||||
Popup.back();
|
|
||||||
},
|
|
||||||
},
|
|
||||||
];
|
|
||||||
},
|
},
|
||||||
}).register('myCardsViewChangePopup');
|
|
||||||
|
|
||||||
class MyCardsComponent extends CardSearchPagedComponent {
|
|
||||||
onCreated() {
|
|
||||||
super.onCreated();
|
|
||||||
|
|
||||||
this.runGlobalSearch(null);
|
|
||||||
Meteor.subscribe('setting');
|
|
||||||
}
|
|
||||||
|
|
||||||
// eslint-disable-next-line no-unused-vars
|
|
||||||
getSubscription(queryParams) {
|
|
||||||
return Meteor.subscribe(
|
|
||||||
'myCards',
|
|
||||||
this.sessionId,
|
|
||||||
this.subscriptionCallbacks,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
myCardsView() {
|
myCardsView() {
|
||||||
// eslint-disable-next-line no-console
|
// eslint-disable-next-line no-console
|
||||||
//console.log('sort:', Utils.myCardsView());
|
//console.log('sort:', Utils.myCardsView());
|
||||||
return Utils.myCardsView();
|
return Utils.myCardsView();
|
||||||
}
|
},
|
||||||
|
|
||||||
labelName(board, labelId) {
|
labelName(board, labelId) {
|
||||||
const label = board.getLabelById(labelId)
|
const label = board.getLabelById(labelId);
|
||||||
const name = label.name
|
const name = label.name;
|
||||||
return name
|
return name;
|
||||||
}
|
},
|
||||||
|
|
||||||
labelColor(board, labelId) {
|
labelColor(board, labelId) {
|
||||||
const label = board.getLabelById(labelId)
|
const label = board.getLabelById(labelId);
|
||||||
const color = label.color
|
const color = label.color;
|
||||||
return color
|
return color;
|
||||||
}
|
},
|
||||||
|
|
||||||
myCardsList() {
|
myCardsList() {
|
||||||
|
const search = Template.instance().search;
|
||||||
const boards = [];
|
const boards = [];
|
||||||
let board = null;
|
let board = null;
|
||||||
let swimlane = null;
|
let swimlane = null;
|
||||||
let list = null;
|
let list = null;
|
||||||
|
|
||||||
const cursor = this.getResults();
|
const cursor = search.getResults();
|
||||||
|
|
||||||
if (cursor) {
|
if (cursor) {
|
||||||
cursor.forEach(card => {
|
cursor.forEach(card => {
|
||||||
|
|
@ -177,6 +160,28 @@ class MyCardsComponent extends CardSearchPagedComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
return [];
|
return [];
|
||||||
}
|
},
|
||||||
}
|
});
|
||||||
MyCardsComponent.register('myCards');
|
|
||||||
|
Template.myCards.events({
|
||||||
|
'click .js-next-page'(evt, tpl) {
|
||||||
|
evt.preventDefault();
|
||||||
|
tpl.search.nextPage();
|
||||||
|
},
|
||||||
|
'click .js-previous-page'(evt, tpl) {
|
||||||
|
evt.preventDefault();
|
||||||
|
tpl.search.previousPage();
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
Template.myCardsViewChangePopup.events({
|
||||||
|
'click .js-my-cards-view-boards'() {
|
||||||
|
Utils.setMyCardsView('boards');
|
||||||
|
Popup.back();
|
||||||
|
},
|
||||||
|
|
||||||
|
'click .js-my-cards-view-table'() {
|
||||||
|
Utils.setMyCardsView('table');
|
||||||
|
Popup.back();
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,13 @@
|
||||||
import { Spinner } from '/client/lib/spinner';
|
import { getSpinnerTemplate } from '/client/lib/spinner';
|
||||||
|
|
||||||
(class extends Spinner {
|
Template.spinner.helpers({
|
||||||
}.register('spinner'));
|
getSpinnerTemplate() {
|
||||||
|
return getSpinnerTemplate();
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
(class extends Spinner {
|
Template.spinnerRaw.helpers({
|
||||||
getSpinnerTemplateRaw() {
|
getSpinnerTemplateRaw() {
|
||||||
let ret = super.getSpinnerTemplate() + 'Raw';
|
return getSpinnerTemplate() + 'Raw';
|
||||||
return ret;
|
},
|
||||||
}
|
});
|
||||||
}.register('spinnerRaw'));
|
|
||||||
|
|
|
||||||
|
|
@ -22,20 +22,18 @@ const supportHelpers = {
|
||||||
};
|
};
|
||||||
|
|
||||||
// Main support page component
|
// Main support page component
|
||||||
BlazeComponent.extendComponent({
|
Template.support.onCreated(function () {
|
||||||
onCreated() {
|
this.error = new ReactiveVar('');
|
||||||
this.error = new ReactiveVar('');
|
this.loading = new ReactiveVar(false);
|
||||||
this.loading = new ReactiveVar(false);
|
|
||||||
|
|
||||||
Meteor.subscribe('setting');
|
Meteor.subscribe('setting');
|
||||||
},
|
});
|
||||||
...supportHelpers
|
|
||||||
}).register('support');
|
Template.support.helpers(supportHelpers);
|
||||||
|
|
||||||
// Header bar component
|
// Header bar component
|
||||||
BlazeComponent.extendComponent({
|
Template.supportHeaderBar.onCreated(function () {
|
||||||
onCreated() {
|
Meteor.subscribe('setting');
|
||||||
Meteor.subscribe('setting');
|
});
|
||||||
},
|
|
||||||
...supportHelpers
|
Template.supportHeaderBar.helpers(supportHelpers);
|
||||||
}).register('supportHeaderBar');
|
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,11 @@
|
||||||
import { ReactiveCache } from '/imports/reactiveCache';
|
import { ReactiveCache } from '/imports/reactiveCache';
|
||||||
import { TAPi18n } from '/imports/i18n';
|
import { TAPi18n } from '/imports/i18n';
|
||||||
|
|
||||||
BlazeComponent.extendComponent({
|
Template.boardActions.onCreated(function () {
|
||||||
onCreated() {
|
this.subscribe('boards');
|
||||||
// Ensure boards are available for action dropdowns
|
});
|
||||||
this.subscribe('boards');
|
|
||||||
},
|
|
||||||
|
|
||||||
|
Template.boardActions.helpers({
|
||||||
boards() {
|
boards() {
|
||||||
const ret = ReactiveCache.getBoards(
|
const ret = ReactiveCache.getBoards(
|
||||||
{
|
{
|
||||||
|
|
@ -32,193 +31,195 @@ BlazeComponent.extendComponent({
|
||||||
}
|
}
|
||||||
return 'Loading boards...';
|
return 'Loading boards...';
|
||||||
},
|
},
|
||||||
|
});
|
||||||
|
|
||||||
events() {
|
Template.boardActions.events({
|
||||||
return [
|
'click .js-create-card-action'(event, tpl) {
|
||||||
{
|
const data = Template.currentData();
|
||||||
'click .js-create-card-action'(event) {
|
const ruleName = data.ruleName.get();
|
||||||
const ruleName = this.data().ruleName.get();
|
const trigger = data.triggerVar.get();
|
||||||
const trigger = this.data().triggerVar.get();
|
const cardName = tpl.find('#card-name').value;
|
||||||
const cardName = this.find('#card-name').value;
|
const listName = tpl.find('#list-name').value;
|
||||||
const listName = this.find('#list-name').value;
|
const swimlaneName = tpl.find('#swimlane-name2').value;
|
||||||
const swimlaneName = this.find('#swimlane-name2').value;
|
const boardId = Session.get('currentBoard');
|
||||||
const boardId = Session.get('currentBoard');
|
const desc = Utils.getTriggerActionDesc(event, tpl);
|
||||||
const desc = Utils.getTriggerActionDesc(event, this);
|
const triggerId = Triggers.insert(trigger);
|
||||||
const triggerId = Triggers.insert(trigger);
|
const actionId = Actions.insert({
|
||||||
const actionId = Actions.insert({
|
actionType: 'createCard',
|
||||||
actionType: 'createCard',
|
swimlaneName,
|
||||||
swimlaneName,
|
cardName,
|
||||||
cardName,
|
listName,
|
||||||
listName,
|
boardId,
|
||||||
boardId,
|
desc,
|
||||||
desc,
|
});
|
||||||
});
|
Rules.insert({
|
||||||
Rules.insert({
|
title: ruleName,
|
||||||
title: ruleName,
|
triggerId,
|
||||||
triggerId,
|
actionId,
|
||||||
actionId,
|
boardId,
|
||||||
boardId,
|
});
|
||||||
});
|
|
||||||
},
|
|
||||||
'click .js-add-swimlane-action'(event) {
|
|
||||||
const ruleName = this.data().ruleName.get();
|
|
||||||
const trigger = this.data().triggerVar.get();
|
|
||||||
const swimlaneName = this.find('#swimlane-name').value;
|
|
||||||
const boardId = Session.get('currentBoard');
|
|
||||||
const desc = Utils.getTriggerActionDesc(event, this);
|
|
||||||
const triggerId = Triggers.insert(trigger);
|
|
||||||
const actionId = Actions.insert({
|
|
||||||
actionType: 'addSwimlane',
|
|
||||||
swimlaneName,
|
|
||||||
boardId,
|
|
||||||
desc,
|
|
||||||
});
|
|
||||||
Rules.insert({
|
|
||||||
title: ruleName,
|
|
||||||
triggerId,
|
|
||||||
actionId,
|
|
||||||
boardId,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
'click .js-add-spec-move-action'(event) {
|
|
||||||
const ruleName = this.data().ruleName.get();
|
|
||||||
const trigger = this.data().triggerVar.get();
|
|
||||||
const actionSelected = this.find('#move-spec-action').value;
|
|
||||||
const swimlaneName = this.find('#swimlaneName').value || '*';
|
|
||||||
const listName = this.find('#listName').value || '*';
|
|
||||||
const boardId = Session.get('currentBoard');
|
|
||||||
const destBoardId = this.find('#board-id').value;
|
|
||||||
const desc = Utils.getTriggerActionDesc(event, this);
|
|
||||||
if (actionSelected === 'top') {
|
|
||||||
const triggerId = Triggers.insert(trigger);
|
|
||||||
const actionId = Actions.insert({
|
|
||||||
actionType: 'moveCardToTop',
|
|
||||||
listName,
|
|
||||||
swimlaneName,
|
|
||||||
boardId: destBoardId,
|
|
||||||
desc,
|
|
||||||
});
|
|
||||||
Rules.insert({
|
|
||||||
title: ruleName,
|
|
||||||
triggerId,
|
|
||||||
actionId,
|
|
||||||
boardId,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (actionSelected === 'bottom') {
|
|
||||||
const triggerId = Triggers.insert(trigger);
|
|
||||||
const actionId = Actions.insert({
|
|
||||||
actionType: 'moveCardToBottom',
|
|
||||||
listName,
|
|
||||||
swimlaneName,
|
|
||||||
boardId: destBoardId,
|
|
||||||
desc,
|
|
||||||
});
|
|
||||||
Rules.insert({
|
|
||||||
title: ruleName,
|
|
||||||
triggerId,
|
|
||||||
actionId,
|
|
||||||
boardId,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
'click .js-add-gen-move-action'(event) {
|
|
||||||
const desc = Utils.getTriggerActionDesc(event, this);
|
|
||||||
const boardId = Session.get('currentBoard');
|
|
||||||
const ruleName = this.data().ruleName.get();
|
|
||||||
const trigger = this.data().triggerVar.get();
|
|
||||||
const actionSelected = this.find('#move-gen-action').value;
|
|
||||||
if (actionSelected === 'top') {
|
|
||||||
const triggerId = Triggers.insert(trigger);
|
|
||||||
const actionId = Actions.insert({
|
|
||||||
actionType: 'moveCardToTop',
|
|
||||||
listTitle: '*',
|
|
||||||
boardId,
|
|
||||||
desc,
|
|
||||||
});
|
|
||||||
Rules.insert({
|
|
||||||
title: ruleName,
|
|
||||||
triggerId,
|
|
||||||
actionId,
|
|
||||||
boardId,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (actionSelected === 'bottom') {
|
|
||||||
const triggerId = Triggers.insert(trigger);
|
|
||||||
const actionId = Actions.insert({
|
|
||||||
actionType: 'moveCardToBottom',
|
|
||||||
listTitle: '*',
|
|
||||||
boardId,
|
|
||||||
desc,
|
|
||||||
});
|
|
||||||
Rules.insert({
|
|
||||||
title: ruleName,
|
|
||||||
triggerId,
|
|
||||||
actionId,
|
|
||||||
boardId,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
'click .js-add-arch-action'(event) {
|
|
||||||
const desc = Utils.getTriggerActionDesc(event, this);
|
|
||||||
const boardId = Session.get('currentBoard');
|
|
||||||
const ruleName = this.data().ruleName.get();
|
|
||||||
const trigger = this.data().triggerVar.get();
|
|
||||||
const actionSelected = this.find('#arch-action').value;
|
|
||||||
if (actionSelected === 'archive') {
|
|
||||||
const triggerId = Triggers.insert(trigger);
|
|
||||||
const actionId = Actions.insert({
|
|
||||||
actionType: 'archive',
|
|
||||||
boardId,
|
|
||||||
desc,
|
|
||||||
});
|
|
||||||
Rules.insert({
|
|
||||||
title: ruleName,
|
|
||||||
triggerId,
|
|
||||||
actionId,
|
|
||||||
boardId,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (actionSelected === 'unarchive') {
|
|
||||||
const triggerId = Triggers.insert(trigger);
|
|
||||||
const actionId = Actions.insert({
|
|
||||||
actionType: 'unarchive',
|
|
||||||
boardId,
|
|
||||||
desc,
|
|
||||||
});
|
|
||||||
Rules.insert({
|
|
||||||
title: ruleName,
|
|
||||||
triggerId,
|
|
||||||
actionId,
|
|
||||||
boardId,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
'click .js-link-card-action'(event) {
|
|
||||||
const ruleName = this.data().ruleName.get();
|
|
||||||
const trigger = this.data().triggerVar.get();
|
|
||||||
const swimlaneName = this.find('#swimlaneName-link').value || '*';
|
|
||||||
const listName = this.find('#listName-link').value || '*';
|
|
||||||
const boardId = Session.get('currentBoard');
|
|
||||||
const destBoardId = this.find('#board-id-link').value;
|
|
||||||
const desc = Utils.getTriggerActionDesc(event, this);
|
|
||||||
const triggerId = Triggers.insert(trigger);
|
|
||||||
const actionId = Actions.insert({
|
|
||||||
actionType: 'linkCard',
|
|
||||||
listName,
|
|
||||||
swimlaneName,
|
|
||||||
boardId: destBoardId,
|
|
||||||
desc,
|
|
||||||
});
|
|
||||||
Rules.insert({
|
|
||||||
title: ruleName,
|
|
||||||
triggerId,
|
|
||||||
actionId,
|
|
||||||
boardId,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
},
|
|
||||||
];
|
|
||||||
},
|
},
|
||||||
}).register('boardActions');
|
'click .js-add-swimlane-action'(event, tpl) {
|
||||||
|
const data = Template.currentData();
|
||||||
|
const ruleName = data.ruleName.get();
|
||||||
|
const trigger = data.triggerVar.get();
|
||||||
|
const swimlaneName = tpl.find('#swimlane-name').value;
|
||||||
|
const boardId = Session.get('currentBoard');
|
||||||
|
const desc = Utils.getTriggerActionDesc(event, tpl);
|
||||||
|
const triggerId = Triggers.insert(trigger);
|
||||||
|
const actionId = Actions.insert({
|
||||||
|
actionType: 'addSwimlane',
|
||||||
|
swimlaneName,
|
||||||
|
boardId,
|
||||||
|
desc,
|
||||||
|
});
|
||||||
|
Rules.insert({
|
||||||
|
title: ruleName,
|
||||||
|
triggerId,
|
||||||
|
actionId,
|
||||||
|
boardId,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
'click .js-add-spec-move-action'(event, tpl) {
|
||||||
|
const data = Template.currentData();
|
||||||
|
const ruleName = data.ruleName.get();
|
||||||
|
const trigger = data.triggerVar.get();
|
||||||
|
const actionSelected = tpl.find('#move-spec-action').value;
|
||||||
|
const swimlaneName = tpl.find('#swimlaneName').value || '*';
|
||||||
|
const listName = tpl.find('#listName').value || '*';
|
||||||
|
const boardId = Session.get('currentBoard');
|
||||||
|
const destBoardId = tpl.find('#board-id').value;
|
||||||
|
const desc = Utils.getTriggerActionDesc(event, tpl);
|
||||||
|
if (actionSelected === 'top') {
|
||||||
|
const triggerId = Triggers.insert(trigger);
|
||||||
|
const actionId = Actions.insert({
|
||||||
|
actionType: 'moveCardToTop',
|
||||||
|
listName,
|
||||||
|
swimlaneName,
|
||||||
|
boardId: destBoardId,
|
||||||
|
desc,
|
||||||
|
});
|
||||||
|
Rules.insert({
|
||||||
|
title: ruleName,
|
||||||
|
triggerId,
|
||||||
|
actionId,
|
||||||
|
boardId,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (actionSelected === 'bottom') {
|
||||||
|
const triggerId = Triggers.insert(trigger);
|
||||||
|
const actionId = Actions.insert({
|
||||||
|
actionType: 'moveCardToBottom',
|
||||||
|
listName,
|
||||||
|
swimlaneName,
|
||||||
|
boardId: destBoardId,
|
||||||
|
desc,
|
||||||
|
});
|
||||||
|
Rules.insert({
|
||||||
|
title: ruleName,
|
||||||
|
triggerId,
|
||||||
|
actionId,
|
||||||
|
boardId,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'click .js-add-gen-move-action'(event, tpl) {
|
||||||
|
const desc = Utils.getTriggerActionDesc(event, tpl);
|
||||||
|
const boardId = Session.get('currentBoard');
|
||||||
|
const data = Template.currentData();
|
||||||
|
const ruleName = data.ruleName.get();
|
||||||
|
const trigger = data.triggerVar.get();
|
||||||
|
const actionSelected = tpl.find('#move-gen-action').value;
|
||||||
|
if (actionSelected === 'top') {
|
||||||
|
const triggerId = Triggers.insert(trigger);
|
||||||
|
const actionId = Actions.insert({
|
||||||
|
actionType: 'moveCardToTop',
|
||||||
|
listTitle: '*',
|
||||||
|
boardId,
|
||||||
|
desc,
|
||||||
|
});
|
||||||
|
Rules.insert({
|
||||||
|
title: ruleName,
|
||||||
|
triggerId,
|
||||||
|
actionId,
|
||||||
|
boardId,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (actionSelected === 'bottom') {
|
||||||
|
const triggerId = Triggers.insert(trigger);
|
||||||
|
const actionId = Actions.insert({
|
||||||
|
actionType: 'moveCardToBottom',
|
||||||
|
listTitle: '*',
|
||||||
|
boardId,
|
||||||
|
desc,
|
||||||
|
});
|
||||||
|
Rules.insert({
|
||||||
|
title: ruleName,
|
||||||
|
triggerId,
|
||||||
|
actionId,
|
||||||
|
boardId,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'click .js-add-arch-action'(event, tpl) {
|
||||||
|
const desc = Utils.getTriggerActionDesc(event, tpl);
|
||||||
|
const boardId = Session.get('currentBoard');
|
||||||
|
const data = Template.currentData();
|
||||||
|
const ruleName = data.ruleName.get();
|
||||||
|
const trigger = data.triggerVar.get();
|
||||||
|
const actionSelected = tpl.find('#arch-action').value;
|
||||||
|
if (actionSelected === 'archive') {
|
||||||
|
const triggerId = Triggers.insert(trigger);
|
||||||
|
const actionId = Actions.insert({
|
||||||
|
actionType: 'archive',
|
||||||
|
boardId,
|
||||||
|
desc,
|
||||||
|
});
|
||||||
|
Rules.insert({
|
||||||
|
title: ruleName,
|
||||||
|
triggerId,
|
||||||
|
actionId,
|
||||||
|
boardId,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (actionSelected === 'unarchive') {
|
||||||
|
const triggerId = Triggers.insert(trigger);
|
||||||
|
const actionId = Actions.insert({
|
||||||
|
actionType: 'unarchive',
|
||||||
|
boardId,
|
||||||
|
desc,
|
||||||
|
});
|
||||||
|
Rules.insert({
|
||||||
|
title: ruleName,
|
||||||
|
triggerId,
|
||||||
|
actionId,
|
||||||
|
boardId,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'click .js-link-card-action'(event, tpl) {
|
||||||
|
const data = Template.currentData();
|
||||||
|
const ruleName = data.ruleName.get();
|
||||||
|
const trigger = data.triggerVar.get();
|
||||||
|
const swimlaneName = tpl.find('#swimlaneName-link').value || '*';
|
||||||
|
const listName = tpl.find('#listName-link').value || '*';
|
||||||
|
const boardId = Session.get('currentBoard');
|
||||||
|
const destBoardId = tpl.find('#board-id-link').value;
|
||||||
|
const desc = Utils.getTriggerActionDesc(event, tpl);
|
||||||
|
const triggerId = Triggers.insert(trigger);
|
||||||
|
const actionId = Actions.insert({
|
||||||
|
actionType: 'linkCard',
|
||||||
|
listName,
|
||||||
|
swimlaneName,
|
||||||
|
boardId: destBoardId,
|
||||||
|
desc,
|
||||||
|
});
|
||||||
|
Rules.insert({
|
||||||
|
title: ruleName,
|
||||||
|
triggerId,
|
||||||
|
actionId,
|
||||||
|
boardId,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
||||||
/* eslint-no-undef */
|
/* eslint-no-undef */
|
||||||
|
|
|
||||||
|
|
@ -3,18 +3,23 @@ Meteor.startup(() => {
|
||||||
cardColors = Cards.simpleSchema()._schema.color.allowedValues;
|
cardColors = Cards.simpleSchema()._schema.color.allowedValues;
|
||||||
});
|
});
|
||||||
|
|
||||||
BlazeComponent.extendComponent({
|
// Module-level shared state so the color popup can read/write the
|
||||||
onCreated() {
|
// cardColorButtonValue without relying on BlazeComponent.getOpenerComponent().
|
||||||
this.subscribe('allRules');
|
let sharedCardColorButtonValue;
|
||||||
this.cardColorButtonValue = new ReactiveVar('green');
|
|
||||||
},
|
|
||||||
|
|
||||||
|
Template.cardActions.onCreated(function () {
|
||||||
|
this.subscribe('allRules');
|
||||||
|
this.cardColorButtonValue = new ReactiveVar('green');
|
||||||
|
sharedCardColorButtonValue = this.cardColorButtonValue;
|
||||||
|
});
|
||||||
|
|
||||||
|
Template.cardActions.helpers({
|
||||||
cardColorButton() {
|
cardColorButton() {
|
||||||
return this.cardColorButtonValue.get();
|
return Template.instance().cardColorButtonValue.get();
|
||||||
},
|
},
|
||||||
|
|
||||||
cardColorButtonText() {
|
cardColorButtonText() {
|
||||||
return `color-${this.cardColorButtonValue.get()}`;
|
return `color-${Template.instance().cardColorButtonValue.get()}`;
|
||||||
},
|
},
|
||||||
|
|
||||||
labels() {
|
labels() {
|
||||||
|
|
@ -26,215 +31,214 @@ BlazeComponent.extendComponent({
|
||||||
}
|
}
|
||||||
return labels;
|
return labels;
|
||||||
},
|
},
|
||||||
|
});
|
||||||
|
|
||||||
events() {
|
Template.cardActions.events({
|
||||||
return [
|
'click .js-set-date-action'(event, tpl) {
|
||||||
{
|
const data = Template.currentData();
|
||||||
'click .js-set-date-action'(event) {
|
const ruleName = data.ruleName.get();
|
||||||
const ruleName = this.data().ruleName.get();
|
const trigger = data.triggerVar.get();
|
||||||
const trigger = this.data().triggerVar.get();
|
const triggerId = Triggers.insert(trigger);
|
||||||
const triggerId = Triggers.insert(trigger);
|
const actionSelected = tpl.find('#setdate-action').value;
|
||||||
const actionSelected = this.find('#setdate-action').value;
|
const dateFieldSelected = tpl.find('#setdate-datefield').value;
|
||||||
const dateFieldSelected = this.find('#setdate-datefield').value;
|
const boardId = Session.get('currentBoard');
|
||||||
const boardId = Session.get('currentBoard');
|
const desc = Utils.getTriggerActionDesc(event, tpl);
|
||||||
const desc = Utils.getTriggerActionDesc(event, this);
|
|
||||||
|
|
||||||
const actionId = Actions.insert({
|
const actionId = Actions.insert({
|
||||||
actionType: actionSelected,
|
actionType: actionSelected,
|
||||||
dateField: dateFieldSelected,
|
dateField: dateFieldSelected,
|
||||||
boardId,
|
boardId,
|
||||||
desc,
|
desc,
|
||||||
});
|
});
|
||||||
|
|
||||||
Rules.insert({
|
Rules.insert({
|
||||||
title: ruleName,
|
title: ruleName,
|
||||||
triggerId,
|
triggerId,
|
||||||
actionId,
|
actionId,
|
||||||
boardId,
|
boardId,
|
||||||
desc,
|
desc,
|
||||||
});
|
});
|
||||||
},
|
|
||||||
|
|
||||||
'click .js-remove-datevalue-action'(event) {
|
|
||||||
const ruleName = this.data().ruleName.get();
|
|
||||||
const trigger = this.data().triggerVar.get();
|
|
||||||
const triggerId = Triggers.insert(trigger);
|
|
||||||
const dateFieldSelected = this.find('#setdate-removedatefieldvalue')
|
|
||||||
.value;
|
|
||||||
const boardId = Session.get('currentBoard');
|
|
||||||
const desc = Utils.getTriggerActionDesc(event, this);
|
|
||||||
|
|
||||||
const actionId = Actions.insert({
|
|
||||||
actionType: 'removeDate',
|
|
||||||
dateField: dateFieldSelected,
|
|
||||||
boardId,
|
|
||||||
desc,
|
|
||||||
});
|
|
||||||
|
|
||||||
Rules.insert({
|
|
||||||
title: ruleName,
|
|
||||||
triggerId,
|
|
||||||
actionId,
|
|
||||||
boardId,
|
|
||||||
desc,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
'click .js-add-label-action'(event) {
|
|
||||||
const ruleName = this.data().ruleName.get();
|
|
||||||
const trigger = this.data().triggerVar.get();
|
|
||||||
const actionSelected = this.find('#label-action').value;
|
|
||||||
const labelId = this.find('#label-id').value;
|
|
||||||
const boardId = Session.get('currentBoard');
|
|
||||||
const desc = Utils.getTriggerActionDesc(event, this);
|
|
||||||
if (actionSelected === 'add') {
|
|
||||||
const triggerId = Triggers.insert(trigger);
|
|
||||||
const actionId = Actions.insert({
|
|
||||||
actionType: 'addLabel',
|
|
||||||
labelId,
|
|
||||||
boardId,
|
|
||||||
desc,
|
|
||||||
});
|
|
||||||
Rules.insert({
|
|
||||||
title: ruleName,
|
|
||||||
triggerId,
|
|
||||||
actionId,
|
|
||||||
boardId,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (actionSelected === 'remove') {
|
|
||||||
const triggerId = Triggers.insert(trigger);
|
|
||||||
const actionId = Actions.insert({
|
|
||||||
actionType: 'removeLabel',
|
|
||||||
labelId,
|
|
||||||
boardId,
|
|
||||||
desc,
|
|
||||||
});
|
|
||||||
Rules.insert({
|
|
||||||
title: ruleName,
|
|
||||||
triggerId,
|
|
||||||
actionId,
|
|
||||||
boardId,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
'click .js-add-member-action'(event) {
|
|
||||||
const ruleName = this.data().ruleName.get();
|
|
||||||
const trigger = this.data().triggerVar.get();
|
|
||||||
const actionSelected = this.find('#member-action').value;
|
|
||||||
const username = this.find('#member-name').value;
|
|
||||||
const boardId = Session.get('currentBoard');
|
|
||||||
const desc = Utils.getTriggerActionDesc(event, this);
|
|
||||||
if (actionSelected === 'add') {
|
|
||||||
const triggerId = Triggers.insert(trigger);
|
|
||||||
const actionId = Actions.insert({
|
|
||||||
actionType: 'addMember',
|
|
||||||
username,
|
|
||||||
boardId,
|
|
||||||
desc,
|
|
||||||
});
|
|
||||||
Rules.insert({
|
|
||||||
title: ruleName,
|
|
||||||
triggerId,
|
|
||||||
actionId,
|
|
||||||
boardId,
|
|
||||||
desc,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (actionSelected === 'remove') {
|
|
||||||
const triggerId = Triggers.insert(trigger);
|
|
||||||
const actionId = Actions.insert({
|
|
||||||
actionType: 'removeMember',
|
|
||||||
username,
|
|
||||||
boardId,
|
|
||||||
desc,
|
|
||||||
});
|
|
||||||
Rules.insert({
|
|
||||||
title: ruleName,
|
|
||||||
triggerId,
|
|
||||||
actionId,
|
|
||||||
boardId,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
'click .js-add-removeall-action'(event) {
|
|
||||||
const ruleName = this.data().ruleName.get();
|
|
||||||
const trigger = this.data().triggerVar.get();
|
|
||||||
const triggerId = Triggers.insert(trigger);
|
|
||||||
const desc = Utils.getTriggerActionDesc(event, this);
|
|
||||||
const boardId = Session.get('currentBoard');
|
|
||||||
const actionId = Actions.insert({
|
|
||||||
actionType: 'removeMember',
|
|
||||||
// deepcode ignore NoHardcodedCredentials: it's no credential
|
|
||||||
username: '*',
|
|
||||||
boardId,
|
|
||||||
desc,
|
|
||||||
});
|
|
||||||
Rules.insert({
|
|
||||||
title: ruleName,
|
|
||||||
triggerId,
|
|
||||||
actionId,
|
|
||||||
boardId,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
'click .js-show-color-palette'(event) {
|
|
||||||
const funct = Popup.open('setCardActionsColor');
|
|
||||||
const colorButton = this.find('#color-action');
|
|
||||||
if (colorButton.value === '') {
|
|
||||||
colorButton.value = 'green';
|
|
||||||
}
|
|
||||||
funct.call(this, event);
|
|
||||||
},
|
|
||||||
'click .js-set-color-action'(event) {
|
|
||||||
const ruleName = this.data().ruleName.get();
|
|
||||||
const trigger = this.data().triggerVar.get();
|
|
||||||
const selectedColor = this.cardColorButtonValue.get();
|
|
||||||
const boardId = Session.get('currentBoard');
|
|
||||||
const desc = Utils.getTriggerActionDesc(event, this);
|
|
||||||
const triggerId = Triggers.insert(trigger);
|
|
||||||
const actionId = Actions.insert({
|
|
||||||
actionType: 'setColor',
|
|
||||||
selectedColor,
|
|
||||||
boardId,
|
|
||||||
desc,
|
|
||||||
});
|
|
||||||
Rules.insert({
|
|
||||||
title: ruleName,
|
|
||||||
triggerId,
|
|
||||||
actionId,
|
|
||||||
boardId,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
},
|
|
||||||
];
|
|
||||||
},
|
|
||||||
}).register('cardActions');
|
|
||||||
|
|
||||||
BlazeComponent.extendComponent({
|
|
||||||
onCreated() {
|
|
||||||
this.currentAction = this.currentData();
|
|
||||||
this.colorButtonValue = Popup.getOpenerComponent().cardColorButtonValue;
|
|
||||||
this.currentColor = new ReactiveVar(this.colorButtonValue.get());
|
|
||||||
},
|
},
|
||||||
|
|
||||||
|
'click .js-remove-datevalue-action'(event, tpl) {
|
||||||
|
const data = Template.currentData();
|
||||||
|
const ruleName = data.ruleName.get();
|
||||||
|
const trigger = data.triggerVar.get();
|
||||||
|
const triggerId = Triggers.insert(trigger);
|
||||||
|
const dateFieldSelected = tpl.find('#setdate-removedatefieldvalue')
|
||||||
|
.value;
|
||||||
|
const boardId = Session.get('currentBoard');
|
||||||
|
const desc = Utils.getTriggerActionDesc(event, tpl);
|
||||||
|
|
||||||
|
const actionId = Actions.insert({
|
||||||
|
actionType: 'removeDate',
|
||||||
|
dateField: dateFieldSelected,
|
||||||
|
boardId,
|
||||||
|
desc,
|
||||||
|
});
|
||||||
|
|
||||||
|
Rules.insert({
|
||||||
|
title: ruleName,
|
||||||
|
triggerId,
|
||||||
|
actionId,
|
||||||
|
boardId,
|
||||||
|
desc,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
'click .js-add-label-action'(event, tpl) {
|
||||||
|
const data = Template.currentData();
|
||||||
|
const ruleName = data.ruleName.get();
|
||||||
|
const trigger = data.triggerVar.get();
|
||||||
|
const actionSelected = tpl.find('#label-action').value;
|
||||||
|
const labelId = tpl.find('#label-id').value;
|
||||||
|
const boardId = Session.get('currentBoard');
|
||||||
|
const desc = Utils.getTriggerActionDesc(event, tpl);
|
||||||
|
if (actionSelected === 'add') {
|
||||||
|
const triggerId = Triggers.insert(trigger);
|
||||||
|
const actionId = Actions.insert({
|
||||||
|
actionType: 'addLabel',
|
||||||
|
labelId,
|
||||||
|
boardId,
|
||||||
|
desc,
|
||||||
|
});
|
||||||
|
Rules.insert({
|
||||||
|
title: ruleName,
|
||||||
|
triggerId,
|
||||||
|
actionId,
|
||||||
|
boardId,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (actionSelected === 'remove') {
|
||||||
|
const triggerId = Triggers.insert(trigger);
|
||||||
|
const actionId = Actions.insert({
|
||||||
|
actionType: 'removeLabel',
|
||||||
|
labelId,
|
||||||
|
boardId,
|
||||||
|
desc,
|
||||||
|
});
|
||||||
|
Rules.insert({
|
||||||
|
title: ruleName,
|
||||||
|
triggerId,
|
||||||
|
actionId,
|
||||||
|
boardId,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'click .js-add-member-action'(event, tpl) {
|
||||||
|
const data = Template.currentData();
|
||||||
|
const ruleName = data.ruleName.get();
|
||||||
|
const trigger = data.triggerVar.get();
|
||||||
|
const actionSelected = tpl.find('#member-action').value;
|
||||||
|
const username = tpl.find('#member-name').value;
|
||||||
|
const boardId = Session.get('currentBoard');
|
||||||
|
const desc = Utils.getTriggerActionDesc(event, tpl);
|
||||||
|
if (actionSelected === 'add') {
|
||||||
|
const triggerId = Triggers.insert(trigger);
|
||||||
|
const actionId = Actions.insert({
|
||||||
|
actionType: 'addMember',
|
||||||
|
username,
|
||||||
|
boardId,
|
||||||
|
desc,
|
||||||
|
});
|
||||||
|
Rules.insert({
|
||||||
|
title: ruleName,
|
||||||
|
triggerId,
|
||||||
|
actionId,
|
||||||
|
boardId,
|
||||||
|
desc,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (actionSelected === 'remove') {
|
||||||
|
const triggerId = Triggers.insert(trigger);
|
||||||
|
const actionId = Actions.insert({
|
||||||
|
actionType: 'removeMember',
|
||||||
|
username,
|
||||||
|
boardId,
|
||||||
|
desc,
|
||||||
|
});
|
||||||
|
Rules.insert({
|
||||||
|
title: ruleName,
|
||||||
|
triggerId,
|
||||||
|
actionId,
|
||||||
|
boardId,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'click .js-add-removeall-action'(event, tpl) {
|
||||||
|
const data = Template.currentData();
|
||||||
|
const ruleName = data.ruleName.get();
|
||||||
|
const trigger = data.triggerVar.get();
|
||||||
|
const triggerId = Triggers.insert(trigger);
|
||||||
|
const desc = Utils.getTriggerActionDesc(event, tpl);
|
||||||
|
const boardId = Session.get('currentBoard');
|
||||||
|
const actionId = Actions.insert({
|
||||||
|
actionType: 'removeMember',
|
||||||
|
// deepcode ignore NoHardcodedCredentials: it's no credential
|
||||||
|
username: '*',
|
||||||
|
boardId,
|
||||||
|
desc,
|
||||||
|
});
|
||||||
|
Rules.insert({
|
||||||
|
title: ruleName,
|
||||||
|
triggerId,
|
||||||
|
actionId,
|
||||||
|
boardId,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
'click .js-show-color-palette'(event, tpl) {
|
||||||
|
const funct = Popup.open('setCardActionsColor');
|
||||||
|
const colorButton = tpl.find('#color-action');
|
||||||
|
if (colorButton.value === '') {
|
||||||
|
colorButton.value = 'green';
|
||||||
|
}
|
||||||
|
funct.call(this, event);
|
||||||
|
},
|
||||||
|
'click .js-set-color-action'(event, tpl) {
|
||||||
|
const data = Template.currentData();
|
||||||
|
const ruleName = data.ruleName.get();
|
||||||
|
const trigger = data.triggerVar.get();
|
||||||
|
const selectedColor = tpl.cardColorButtonValue.get();
|
||||||
|
const boardId = Session.get('currentBoard');
|
||||||
|
const desc = Utils.getTriggerActionDesc(event, tpl);
|
||||||
|
const triggerId = Triggers.insert(trigger);
|
||||||
|
const actionId = Actions.insert({
|
||||||
|
actionType: 'setColor',
|
||||||
|
selectedColor,
|
||||||
|
boardId,
|
||||||
|
desc,
|
||||||
|
});
|
||||||
|
Rules.insert({
|
||||||
|
title: ruleName,
|
||||||
|
triggerId,
|
||||||
|
actionId,
|
||||||
|
boardId,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
Template.setCardActionsColorPopup.onCreated(function () {
|
||||||
|
this.currentColor = new ReactiveVar(
|
||||||
|
sharedCardColorButtonValue.get()
|
||||||
|
);
|
||||||
|
this.colorButtonValue = sharedCardColorButtonValue;
|
||||||
|
});
|
||||||
|
|
||||||
|
Template.setCardActionsColorPopup.helpers({
|
||||||
colors() {
|
colors() {
|
||||||
return cardColors.map(color => ({ color, name: '' }));
|
return cardColors.map(color => ({ color, name: '' }));
|
||||||
},
|
},
|
||||||
|
|
||||||
isSelected(color) {
|
isSelected(color) {
|
||||||
return this.currentColor.get() === color;
|
return Template.instance().currentColor.get() === color;
|
||||||
},
|
},
|
||||||
|
});
|
||||||
|
|
||||||
events() {
|
Template.setCardActionsColorPopup.events({
|
||||||
return [
|
'click .js-palette-color'(event, tpl) {
|
||||||
{
|
tpl.currentColor.set(Template.currentData().color);
|
||||||
'click .js-palette-color'() {
|
|
||||||
this.currentColor.set(this.currentData().color);
|
|
||||||
},
|
|
||||||
'click .js-submit'() {
|
|
||||||
this.colorButtonValue.set(this.currentColor.get());
|
|
||||||
Popup.back();
|
|
||||||
},
|
|
||||||
},
|
|
||||||
];
|
|
||||||
},
|
},
|
||||||
}).register('setCardActionsColorPopup');
|
'click .js-submit'(event, tpl) {
|
||||||
|
tpl.colorButtonValue.set(tpl.currentColor.get());
|
||||||
|
Popup.back();
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,150 +1,149 @@
|
||||||
BlazeComponent.extendComponent({
|
Template.checklistActions.onCreated(function () {
|
||||||
onCreated() {
|
this.subscribe('allRules');
|
||||||
this.subscribe('allRules');
|
});
|
||||||
|
|
||||||
|
Template.checklistActions.events({
|
||||||
|
'click .js-add-checklist-items-action'(event, tpl) {
|
||||||
|
const data = Template.currentData();
|
||||||
|
const ruleName = data.ruleName.get();
|
||||||
|
const trigger = data.triggerVar.get();
|
||||||
|
const checklistName = tpl.find('#checklist-name-3').value;
|
||||||
|
const checklistItems = tpl.find('#checklist-items').value;
|
||||||
|
const boardId = Session.get('currentBoard');
|
||||||
|
const desc = Utils.getTriggerActionDesc(event, tpl);
|
||||||
|
const triggerId = Triggers.insert(trigger);
|
||||||
|
const actionId = Actions.insert({
|
||||||
|
actionType: 'addChecklistWithItems',
|
||||||
|
checklistName,
|
||||||
|
checklistItems,
|
||||||
|
boardId,
|
||||||
|
desc,
|
||||||
|
});
|
||||||
|
Rules.insert({
|
||||||
|
title: ruleName,
|
||||||
|
triggerId,
|
||||||
|
actionId,
|
||||||
|
boardId,
|
||||||
|
});
|
||||||
},
|
},
|
||||||
events() {
|
'click .js-add-checklist-action'(event, tpl) {
|
||||||
return [
|
const data = Template.currentData();
|
||||||
{
|
const ruleName = data.ruleName.get();
|
||||||
'click .js-add-checklist-items-action'(event) {
|
const trigger = data.triggerVar.get();
|
||||||
const ruleName = this.data().ruleName.get();
|
const actionSelected = tpl.find('#check-action').value;
|
||||||
const trigger = this.data().triggerVar.get();
|
const checklistName = tpl.find('#checklist-name').value;
|
||||||
const checklistName = this.find('#checklist-name-3').value;
|
const boardId = Session.get('currentBoard');
|
||||||
const checklistItems = this.find('#checklist-items').value;
|
const desc = Utils.getTriggerActionDesc(event, tpl);
|
||||||
const boardId = Session.get('currentBoard');
|
if (actionSelected === 'add') {
|
||||||
const desc = Utils.getTriggerActionDesc(event, this);
|
const triggerId = Triggers.insert(trigger);
|
||||||
const triggerId = Triggers.insert(trigger);
|
const actionId = Actions.insert({
|
||||||
const actionId = Actions.insert({
|
actionType: 'addChecklist',
|
||||||
actionType: 'addChecklistWithItems',
|
checklistName,
|
||||||
checklistName,
|
boardId,
|
||||||
checklistItems,
|
desc,
|
||||||
boardId,
|
});
|
||||||
desc,
|
Rules.insert({
|
||||||
});
|
title: ruleName,
|
||||||
Rules.insert({
|
triggerId,
|
||||||
title: ruleName,
|
actionId,
|
||||||
triggerId,
|
boardId,
|
||||||
actionId,
|
});
|
||||||
boardId,
|
}
|
||||||
});
|
if (actionSelected === 'remove') {
|
||||||
},
|
const triggerId = Triggers.insert(trigger);
|
||||||
'click .js-add-checklist-action'(event) {
|
const actionId = Actions.insert({
|
||||||
const ruleName = this.data().ruleName.get();
|
actionType: 'removeChecklist',
|
||||||
const trigger = this.data().triggerVar.get();
|
checklistName,
|
||||||
const actionSelected = this.find('#check-action').value;
|
boardId,
|
||||||
const checklistName = this.find('#checklist-name').value;
|
desc,
|
||||||
const boardId = Session.get('currentBoard');
|
});
|
||||||
const desc = Utils.getTriggerActionDesc(event, this);
|
Rules.insert({
|
||||||
if (actionSelected === 'add') {
|
title: ruleName,
|
||||||
const triggerId = Triggers.insert(trigger);
|
triggerId,
|
||||||
const actionId = Actions.insert({
|
actionId,
|
||||||
actionType: 'addChecklist',
|
boardId,
|
||||||
checklistName,
|
});
|
||||||
boardId,
|
}
|
||||||
desc,
|
|
||||||
});
|
|
||||||
Rules.insert({
|
|
||||||
title: ruleName,
|
|
||||||
triggerId,
|
|
||||||
actionId,
|
|
||||||
boardId,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (actionSelected === 'remove') {
|
|
||||||
const triggerId = Triggers.insert(trigger);
|
|
||||||
const actionId = Actions.insert({
|
|
||||||
actionType: 'removeChecklist',
|
|
||||||
checklistName,
|
|
||||||
boardId,
|
|
||||||
desc,
|
|
||||||
});
|
|
||||||
Rules.insert({
|
|
||||||
title: ruleName,
|
|
||||||
triggerId,
|
|
||||||
actionId,
|
|
||||||
boardId,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
'click .js-add-checkall-action'(event) {
|
|
||||||
const ruleName = this.data().ruleName.get();
|
|
||||||
const trigger = this.data().triggerVar.get();
|
|
||||||
const actionSelected = this.find('#checkall-action').value;
|
|
||||||
const checklistName = this.find('#checklist-name2').value;
|
|
||||||
const boardId = Session.get('currentBoard');
|
|
||||||
const desc = Utils.getTriggerActionDesc(event, this);
|
|
||||||
if (actionSelected === 'check') {
|
|
||||||
const triggerId = Triggers.insert(trigger);
|
|
||||||
const actionId = Actions.insert({
|
|
||||||
actionType: 'checkAll',
|
|
||||||
checklistName,
|
|
||||||
boardId,
|
|
||||||
desc,
|
|
||||||
});
|
|
||||||
Rules.insert({
|
|
||||||
title: ruleName,
|
|
||||||
triggerId,
|
|
||||||
actionId,
|
|
||||||
boardId,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (actionSelected === 'uncheck') {
|
|
||||||
const triggerId = Triggers.insert(trigger);
|
|
||||||
const actionId = Actions.insert({
|
|
||||||
actionType: 'uncheckAll',
|
|
||||||
checklistName,
|
|
||||||
boardId,
|
|
||||||
desc,
|
|
||||||
});
|
|
||||||
Rules.insert({
|
|
||||||
title: ruleName,
|
|
||||||
triggerId,
|
|
||||||
actionId,
|
|
||||||
boardId,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
'click .js-add-check-item-action'(event) {
|
|
||||||
const ruleName = this.data().ruleName.get();
|
|
||||||
const trigger = this.data().triggerVar.get();
|
|
||||||
const checkItemName = this.find('#checkitem-name');
|
|
||||||
const checklistName = this.find('#checklist-name3');
|
|
||||||
const actionSelected = this.find('#check-item-action').value;
|
|
||||||
const boardId = Session.get('currentBoard');
|
|
||||||
const desc = Utils.getTriggerActionDesc(event, this);
|
|
||||||
if (actionSelected === 'check') {
|
|
||||||
const triggerId = Triggers.insert(trigger);
|
|
||||||
const actionId = Actions.insert({
|
|
||||||
actionType: 'checkItem',
|
|
||||||
checklistName,
|
|
||||||
checkItemName,
|
|
||||||
boardId,
|
|
||||||
desc,
|
|
||||||
});
|
|
||||||
Rules.insert({
|
|
||||||
title: ruleName,
|
|
||||||
triggerId,
|
|
||||||
actionId,
|
|
||||||
boardId,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (actionSelected === 'uncheck') {
|
|
||||||
const triggerId = Triggers.insert(trigger);
|
|
||||||
const actionId = Actions.insert({
|
|
||||||
actionType: 'uncheckItem',
|
|
||||||
checklistName,
|
|
||||||
checkItemName,
|
|
||||||
boardId,
|
|
||||||
desc,
|
|
||||||
});
|
|
||||||
Rules.insert({
|
|
||||||
title: ruleName,
|
|
||||||
triggerId,
|
|
||||||
actionId,
|
|
||||||
boardId,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
];
|
|
||||||
},
|
},
|
||||||
}).register('checklistActions');
|
'click .js-add-checkall-action'(event, tpl) {
|
||||||
|
const data = Template.currentData();
|
||||||
|
const ruleName = data.ruleName.get();
|
||||||
|
const trigger = data.triggerVar.get();
|
||||||
|
const actionSelected = tpl.find('#checkall-action').value;
|
||||||
|
const checklistName = tpl.find('#checklist-name2').value;
|
||||||
|
const boardId = Session.get('currentBoard');
|
||||||
|
const desc = Utils.getTriggerActionDesc(event, tpl);
|
||||||
|
if (actionSelected === 'check') {
|
||||||
|
const triggerId = Triggers.insert(trigger);
|
||||||
|
const actionId = Actions.insert({
|
||||||
|
actionType: 'checkAll',
|
||||||
|
checklistName,
|
||||||
|
boardId,
|
||||||
|
desc,
|
||||||
|
});
|
||||||
|
Rules.insert({
|
||||||
|
title: ruleName,
|
||||||
|
triggerId,
|
||||||
|
actionId,
|
||||||
|
boardId,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (actionSelected === 'uncheck') {
|
||||||
|
const triggerId = Triggers.insert(trigger);
|
||||||
|
const actionId = Actions.insert({
|
||||||
|
actionType: 'uncheckAll',
|
||||||
|
checklistName,
|
||||||
|
boardId,
|
||||||
|
desc,
|
||||||
|
});
|
||||||
|
Rules.insert({
|
||||||
|
title: ruleName,
|
||||||
|
triggerId,
|
||||||
|
actionId,
|
||||||
|
boardId,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'click .js-add-check-item-action'(event, tpl) {
|
||||||
|
const data = Template.currentData();
|
||||||
|
const ruleName = data.ruleName.get();
|
||||||
|
const trigger = data.triggerVar.get();
|
||||||
|
const checkItemName = tpl.find('#checkitem-name');
|
||||||
|
const checklistName = tpl.find('#checklist-name3');
|
||||||
|
const actionSelected = tpl.find('#check-item-action').value;
|
||||||
|
const boardId = Session.get('currentBoard');
|
||||||
|
const desc = Utils.getTriggerActionDesc(event, tpl);
|
||||||
|
if (actionSelected === 'check') {
|
||||||
|
const triggerId = Triggers.insert(trigger);
|
||||||
|
const actionId = Actions.insert({
|
||||||
|
actionType: 'checkItem',
|
||||||
|
checklistName,
|
||||||
|
checkItemName,
|
||||||
|
boardId,
|
||||||
|
desc,
|
||||||
|
});
|
||||||
|
Rules.insert({
|
||||||
|
title: ruleName,
|
||||||
|
triggerId,
|
||||||
|
actionId,
|
||||||
|
boardId,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (actionSelected === 'uncheck') {
|
||||||
|
const triggerId = Triggers.insert(trigger);
|
||||||
|
const actionId = Actions.insert({
|
||||||
|
actionType: 'uncheckItem',
|
||||||
|
checklistName,
|
||||||
|
checkItemName,
|
||||||
|
boardId,
|
||||||
|
desc,
|
||||||
|
});
|
||||||
|
Rules.insert({
|
||||||
|
title: ruleName,
|
||||||
|
triggerId,
|
||||||
|
actionId,
|
||||||
|
boardId,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,34 +1,27 @@
|
||||||
BlazeComponent.extendComponent({
|
Template.mailActions.events({
|
||||||
onCreated() {},
|
'click .js-mail-action'(event, tpl) {
|
||||||
|
const emailTo = tpl.find('#email-to').value;
|
||||||
events() {
|
const emailSubject = tpl.find('#email-subject').value;
|
||||||
return [
|
const emailMsg = tpl.find('#email-msg').value;
|
||||||
{
|
const data = Template.currentData();
|
||||||
'click .js-mail-action'(event) {
|
const trigger = data.triggerVar.get();
|
||||||
const emailTo = this.find('#email-to').value;
|
const ruleName = data.ruleName.get();
|
||||||
const emailSubject = this.find('#email-subject').value;
|
const triggerId = Triggers.insert(trigger);
|
||||||
const emailMsg = this.find('#email-msg').value;
|
const boardId = Session.get('currentBoard');
|
||||||
const trigger = this.data().triggerVar.get();
|
const desc = Utils.getTriggerActionDesc(event, tpl);
|
||||||
const ruleName = this.data().ruleName.get();
|
const actionId = Actions.insert({
|
||||||
const triggerId = Triggers.insert(trigger);
|
actionType: 'sendEmail',
|
||||||
const boardId = Session.get('currentBoard');
|
emailTo,
|
||||||
const desc = Utils.getTriggerActionDesc(event, this);
|
emailSubject,
|
||||||
const actionId = Actions.insert({
|
emailMsg,
|
||||||
actionType: 'sendEmail',
|
boardId,
|
||||||
emailTo,
|
desc,
|
||||||
emailSubject,
|
});
|
||||||
emailMsg,
|
Rules.insert({
|
||||||
boardId,
|
title: ruleName,
|
||||||
desc,
|
triggerId,
|
||||||
});
|
actionId,
|
||||||
Rules.insert({
|
boardId,
|
||||||
title: ruleName,
|
});
|
||||||
triggerId,
|
|
||||||
actionId,
|
|
||||||
boardId,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
},
|
|
||||||
];
|
|
||||||
},
|
},
|
||||||
}).register('mailActions');
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,15 @@
|
||||||
import { ReactiveCache } from '/imports/reactiveCache';
|
import { ReactiveCache } from '/imports/reactiveCache';
|
||||||
|
|
||||||
BlazeComponent.extendComponent({
|
Template.ruleDetails.onCreated(function () {
|
||||||
onCreated() {
|
this.subscribe('allRules');
|
||||||
this.subscribe('allRules');
|
this.subscribe('allTriggers');
|
||||||
this.subscribe('allTriggers');
|
this.subscribe('allActions');
|
||||||
this.subscribe('allActions');
|
this.subscribe('boards');
|
||||||
this.subscribe('boards');
|
});
|
||||||
},
|
|
||||||
|
|
||||||
|
Template.ruleDetails.helpers({
|
||||||
trigger() {
|
trigger() {
|
||||||
const ruleId = this.data().ruleId;
|
const ruleId = Template.currentData().ruleId;
|
||||||
const rule = ReactiveCache.getRule(ruleId.get());
|
const rule = ReactiveCache.getRule(ruleId.get());
|
||||||
const trigger = ReactiveCache.getTrigger(rule.triggerId);
|
const trigger = ReactiveCache.getTrigger(rule.triggerId);
|
||||||
const desc = trigger.description();
|
const desc = trigger.description();
|
||||||
|
|
@ -17,15 +17,11 @@ BlazeComponent.extendComponent({
|
||||||
return upperdesc;
|
return upperdesc;
|
||||||
},
|
},
|
||||||
action() {
|
action() {
|
||||||
const ruleId = this.data().ruleId;
|
const ruleId = Template.currentData().ruleId;
|
||||||
const rule = ReactiveCache.getRule(ruleId.get());
|
const rule = ReactiveCache.getRule(ruleId.get());
|
||||||
const action = ReactiveCache.getAction(rule.actionId);
|
const action = ReactiveCache.getAction(rule.actionId);
|
||||||
const desc = action.description();
|
const desc = action.description();
|
||||||
const upperdesc = desc.charAt(0).toUpperCase() + desc.substr(1);
|
const upperdesc = desc.charAt(0).toUpperCase() + desc.substr(1);
|
||||||
return upperdesc;
|
return upperdesc;
|
||||||
},
|
},
|
||||||
|
});
|
||||||
events() {
|
|
||||||
return [{}];
|
|
||||||
},
|
|
||||||
}).register('ruleDetails');
|
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,20 @@
|
||||||
import { ReactiveCache } from '/imports/reactiveCache';
|
import { ReactiveCache } from '/imports/reactiveCache';
|
||||||
|
|
||||||
BlazeComponent.extendComponent({
|
Template.rulesActions.onCreated(function () {
|
||||||
onCreated() {
|
this.currentActions = new ReactiveVar('board');
|
||||||
this.currentActions = new ReactiveVar('board');
|
});
|
||||||
|
|
||||||
|
Template.rulesActions.helpers({
|
||||||
|
currentActions() {
|
||||||
|
return Template.instance().currentActions;
|
||||||
|
},
|
||||||
|
|
||||||
|
data() {
|
||||||
|
return Template.currentData();
|
||||||
},
|
},
|
||||||
|
|
||||||
ruleNameStr() {
|
ruleNameStr() {
|
||||||
const rn = this.data() && this.data().ruleName;
|
const rn = Template.currentData() && Template.currentData().ruleName;
|
||||||
try {
|
try {
|
||||||
return rn && typeof rn.get === 'function' ? rn.get() : '';
|
return rn && typeof rn.get === 'function' ? rn.get() : '';
|
||||||
} catch (_) {
|
} catch (_) {
|
||||||
|
|
@ -14,59 +22,59 @@ BlazeComponent.extendComponent({
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
setBoardActions() {
|
|
||||||
this.currentActions.set('board');
|
|
||||||
$('.js-set-card-actions').removeClass('active');
|
|
||||||
$('.js-set-board-actions').addClass('active');
|
|
||||||
$('.js-set-checklist-actions').removeClass('active');
|
|
||||||
$('.js-set-mail-actions').removeClass('active');
|
|
||||||
},
|
|
||||||
setCardActions() {
|
|
||||||
this.currentActions.set('card');
|
|
||||||
$('.js-set-card-actions').addClass('active');
|
|
||||||
$('.js-set-board-actions').removeClass('active');
|
|
||||||
$('.js-set-checklist-actions').removeClass('active');
|
|
||||||
$('.js-set-mail-actions').removeClass('active');
|
|
||||||
},
|
|
||||||
setChecklistActions() {
|
|
||||||
this.currentActions.set('checklist');
|
|
||||||
$('.js-set-card-actions').removeClass('active');
|
|
||||||
$('.js-set-board-actions').removeClass('active');
|
|
||||||
$('.js-set-checklist-actions').addClass('active');
|
|
||||||
$('.js-set-mail-actions').removeClass('active');
|
|
||||||
},
|
|
||||||
setMailActions() {
|
|
||||||
this.currentActions.set('mail');
|
|
||||||
$('.js-set-card-actions').removeClass('active');
|
|
||||||
$('.js-set-board-actions').removeClass('active');
|
|
||||||
$('.js-set-checklist-actions').removeClass('active');
|
|
||||||
$('.js-set-mail-actions').addClass('active');
|
|
||||||
},
|
|
||||||
|
|
||||||
rules() {
|
rules() {
|
||||||
const ret = ReactiveCache.getRules({});
|
const ret = ReactiveCache.getRules({});
|
||||||
return ret;
|
return ret;
|
||||||
},
|
},
|
||||||
|
|
||||||
name() {
|
name() {
|
||||||
// console.log(this.data());
|
// console.log(Template.currentData());
|
||||||
},
|
},
|
||||||
events() {
|
});
|
||||||
return [
|
|
||||||
{
|
function setBoardActions(tpl) {
|
||||||
'click .js-set-board-actions'() {
|
tpl.currentActions.set('board');
|
||||||
this.setBoardActions();
|
$('.js-set-card-actions').removeClass('active');
|
||||||
},
|
$('.js-set-board-actions').addClass('active');
|
||||||
'click .js-set-card-actions'() {
|
$('.js-set-checklist-actions').removeClass('active');
|
||||||
this.setCardActions();
|
$('.js-set-mail-actions').removeClass('active');
|
||||||
},
|
}
|
||||||
'click .js-set-mail-actions'() {
|
|
||||||
this.setMailActions();
|
function setCardActions(tpl) {
|
||||||
},
|
tpl.currentActions.set('card');
|
||||||
'click .js-set-checklist-actions'() {
|
$('.js-set-card-actions').addClass('active');
|
||||||
this.setChecklistActions();
|
$('.js-set-board-actions').removeClass('active');
|
||||||
},
|
$('.js-set-checklist-actions').removeClass('active');
|
||||||
},
|
$('.js-set-mail-actions').removeClass('active');
|
||||||
];
|
}
|
||||||
|
|
||||||
|
function setChecklistActions(tpl) {
|
||||||
|
tpl.currentActions.set('checklist');
|
||||||
|
$('.js-set-card-actions').removeClass('active');
|
||||||
|
$('.js-set-board-actions').removeClass('active');
|
||||||
|
$('.js-set-checklist-actions').addClass('active');
|
||||||
|
$('.js-set-mail-actions').removeClass('active');
|
||||||
|
}
|
||||||
|
|
||||||
|
function setMailActions(tpl) {
|
||||||
|
tpl.currentActions.set('mail');
|
||||||
|
$('.js-set-card-actions').removeClass('active');
|
||||||
|
$('.js-set-board-actions').removeClass('active');
|
||||||
|
$('.js-set-checklist-actions').removeClass('active');
|
||||||
|
$('.js-set-mail-actions').addClass('active');
|
||||||
|
}
|
||||||
|
|
||||||
|
Template.rulesActions.events({
|
||||||
|
'click .js-set-board-actions'(event, tpl) {
|
||||||
|
setBoardActions(tpl);
|
||||||
},
|
},
|
||||||
}).register('rulesActions');
|
'click .js-set-card-actions'(event, tpl) {
|
||||||
|
setCardActions(tpl);
|
||||||
|
},
|
||||||
|
'click .js-set-mail-actions'(event, tpl) {
|
||||||
|
setMailActions(tpl);
|
||||||
|
},
|
||||||
|
'click .js-set-checklist-actions'(event, tpl) {
|
||||||
|
setChecklistActions(tpl);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
import { ReactiveCache } from '/imports/reactiveCache';
|
import { ReactiveCache } from '/imports/reactiveCache';
|
||||||
|
|
||||||
BlazeComponent.extendComponent({
|
Template.rulesList.onCreated(function () {
|
||||||
onCreated() {
|
this.subscribe('allRules');
|
||||||
this.subscribe('allRules');
|
});
|
||||||
},
|
|
||||||
|
|
||||||
|
Template.rulesList.helpers({
|
||||||
rules() {
|
rules() {
|
||||||
const boardId = Session.get('currentBoard');
|
const boardId = Session.get('currentBoard');
|
||||||
const ret = ReactiveCache.getRules({
|
const ret = ReactiveCache.getRules({
|
||||||
|
|
@ -12,7 +12,4 @@ BlazeComponent.extendComponent({
|
||||||
});
|
});
|
||||||
return ret;
|
return ret;
|
||||||
},
|
},
|
||||||
events() {
|
});
|
||||||
return [{}];
|
|
||||||
},
|
|
||||||
}).register('rulesList');
|
|
||||||
|
|
|
||||||
|
|
@ -1,103 +1,98 @@
|
||||||
import { ReactiveCache } from '/imports/reactiveCache';
|
import { ReactiveCache } from '/imports/reactiveCache';
|
||||||
|
|
||||||
BlazeComponent.extendComponent({
|
Template.rulesMain.onCreated(function () {
|
||||||
onCreated() {
|
this.rulesCurrentTab = new ReactiveVar('rulesList');
|
||||||
this.rulesCurrentTab = new ReactiveVar('rulesList');
|
this.ruleName = new ReactiveVar('');
|
||||||
this.ruleName = new ReactiveVar('');
|
this.triggerVar = new ReactiveVar();
|
||||||
this.triggerVar = new ReactiveVar();
|
this.ruleId = new ReactiveVar();
|
||||||
this.ruleId = new ReactiveVar();
|
});
|
||||||
},
|
|
||||||
|
|
||||||
setTrigger() {
|
Template.rulesMain.helpers({
|
||||||
this.rulesCurrentTab.set('trigger');
|
rulesCurrentTab() {
|
||||||
|
return Template.instance().rulesCurrentTab;
|
||||||
},
|
},
|
||||||
sanitizeObject(obj) {
|
ruleName() {
|
||||||
Object.keys(obj).forEach(key => {
|
return Template.instance().ruleName;
|
||||||
if (obj[key] === '' || obj[key] === undefined) {
|
},
|
||||||
obj[key] = '*';
|
triggerVar() {
|
||||||
|
return Template.instance().triggerVar;
|
||||||
|
},
|
||||||
|
ruleId() {
|
||||||
|
return Template.instance().ruleId;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
function sanitizeObject(obj) {
|
||||||
|
Object.keys(obj).forEach(key => {
|
||||||
|
if (obj[key] === '' || obj[key] === undefined) {
|
||||||
|
obj[key] = '*';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Template.rulesMain.events({
|
||||||
|
'click .js-delete-rule'() {
|
||||||
|
const rule = Template.currentData();
|
||||||
|
Rules.remove(rule._id);
|
||||||
|
Actions.remove(rule.actionId);
|
||||||
|
Triggers.remove(rule.triggerId);
|
||||||
|
},
|
||||||
|
'click .js-goto-trigger'(event, tpl) {
|
||||||
|
event.preventDefault();
|
||||||
|
const ruleTitle = tpl.find('#ruleTitle').value;
|
||||||
|
if (ruleTitle !== undefined && ruleTitle !== '') {
|
||||||
|
tpl.find('#ruleTitle').value = '';
|
||||||
|
tpl.ruleName.set(ruleTitle);
|
||||||
|
tpl.rulesCurrentTab.set('trigger');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'click .js-goto-action'(event, tpl) {
|
||||||
|
event.preventDefault();
|
||||||
|
// Add user to the trigger
|
||||||
|
const username = $(event.currentTarget.offsetParent)
|
||||||
|
.find('.user-name')
|
||||||
|
.val();
|
||||||
|
let trigger = tpl.triggerVar.get();
|
||||||
|
trigger.userId = '*';
|
||||||
|
if (username !== undefined) {
|
||||||
|
const userFound = ReactiveCache.getUser({ username });
|
||||||
|
if (userFound !== undefined) {
|
||||||
|
trigger.userId = userFound._id;
|
||||||
|
tpl.triggerVar.set(trigger);
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
// Sanitize trigger
|
||||||
|
trigger = tpl.triggerVar.get();
|
||||||
|
sanitizeObject(trigger);
|
||||||
|
tpl.triggerVar.set(trigger);
|
||||||
|
tpl.rulesCurrentTab.set('action');
|
||||||
},
|
},
|
||||||
setRulesList() {
|
'click .js-show-user-field'(event) {
|
||||||
this.rulesCurrentTab.set('rulesList');
|
event.preventDefault();
|
||||||
|
$(event.currentTarget.offsetParent)
|
||||||
|
.find('.user-details')
|
||||||
|
.removeClass('hide-element');
|
||||||
},
|
},
|
||||||
|
'click .js-goto-rules'(event, tpl) {
|
||||||
setAction() {
|
event.preventDefault();
|
||||||
this.rulesCurrentTab.set('action');
|
tpl.rulesCurrentTab.set('rulesList');
|
||||||
},
|
},
|
||||||
|
'click .js-goback'(event, tpl) {
|
||||||
setRuleDetails() {
|
event.preventDefault();
|
||||||
this.rulesCurrentTab.set('ruleDetails');
|
if (
|
||||||
|
tpl.rulesCurrentTab.get() === 'trigger' ||
|
||||||
|
tpl.rulesCurrentTab.get() === 'ruleDetails'
|
||||||
|
) {
|
||||||
|
tpl.rulesCurrentTab.set('rulesList');
|
||||||
|
}
|
||||||
|
if (tpl.rulesCurrentTab.get() === 'action') {
|
||||||
|
tpl.rulesCurrentTab.set('trigger');
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
'click .js-goto-details'(event, tpl) {
|
||||||
events() {
|
event.preventDefault();
|
||||||
return [
|
const rule = Template.currentData();
|
||||||
{
|
tpl.ruleId.set(rule._id);
|
||||||
'click .js-delete-rule'() {
|
tpl.rulesCurrentTab.set('ruleDetails');
|
||||||
const rule = this.currentData();
|
|
||||||
Rules.remove(rule._id);
|
|
||||||
Actions.remove(rule.actionId);
|
|
||||||
Triggers.remove(rule.triggerId);
|
|
||||||
},
|
|
||||||
'click .js-goto-trigger'(event) {
|
|
||||||
event.preventDefault();
|
|
||||||
const ruleTitle = this.find('#ruleTitle').value;
|
|
||||||
if (ruleTitle !== undefined && ruleTitle !== '') {
|
|
||||||
this.find('#ruleTitle').value = '';
|
|
||||||
this.ruleName.set(ruleTitle);
|
|
||||||
this.setTrigger();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
'click .js-goto-action'(event) {
|
|
||||||
event.preventDefault();
|
|
||||||
// Add user to the trigger
|
|
||||||
const username = $(event.currentTarget.offsetParent)
|
|
||||||
.find('.user-name')
|
|
||||||
.val();
|
|
||||||
let trigger = this.triggerVar.get();
|
|
||||||
trigger.userId = '*';
|
|
||||||
if (username !== undefined) {
|
|
||||||
const userFound = ReactiveCache.getUser({ username });
|
|
||||||
if (userFound !== undefined) {
|
|
||||||
trigger.userId = userFound._id;
|
|
||||||
this.triggerVar.set(trigger);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Sanitize trigger
|
|
||||||
trigger = this.triggerVar.get();
|
|
||||||
this.sanitizeObject(trigger);
|
|
||||||
this.triggerVar.set(trigger);
|
|
||||||
this.setAction();
|
|
||||||
},
|
|
||||||
'click .js-show-user-field'(event) {
|
|
||||||
event.preventDefault();
|
|
||||||
$(event.currentTarget.offsetParent)
|
|
||||||
.find('.user-details')
|
|
||||||
.removeClass('hide-element');
|
|
||||||
},
|
|
||||||
'click .js-goto-rules'(event) {
|
|
||||||
event.preventDefault();
|
|
||||||
this.setRulesList();
|
|
||||||
},
|
|
||||||
'click .js-goback'(event) {
|
|
||||||
event.preventDefault();
|
|
||||||
if (
|
|
||||||
this.rulesCurrentTab.get() === 'trigger' ||
|
|
||||||
this.rulesCurrentTab.get() === 'ruleDetails'
|
|
||||||
) {
|
|
||||||
this.setRulesList();
|
|
||||||
}
|
|
||||||
if (this.rulesCurrentTab.get() === 'action') {
|
|
||||||
this.setTrigger();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
'click .js-goto-details'(event) {
|
|
||||||
event.preventDefault();
|
|
||||||
const rule = this.currentData();
|
|
||||||
this.ruleId.set(rule._id);
|
|
||||||
this.setRuleDetails();
|
|
||||||
},
|
|
||||||
},
|
|
||||||
];
|
|
||||||
},
|
},
|
||||||
}).register('rulesMain');
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,14 @@
|
||||||
import { ReactiveCache } from '/imports/reactiveCache';
|
import { ReactiveCache } from '/imports/reactiveCache';
|
||||||
|
|
||||||
BlazeComponent.extendComponent({
|
Template.rulesTriggers.onCreated(function () {
|
||||||
onCreated() {
|
this.showBoardTrigger = new ReactiveVar(true);
|
||||||
this.showBoardTrigger = new ReactiveVar(true);
|
this.showCardTrigger = new ReactiveVar(false);
|
||||||
this.showCardTrigger = new ReactiveVar(false);
|
this.showChecklistTrigger = new ReactiveVar(false);
|
||||||
this.showChecklistTrigger = new ReactiveVar(false);
|
});
|
||||||
},
|
|
||||||
|
|
||||||
|
Template.rulesTriggers.helpers({
|
||||||
ruleNameStr() {
|
ruleNameStr() {
|
||||||
const rn = this.data() && this.data().ruleName;
|
const rn = Template.currentData() && Template.currentData().ruleName;
|
||||||
try {
|
try {
|
||||||
return rn && typeof rn.get === 'function' ? rn.get() : '';
|
return rn && typeof rn.get === 'function' ? rn.get() : '';
|
||||||
} catch (_) {
|
} catch (_) {
|
||||||
|
|
@ -16,29 +16,16 @@ BlazeComponent.extendComponent({
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
setBoardTriggers() {
|
showBoardTrigger() {
|
||||||
this.showBoardTrigger.set(true);
|
return Template.instance().showBoardTrigger;
|
||||||
this.showCardTrigger.set(false);
|
|
||||||
this.showChecklistTrigger.set(false);
|
|
||||||
$('.js-set-card-triggers').removeClass('active');
|
|
||||||
$('.js-set-board-triggers').addClass('active');
|
|
||||||
$('.js-set-checklist-triggers').removeClass('active');
|
|
||||||
},
|
},
|
||||||
setCardTriggers() {
|
|
||||||
this.showBoardTrigger.set(false);
|
showCardTrigger() {
|
||||||
this.showCardTrigger.set(true);
|
return Template.instance().showCardTrigger;
|
||||||
this.showChecklistTrigger.set(false);
|
|
||||||
$('.js-set-card-triggers').addClass('active');
|
|
||||||
$('.js-set-board-triggers').removeClass('active');
|
|
||||||
$('.js-set-checklist-triggers').removeClass('active');
|
|
||||||
},
|
},
|
||||||
setChecklistTriggers() {
|
|
||||||
this.showBoardTrigger.set(false);
|
showChecklistTrigger() {
|
||||||
this.showCardTrigger.set(false);
|
return Template.instance().showChecklistTrigger;
|
||||||
this.showChecklistTrigger.set(true);
|
|
||||||
$('.js-set-card-triggers').removeClass('active');
|
|
||||||
$('.js-set-board-triggers').removeClass('active');
|
|
||||||
$('.js-set-checklist-triggers').addClass('active');
|
|
||||||
},
|
},
|
||||||
|
|
||||||
rules() {
|
rules() {
|
||||||
|
|
@ -47,21 +34,45 @@ BlazeComponent.extendComponent({
|
||||||
},
|
},
|
||||||
|
|
||||||
name() {
|
name() {
|
||||||
// console.log(this.data());
|
// console.log(Template.currentData());
|
||||||
},
|
},
|
||||||
events() {
|
});
|
||||||
return [
|
|
||||||
{
|
function setBoardTriggers(tpl) {
|
||||||
'click .js-set-board-triggers'() {
|
tpl.showBoardTrigger.set(true);
|
||||||
this.setBoardTriggers();
|
tpl.showCardTrigger.set(false);
|
||||||
},
|
tpl.showChecklistTrigger.set(false);
|
||||||
'click .js-set-card-triggers'() {
|
$('.js-set-card-triggers').removeClass('active');
|
||||||
this.setCardTriggers();
|
$('.js-set-board-triggers').addClass('active');
|
||||||
},
|
$('.js-set-checklist-triggers').removeClass('active');
|
||||||
'click .js-set-checklist-triggers'() {
|
}
|
||||||
this.setChecklistTriggers();
|
|
||||||
},
|
function setCardTriggers(tpl) {
|
||||||
},
|
tpl.showBoardTrigger.set(false);
|
||||||
];
|
tpl.showCardTrigger.set(true);
|
||||||
|
tpl.showChecklistTrigger.set(false);
|
||||||
|
$('.js-set-card-triggers').addClass('active');
|
||||||
|
$('.js-set-board-triggers').removeClass('active');
|
||||||
|
$('.js-set-checklist-triggers').removeClass('active');
|
||||||
|
}
|
||||||
|
|
||||||
|
function setChecklistTriggers(tpl) {
|
||||||
|
tpl.showBoardTrigger.set(false);
|
||||||
|
tpl.showCardTrigger.set(false);
|
||||||
|
tpl.showChecklistTrigger.set(true);
|
||||||
|
$('.js-set-card-triggers').removeClass('active');
|
||||||
|
$('.js-set-board-triggers').removeClass('active');
|
||||||
|
$('.js-set-checklist-triggers').addClass('active');
|
||||||
|
}
|
||||||
|
|
||||||
|
Template.rulesTriggers.events({
|
||||||
|
'click .js-set-board-triggers'(event, tpl) {
|
||||||
|
setBoardTriggers(tpl);
|
||||||
},
|
},
|
||||||
}).register('rulesTriggers');
|
'click .js-set-card-triggers'(event, tpl) {
|
||||||
|
setCardTriggers(tpl);
|
||||||
|
},
|
||||||
|
'click .js-set-checklist-triggers'(event, tpl) {
|
||||||
|
setChecklistTriggers(tpl);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,120 +1,115 @@
|
||||||
BlazeComponent.extendComponent({
|
Template.boardTriggers.onCreated(function () {
|
||||||
onCreated() {
|
this.provaVar = new ReactiveVar('');
|
||||||
this.provaVar = new ReactiveVar('');
|
this.currentPopupTriggerId = 'def';
|
||||||
this.currentPopupTriggerId = 'def';
|
this.cardTitleFilters = {};
|
||||||
this.cardTitleFilters = {};
|
this.setNameFilter = (name) => {
|
||||||
},
|
|
||||||
setNameFilter(name) {
|
|
||||||
this.cardTitleFilters[this.currentPopupTriggerId] = name;
|
this.cardTitleFilters[this.currentPopupTriggerId] = name;
|
||||||
},
|
};
|
||||||
|
});
|
||||||
|
|
||||||
events() {
|
Template.boardTriggers.events({
|
||||||
return [
|
'click .js-open-card-title-popup'(event, tpl) {
|
||||||
{
|
const funct = Popup.open('boardCardTitle');
|
||||||
'click .js-open-card-title-popup'(event) {
|
const divId = $(event.currentTarget.parentNode.parentNode).attr('id');
|
||||||
const funct = Popup.open('boardCardTitle');
|
tpl.currentPopupTriggerId = divId;
|
||||||
const divId = $(event.currentTarget.parentNode.parentNode).attr('id');
|
funct.call(this, event);
|
||||||
//console.log('current popup');
|
|
||||||
//console.log(this.currentPopupTriggerId);
|
|
||||||
this.currentPopupTriggerId = divId;
|
|
||||||
funct.call(this, event);
|
|
||||||
},
|
|
||||||
'click .js-add-create-trigger'(event) {
|
|
||||||
const desc = Utils.getTriggerActionDesc(event, this);
|
|
||||||
const datas = this.data();
|
|
||||||
const listName = this.find('#create-list-name').value;
|
|
||||||
const swimlaneName = this.find('#create-swimlane-name').value;
|
|
||||||
const boardId = Session.get('currentBoard');
|
|
||||||
const divId = $(event.currentTarget.parentNode).attr('id');
|
|
||||||
const cardTitle = this.cardTitleFilters[divId];
|
|
||||||
// move to generic funciont
|
|
||||||
datas.triggerVar.set({
|
|
||||||
activityType: 'createCard',
|
|
||||||
boardId,
|
|
||||||
cardTitle,
|
|
||||||
swimlaneName,
|
|
||||||
listName,
|
|
||||||
desc,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
'click .js-add-moved-trigger'(event) {
|
|
||||||
const datas = this.data();
|
|
||||||
const desc = Utils.getTriggerActionDesc(event, this);
|
|
||||||
const swimlaneName = this.find('#create-swimlane-name-2').value;
|
|
||||||
const actionSelected = this.find('#move-action').value;
|
|
||||||
const listName = this.find('#move-list-name').value;
|
|
||||||
const boardId = Session.get('currentBoard');
|
|
||||||
const divId = $(event.currentTarget.parentNode).attr('id');
|
|
||||||
const cardTitle = this.cardTitleFilters[divId];
|
|
||||||
if (actionSelected === 'moved-to') {
|
|
||||||
datas.triggerVar.set({
|
|
||||||
activityType: 'moveCard',
|
|
||||||
boardId,
|
|
||||||
listName,
|
|
||||||
cardTitle,
|
|
||||||
swimlaneName,
|
|
||||||
oldListName: '*',
|
|
||||||
desc,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (actionSelected === 'moved-from') {
|
|
||||||
datas.triggerVar.set({
|
|
||||||
activityType: 'moveCard',
|
|
||||||
boardId,
|
|
||||||
cardTitle,
|
|
||||||
swimlaneName,
|
|
||||||
listName: '*',
|
|
||||||
oldListName: listName,
|
|
||||||
desc,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
'click .js-add-gen-moved-trigger'(event) {
|
|
||||||
const datas = this.data();
|
|
||||||
const desc = Utils.getTriggerActionDesc(event, this);
|
|
||||||
const boardId = Session.get('currentBoard');
|
|
||||||
|
|
||||||
datas.triggerVar.set({
|
|
||||||
activityType: 'moveCard',
|
|
||||||
boardId,
|
|
||||||
swimlaneName: '*',
|
|
||||||
listName: '*',
|
|
||||||
oldListName: '*',
|
|
||||||
desc,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
'click .js-add-arc-trigger'(event) {
|
|
||||||
const datas = this.data();
|
|
||||||
const desc = Utils.getTriggerActionDesc(event, this);
|
|
||||||
const actionSelected = this.find('#arch-action').value;
|
|
||||||
const boardId = Session.get('currentBoard');
|
|
||||||
if (actionSelected === 'archived') {
|
|
||||||
datas.triggerVar.set({
|
|
||||||
activityType: 'archivedCard',
|
|
||||||
boardId,
|
|
||||||
desc,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (actionSelected === 'unarchived') {
|
|
||||||
datas.triggerVar.set({
|
|
||||||
activityType: 'restoredCard',
|
|
||||||
boardId,
|
|
||||||
desc,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
];
|
|
||||||
},
|
},
|
||||||
}).register('boardTriggers');
|
'click .js-add-create-trigger'(event, tpl) {
|
||||||
|
const desc = Utils.getTriggerActionDesc(event, tpl);
|
||||||
|
const datas = Template.currentData();
|
||||||
|
const listName = tpl.find('#create-list-name').value;
|
||||||
|
const swimlaneName = tpl.find('#create-swimlane-name').value;
|
||||||
|
const boardId = Session.get('currentBoard');
|
||||||
|
const divId = $(event.currentTarget.parentNode).attr('id');
|
||||||
|
const cardTitle = tpl.cardTitleFilters[divId];
|
||||||
|
// move to generic funciont
|
||||||
|
datas.triggerVar.set({
|
||||||
|
activityType: 'createCard',
|
||||||
|
boardId,
|
||||||
|
cardTitle,
|
||||||
|
swimlaneName,
|
||||||
|
listName,
|
||||||
|
desc,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
'click .js-add-moved-trigger'(event, tpl) {
|
||||||
|
const datas = Template.currentData();
|
||||||
|
const desc = Utils.getTriggerActionDesc(event, tpl);
|
||||||
|
const swimlaneName = tpl.find('#create-swimlane-name-2').value;
|
||||||
|
const actionSelected = tpl.find('#move-action').value;
|
||||||
|
const listName = tpl.find('#move-list-name').value;
|
||||||
|
const boardId = Session.get('currentBoard');
|
||||||
|
const divId = $(event.currentTarget.parentNode).attr('id');
|
||||||
|
const cardTitle = tpl.cardTitleFilters[divId];
|
||||||
|
if (actionSelected === 'moved-to') {
|
||||||
|
datas.triggerVar.set({
|
||||||
|
activityType: 'moveCard',
|
||||||
|
boardId,
|
||||||
|
listName,
|
||||||
|
cardTitle,
|
||||||
|
swimlaneName,
|
||||||
|
oldListName: '*',
|
||||||
|
desc,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (actionSelected === 'moved-from') {
|
||||||
|
datas.triggerVar.set({
|
||||||
|
activityType: 'moveCard',
|
||||||
|
boardId,
|
||||||
|
cardTitle,
|
||||||
|
swimlaneName,
|
||||||
|
listName: '*',
|
||||||
|
oldListName: listName,
|
||||||
|
desc,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'click .js-add-gen-moved-trigger'(event, tpl) {
|
||||||
|
const datas = Template.currentData();
|
||||||
|
const desc = Utils.getTriggerActionDesc(event, tpl);
|
||||||
|
const boardId = Session.get('currentBoard');
|
||||||
|
|
||||||
|
datas.triggerVar.set({
|
||||||
|
activityType: 'moveCard',
|
||||||
|
boardId,
|
||||||
|
swimlaneName: '*',
|
||||||
|
listName: '*',
|
||||||
|
oldListName: '*',
|
||||||
|
desc,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
'click .js-add-arc-trigger'(event, tpl) {
|
||||||
|
const datas = Template.currentData();
|
||||||
|
const desc = Utils.getTriggerActionDesc(event, tpl);
|
||||||
|
const actionSelected = tpl.find('#arch-action').value;
|
||||||
|
const boardId = Session.get('currentBoard');
|
||||||
|
if (actionSelected === 'archived') {
|
||||||
|
datas.triggerVar.set({
|
||||||
|
activityType: 'archivedCard',
|
||||||
|
boardId,
|
||||||
|
desc,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (actionSelected === 'unarchived') {
|
||||||
|
datas.triggerVar.set({
|
||||||
|
activityType: 'restoredCard',
|
||||||
|
boardId,
|
||||||
|
desc,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
Template.boardCardTitlePopup.events({
|
Template.boardCardTitlePopup.events({
|
||||||
submit(event, templateInstance) {
|
submit(event) {
|
||||||
const title = templateInstance
|
const title = $(event.target)
|
||||||
.$('.js-card-filter-name')
|
.find('.js-card-filter-name')
|
||||||
.val()
|
.val()
|
||||||
.trim();
|
.trim();
|
||||||
Popup.getOpenerComponent().setNameFilter(title);
|
const opener = Popup.getOpenerComponent();
|
||||||
|
if (opener?.setNameFilter) {
|
||||||
|
opener.setNameFilter(title);
|
||||||
|
}
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
Popup.back();
|
Popup.back();
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,10 @@
|
||||||
import { TAPi18n } from '/imports/i18n';
|
import { TAPi18n } from '/imports/i18n';
|
||||||
|
|
||||||
BlazeComponent.extendComponent({
|
Template.cardTriggers.onCreated(function () {
|
||||||
onCreated() {
|
this.subscribe('allRules');
|
||||||
this.subscribe('allRules');
|
});
|
||||||
},
|
|
||||||
|
Template.cardTriggers.helpers({
|
||||||
labels() {
|
labels() {
|
||||||
const labels = Utils.getCurrentBoard().labels;
|
const labels = Utils.getCurrentBoard().labels;
|
||||||
for (let i = 0; i < labels.length; i++) {
|
for (let i = 0; i < labels.length; i++) {
|
||||||
|
|
@ -16,120 +17,117 @@ BlazeComponent.extendComponent({
|
||||||
}
|
}
|
||||||
return labels;
|
return labels;
|
||||||
},
|
},
|
||||||
events() {
|
});
|
||||||
return [
|
|
||||||
{
|
Template.cardTriggers.events({
|
||||||
'click .js-add-gen-label-trigger'(event) {
|
'click .js-add-gen-label-trigger'(event, tpl) {
|
||||||
const desc = Utils.getTriggerActionDesc(event, this);
|
const desc = Utils.getTriggerActionDesc(event, tpl);
|
||||||
const datas = this.data();
|
const datas = Template.currentData();
|
||||||
const actionSelected = this.find('#label-action').value;
|
const actionSelected = tpl.find('#label-action').value;
|
||||||
const boardId = Session.get('currentBoard');
|
const boardId = Session.get('currentBoard');
|
||||||
if (actionSelected === 'added') {
|
if (actionSelected === 'added') {
|
||||||
datas.triggerVar.set({
|
datas.triggerVar.set({
|
||||||
activityType: 'addedLabel',
|
activityType: 'addedLabel',
|
||||||
boardId,
|
boardId,
|
||||||
labelId: '*',
|
labelId: '*',
|
||||||
desc,
|
desc,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (actionSelected === 'removed') {
|
if (actionSelected === 'removed') {
|
||||||
datas.triggerVar.set({
|
datas.triggerVar.set({
|
||||||
activityType: 'removedLabel',
|
activityType: 'removedLabel',
|
||||||
boardId,
|
boardId,
|
||||||
labelId: '*',
|
labelId: '*',
|
||||||
desc,
|
desc,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
|
||||||
'click .js-add-spec-label-trigger'(event) {
|
|
||||||
const desc = Utils.getTriggerActionDesc(event, this);
|
|
||||||
const datas = this.data();
|
|
||||||
const actionSelected = this.find('#spec-label-action').value;
|
|
||||||
const labelId = this.find('#spec-label').value;
|
|
||||||
const boardId = Session.get('currentBoard');
|
|
||||||
if (actionSelected === 'added') {
|
|
||||||
datas.triggerVar.set({
|
|
||||||
activityType: 'addedLabel',
|
|
||||||
boardId,
|
|
||||||
labelId,
|
|
||||||
desc,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (actionSelected === 'removed') {
|
|
||||||
datas.triggerVar.set({
|
|
||||||
activityType: 'removedLabel',
|
|
||||||
boardId,
|
|
||||||
labelId,
|
|
||||||
desc,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
'click .js-add-gen-member-trigger'(event) {
|
|
||||||
const desc = Utils.getTriggerActionDesc(event, this);
|
|
||||||
const datas = this.data();
|
|
||||||
const actionSelected = this.find('#gen-member-action').value;
|
|
||||||
const boardId = Session.get('currentBoard');
|
|
||||||
if (actionSelected === 'added') {
|
|
||||||
datas.triggerVar.set({
|
|
||||||
activityType: 'joinMember',
|
|
||||||
boardId,
|
|
||||||
username: '*',
|
|
||||||
desc,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (actionSelected === 'removed') {
|
|
||||||
datas.triggerVar.set({
|
|
||||||
activityType: 'unjoinMember',
|
|
||||||
boardId,
|
|
||||||
username: '*',
|
|
||||||
desc,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
'click .js-add-spec-member-trigger'(event) {
|
|
||||||
const desc = Utils.getTriggerActionDesc(event, this);
|
|
||||||
const datas = this.data();
|
|
||||||
const actionSelected = this.find('#spec-member-action').value;
|
|
||||||
const username = this.find('#spec-member').value;
|
|
||||||
const boardId = Session.get('currentBoard');
|
|
||||||
if (actionSelected === 'added') {
|
|
||||||
datas.triggerVar.set({
|
|
||||||
activityType: 'joinMember',
|
|
||||||
boardId,
|
|
||||||
username,
|
|
||||||
desc,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (actionSelected === 'removed') {
|
|
||||||
datas.triggerVar.set({
|
|
||||||
activityType: 'unjoinMember',
|
|
||||||
boardId,
|
|
||||||
username,
|
|
||||||
desc,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
'click .js-add-attachment-trigger'(event) {
|
|
||||||
const desc = Utils.getTriggerActionDesc(event, this);
|
|
||||||
const datas = this.data();
|
|
||||||
const actionSelected = this.find('#attach-action').value;
|
|
||||||
const boardId = Session.get('currentBoard');
|
|
||||||
if (actionSelected === 'added') {
|
|
||||||
datas.triggerVar.set({
|
|
||||||
activityType: 'addAttachment',
|
|
||||||
boardId,
|
|
||||||
desc,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (actionSelected === 'removed') {
|
|
||||||
datas.triggerVar.set({
|
|
||||||
activityType: 'deleteAttachment',
|
|
||||||
boardId,
|
|
||||||
desc,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
];
|
|
||||||
},
|
},
|
||||||
}).register('cardTriggers');
|
'click .js-add-spec-label-trigger'(event, tpl) {
|
||||||
|
const desc = Utils.getTriggerActionDesc(event, tpl);
|
||||||
|
const datas = Template.currentData();
|
||||||
|
const actionSelected = tpl.find('#spec-label-action').value;
|
||||||
|
const labelId = tpl.find('#spec-label').value;
|
||||||
|
const boardId = Session.get('currentBoard');
|
||||||
|
if (actionSelected === 'added') {
|
||||||
|
datas.triggerVar.set({
|
||||||
|
activityType: 'addedLabel',
|
||||||
|
boardId,
|
||||||
|
labelId,
|
||||||
|
desc,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (actionSelected === 'removed') {
|
||||||
|
datas.triggerVar.set({
|
||||||
|
activityType: 'removedLabel',
|
||||||
|
boardId,
|
||||||
|
labelId,
|
||||||
|
desc,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'click .js-add-gen-member-trigger'(event, tpl) {
|
||||||
|
const desc = Utils.getTriggerActionDesc(event, tpl);
|
||||||
|
const datas = Template.currentData();
|
||||||
|
const actionSelected = tpl.find('#gen-member-action').value;
|
||||||
|
const boardId = Session.get('currentBoard');
|
||||||
|
if (actionSelected === 'added') {
|
||||||
|
datas.triggerVar.set({
|
||||||
|
activityType: 'joinMember',
|
||||||
|
boardId,
|
||||||
|
username: '*',
|
||||||
|
desc,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (actionSelected === 'removed') {
|
||||||
|
datas.triggerVar.set({
|
||||||
|
activityType: 'unjoinMember',
|
||||||
|
boardId,
|
||||||
|
username: '*',
|
||||||
|
desc,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'click .js-add-spec-member-trigger'(event, tpl) {
|
||||||
|
const desc = Utils.getTriggerActionDesc(event, tpl);
|
||||||
|
const datas = Template.currentData();
|
||||||
|
const actionSelected = tpl.find('#spec-member-action').value;
|
||||||
|
const username = tpl.find('#spec-member').value;
|
||||||
|
const boardId = Session.get('currentBoard');
|
||||||
|
if (actionSelected === 'added') {
|
||||||
|
datas.triggerVar.set({
|
||||||
|
activityType: 'joinMember',
|
||||||
|
boardId,
|
||||||
|
username,
|
||||||
|
desc,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (actionSelected === 'removed') {
|
||||||
|
datas.triggerVar.set({
|
||||||
|
activityType: 'unjoinMember',
|
||||||
|
boardId,
|
||||||
|
username,
|
||||||
|
desc,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'click .js-add-attachment-trigger'(event, tpl) {
|
||||||
|
const desc = Utils.getTriggerActionDesc(event, tpl);
|
||||||
|
const datas = Template.currentData();
|
||||||
|
const actionSelected = tpl.find('#attach-action').value;
|
||||||
|
const boardId = Session.get('currentBoard');
|
||||||
|
if (actionSelected === 'added') {
|
||||||
|
datas.triggerVar.set({
|
||||||
|
activityType: 'addAttachment',
|
||||||
|
boardId,
|
||||||
|
desc,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (actionSelected === 'removed') {
|
||||||
|
datas.triggerVar.set({
|
||||||
|
activityType: 'deleteAttachment',
|
||||||
|
boardId,
|
||||||
|
desc,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,147 +1,142 @@
|
||||||
BlazeComponent.extendComponent({
|
Template.checklistTriggers.onCreated(function () {
|
||||||
onCreated() {
|
this.subscribe('allRules');
|
||||||
this.subscribe('allRules');
|
});
|
||||||
},
|
|
||||||
events() {
|
|
||||||
return [
|
|
||||||
{
|
|
||||||
'click .js-add-gen-check-trigger'(event) {
|
|
||||||
const desc = Utils.getTriggerActionDesc(event, this);
|
|
||||||
const datas = this.data();
|
|
||||||
const actionSelected = this.find('#gen-check-action').value;
|
|
||||||
const boardId = Session.get('currentBoard');
|
|
||||||
if (actionSelected === 'created') {
|
|
||||||
datas.triggerVar.set({
|
|
||||||
activityType: 'addChecklist',
|
|
||||||
boardId,
|
|
||||||
checklistName: '*',
|
|
||||||
desc,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (actionSelected === 'removed') {
|
|
||||||
datas.triggerVar.set({
|
|
||||||
activityType: 'removeChecklist',
|
|
||||||
boardId,
|
|
||||||
checklistName: '*',
|
|
||||||
desc,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
'click .js-add-spec-check-trigger'(event) {
|
|
||||||
const desc = Utils.getTriggerActionDesc(event, this);
|
|
||||||
const datas = this.data();
|
|
||||||
const actionSelected = this.find('#spec-check-action').value;
|
|
||||||
const checklistId = this.find('#check-name').value;
|
|
||||||
const boardId = Session.get('currentBoard');
|
|
||||||
if (actionSelected === 'created') {
|
|
||||||
datas.triggerVar.set({
|
|
||||||
activityType: 'addChecklist',
|
|
||||||
boardId,
|
|
||||||
checklistName: checklistId,
|
|
||||||
desc,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (actionSelected === 'removed') {
|
|
||||||
datas.triggerVar.set({
|
|
||||||
activityType: 'removeChecklist',
|
|
||||||
boardId,
|
|
||||||
checklistName: checklistId,
|
|
||||||
desc,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
'click .js-add-gen-comp-trigger'(event) {
|
|
||||||
const desc = Utils.getTriggerActionDesc(event, this);
|
|
||||||
|
|
||||||
const datas = this.data();
|
Template.checklistTriggers.events({
|
||||||
const actionSelected = this.find('#gen-comp-check-action').value;
|
'click .js-add-gen-check-trigger'(event, tpl) {
|
||||||
const boardId = Session.get('currentBoard');
|
const desc = Utils.getTriggerActionDesc(event, tpl);
|
||||||
if (actionSelected === 'completed') {
|
const datas = Template.currentData();
|
||||||
datas.triggerVar.set({
|
const actionSelected = tpl.find('#gen-check-action').value;
|
||||||
activityType: 'completeChecklist',
|
const boardId = Session.get('currentBoard');
|
||||||
boardId,
|
if (actionSelected === 'created') {
|
||||||
checklistName: '*',
|
datas.triggerVar.set({
|
||||||
desc,
|
activityType: 'addChecklist',
|
||||||
});
|
boardId,
|
||||||
}
|
checklistName: '*',
|
||||||
if (actionSelected === 'uncompleted') {
|
desc,
|
||||||
datas.triggerVar.set({
|
});
|
||||||
activityType: 'uncompleteChecklist',
|
}
|
||||||
boardId,
|
if (actionSelected === 'removed') {
|
||||||
checklistName: '*',
|
datas.triggerVar.set({
|
||||||
desc,
|
activityType: 'removeChecklist',
|
||||||
});
|
boardId,
|
||||||
}
|
checklistName: '*',
|
||||||
},
|
desc,
|
||||||
'click .js-add-spec-comp-trigger'(event) {
|
});
|
||||||
const desc = Utils.getTriggerActionDesc(event, this);
|
}
|
||||||
const datas = this.data();
|
|
||||||
const actionSelected = this.find('#spec-comp-check-action').value;
|
|
||||||
const checklistId = this.find('#spec-comp-check-name').value;
|
|
||||||
const boardId = Session.get('currentBoard');
|
|
||||||
if (actionSelected === 'completed') {
|
|
||||||
datas.triggerVar.set({
|
|
||||||
activityType: 'completeChecklist',
|
|
||||||
boardId,
|
|
||||||
checklistName: checklistId,
|
|
||||||
desc,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (actionSelected === 'uncompleted') {
|
|
||||||
datas.triggerVar.set({
|
|
||||||
activityType: 'uncompleteChecklist',
|
|
||||||
boardId,
|
|
||||||
checklistName: checklistId,
|
|
||||||
desc,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
'click .js-add-gen-check-item-trigger'(event) {
|
|
||||||
const desc = Utils.getTriggerActionDesc(event, this);
|
|
||||||
const datas = this.data();
|
|
||||||
const actionSelected = this.find('#check-item-gen-action').value;
|
|
||||||
const boardId = Session.get('currentBoard');
|
|
||||||
if (actionSelected === 'checked') {
|
|
||||||
datas.triggerVar.set({
|
|
||||||
activityType: 'checkedItem',
|
|
||||||
boardId,
|
|
||||||
checklistItemName: '*',
|
|
||||||
desc,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (actionSelected === 'unchecked') {
|
|
||||||
datas.triggerVar.set({
|
|
||||||
activityType: 'uncheckedItem',
|
|
||||||
boardId,
|
|
||||||
checklistItemName: '*',
|
|
||||||
desc,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
'click .js-add-spec-check-item-trigger'(event) {
|
|
||||||
const desc = Utils.getTriggerActionDesc(event, this);
|
|
||||||
const datas = this.data();
|
|
||||||
const actionSelected = this.find('#check-item-spec-action').value;
|
|
||||||
const checklistItemId = this.find('#check-item-name').value;
|
|
||||||
const boardId = Session.get('currentBoard');
|
|
||||||
if (actionSelected === 'checked') {
|
|
||||||
datas.triggerVar.set({
|
|
||||||
activityType: 'checkedItem',
|
|
||||||
boardId,
|
|
||||||
checklistItemName: checklistItemId,
|
|
||||||
desc,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (actionSelected === 'unchecked') {
|
|
||||||
datas.triggerVar.set({
|
|
||||||
activityType: 'uncheckedItem',
|
|
||||||
boardId,
|
|
||||||
checklistItemName: checklistItemId,
|
|
||||||
desc,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
];
|
|
||||||
},
|
},
|
||||||
}).register('checklistTriggers');
|
'click .js-add-spec-check-trigger'(event, tpl) {
|
||||||
|
const desc = Utils.getTriggerActionDesc(event, tpl);
|
||||||
|
const datas = Template.currentData();
|
||||||
|
const actionSelected = tpl.find('#spec-check-action').value;
|
||||||
|
const checklistId = tpl.find('#check-name').value;
|
||||||
|
const boardId = Session.get('currentBoard');
|
||||||
|
if (actionSelected === 'created') {
|
||||||
|
datas.triggerVar.set({
|
||||||
|
activityType: 'addChecklist',
|
||||||
|
boardId,
|
||||||
|
checklistName: checklistId,
|
||||||
|
desc,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (actionSelected === 'removed') {
|
||||||
|
datas.triggerVar.set({
|
||||||
|
activityType: 'removeChecklist',
|
||||||
|
boardId,
|
||||||
|
checklistName: checklistId,
|
||||||
|
desc,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'click .js-add-gen-comp-trigger'(event, tpl) {
|
||||||
|
const desc = Utils.getTriggerActionDesc(event, tpl);
|
||||||
|
|
||||||
|
const datas = Template.currentData();
|
||||||
|
const actionSelected = tpl.find('#gen-comp-check-action').value;
|
||||||
|
const boardId = Session.get('currentBoard');
|
||||||
|
if (actionSelected === 'completed') {
|
||||||
|
datas.triggerVar.set({
|
||||||
|
activityType: 'completeChecklist',
|
||||||
|
boardId,
|
||||||
|
checklistName: '*',
|
||||||
|
desc,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (actionSelected === 'uncompleted') {
|
||||||
|
datas.triggerVar.set({
|
||||||
|
activityType: 'uncompleteChecklist',
|
||||||
|
boardId,
|
||||||
|
checklistName: '*',
|
||||||
|
desc,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'click .js-add-spec-comp-trigger'(event, tpl) {
|
||||||
|
const desc = Utils.getTriggerActionDesc(event, tpl);
|
||||||
|
const datas = Template.currentData();
|
||||||
|
const actionSelected = tpl.find('#spec-comp-check-action').value;
|
||||||
|
const checklistId = tpl.find('#spec-comp-check-name').value;
|
||||||
|
const boardId = Session.get('currentBoard');
|
||||||
|
if (actionSelected === 'completed') {
|
||||||
|
datas.triggerVar.set({
|
||||||
|
activityType: 'completeChecklist',
|
||||||
|
boardId,
|
||||||
|
checklistName: checklistId,
|
||||||
|
desc,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (actionSelected === 'uncompleted') {
|
||||||
|
datas.triggerVar.set({
|
||||||
|
activityType: 'uncompleteChecklist',
|
||||||
|
boardId,
|
||||||
|
checklistName: checklistId,
|
||||||
|
desc,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'click .js-add-gen-check-item-trigger'(event, tpl) {
|
||||||
|
const desc = Utils.getTriggerActionDesc(event, tpl);
|
||||||
|
const datas = Template.currentData();
|
||||||
|
const actionSelected = tpl.find('#check-item-gen-action').value;
|
||||||
|
const boardId = Session.get('currentBoard');
|
||||||
|
if (actionSelected === 'checked') {
|
||||||
|
datas.triggerVar.set({
|
||||||
|
activityType: 'checkedItem',
|
||||||
|
boardId,
|
||||||
|
checklistItemName: '*',
|
||||||
|
desc,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (actionSelected === 'unchecked') {
|
||||||
|
datas.triggerVar.set({
|
||||||
|
activityType: 'uncheckedItem',
|
||||||
|
boardId,
|
||||||
|
checklistItemName: '*',
|
||||||
|
desc,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'click .js-add-spec-check-item-trigger'(event, tpl) {
|
||||||
|
const desc = Utils.getTriggerActionDesc(event, tpl);
|
||||||
|
const datas = Template.currentData();
|
||||||
|
const actionSelected = tpl.find('#check-item-spec-action').value;
|
||||||
|
const checklistItemId = tpl.find('#check-item-name').value;
|
||||||
|
const boardId = Session.get('currentBoard');
|
||||||
|
if (actionSelected === 'checked') {
|
||||||
|
datas.triggerVar.set({
|
||||||
|
activityType: 'checkedItem',
|
||||||
|
boardId,
|
||||||
|
checklistItemName: checklistItemId,
|
||||||
|
desc,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (actionSelected === 'unchecked') {
|
||||||
|
datas.triggerVar.set({
|
||||||
|
activityType: 'uncheckedItem',
|
||||||
|
boardId,
|
||||||
|
checklistItemName: checklistItemId,
|
||||||
|
desc,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
|
||||||
|
|
@ -7,44 +7,34 @@ Meteor.startup(() => {
|
||||||
swimlaneColors = Swimlanes.simpleSchema()._schema.color.allowedValues;
|
swimlaneColors = Swimlanes.simpleSchema()._schema.color.allowedValues;
|
||||||
});
|
});
|
||||||
|
|
||||||
BlazeComponent.extendComponent({
|
function swimlaneHeaderCollapsed(check = undefined) {
|
||||||
async editTitle(event) {
|
const swimlane = Template.currentData();
|
||||||
|
const status = Utils.getSwimlaneCollapseState(swimlane);
|
||||||
|
if (check === undefined) {
|
||||||
|
return status;
|
||||||
|
} else {
|
||||||
|
const next = typeof check === 'boolean' ? check : !status;
|
||||||
|
Utils.setSwimlaneCollapseState(swimlane, next);
|
||||||
|
return next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Template.swimlaneHeader.events({
|
||||||
|
'click .js-collapse-swimlane'(event) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
const newTitle = this.childComponents('inlinedForm')[0]
|
swimlaneHeaderCollapsed(!swimlaneHeaderCollapsed());
|
||||||
.getValue()
|
},
|
||||||
.trim();
|
'click .js-open-swimlane-menu': Popup.open('swimlaneAction'),
|
||||||
const swimlane = this.currentData();
|
'click .js-open-add-swimlane-menu': Popup.open('swimlaneAdd'),
|
||||||
|
async submit(event, tpl) {
|
||||||
|
event.preventDefault();
|
||||||
|
const newTitle = tpl.$('.list-name-input').val().trim();
|
||||||
|
const swimlane = Template.currentData();
|
||||||
if (newTitle) {
|
if (newTitle) {
|
||||||
await swimlane.rename(newTitle.trim());
|
await swimlane.rename(newTitle.trim());
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
collapsed(check = undefined) {
|
});
|
||||||
const swimlane = Template.currentData();
|
|
||||||
const status = Utils.getSwimlaneCollapseState(swimlane);
|
|
||||||
if (check === undefined) {
|
|
||||||
// just check
|
|
||||||
return status;
|
|
||||||
} else {
|
|
||||||
const next = typeof check === 'boolean' ? check : !status;
|
|
||||||
Utils.setSwimlaneCollapseState(swimlane, next);
|
|
||||||
return next;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
events() {
|
|
||||||
return [
|
|
||||||
{
|
|
||||||
'click .js-collapse-swimlane'(event) {
|
|
||||||
event.preventDefault();
|
|
||||||
this.collapsed(!this.collapsed());
|
|
||||||
},
|
|
||||||
'click .js-open-swimlane-menu': Popup.open('swimlaneAction'),
|
|
||||||
'click .js-open-add-swimlane-menu': Popup.open('swimlaneAdd'),
|
|
||||||
submit: this.editTitle,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
},
|
|
||||||
}).register('swimlaneHeader');
|
|
||||||
|
|
||||||
Template.swimlaneFixedHeader.helpers({
|
Template.swimlaneFixedHeader.helpers({
|
||||||
isBoardAdmin() {
|
isBoardAdmin() {
|
||||||
|
|
@ -123,128 +113,105 @@ Template.swimlaneActionPopup.events({
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
BlazeComponent.extendComponent({
|
Template.swimlaneAddPopup.onCreated(function () {
|
||||||
onCreated() {
|
this.currentSwimlane = Template.currentData();
|
||||||
this.currentSwimlane = this.currentData();
|
});
|
||||||
|
|
||||||
|
Template.swimlaneAddPopup.events({
|
||||||
|
submit(event, tpl) {
|
||||||
|
event.preventDefault();
|
||||||
|
const currentBoard = Utils.getCurrentBoard();
|
||||||
|
const nextSwimlane = currentBoard.nextSwimlane(tpl.currentSwimlane);
|
||||||
|
const titleInput = tpl.find('.swimlane-name-input');
|
||||||
|
const title = titleInput.value.trim();
|
||||||
|
const sortValue = calculateIndexData(
|
||||||
|
tpl.currentSwimlane,
|
||||||
|
nextSwimlane,
|
||||||
|
1,
|
||||||
|
);
|
||||||
|
const swimlaneType = currentBoard.isTemplatesBoard()
|
||||||
|
? 'template-swimlane'
|
||||||
|
: 'swimlane';
|
||||||
|
|
||||||
|
if (title) {
|
||||||
|
Swimlanes.insert({
|
||||||
|
title,
|
||||||
|
boardId: Session.get('currentBoard'),
|
||||||
|
sort: sortValue.base || 0,
|
||||||
|
type: swimlaneType,
|
||||||
|
});
|
||||||
|
|
||||||
|
titleInput.value = '';
|
||||||
|
titleInput.focus();
|
||||||
|
}
|
||||||
|
// XXX ideally, we should move the popup to the newly
|
||||||
|
// created swimlane so a user can add more than one swimlane
|
||||||
|
// with a minimum of interactions
|
||||||
|
Popup.back();
|
||||||
},
|
},
|
||||||
|
'click .js-swimlane-template': Popup.open('searchElement'),
|
||||||
|
});
|
||||||
|
|
||||||
events() {
|
Template.setSwimlaneColorPopup.onCreated(function () {
|
||||||
return [
|
this.currentSwimlane = Template.currentData();
|
||||||
{
|
this.currentColor = new ReactiveVar(this.currentSwimlane.color);
|
||||||
submit(event) {
|
});
|
||||||
event.preventDefault();
|
|
||||||
const currentBoard = Utils.getCurrentBoard();
|
|
||||||
const nextSwimlane = currentBoard.nextSwimlane(this.currentSwimlane);
|
|
||||||
const titleInput = this.find('.swimlane-name-input');
|
|
||||||
const title = titleInput.value.trim();
|
|
||||||
const sortValue = calculateIndexData(
|
|
||||||
this.currentSwimlane,
|
|
||||||
nextSwimlane,
|
|
||||||
1,
|
|
||||||
);
|
|
||||||
const swimlaneType = currentBoard.isTemplatesBoard()
|
|
||||||
? 'template-swimlane'
|
|
||||||
: 'swimlane';
|
|
||||||
|
|
||||||
if (title) {
|
|
||||||
Swimlanes.insert({
|
|
||||||
title,
|
|
||||||
boardId: Session.get('currentBoard'),
|
|
||||||
sort: sortValue.base || 0,
|
|
||||||
type: swimlaneType,
|
|
||||||
});
|
|
||||||
|
|
||||||
titleInput.value = '';
|
|
||||||
titleInput.focus();
|
|
||||||
}
|
|
||||||
// XXX ideally, we should move the popup to the newly
|
|
||||||
// created swimlane so a user can add more than one swimlane
|
|
||||||
// with a minimum of interactions
|
|
||||||
Popup.back();
|
|
||||||
},
|
|
||||||
'click .js-swimlane-template': Popup.open('searchElement'),
|
|
||||||
},
|
|
||||||
];
|
|
||||||
},
|
|
||||||
}).register('swimlaneAddPopup');
|
|
||||||
|
|
||||||
BlazeComponent.extendComponent({
|
|
||||||
onCreated() {
|
|
||||||
this.currentSwimlane = this.currentData();
|
|
||||||
this.currentColor = new ReactiveVar(this.currentSwimlane.color);
|
|
||||||
},
|
|
||||||
|
|
||||||
|
Template.setSwimlaneColorPopup.helpers({
|
||||||
colors() {
|
colors() {
|
||||||
return swimlaneColors.map(color => ({ color, name: '' }));
|
return swimlaneColors.map(color => ({ color, name: '' }));
|
||||||
},
|
},
|
||||||
|
|
||||||
isSelected(color) {
|
isSelected(color) {
|
||||||
return this.currentColor.get() === color;
|
return Template.instance().currentColor.get() === color;
|
||||||
},
|
},
|
||||||
|
});
|
||||||
|
|
||||||
events() {
|
Template.setSwimlaneColorPopup.events({
|
||||||
return [
|
async 'submit form'(event, tpl) {
|
||||||
{
|
event.preventDefault();
|
||||||
async 'submit form'(event) {
|
await tpl.currentSwimlane.setColor(tpl.currentColor.get());
|
||||||
event.preventDefault();
|
Popup.back();
|
||||||
await this.currentSwimlane.setColor(this.currentColor.get());
|
|
||||||
Popup.back();
|
|
||||||
},
|
|
||||||
'click .js-palette-color'() {
|
|
||||||
this.currentColor.set(this.currentData().color);
|
|
||||||
},
|
|
||||||
async 'click .js-submit'() {
|
|
||||||
await this.currentSwimlane.setColor(this.currentColor.get());
|
|
||||||
Popup.back();
|
|
||||||
},
|
|
||||||
async 'click .js-remove-color'() {
|
|
||||||
await this.currentSwimlane.setColor(null);
|
|
||||||
Popup.back();
|
|
||||||
},
|
|
||||||
},
|
|
||||||
];
|
|
||||||
},
|
},
|
||||||
}).register('setSwimlaneColorPopup');
|
'click .js-palette-color'(event, tpl) {
|
||||||
|
tpl.currentColor.set(Template.currentData().color);
|
||||||
BlazeComponent.extendComponent({
|
|
||||||
onCreated() {
|
|
||||||
this.currentSwimlane = this.currentData();
|
|
||||||
},
|
},
|
||||||
|
async 'click .js-submit'(event, tpl) {
|
||||||
|
await tpl.currentSwimlane.setColor(tpl.currentColor.get());
|
||||||
|
Popup.back();
|
||||||
|
},
|
||||||
|
async 'click .js-remove-color'(event, tpl) {
|
||||||
|
await tpl.currentSwimlane.setColor(null);
|
||||||
|
Popup.back();
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
applySwimlaneHeight() {
|
Template.setSwimlaneHeightPopup.onCreated(function () {
|
||||||
const swimlane = this.currentData();
|
this.currentSwimlane = Template.currentData();
|
||||||
|
});
|
||||||
|
|
||||||
|
Template.setSwimlaneHeightPopup.helpers({
|
||||||
|
swimlaneHeightValue() {
|
||||||
|
const swimlane = Template.currentData();
|
||||||
|
const board = swimlane.boardId;
|
||||||
|
return ReactiveCache.getCurrentUser().getSwimlaneHeight(board, swimlane._id);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
Template.setSwimlaneHeightPopup.events({
|
||||||
|
'click .swimlane-height-apply'(event, tpl) {
|
||||||
|
const swimlane = Template.currentData();
|
||||||
const board = swimlane.boardId;
|
const board = swimlane.boardId;
|
||||||
const height = parseInt(
|
const height = parseInt(
|
||||||
Template.instance()
|
tpl.$('.swimlane-height-value').val(),
|
||||||
.$('.swimlane-height-value')
|
|
||||||
.val(),
|
|
||||||
10,
|
10,
|
||||||
);
|
);
|
||||||
|
|
||||||
// FIXME(mark-i-m): where do we put constants?
|
|
||||||
// also in imports/i18n/data/en.i18n.json
|
|
||||||
if (height != -1 && (height < 100 || !height)) {
|
if (height != -1 && (height < 100 || !height)) {
|
||||||
Template.instance()
|
tpl.$('.swimlane-height-error').click();
|
||||||
.$('.swimlane-height-error')
|
|
||||||
.click();
|
|
||||||
} else {
|
} else {
|
||||||
Meteor.call('applySwimlaneHeight', board, swimlane._id, height);
|
Meteor.call('applySwimlaneHeight', board, swimlane._id, height);
|
||||||
Popup.back();
|
Popup.back();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
'click .swimlane-height-error': Popup.open('swimlaneHeightError'),
|
||||||
swimlaneHeightValue() {
|
});
|
||||||
const swimlane = this.currentData();
|
|
||||||
const board = swimlane.boardId;
|
|
||||||
return ReactiveCache.getCurrentUser().getSwimlaneHeight(board, swimlane._id);
|
|
||||||
},
|
|
||||||
|
|
||||||
events() {
|
|
||||||
return [
|
|
||||||
{
|
|
||||||
'click .swimlane-height-apply': this.applySwimlaneHeight,
|
|
||||||
'click .swimlane-height-error': Popup.open('swimlaneHeightError'),
|
|
||||||
},
|
|
||||||
];
|
|
||||||
},
|
|
||||||
}).register('setSwimlaneHeightPopup');
|
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -76,53 +76,38 @@ Template.userAvatarInitials.helpers({
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
BlazeComponent.extendComponent({
|
Template.boardOrgRow.onCreated(function () {
|
||||||
onCreated() {
|
this.error = new ReactiveVar('');
|
||||||
this.error = new ReactiveVar('');
|
this.loading = new ReactiveVar(false);
|
||||||
this.loading = new ReactiveVar(false);
|
this.findOrgsOptions = new ReactiveVar({});
|
||||||
this.findOrgsOptions = new ReactiveVar({});
|
|
||||||
|
|
||||||
this.page = new ReactiveVar(1);
|
this.page = new ReactiveVar(1);
|
||||||
this.autorun(() => {
|
this.autorun(() => {
|
||||||
const limitOrgs = this.page.get() * Number.MAX_SAFE_INTEGER;
|
const limitOrgs = this.page.get() * Number.MAX_SAFE_INTEGER;
|
||||||
this.subscribe('org', this.findOrgsOptions.get(), limitOrgs, () => {});
|
this.subscribe('org', this.findOrgsOptions.get(), limitOrgs, () => {});
|
||||||
});
|
});
|
||||||
},
|
});
|
||||||
|
|
||||||
onRendered() {
|
Template.boardOrgRow.onRendered(function () {
|
||||||
this.setLoading(false);
|
this.loading.set(false);
|
||||||
},
|
});
|
||||||
|
|
||||||
setError(error) {
|
|
||||||
this.error.set(error);
|
|
||||||
},
|
|
||||||
|
|
||||||
setLoading(w) {
|
|
||||||
this.loading.set(w);
|
|
||||||
},
|
|
||||||
|
|
||||||
isLoading() {
|
|
||||||
return this.loading.get();
|
|
||||||
},
|
|
||||||
|
|
||||||
events() {
|
|
||||||
return [
|
|
||||||
{
|
|
||||||
'keyup input'() {
|
|
||||||
this.setError('');
|
|
||||||
},
|
|
||||||
'click .js-manage-board-removeOrg': Popup.open('removeBoardOrg'),
|
|
||||||
},
|
|
||||||
];
|
|
||||||
},
|
|
||||||
}).register('boardOrgRow');
|
|
||||||
|
|
||||||
Template.boardOrgRow.helpers({
|
Template.boardOrgRow.helpers({
|
||||||
|
isLoading() {
|
||||||
|
return Template.instance().loading.get();
|
||||||
|
},
|
||||||
orgData() {
|
orgData() {
|
||||||
return ReactiveCache.getOrg(this.orgId);
|
return ReactiveCache.getOrg(this.orgId);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Template.boardOrgRow.events({
|
||||||
|
'keyup input'(event, tpl) {
|
||||||
|
tpl.error.set('');
|
||||||
|
},
|
||||||
|
'click .js-manage-board-removeOrg': Popup.open('removeBoardOrg'),
|
||||||
|
});
|
||||||
|
|
||||||
Template.boardOrgName.helpers({
|
Template.boardOrgName.helpers({
|
||||||
orgName() {
|
orgName() {
|
||||||
const org = ReactiveCache.getOrg(this.orgId);
|
const org = ReactiveCache.getOrg(this.orgId);
|
||||||
|
|
@ -135,53 +120,38 @@ Template.boardOrgName.helpers({
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
BlazeComponent.extendComponent({
|
Template.boardTeamRow.onCreated(function () {
|
||||||
onCreated() {
|
this.error = new ReactiveVar('');
|
||||||
this.error = new ReactiveVar('');
|
this.loading = new ReactiveVar(false);
|
||||||
this.loading = new ReactiveVar(false);
|
this.findOrgsOptions = new ReactiveVar({});
|
||||||
this.findOrgsOptions = new ReactiveVar({});
|
|
||||||
|
|
||||||
this.page = new ReactiveVar(1);
|
this.page = new ReactiveVar(1);
|
||||||
this.autorun(() => {
|
this.autorun(() => {
|
||||||
const limitTeams = this.page.get() * Number.MAX_SAFE_INTEGER;
|
const limitTeams = this.page.get() * Number.MAX_SAFE_INTEGER;
|
||||||
this.subscribe('team', this.findOrgsOptions.get(), limitTeams, () => {});
|
this.subscribe('team', this.findOrgsOptions.get(), limitTeams, () => {});
|
||||||
});
|
});
|
||||||
},
|
});
|
||||||
|
|
||||||
onRendered() {
|
Template.boardTeamRow.onRendered(function () {
|
||||||
this.setLoading(false);
|
this.loading.set(false);
|
||||||
},
|
});
|
||||||
|
|
||||||
setError(error) {
|
|
||||||
this.error.set(error);
|
|
||||||
},
|
|
||||||
|
|
||||||
setLoading(w) {
|
|
||||||
this.loading.set(w);
|
|
||||||
},
|
|
||||||
|
|
||||||
isLoading() {
|
|
||||||
return this.loading.get();
|
|
||||||
},
|
|
||||||
|
|
||||||
events() {
|
|
||||||
return [
|
|
||||||
{
|
|
||||||
'keyup input'() {
|
|
||||||
this.setError('');
|
|
||||||
},
|
|
||||||
'click .js-manage-board-removeTeam': Popup.open('removeBoardTeam'),
|
|
||||||
},
|
|
||||||
];
|
|
||||||
},
|
|
||||||
}).register('boardTeamRow');
|
|
||||||
|
|
||||||
Template.boardTeamRow.helpers({
|
Template.boardTeamRow.helpers({
|
||||||
|
isLoading() {
|
||||||
|
return Template.instance().loading.get();
|
||||||
|
},
|
||||||
teamData() {
|
teamData() {
|
||||||
return ReactiveCache.getTeam(this.teamId);
|
return ReactiveCache.getTeam(this.teamId);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Template.boardTeamRow.events({
|
||||||
|
'keyup input'(event, tpl) {
|
||||||
|
tpl.error.set('');
|
||||||
|
},
|
||||||
|
'click .js-manage-board-removeTeam': Popup.open('removeBoardTeam'),
|
||||||
|
});
|
||||||
|
|
||||||
Template.boardTeamName.helpers({
|
Template.boardTeamName.helpers({
|
||||||
teamName() {
|
teamName() {
|
||||||
const team = ReactiveCache.getTeam(this.teamId);
|
const team = ReactiveCache.getTeam(this.teamId);
|
||||||
|
|
@ -194,87 +164,79 @@ Template.boardTeamName.helpers({
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
BlazeComponent.extendComponent({
|
Template.changeAvatarPopup.onCreated(function () {
|
||||||
onCreated() {
|
this.error = new ReactiveVar('');
|
||||||
this.error = new ReactiveVar('');
|
Meteor.subscribe('my-avatars');
|
||||||
|
});
|
||||||
|
|
||||||
Meteor.subscribe('my-avatars');
|
Template.changeAvatarPopup.helpers({
|
||||||
|
error() {
|
||||||
|
return Template.instance().error;
|
||||||
},
|
},
|
||||||
|
|
||||||
uploadedAvatars() {
|
uploadedAvatars() {
|
||||||
const ret = ReactiveCache.getAvatars({ userId: Meteor.userId() }, {}, true);
|
const ret = ReactiveCache.getAvatars({ userId: Meteor.userId() }, {}, true);
|
||||||
return ret;
|
return ret;
|
||||||
},
|
},
|
||||||
|
|
||||||
isSelected() {
|
isSelected() {
|
||||||
const userProfile = ReactiveCache.getCurrentUser().profile;
|
const userProfile = ReactiveCache.getCurrentUser().profile;
|
||||||
const avatarUrl = userProfile && userProfile.avatarUrl;
|
const avatarUrl = userProfile && userProfile.avatarUrl;
|
||||||
const currentAvatarUrl = this.currentData().link();
|
const currentAvatarUrl = Template.currentData().link();
|
||||||
return avatarUrl === currentAvatarUrl;
|
return avatarUrl === currentAvatarUrl;
|
||||||
},
|
},
|
||||||
|
|
||||||
noAvatarUrl() {
|
noAvatarUrl() {
|
||||||
const userProfile = ReactiveCache.getCurrentUser().profile;
|
const userProfile = ReactiveCache.getCurrentUser().profile;
|
||||||
const avatarUrl = userProfile && userProfile.avatarUrl;
|
const avatarUrl = userProfile && userProfile.avatarUrl;
|
||||||
return !avatarUrl;
|
return !avatarUrl;
|
||||||
},
|
},
|
||||||
|
});
|
||||||
|
|
||||||
setAvatar(avatarUrl) {
|
function changeAvatarSetAvatar(tpl, avatarUrl) {
|
||||||
Meteor.call('setAvatarUrl', avatarUrl, (err) => {
|
Meteor.call('setAvatarUrl', avatarUrl, (err) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
this.setError(err.reason || 'Error setting avatar');
|
tpl.error.set(err.reason || 'Error setting avatar');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
|
|
||||||
setError(error) {
|
Template.changeAvatarPopup.events({
|
||||||
this.error.set(error);
|
'click .js-upload-avatar'(event, tpl) {
|
||||||
|
tpl.$('.js-upload-avatar-input').click();
|
||||||
},
|
},
|
||||||
|
'change .js-upload-avatar-input'(event, tpl) {
|
||||||
events() {
|
if (event.currentTarget.files && event.currentTarget.files[0]) {
|
||||||
return [
|
const uploader = Avatars.insert(
|
||||||
{
|
{
|
||||||
'click .js-upload-avatar'() {
|
file: event.currentTarget.files[0],
|
||||||
this.$('.js-upload-avatar-input').click();
|
chunkSize: 'dynamic',
|
||||||
},
|
},
|
||||||
'change .js-upload-avatar-input'(event) {
|
false,
|
||||||
const self = this;
|
);
|
||||||
if (event.currentTarget.files && event.currentTarget.files[0]) {
|
uploader.on('error', (error, fileData) => {
|
||||||
const uploader = Avatars.insert(
|
tpl.error.set(error.reason);
|
||||||
{
|
});
|
||||||
file: event.currentTarget.files[0],
|
uploader.start();
|
||||||
chunkSize: 'dynamic',
|
}
|
||||||
},
|
|
||||||
false,
|
|
||||||
);
|
|
||||||
uploader.on('error', (error, fileData) => {
|
|
||||||
self.setError(error.reason);
|
|
||||||
});
|
|
||||||
uploader.start();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
'click .js-select-avatar'(event) {
|
|
||||||
event.preventDefault();
|
|
||||||
event.stopPropagation();
|
|
||||||
const data = Blaze.getData(event.currentTarget);
|
|
||||||
if (data && typeof data.link === 'function') {
|
|
||||||
const avatarUrl = data.link();
|
|
||||||
this.setAvatar(avatarUrl);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
'click .js-select-initials'(event) {
|
|
||||||
event.preventDefault();
|
|
||||||
event.stopPropagation();
|
|
||||||
this.setAvatar('');
|
|
||||||
},
|
|
||||||
'click .js-delete-avatar': Popup.afterConfirm('deleteAvatar', function() {
|
|
||||||
Avatars.remove(this._id);
|
|
||||||
Popup.back();
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
];
|
|
||||||
},
|
},
|
||||||
}).register('changeAvatarPopup');
|
'click .js-select-avatar'(event, tpl) {
|
||||||
|
event.preventDefault();
|
||||||
|
event.stopPropagation();
|
||||||
|
const data = Blaze.getData(event.currentTarget);
|
||||||
|
if (data && typeof data.link === 'function') {
|
||||||
|
const avatarUrl = data.link();
|
||||||
|
changeAvatarSetAvatar(tpl, avatarUrl);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'click .js-select-initials'(event, tpl) {
|
||||||
|
event.preventDefault();
|
||||||
|
event.stopPropagation();
|
||||||
|
changeAvatarSetAvatar(tpl, '');
|
||||||
|
},
|
||||||
|
'click .js-delete-avatar': Popup.afterConfirm('deleteAvatar', function (event) {
|
||||||
|
Avatars.remove(this._id);
|
||||||
|
Popup.back();
|
||||||
|
event.stopPropagation();
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
Template.cardMemberPopup.helpers({
|
Template.cardMemberPopup.helpers({
|
||||||
user() {
|
user() {
|
||||||
|
|
|
||||||
|
|
@ -7,11 +7,9 @@ Template.headerUserBar.events({
|
||||||
'click .js-change-avatar': Popup.open('changeAvatar'),
|
'click .js-change-avatar': Popup.open('changeAvatar'),
|
||||||
});
|
});
|
||||||
|
|
||||||
BlazeComponent.extendComponent({
|
Template.memberMenuPopup.onCreated(function () {
|
||||||
onCreated() {
|
Meteor.subscribe('setting');
|
||||||
Meteor.subscribe('setting');
|
});
|
||||||
},
|
|
||||||
}).register('memberMenuPopup');
|
|
||||||
|
|
||||||
Template.memberMenuPopup.helpers({
|
Template.memberMenuPopup.helpers({
|
||||||
templatesBoardId() {
|
templatesBoardId() {
|
||||||
|
|
@ -114,12 +112,6 @@ Template.memberMenuPopup.events({
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
BlazeComponent.extendComponent({
|
|
||||||
onCreated() {
|
|
||||||
Meteor.subscribe('setting');
|
|
||||||
},
|
|
||||||
}).register('editProfilePopup');
|
|
||||||
|
|
||||||
Template.invitePeoplePopup.events({
|
Template.invitePeoplePopup.events({
|
||||||
'click a.js-toggle-board-choose'(event){
|
'click a.js-toggle-board-choose'(event){
|
||||||
let target = $(event.target);
|
let target = $(event.target);
|
||||||
|
|
@ -169,6 +161,7 @@ Template.invitePeoplePopup.events({
|
||||||
});
|
});
|
||||||
|
|
||||||
Template.editProfilePopup.onCreated(function() {
|
Template.editProfilePopup.onCreated(function() {
|
||||||
|
Meteor.subscribe('setting');
|
||||||
this.subscribe('accountSettings');
|
this.subscribe('accountSettings');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue