Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ab183acac3 | ||
|
|
d9b967a74d | ||
|
|
4180224fd9 | ||
|
|
aa34da61fe | ||
|
|
058b95f4eb | ||
|
|
4115d62bac | ||
|
|
3d72c82bca | ||
|
|
4bed5059c2 | ||
|
|
ac57df409e | ||
|
|
e242e2b137 | ||
|
|
94cb33a0ce | ||
|
|
a2894bf0cb | ||
|
|
a56d47c768 | ||
|
|
3214800741 | ||
|
|
c11c3f9a88 | ||
|
|
81d120ac50 | ||
|
|
50b25572f1 | ||
|
|
39ac19db20 | ||
|
|
5dbbaae6fd | ||
|
|
423480903f | ||
|
|
f00395a6b6 | ||
|
|
391c0606d1 | ||
|
|
a27aaca918 | ||
|
|
03e5d84e0e | ||
|
|
8f21c86737 | ||
|
|
25dc779a73 | ||
|
|
a647768368 | ||
|
|
80b23e5cc1 | ||
|
|
4ab1a04814 | ||
|
|
2e17f2b4b9 | ||
|
|
34000ad159 | ||
|
|
bbcb236a46 | ||
|
|
01bd94d2b3 | ||
|
|
5913a4af1b |
No files matched your search
@@ -1,3 +1,24 @@
|
||||
# v4.78 2021-01-16 Wekan release
|
||||
|
||||
This release adds the following new features:
|
||||
|
||||
- [Search All Boards](https://github.com/wekan/wekan/pull/3433). Currently limited to 50 results. Will be improved later.
|
||||
Thanks to jrsuplee and xet7.
|
||||
|
||||
and fixes the following bugs:
|
||||
|
||||
- [HTML is not needed in Rules translations, so disabled it](https://github.com/wekan/wekan/commit/a2894bf0cb11161f2f9382e900ffbae2a1570d38).
|
||||
Thanks to jrsuplee and xet7.
|
||||
- [Limit amount of data in publications where possible](https://github.com/wekan/wekan/commit/4115d62bac882ceaaec531b1f9df2666097be51a).
|
||||
Thanks to xet7.
|
||||
- [Fixed Display issues with assignee on minicard](https://github.com/wekan/wekan/commit/aa34da61fe80a2ab2a87b6413b3b9c25fb8ea96f).
|
||||
Thanks to bronger and xet7.
|
||||
- [Limit visibility of Global Search, My Cards and Due Cards to logged in users, because they do not work without
|
||||
logging in](https://github.com/wekan/wekan/commit/4180224fd9841a3e6cab9eacb1447978482e1e91).
|
||||
Thanks to xet7.
|
||||
|
||||
Thanks to above GitHub users for their contributions and translators for their translations.
|
||||
|
||||
# v4.77 2021-01-13 Wekan release
|
||||
|
||||
This release adds the following new features:
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
appId: wekan-public/apps/77b94f60-dec9-0136-304e-16ff53095928
|
||||
appVersion: "v4.77.0"
|
||||
appVersion: "v4.78.0"
|
||||
files:
|
||||
userUploads:
|
||||
- README.md
|
||||
|
||||
@@ -85,6 +85,7 @@ template(name="minicard")
|
||||
.minicard-assignees.js-minicard-assignees
|
||||
each getAssignees
|
||||
+userAvatar(userId=this)
|
||||
hr(class="assigneehr" title="{{_ 'assignee'}}")
|
||||
|
||||
if getMembers
|
||||
.minicard-members.js-minicard-members
|
||||
|
||||
@@ -165,7 +165,11 @@
|
||||
.minicard-members,
|
||||
.minicard-assignees
|
||||
float: right
|
||||
margin: 2px -8px 2px 0
|
||||
margin-left: 5px
|
||||
|
||||
.assigneehr
|
||||
border-top: 1px solid red
|
||||
margin-bottom: 4px
|
||||
|
||||
.member
|
||||
float: right
|
||||
@@ -180,7 +184,7 @@
|
||||
width: @height
|
||||
|
||||
+ .badges
|
||||
margin-top: 10px
|
||||
margin-top: 5px
|
||||
|
||||
.minicard-members:empty,
|
||||
.minicard-assignees:empty
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
template(name="resultCard")
|
||||
.result-card-wrapper
|
||||
a.minicard-wrapper.card-title(href=card.absoluteUrl)
|
||||
+minicard(this)
|
||||
//= card.title
|
||||
ul.result-card-context-list
|
||||
li.result-card-context(title="{{_ 'board'}}")
|
||||
+viewer
|
||||
= getBoard.title
|
||||
li.result-card-context.result-card-context-separator
|
||||
= ' '
|
||||
| {{_ 'context-separator'}}
|
||||
= ' '
|
||||
li.result-card-context(title="{{_ 'swimlane'}}")
|
||||
+viewer
|
||||
= getSwimlane.title
|
||||
li.result-card-context.result-card-context-separator
|
||||
= ' '
|
||||
| {{_ 'context-separator'}}
|
||||
= ' '
|
||||
li.result-card-context(title="{{_ 'list'}}")
|
||||
+viewer
|
||||
= getList.title
|
||||
@@ -0,0 +1,11 @@
|
||||
Template.resultCard.helpers({
|
||||
userId() {
|
||||
return Meteor.userId();
|
||||
},
|
||||
});
|
||||
|
||||
BlazeComponent.extendComponent({
|
||||
events() {
|
||||
return [{}];
|
||||
},
|
||||
}).register('resultCard');
|
||||
@@ -0,0 +1,21 @@
|
||||
.result-card-list-wrapper
|
||||
margin: 1rem
|
||||
border-radius: 5px
|
||||
padding: 1.5rem
|
||||
padding-top: 0.75rem
|
||||
display: inline-block
|
||||
min-width: 250px
|
||||
max-width: 350px
|
||||
|
||||
.result-card-wrapper
|
||||
margin-top: 0
|
||||
margin-bottom: 10px
|
||||
|
||||
.result-card-context
|
||||
display: inline-block
|
||||
|
||||
.result-card-context-separator
|
||||
font-weight: bold
|
||||
|
||||
.result-card-context-list
|
||||
margin-bottom: 0.7rem
|
||||
@@ -1,69 +1,73 @@
|
||||
template(name="dueCardsHeaderBar")
|
||||
h1
|
||||
i.fa.fa-calendar
|
||||
| {{_ 'dueCards-title'}}
|
||||
if currentUser
|
||||
h1
|
||||
i.fa.fa-calendar
|
||||
| {{_ 'dueCards-title'}}
|
||||
|
||||
.board-header-btns.left
|
||||
a.board-header-btn.js-due-cards-view-change(title="{{_ 'dueCardsViewChange-title'}}")
|
||||
i.fa.fa-caret-down
|
||||
if $eq dueCardsView 'me'
|
||||
i.fa.fa-user
|
||||
| {{_ 'dueCardsViewChange-choice-me'}}
|
||||
if $eq dueCardsView 'all'
|
||||
i.fa.fa-users
|
||||
| {{_ 'dueCardsViewChange-choice-all'}}
|
||||
.board-header-btns.left
|
||||
a.board-header-btn.js-due-cards-view-change(title="{{_ 'dueCardsViewChange-title'}}")
|
||||
i.fa.fa-caret-down
|
||||
if $eq dueCardsView 'me'
|
||||
i.fa.fa-user
|
||||
| {{_ 'dueCardsViewChange-choice-me'}}
|
||||
if $eq dueCardsView 'all'
|
||||
i.fa.fa-users
|
||||
| {{_ 'dueCardsViewChange-choice-all'}}
|
||||
|
||||
template(name="dueCardsModalTitle")
|
||||
h2
|
||||
i.fa.fa-keyboard-o
|
||||
| {{_ 'dueCards-title'}}
|
||||
if currentUser
|
||||
h2
|
||||
i.fa.fa-keyboard-o
|
||||
| {{_ 'dueCards-title'}}
|
||||
|
||||
template(name="dueCards")
|
||||
if isPageReady.get
|
||||
.wrapper
|
||||
.due-cards-dueat-list-wrapper
|
||||
each card in dueCardsList
|
||||
.due-cards-card-wrapper
|
||||
a.minicard-wrapper.card-title(href=card.absoluteUrl)
|
||||
+minicard(card)
|
||||
ul.due-cards-context-list
|
||||
li.due-cards-context(title="{{_ 'board'}}")
|
||||
+viewer
|
||||
= card.getBoard.title
|
||||
li.due-cards-context.due-cards-context-separator
|
||||
= ' '
|
||||
| {{_ 'context-separator'}}
|
||||
= ' '
|
||||
li.due-cards-context(title="{{_ 'swimlane'}}")
|
||||
+viewer
|
||||
= card.getSwimlane.title
|
||||
li.due-cards-context
|
||||
= ' '
|
||||
| {{_ 'context-separator'}}
|
||||
= ' '
|
||||
li.due-cards-context(title="{{_ 'list'}}")
|
||||
+viewer
|
||||
= card.getList.title
|
||||
else
|
||||
+spinner
|
||||
if currentUser
|
||||
if isPageReady.get
|
||||
.wrapper
|
||||
.due-cards-dueat-list-wrapper
|
||||
each card in dueCardsList
|
||||
.due-cards-card-wrapper
|
||||
a.minicard-wrapper.card-title(href=card.absoluteUrl)
|
||||
+minicard(card)
|
||||
ul.due-cards-context-list
|
||||
li.due-cards-context(title="{{_ 'board'}}")
|
||||
+viewer
|
||||
= card.getBoard.title
|
||||
li.due-cards-context.due-cards-context-separator
|
||||
= ' '
|
||||
| {{_ 'context-separator'}}
|
||||
= ' '
|
||||
li.due-cards-context(title="{{_ 'swimlane'}}")
|
||||
+viewer
|
||||
= card.getSwimlane.title
|
||||
li.due-cards-context
|
||||
= ' '
|
||||
| {{_ 'context-separator'}}
|
||||
= ' '
|
||||
li.due-cards-context(title="{{_ 'list'}}")
|
||||
+viewer
|
||||
= card.getList.title
|
||||
else
|
||||
+spinner
|
||||
|
||||
template(name="dueCardsViewChangePopup")
|
||||
ul.pop-over-list
|
||||
li
|
||||
with "dueCardsViewChange-choice-me"
|
||||
a.js-due-cards-view-me
|
||||
i.fa.fa-user.colorful
|
||||
| {{_ 'dueCardsViewChange-choice-me'}}
|
||||
if $eq Utils.dueCardsView "me"
|
||||
i.fa.fa-check
|
||||
hr
|
||||
li
|
||||
with "dueCardsViewChange-choice-all"
|
||||
a.js-due-cards-view-all
|
||||
i.fa.fa-users.colorful
|
||||
| {{_ 'dueCardsViewChange-choice-all'}}
|
||||
span.sub-name
|
||||
+viewer
|
||||
| {{_ 'dueCardsViewChange-choice-all-description' }}
|
||||
if $eq Utils.dueCardsView "all"
|
||||
i.fa.fa-check
|
||||
if currentUser
|
||||
ul.pop-over-list
|
||||
li
|
||||
with "dueCardsViewChange-choice-me"
|
||||
a.js-due-cards-view-me
|
||||
i.fa.fa-user.colorful
|
||||
| {{_ 'dueCardsViewChange-choice-me'}}
|
||||
if $eq Utils.dueCardsView "me"
|
||||
i.fa.fa-check
|
||||
hr
|
||||
li
|
||||
with "dueCardsViewChange-choice-all"
|
||||
a.js-due-cards-view-all
|
||||
i.fa.fa-users.colorful
|
||||
| {{_ 'dueCardsViewChange-choice-all'}}
|
||||
span.sub-name
|
||||
+viewer
|
||||
| {{_ 'dueCardsViewChange-choice-all-description' }}
|
||||
if $eq Utils.dueCardsView "all"
|
||||
i.fa.fa-check
|
||||
@@ -0,0 +1,82 @@
|
||||
template(name="globalSearchHeaderBar")
|
||||
if currentUser
|
||||
h1
|
||||
i.fa.fa-search
|
||||
| {{_ 'globalSearch-title'}}
|
||||
|
||||
template(name="globalSearchModalTitle")
|
||||
if currentUser
|
||||
h2
|
||||
i.fa.fa-keyboard-o
|
||||
| {{_ 'globalSearch-title'}}
|
||||
|
||||
template(name="globalSearch")
|
||||
if currentUser
|
||||
.wrapper
|
||||
form.global-search-instructions.js-search-query-form
|
||||
input.global-search-query-input(type="text" name="searchQuery" placeholder="{{_ 'search-example'}}" autofocus dir="auto")
|
||||
if searching.get
|
||||
+spinner
|
||||
else if hasResults.get
|
||||
.global-search-dueat-list-wrapper
|
||||
h1
|
||||
if $eq resultsCount.get 0
|
||||
| {{_ 'no-cards-found' }}
|
||||
else if $eq resultsCount.get 1
|
||||
| {{_ 'one-card-found' }}
|
||||
else if $eq resultsCount.get totalHits.get
|
||||
| {{_ 'n-cards-found' resultsCount.get }}
|
||||
else
|
||||
| {{_ 'n-n-of-n-cards-found' 1 resultsCount.get totalHits.get }}
|
||||
if queryErrors.get
|
||||
div
|
||||
each msg in errorMessages
|
||||
span.global-search-error-messages
|
||||
| {{_ msg.tag msg.value }}
|
||||
each card in results
|
||||
+resultCard(card)
|
||||
else
|
||||
.global-search-instructions
|
||||
h1 Search Operators
|
||||
+viewer
|
||||
= 'Searches can include operators to refine the search. Operators are specified by writing the operator'
|
||||
= 'name and value separated by a colon. For example, an operator specification of `list:Blocked` would limit the search'
|
||||
= 'to cards that are contained in a list named *Blocked*. If the value contains spaces or special characters'
|
||||
= 'it must be enclosed in quotation marks (e.g. `list:"To Review"`).\n'
|
||||
= 'Available operators are:\n'
|
||||
= '* `board:title` - cards in boards matching the specified title\n'
|
||||
= '* `list:title` - cards in lists matching the specified title\n'
|
||||
= '* `swimlane:title` - cards in swimlanes matching the specified title\n'
|
||||
= '* `label:color` - cards that have a label matching the given color\n'
|
||||
= '* `label:name` - cards that have a label matching the given name\n'
|
||||
= '* `user:username` - cards where the specified user is a member or assignee\n'
|
||||
= '* `@username` - shorthand for `user:username`\n'
|
||||
= '* `#label` - shorthand for `label:color-or-name`\n'
|
||||
= '## Notes\n'
|
||||
= '* Multiple operators may be specified.\n'
|
||||
= '* Similar operators are *OR*ed together. Cards that match any of the conditions will be returned.\n'
|
||||
= ' `list:Available list:Blocked` would return cards contained in any list named *Blocked* or *Available*.\n'
|
||||
= '* Differing operators are *AND*ed together. Only cards that match all of the differing operators are returned.\n'
|
||||
= '`list:Available label:red` returns only cards in the list *Available* with a *red* label.\n'
|
||||
= '* Text searches are case insensitive.\n'
|
||||
|
||||
template(name="globalSearchViewChangePopup")
|
||||
if currentUser
|
||||
ul.pop-over-list
|
||||
li
|
||||
with "globalSearchViewChange-choice-me"
|
||||
a.js-global-search-view-me
|
||||
i.fa.fa-user.colorful
|
||||
| {{_ 'globalSearchViewChange-choice-me'}}
|
||||
if $eq Utils.globalSearchView "me"
|
||||
i.fa.fa-check
|
||||
li
|
||||
with "globalSearchViewChange-choice-all"
|
||||
a.js-global-search-view-all
|
||||
i.fa.fa-users.colorful
|
||||
| {{_ 'globalSearchViewChange-choice-all'}}
|
||||
span.sub-name
|
||||
+viewer
|
||||
| {{_ 'globalSearchViewChange-choice-all-description' }}
|
||||
if $eq Utils.globalSearchView "all"
|
||||
i.fa.fa-check
|
||||
@@ -0,0 +1,201 @@
|
||||
const subManager = new SubsManager();
|
||||
|
||||
BlazeComponent.extendComponent({
|
||||
events() {
|
||||
return [
|
||||
{
|
||||
'click .js-due-cards-view-change': Popup.open('globalSearchViewChange'),
|
||||
},
|
||||
];
|
||||
},
|
||||
}).register('globalSearchHeaderBar');
|
||||
|
||||
Template.globalSearch.helpers({
|
||||
userId() {
|
||||
return Meteor.userId();
|
||||
},
|
||||
});
|
||||
|
||||
BlazeComponent.extendComponent({
|
||||
events() {
|
||||
return [
|
||||
{
|
||||
'click .js-due-cards-view-me'() {
|
||||
Utils.setDueCardsView('me');
|
||||
Popup.close();
|
||||
},
|
||||
|
||||
'click .js-due-cards-view-all'() {
|
||||
Utils.setDueCardsView('all');
|
||||
Popup.close();
|
||||
},
|
||||
},
|
||||
];
|
||||
},
|
||||
}).register('globalSearchViewChangePopup');
|
||||
|
||||
BlazeComponent.extendComponent({
|
||||
onCreated() {
|
||||
this.isPageReady = new ReactiveVar(true);
|
||||
this.searching = new ReactiveVar(false);
|
||||
this.hasResults = new ReactiveVar(false);
|
||||
this.query = new ReactiveVar('');
|
||||
this.queryParams = null;
|
||||
this.resultsCount = new ReactiveVar(0);
|
||||
this.totalHits = new ReactiveVar(0);
|
||||
this.queryErrors = new ReactiveVar(null);
|
||||
Meteor.subscribe('setting');
|
||||
},
|
||||
|
||||
results() {
|
||||
if (this.queryParams) {
|
||||
const results = Cards.globalSearch(this.queryParams);
|
||||
// eslint-disable-next-line no-console
|
||||
// console.log('user:', Meteor.user());
|
||||
// eslint-disable-next-line no-console
|
||||
// console.log('user:', Meteor.user().sessionData);
|
||||
// console.log('errors:', results.errors);
|
||||
this.totalHits.set(Meteor.user().sessionData.totalHits);
|
||||
this.resultsCount.set(results.cards.count());
|
||||
this.queryErrors.set(results.errors);
|
||||
return results.cards;
|
||||
}
|
||||
this.resultsCount.set(0);
|
||||
return [];
|
||||
},
|
||||
|
||||
errorMessages() {
|
||||
const errors = this.queryErrors.get();
|
||||
const messages = [];
|
||||
|
||||
errors.notFound.boards.forEach(board => {
|
||||
messages.push({ tag: 'board-title-not-found', value: board });
|
||||
});
|
||||
errors.notFound.swimlanes.forEach(swim => {
|
||||
messages.push({ tag: 'swimlane-title-not-found', value: swim });
|
||||
});
|
||||
errors.notFound.lists.forEach(list => {
|
||||
messages.push({ tag: 'list-title-not-found', value: list });
|
||||
});
|
||||
errors.notFound.users.forEach(user => {
|
||||
messages.push({ tag: 'user-username-not-found', value: user });
|
||||
});
|
||||
|
||||
return messages;
|
||||
},
|
||||
|
||||
events() {
|
||||
return [
|
||||
{
|
||||
'submit .js-search-query-form'(evt) {
|
||||
evt.preventDefault();
|
||||
this.query.set(evt.target.searchQuery.value);
|
||||
this.queryErrors.set(null);
|
||||
|
||||
if (!this.query.get()) {
|
||||
this.searching.set(false);
|
||||
this.hasResults.set(false);
|
||||
return;
|
||||
}
|
||||
|
||||
this.searching.set(true);
|
||||
this.hasResults.set(false);
|
||||
|
||||
let query = this.query.get();
|
||||
// eslint-disable-next-line no-console
|
||||
// console.log('query:', query);
|
||||
|
||||
const reOperator1 = /^((?<operator>\w+):|(?<abbrev>[#@]))(?<value>\w+)(\s+|$)/;
|
||||
const reOperator2 = /^((?<operator>\w+):|(?<abbrev>[#@]))(?<quote>["']*)(?<value>.*?)\k<quote>(\s+|$)/;
|
||||
const reText = /^(?<text>\S+)(\s+|$)/;
|
||||
const reQuotedText = /^(?<quote>["'])(?<text>\w+)\k<quote>(\s+|$)/;
|
||||
|
||||
const operatorMap = {};
|
||||
operatorMap[TAPi18n.__('operator-board')] = 'boards';
|
||||
operatorMap[TAPi18n.__('operator-board-abbrev')] = 'boards';
|
||||
operatorMap[TAPi18n.__('operator-swimlane')] = 'swimlanes';
|
||||
operatorMap[TAPi18n.__('operator-swimlane-abbrev')] = 'swimlanes';
|
||||
operatorMap[TAPi18n.__('operator-list')] = 'lists';
|
||||
operatorMap[TAPi18n.__('operator-list-abbrev')] = 'lists';
|
||||
operatorMap[TAPi18n.__('operator-label')] = 'labels';
|
||||
operatorMap[TAPi18n.__('operator-label-abbrev')] = 'labels';
|
||||
operatorMap[TAPi18n.__('operator-user')] = 'users';
|
||||
operatorMap[TAPi18n.__('operator-user-abbrev')] = 'users';
|
||||
operatorMap[TAPi18n.__('operator-is')] = 'is';
|
||||
|
||||
// eslint-disable-next-line no-console
|
||||
// console.log('operatorMap:', operatorMap);
|
||||
const params = {
|
||||
boards: [],
|
||||
swimlanes: [],
|
||||
lists: [],
|
||||
users: [],
|
||||
labels: [],
|
||||
is: [],
|
||||
};
|
||||
|
||||
let text = '';
|
||||
while (query) {
|
||||
m = query.match(reOperator1);
|
||||
if (!m) {
|
||||
m = query.match(reOperator2);
|
||||
if (m) {
|
||||
query = query.replace(reOperator2, '');
|
||||
}
|
||||
} else {
|
||||
query = query.replace(reOperator1, '');
|
||||
}
|
||||
if (m) {
|
||||
let op;
|
||||
if (m.groups.operator) {
|
||||
op = m.groups.operator.toLowerCase();
|
||||
} else {
|
||||
op = m.groups.abbrev;
|
||||
}
|
||||
if (op in operatorMap) {
|
||||
params[operatorMap[op]].push(m.groups.value);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
m = query.match(reQuotedText);
|
||||
if (!m) {
|
||||
m = query.match(reText);
|
||||
if (m) {
|
||||
query = query.replace(reText, '');
|
||||
}
|
||||
} else {
|
||||
query = query.replace(reQuotedText, '');
|
||||
}
|
||||
if (m) {
|
||||
text += (text ? ' ' : '') + m.groups.text;
|
||||
}
|
||||
}
|
||||
|
||||
// eslint-disable-next-line no-console
|
||||
// console.log('text:', text);
|
||||
params.text = text;
|
||||
|
||||
// eslint-disable-next-line no-console
|
||||
// console.log('params:', params);
|
||||
|
||||
this.queryParams = params;
|
||||
|
||||
this.autorun(() => {
|
||||
const handle = subManager.subscribe('globalSearch', params);
|
||||
Tracker.nonreactive(() => {
|
||||
Tracker.autorun(() => {
|
||||
// eslint-disable-next-line no-console
|
||||
// console.log('ready:', handle.ready());
|
||||
if (handle.ready()) {
|
||||
this.searching.set(false);
|
||||
this.hasResults.set(true);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
},
|
||||
},
|
||||
];
|
||||
},
|
||||
}).register('globalSearch');
|
||||
@@ -0,0 +1,97 @@
|
||||
.global-search-board-wrapper
|
||||
border-radius: 8px
|
||||
//padding: 0.5rem
|
||||
min-width: 400px
|
||||
border-width: 8px
|
||||
border-color: grey
|
||||
border-style: solid
|
||||
margin-bottom: 2rem
|
||||
margin-right: auto
|
||||
margin-left: auto
|
||||
|
||||
.global-search-board-title
|
||||
font-size: 1.4rem
|
||||
font-weight: bold
|
||||
padding: 0.5rem
|
||||
background-color: grey
|
||||
color: white
|
||||
|
||||
.global-search-swimlane-title
|
||||
font-size: 1.1rem
|
||||
font-weight: bold
|
||||
padding: 0.5rem
|
||||
padding-bottom: 0.4rem
|
||||
margin-top: 0
|
||||
margin-bottom: 0.5rem
|
||||
//border-top: black 1px solid
|
||||
//border-bottom: black 1px solid
|
||||
text-align: center
|
||||
|
||||
.swimlane-default-color
|
||||
background-color: lightgrey
|
||||
|
||||
.global-search-list-title
|
||||
font-weight: bold
|
||||
font-size: 1.1rem
|
||||
//padding-bottom: 0
|
||||
//margin-bottom: 0
|
||||
text-align: center
|
||||
margin-bottom: 0.7rem
|
||||
|
||||
.global-search-list-wrapper
|
||||
margin: 1rem
|
||||
border-radius: 5px
|
||||
padding: 1.5rem
|
||||
padding-top: 0.75rem
|
||||
display: inline-block
|
||||
min-width: 250px
|
||||
max-width: 350px
|
||||
|
||||
.global-search-card-wrapper
|
||||
margin-top: 0
|
||||
margin-bottom: 10px
|
||||
|
||||
.global-search-dueat-list-wrapper
|
||||
max-width: 500px
|
||||
margin-right: auto
|
||||
margin-left: auto
|
||||
|
||||
.global-search-field-name
|
||||
font-weight: bold
|
||||
|
||||
.global-search-context
|
||||
display: inline-block
|
||||
|
||||
.global-search-context-separator
|
||||
font-weight: bold
|
||||
|
||||
.global-search-context-list
|
||||
margin-bottom: 0.7rem
|
||||
|
||||
.global-search-error-messages
|
||||
color: darkred
|
||||
|
||||
.global-search-instructions
|
||||
width: 40%
|
||||
min-width: 400px
|
||||
margin-right: auto
|
||||
margin-left: auto
|
||||
line-height: 150%
|
||||
|
||||
.global-search-query-input
|
||||
width: 90% !important
|
||||
margin-right: auto
|
||||
margin-left: auto
|
||||
|
||||
.global-search-operator
|
||||
font-family: Courier
|
||||
|
||||
.global-search-value
|
||||
font-family: Courier
|
||||
font-style: italic
|
||||
|
||||
code
|
||||
color: white
|
||||
background-color: grey
|
||||
padding: 0.1rem !important
|
||||
font-size: 0.7rem !important
|
||||
@@ -1,88 +1,92 @@
|
||||
template(name="myCardsHeaderBar")
|
||||
h1
|
||||
//a.back-btn(href="{{pathFor 'home'}}")
|
||||
// i.fa.fa-chevron-left
|
||||
i.fa.fa-list
|
||||
| {{_ 'my-cards'}}
|
||||
if currentUser
|
||||
h1
|
||||
//a.back-btn(href="{{pathFor 'home'}}")
|
||||
// i.fa.fa-chevron-left
|
||||
i.fa.fa-list
|
||||
| {{_ 'my-cards'}}
|
||||
|
||||
.board-header-btns.left
|
||||
a.board-header-btn.js-toggle-my-cards-choose-sort(title="{{_ 'myCardsSortChange-title'}}")
|
||||
i.fa.fa-caret-down
|
||||
if $eq myCardsSort 'board'
|
||||
i.fa.fa-th-large
|
||||
| {{_ 'myCardsSortChange-choice-board'}}
|
||||
if $eq myCardsSort 'dueAt'
|
||||
i.fa.fa-calendar
|
||||
| {{_ 'myCardsSortChange-choice-dueat'}}
|
||||
.board-header-btns.left
|
||||
a.board-header-btn.js-toggle-my-cards-choose-sort(title="{{_ 'myCardsSortChange-title'}}")
|
||||
i.fa.fa-caret-down
|
||||
if $eq myCardsSort 'board'
|
||||
i.fa.fa-th-large
|
||||
| {{_ 'myCardsSortChange-choice-board'}}
|
||||
if $eq myCardsSort 'dueAt'
|
||||
i.fa.fa-calendar
|
||||
| {{_ 'myCardsSortChange-choice-dueat'}}
|
||||
|
||||
template(name="myCardsModalTitle")
|
||||
h2
|
||||
i.fa.fa-keyboard-o
|
||||
| {{_ 'my-cards'}}
|
||||
if currentUser
|
||||
h2
|
||||
i.fa.fa-keyboard-o
|
||||
| {{_ 'my-cards'}}
|
||||
|
||||
template(name="myCards")
|
||||
if isPageReady.get
|
||||
.wrapper
|
||||
if $eq myCardsSort 'board'
|
||||
each board in myCardsList
|
||||
.my-cards-board-wrapper
|
||||
.my-cards-board-title
|
||||
+viewer
|
||||
= board.title
|
||||
each swimlane in board.mySwimlanes
|
||||
.my-cards-swimlane-title(class="{{#if swimlane.colorClass}}{{ swimlane.colorClass }}{{else}}swimlane-default-color{{/if}}")
|
||||
if currentUser
|
||||
if isPageReady.get
|
||||
.wrapper
|
||||
if $eq myCardsSort 'board'
|
||||
each board in myCardsList
|
||||
.my-cards-board-wrapper
|
||||
.my-cards-board-title
|
||||
+viewer
|
||||
= swimlane.title
|
||||
each list in swimlane.myLists
|
||||
.my-cards-list-wrapper
|
||||
.my-cards-list-title(class=list.colorClass)
|
||||
= board.title
|
||||
each swimlane in board.mySwimlanes
|
||||
.my-cards-swimlane-title(class="{{#if swimlane.colorClass}}{{ swimlane.colorClass }}{{else}}swimlane-default-color{{/if}}")
|
||||
+viewer
|
||||
= swimlane.title
|
||||
each list in swimlane.myLists
|
||||
.my-cards-list-wrapper
|
||||
.my-cards-list-title(class=list.colorClass)
|
||||
+viewer
|
||||
= list.title
|
||||
each card in list.myCards
|
||||
.my-cards-card-wrapper
|
||||
a.minicard-wrapper(href=card.absoluteUrl)
|
||||
+minicard(card)
|
||||
else
|
||||
.my-cards-dueat-list-wrapper
|
||||
each card in myDueCardsList
|
||||
.my-cards-card-wrapper
|
||||
a.minicard-wrapper.card-title(href=card.absoluteUrl)
|
||||
+minicard(card)
|
||||
ul.my-cards-context-list
|
||||
li.my-cards-context(title="{{_ 'board'}}")
|
||||
+viewer
|
||||
= list.title
|
||||
each card in list.myCards
|
||||
.my-cards-card-wrapper
|
||||
a.minicard-wrapper(href=card.absoluteUrl)
|
||||
+minicard(card)
|
||||
else
|
||||
.my-cards-dueat-list-wrapper
|
||||
each card in myDueCardsList
|
||||
.my-cards-card-wrapper
|
||||
a.minicard-wrapper.card-title(href=card.absoluteUrl)
|
||||
+minicard(card)
|
||||
ul.my-cards-context-list
|
||||
li.my-cards-context(title="{{_ 'board'}}")
|
||||
+viewer
|
||||
= card.getBoard.title
|
||||
li.my-cards-context.my-cards-context-separator
|
||||
= ' '
|
||||
| {{_ 'context-separator'}}
|
||||
= ' '
|
||||
li.my-cards-context(title="{{_ 'swimlane'}}")
|
||||
+viewer
|
||||
= card.getSwimlane.title
|
||||
li.my-cards-context
|
||||
= ' '
|
||||
| {{_ 'context-separator'}}
|
||||
= ' '
|
||||
li.my-cards-context(title="{{_ 'list'}}")
|
||||
+viewer
|
||||
= card.getList.title
|
||||
else
|
||||
+spinner
|
||||
= card.getBoard.title
|
||||
li.my-cards-context.my-cards-context-separator
|
||||
= ' '
|
||||
| {{_ 'context-separator'}}
|
||||
= ' '
|
||||
li.my-cards-context(title="{{_ 'swimlane'}}")
|
||||
+viewer
|
||||
= card.getSwimlane.title
|
||||
li.my-cards-context
|
||||
= ' '
|
||||
| {{_ 'context-separator'}}
|
||||
= ' '
|
||||
li.my-cards-context(title="{{_ 'list'}}")
|
||||
+viewer
|
||||
= card.getList.title
|
||||
else
|
||||
+spinner
|
||||
|
||||
template(name="myCardsSortChangePopup")
|
||||
ul.pop-over-list
|
||||
li
|
||||
with "my-cards-sort-board"
|
||||
a.js-my-cards-sort-board
|
||||
i.fa.fa-th-large.colorful
|
||||
| {{_ 'myCardsSortChange-choice-board'}}
|
||||
if $eq Utils.myCardsSort "board"
|
||||
i.fa.fa-check
|
||||
hr
|
||||
li
|
||||
with "my-cards-sort-dueat"
|
||||
a.js-my-cards-sort-dueat
|
||||
i.fa.fa-calendar.colorful
|
||||
| {{_ 'myCardsSortChange-choice-dueat'}}
|
||||
if $eq Utils.myCardsSort "dueAt"
|
||||
i.fa.fa-check
|
||||
if currentUser
|
||||
ul.pop-over-list
|
||||
li
|
||||
with "my-cards-sort-board"
|
||||
a.js-my-cards-sort-board
|
||||
i.fa.fa-th-large.colorful
|
||||
| {{_ 'myCardsSortChange-choice-board'}}
|
||||
if $eq Utils.myCardsSort "board"
|
||||
i.fa.fa-check
|
||||
hr
|
||||
li
|
||||
with "my-cards-sort-dueat"
|
||||
a.js-my-cards-sort-dueat
|
||||
i.fa.fa-calendar.colorful
|
||||
| {{_ 'myCardsSortChange-choice-dueat'}}
|
||||
if $eq Utils.myCardsSort "dueAt"
|
||||
i.fa.fa-check
|
||||
@@ -3,32 +3,32 @@ template(name="cardActions")
|
||||
div.trigger-content
|
||||
div.trigger-dropdown
|
||||
select(id="setdate-action")
|
||||
option(value="setDate") {{{_'r-set'}}}
|
||||
option(value="updateDate") {{{_'r-update'}}}
|
||||
option(value="setDate") {{_'r-set'}}
|
||||
option(value="updateDate") {{_'r-update'}}
|
||||
div.trigger-text
|
||||
| {{{_'r-datefield'}}}
|
||||
| {{_'r-datefield'}}
|
||||
div.trigger-dropdown
|
||||
select(id="setdate-datefield")
|
||||
option(value="startAt") {{{_'r-df-start-at'}}}
|
||||
option(value="dueAt") {{{_'r-df-due-at'}}}
|
||||
option(value="endAt") {{{_'r-df-end-at'}}}
|
||||
option(value="receivedAt") {{{_'r-df-received-at'}}}
|
||||
option(value="startAt") {{_'r-df-start-at'}}
|
||||
option(value="dueAt") {{_'r-df-due-at'}}
|
||||
option(value="endAt") {{_'r-df-end-at'}}
|
||||
option(value="receivedAt") {{_'r-df-received-at'}}
|
||||
div.trigger-text
|
||||
| {{{_'r-to-current-datetime'}}}
|
||||
| {{_'r-to-current-datetime'}}
|
||||
div.trigger-button.js-set-date-action.js-goto-rules
|
||||
i.fa.fa-plus
|
||||
|
||||
div.trigger-item
|
||||
div.trigger-content
|
||||
div.trigger-text
|
||||
| {{{_'r-remove-value-from'}}}
|
||||
| {{{_'r-datefield'}}}
|
||||
| {{_'r-remove-value-from'}}
|
||||
| {{_'r-datefield'}}
|
||||
div.trigger-dropdown
|
||||
select(id="setdate-removedatefieldvalue")
|
||||
option(value="startAt") {{{_'r-df-start-at'}}}
|
||||
option(value="dueAt") {{{_'r-df-due-at'}}}
|
||||
option(value="endAt") {{{_'r-df-end-at'}}}
|
||||
option(value="receivedAt") {{{_'r-df-received-at'}}}
|
||||
option(value="startAt") {{_'r-df-start-at'}}
|
||||
option(value="dueAt") {{_'r-df-due-at'}}
|
||||
option(value="endAt") {{_'r-df-end-at'}}
|
||||
option(value="receivedAt") {{_'r-df-received-at'}}
|
||||
div.trigger-button.js-remove-datevalue-action.js-goto-rules
|
||||
i.fa.fa-plus
|
||||
|
||||
@@ -36,10 +36,10 @@ template(name="cardActions")
|
||||
div.trigger-content
|
||||
div.trigger-dropdown
|
||||
select(id="label-action")
|
||||
option(value="add") {{{_'r-add'}}}
|
||||
option(value="remove") {{{_'r-remove'}}}
|
||||
option(value="add") {{_'r-add'}}
|
||||
option(value="remove") {{_'r-remove'}}
|
||||
div.trigger-text
|
||||
| {{{_'r-label'}}}
|
||||
| {{_'r-label'}}
|
||||
div.trigger-dropdown
|
||||
select(id="label-id")
|
||||
each labels
|
||||
@@ -52,26 +52,26 @@ template(name="cardActions")
|
||||
div.trigger-content
|
||||
div.trigger-dropdown
|
||||
select(id="member-action")
|
||||
option(value="add") {{{_'r-add'}}}
|
||||
option(value="remove") {{{_'r-remove'}}}
|
||||
option(value="add") {{_'r-add'}}
|
||||
option(value="remove") {{_'r-remove'}}
|
||||
div.trigger-text
|
||||
| {{{_'r-member'}}}
|
||||
| {{_'r-member'}}
|
||||
div.trigger-dropdown
|
||||
input(id="member-name",type=text,placeholder="{{{_'r-name'}}}")
|
||||
input(id="member-name",type=text,placeholder="{{_'r-name'}}")
|
||||
div.trigger-button.js-add-member-action.js-goto-rules
|
||||
i.fa.fa-plus
|
||||
|
||||
div.trigger-item
|
||||
div.trigger-content
|
||||
div.trigger-text
|
||||
| {{{_'r-remove-all'}}}
|
||||
| {{_'r-remove-all'}}
|
||||
div.trigger-button.js-add-removeall-action.js-goto-rules
|
||||
i.fa.fa-plus
|
||||
|
||||
div.trigger-item
|
||||
div.trigger-content
|
||||
div.trigger-text
|
||||
| {{{_'r-set-color'}}}
|
||||
| {{_'r-set-color'}}
|
||||
button.trigger-button.trigger-button-color.js-show-color-palette(
|
||||
id="color-action"
|
||||
class="card-details-{{cardColorButton}}")
|
||||
|
||||
@@ -3,12 +3,12 @@ template(name="checklistActions")
|
||||
div.trigger-content
|
||||
div.trigger-dropdown
|
||||
select(id="check-action")
|
||||
option(value="add") {{{_'r-add'}}}
|
||||
option(value="remove") {{{_'r-remove'}}}
|
||||
option(value="add") {{_'r-add'}}
|
||||
option(value="remove") {{_'r-remove'}}
|
||||
div.trigger-text
|
||||
| {{{_'r-checklist'}}}
|
||||
| {{_'r-checklist'}}
|
||||
div.trigger-dropdown
|
||||
input(id="checklist-name",type=text,placeholder="{{{_'r-name'}}}")
|
||||
input(id="checklist-name",type=text,placeholder="{{_'r-name'}}")
|
||||
div.trigger-button.js-add-checklist-action.js-goto-rules
|
||||
i.fa.fa-plus
|
||||
|
||||
@@ -16,12 +16,12 @@ template(name="checklistActions")
|
||||
div.trigger-content
|
||||
div.trigger-dropdown
|
||||
select(id="checkall-action")
|
||||
option(value="check") {{{_'r-check-all'}}}
|
||||
option(value="uncheck") {{{_'r-uncheck-all'}}}
|
||||
option(value="check") {{_'r-check-all'}}
|
||||
option(value="uncheck") {{_'r-uncheck-all'}}
|
||||
div.trigger-text
|
||||
| {{{_'r-items-check'}}}
|
||||
| {{_'r-items-check'}}
|
||||
div.trigger-dropdown
|
||||
input(id="checklist-name2",type=text,placeholder="{{{_'r-name'}}}")
|
||||
input(id="checklist-name2",type=text,placeholder="{{_'r-name'}}")
|
||||
div.trigger-button.js-add-checkall-action.js-goto-rules
|
||||
i.fa.fa-plus
|
||||
|
||||
@@ -30,36 +30,36 @@ template(name="checklistActions")
|
||||
div.trigger-content
|
||||
div.trigger-dropdown
|
||||
select(id="check-item-action")
|
||||
option(value="check") {{{_'r-check'}}}
|
||||
option(value="uncheck") {{{_'r-uncheck'}}}
|
||||
option(value="check") {{_'r-check'}}
|
||||
option(value="uncheck") {{_'r-uncheck'}}
|
||||
div.trigger-text
|
||||
| {{{_'r-item'}}}
|
||||
| {{_'r-item'}}
|
||||
div.trigger-dropdown
|
||||
input(id="checkitem-name",type=text,placeholder="{{{_'r-name'}}}")
|
||||
input(id="checkitem-name",type=text,placeholder="{{_'r-name'}}")
|
||||
div.trigger-text
|
||||
| {{{_'r-of-checklist'}}}
|
||||
| {{_'r-of-checklist'}}
|
||||
div.trigger-dropdown
|
||||
input(id="checklist-name3",type=text,placeholder="{{{_'r-name'}}}")
|
||||
input(id="checklist-name3",type=text,placeholder="{{_'r-name'}}")
|
||||
div.trigger-button.js-add-check-item-action.js-goto-rules
|
||||
i.fa.fa-plus
|
||||
|
||||
div.trigger-item
|
||||
div.trigger-content
|
||||
div.trigger-text
|
||||
| {{{_'r-add-checklist'}}}
|
||||
| {{_'r-add-checklist'}}
|
||||
div.trigger-dropdown
|
||||
input(id="checklist-name-3",type=text,placeholder="{{{_'r-name'}}}")
|
||||
input(id="checklist-name-3",type=text,placeholder="{{_'r-name'}}")
|
||||
div.trigger-text
|
||||
| {{{_'r-with-items'}}}
|
||||
| {{_'r-with-items'}}
|
||||
div.trigger-dropdown
|
||||
input(id="checklist-items",type=text,placeholder="{{{_'r-items-list'}}}")
|
||||
input(id="checklist-items",type=text,placeholder="{{_'r-items-list'}}")
|
||||
div.trigger-button.js-add-checklist-items-action.js-goto-rules
|
||||
i.fa.fa-plus
|
||||
|
||||
div.trigger-item
|
||||
div.trigger-content
|
||||
div.trigger-text
|
||||
| {{{_'r-checklist-note'}}}
|
||||
| {{_'r-checklist-note'}}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ template(name="ruleDetails")
|
||||
.rules
|
||||
h2
|
||||
i.fa.fa-magic
|
||||
| {{{_ 'r-rule-details' }}}
|
||||
| {{_ 'r-rule-details' }}
|
||||
.triggers-content
|
||||
.triggers-body
|
||||
.triggers-main-body
|
||||
@@ -21,4 +21,4 @@ template(name="ruleDetails")
|
||||
div.rules-back
|
||||
button.js-goback
|
||||
i.fa.fa-chevron-left
|
||||
| {{{_ 'back'}}}
|
||||
| {{_ 'back'}}
|
||||
@@ -1,7 +1,7 @@
|
||||
template(name="rulesActions")
|
||||
h2
|
||||
i.fa.fa-magic
|
||||
| {{{_ 'r-rule' }}} "#{data.ruleName.get}" - {{{_ 'r-add-action'}}}
|
||||
| {{_ 'r-rule' }} "#{data.ruleName.get}" - {{_ 'r-add-action'}}
|
||||
.triggers-content
|
||||
.triggers-body
|
||||
.triggers-side-menu
|
||||
@@ -26,4 +26,4 @@ template(name="rulesActions")
|
||||
div.rules-back
|
||||
button.js-goback
|
||||
i.fa.fa-chevron-left
|
||||
| {{{_ 'back'}}}
|
||||
| {{_ 'back'}}
|
||||
@@ -2,7 +2,7 @@ template(name="rulesList")
|
||||
.rules
|
||||
h2
|
||||
i.fa.fa-magic
|
||||
| {{{_ 'r-board-rules' }}}
|
||||
| {{_ 'r-board-rules' }}
|
||||
|
||||
ul.rules-list
|
||||
each rules
|
||||
@@ -12,26 +12,26 @@ template(name="rulesList")
|
||||
div.rules-btns-group
|
||||
button.js-goto-details
|
||||
i.fa.fa-eye
|
||||
| {{{_ 'r-view-rule'}}}
|
||||
| {{_ 'r-view-rule'}}
|
||||
if currentUser.isAdmin
|
||||
button.js-delete-rule
|
||||
i.fa.fa-trash-o
|
||||
| {{{_ 'r-delete-rule'}}}
|
||||
| {{_ 'r-delete-rule'}}
|
||||
else if currentUser.isBoardAdmin
|
||||
button.js-delete-rule
|
||||
i.fa.fa-trash-o
|
||||
| {{{_ 'r-delete-rule'}}}
|
||||
| {{_ 'r-delete-rule'}}
|
||||
else
|
||||
li.no-items-message {{{_ 'r-no-rules' }}}
|
||||
li.no-items-message {{_ 'r-no-rules' }}
|
||||
if currentUser.isAdmin
|
||||
div.rules-add
|
||||
button.js-goto-trigger
|
||||
i.fa.fa-plus
|
||||
| {{{_ 'r-add-rule'}}}
|
||||
input(type=text,placeholder="{{{_ 'r-new-rule-name' }}}",id="ruleTitle")
|
||||
| {{_ 'r-add-rule'}}
|
||||
input(type=text,placeholder="{{_ 'r-new-rule-name' }}",id="ruleTitle")
|
||||
else if currentUser.isBoardAdmin
|
||||
div.rules-add
|
||||
button.js-goto-trigger
|
||||
i.fa.fa-plus
|
||||
| {{{_ 'r-add-rule'}}}
|
||||
input(type=text,placeholder="{{{_ 'r-new-rule-name' }}}",id="ruleTitle")
|
||||
| {{_ 'r-add-rule'}}
|
||||
input(type=text,placeholder="{{_ 'r-new-rule-name' }}",id="ruleTitle")
|
||||
@@ -1,7 +1,7 @@
|
||||
template(name="rulesTriggers")
|
||||
h2
|
||||
i.fa.fa-magic
|
||||
| {{{_ 'r-rule' }}} "#{data.ruleName.get}" - {{{_ 'r-add-trigger'}}}
|
||||
| {{_ 'r-rule' }} "#{data.ruleName.get}" - {{_ 'r-add-trigger'}}
|
||||
.triggers-content
|
||||
.triggers-body
|
||||
.triggers-side-menu
|
||||
@@ -22,4 +22,4 @@ template(name="rulesTriggers")
|
||||
div.rules-back
|
||||
button.js-goback
|
||||
i.fa.fa-chevron-left
|
||||
| {{{_ 'back'}}}
|
||||
| {{_ 'back'}}
|
||||
@@ -100,7 +100,7 @@ template(name="boardTriggers")
|
||||
div.trigger-item
|
||||
div.trigger-content
|
||||
div.trigger-text
|
||||
| {{{_'r-board-note'}}}
|
||||
| {{_'r-board-note'}}
|
||||
|
||||
template(name="boardCardTitlePopup")
|
||||
form
|
||||
@@ -109,8 +109,3 @@ template(name="boardCardTitlePopup")
|
||||
input.js-card-filter-name(type="text" value=title autofocus)
|
||||
input.js-card-filter-button.primary.wide(type="submit" value="{{_ 'set-filter'}}")
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -21,6 +21,10 @@ template(name="memberMenuPopup")
|
||||
a.js-due-cards(href="{{pathFor 'due-cards'}}")
|
||||
i.fa.fa-calendar
|
||||
| {{_ 'dueCards-title'}}
|
||||
li
|
||||
a.js-global-search(href="{{pathFor 'global-search'}}")
|
||||
i.fa.fa-search
|
||||
| {{_ 'globalSearch-title'}}
|
||||
li
|
||||
a.js-broken-cards(href="{{pathFor 'broken-cards'}}")
|
||||
i.fa.fa-chain-broken
|
||||
|
||||
+17
-1
@@ -149,6 +149,23 @@ FlowRouter.route('/due-cards', {
|
||||
},
|
||||
});
|
||||
|
||||
FlowRouter.route('/global-search', {
|
||||
name: 'global-search',
|
||||
action() {
|
||||
Filter.reset();
|
||||
// EscapeActions.executeAll();
|
||||
EscapeActions.executeUpTo('popup-close');
|
||||
|
||||
Utils.manageCustomUI();
|
||||
Utils.manageMatomo();
|
||||
|
||||
BlazeLayout.render('defaultLayout', {
|
||||
headerBar: 'globalSearchHeaderBar',
|
||||
content: 'globalSearch',
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
FlowRouter.route('/broken-cards', {
|
||||
name: 'broken-cards',
|
||||
action() {
|
||||
@@ -165,7 +182,6 @@ FlowRouter.route('/broken-cards', {
|
||||
headerBar: 'brokenCardsHeaderBar',
|
||||
content: brokenCardsTemplate,
|
||||
});
|
||||
// }
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
+887
-867
File diff suppressed because it is too large.
Load diff
+887
-867
File diff suppressed because it is too large.
Load diff
+887
-867
File diff suppressed because it is too large.
Load diff
+887
-867
File diff suppressed because it is too large.
Load diff
+887
-867
File diff suppressed because it is too large.
Load diff
+887
-867
File diff suppressed because it is too large.
Load diff
+887
-867
File diff suppressed because it is too large.
Load diff
+887
-867
File diff suppressed because it is too large.
Load diff
+887
-867
File diff suppressed because it is too large.
Load diff
+21
-1
@@ -864,5 +864,25 @@
|
||||
"dueCardsViewChange-choice-me": "Me",
|
||||
"dueCardsViewChange-choice-all": "All Users",
|
||||
"dueCardsViewChange-choice-all-description": "Shows all incomplete cards with a *Due* date from boards for which the user has permission.",
|
||||
"broken-cards": "Broken Cards"
|
||||
"broken-cards": "Broken Cards",
|
||||
"board-title-not-found": "Board '%s' not found.",
|
||||
"swimlane-title-not-found": "Swimlane '%s' not found.",
|
||||
"list-title-not-found": "List '%s' not found.",
|
||||
"user-username-not-found": "Username '%s' not found.",
|
||||
"globalSearch-title": "Search All Boards",
|
||||
"no-cards-found": "No Cards Found",
|
||||
"one-card-found": "One Card Found",
|
||||
"n-cards-found": "%s Cards Found",
|
||||
"n-n-of-n-cards-found": "%s-%s of %s Cards Found",
|
||||
"operator-board": "board",
|
||||
"operator-board-abbrev": "b",
|
||||
"operator-swimlane": "swimlane",
|
||||
"operator-swimlane-abbrev": "s",
|
||||
"operator-list": "list",
|
||||
"operator-list-abbrev": "l",
|
||||
"operator-label": "label",
|
||||
"operator-label-abbrev": "#",
|
||||
"operator-user": "user",
|
||||
"operator-user-abbrev": "@",
|
||||
"operator-is": "is"
|
||||
}
|
||||
+887
-867
File diff suppressed because it is too large.
Load diff
+887
-867
File diff suppressed because it is too large.
Load diff
+887
-867
File diff suppressed because it is too large.
Load diff
+887
-867
File diff suppressed because it is too large.
Load diff
+887
-867
File diff suppressed because it is too large.
Load diff
+887
-867
File diff suppressed because it is too large.
Load diff
+887
-867
File diff suppressed because it is too large.
Load diff
+887
-867
File diff suppressed because it is too large.
Load diff
+887
-867
File diff suppressed because it is too large.
Load diff
+887
-867
File diff suppressed because it is too large.
Load diff
+887
-867
File diff suppressed because it is too large.
Load diff
+887
-867
File diff suppressed because it is too large.
Load diff
+887
-867
File diff suppressed because it is too large.
Load diff
+887
-867
File diff suppressed because it is too large.
Load diff
+887
-867
File diff suppressed because it is too large.
Load diff
+887
-867
File diff suppressed because it is too large.
Load diff
+887
-867
File diff suppressed because it is too large.
Load diff
+887
-867
File diff suppressed because it is too large.
Load diff
+887
-867
File diff suppressed because it is too large.
Load diff
+887
-867
File diff suppressed because it is too large.
Load diff
+887
-867
File diff suppressed because it is too large.
Load diff
+887
-867
File diff suppressed because it is too large.
Load diff
+887
-867
File diff suppressed because it is too large.
Load diff
+887
-867
File diff suppressed because it is too large.
Load diff
+887
-867
File diff suppressed because it is too large.
Load diff
+887
-867
File diff suppressed because it is too large.
Load diff
+887
-867
File diff suppressed because it is too large.
Load diff
+887
-867
File diff suppressed because it is too large.
Load diff
+887
-867
File diff suppressed because it is too large.
Load diff
+887
-867
File diff suppressed because it is too large.
Load diff
+887
-867
File diff suppressed because it is too large.
Load diff
+887
-867
File diff suppressed because it is too large.
Load diff
+887
-867
File diff suppressed because it is too large.
Load diff
+887
-867
File diff suppressed because it is too large.
Load diff
+887
-867
File diff suppressed because it is too large.
Load diff
+21
-1
@@ -864,5 +864,25 @@
|
||||
"dueCardsViewChange-choice-me": "Мне",
|
||||
"dueCardsViewChange-choice-all": "Все пользователи",
|
||||
"dueCardsViewChange-choice-all-description": "Показать все незавершенные карточки с установленным сроком с досок для которых у пользователя есть разрешения.",
|
||||
"broken-cards": "Просроченные карточки"
|
||||
"broken-cards": "Просроченные карточки",
|
||||
"board-title-not-found": "Доска '%s' не найдена.",
|
||||
"swimlane-title-not-found": "Дорожка '%s' не найдена.",
|
||||
"list-title-not-found": "Список '%s' не найден.",
|
||||
"user-username-not-found": "Имя пользователя '%s' не найдено.",
|
||||
"globalSearch-title": "Искать на всех досках",
|
||||
"no-cards-found": "Ни одной карточки не найдено",
|
||||
"one-card-found": "Найдена одна карточка",
|
||||
"n-cards-found": "Карточек найдено %s",
|
||||
"n-n-of-n-cards-found": "Карточки %s - %s из %s найденных",
|
||||
"operator-board": "доска",
|
||||
"operator-board-abbrev": "д",
|
||||
"operator-swimlane": "дорожка",
|
||||
"operator-swimlane-abbrev": "дор.",
|
||||
"operator-list": "список",
|
||||
"operator-list-abbrev": "l",
|
||||
"operator-label": "метку",
|
||||
"operator-label-abbrev": "#",
|
||||
"operator-user": "пользователь",
|
||||
"operator-user-abbrev": "@",
|
||||
"operator-is": " "
|
||||
}
|
||||
+887
-867
File diff suppressed because it is too large.
Load diff
+887
-867
File diff suppressed because it is too large.
Load diff
+887
-867
File diff suppressed because it is too large.
Load diff
+887
-867
File diff suppressed because it is too large.
Load diff
+887
-867
File diff suppressed because it is too large.
Load diff
+887
-867
File diff suppressed because it is too large.
Load diff
+887
-867
File diff suppressed because it is too large.
Load diff
+887
-867
File diff suppressed because it is too large.
Load diff
+887
-867
File diff suppressed because it is too large.
Load diff
+887
-867
File diff suppressed because it is too large.
Load diff
+887
-867
File diff suppressed because it is too large.
Load diff
+887
-867
File diff suppressed because it is too large.
Load diff
+887
-867
File diff suppressed because it is too large.
Load diff
@@ -1208,6 +1208,45 @@ function boardRemover(userId, doc) {
|
||||
);
|
||||
}
|
||||
|
||||
Boards.userSearch = (
|
||||
userId,
|
||||
selector = {},
|
||||
projection = {},
|
||||
includeArchived = false,
|
||||
) => {
|
||||
if (!includeArchived) {
|
||||
selector.archived = false;
|
||||
}
|
||||
selector.$or = [
|
||||
{ permission: 'public' },
|
||||
{ members: { $elemMatch: { userId, isActive: true } } },
|
||||
];
|
||||
|
||||
return Boards.find(selector, projection);
|
||||
};
|
||||
|
||||
Boards.userBoards = (userId, includeArchived = false, selector = {}) => {
|
||||
check(userId, String);
|
||||
|
||||
if (!includeArchived) {
|
||||
selector = {
|
||||
archived: false,
|
||||
};
|
||||
}
|
||||
selector.$or = [
|
||||
{ permission: 'public' },
|
||||
{ members: { $elemMatch: { userId, isActive: true } } },
|
||||
];
|
||||
|
||||
return Boards.find(selector);
|
||||
};
|
||||
|
||||
Boards.userBoardIds = (userId, includeArchived = false, selector = {}) => {
|
||||
return Boards.userBoards(userId, includeArchived, selector).map(board => {
|
||||
return board._id;
|
||||
});
|
||||
};
|
||||
|
||||
if (Meteor.isServer) {
|
||||
Boards.allow({
|
||||
insert: Meteor.userId,
|
||||
|
||||
+195
@@ -1730,6 +1730,201 @@ Cards.mutations({
|
||||
},
|
||||
});
|
||||
|
||||
Cards.globalSearch = queryParams => {
|
||||
const userId = Meteor.userId();
|
||||
// eslint-disable-next-line no-console
|
||||
// console.log('userId:', userId);
|
||||
|
||||
const errors = {
|
||||
notFound: {
|
||||
boards: [],
|
||||
swimlanes: [],
|
||||
lists: [],
|
||||
labels: [],
|
||||
users: [],
|
||||
is: [],
|
||||
},
|
||||
};
|
||||
|
||||
const selector = {
|
||||
archived: false,
|
||||
type: 'cardType-card',
|
||||
boardId: { $in: Boards.userBoardIds(userId) },
|
||||
swimlaneId: { $nin: Swimlanes.archivedSwimlaneIds() },
|
||||
listId: { $nin: Lists.archivedListIds() },
|
||||
};
|
||||
|
||||
if (queryParams.boards.length) {
|
||||
const queryBoards = [];
|
||||
queryParams.boards.forEach(query => {
|
||||
const boards = Boards.userSearch(userId, {
|
||||
title: new RegExp(query, 'i'),
|
||||
});
|
||||
if (boards.count()) {
|
||||
boards.forEach(board => {
|
||||
queryBoards.push(board._id);
|
||||
});
|
||||
} else {
|
||||
errors.notFound.boards.push(query);
|
||||
}
|
||||
});
|
||||
|
||||
selector.boardId.$in = queryBoards;
|
||||
}
|
||||
|
||||
if (queryParams.swimlanes.length) {
|
||||
const querySwimlanes = [];
|
||||
queryParams.swimlanes.forEach(query => {
|
||||
const swimlanes = Swimlanes.find({
|
||||
title: new RegExp(query, 'i'),
|
||||
});
|
||||
if (swimlanes.count()) {
|
||||
swimlanes.forEach(swim => {
|
||||
querySwimlanes.push(swim._id);
|
||||
});
|
||||
} else {
|
||||
errors.notFound.swimlanes.push(query);
|
||||
}
|
||||
});
|
||||
|
||||
selector.swimlaneId.$in = querySwimlanes;
|
||||
}
|
||||
|
||||
if (queryParams.lists.length) {
|
||||
const queryLists = [];
|
||||
queryParams.lists.forEach(query => {
|
||||
const lists = Lists.find({
|
||||
title: new RegExp(query, 'i'),
|
||||
});
|
||||
if (lists.count()) {
|
||||
lists.forEach(list => {
|
||||
queryLists.push(list._id);
|
||||
});
|
||||
} else {
|
||||
errors.notFound.lists.push(query);
|
||||
}
|
||||
});
|
||||
|
||||
selector.listId.$in = queryLists;
|
||||
}
|
||||
|
||||
if (queryParams.users.length) {
|
||||
const queryUsers = [];
|
||||
queryParams.users.forEach(query => {
|
||||
const users = Users.find({
|
||||
username: query,
|
||||
});
|
||||
if (users.count()) {
|
||||
users.forEach(user => {
|
||||
queryUsers.push(user._id);
|
||||
});
|
||||
} else {
|
||||
errors.notFound.users.push(query);
|
||||
}
|
||||
});
|
||||
|
||||
selector.$or = [
|
||||
{ members: { $in: queryUsers } },
|
||||
{ assignees: { $in: queryUsers } },
|
||||
];
|
||||
}
|
||||
|
||||
if (queryParams.labels.length) {
|
||||
queryParams.labels.forEach(label => {
|
||||
const queryLabels = [];
|
||||
|
||||
let boards = Boards.userSearch(userId, {
|
||||
labels: { $elemMatch: { color: label.toLowerCase() } },
|
||||
});
|
||||
|
||||
if (boards.count()) {
|
||||
boards.forEach(board => {
|
||||
// eslint-disable-next-line no-console
|
||||
// console.log('board:', board);
|
||||
// eslint-disable-next-line no-console
|
||||
// console.log('board.labels:', board.labels);
|
||||
board.labels
|
||||
.filter(boardLabel => {
|
||||
return boardLabel.color === label.toLowerCase();
|
||||
})
|
||||
.forEach(boardLabel => {
|
||||
queryLabels.push(boardLabel._id);
|
||||
});
|
||||
});
|
||||
} else {
|
||||
// eslint-disable-next-line no-console
|
||||
// console.log('label:', label);
|
||||
const reLabel = new RegExp(label, 'i');
|
||||
// eslint-disable-next-line no-console
|
||||
// console.log('reLabel:', reLabel);
|
||||
boards = Boards.userSearch(userId, {
|
||||
labels: { $elemMatch: { name: reLabel } },
|
||||
});
|
||||
|
||||
if (boards.count()) {
|
||||
boards.forEach(board => {
|
||||
board.labels
|
||||
.filter(boardLabel => {
|
||||
return boardLabel.name.match(reLabel);
|
||||
})
|
||||
.forEach(boardLabel => {
|
||||
queryLabels.push(boardLabel._id);
|
||||
});
|
||||
});
|
||||
} else {
|
||||
errors.notFound.labels.push({ tag: 'label', value: label });
|
||||
}
|
||||
}
|
||||
|
||||
selector.labelIds = { $in: queryLabels };
|
||||
});
|
||||
}
|
||||
|
||||
if (queryParams.text) {
|
||||
const regex = new RegExp(queryParams.text, 'i');
|
||||
|
||||
selector.$or = [
|
||||
{ title: regex },
|
||||
{ description: regex },
|
||||
{ customFields: { $elemMatch: { value: regex } } },
|
||||
];
|
||||
}
|
||||
|
||||
// eslint-disable-next-line no-console
|
||||
// console.log('selector:', selector);
|
||||
const cards = Cards.find(selector, {
|
||||
fields: {
|
||||
_id: 1,
|
||||
archived: 1,
|
||||
boardId: 1,
|
||||
swimlaneId: 1,
|
||||
listId: 1,
|
||||
title: 1,
|
||||
type: 1,
|
||||
sort: 1,
|
||||
members: 1,
|
||||
assignees: 1,
|
||||
colors: 1,
|
||||
dueAt: 1,
|
||||
labelIds: 1,
|
||||
},
|
||||
limit: 50,
|
||||
});
|
||||
|
||||
// eslint-disable-next-line no-console
|
||||
// console.log('count:', cards.count());
|
||||
|
||||
if (Meteor.isServer) {
|
||||
Users.update(userId, {
|
||||
$set: {
|
||||
'sessionData.totalHits': cards.count(),
|
||||
'sessionData.lastHit': cards.count() > 50 ? 50 : cards.count(),
|
||||
},
|
||||
});
|
||||
}
|
||||
return { cards, errors };
|
||||
};
|
||||
|
||||
//FUNCTIONS FOR creation of Activities
|
||||
|
||||
function updateActivities(doc, fieldNames, modifier) {
|
||||
|
||||
@@ -328,6 +328,16 @@ Lists.mutations({
|
||||
},
|
||||
});
|
||||
|
||||
Lists.archivedLists = () => {
|
||||
return Lists.find({ archived: true });
|
||||
};
|
||||
|
||||
Lists.archivedListIds = () => {
|
||||
return Lists.archivedLists().map(list => {
|
||||
return list._id;
|
||||
});
|
||||
};
|
||||
|
||||
Meteor.methods({
|
||||
applyWipLimit(listId, limit) {
|
||||
check(listId, String);
|
||||
|
||||
@@ -283,6 +283,16 @@ Swimlanes.mutations({
|
||||
},
|
||||
});
|
||||
|
||||
Swimlanes.archivedSwimlanes = () => {
|
||||
return Swimlanes.find({ archived: true });
|
||||
};
|
||||
|
||||
Swimlanes.archivedSwimlaneIds = () => {
|
||||
return Swimlanes.archivedSwimlanes().map(swim => {
|
||||
return swim._id;
|
||||
});
|
||||
};
|
||||
|
||||
Swimlanes.hookOptions.after.update = { fetchPrevious: false };
|
||||
|
||||
if (Meteor.isServer) {
|
||||
|
||||
@@ -311,6 +311,33 @@ Users.attachSchema(
|
||||
optional: false,
|
||||
defaultValue: 'password',
|
||||
},
|
||||
sessionData: {
|
||||
/**
|
||||
* profile settings
|
||||
*/
|
||||
type: Object,
|
||||
optional: true,
|
||||
// eslint-disable-next-line consistent-return
|
||||
autoValue() {
|
||||
if (this.isInsert && !this.isSet) {
|
||||
return {};
|
||||
}
|
||||
},
|
||||
},
|
||||
'sessionData.totalHits': {
|
||||
/**
|
||||
* Total hits from last search
|
||||
*/
|
||||
type: Number,
|
||||
optional: true,
|
||||
},
|
||||
'sessionData.lastHit': {
|
||||
/**
|
||||
* last hit that was returned
|
||||
*/
|
||||
type: Number,
|
||||
optional: true,
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
|
||||
Generated
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "wekan",
|
||||
"version": "v4.77.0",
|
||||
"version": "v4.78.0",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "wekan",
|
||||
"version": "v4.77.0",
|
||||
"version": "v4.78.0",
|
||||
"description": "Open-Source kanban",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
|
||||
+65
-5
@@ -1524,7 +1524,7 @@ var n=this.pipeline.run(e.tokenizer(t)),r=new e.Vector,i=[],o=this._fields.reduc
|
||||
<ul class="toc-list-h1">
|
||||
|
||||
<li>
|
||||
<a href="#wekan-rest-api" class="toc-h1 toc-link" data-title="Wekan REST API v4.77">Wekan REST API v4.77</a>
|
||||
<a href="#wekan-rest-api" class="toc-h1 toc-link" data-title="Wekan REST API v4.78">Wekan REST API v4.78</a>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -2017,6 +2017,11 @@ var n=this.pipeline.run(e.tokenizer(t)),r=new e.Vector,i=[],o=this._fields.reduc
|
||||
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="#tocsuserssessiondata" class="toc-h2 toc-link" data-title="UsersSessiondata">UsersSessiondata</a>
|
||||
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
</li>
|
||||
@@ -2032,7 +2037,7 @@ var n=this.pipeline.run(e.tokenizer(t)),r=new e.Vector,i=[],o=this._fields.reduc
|
||||
<div class="page-wrapper">
|
||||
<div class="dark-box"></div>
|
||||
<div class="content">
|
||||
<h1 id="wekan-rest-api">Wekan REST API v4.77</h1>
|
||||
<h1 id="wekan-rest-api">Wekan REST API v4.78</h1>
|
||||
<blockquote>
|
||||
<p>Scroll down for code samples, example requests and responses. Select a language for code samples from the tabs above or the mobile navigation menu.</p>
|
||||
</blockquote>
|
||||
@@ -13138,7 +13143,11 @@ System.out.println(response.toString());
|
||||
<span class="hljs-attr">"isAdmin"</span>: <span class="hljs-literal">true</span>,
|
||||
<span class="hljs-attr">"createdThroughApi"</span>: <span class="hljs-literal">true</span>,
|
||||
<span class="hljs-attr">"loginDisabled"</span>: <span class="hljs-literal">true</span>,
|
||||
<span class="hljs-attr">"authenticationMethod"</span>: <span class="hljs-string">"string"</span>
|
||||
<span class="hljs-attr">"authenticationMethod"</span>: <span class="hljs-string">"string"</span>,
|
||||
<span class="hljs-attr">"sessionData"</span>: {
|
||||
<span class="hljs-attr">"totalHits"</span>: <span class="hljs-number">0</span>,
|
||||
<span class="hljs-attr">"lastHit"</span>: <span class="hljs-number">0</span>
|
||||
}
|
||||
}
|
||||
</code></pre>
|
||||
<h3 id="get_current_user-responses">Responses</h3>
|
||||
@@ -13795,7 +13804,11 @@ System.out.println(response.toString());
|
||||
<span class="hljs-attr">"isAdmin"</span>: <span class="hljs-literal">true</span>,
|
||||
<span class="hljs-attr">"createdThroughApi"</span>: <span class="hljs-literal">true</span>,
|
||||
<span class="hljs-attr">"loginDisabled"</span>: <span class="hljs-literal">true</span>,
|
||||
<span class="hljs-attr">"authenticationMethod"</span>: <span class="hljs-string">"string"</span>
|
||||
<span class="hljs-attr">"authenticationMethod"</span>: <span class="hljs-string">"string"</span>,
|
||||
<span class="hljs-attr">"sessionData"</span>: {
|
||||
<span class="hljs-attr">"totalHits"</span>: <span class="hljs-number">0</span>,
|
||||
<span class="hljs-attr">"lastHit"</span>: <span class="hljs-number">0</span>
|
||||
}
|
||||
}
|
||||
</code></pre>
|
||||
<h3 id="get_user-responses">Responses</h3>
|
||||
@@ -17275,7 +17288,11 @@ UserSecurity
|
||||
<span class="hljs-attr">"isAdmin"</span>: <span class="hljs-literal">true</span>,
|
||||
<span class="hljs-attr">"createdThroughApi"</span>: <span class="hljs-literal">true</span>,
|
||||
<span class="hljs-attr">"loginDisabled"</span>: <span class="hljs-literal">true</span>,
|
||||
<span class="hljs-attr">"authenticationMethod"</span>: <span class="hljs-string">"string"</span>
|
||||
<span class="hljs-attr">"authenticationMethod"</span>: <span class="hljs-string">"string"</span>,
|
||||
<span class="hljs-attr">"sessionData"</span>: {
|
||||
<span class="hljs-attr">"totalHits"</span>: <span class="hljs-number">0</span>,
|
||||
<span class="hljs-attr">"lastHit"</span>: <span class="hljs-number">0</span>
|
||||
}
|
||||
}
|
||||
|
||||
</code></pre>
|
||||
@@ -17369,6 +17386,13 @@ UserSecurity
|
||||
<td>none</td>
|
||||
<td>authentication method of the user</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>sessionData</td>
|
||||
<td><a href="#schemauserssessiondata">UsersSessiondata</a></td>
|
||||
<td>false</td>
|
||||
<td>none</td>
|
||||
<td>profile settings</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<h2 id="tocsusersemails">UsersEmails</h2>
|
||||
@@ -17663,6 +17687,42 @@ UserSecurity
|
||||
<td>sort</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<h2 id="tocsuserssessiondata">UsersSessiondata</h2>
|
||||
<p><a id="schemauserssessiondata"></a></p>
|
||||
<pre class="highlight tab tab-json"><code>{
|
||||
<span class="hljs-attr">"totalHits"</span>: <span class="hljs-number">0</span>,
|
||||
<span class="hljs-attr">"lastHit"</span>: <span class="hljs-number">0</span>
|
||||
}
|
||||
|
||||
</code></pre>
|
||||
<h3 id="properties">Properties</h3>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Type</th>
|
||||
<th>Required</th>
|
||||
<th>Restrictions</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>totalHits</td>
|
||||
<td>number</td>
|
||||
<td>false</td>
|
||||
<td>none</td>
|
||||
<td>Total hits from last search</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>lastHit</td>
|
||||
<td>number</td>
|
||||
<td>false</td>
|
||||
<td>none</td>
|
||||
<td>last hit that was returned</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
</div>
|
||||
|
||||
+17
-1
@@ -1,7 +1,7 @@
|
||||
swagger: '2.0'
|
||||
info:
|
||||
title: Wekan REST API
|
||||
version: v4.77
|
||||
version: v4.78
|
||||
description: |
|
||||
The REST API allows you to control and extend Wekan with ease.
|
||||
|
||||
@@ -3335,6 +3335,11 @@ definitions:
|
||||
description: |
|
||||
authentication method of the user
|
||||
type: string
|
||||
sessionData:
|
||||
description: |
|
||||
profile settings
|
||||
$ref: "#/definitions/UsersSessiondata"
|
||||
x-nullable: true
|
||||
required:
|
||||
- createdAt
|
||||
- modifiedAt
|
||||
@@ -3476,3 +3481,14 @@ definitions:
|
||||
- cardTemplatesSwimlaneId
|
||||
- listTemplatesSwimlaneId
|
||||
- boardTemplatesSwimlaneId
|
||||
UsersSessiondata:
|
||||
type: object
|
||||
properties:
|
||||
totalHits:
|
||||
description: |
|
||||
Total hits from last search
|
||||
type: number
|
||||
lastHit:
|
||||
description: |
|
||||
last hit that was returned
|
||||
type: number
|
||||
@@ -22,10 +22,10 @@ const pkgdef :Spk.PackageDefinition = (
|
||||
appTitle = (defaultText = "Wekan"),
|
||||
# The name of the app as it is displayed to the user.
|
||||
|
||||
appVersion = 477,
|
||||
appVersion = 478,
|
||||
# Increment this for every release.
|
||||
|
||||
appMarketingVersion = (defaultText = "4.77.0~2021-01-13"),
|
||||
appMarketingVersion = (defaultText = "4.78.0~2021-01-16"),
|
||||
# Human-readable presentation of the app version.
|
||||
|
||||
minUpgradableAppVersion = 0,
|
||||
|
||||
@@ -72,7 +72,18 @@ Meteor.publish('myCards', function() {
|
||||
Boards.find({ _id: { $in: boards } }),
|
||||
Swimlanes.find({ _id: { $in: swimlanes } }),
|
||||
Lists.find({ _id: { $in: lists } }),
|
||||
Users.find({ _id: { $in: users } }),
|
||||
Users.find(
|
||||
{ _id: { $in: users } },
|
||||
{
|
||||
fields: {
|
||||
_id: 1,
|
||||
username: 1,
|
||||
'profile.fullname': 1,
|
||||
'profile.avatarUrl': 1,
|
||||
'profile.initials': 1,
|
||||
},
|
||||
},
|
||||
),
|
||||
];
|
||||
});
|
||||
|
||||
@@ -82,7 +93,18 @@ Meteor.publish('dueCards', function(allUsers = false) {
|
||||
// eslint-disable-next-line no-console
|
||||
// console.log('all users:', allUsers);
|
||||
|
||||
const user = Users.findOne(this.userId);
|
||||
const user = Users.findOne(
|
||||
{ _id: this.userId },
|
||||
{
|
||||
fields: {
|
||||
_id: 1,
|
||||
username: 1,
|
||||
'profile.fullname': 1,
|
||||
'profile.avatarUrl': 1,
|
||||
'profile.initials': 1,
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
const archivedBoards = [];
|
||||
Boards.find({ archived: true }).forEach(board => {
|
||||
@@ -166,6 +188,57 @@ Meteor.publish('dueCards', function(allUsers = false) {
|
||||
}
|
||||
});
|
||||
|
||||
return [
|
||||
cards,
|
||||
Boards.find({ _id: { $in: boards } }),
|
||||
Swimlanes.find({ _id: { $in: swimlanes } }),
|
||||
Lists.find({ _id: { $in: lists } }),
|
||||
Users.find(
|
||||
{ _id: { $in: users } },
|
||||
{
|
||||
fields: {
|
||||
_id: 1,
|
||||
username: 1,
|
||||
'profile.fullname': 1,
|
||||
'profile.avatarUrl': 1,
|
||||
'profile.initials': 1,
|
||||
},
|
||||
},
|
||||
),
|
||||
];
|
||||
});
|
||||
|
||||
Meteor.publish('globalSearch', function(queryParams) {
|
||||
check(queryParams, Object);
|
||||
|
||||
// eslint-disable-next-line no-console
|
||||
// console.log('queryParams:', queryParams);
|
||||
|
||||
const cards = Cards.globalSearch(queryParams).cards;
|
||||
|
||||
const boards = [];
|
||||
const swimlanes = [];
|
||||
const lists = [];
|
||||
const users = [this.userId];
|
||||
|
||||
cards.forEach(card => {
|
||||
if (card.boardId) boards.push(card.boardId);
|
||||
if (card.swimlaneId) swimlanes.push(card.swimlaneId);
|
||||
if (card.listId) lists.push(card.listId);
|
||||
if (card.members) {
|
||||
card.members.forEach(userId => {
|
||||
users.push(userId);
|
||||
});
|
||||
}
|
||||
if (card.assignees) {
|
||||
card.assignees.forEach(userId => {
|
||||
users.push(userId);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// eslint-disable-next-line no-console
|
||||
// console.log('users:', users);
|
||||
return [
|
||||
cards,
|
||||
Boards.find({ _id: { $in: boards } }),
|
||||
@@ -176,7 +249,18 @@ Meteor.publish('dueCards', function(allUsers = false) {
|
||||
});
|
||||
|
||||
Meteor.publish('brokenCards', function() {
|
||||
const user = Users.findOne(this.userId);
|
||||
const user = Users.findOne(
|
||||
{ _id: this.userId },
|
||||
{
|
||||
fields: {
|
||||
_id: 1,
|
||||
username: 1,
|
||||
'profile.fullname': 1,
|
||||
'profile.avatarUrl': 1,
|
||||
'profile.initials': 1,
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
const permiitedBoards = [null];
|
||||
let selector = {};
|
||||
@@ -221,11 +305,22 @@ Meteor.publish('brokenCards', function() {
|
||||
const boards = [];
|
||||
const swimlanes = [];
|
||||
const lists = [];
|
||||
const users = [];
|
||||
|
||||
cards.forEach(card => {
|
||||
if (card.boardId) boards.push(card.boardId);
|
||||
if (card.swimlaneId) swimlanes.push(card.swimlaneId);
|
||||
if (card.listId) lists.push(card.listId);
|
||||
if (card.members) {
|
||||
card.members.forEach(userId => {
|
||||
users.push(userId);
|
||||
});
|
||||
}
|
||||
if (card.assignees) {
|
||||
card.assignees.forEach(userId => {
|
||||
users.push(userId);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
return [
|
||||
@@ -233,5 +328,17 @@ Meteor.publish('brokenCards', function() {
|
||||
Boards.find({ _id: { $in: boards } }),
|
||||
Swimlanes.find({ _id: { $in: swimlanes } }),
|
||||
Lists.find({ _id: { $in: lists } }),
|
||||
Users.find(
|
||||
{ _id: { $in: users } },
|
||||
{
|
||||
fields: {
|
||||
_id: 1,
|
||||
username: 1,
|
||||
'profile.fullname': 1,
|
||||
'profile.avatarUrl': 1,
|
||||
'profile.initials': 1,
|
||||
},
|
||||
},
|
||||
),
|
||||
];
|
||||
});
|
||||
Reference in new issue
Block a user