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:
Harry Adel 2026-03-08 11:02:09 +02:00
parent bae23f9ed8
commit 477e1c89e5
29 changed files with 2859 additions and 2894 deletions

View file

@ -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) {

View file

@ -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) {

View file

@ -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;

View file

@ -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({

View file

@ -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;
} },
}) });

View file

@ -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');

View file

@ -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();
},
});

View file

@ -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();
},
});

View file

@ -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';

View file

@ -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;
}
},
});

View file

@ -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();
},
});

View file

@ -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'));

View file

@ -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');

View file

@ -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 */

View file

@ -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();
},
});

View file

@ -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,
});
}
},
});

View file

@ -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'); });

View file

@ -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');

View file

@ -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);
},
});

View file

@ -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');

View file

@ -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'); });

View file

@ -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);
},
});

View file

@ -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();
}, },

View file

@ -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,
});
}
},
});

View file

@ -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,
});
}
},
});

View file

@ -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

View file

@ -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() {

View file

@ -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');
}); });