Board filter (#1507)
* filter field Signed-off-by: Jakob Röhrl <jakob.roehrl@web.de> * build filters Signed-off-by: Jakob Röhrl <jakob.roehrl@web.de> * Implement tag and assigned user filters Signed-off-by: Julius Härtl <jus@bitgrid.net> * small changes Signed-off-by: Jakob Röhrl <jakob.roehrl@web.de> * new icon Signed-off-by: Jakob Röhrl <jakob.roehrl@web.de> * Properly style filter popover Signed-off-by: Julius Härtl <jus@bitgrid.net> * Make sure that due is reactive Signed-off-by: Julius Härtl <jus@bitgrid.net> * filers are working now :) Signed-off-by: Jakob Röhrl <jakob.roehrl@web.de> Co-authored-by: Julius Härtl <jus@bitgrid.net>
This commit is contained in:
@@ -59,6 +59,7 @@
|
|||||||
@include icon-black-white('archive', 'deck', 1);
|
@include icon-black-white('archive', 'deck', 1);
|
||||||
@include icon-black-white('circles', 'deck', 1);
|
@include icon-black-white('circles', 'deck', 1);
|
||||||
@include icon-black-white('clone', 'deck', 1);
|
@include icon-black-white('clone', 'deck', 1);
|
||||||
|
@include icon-black-white('filter', 'deck', 1);
|
||||||
@include icon-black-white('attach', 'deck', 1);
|
@include icon-black-white('attach', 'deck', 1);
|
||||||
|
|
||||||
.icon-toggle-compact-collapsed {
|
.icon-toggle-compact-collapsed {
|
||||||
|
|||||||
78
img/filter.svg
Normal file
78
img/filter.svg
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
width="16"
|
||||||
|
height="16"
|
||||||
|
viewBox="0 0 4.2333332 4.2333335"
|
||||||
|
version="1.1"
|
||||||
|
id="svg4524"
|
||||||
|
inkscape:version="0.92.4 5da689c313, 2019-01-14"
|
||||||
|
sodipodi:docname="filter.svg">
|
||||||
|
<defs
|
||||||
|
id="defs4518" />
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="base"
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1.0"
|
||||||
|
inkscape:pageopacity="0.0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:zoom="11.2"
|
||||||
|
inkscape:cx="-13.015771"
|
||||||
|
inkscape:cy="15.433087"
|
||||||
|
inkscape:document-units="mm"
|
||||||
|
inkscape:current-layer="layer1"
|
||||||
|
showgrid="false"
|
||||||
|
units="px"
|
||||||
|
showguides="true"
|
||||||
|
inkscape:guide-bbox="true"
|
||||||
|
inkscape:window-width="1920"
|
||||||
|
inkscape:window-height="1017"
|
||||||
|
inkscape:window-x="0"
|
||||||
|
inkscape:window-y="26"
|
||||||
|
inkscape:window-maximized="1">
|
||||||
|
<sodipodi:guide
|
||||||
|
position="3.1773623,1.9016928"
|
||||||
|
orientation="0,1"
|
||||||
|
id="guide5088"
|
||||||
|
inkscape:locked="false" />
|
||||||
|
</sodipodi:namedview>
|
||||||
|
<metadata
|
||||||
|
id="metadata4521">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title></dc:title>
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g
|
||||||
|
inkscape:label="Ebene 1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1"
|
||||||
|
transform="translate(0,-292.76665)">
|
||||||
|
<path
|
||||||
|
style="opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.09337848;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke fill markers"
|
||||||
|
d="M 0.51971728,293.23203 H 3.8033853 l -1.1728849,1.45285 H 1.6418341 Z"
|
||||||
|
id="rect5069"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="ccccc" />
|
||||||
|
<path
|
||||||
|
style="opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.05817544;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke fill markers"
|
||||||
|
d="m 1.6418341,294.68488 h 0.9921874 v 1.86627 L 1.637658,296.09596 Z"
|
||||||
|
id="rect5069-7"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="ccccc" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 2.6 KiB |
10
package-lock.json
generated
10
package-lock.json
generated
@@ -13118,7 +13118,7 @@
|
|||||||
},
|
},
|
||||||
"mkdirp": {
|
"mkdirp": {
|
||||||
"version": "0.5.1",
|
"version": "0.5.1",
|
||||||
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
|
"resolved": "http://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
|
||||||
"integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
|
"integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
@@ -13778,7 +13778,7 @@
|
|||||||
},
|
},
|
||||||
"os-homedir": {
|
"os-homedir": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz",
|
"resolved": "http://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz",
|
||||||
"integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=",
|
"integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
@@ -13795,7 +13795,7 @@
|
|||||||
},
|
},
|
||||||
"os-tmpdir": {
|
"os-tmpdir": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
|
"resolved": "http://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
|
||||||
"integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=",
|
"integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
@@ -13967,7 +13967,7 @@
|
|||||||
},
|
},
|
||||||
"path-is-absolute": {
|
"path-is-absolute": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
|
"resolved": "http://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
|
||||||
"integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18="
|
"integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18="
|
||||||
},
|
},
|
||||||
"path-key": {
|
"path-key": {
|
||||||
@@ -16710,7 +16710,7 @@
|
|||||||
},
|
},
|
||||||
"string_decoder": {
|
"string_decoder": {
|
||||||
"version": "1.1.1",
|
"version": "1.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
|
"resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
|
||||||
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
|
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"safe-buffer": "~5.1.0"
|
"safe-buffer": "~5.1.0"
|
||||||
|
|||||||
@@ -47,6 +47,102 @@
|
|||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
<div class="board-action-buttons">
|
<div class="board-action-buttons">
|
||||||
|
<Popover>
|
||||||
|
<Actions slot="trigger">
|
||||||
|
<ActionButton icon="icon-filter" :title="t('deck', 'Apply filter')" />
|
||||||
|
</Actions>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="filter">
|
||||||
|
<h3>{{ t('deck', 'Filter by tag') }}</h3>
|
||||||
|
<div v-for="label in board.labels" :key="label.id" class="filter--item">
|
||||||
|
<input
|
||||||
|
:id="label.id"
|
||||||
|
v-model="filter.tags"
|
||||||
|
type="checkbox"
|
||||||
|
class="checkbox"
|
||||||
|
:value="label.id"
|
||||||
|
@change="setFilter">
|
||||||
|
<label :for="label.id"><span class="label" :style="labelStyle(label)">{{ label.title }}</span></label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h3>{{ t('deck', 'Filter by assigned user') }}</h3>
|
||||||
|
<div v-for="user in board.users" :key="user.uid" class="filter--item">
|
||||||
|
<input
|
||||||
|
:id="user.uid"
|
||||||
|
v-model="filter.users"
|
||||||
|
type="checkbox"
|
||||||
|
class="checkbox"
|
||||||
|
:value="user.uid"
|
||||||
|
@change="setFilter">
|
||||||
|
<label :for="user.uid"><Avatar :user="user.uid" :size="24" :disable-menu="true" /> {{ user.displayname }}</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h3>{{ t('deck', 'Filter by duedate') }}</h3>
|
||||||
|
|
||||||
|
<div class="filter--item">
|
||||||
|
<input
|
||||||
|
id="overdue"
|
||||||
|
v-model="filter.due"
|
||||||
|
type="radio"
|
||||||
|
class="radio"
|
||||||
|
value="overdue"
|
||||||
|
@change="setFilter"
|
||||||
|
@click="beforeSetFilter">
|
||||||
|
<label for="overdue">{{ t('deck', 'Overdue') }}</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="filter--item">
|
||||||
|
<input
|
||||||
|
id="dueToday"
|
||||||
|
v-model="filter.due"
|
||||||
|
type="radio"
|
||||||
|
class="radio"
|
||||||
|
value="dueToday"
|
||||||
|
@change="setFilter"
|
||||||
|
@click="beforeSetFilter">
|
||||||
|
<label for="dueToday">{{ t('deck', 'Today') }}</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="filter--item">
|
||||||
|
<input
|
||||||
|
id="dueWeek"
|
||||||
|
v-model="filter.due"
|
||||||
|
type="radio"
|
||||||
|
class="radio"
|
||||||
|
value="dueWeek"
|
||||||
|
@change="setFilter"
|
||||||
|
@click="beforeSetFilter">
|
||||||
|
<label for="dueWeek">{{ t('deck', 'Next 7 days') }}</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="filter--item">
|
||||||
|
<input
|
||||||
|
id="dueMonth"
|
||||||
|
v-model="filter.due"
|
||||||
|
type="radio"
|
||||||
|
class="radio"
|
||||||
|
value="dueMonth"
|
||||||
|
@change="setFilter"
|
||||||
|
@click="beforeSetFilter">
|
||||||
|
<label for="dueMonth">{{ t('deck', 'Next 30 days') }}</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="filter--item">
|
||||||
|
<input
|
||||||
|
id="noDue"
|
||||||
|
v-model="filter.due"
|
||||||
|
type="radio"
|
||||||
|
class="radio"
|
||||||
|
value="noDue"
|
||||||
|
@change="setFilter"
|
||||||
|
@click="beforeSetFilter">
|
||||||
|
<label for="noDue">{{ t('deck', 'No due date') }}</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</Popover>
|
||||||
|
|
||||||
<Actions style="opacity: .5;">
|
<Actions style="opacity: .5;">
|
||||||
<ActionButton v-if="showArchived"
|
<ActionButton v-if="showArchived"
|
||||||
icon="icon-archive"
|
icon="icon-archive"
|
||||||
@@ -69,7 +165,7 @@
|
|||||||
</Actions>
|
</Actions>
|
||||||
<!-- FIXME: ActionRouter currently doesn't work as an inline action -->
|
<!-- FIXME: ActionRouter currently doesn't work as an inline action -->
|
||||||
<Actions>
|
<Actions>
|
||||||
<ActionButton icon="icon-share" @click="toggleDetailsView" />
|
<ActionButton icon="icon-menu-sidebar" @click="toggleDetailsView" />
|
||||||
</Actions>
|
</Actions>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -78,13 +174,15 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { mapState, mapGetters } from 'vuex'
|
import { mapState, mapGetters } from 'vuex'
|
||||||
import { Actions, ActionButton } from '@nextcloud/vue'
|
import { Actions, ActionButton, Popover, Avatar } from '@nextcloud/vue'
|
||||||
|
import labelStyle from '../mixins/labelStyle'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'Controls',
|
name: 'Controls',
|
||||||
components: {
|
components: {
|
||||||
Actions, ActionButton,
|
Actions, ActionButton, Popover, Avatar,
|
||||||
},
|
},
|
||||||
|
mixins: [ labelStyle ],
|
||||||
props: {
|
props: {
|
||||||
board: {
|
board: {
|
||||||
type: Object,
|
type: Object,
|
||||||
@@ -98,8 +196,10 @@ export default {
|
|||||||
stack: '',
|
stack: '',
|
||||||
showArchived: false,
|
showArchived: false,
|
||||||
isAddStackVisible: false,
|
isAddStackVisible: false,
|
||||||
|
filter: { tags: [], users: [], due: '' },
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
computed: {
|
computed: {
|
||||||
...mapGetters([
|
...mapGetters([
|
||||||
'canEdit',
|
'canEdit',
|
||||||
@@ -115,6 +215,15 @@ export default {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
beforeSetFilter(e) {
|
||||||
|
if (this.filter.due === e.target.value) {
|
||||||
|
this.filter.due = ''
|
||||||
|
this.$store.dispatch('setFilter', { ...this.filter })
|
||||||
|
}
|
||||||
|
},
|
||||||
|
setFilter() {
|
||||||
|
this.$nextTick(() => this.$store.dispatch('setFilter', { ...this.filter }))
|
||||||
|
},
|
||||||
toggleNav() {
|
toggleNav() {
|
||||||
this.$store.dispatch('toggleNav')
|
this.$store.dispatch('toggleNav')
|
||||||
},
|
},
|
||||||
@@ -210,5 +319,34 @@ export default {
|
|||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.filter--item {
|
||||||
|
input + label {
|
||||||
|
display: block;
|
||||||
|
padding: 6px 0;
|
||||||
|
vertical-align: middle;
|
||||||
|
.avatardiv {
|
||||||
|
vertical-align: middle;
|
||||||
|
margin-bottom: 2px;
|
||||||
|
margin-right: 3px;
|
||||||
|
}
|
||||||
|
.label {
|
||||||
|
padding: 5px;
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.filter {
|
||||||
|
width: 250px;
|
||||||
|
max-height: 80vh;
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
.filter h3 {
|
||||||
|
margin-top: 0px;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<style lang="scss">
|
||||||
|
.tooltip-inner.popover-inner {
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -105,6 +105,7 @@ import axios from '@nextcloud/axios'
|
|||||||
|
|
||||||
import CardBadges from './CardBadges'
|
import CardBadges from './CardBadges'
|
||||||
import Color from '../../mixins/color'
|
import Color from '../../mixins/color'
|
||||||
|
import labelStyle from '../../mixins/labelStyle'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'CardItem',
|
name: 'CardItem',
|
||||||
@@ -112,7 +113,7 @@ export default {
|
|||||||
directives: {
|
directives: {
|
||||||
ClickOutside,
|
ClickOutside,
|
||||||
},
|
},
|
||||||
mixins: [Color],
|
mixins: [Color, labelStyle],
|
||||||
props: {
|
props: {
|
||||||
id: {
|
id: {
|
||||||
type: Number,
|
type: Number,
|
||||||
@@ -150,14 +151,6 @@ export default {
|
|||||||
menu() {
|
menu() {
|
||||||
return []
|
return []
|
||||||
},
|
},
|
||||||
labelStyle() {
|
|
||||||
return (label) => {
|
|
||||||
return {
|
|
||||||
backgroundColor: '#' + label.color,
|
|
||||||
color: this.textColor(label.color),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
currentCard() {
|
currentCard() {
|
||||||
return this.$route.params.cardId === this.id
|
return this.$route.params.cardId === this.id
|
||||||
},
|
},
|
||||||
|
|||||||
37
src/mixins/labelStyle.js
Normal file
37
src/mixins/labelStyle.js
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
/*
|
||||||
|
* @copyright Copyright (c) 2020 Julius Härtl <jus@bitgrid.net>
|
||||||
|
*
|
||||||
|
* @author Julius Härtl <jus@bitgrid.net>
|
||||||
|
*
|
||||||
|
* @license GNU AGPL version 3 or any later version
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
import Color from './color'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
mixins: [ Color ],
|
||||||
|
computed: {
|
||||||
|
labelStyle() {
|
||||||
|
return (label) => {
|
||||||
|
return {
|
||||||
|
backgroundColor: '#' + label.color,
|
||||||
|
color: this.textColor(label.color),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
@@ -30,9 +30,56 @@ export default {
|
|||||||
cards: [],
|
cards: [],
|
||||||
},
|
},
|
||||||
getters: {
|
getters: {
|
||||||
cardsByStack: (state, getters) => (id) => {
|
cardsByStack: (state, getters, rootState) => (id) => {
|
||||||
return state.cards.filter((card) => card.stackId === id && (getters.getSearchQuery === '' || (card.title.toLowerCase().includes(getters.getSearchQuery.toLowerCase()) || card.description.toLowerCase().includes(getters.getSearchQuery.toLowerCase())))
|
return state.cards.filter((card) => {
|
||||||
).sort((a, b) => a.order - b.order)
|
const { tags, users, due } = rootState.filter
|
||||||
|
let allTagsMatch = true
|
||||||
|
let allUsersMatch = true
|
||||||
|
|
||||||
|
if (tags.length > 0) {
|
||||||
|
tags.forEach((tag) => {
|
||||||
|
if (card.labels.findIndex((l) => l.id === tag) === -1) {
|
||||||
|
allTagsMatch = false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
if (!allTagsMatch) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (users.length > 0) {
|
||||||
|
users.forEach((user) => {
|
||||||
|
if (card.assignedUsers.findIndex((u) => u.participant.uid === user) === -1) {
|
||||||
|
allUsersMatch = false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
if (!allUsersMatch) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (due !== '') {
|
||||||
|
const datediffHour = ((new Date(card.duedate) - new Date()) / 3600000)
|
||||||
|
switch (due) {
|
||||||
|
case 'noDue':
|
||||||
|
return (card.duedate === null)
|
||||||
|
case 'overdue':
|
||||||
|
return (card.overdue === 3)
|
||||||
|
case 'dueToday':
|
||||||
|
return (card.overdue >= 2)
|
||||||
|
case 'dueWeek':
|
||||||
|
return (datediffHour <= 168 && card.duedate !== null)
|
||||||
|
case 'dueMonth':
|
||||||
|
return (datediffHour <= 5040 && card.duedate !== null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
.filter((card) => card.stackId === id && (getters.getSearchQuery === ''
|
||||||
|
|| (card.title.toLowerCase().includes(getters.getSearchQuery.toLowerCase())
|
||||||
|
|| card.description.toLowerCase().includes(getters.getSearchQuery.toLowerCase()))
|
||||||
|
.sort((a, b) => a.order - b.order)))
|
||||||
},
|
},
|
||||||
cardById: state => (id) => {
|
cardById: state => (id) => {
|
||||||
return state.cards.find((card) => card.id === id)
|
return state.cards.find((card) => card.id === id)
|
||||||
|
|||||||
@@ -60,11 +60,17 @@ export default new Vuex.Store({
|
|||||||
assignableUsers: [],
|
assignableUsers: [],
|
||||||
boardFilter: BOARD_FILTERS.ALL,
|
boardFilter: BOARD_FILTERS.ALL,
|
||||||
searchQuery: '',
|
searchQuery: '',
|
||||||
|
activity: [],
|
||||||
|
activityLoadMore: true,
|
||||||
|
filter: { tags: [], users: [], due: '' },
|
||||||
},
|
},
|
||||||
getters: {
|
getters: {
|
||||||
getSearchQuery: state => {
|
getSearchQuery: state => {
|
||||||
return state.searchQuery
|
return state.searchQuery
|
||||||
},
|
},
|
||||||
|
getFilter: state => {
|
||||||
|
return state.filter
|
||||||
|
},
|
||||||
boards: state => {
|
boards: state => {
|
||||||
return state.boards
|
return state.boards
|
||||||
},
|
},
|
||||||
@@ -112,6 +118,9 @@ export default new Vuex.Store({
|
|||||||
setSearchQuery(state, searchQuery) {
|
setSearchQuery(state, searchQuery) {
|
||||||
state.searchQuery = searchQuery
|
state.searchQuery = searchQuery
|
||||||
},
|
},
|
||||||
|
setFilter(state, filter) {
|
||||||
|
Object.assign(state.filter, filter)
|
||||||
|
},
|
||||||
toggleShowArchived(state) {
|
toggleShowArchived(state) {
|
||||||
state.showArchived = !state.showArchived
|
state.showArchived = !state.showArchived
|
||||||
},
|
},
|
||||||
@@ -232,6 +241,9 @@ export default new Vuex.Store({
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
actions: {
|
actions: {
|
||||||
|
setFilter({ commit }, filter) {
|
||||||
|
commit('setFilter', filter)
|
||||||
|
},
|
||||||
async loadBoardById({ commit }, boardId) {
|
async loadBoardById({ commit }, boardId) {
|
||||||
commit('setCurrentBoard', null)
|
commit('setCurrentBoard', null)
|
||||||
const board = await apiClient.loadById(boardId)
|
const board = await apiClient.loadById(boardId)
|
||||||
|
|||||||
Reference in New Issue
Block a user