mirror of
https://github.com/wekan/wekan.git
synced 2025-12-20 09:20:12 +01:00
Add Feature: allow user to sort Lists in Board by his own preference, boardadmin can star list
This commit is contained in:
parent
2737d6b23f
commit
bc2a20f04e
15 changed files with 272 additions and 14 deletions
|
|
@ -77,6 +77,10 @@ template(name="boardHeaderBar")
|
||||||
i.fa.fa-archive
|
i.fa.fa-archive
|
||||||
span {{_ 'archives'}}
|
span {{_ 'archives'}}
|
||||||
|
|
||||||
|
if showSort
|
||||||
|
a.board-header-btn.js-open-sort-view(title="{{_ 'sort-desc'}}")
|
||||||
|
i.fa(class="{{directionClass}}")
|
||||||
|
span {{_ 'sort'}}{{_ listSortShortDesc}}
|
||||||
a.board-header-btn.js-open-filter-view(
|
a.board-header-btn.js-open-filter-view(
|
||||||
title="{{#if Filter.isActive}}{{_ 'filter-on-desc'}}{{else}}{{_ 'filter'}}{{/if}}"
|
title="{{#if Filter.isActive}}{{_ 'filter-on-desc'}}{{else}}{{_ 'filter'}}{{/if}}"
|
||||||
class="{{#if Filter.isActive}}emphasis{{/if}}")
|
class="{{#if Filter.isActive}}emphasis{{/if}}")
|
||||||
|
|
@ -194,6 +198,20 @@ template(name="createBoard")
|
||||||
| /
|
| /
|
||||||
a.js-board-template {{_ 'template'}}
|
a.js-board-template {{_ 'template'}}
|
||||||
|
|
||||||
|
template(name="listsortPopup")
|
||||||
|
h2
|
||||||
|
| {{_ 'list-sort-by'}}
|
||||||
|
hr
|
||||||
|
ul.pop-over-list
|
||||||
|
each value in allowedSortValues
|
||||||
|
li
|
||||||
|
a.js-sort-by(name="{{value.name}}")
|
||||||
|
if $eq sortby value.name
|
||||||
|
i(class="fa {{Direction}}")
|
||||||
|
| {{_ value.label }}{{_ value.shortLabel}}
|
||||||
|
if $eq sortby value.name
|
||||||
|
i(class="fa fa-check")
|
||||||
|
|
||||||
template(name="boardChangeTitlePopup")
|
template(name="boardChangeTitlePopup")
|
||||||
form
|
form
|
||||||
label
|
label
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
const DOWNCLS = 'fa-sort-down';
|
||||||
|
const UPCLS = 'fa-sort-up';
|
||||||
Template.boardMenuPopup.events({
|
Template.boardMenuPopup.events({
|
||||||
'click .js-rename-board': Popup.open('boardChangeTitle'),
|
'click .js-rename-board': Popup.open('boardChangeTitle'),
|
||||||
'click .js-custom-fields'() {
|
'click .js-custom-fields'() {
|
||||||
|
|
@ -80,7 +82,25 @@ BlazeComponent.extendComponent({
|
||||||
const currentBoard = Boards.findOne(Session.get('currentBoard'));
|
const currentBoard = Boards.findOne(Session.get('currentBoard'));
|
||||||
return currentBoard && currentBoard.stars >= 2;
|
return currentBoard && currentBoard.stars >= 2;
|
||||||
},
|
},
|
||||||
|
showSort() {
|
||||||
|
return Meteor.user().hasSortBy();
|
||||||
|
},
|
||||||
|
directionClass() {
|
||||||
|
return this.currentDirection() === -1 ? DOWNCLS : UPCLS;
|
||||||
|
},
|
||||||
|
changeDirection() {
|
||||||
|
const direction = 0 - this.currentDirection() === -1 ? '-' : '';
|
||||||
|
Meteor.call('setListSortBy', direction + this.currentListSortBy());
|
||||||
|
},
|
||||||
|
currentDirection() {
|
||||||
|
return Meteor.user().getListSortByDirection();
|
||||||
|
},
|
||||||
|
currentListSortBy() {
|
||||||
|
return Meteor.user().getListSortBy();
|
||||||
|
},
|
||||||
|
listSortShortDesc() {
|
||||||
|
return `list-label-short-${this.currentListSortBy()}`;
|
||||||
|
},
|
||||||
events() {
|
events() {
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
|
|
@ -118,6 +138,16 @@ BlazeComponent.extendComponent({
|
||||||
'click .js-open-filter-view'() {
|
'click .js-open-filter-view'() {
|
||||||
Sidebar.setView('filter');
|
Sidebar.setView('filter');
|
||||||
},
|
},
|
||||||
|
'click .js-open-sort-view'(evt) {
|
||||||
|
const target = evt.target;
|
||||||
|
if (target.tagName === 'I') {
|
||||||
|
// click on the text, popup choices
|
||||||
|
this.changeDirection();
|
||||||
|
} else {
|
||||||
|
// change the sort order
|
||||||
|
Popup.open('listsort')(evt);
|
||||||
|
}
|
||||||
|
},
|
||||||
'click .js-filter-reset'(event) {
|
'click .js-filter-reset'(event) {
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
Sidebar.setView();
|
Sidebar.setView();
|
||||||
|
|
@ -277,3 +307,73 @@ BlazeComponent.extendComponent({
|
||||||
];
|
];
|
||||||
},
|
},
|
||||||
}).register('boardChangeWatchPopup');
|
}).register('boardChangeWatchPopup');
|
||||||
|
|
||||||
|
BlazeComponent.extendComponent({
|
||||||
|
onCreated() {
|
||||||
|
//this.sortBy = new ReactiveVar();
|
||||||
|
////this.sortDirection = new ReactiveVar();
|
||||||
|
//this.setSortBy();
|
||||||
|
this.downClass = DOWNCLS;
|
||||||
|
this.upClass = UPCLS;
|
||||||
|
},
|
||||||
|
allowedSortValues() {
|
||||||
|
const types = [];
|
||||||
|
const pushed = {};
|
||||||
|
Meteor.user()
|
||||||
|
.getListSortTypes()
|
||||||
|
.forEach(type => {
|
||||||
|
const key = type.replace(/^-/, '');
|
||||||
|
if (pushed[key] === undefined) {
|
||||||
|
types.push({
|
||||||
|
name: key,
|
||||||
|
label: `list-label-${key}`,
|
||||||
|
shortLabel: `list-label-short-${key}`,
|
||||||
|
});
|
||||||
|
pushed[key] = 1;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return types;
|
||||||
|
},
|
||||||
|
Direction() {
|
||||||
|
return Meteor.user().getListSortByDirection() === -1
|
||||||
|
? this.downClass
|
||||||
|
: this.upClass;
|
||||||
|
},
|
||||||
|
sortby() {
|
||||||
|
return Meteor.user().getListSortBy();
|
||||||
|
},
|
||||||
|
|
||||||
|
setSortBy(type = null) {
|
||||||
|
const user = Meteor.user();
|
||||||
|
if (type === null) {
|
||||||
|
type = user._getListSortBy();
|
||||||
|
} else {
|
||||||
|
let value = '';
|
||||||
|
if (type.map) {
|
||||||
|
// is an array
|
||||||
|
value = (type[1] === -1 ? '-' : '') + type[0];
|
||||||
|
}
|
||||||
|
Meteor.call('setListSortBy', value);
|
||||||
|
}
|
||||||
|
//this.sortBy.set(type[0]);
|
||||||
|
//this.sortDirection.set(type[1]);
|
||||||
|
},
|
||||||
|
|
||||||
|
events() {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
'click .js-sort-by'(evt) {
|
||||||
|
evt.preventDefault();
|
||||||
|
const target = evt.target;
|
||||||
|
const sortby = target.getAttribute('name');
|
||||||
|
const down = !!target.querySelector(`.${this.upClass}`);
|
||||||
|
const direction = down ? -1 : 1;
|
||||||
|
this.setSortBy([sortby, direction]);
|
||||||
|
if (Utils.isMiniScreen) {
|
||||||
|
Popup.close();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
},
|
||||||
|
}).register('listsortPopup');
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ template(name="listHeader")
|
||||||
if currentList
|
if currentList
|
||||||
a.list-header-left-icon.fa.fa-angle-left.js-unselect-list
|
a.list-header-left-icon.fa.fa-angle-left.js-unselect-list
|
||||||
h2.list-header-name(
|
h2.list-header-name(
|
||||||
title="{{ moment updatedAt 'LLL' }}"
|
title="{{ moment modifiedAt 'LLL' }}"
|
||||||
class="{{#if currentUser.isBoardMember}}{{#unless currentUser.isCommentOnly}}js-open-inlined-form is-editable{{/unless}}{{/if}}")
|
class="{{#if currentUser.isBoardMember}}{{#unless currentUser.isCommentOnly}}js-open-inlined-form is-editable{{/unless}}{{/if}}")
|
||||||
+viewer
|
+viewer
|
||||||
= title
|
= title
|
||||||
|
|
@ -39,6 +39,8 @@ template(name="listHeader")
|
||||||
i.list-header-watch-icon.fa.fa-eye
|
i.list-header-watch-icon.fa.fa-eye
|
||||||
div.list-header-menu
|
div.list-header-menu
|
||||||
unless currentUser.isCommentOnly
|
unless currentUser.isCommentOnly
|
||||||
|
if isBoardAdmin
|
||||||
|
a.fa.js-list-star.list-header-plus-icon(class="fa-star{{#unless starred}}-o{{/unless}}")
|
||||||
if canSeeAddCard
|
if canSeeAddCard
|
||||||
a.js-add-card.fa.fa-plus.list-header-plus-icon
|
a.js-add-card.fa.fa-plus.list-header-plus-icon
|
||||||
a.fa.fa-navicon.js-open-list-menu
|
a.fa.fa-navicon.js-open-list-menu
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,20 @@ BlazeComponent.extendComponent({
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
isBoardAdmin() {
|
||||||
|
return Meteor.user().isBoardAdmin();
|
||||||
|
},
|
||||||
|
starred(check = undefined) {
|
||||||
|
const list = Template.currentData();
|
||||||
|
const status = list.isStarred();
|
||||||
|
if (check === undefined) {
|
||||||
|
// just check
|
||||||
|
return status;
|
||||||
|
} else {
|
||||||
|
list.star(!status);
|
||||||
|
return !status;
|
||||||
|
}
|
||||||
|
},
|
||||||
editTitle(event) {
|
editTitle(event) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
const newTitle = this.childComponents('inlinedForm')[0]
|
const newTitle = this.childComponents('inlinedForm')[0]
|
||||||
|
|
@ -61,6 +75,10 @@ BlazeComponent.extendComponent({
|
||||||
events() {
|
events() {
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
|
'click .js-list-star'(event) {
|
||||||
|
event.preventDefault();
|
||||||
|
this.starred(!this.starred());
|
||||||
|
},
|
||||||
'click .js-open-list-menu': Popup.open('listAction'),
|
'click .js-open-list-menu': Popup.open('listAction'),
|
||||||
'click .js-add-card'(event) {
|
'click .js-add-card'(event) {
|
||||||
const listDom = $(event.target).parents(
|
const listDom = $(event.target).parents(
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,9 @@
|
||||||
and #each x in y constructors to fix this.
|
and #each x in y constructors to fix this.
|
||||||
|
|
||||||
template(name="filterSidebar")
|
template(name="filterSidebar")
|
||||||
|
ul.sidebar-list
|
||||||
|
span {{_ 'list-filter-label'}}
|
||||||
|
input.js-list-filter(type="text")
|
||||||
ul.sidebar-list
|
ul.sidebar-list
|
||||||
li(class="{{#if Filter.labelIds.isSelected undefined}}active{{/if}}")
|
li(class="{{#if Filter.labelIds.isSelected undefined}}active{{/if}}")
|
||||||
a.name.js-toggle-label-filter
|
a.name.js-toggle-label-filter
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,10 @@ BlazeComponent.extendComponent({
|
||||||
events() {
|
events() {
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
|
'change .js-list-filter'(evt) {
|
||||||
|
evt.preventDefault();
|
||||||
|
Filter.lists.set(this.find('.js-list-filter').value.trim());
|
||||||
|
},
|
||||||
'click .js-toggle-label-filter'(evt) {
|
'click .js-toggle-label-filter'(evt) {
|
||||||
evt.preventDefault();
|
evt.preventDefault();
|
||||||
Filter.labelIds.toggle(this.currentData()._id);
|
Filter.labelIds.toggle(this.currentData()._id);
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,7 @@ template(name="listsGroup")
|
||||||
+cardDetails(currentCard)
|
+cardDetails(currentCard)
|
||||||
|
|
||||||
template(name="addListForm")
|
template(name="addListForm")
|
||||||
.list.list-composer.js-list-composer
|
.list.list-composer.js-list-composer(class="{{#if isMiniScreen}}mini-list{{/if}}")
|
||||||
.list-header-add
|
.list-header-add
|
||||||
+inlinedForm(autoclose=false)
|
+inlinedForm(autoclose=false)
|
||||||
input.list-name-input.full-line(type="text" placeholder="{{_ 'add-list'}}"
|
input.list-name-input.full-line(type="text" placeholder="{{_ 'add-list'}}"
|
||||||
|
|
|
||||||
|
|
@ -267,6 +267,11 @@ BlazeComponent.extendComponent({
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (Filter.lists._isActive()) {
|
||||||
|
if (!list.title.match(Filter.lists.getRegexSelector())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
if (Filter.hideEmpty.isSelected()) {
|
if (Filter.hideEmpty.isSelected()) {
|
||||||
const swimlaneId = this.parentComponent()
|
const swimlaneId = this.parentComponent()
|
||||||
.parentComponent()
|
.parentComponent()
|
||||||
|
|
|
||||||
|
|
@ -439,6 +439,14 @@ class AdvancedFilter {
|
||||||
const commands = this._filterToCommands();
|
const commands = this._filterToCommands();
|
||||||
return this._arrayToSelector(commands);
|
return this._arrayToSelector(commands);
|
||||||
}
|
}
|
||||||
|
getRegexSelector() {
|
||||||
|
// generate a regex for filter list
|
||||||
|
this._dep.depend();
|
||||||
|
return new RegExp(
|
||||||
|
`^.*${this._filter.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}.*$`,
|
||||||
|
'i',
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// The global Filter object.
|
// The global Filter object.
|
||||||
|
|
@ -455,8 +463,16 @@ Filter = {
|
||||||
hideEmpty: new SetFilter(),
|
hideEmpty: new SetFilter(),
|
||||||
customFields: new SetFilter('_id'),
|
customFields: new SetFilter('_id'),
|
||||||
advanced: new AdvancedFilter(),
|
advanced: new AdvancedFilter(),
|
||||||
|
lists: new AdvancedFilter(), // we need the ability to filter list by name as well
|
||||||
|
|
||||||
_fields: ['labelIds', 'members', 'archive', 'hideEmpty', 'customFields'],
|
_fields: [
|
||||||
|
'labelIds',
|
||||||
|
'members',
|
||||||
|
'archive',
|
||||||
|
'hideEmpty',
|
||||||
|
'customFields',
|
||||||
|
'lists',
|
||||||
|
],
|
||||||
|
|
||||||
// We don't filter cards that have been added after the last filter change. To
|
// We don't filter cards that have been added after the last filter change. To
|
||||||
// implement this we keep the id of these cards in this `_exceptions` fields
|
// implement this we keep the id of these cards in this `_exceptions` fields
|
||||||
|
|
|
||||||
|
|
@ -300,8 +300,18 @@
|
||||||
"error-username-taken": "This username is already taken",
|
"error-username-taken": "This username is already taken",
|
||||||
"error-email-taken": "Email has already been taken",
|
"error-email-taken": "Email has already been taken",
|
||||||
"export-board": "Export board",
|
"export-board": "Export board",
|
||||||
|
"sort": "Sort",
|
||||||
|
"sort-desc": "Click to Sort List",
|
||||||
|
"list-sort-by": "Sort the List By:",
|
||||||
|
"list-label-modifiedAt": "Last Access Time",
|
||||||
|
"list-label-title": "Name of the List",
|
||||||
|
"list-label-sort": "Your Manual Order",
|
||||||
|
"list-label-short-modifiedAt": "(L)",
|
||||||
|
"list-label-short-title": "(N)",
|
||||||
|
"list-label-short-sort": "(M)",
|
||||||
"filter": "Filter",
|
"filter": "Filter",
|
||||||
"filter-cards": "Filter Cards",
|
"filter-cards": "Filter Cards or Lists",
|
||||||
|
"list-filter-label": "Filter List by Title",
|
||||||
"filter-clear": "Clear filter",
|
"filter-clear": "Clear filter",
|
||||||
"filter-no-label": "No label",
|
"filter-no-label": "No label",
|
||||||
"filter-no-member": "No member",
|
"filter-no-member": "No member",
|
||||||
|
|
|
||||||
|
|
@ -409,18 +409,20 @@ Boards.helpers({
|
||||||
},
|
},
|
||||||
|
|
||||||
lists() {
|
lists() {
|
||||||
const enabled = Meteor.user().hasShowDesktopDragHandles();
|
const enabled = Meteor.user().hasSortBy();
|
||||||
return enabled ? this.draggableLists() : this.newestLists();
|
return enabled ? this.newestLists() : this.draggableLists();
|
||||||
},
|
},
|
||||||
|
|
||||||
newestLists() {
|
newestLists() {
|
||||||
// sorted lists from newest to the oldest, by its creation date or its cards' last modification date
|
// sorted lists from newest to the oldest, by its creation date or its cards' last modification date
|
||||||
|
const value = Meteor.user()._getListSortBy();
|
||||||
|
const sortKey = { starred: -1, [value[0]]: value[1] }; // [["starred",-1],value];
|
||||||
return Lists.find(
|
return Lists.find(
|
||||||
{
|
{
|
||||||
boardId: this._id,
|
boardId: this._id,
|
||||||
archived: false,
|
archived: false,
|
||||||
},
|
},
|
||||||
{ sort: { updatedAt: -1 } },
|
{ sort: sortKey },
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
draggableLists() {
|
draggableLists() {
|
||||||
|
|
|
||||||
|
|
@ -1696,9 +1696,11 @@ if (Meteor.isServer) {
|
||||||
const activityType = `a-${action}`;
|
const activityType = `a-${action}`;
|
||||||
const card = Cards.findOne(doc._id);
|
const card = Cards.findOne(doc._id);
|
||||||
const list = card.list();
|
const list = card.list();
|
||||||
if (list) {
|
if (list && action === 'endAt') {
|
||||||
// change list modifiedAt
|
// change list modifiedAt
|
||||||
const modifiedAt = new Date();
|
const modifiedAt = new Date(
|
||||||
|
new Date(value).getTime() - 365 * 24 * 3600 * 1e3,
|
||||||
|
); // set it as 1 year before
|
||||||
const boardId = list.boardId;
|
const boardId = list.boardId;
|
||||||
Lists.direct.update(
|
Lists.direct.update(
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,15 @@ Lists.attachSchema(
|
||||||
*/
|
*/
|
||||||
type: String,
|
type: String,
|
||||||
},
|
},
|
||||||
|
starred: {
|
||||||
|
/**
|
||||||
|
* if a list is stared
|
||||||
|
* then we put it on the top
|
||||||
|
*/
|
||||||
|
type: Boolean,
|
||||||
|
optional: true,
|
||||||
|
defaultValue: false,
|
||||||
|
},
|
||||||
archived: {
|
archived: {
|
||||||
/**
|
/**
|
||||||
* is the list archived
|
* is the list archived
|
||||||
|
|
@ -81,10 +90,14 @@ Lists.attachSchema(
|
||||||
denyUpdate: false,
|
denyUpdate: false,
|
||||||
// eslint-disable-next-line consistent-return
|
// eslint-disable-next-line consistent-return
|
||||||
autoValue() {
|
autoValue() {
|
||||||
if (this.isInsert || this.isUpsert || this.isUpdate) {
|
// this is redundant with updatedAt
|
||||||
|
/*if (this.isInsert || this.isUpsert || this.isUpdate) {
|
||||||
return new Date();
|
return new Date();
|
||||||
} else {
|
} else {
|
||||||
this.unset();
|
this.unset();
|
||||||
|
}*/
|
||||||
|
if (!this.isSet) {
|
||||||
|
return new Date();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
@ -252,6 +265,10 @@ Lists.helpers({
|
||||||
return this.type === 'template-list';
|
return this.type === 'template-list';
|
||||||
},
|
},
|
||||||
|
|
||||||
|
isStarred() {
|
||||||
|
return this.starred === true;
|
||||||
|
},
|
||||||
|
|
||||||
remove() {
|
remove() {
|
||||||
Lists.remove({ _id: this._id });
|
Lists.remove({ _id: this._id });
|
||||||
},
|
},
|
||||||
|
|
@ -261,6 +278,9 @@ Lists.mutations({
|
||||||
rename(title) {
|
rename(title) {
|
||||||
return { $set: { title } };
|
return { $set: { title } };
|
||||||
},
|
},
|
||||||
|
star(enable = true) {
|
||||||
|
return { $set: { starred: !!enable } };
|
||||||
|
},
|
||||||
|
|
||||||
archive() {
|
archive() {
|
||||||
if (this.isTemplateList()) {
|
if (this.isTemplateList()) {
|
||||||
|
|
|
||||||
|
|
@ -174,8 +174,8 @@ Swimlanes.helpers({
|
||||||
},
|
},
|
||||||
|
|
||||||
lists() {
|
lists() {
|
||||||
const enabled = Meteor.user().hasShowDesktopDragHandles();
|
const enabled = Meteor.user().hasSortBy();
|
||||||
return enabled ? this.draggableLists() : this.newestLists();
|
return enabled ? this.newestLists() : this.draggableLists();
|
||||||
},
|
},
|
||||||
newestLists() {
|
newestLists() {
|
||||||
// sorted lists from newest to the oldest, by its creation date or its cards' last modification date
|
// sorted lists from newest to the oldest, by its creation date or its cards' last modification date
|
||||||
|
|
@ -185,7 +185,7 @@ Swimlanes.helpers({
|
||||||
swimlaneId: { $in: [this._id, ''] },
|
swimlaneId: { $in: [this._id, ''] },
|
||||||
archived: false,
|
archived: false,
|
||||||
},
|
},
|
||||||
{ sort: { updatedAt: -1 } },
|
{ sort: { modifiedAt: -1 } },
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
draggableLists() {
|
draggableLists() {
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,16 @@ const isSandstorm =
|
||||||
Meteor.settings && Meteor.settings.public && Meteor.settings.public.sandstorm;
|
Meteor.settings && Meteor.settings.public && Meteor.settings.public.sandstorm;
|
||||||
Users = Meteor.users;
|
Users = Meteor.users;
|
||||||
|
|
||||||
|
const allowedSortValues = [
|
||||||
|
'-modifiedAt',
|
||||||
|
'modifiedAt',
|
||||||
|
'-title',
|
||||||
|
'title',
|
||||||
|
'-sort',
|
||||||
|
'sort',
|
||||||
|
];
|
||||||
|
const defaultSortBy = allowedSortValues[0];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A User in wekan
|
* A User in wekan
|
||||||
*/
|
*/
|
||||||
|
|
@ -191,6 +201,15 @@ Users.attachSchema(
|
||||||
'board-view-cal',
|
'board-view-cal',
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
'profile.listSortBy': {
|
||||||
|
/**
|
||||||
|
* default sort list for user
|
||||||
|
*/
|
||||||
|
type: String,
|
||||||
|
optional: true,
|
||||||
|
defaultValue: defaultSortBy,
|
||||||
|
allowedValues: allowedSortValues,
|
||||||
|
},
|
||||||
'profile.templatesBoardId': {
|
'profile.templatesBoardId': {
|
||||||
/**
|
/**
|
||||||
* Reference to the templates board
|
* Reference to the templates board
|
||||||
|
|
@ -365,6 +384,31 @@ Users.helpers({
|
||||||
return _.contains(invitedBoards, boardId);
|
return _.contains(invitedBoards, boardId);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_getListSortBy() {
|
||||||
|
const profile = this.profile || {};
|
||||||
|
const sortBy = profile.listSortBy || defaultSortBy;
|
||||||
|
const keyPattern = /^(-{0,1})(.*$)/;
|
||||||
|
const ret = [];
|
||||||
|
if (keyPattern.exec(sortBy)) {
|
||||||
|
ret[0] = RegExp.$2;
|
||||||
|
ret[1] = RegExp.$1 ? -1 : 1;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
},
|
||||||
|
hasSortBy() {
|
||||||
|
// if use doesn't have dragHandle, then we can let user to choose sort list by different order
|
||||||
|
return !this.hasShowDesktopDragHandles();
|
||||||
|
},
|
||||||
|
getListSortBy() {
|
||||||
|
return this._getListSortBy()[0];
|
||||||
|
},
|
||||||
|
getListSortTypes() {
|
||||||
|
return allowedSortValues;
|
||||||
|
},
|
||||||
|
getListSortByDirection() {
|
||||||
|
return this._getListSortBy()[1];
|
||||||
|
},
|
||||||
|
|
||||||
hasTag(tag) {
|
hasTag(tag) {
|
||||||
const { tags = [] } = this.profile || {};
|
const { tags = [] } = this.profile || {};
|
||||||
return _.contains(tags, tag);
|
return _.contains(tags, tag);
|
||||||
|
|
@ -485,6 +529,13 @@ Users.mutations({
|
||||||
else this.addTag(tag);
|
else this.addTag(tag);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
setListSortBy(value) {
|
||||||
|
return {
|
||||||
|
$set: {
|
||||||
|
'profile.listSortBy': value,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
},
|
||||||
toggleDesktopHandles(value = false) {
|
toggleDesktopHandles(value = false) {
|
||||||
return {
|
return {
|
||||||
$set: {
|
$set: {
|
||||||
|
|
@ -569,6 +620,10 @@ Meteor.methods({
|
||||||
Users.update(userId, { $set: { username } });
|
Users.update(userId, { $set: { username } });
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
setListSortBy(value) {
|
||||||
|
check(value, String);
|
||||||
|
Meteor.user().setListSortBy(value);
|
||||||
|
},
|
||||||
toggleDesktopDragHandles() {
|
toggleDesktopDragHandles() {
|
||||||
const user = Meteor.user();
|
const user = Meteor.user();
|
||||||
user.toggleDesktopHandles(user.hasShowDesktopDragHandles());
|
user.toggleDesktopHandles(user.hasShowDesktopDragHandles());
|
||||||
|
|
@ -800,6 +855,9 @@ if (Meteor.isServer) {
|
||||||
if (Meteor.isServer) {
|
if (Meteor.isServer) {
|
||||||
// Let mongoDB ensure username unicity
|
// Let mongoDB ensure username unicity
|
||||||
Meteor.startup(() => {
|
Meteor.startup(() => {
|
||||||
|
allowedSortValues.forEach(value => {
|
||||||
|
Lists._collection._ensureIndex(value);
|
||||||
|
});
|
||||||
Users._collection._ensureIndex({ modifiedAt: -1 });
|
Users._collection._ensureIndex({ modifiedAt: -1 });
|
||||||
Users._collection._ensureIndex(
|
Users._collection._ensureIndex(
|
||||||
{
|
{
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue