mirror of
https://github.com/wekan/wekan.git
synced 2026-02-04 23:51:48 +01:00
Add Features: allowing lists to be sorted by modifiedAt when not in draggable mode.
Bug Fix #2093: the broken should be prior to file attachment feature introduced, and tested export board is working. Thanks to whowillcare ! ( xet7 merged this pull request manually from https://github.com/wekan/wekan/pull/2756 ) Closes #2093
This commit is contained in:
parent
13a2bd6380
commit
7d6d3af54a
29 changed files with 475 additions and 41 deletions
|
|
@ -409,6 +409,23 @@ Boards.helpers({
|
|||
},
|
||||
|
||||
lists() {
|
||||
const enabled = Meteor.user().hasSortBy();
|
||||
return enabled ? this.newestLists() : this.draggableLists();
|
||||
},
|
||||
|
||||
newestLists() {
|
||||
// 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(
|
||||
{
|
||||
boardId: this._id,
|
||||
archived: false,
|
||||
},
|
||||
{ sort: sortKey },
|
||||
);
|
||||
},
|
||||
draggableLists() {
|
||||
return Lists.find({ boardId: this._id }, { sort: { sort: 1 } });
|
||||
},
|
||||
|
||||
|
|
|
|||
|
|
@ -1695,6 +1695,25 @@ if (Meteor.isServer) {
|
|||
const oldvalue = doc[action] || '';
|
||||
const activityType = `a-${action}`;
|
||||
const card = Cards.findOne(doc._id);
|
||||
const list = card.list();
|
||||
if (list && action === 'endAt') {
|
||||
// change list modifiedAt
|
||||
const modifiedAt = new Date(
|
||||
new Date(value).getTime() - 365 * 24 * 3600 * 1e3,
|
||||
); // set it as 1 year before
|
||||
const boardId = list.boardId;
|
||||
Lists.direct.update(
|
||||
{
|
||||
_id: list._id,
|
||||
},
|
||||
{
|
||||
$set: {
|
||||
modifiedAt,
|
||||
boardId,
|
||||
},
|
||||
},
|
||||
);
|
||||
}
|
||||
const username = Users.findOne(userId).username;
|
||||
const activity = {
|
||||
userId,
|
||||
|
|
@ -1852,15 +1871,8 @@ if (Meteor.isServer) {
|
|||
const check = Users.findOne({
|
||||
_id: req.body.authorId,
|
||||
});
|
||||
const members = req.body.members || [req.body.authorId];
|
||||
if (typeof check !== 'undefined') {
|
||||
let members = req.body.members || [];
|
||||
if (_.isString(members)) {
|
||||
if (members === '') {
|
||||
members = [];
|
||||
} else {
|
||||
members = [members];
|
||||
}
|
||||
}
|
||||
const id = Cards.direct.insert({
|
||||
title: req.body.title,
|
||||
boardId: paramBoardId,
|
||||
|
|
|
|||
|
|
@ -50,12 +50,18 @@ if (Meteor.isServer) {
|
|||
});
|
||||
}
|
||||
|
||||
// exporter maybe is broken since Gridfs introduced, add fs and path
|
||||
|
||||
export class Exporter {
|
||||
constructor(boardId) {
|
||||
this._boardId = boardId;
|
||||
}
|
||||
|
||||
build() {
|
||||
const fs = Npm.require('fs');
|
||||
const os = Npm.require('os');
|
||||
const path = Npm.require('path');
|
||||
|
||||
const byBoard = { boardId: this._boardId };
|
||||
const byBoardNoLinked = {
|
||||
boardId: this._boardId,
|
||||
|
|
@ -134,6 +140,11 @@ export class Exporter {
|
|||
const getBase64Data = function(doc, callback) {
|
||||
let buffer = new Buffer(0);
|
||||
// callback has the form function (err, res) {}
|
||||
const tmpFile = path.join(
|
||||
os.tmpdir(),
|
||||
`tmpexport${process.pid}${Math.random()}`,
|
||||
);
|
||||
const tmpWriteable = fs.createWriteStream(tmpFile);
|
||||
const readStream = doc.createReadStream();
|
||||
readStream.on('data', function(chunk) {
|
||||
buffer = Buffer.concat([buffer, chunk]);
|
||||
|
|
@ -143,8 +154,12 @@ export class Exporter {
|
|||
});
|
||||
readStream.on('end', function() {
|
||||
// done
|
||||
fs.unlink(tmpFile, () => {
|
||||
//ignored
|
||||
});
|
||||
callback(null, buffer.toString('base64'));
|
||||
});
|
||||
readStream.pipe(tmpWriteable);
|
||||
};
|
||||
const getBase64DataSync = Meteor.wrapAsync(getBase64Data);
|
||||
result.attachments = Attachments.find(byBoard)
|
||||
|
|
|
|||
|
|
@ -11,6 +11,15 @@ Lists.attachSchema(
|
|||
*/
|
||||
type: String,
|
||||
},
|
||||
starred: {
|
||||
/**
|
||||
* if a list is stared
|
||||
* then we put it on the top
|
||||
*/
|
||||
type: Boolean,
|
||||
optional: true,
|
||||
defaultValue: false,
|
||||
},
|
||||
archived: {
|
||||
/**
|
||||
* is the list archived
|
||||
|
|
@ -81,10 +90,14 @@ Lists.attachSchema(
|
|||
denyUpdate: false,
|
||||
// eslint-disable-next-line consistent-return
|
||||
autoValue() {
|
||||
if (this.isInsert || this.isUpsert || this.isUpdate) {
|
||||
// this is redundant with updatedAt
|
||||
/*if (this.isInsert || this.isUpsert || this.isUpdate) {
|
||||
return new Date();
|
||||
} else {
|
||||
this.unset();
|
||||
}*/
|
||||
if (!this.isSet) {
|
||||
return new Date();
|
||||
}
|
||||
},
|
||||
},
|
||||
|
|
@ -252,6 +265,14 @@ Lists.helpers({
|
|||
return this.type === 'template-list';
|
||||
},
|
||||
|
||||
isStarred() {
|
||||
return this.starred === true;
|
||||
},
|
||||
|
||||
absoluteUrl() {
|
||||
const card = Cards.findOne({ listId: this._id });
|
||||
return card && card.absoluteUrl();
|
||||
},
|
||||
remove() {
|
||||
Lists.remove({ _id: this._id });
|
||||
},
|
||||
|
|
@ -261,6 +282,9 @@ Lists.mutations({
|
|||
rename(title) {
|
||||
return { $set: { title } };
|
||||
},
|
||||
star(enable = true) {
|
||||
return { $set: { starred: !!enable } };
|
||||
},
|
||||
|
||||
archive() {
|
||||
if (this.isTemplateList()) {
|
||||
|
|
|
|||
|
|
@ -174,6 +174,21 @@ Swimlanes.helpers({
|
|||
},
|
||||
|
||||
lists() {
|
||||
const enabled = Meteor.user().hasSortBy();
|
||||
return enabled ? this.newestLists() : this.draggableLists();
|
||||
},
|
||||
newestLists() {
|
||||
// sorted lists from newest to the oldest, by its creation date or its cards' last modification date
|
||||
return Lists.find(
|
||||
{
|
||||
boardId: this.boardId,
|
||||
swimlaneId: { $in: [this._id, ''] },
|
||||
archived: false,
|
||||
},
|
||||
{ sort: { modifiedAt: -1 } },
|
||||
);
|
||||
},
|
||||
draggableLists() {
|
||||
return Lists.find(
|
||||
{
|
||||
boardId: this.boardId,
|
||||
|
|
|
|||
|
|
@ -4,6 +4,16 @@ const isSandstorm =
|
|||
Meteor.settings && Meteor.settings.public && Meteor.settings.public.sandstorm;
|
||||
Users = Meteor.users;
|
||||
|
||||
const allowedSortValues = [
|
||||
'-modifiedAt',
|
||||
'modifiedAt',
|
||||
'-title',
|
||||
'title',
|
||||
'-sort',
|
||||
'sort',
|
||||
];
|
||||
const defaultSortBy = allowedSortValues[0];
|
||||
|
||||
/**
|
||||
* A User in wekan
|
||||
*/
|
||||
|
|
@ -109,6 +119,13 @@ Users.attachSchema(
|
|||
type: String,
|
||||
optional: true,
|
||||
},
|
||||
'profile.showDesktopDragHandles': {
|
||||
/**
|
||||
* does the user want to hide system messages?
|
||||
*/
|
||||
type: Boolean,
|
||||
optional: true,
|
||||
},
|
||||
'profile.hiddenSystemMessages': {
|
||||
/**
|
||||
* does the user want to hide system messages?
|
||||
|
|
@ -184,6 +201,15 @@ Users.attachSchema(
|
|||
'board-view-cal',
|
||||
],
|
||||
},
|
||||
'profile.listSortBy': {
|
||||
/**
|
||||
* default sort list for user
|
||||
*/
|
||||
type: String,
|
||||
optional: true,
|
||||
defaultValue: defaultSortBy,
|
||||
allowedValues: allowedSortValues,
|
||||
},
|
||||
'profile.templatesBoardId': {
|
||||
/**
|
||||
* Reference to the templates board
|
||||
|
|
@ -358,6 +384,31 @@ Users.helpers({
|
|||
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) {
|
||||
const { tags = [] } = this.profile || {};
|
||||
return _.contains(tags, tag);
|
||||
|
|
@ -368,6 +419,11 @@ Users.helpers({
|
|||
return _.contains(notifications, activityId);
|
||||
},
|
||||
|
||||
hasShowDesktopDragHandles() {
|
||||
const profile = this.profile || {};
|
||||
return profile.showDesktopDragHandles || false;
|
||||
},
|
||||
|
||||
hasHiddenSystemMessages() {
|
||||
const profile = this.profile || {};
|
||||
return profile.hiddenSystemMessages || false;
|
||||
|
|
@ -473,6 +529,21 @@ Users.mutations({
|
|||
else this.addTag(tag);
|
||||
},
|
||||
|
||||
setListSortBy(value) {
|
||||
return {
|
||||
$set: {
|
||||
'profile.listSortBy': value,
|
||||
},
|
||||
};
|
||||
},
|
||||
toggleDesktopHandles(value = false) {
|
||||
return {
|
||||
$set: {
|
||||
'profile.showDesktopDragHandles': !value,
|
||||
},
|
||||
};
|
||||
},
|
||||
|
||||
toggleSystem(value = false) {
|
||||
return {
|
||||
$set: {
|
||||
|
|
@ -549,6 +620,14 @@ Meteor.methods({
|
|||
Users.update(userId, { $set: { username } });
|
||||
}
|
||||
},
|
||||
setListSortBy(value) {
|
||||
check(value, String);
|
||||
Meteor.user().setListSortBy(value);
|
||||
},
|
||||
toggleDesktopDragHandles() {
|
||||
const user = Meteor.user();
|
||||
user.toggleDesktopHandles(user.hasShowDesktopDragHandles());
|
||||
},
|
||||
toggleSystemMessages() {
|
||||
const user = Meteor.user();
|
||||
user.toggleSystem(user.hasHiddenSystemMessages());
|
||||
|
|
@ -776,6 +855,9 @@ if (Meteor.isServer) {
|
|||
if (Meteor.isServer) {
|
||||
// Let mongoDB ensure username unicity
|
||||
Meteor.startup(() => {
|
||||
allowedSortValues.forEach(value => {
|
||||
Lists._collection._ensureIndex(value);
|
||||
});
|
||||
Users._collection._ensureIndex({ modifiedAt: -1 });
|
||||
Users._collection._ensureIndex(
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue