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;
BlazeComponent.extendComponent({
onCreated() {
// XXX Should we use ReactiveNumber?
this.page = new ReactiveVar(1);
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;
Template.activities.onCreated(function () {
// Register with sidebar so it can call loadNextPage on us
if (Sidebar) {
Sidebar.activitiesInstance = this;
}
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) 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() {
// XXX Should we use ReactiveNumber?
this.page = new ReactiveVar(1);
this.loadNextPageLocked = false;
this.loadNextPage = () => {
if (this.loadNextPageLocked === false) {
this.page.set(this.page.get() + 1);
this.loadNextPageLocked = true;
}
},
showActivities() {
let ret = false;
let mode = this.data()?.mode;
};
// TODO is sidebar always available? E.g. on small screens/mobile devices
const sidebar = Sidebar;
if (sidebar && sidebar.infiniteScrolling) {
sidebar.infiniteScrolling.resetNextPeak();
}
this.autorun(() => {
const data = Template.currentData();
let mode = data?.mode;
if (mode) {
const capitalizedMode = Utils.capitalize(mode);
let searchId;
const showActivities = _showActivities(data);
if (mode === 'linkedcard' || mode === 'linkedboard') {
const currentCard = Utils.getCurrentCard();
ret = currentCard.showActivities ?? false;
searchId = currentCard.linkedId;
mode = mode.replace('linked', '');
} else if (mode === 'card') {
ret = this.data()?.card?.showActivities ?? false;
searchId = Utils.getCurrentCardId();
} else {
ret = Utils.getCurrentBoard().showActivities ?? false;
searchId = Session.get(`current${capitalizedMode}`);
}
}
return ret;
},
activities() {
const ret = this.data().card.activities();
return ret;
},
}).register('activities');
const limit = this.page.get() * activitiesPerPage;
if (searchId === null) return;
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() {
const checkItemId = this.currentData().activity.checklistItemId;
const checkItemId = this.activity.checklistItemId;
const checkItem = ReactiveCache.getChecklistItem(checkItemId);
return checkItem && checkItem.title;
},
boardLabelLink() {
const data = this.currentData();
const currentBoardId = Session.get('currentBoard');
if (data.mode !== 'board') {
// data.mode: card, linkedcard, linkedboard
return createBoardLink(data.activity.board(), data.activity.listName ? data.activity.listName : null);
if (this.mode !== 'board') {
return createBoardLink(this.activity.board(), this.activity.listName ? this.activity.listName : null);
}
else if (currentBoardId != data.activity.boardId) {
// data.mode: board
// current activitie is linked
return createBoardLink(data.activity.board(), data.activity.listName ? data.activity.listName : null);
else if (currentBoardId != this.activity.boardId) {
return createBoardLink(this.activity.board(), this.activity.listName ? this.activity.listName : null);
}
return TAPi18n.__('this-board');
},
cardLabelLink() {
const data = this.currentData();
const currentBoardId = Session.get('currentBoard');
if (data.mode == 'card') {
// data.mode: card
if (this.mode == 'card') {
return TAPi18n.__('this-card');
}
else if (data.mode !== 'board') {
// data.mode: linkedcard, linkedboard
return createCardLink(data.activity.card(), null);
else if (this.mode !== 'board') {
return createCardLink(this.activity.card(), null);
}
else if (currentBoardId != data.activity.boardId) {
// data.mode: board
// current activitie is linked
return createCardLink(data.activity.card(), data.activity.board().title);
else if (currentBoardId != this.activity.boardId) {
return createCardLink(this.activity.card(), this.activity.board().title);
}
return createCardLink(this.currentData().activity.card(), null);
return createCardLink(this.activity.card(), null);
},
cardLink() {
const data = this.currentData();
const currentBoardId = Session.get('currentBoard');
if (data.mode !== 'board') {
// data.mode: card, linkedcard, linkedboard
return createCardLink(data.activity.card(), null);
if (this.mode !== 'board') {
return createCardLink(this.activity.card(), null);
}
else if (currentBoardId != data.activity.boardId) {
// data.mode: board
// current activitie is linked
return createCardLink(data.activity.card(), data.activity.board().title);
else if (currentBoardId != this.activity.boardId) {
return createCardLink(this.activity.card(), this.activity.board().title);
}
return createCardLink(this.currentData().activity.card(), null);
return createCardLink(this.activity.card(), null);
},
receivedDate() {
const receivedDate = this.currentData().activity.card();
if (!receivedDate) return null;
return receivedDate.receivedAt;
const card = this.activity.card();
if (!card) return null;
return card.receivedAt;
},
startDate() {
const startDate = this.currentData().activity.card();
if (!startDate) return null;
return startDate.startAt;
const card = this.activity.card();
if (!card) return null;
return card.startAt;
},
dueDate() {
const dueDate = this.currentData().activity.card();
if (!dueDate) return null;
return dueDate.dueAt;
const card = this.activity.card();
if (!card) return null;
return card.dueAt;
},
endDate() {
const endDate = this.currentData().activity.card();
if (!endDate) return null;
return endDate.endAt;
const card = this.activity.card();
if (!card) return null;
return card.endAt;
},
lastLabel() {
const lastLabelId = this.currentData().activity.labelId;
const lastLabelId = this.activity.labelId;
if (!lastLabelId) return null;
const lastLabel = ReactiveCache.getBoard(
this.currentData().activity.boardId,
this.activity.boardId,
).getLabelById(lastLabelId);
if (lastLabel && (lastLabel.name === undefined || lastLabel.name === '')) {
return lastLabel.color;
@ -175,7 +169,7 @@ BlazeComponent.extendComponent({
lastCustomField() {
const lastCustomField = ReactiveCache.getCustomField(
this.currentData().activity.customFieldId,
this.activity.customFieldId,
);
if (!lastCustomField) return null;
return lastCustomField.name;
@ -183,10 +177,10 @@ BlazeComponent.extendComponent({
lastCustomFieldValue() {
const lastCustomField = ReactiveCache.getCustomField(
this.currentData().activity.customFieldId,
this.activity.customFieldId,
);
if (!lastCustomField) return null;
const value = this.currentData().activity.value;
const value = this.activity.value;
if (
lastCustomField.settings.dropdownItems &&
lastCustomField.settings.dropdownItems.length > 0
@ -203,13 +197,13 @@ BlazeComponent.extendComponent({
},
listLabel() {
const activity = this.currentData().activity;
const activity = this.activity;
const list = activity.list();
return (list && list.title) || activity.title;
},
sourceLink() {
const source = this.currentData().activity.source;
const source = this.activity.source;
if (source) {
if (source.url) {
return Blaze.toHTML(
@ -229,12 +223,12 @@ BlazeComponent.extendComponent({
memberLink() {
return Blaze.toHTMLWithData(Template.memberName, {
user: this.currentData().activity.member(),
user: this.activity.member(),
});
},
attachmentLink() {
const attachment = this.currentData().activity.attachment();
const attachment = this.activity.attachment();
// trying to display url before file is stored generates js errors
return (
(attachment &&
@ -248,17 +242,16 @@ BlazeComponent.extendComponent({
sanitizeText(attachment.name),
),
)) ||
sanitizeText(this.currentData().activity.attachmentName)
sanitizeText(this.activity.attachmentName)
);
},
customField() {
const customField = this.currentData().activity.customField();
const customField = this.activity.customField();
if (!customField) return null;
return customField.name;
},
}).register('activity');
});
Template.activity.helpers({
sanitize(value) {

View file

@ -2,94 +2,79 @@ import { ReactiveCache } from '/imports/reactiveCache';
const commentFormIsOpen = new ReactiveVar(false);
BlazeComponent.extendComponent({
onDestroyed() {
commentFormIsOpen.set(false);
$('.note-popover').hide();
},
Template.commentForm.onDestroyed(function () {
commentFormIsOpen.set(false);
$('.note-popover').hide();
});
Template.commentForm.helpers({
commentFormIsOpen() {
return commentFormIsOpen.get();
},
});
getInput() {
return this.$('.js-new-comment-input');
Template.commentForm.events({
'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();
},
events() {
return [
{
'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();
}
},
},
];
// Pressing Ctrl+Enter should submit the form
'keydown form textarea'(evt, tpl) {
if (evt.keyCode === 13 && (evt.metaKey || evt.ctrlKey)) {
tpl.find('button[type=submit]').click();
}
},
}).register('commentForm');
});
BlazeComponent.extendComponent({
Template.comments.helpers({
getComments() {
const data = this.data();
const data = Template.currentData();
if (!data || typeof data.comments !== 'function') return [];
return data.comments();
},
}).register("comments");
});
BlazeComponent.extendComponent({
events() {
return [
{
'click .js-delete-comment': Popup.afterConfirm('deleteComment', () => {
const commentId = this.data()._id;
CardComments.remove(commentId);
Popup.back();
}),
'submit .js-edit-comment'(evt) {
evt.preventDefault();
const commentText = this.currentComponent()
.getValue()
.trim();
const commentId = this.data()._id;
if (commentText) {
CardComments.update(commentId, {
$set: {
text: commentText,
},
});
}
Template.comment.events({
'click .js-delete-comment': Popup.afterConfirm('deleteComment', function () {
const commentId = this._id;
CardComments.remove(commentId);
Popup.back();
}),
'submit .js-edit-comment'(evt, tpl) {
evt.preventDefault();
const textarea = tpl.find('.js-edit-comment textarea,input[type=text]');
const commentText = textarea && textarea.value ? textarea.value.trim() : '';
const commentId = this._id;
if (commentText) {
CardComments.update(commentId, {
$set: {
text: commentText,
},
},
];
});
}
},
}).register("comment");
});
// XXX This should be a static method of the `commentForm` component
function resetCommentInput(input) {

View file

@ -1,69 +1,69 @@
import { BlazeComponent } from 'meteor/peerlibrary:blaze-components';
import { ReactiveVar } from 'meteor/reactive-var';
import { Meteor } from 'meteor/meteor';
import { Template } from 'meteor/templating';
import './originalPosition.html';
/**
* 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(() => {
const data = this.data();
if (data && data.entityId && data.entityType) {
this.loadOriginalPosition(data.entityId, data.entityType);
}
});
}
Template.originalPosition.onCreated(function () {
this.originalPosition = new ReactiveVar(null);
this.isLoading = new ReactiveVar(false);
this.hasMoved = new ReactiveVar(false);
loadOriginalPosition(entityId, entityType) {
this.isLoading.set(true);
const tpl = this;
function loadOriginalPosition(entityId, entityType) {
tpl.isLoading.set(true);
const methodName = `positionHistory.get${entityType.charAt(0).toUpperCase() + entityType.slice(1)}OriginalPosition`;
Meteor.call(methodName, entityId, (error, result) => {
this.isLoading.set(false);
tpl.isLoading.set(false);
if (error) {
console.error('Error loading original position:', error);
this.originalPosition.set(null);
tpl.originalPosition.set(null);
} else {
this.originalPosition.set(result);
tpl.originalPosition.set(result);
// Check if the entity has moved
const movedMethodName = `positionHistory.has${entityType.charAt(0).toUpperCase() + entityType.slice(1)}Moved`;
Meteor.call(movedMethodName, entityId, (movedError, movedResult) => {
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() {
return this.originalPosition.get();
}
return Template.instance().originalPosition.get();
},
isLoading() {
return this.isLoading.get();
}
return Template.instance().isLoading.get();
},
hasMovedFromOriginal() {
return this.hasMoved.get();
}
return Template.instance().hasMoved.get();
},
getOriginalPositionDescription() {
const position = this.getOriginalPosition();
const position = Template.instance().originalPosition.get();
if (!position) return 'No original position data';
if (position.originalPosition) {
const entityType = this.data().entityType;
const data = Template.currentData();
const entityType = data.entityType;
let description = `Original position: ${position.originalPosition.sort || 0}`;
if (entityType === 'list' && position.originalSwimlaneId) {
@ -81,18 +81,14 @@ class OriginalPositionComponent extends BlazeComponent {
}
return 'No original position data';
}
},
getOriginalTitle() {
const position = this.getOriginalPosition();
const position = Template.instance().originalPosition.get();
return position ? position.originalTitle : '';
}
},
showOriginalPosition() {
return this.getOriginalPosition() !== null;
}
}
OriginalPositionComponent.register('originalPosition');
export default OriginalPositionComponent;
return Template.instance().originalPosition.get() !== null;
},
});

View file

@ -1,34 +1,30 @@
BlazeComponent.extendComponent({
onCreated() {
// Provide the expected parent component properties for cardDetails
this.showOverlay = new ReactiveVar(false);
this.mouseHasEnterCardDetails = false;
},
Template.ganttCard.onCreated(function () {
// Provide the expected parent component properties for cardDetails
this.showOverlay = new ReactiveVar(false);
this.mouseHasEnterCardDetails = false;
});
Template.ganttCard.helpers({
selectedCard() {
// The selected card is now passed as a parameter to the component
return this.currentData();
return Template.currentData();
},
});
events() {
return [
{
'click .js-close-card-details'(event) {
event.preventDefault();
// Find the ganttView template instance and clear selectedCardId
let view = Blaze.currentView;
while (view) {
if (view.templateInstance && view.templateInstance().selectedCardId) {
view.templateInstance().selectedCardId.set(null);
break;
}
view = view.parentView;
}
},
},
];
Template.ganttCard.events({
'click .js-close-card-details'(event) {
event.preventDefault();
// Find the ganttView template instance and clear selectedCardId
let view = Blaze.currentView;
while (view) {
if (view.templateInstance && view.templateInstance().selectedCardId) {
view.templateInstance().selectedCardId.set(null);
break;
}
view = view.parentView;
}
},
}).register('ganttCard');
});
// Add click handler to ganttView for card titles
Template.ganttView.events({

View file

@ -7,36 +7,63 @@ import getSlug from 'limax';
const Papa = require('papaparse');
BlazeComponent.extendComponent({
Template.importHeaderBar.helpers({
title() {
return `import-board-title-${Session.get('importSource')}`;
},
}).register('importHeaderBar');
});
BlazeComponent.extendComponent({
onCreated() {
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');
},
// Helper to find the closest ancestor template instance by name
function findParentTemplateInstance(childTemplateInstance, parentTemplateName) {
let view = childTemplateInstance.view;
while (view) {
if (view.name === `Template.${parentTemplateName}` && view.templateInstance) {
return view.templateInstance();
}
view = view.parentView;
}
return null;
}
currentTemplate() {
return this.steps[this._currentStepIndex.get()];
},
function _prepareAdditionalData(dataObject) {
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;
if (nextStepIndex >= this.steps.length) {
this.finishImport();
} else {
this._currentStepIndex.set(nextStepIndex);
}
},
};
importData(evt, dataSource) {
this.setError = (error) => {
this.error.set(error);
};
this.importData = (evt, dataSource) => {
evt.preventDefault();
const input = this.find('.js-import-json').value;
if (dataSource === 'csv') {
@ -44,7 +71,7 @@ BlazeComponent.extendComponent({
const ret = Papa.parse(csv);
if (ret && ret.data && ret.data.length) this.importedData.set(ret.data);
else throw new Meteor.Error('error-csv-schema');
const membersToMap = this._prepareAdditionalData(ret.data);
const membersToMap = _prepareAdditionalData(ret.data);
this.membersToMap.set(membersToMap);
this.nextStep();
} else {
@ -52,7 +79,7 @@ BlazeComponent.extendComponent({
const dataObject = JSON.parse(input);
this.setError('');
this.importedData.set(dataObject);
const membersToMap = this._prepareAdditionalData(dataObject);
const membersToMap = _prepareAdditionalData(dataObject);
// store members data and mapping in Session
// (we go deep and 2-way, so storing in data context is not a viable option)
this.membersToMap.set(membersToMap);
@ -61,13 +88,9 @@ BlazeComponent.extendComponent({
this.setError('error-json-malformed');
}
}
},
};
setError(error) {
this.error.set(error);
},
finishImport() {
this.finishImport = () => {
const additionalData = {};
const membersMapping = this.membersToMap.get();
if (membersMapping) {
@ -95,44 +118,27 @@ BlazeComponent.extendComponent({
FlowRouter.go('board', {
id: res,
slug: title,
})
});
//Utils.goBoardId(res);
}
},
);
},
};
});
_prepareAdditionalData(dataObject) {
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;
Template.import.helpers({
error() {
return Template.instance().error;
},
_screenAdditionalData() {
return 'mapMembers';
},
}).register('import');
BlazeComponent.extendComponent({
template() {
return 'importTextarea';
currentTemplate() {
return Template.instance().steps[Template.instance()._currentStepIndex.get()];
},
});
Template.importTextarea.helpers({
instruction() {
return `import-board-instruction-${Session.get('importSource')}`;
},
importPlaceHolder() {
const importSource = Session.get('importSource');
if (importSource === 'csv') {
@ -141,81 +147,37 @@ BlazeComponent.extendComponent({
return 'import-json-placeholder';
}
},
});
events() {
return [
{
submit(evt) {
return this.parentComponent().importData(
evt,
Session.get('importSource'),
);
},
},
];
Template.importTextarea.events({
submit(evt, tpl) {
const importTpl = findParentTemplateInstance(tpl, 'import');
if (importTpl) {
return importTpl.importData(evt, Session.get('importSource'));
}
},
}).register('importTextarea');
});
BlazeComponent.extendComponent({
onCreated() {
this.usersLoaded = new ReactiveVar(false);
// Module-level reference so popup children can access importMapMembers methods
let _importMapMembersTpl = null;
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) {
// eslint-disable-next-line no-console
// console.log('found username:', user.username);
member.wekanId = user._id;
}
}
return member;
}),
);
}
this.usersLoaded.set(handle.ready());
});
});
});
},
Template.importMapMembers.onCreated(function () {
_importMapMembersTpl = this;
this.usersLoaded = new ReactiveVar(false);
members() {
return this.parentComponent().membersToMap.get();
},
this.members = () => {
const importTpl = findParentTemplateInstance(this, 'import');
return importTpl ? importTpl.membersToMap.get() : [];
};
_refreshMembers(listOfMembers) {
return this.parentComponent().membersToMap.set(listOfMembers);
},
this._refreshMembers = (listOfMembers) => {
const importTpl = findParentTemplateInstance(this, 'import');
if (importTpl) {
importTpl.membersToMap.set(listOfMembers);
}
};
/**
* 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) {
this._setPropertyForMember = (property, value, memberId, unset = false) => {
const listOfMembers = this.members();
let finder = null;
if (memberId) {
@ -241,17 +203,13 @@ BlazeComponent.extendComponent({
});
// Session.get gives us a copy, we have to set it back so it sticks
this._refreshMembers(listOfMembers);
},
};
setSelectedMember(memberId) {
this.setSelectedMember = (memberId) => {
return this._setPropertyForMember('selected', true, memberId, true);
},
};
/**
* returns the member with specified id,
* or the selected member if memberId is not specified
*/
getMember(memberId = null) {
this.getMember = (memberId = null) => {
const allMembers = this.members();
let finder = null;
if (memberId) {
@ -260,117 +218,154 @@ BlazeComponent.extendComponent({
finder = user => user.selected;
}
return allMembers.find(finder);
},
};
mapSelectedMember(wekanId) {
this.mapSelectedMember = (wekanId) => {
return this._setPropertyForMember('wekanId', wekanId, null);
},
};
unmapMember(memberId) {
this.unmapMember = (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();
this.parentComponent().nextStep();
const importTpl = findParentTemplateInstance(tpl, 'import');
if (importTpl) {
importTpl.nextStep();
}
},
events() {
return [
{
submit: this.onSubmit,
'click .js-select-member'(evt) {
const memberToMap = this.currentData();
if (memberToMap.wekan) {
// todo xxx ask for confirmation?
this.unmapMember(memberToMap.id);
} else {
this.setSelectedMember(memberToMap.id);
Popup.open('importMapMembersAdd')(evt);
}
},
},
];
'click .js-select-member'(evt, tpl) {
const memberToMap = Template.currentData();
if (memberToMap.wekan) {
// todo xxx ask for confirmation?
tpl.unmapMember(memberToMap.id);
} else {
tpl.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
const importMemberPopupState = {
searching: new ReactiveVar(false),
searchResults: new ReactiveVar([]),
noResults: new ReactiveVar(false),
searchTimeout: null
searchTimeout: null,
};
BlazeComponent.extendComponent({
onCreated() {
// Use global state
this.searching = importMemberPopupState.searching;
this.searchResults = importMemberPopupState.searchResults;
this.noResults = importMemberPopupState.noResults;
this.searchTimeout = importMemberPopupState.searchTimeout;
},
Template.importMapMembersAddPopup.onCreated(function () {
this.searching = importMemberPopupState.searching;
this.searchResults = importMemberPopupState.searchResults;
this.noResults = importMemberPopupState.noResults;
this.searchTimeout = null;
onRendered() {
this.find('.js-search-member-input').focus();
},
this.searching.set(false);
this.searchResults.set([]);
this.noResults.set(false);
});
performSearch(query) {
if (!query || query.length < 2) {
this.searchResults.set([]);
this.noResults.set(false);
return;
Template.importMapMembersAddPopup.onRendered(function () {
this.find('.js-search-member-input').focus();
});
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);
this.noResults.set(false);
const results = UserSearchIndex.search(query, { limit: 20 }).fetch();
this.searchResults.set(results);
this.searching.set(false);
if (results.length === 0) {
this.noResults.set(true);
}
tpl.searchTimeout = setTimeout(() => {
importPerformSearch(tpl, query);
}, 300);
},
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({
searchResults() {
@ -381,5 +376,5 @@ Template.importMapMembersAddPopup.helpers({
},
noResults() {
return importMemberPopupState.noResults;
}
})
},
});

View file

@ -18,21 +18,19 @@ const accessibilityHelpers = {
};
// Main accessibility page component
BlazeComponent.extendComponent({
onCreated() {
this.error = new ReactiveVar('');
this.loading = new ReactiveVar(false);
Template.accessibility.onCreated(function () {
this.error = new ReactiveVar('');
this.loading = new ReactiveVar(false);
Meteor.subscribe('setting');
Meteor.subscribe('accessibilitySettings');
},
...accessibilityHelpers
}).register('accessibility');
Meteor.subscribe('setting');
Meteor.subscribe('accessibilitySettings');
});
Template.accessibility.helpers(accessibilityHelpers);
// Header bar component
BlazeComponent.extendComponent({
onCreated() {
Meteor.subscribe('accessibilitySettings');
},
...accessibilityHelpers
}).register('accessibilityHeaderBar');
Template.accessibilityHeaderBar.onCreated(function () {
Meteor.subscribe('accessibilitySettings');
});
Template.accessibilityHeaderBar.helpers(accessibilityHelpers);

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({
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 {
onCreated() {
super.onCreated();
Meteor.subscribe('brokenCards', this.sessionId);
}
}
BrokenCardsComponent.register('brokenCards');
Template.brokenCards.events({
'click .js-next-page'(evt, tpl) {
evt.preventDefault();
tpl.search.nextPage();
},
'click .js-previous-page'(evt, tpl) {
evt.preventDefault();
tpl.search.previousPage();
},
});

View file

@ -1,178 +1,37 @@
import { ReactiveCache } from '/imports/reactiveCache';
import { BlazeComponent } from 'meteor/peerlibrary:blaze-components';
import { TAPi18n } from '/imports/i18n';
// const subManager = new SubsManager();
BlazeComponent.extendComponent({
Template.dueCardsHeaderBar.helpers({
dueCardsView() {
// eslint-disable-next-line no-console
// console.log('sort:', Utils.dueCardsView());
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({
events() {
return [
{
'click .js-due-cards-view-me'() {
if (Utils && Utils.setDueCardsView) {
Utils.setDueCardsView('me');
}
Popup.back();
},
Template.dueCardsHeaderBar.events({
'click .js-due-cards-view-change': Popup.open('dueCardsViewChange'),
});
'click .js-due-cards-view-all'() {
if (Utils && Utils.setDueCardsView) {
Utils.setDueCardsView('all');
}
Popup.back();
},
},
];
},
}).register('dueCardsViewChangePopup');
Template.dueCards.onCreated(function () {
this._cachedCards = null;
this._cachedTimestamp = null;
this.subscriptionHandle = null;
this.isLoading = new ReactiveVar(true);
this.hasResults = new ReactiveVar(false);
this.searching = new ReactiveVar(false);
class DueCardsComponent extends BlazeComponent {
onCreated() {
super.onCreated();
const tpl = this;
this._cachedCards = null;
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());
function dueCardsView() {
return Utils && Utils.dueCardsView ? Utils.dueCardsView() : 'me';
}
sortByBoard() {
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() {
function dueCardsList() {
// Check if subscription is ready
if (!this.subscriptionHandle || !this.subscriptionHandle.ready()) {
if (!tpl.subscriptionHandle || !tpl.subscriptionHandle.ready()) {
if (process.env.DEBUG === 'true') {
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
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') {
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)
@ -208,7 +67,7 @@ class DueCardsComponent extends BlazeComponent {
}
// Filter cards based on user view preference
const allUsers = this.dueCardsView() === 'all';
const allUsers = dueCardsView() === 'all';
const currentUser = ReactiveCache.getCurrentUser();
let filteredCards = cards;
@ -255,15 +114,106 @@ class DueCardsComponent extends BlazeComponent {
}
// Cache the results for 5 seconds to avoid re-filtering on every render
this._cachedCards = filteredCards;
this._cachedTimestamp = Date.now();
tpl._cachedCards = filteredCards;
tpl._cachedTimestamp = Date.now();
// Update reactive variables
this.hasResults.set(filteredCards && filteredCards.length > 0);
this.isLoading.set(false);
tpl.hasResults.set(filteredCards && filteredCards.length > 0);
tpl.isLoading.set(false);
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);
BlazeComponent.extendComponent({
onRendered() {
Template.editor.onRendered(function () {
const tpl = this;
// 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.
// - Also this same TODO below at event, if someone gets it working.
@ -89,7 +89,7 @@ BlazeComponent.extendComponent({
];
const enableTextarea = function() {
const $textarea = this.$(textareaSelector);
const $textarea = tpl.$(textareaSelector);
autosize($textarea);
$textarea.escapeableTextComplete(mentions);
};
@ -314,29 +314,25 @@ BlazeComponent.extendComponent({
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');
Utils.showCopied(promise, $tooltip);
},
'click a.fa.fa-brands.fa-markdown'(event) {
const $editor = this.$('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) {
// Utils.copyPre();
//},
}
]
}
}).register('editor');
Template.editor.events({
'click a.fa.fa-copy'(event, tpl) {
const $editor = tpl.$('textarea.editor');
const promise = Utils.copyTextToClipboard($editor[0].value);
const $tooltip = tpl.$('.copied-tooltip');
Utils.showCopied(promise, $tooltip);
},
'click a.fa.fa-brands.fa-markdown'(event, tpl) {
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) {
// Utils.copyPre();
//},
});
import DOMPurify from 'dompurify';
import { sanitizeHTML } from '/imports/lib/secureDOMPurify';

View file

@ -1,114 +1,154 @@
import { TAPi18n } from '/imports/i18n';
import { CardSearchPagedComponent } from '../../lib/cardSearch';
import { CardSearchPaged } from '../../lib/cardSearch';
import Boards from '../../../models/boards';
import { Query, QueryErrors } from '../../../config/query-classes';
// const subManager = new SubsManager();
BlazeComponent.extendComponent({
events() {
return [
{
'click .js-due-cards-view-change': Popup.open('globalSearchViewChange'),
},
];
},
}).register('globalSearchHeaderBar');
Template.globalSearchHeaderBar.events({
'click .js-due-cards-view-change': Popup.open('globalSearchViewChange'),
});
Template.globalSearch.onCreated(function () {
const search = new CardSearchPaged(this);
this.search = search;
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({
userId() {
return Meteor.userId();
},
});
class GlobalSearchComponent extends CardSearchPagedComponent {
onCreated() {
super.onCreated();
this.myLists = new ReactiveVar([]);
this.myLabelNames = new ReactiveVar([]);
this.myBoardNames = new ReactiveVar([]);
this.parsingErrors = new QueryErrors();
this.queryParams = null;
// 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;
},
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) => {
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);
}
});
}
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();
}
myLists() {
return Template.instance().myLists;
},
myLabelNames() {
return Template.instance().myLabelNames;
},
myBoardNames() {
return Template.instance().myBoardNames;
},
errorMessages() {
if (this.parsingErrors.hasErrors()) {
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());
}
return errorMessages(Template.instance());
},
searchInstructions() {
const tags = {
@ -203,7 +243,7 @@ class GlobalSearchComponent extends CardSearchPagedComponent {
.replace(/\>\*/, '\>\`')
});
return text;
}
},
labelColors() {
return Boards.simpleSchema()._schema['labels.$.color'].allowedValues.map(
@ -211,89 +251,163 @@ class GlobalSearchComponent extends CardSearchPagedComponent {
return { color, name: TAPi18n.__(`color-${color}`) };
},
);
}
},
});
events() {
return super.events().concat([
{
'submit .js-search-query-form'(evt) {
evt.preventDefault();
this.searchAllBoards(evt.target.searchQuery.value);
},
'click .js-label-color'(evt) {
evt.preventDefault();
const input = document.getElementById('global-search-input');
this.query.set(
`${input.value} ${TAPi18n.__('operator-label')}:"${
evt.currentTarget.textContent
}"`,
);
document.getElementById('global-search-input').focus();
},
'click .js-copy-debug-selector'(evt) {
/* Get the text field */
const selector = document.getElementById("debug-selector");
Template.globalSearch.events({
'submit .js-search-query-form'(evt, tpl) {
evt.preventDefault();
searchAllBoards(tpl, evt.target.searchQuery.value);
},
'click .js-label-color'(evt, tpl) {
evt.preventDefault();
const input = document.getElementById('global-search-input');
tpl.search.query.set(
`${input.value} ${TAPi18n.__('operator-label')}:"${
evt.currentTarget.textContent
}"`,
);
document.getElementById('global-search-input').focus();
},
'click .js-copy-debug-selector'(evt) {
/* Get the text field */
const selector = document.getElementById("debug-selector");
try {
navigator.clipboard.writeText(selector.textContent);
alert("Selector copied to clipboard");
} catch(err) {
alert("Error copying text: " + err);
}
try {
navigator.clipboard.writeText(selector.textContent);
alert("Selector copied to clipboard");
} catch(err) {
alert("Error copying text: " + err);
}
},
'click .js-copy-debug-projection'(evt) {
/* Get the text field */
const projection = document.getElementById("debug-projection");
},
'click .js-copy-debug-projection'(evt) {
/* Get the text field */
const projection = document.getElementById("debug-projection");
try {
navigator.clipboard.writeText(projection.textContent);
alert("Projection copied to clipboard");
} catch(err) {
alert("Error copying text: " + err);
}
try {
navigator.clipboard.writeText(projection.textContent);
alert("Projection copied to clipboard");
} catch(err) {
alert("Error copying text: " + err);
}
},
'click .js-board-title'(evt) {
evt.preventDefault();
const input = document.getElementById('global-search-input');
this.query.set(
`${input.value} ${TAPi18n.__('operator-board')}:"${
evt.currentTarget.textContent
}"`,
);
document.getElementById('global-search-input').focus();
},
'click .js-list-title'(evt) {
evt.preventDefault();
const input = document.getElementById('global-search-input');
this.query.set(
`${input.value} ${TAPi18n.__('operator-list')}:"${
evt.currentTarget.textContent
}"`,
);
document.getElementById('global-search-input').focus();
},
'click .js-label-name'(evt) {
evt.preventDefault();
const input = document.getElementById('global-search-input');
this.query.set(
`${input.value} ${TAPi18n.__('operator-label')}:"${
evt.currentTarget.textContent
}"`,
);
document.getElementById('global-search-input').focus();
},
'click .js-new-search'(evt) {
evt.preventDefault();
const input = document.getElementById('global-search-input');
input.value = '';
this.query.set('');
this.hasResults.set(false);
},
},
]);
}
}
},
'click .js-board-title'(evt, tpl) {
evt.preventDefault();
const input = document.getElementById('global-search-input');
tpl.search.query.set(
`${input.value} ${TAPi18n.__('operator-board')}:"${
evt.currentTarget.textContent
}"`,
);
document.getElementById('global-search-input').focus();
},
'click .js-list-title'(evt, tpl) {
evt.preventDefault();
const input = document.getElementById('global-search-input');
tpl.search.query.set(
`${input.value} ${TAPi18n.__('operator-list')}:"${
evt.currentTarget.textContent
}"`,
);
document.getElementById('global-search-input').focus();
},
'click .js-label-name'(evt, tpl) {
evt.preventDefault();
const input = document.getElementById('global-search-input');
tpl.search.query.set(
`${input.value} ${TAPi18n.__('operator-label')}:"${
evt.currentTarget.textContent
}"`,
);
document.getElementById('global-search-input').focus();
},
'click .js-new-search'(evt, tpl) {
evt.preventDefault();
const input = document.getElementById('global-search-input');
input.value = '';
tpl.search.query.set('');
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() {
// eslint-disable-next-line no-console
// console.log('sort:', Utils.myCardsSort());
@ -12,86 +12,69 @@ BlazeComponent.extendComponent({
// console.log('sort:', Utils.myCardsView());
return Utils.myCardsView();
},
});
events() {
return [
{
'click .js-toggle-my-cards-choose-sort': Popup.open(
'myCardsSortChange',
),
'click .js-my-cards-view-change': Popup.open(
'myCardsViewChange'),
},
];
},
}).register('myCardsHeaderBar');
Template.myCardsHeaderBar.events({
'click .js-toggle-my-cards-choose-sort': Popup.open(
'myCardsSortChange',
),
'click .js-my-cards-view-change': Popup.open(
'myCardsViewChange'),
});
Template.myCards.onCreated(function () {
const search = new CardSearchPaged(this);
this.search = search;
// 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({
userId() {
return Meteor.userId();
},
});
BlazeComponent.extendComponent({
events() {
return [
{
'click .js-my-cards-view-boards'() {
Utils.setMyCardsView('boards');
Popup.back();
},
'click .js-my-cards-view-table'() {
Utils.setMyCardsView('table');
Popup.back();
},
},
];
// Return ReactiveVar so jade can use .get pattern
searching() {
return Template.instance().search.searching;
},
}).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() {
// eslint-disable-next-line no-console
//console.log('sort:', Utils.myCardsView());
return Utils.myCardsView();
}
},
labelName(board, labelId) {
const label = board.getLabelById(labelId)
const name = label.name
return name
}
const label = board.getLabelById(labelId);
const name = label.name;
return name;
},
labelColor(board, labelId) {
const label = board.getLabelById(labelId)
const color = label.color
return color
}
const label = board.getLabelById(labelId);
const color = label.color;
return color;
},
myCardsList() {
const search = Template.instance().search;
const boards = [];
let board = null;
let swimlane = null;
let list = null;
const cursor = this.getResults();
const cursor = search.getResults();
if (cursor) {
cursor.forEach(card => {
@ -177,6 +160,28 @@ class MyCardsComponent extends CardSearchPagedComponent {
}
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 {
}.register('spinner'));
Template.spinner.helpers({
getSpinnerTemplate() {
return getSpinnerTemplate();
},
});
(class extends Spinner {
Template.spinnerRaw.helpers({
getSpinnerTemplateRaw() {
let ret = super.getSpinnerTemplate() + 'Raw';
return ret;
}
}.register('spinnerRaw'));
return getSpinnerTemplate() + 'Raw';
},
});

View file

@ -22,20 +22,18 @@ const supportHelpers = {
};
// Main support page component
BlazeComponent.extendComponent({
onCreated() {
this.error = new ReactiveVar('');
this.loading = new ReactiveVar(false);
Template.support.onCreated(function () {
this.error = new ReactiveVar('');
this.loading = new ReactiveVar(false);
Meteor.subscribe('setting');
},
...supportHelpers
}).register('support');
Meteor.subscribe('setting');
});
Template.support.helpers(supportHelpers);
// Header bar component
BlazeComponent.extendComponent({
onCreated() {
Meteor.subscribe('setting');
},
...supportHelpers
}).register('supportHeaderBar');
Template.supportHeaderBar.onCreated(function () {
Meteor.subscribe('setting');
});
Template.supportHeaderBar.helpers(supportHelpers);

View file

@ -1,12 +1,11 @@
import { ReactiveCache } from '/imports/reactiveCache';
import { TAPi18n } from '/imports/i18n';
BlazeComponent.extendComponent({
onCreated() {
// Ensure boards are available for action dropdowns
this.subscribe('boards');
},
Template.boardActions.onCreated(function () {
this.subscribe('boards');
});
Template.boardActions.helpers({
boards() {
const ret = ReactiveCache.getBoards(
{
@ -32,193 +31,195 @@ BlazeComponent.extendComponent({
}
return 'Loading boards...';
},
});
events() {
return [
{
'click .js-create-card-action'(event) {
const ruleName = this.data().ruleName.get();
const trigger = this.data().triggerVar.get();
const cardName = this.find('#card-name').value;
const listName = this.find('#list-name').value;
const swimlaneName = this.find('#swimlane-name2').value;
const boardId = Session.get('currentBoard');
const desc = Utils.getTriggerActionDesc(event, this);
const triggerId = Triggers.insert(trigger);
const actionId = Actions.insert({
actionType: 'createCard',
swimlaneName,
cardName,
listName,
boardId,
desc,
});
Rules.insert({
title: ruleName,
triggerId,
actionId,
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,
});
},
},
];
Template.boardActions.events({
'click .js-create-card-action'(event, tpl) {
const data = Template.currentData();
const ruleName = data.ruleName.get();
const trigger = data.triggerVar.get();
const cardName = tpl.find('#card-name').value;
const listName = tpl.find('#list-name').value;
const swimlaneName = tpl.find('#swimlane-name2').value;
const boardId = Session.get('currentBoard');
const desc = Utils.getTriggerActionDesc(event, tpl);
const triggerId = Triggers.insert(trigger);
const actionId = Actions.insert({
actionType: 'createCard',
swimlaneName,
cardName,
listName,
boardId,
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 */

View file

@ -3,18 +3,23 @@ Meteor.startup(() => {
cardColors = Cards.simpleSchema()._schema.color.allowedValues;
});
BlazeComponent.extendComponent({
onCreated() {
this.subscribe('allRules');
this.cardColorButtonValue = new ReactiveVar('green');
},
// Module-level shared state so the color popup can read/write the
// cardColorButtonValue without relying on BlazeComponent.getOpenerComponent().
let sharedCardColorButtonValue;
Template.cardActions.onCreated(function () {
this.subscribe('allRules');
this.cardColorButtonValue = new ReactiveVar('green');
sharedCardColorButtonValue = this.cardColorButtonValue;
});
Template.cardActions.helpers({
cardColorButton() {
return this.cardColorButtonValue.get();
return Template.instance().cardColorButtonValue.get();
},
cardColorButtonText() {
return `color-${this.cardColorButtonValue.get()}`;
return `color-${Template.instance().cardColorButtonValue.get()}`;
},
labels() {
@ -26,215 +31,214 @@ BlazeComponent.extendComponent({
}
return labels;
},
});
events() {
return [
{
'click .js-set-date-action'(event) {
const ruleName = this.data().ruleName.get();
const trigger = this.data().triggerVar.get();
const triggerId = Triggers.insert(trigger);
const actionSelected = this.find('#setdate-action').value;
const dateFieldSelected = this.find('#setdate-datefield').value;
const boardId = Session.get('currentBoard');
const desc = Utils.getTriggerActionDesc(event, this);
Template.cardActions.events({
'click .js-set-date-action'(event, tpl) {
const data = Template.currentData();
const ruleName = data.ruleName.get();
const trigger = data.triggerVar.get();
const triggerId = Triggers.insert(trigger);
const actionSelected = tpl.find('#setdate-action').value;
const dateFieldSelected = tpl.find('#setdate-datefield').value;
const boardId = Session.get('currentBoard');
const desc = Utils.getTriggerActionDesc(event, tpl);
const actionId = Actions.insert({
actionType: actionSelected,
dateField: dateFieldSelected,
boardId,
desc,
});
const actionId = Actions.insert({
actionType: actionSelected,
dateField: dateFieldSelected,
boardId,
desc,
});
Rules.insert({
title: ruleName,
triggerId,
actionId,
boardId,
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());
Rules.insert({
title: ruleName,
triggerId,
actionId,
boardId,
desc,
});
},
'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() {
return cardColors.map(color => ({ color, name: '' }));
},
isSelected(color) {
return this.currentColor.get() === color;
return Template.instance().currentColor.get() === color;
},
});
events() {
return [
{
'click .js-palette-color'() {
this.currentColor.set(this.currentData().color);
},
'click .js-submit'() {
this.colorButtonValue.set(this.currentColor.get());
Popup.back();
},
},
];
Template.setCardActionsColorPopup.events({
'click .js-palette-color'(event, tpl) {
tpl.currentColor.set(Template.currentData().color);
},
}).register('setCardActionsColorPopup');
'click .js-submit'(event, tpl) {
tpl.colorButtonValue.set(tpl.currentColor.get());
Popup.back();
},
});

View file

@ -1,150 +1,149 @@
BlazeComponent.extendComponent({
onCreated() {
this.subscribe('allRules');
Template.checklistActions.onCreated(function () {
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() {
return [
{
'click .js-add-checklist-items-action'(event) {
const ruleName = this.data().ruleName.get();
const trigger = this.data().triggerVar.get();
const checklistName = this.find('#checklist-name-3').value;
const checklistItems = this.find('#checklist-items').value;
const boardId = Session.get('currentBoard');
const desc = Utils.getTriggerActionDesc(event, this);
const triggerId = Triggers.insert(trigger);
const actionId = Actions.insert({
actionType: 'addChecklistWithItems',
checklistName,
checklistItems,
boardId,
desc,
});
Rules.insert({
title: ruleName,
triggerId,
actionId,
boardId,
});
},
'click .js-add-checklist-action'(event) {
const ruleName = this.data().ruleName.get();
const trigger = this.data().triggerVar.get();
const actionSelected = this.find('#check-action').value;
const checklistName = this.find('#checklist-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: 'addChecklist',
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,
});
}
},
},
];
'click .js-add-checklist-action'(event, tpl) {
const data = Template.currentData();
const ruleName = data.ruleName.get();
const trigger = data.triggerVar.get();
const actionSelected = tpl.find('#check-action').value;
const checklistName = tpl.find('#checklist-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: 'addChecklist',
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,
});
}
},
}).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({
onCreated() {},
events() {
return [
{
'click .js-mail-action'(event) {
const emailTo = this.find('#email-to').value;
const emailSubject = this.find('#email-subject').value;
const emailMsg = this.find('#email-msg').value;
const trigger = this.data().triggerVar.get();
const ruleName = this.data().ruleName.get();
const triggerId = Triggers.insert(trigger);
const boardId = Session.get('currentBoard');
const desc = Utils.getTriggerActionDesc(event, this);
const actionId = Actions.insert({
actionType: 'sendEmail',
emailTo,
emailSubject,
emailMsg,
boardId,
desc,
});
Rules.insert({
title: ruleName,
triggerId,
actionId,
boardId,
});
},
},
];
Template.mailActions.events({
'click .js-mail-action'(event, tpl) {
const emailTo = tpl.find('#email-to').value;
const emailSubject = tpl.find('#email-subject').value;
const emailMsg = tpl.find('#email-msg').value;
const data = Template.currentData();
const trigger = data.triggerVar.get();
const ruleName = data.ruleName.get();
const triggerId = Triggers.insert(trigger);
const boardId = Session.get('currentBoard');
const desc = Utils.getTriggerActionDesc(event, tpl);
const actionId = Actions.insert({
actionType: 'sendEmail',
emailTo,
emailSubject,
emailMsg,
boardId,
desc,
});
Rules.insert({
title: ruleName,
triggerId,
actionId,
boardId,
});
},
}).register('mailActions');
});

View file

@ -1,15 +1,15 @@
import { ReactiveCache } from '/imports/reactiveCache';
BlazeComponent.extendComponent({
onCreated() {
this.subscribe('allRules');
this.subscribe('allTriggers');
this.subscribe('allActions');
this.subscribe('boards');
},
Template.ruleDetails.onCreated(function () {
this.subscribe('allRules');
this.subscribe('allTriggers');
this.subscribe('allActions');
this.subscribe('boards');
});
Template.ruleDetails.helpers({
trigger() {
const ruleId = this.data().ruleId;
const ruleId = Template.currentData().ruleId;
const rule = ReactiveCache.getRule(ruleId.get());
const trigger = ReactiveCache.getTrigger(rule.triggerId);
const desc = trigger.description();
@ -17,15 +17,11 @@ BlazeComponent.extendComponent({
return upperdesc;
},
action() {
const ruleId = this.data().ruleId;
const ruleId = Template.currentData().ruleId;
const rule = ReactiveCache.getRule(ruleId.get());
const action = ReactiveCache.getAction(rule.actionId);
const desc = action.description();
const upperdesc = desc.charAt(0).toUpperCase() + desc.substr(1);
return upperdesc;
},
events() {
return [{}];
},
}).register('ruleDetails');
});

View file

@ -1,12 +1,20 @@
import { ReactiveCache } from '/imports/reactiveCache';
BlazeComponent.extendComponent({
onCreated() {
this.currentActions = new ReactiveVar('board');
Template.rulesActions.onCreated(function () {
this.currentActions = new ReactiveVar('board');
});
Template.rulesActions.helpers({
currentActions() {
return Template.instance().currentActions;
},
data() {
return Template.currentData();
},
ruleNameStr() {
const rn = this.data() && this.data().ruleName;
const rn = Template.currentData() && Template.currentData().ruleName;
try {
return rn && typeof rn.get === 'function' ? rn.get() : '';
} 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() {
const ret = ReactiveCache.getRules({});
return ret;
},
name() {
// console.log(this.data());
// console.log(Template.currentData());
},
events() {
return [
{
'click .js-set-board-actions'() {
this.setBoardActions();
},
'click .js-set-card-actions'() {
this.setCardActions();
},
'click .js-set-mail-actions'() {
this.setMailActions();
},
'click .js-set-checklist-actions'() {
this.setChecklistActions();
},
},
];
});
function setBoardActions(tpl) {
tpl.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');
}
function setCardActions(tpl) {
tpl.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');
}
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';
BlazeComponent.extendComponent({
onCreated() {
this.subscribe('allRules');
},
Template.rulesList.onCreated(function () {
this.subscribe('allRules');
});
Template.rulesList.helpers({
rules() {
const boardId = Session.get('currentBoard');
const ret = ReactiveCache.getRules({
@ -12,7 +12,4 @@ BlazeComponent.extendComponent({
});
return ret;
},
events() {
return [{}];
},
}).register('rulesList');
});

View file

@ -1,103 +1,98 @@
import { ReactiveCache } from '/imports/reactiveCache';
BlazeComponent.extendComponent({
onCreated() {
this.rulesCurrentTab = new ReactiveVar('rulesList');
this.ruleName = new ReactiveVar('');
this.triggerVar = new ReactiveVar();
this.ruleId = new ReactiveVar();
},
Template.rulesMain.onCreated(function () {
this.rulesCurrentTab = new ReactiveVar('rulesList');
this.ruleName = new ReactiveVar('');
this.triggerVar = new ReactiveVar();
this.ruleId = new ReactiveVar();
});
setTrigger() {
this.rulesCurrentTab.set('trigger');
Template.rulesMain.helpers({
rulesCurrentTab() {
return Template.instance().rulesCurrentTab;
},
sanitizeObject(obj) {
Object.keys(obj).forEach(key => {
if (obj[key] === '' || obj[key] === undefined) {
obj[key] = '*';
ruleName() {
return Template.instance().ruleName;
},
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() {
this.rulesCurrentTab.set('rulesList');
'click .js-show-user-field'(event) {
event.preventDefault();
$(event.currentTarget.offsetParent)
.find('.user-details')
.removeClass('hide-element');
},
setAction() {
this.rulesCurrentTab.set('action');
'click .js-goto-rules'(event, tpl) {
event.preventDefault();
tpl.rulesCurrentTab.set('rulesList');
},
setRuleDetails() {
this.rulesCurrentTab.set('ruleDetails');
'click .js-goback'(event, tpl) {
event.preventDefault();
if (
tpl.rulesCurrentTab.get() === 'trigger' ||
tpl.rulesCurrentTab.get() === 'ruleDetails'
) {
tpl.rulesCurrentTab.set('rulesList');
}
if (tpl.rulesCurrentTab.get() === 'action') {
tpl.rulesCurrentTab.set('trigger');
}
},
events() {
return [
{
'click .js-delete-rule'() {
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();
},
},
];
'click .js-goto-details'(event, tpl) {
event.preventDefault();
const rule = Template.currentData();
tpl.ruleId.set(rule._id);
tpl.rulesCurrentTab.set('ruleDetails');
},
}).register('rulesMain');
});

View file

@ -1,14 +1,14 @@
import { ReactiveCache } from '/imports/reactiveCache';
BlazeComponent.extendComponent({
onCreated() {
this.showBoardTrigger = new ReactiveVar(true);
this.showCardTrigger = new ReactiveVar(false);
this.showChecklistTrigger = new ReactiveVar(false);
},
Template.rulesTriggers.onCreated(function () {
this.showBoardTrigger = new ReactiveVar(true);
this.showCardTrigger = new ReactiveVar(false);
this.showChecklistTrigger = new ReactiveVar(false);
});
Template.rulesTriggers.helpers({
ruleNameStr() {
const rn = this.data() && this.data().ruleName;
const rn = Template.currentData() && Template.currentData().ruleName;
try {
return rn && typeof rn.get === 'function' ? rn.get() : '';
} catch (_) {
@ -16,29 +16,16 @@ BlazeComponent.extendComponent({
}
},
setBoardTriggers() {
this.showBoardTrigger.set(true);
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');
showBoardTrigger() {
return Template.instance().showBoardTrigger;
},
setCardTriggers() {
this.showBoardTrigger.set(false);
this.showCardTrigger.set(true);
this.showChecklistTrigger.set(false);
$('.js-set-card-triggers').addClass('active');
$('.js-set-board-triggers').removeClass('active');
$('.js-set-checklist-triggers').removeClass('active');
showCardTrigger() {
return Template.instance().showCardTrigger;
},
setChecklistTriggers() {
this.showBoardTrigger.set(false);
this.showCardTrigger.set(false);
this.showChecklistTrigger.set(true);
$('.js-set-card-triggers').removeClass('active');
$('.js-set-board-triggers').removeClass('active');
$('.js-set-checklist-triggers').addClass('active');
showChecklistTrigger() {
return Template.instance().showChecklistTrigger;
},
rules() {
@ -47,21 +34,45 @@ BlazeComponent.extendComponent({
},
name() {
// console.log(this.data());
// console.log(Template.currentData());
},
events() {
return [
{
'click .js-set-board-triggers'() {
this.setBoardTriggers();
},
'click .js-set-card-triggers'() {
this.setCardTriggers();
},
'click .js-set-checklist-triggers'() {
this.setChecklistTriggers();
},
},
];
});
function setBoardTriggers(tpl) {
tpl.showBoardTrigger.set(true);
tpl.showCardTrigger.set(false);
tpl.showChecklistTrigger.set(false);
$('.js-set-card-triggers').removeClass('active');
$('.js-set-board-triggers').addClass('active');
$('.js-set-checklist-triggers').removeClass('active');
}
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({
onCreated() {
this.provaVar = new ReactiveVar('');
this.currentPopupTriggerId = 'def';
this.cardTitleFilters = {};
},
setNameFilter(name) {
Template.boardTriggers.onCreated(function () {
this.provaVar = new ReactiveVar('');
this.currentPopupTriggerId = 'def';
this.cardTitleFilters = {};
this.setNameFilter = (name) => {
this.cardTitleFilters[this.currentPopupTriggerId] = name;
},
};
});
events() {
return [
{
'click .js-open-card-title-popup'(event) {
const funct = Popup.open('boardCardTitle');
const divId = $(event.currentTarget.parentNode.parentNode).attr('id');
//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,
});
}
},
},
];
Template.boardTriggers.events({
'click .js-open-card-title-popup'(event, tpl) {
const funct = Popup.open('boardCardTitle');
const divId = $(event.currentTarget.parentNode.parentNode).attr('id');
tpl.currentPopupTriggerId = divId;
funct.call(this, event);
},
}).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({
submit(event, templateInstance) {
const title = templateInstance
.$('.js-card-filter-name')
submit(event) {
const title = $(event.target)
.find('.js-card-filter-name')
.val()
.trim();
Popup.getOpenerComponent().setNameFilter(title);
const opener = Popup.getOpenerComponent();
if (opener?.setNameFilter) {
opener.setNameFilter(title);
}
event.preventDefault();
Popup.back();
},

View file

@ -1,9 +1,10 @@
import { TAPi18n } from '/imports/i18n';
BlazeComponent.extendComponent({
onCreated() {
this.subscribe('allRules');
},
Template.cardTriggers.onCreated(function () {
this.subscribe('allRules');
});
Template.cardTriggers.helpers({
labels() {
const labels = Utils.getCurrentBoard().labels;
for (let i = 0; i < labels.length; i++) {
@ -16,120 +17,117 @@ BlazeComponent.extendComponent({
}
return labels;
},
events() {
return [
{
'click .js-add-gen-label-trigger'(event) {
const desc = Utils.getTriggerActionDesc(event, this);
const datas = this.data();
const actionSelected = this.find('#label-action').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-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,
});
}
},
},
];
});
Template.cardTriggers.events({
'click .js-add-gen-label-trigger'(event, tpl) {
const desc = Utils.getTriggerActionDesc(event, tpl);
const datas = Template.currentData();
const actionSelected = tpl.find('#label-action').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,
});
}
},
}).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({
onCreated() {
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);
Template.checklistTriggers.onCreated(function () {
this.subscribe('allRules');
});
const datas = this.data();
const actionSelected = this.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) {
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,
});
}
},
},
];
Template.checklistTriggers.events({
'click .js-add-gen-check-trigger'(event, tpl) {
const desc = Utils.getTriggerActionDesc(event, tpl);
const datas = Template.currentData();
const actionSelected = tpl.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,
});
}
},
}).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;
});
BlazeComponent.extendComponent({
async editTitle(event) {
function swimlaneHeaderCollapsed(check = undefined) {
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();
const newTitle = this.childComponents('inlinedForm')[0]
.getValue()
.trim();
const swimlane = this.currentData();
swimlaneHeaderCollapsed(!swimlaneHeaderCollapsed());
},
'click .js-open-swimlane-menu': Popup.open('swimlaneAction'),
'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) {
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({
isBoardAdmin() {
@ -123,128 +113,105 @@ Template.swimlaneActionPopup.events({
},
});
BlazeComponent.extendComponent({
onCreated() {
this.currentSwimlane = this.currentData();
Template.swimlaneAddPopup.onCreated(function () {
this.currentSwimlane = Template.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() {
return [
{
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.onCreated(function () {
this.currentSwimlane = Template.currentData();
this.currentColor = new ReactiveVar(this.currentSwimlane.color);
});
Template.setSwimlaneColorPopup.helpers({
colors() {
return swimlaneColors.map(color => ({ color, name: '' }));
},
isSelected(color) {
return this.currentColor.get() === color;
return Template.instance().currentColor.get() === color;
},
});
events() {
return [
{
async 'submit form'(event) {
event.preventDefault();
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();
},
},
];
Template.setSwimlaneColorPopup.events({
async 'submit form'(event, tpl) {
event.preventDefault();
await tpl.currentSwimlane.setColor(tpl.currentColor.get());
Popup.back();
},
}).register('setSwimlaneColorPopup');
BlazeComponent.extendComponent({
onCreated() {
this.currentSwimlane = this.currentData();
'click .js-palette-color'(event, tpl) {
tpl.currentColor.set(Template.currentData().color);
},
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() {
const swimlane = this.currentData();
Template.setSwimlaneHeightPopup.onCreated(function () {
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 height = parseInt(
Template.instance()
.$('.swimlane-height-value')
.val(),
tpl.$('.swimlane-height-value').val(),
10,
);
// FIXME(mark-i-m): where do we put constants?
// also in imports/i18n/data/en.i18n.json
if (height != -1 && (height < 100 || !height)) {
Template.instance()
.$('.swimlane-height-error')
.click();
tpl.$('.swimlane-height-error').click();
} else {
Meteor.call('applySwimlaneHeight', board, swimlane._id, height);
Popup.back();
}
},
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');
'click .swimlane-height-error': Popup.open('swimlaneHeightError'),
});

File diff suppressed because it is too large Load diff

View file

@ -76,53 +76,38 @@ Template.userAvatarInitials.helpers({
},
});
BlazeComponent.extendComponent({
onCreated() {
this.error = new ReactiveVar('');
this.loading = new ReactiveVar(false);
this.findOrgsOptions = new ReactiveVar({});
Template.boardOrgRow.onCreated(function () {
this.error = new ReactiveVar('');
this.loading = new ReactiveVar(false);
this.findOrgsOptions = new ReactiveVar({});
this.page = new ReactiveVar(1);
this.autorun(() => {
const limitOrgs = this.page.get() * Number.MAX_SAFE_INTEGER;
this.subscribe('org', this.findOrgsOptions.get(), limitOrgs, () => {});
});
},
this.page = new ReactiveVar(1);
this.autorun(() => {
const limitOrgs = this.page.get() * Number.MAX_SAFE_INTEGER;
this.subscribe('org', this.findOrgsOptions.get(), limitOrgs, () => {});
});
});
onRendered() {
this.setLoading(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.onRendered(function () {
this.loading.set(false);
});
Template.boardOrgRow.helpers({
isLoading() {
return Template.instance().loading.get();
},
orgData() {
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({
orgName() {
const org = ReactiveCache.getOrg(this.orgId);
@ -135,53 +120,38 @@ Template.boardOrgName.helpers({
},
});
BlazeComponent.extendComponent({
onCreated() {
this.error = new ReactiveVar('');
this.loading = new ReactiveVar(false);
this.findOrgsOptions = new ReactiveVar({});
Template.boardTeamRow.onCreated(function () {
this.error = new ReactiveVar('');
this.loading = new ReactiveVar(false);
this.findOrgsOptions = new ReactiveVar({});
this.page = new ReactiveVar(1);
this.autorun(() => {
const limitTeams = this.page.get() * Number.MAX_SAFE_INTEGER;
this.subscribe('team', this.findOrgsOptions.get(), limitTeams, () => {});
});
},
this.page = new ReactiveVar(1);
this.autorun(() => {
const limitTeams = this.page.get() * Number.MAX_SAFE_INTEGER;
this.subscribe('team', this.findOrgsOptions.get(), limitTeams, () => {});
});
});
onRendered() {
this.setLoading(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.onRendered(function () {
this.loading.set(false);
});
Template.boardTeamRow.helpers({
isLoading() {
return Template.instance().loading.get();
},
teamData() {
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({
teamName() {
const team = ReactiveCache.getTeam(this.teamId);
@ -194,87 +164,79 @@ Template.boardTeamName.helpers({
},
});
BlazeComponent.extendComponent({
onCreated() {
this.error = new ReactiveVar('');
Template.changeAvatarPopup.onCreated(function () {
this.error = new ReactiveVar('');
Meteor.subscribe('my-avatars');
});
Meteor.subscribe('my-avatars');
Template.changeAvatarPopup.helpers({
error() {
return Template.instance().error;
},
uploadedAvatars() {
const ret = ReactiveCache.getAvatars({ userId: Meteor.userId() }, {}, true);
return ret;
},
isSelected() {
const userProfile = ReactiveCache.getCurrentUser().profile;
const avatarUrl = userProfile && userProfile.avatarUrl;
const currentAvatarUrl = this.currentData().link();
const currentAvatarUrl = Template.currentData().link();
return avatarUrl === currentAvatarUrl;
},
noAvatarUrl() {
const userProfile = ReactiveCache.getCurrentUser().profile;
const avatarUrl = userProfile && userProfile.avatarUrl;
return !avatarUrl;
},
});
setAvatar(avatarUrl) {
Meteor.call('setAvatarUrl', avatarUrl, (err) => {
if (err) {
this.setError(err.reason || 'Error setting avatar');
}
});
},
function changeAvatarSetAvatar(tpl, avatarUrl) {
Meteor.call('setAvatarUrl', avatarUrl, (err) => {
if (err) {
tpl.error.set(err.reason || 'Error setting avatar');
}
});
}
setError(error) {
this.error.set(error);
Template.changeAvatarPopup.events({
'click .js-upload-avatar'(event, tpl) {
tpl.$('.js-upload-avatar-input').click();
},
events() {
return [
{
'click .js-upload-avatar'() {
this.$('.js-upload-avatar-input').click();
'change .js-upload-avatar-input'(event, tpl) {
if (event.currentTarget.files && event.currentTarget.files[0]) {
const uploader = Avatars.insert(
{
file: event.currentTarget.files[0],
chunkSize: 'dynamic',
},
'change .js-upload-avatar-input'(event) {
const self = this;
if (event.currentTarget.files && event.currentTarget.files[0]) {
const uploader = Avatars.insert(
{
file: event.currentTarget.files[0],
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();
}),
},
];
false,
);
uploader.on('error', (error, fileData) => {
tpl.error.set(error.reason);
});
uploader.start();
}
},
}).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({
user() {

View file

@ -7,11 +7,9 @@ Template.headerUserBar.events({
'click .js-change-avatar': Popup.open('changeAvatar'),
});
BlazeComponent.extendComponent({
onCreated() {
Meteor.subscribe('setting');
},
}).register('memberMenuPopup');
Template.memberMenuPopup.onCreated(function () {
Meteor.subscribe('setting');
});
Template.memberMenuPopup.helpers({
templatesBoardId() {
@ -114,12 +112,6 @@ Template.memberMenuPopup.events({
},
});
BlazeComponent.extendComponent({
onCreated() {
Meteor.subscribe('setting');
},
}).register('editProfilePopup');
Template.invitePeoplePopup.events({
'click a.js-toggle-board-choose'(event){
let target = $(event.target);
@ -169,6 +161,7 @@ Template.invitePeoplePopup.events({
});
Template.editProfilePopup.onCreated(function() {
Meteor.subscribe('setting');
this.subscribe('accountSettings');
});