forked from vikunja/frontend
feat: add button to clear active filters
This commit is contained in:
parent
6e043e3b9e
commit
f3d338c857
|
@ -1,16 +1,24 @@
|
|||
<template>
|
||||
<transition name="fade">
|
||||
<filters
|
||||
v-if="visibleInternal"
|
||||
v-model="value"
|
||||
ref="filters"
|
||||
/>
|
||||
</transition>
|
||||
<x-button
|
||||
v-if="hasFilters"
|
||||
type="secondary"
|
||||
@click="clearFilters"
|
||||
>
|
||||
{{ $t('filters.clear') }}
|
||||
</x-button>
|
||||
<filters
|
||||
:class="{'is-open': visibleInternal}"
|
||||
class="filter-popup"
|
||||
v-model="value"
|
||||
@change="update"
|
||||
ref="filters"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {closeWhenClickedOutside} from '@/helpers/closeWhenClickedOutside'
|
||||
import Filters from '../../../components/list/partials/filters'
|
||||
import {defaultParams} from '../../tasks/mixins/taskList'
|
||||
|
||||
export default {
|
||||
name: 'filter-popup',
|
||||
|
@ -30,16 +38,25 @@ export default {
|
|||
data() {
|
||||
return {
|
||||
visibleInternal: false,
|
||||
value: null,
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
value: {
|
||||
get() {
|
||||
return this.modelValue
|
||||
},
|
||||
set(value) {
|
||||
this.$emit('update:modelValue', value)
|
||||
},
|
||||
hasFilters() {
|
||||
// this.value also contains the page parameter which we don't want to include in filters
|
||||
const {sort_by, order_by, filter_by, filter_value, filter_comparator, filter_concat, s} = this.value
|
||||
const filterParams = {
|
||||
sort_by,
|
||||
order_by,
|
||||
filter_by,
|
||||
filter_value,
|
||||
filter_comparator,
|
||||
filter_concat,
|
||||
s: s ?? null,
|
||||
}
|
||||
const def = {...defaultParams(), s: null}
|
||||
|
||||
return JSON.stringify(filterParams) !== JSON.stringify(def)
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
|
@ -51,10 +68,13 @@ export default {
|
|||
watch: {
|
||||
modelValue: {
|
||||
handler(value) {
|
||||
this.params = value
|
||||
this.value = value
|
||||
},
|
||||
immediate: true,
|
||||
},
|
||||
value() {
|
||||
this.update()
|
||||
},
|
||||
visible() {
|
||||
this.visibleInternal = !this.visibleInternal
|
||||
},
|
||||
|
@ -69,6 +89,28 @@ export default {
|
|||
this.visibleInternal = false
|
||||
})
|
||||
},
|
||||
clearFilters() {
|
||||
this.value = {...defaultParams()}
|
||||
},
|
||||
update() {
|
||||
this.$emit('update:modelValue', this.value)
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.filter-popup {
|
||||
transition: opacity $transition;
|
||||
opacity: 0;
|
||||
height: 0;
|
||||
overflow: hidden;
|
||||
position: absolute;
|
||||
top: 2rem;
|
||||
|
||||
&.is-open {
|
||||
opacity: 1;
|
||||
height: auto;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -464,9 +464,7 @@ export default {
|
|||
foundDone = i
|
||||
}
|
||||
})
|
||||
if (foundDone === false) {
|
||||
this.filters.done = true
|
||||
}
|
||||
this.filters.done = foundDone === false
|
||||
},
|
||||
async prepareRelatedObjectFilter(kind, filterName = null, servicePrefix = null) {
|
||||
if (filterName === null) {
|
||||
|
|
|
@ -9,12 +9,12 @@
|
|||
>
|
||||
{{ $t('filters.title') }}
|
||||
</x-button>
|
||||
<filter-popup
|
||||
:visible="showTaskFilter"
|
||||
v-model="params"
|
||||
@update:modelValue="loadTasks()"
|
||||
/>
|
||||
</div>
|
||||
<filter-popup
|
||||
:visible="showTaskFilter"
|
||||
v-model="params"
|
||||
@update:modelValue="loadTasks()"
|
||||
/>
|
||||
</div>
|
||||
<div class="dates">
|
||||
<template v-for="(y, yk) in days" :key="yk + 'year'">
|
||||
|
@ -349,7 +349,7 @@ export default {
|
|||
return
|
||||
}
|
||||
|
||||
let newTask = { ...taskDragged }
|
||||
let newTask = {...taskDragged}
|
||||
|
||||
const didntHaveDates = newTask.startDate === null ? true : false
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import TaskCollectionService from '@/services/taskCollection'
|
||||
|
||||
// FIXME: merge with DEFAULT_PARAMS in filters.vue
|
||||
const DEFAULT_PARAMS = {
|
||||
export const DEFAULT_PARAMS = {
|
||||
sort_by: ['position', 'id'],
|
||||
order_by: ['asc', 'desc'],
|
||||
filter_by: ['done'],
|
||||
|
@ -10,6 +10,17 @@ const DEFAULT_PARAMS = {
|
|||
filter_concat: 'and',
|
||||
}
|
||||
|
||||
export const defaultParams = () => {
|
||||
return {
|
||||
sort_by: ['position', 'id'],
|
||||
order_by: ['asc', 'desc'],
|
||||
filter_by: ['done'],
|
||||
filter_value: ['false'],
|
||||
filter_comparator: ['equals'],
|
||||
filter_concat: 'and',
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This mixin provides a base set of methods and properties to get tasks on a list.
|
||||
*/
|
||||
|
@ -26,7 +37,7 @@ export default {
|
|||
searchTerm: '',
|
||||
|
||||
showTaskFilter: false,
|
||||
params: DEFAULT_PARAMS,
|
||||
params: {...DEFAULT_PARAMS},
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
|
@ -94,7 +105,7 @@ export default {
|
|||
this.initTasks(page, search)
|
||||
},
|
||||
loadTasksOnSavedFilter() {
|
||||
if(typeof this.$route.params.listId !== 'undefined' && parseInt(this.$route.params.listId) < 0) {
|
||||
if (typeof this.$route.params.listId !== 'undefined' && parseInt(this.$route.params.listId) < 0) {
|
||||
this.loadTasks(1, '', null, true)
|
||||
}
|
||||
},
|
||||
|
|
|
@ -344,6 +344,7 @@
|
|||
},
|
||||
"filters": {
|
||||
"title": "Filters",
|
||||
"clear": "Clear Filters",
|
||||
"attributes": {
|
||||
"title": "Title",
|
||||
"titlePlaceholder": "The saved filter title goes here…",
|
||||
|
|
|
@ -47,10 +47,6 @@ $filter-container-top-link-share-list: -47px;
|
|||
justify-content: space-between;
|
||||
margin-right: .5rem;
|
||||
|
||||
.button, .input {
|
||||
height: $switch-view-height;
|
||||
}
|
||||
|
||||
.field {
|
||||
transition: width $transition;
|
||||
width: 100%;
|
||||
|
|
|
@ -9,11 +9,11 @@
|
|||
>
|
||||
{{ $t('filters.title') }}
|
||||
</x-button>
|
||||
<filter-popup
|
||||
:visible="showFilters"
|
||||
v-model="params"
|
||||
/>
|
||||
</div>
|
||||
<filter-popup
|
||||
:visible="showFilters"
|
||||
v-model="params"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
:class="{ 'is-loading': loading && !oneTaskUpdating}"
|
||||
|
@ -143,7 +143,7 @@
|
|||
:component-data="taskDraggableTaskComponentData"
|
||||
>
|
||||
<template #item="{element: task}">
|
||||
<kanban-card :task="task" />
|
||||
<kanban-card :task="task"/>
|
||||
</template>
|
||||
</draggable>
|
||||
</div>
|
||||
|
@ -213,7 +213,7 @@
|
|||
<!-- This router view is used to show the task popup while keeping the kanban board itself -->
|
||||
<router-view v-slot="{ Component }">
|
||||
<transition name="modal">
|
||||
<component :is="Component" />
|
||||
<component :is="Component"/>
|
||||
</transition>
|
||||
</router-view>
|
||||
|
||||
|
@ -224,10 +224,10 @@
|
|||
v-if="showBucketDeleteModal"
|
||||
>
|
||||
<template #header><span>{{ $t('list.kanban.deleteHeaderBucket') }}</span></template>
|
||||
|
||||
|
||||
<template #text>
|
||||
<p>{{ $t('list.kanban.deleteBucketText1') }}<br/>
|
||||
{{ $t('list.kanban.deleteBucketText2') }}</p>
|
||||
{{ $t('list.kanban.deleteBucketText2') }}</p>
|
||||
</template>
|
||||
</modal>
|
||||
</transition>
|
||||
|
@ -328,10 +328,10 @@ export default {
|
|||
return {
|
||||
type: 'transition',
|
||||
tag: 'div',
|
||||
name: !this.dragBucket ? 'move-bucket': null,
|
||||
name: !this.dragBucket ? 'move-bucket' : null,
|
||||
class: [
|
||||
'kanban-bucket-container',
|
||||
{ 'dragging-disabled': !this.canWrite },
|
||||
{'dragging-disabled': !this.canWrite},
|
||||
],
|
||||
}
|
||||
},
|
||||
|
@ -339,10 +339,10 @@ export default {
|
|||
return {
|
||||
type: 'transition',
|
||||
tag: 'div',
|
||||
name: !this.drag ? 'move-card': null,
|
||||
name: !this.drag ? 'move-card' : null,
|
||||
class: [
|
||||
'dropper',
|
||||
{ 'dragging-disabled': !this.canWrite },
|
||||
{'dragging-disabled': !this.canWrite},
|
||||
],
|
||||
}
|
||||
},
|
||||
|
@ -357,7 +357,7 @@ export default {
|
|||
list: state => state.currentList,
|
||||
}),
|
||||
},
|
||||
|
||||
|
||||
methods: {
|
||||
toggleFilterPopup() {
|
||||
this.showFilters = !this.showFilters
|
||||
|
@ -369,7 +369,7 @@ export default {
|
|||
return
|
||||
}
|
||||
|
||||
const { listId, params } = this.loadBucketParameter
|
||||
const {listId, params} = this.loadBucketParameter
|
||||
|
||||
this.collapsedBuckets = getCollapsedBucketState(listId)
|
||||
|
||||
|
@ -424,7 +424,7 @@ export default {
|
|||
|
||||
const newTask = cloneDeep(task) // cloning the task to avoid vuex store mutations
|
||||
newTask.bucketId = newBucket.id,
|
||||
newTask.kanbanPosition = calculateItemPosition(taskBefore !== null ? taskBefore.kanbanPosition : null, taskAfter !== null ? taskAfter.kanbanPosition : null)
|
||||
newTask.kanbanPosition = calculateItemPosition(taskBefore !== null ? taskBefore.kanbanPosition : null, taskAfter !== null ? taskAfter.kanbanPosition : null)
|
||||
|
||||
try {
|
||||
await this.$store.dispatch('tasks/update', newTask)
|
||||
|
|
|
@ -48,12 +48,12 @@
|
|||
>
|
||||
{{ $t('filters.title') }}
|
||||
</x-button>
|
||||
<filter-popup
|
||||
:visible="showTaskFilter"
|
||||
v-model="params"
|
||||
@update:modelValue="loadTasks()"
|
||||
/>
|
||||
</div>
|
||||
<filter-popup
|
||||
:visible="showTaskFilter"
|
||||
v-model="params"
|
||||
@update:modelValue="loadTasks()"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<card :padding="false" :has-content="false" class="has-overflow">
|
||||
|
@ -125,7 +125,7 @@
|
|||
</card>
|
||||
</div>
|
||||
|
||||
<Pagination
|
||||
<Pagination
|
||||
:total-pages="taskCollectionService.totalPages"
|
||||
:current-page="currentPage"
|
||||
/>
|
||||
|
@ -134,7 +134,7 @@
|
|||
<!-- This router view is used to show the task popup while keeping the kanban board itself -->
|
||||
<router-view v-slot="{ Component }">
|
||||
<transition name="modal">
|
||||
<component :is="Component" />
|
||||
<component :is="Component"/>
|
||||
</transition>
|
||||
</router-view>
|
||||
</div>
|
||||
|
@ -293,11 +293,11 @@ export default {
|
|||
|
||||
async saveTaskPosition(e) {
|
||||
this.drag = false
|
||||
|
||||
|
||||
const task = this.tasks[e.newIndex]
|
||||
const taskBefore = this.tasks[e.newIndex - 1] ?? null
|
||||
const taskAfter = this.tasks[e.newIndex + 1] ?? null
|
||||
|
||||
const taskAfter = this.tasks[e.newIndex + 1] ?? null
|
||||
|
||||
const newTask = {
|
||||
...task,
|
||||
position: calculateItemPosition(taskBefore !== null ? taskBefore.position : null, taskAfter !== null ? taskAfter.position : null),
|
||||
|
|
|
@ -16,6 +16,11 @@
|
|||
>
|
||||
{{ $t('filters.title') }}
|
||||
</x-button>
|
||||
<filter-popup
|
||||
:visible="showTaskFilter"
|
||||
v-model="params"
|
||||
@update:modelValue="loadTasks()"
|
||||
/>
|
||||
</div>
|
||||
<transition name="fade">
|
||||
<card v-if="showActiveColumnsFilter">
|
||||
|
@ -58,11 +63,6 @@
|
|||
</fancycheckbox>
|
||||
</card>
|
||||
</transition>
|
||||
<filter-popup
|
||||
:visible="showTaskFilter"
|
||||
v-model="params"
|
||||
@update:modelValue="loadTasks()"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<card :padding="false" :has-content="false">
|
||||
|
|
Loading…
Reference in New Issue