Saved filters (#239)
Fix saving Cleanup Fix single value prepare Add prepare percent done stub Fix populating filters with saved values when editing for single values Fix populating filters with saved values when editing Add edit filter view page Hide adding new tasks to pseudolists Make sure all filter values are passed as strings as per requirement from the api Add redirect to list after creating it Add creating saved filter Add filter by percent done Add end date filter Add start date filter Add extra checkbox to enable/disable priority filter Add changing priority Add more filter stubs Fix dates for filters Add saved filter create form Add include nulls and concat to filter options Add new saved filter component Co-authored-by: kolaente <k@knt.li> Reviewed-on: https://kolaente.dev/vikunja/frontend/pulls/239 Co-Authored-By: konrad <konrad@kola-entertainments.de> Co-Committed-By: konrad <konrad@kola-entertainments.de>
This commit is contained in:
@ -1,6 +1,15 @@
|
||||
<template>
|
||||
<div class="card filters">
|
||||
<div class="card-content">
|
||||
<fancycheckbox v-model="params.filter_include_nulls">
|
||||
Include Tasks which don't have a value set
|
||||
</fancycheckbox>
|
||||
<fancycheckbox
|
||||
v-model="filters.requireAllFilters"
|
||||
@change="setFilterConcat()"
|
||||
>
|
||||
Require all filters to be true for a task to show up
|
||||
</fancycheckbox>
|
||||
<div class="field">
|
||||
<label class="label">Show Done Tasks</label>
|
||||
<div class="control">
|
||||
@ -21,6 +30,62 @@
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label class="label">Priority</label>
|
||||
<div class="control single-value-control">
|
||||
<priority-select
|
||||
:disabled="!filters.usePriority"
|
||||
v-model.number="filters.priority"
|
||||
@change="setPriority"
|
||||
/>
|
||||
<fancycheckbox
|
||||
v-model="filters.usePriority"
|
||||
@change="setPriority"
|
||||
>
|
||||
Enable Filter By Priority
|
||||
</fancycheckbox>
|
||||
</div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label class="label">Start Date</label>
|
||||
<div class="control">
|
||||
<flat-pickr
|
||||
:config="flatPickerConfig"
|
||||
@on-close="setStartDateFilter"
|
||||
class="input"
|
||||
placeholder="Start Date Range"
|
||||
v-model="filters.startDate"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label class="label">End Date</label>
|
||||
<div class="control">
|
||||
<flat-pickr
|
||||
:config="flatPickerConfig"
|
||||
@on-close="setEndDateFilter"
|
||||
class="input"
|
||||
placeholder="End Date Range"
|
||||
v-model="filters.endDate"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label class="label">Percent Done</label>
|
||||
<div class="control single-value-control">
|
||||
<percent-done-select
|
||||
v-model.number="filters.percentDone"
|
||||
@change="setPercentDoneFilter"
|
||||
:disabled="!filters.usePercentDone"
|
||||
/>
|
||||
<fancycheckbox
|
||||
v-model="filters.usePercentDone"
|
||||
@change="setPercentDoneFilter"
|
||||
>
|
||||
Enable Filter By Percent Done
|
||||
</fancycheckbox>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@ -30,11 +95,17 @@ import Fancycheckbox from '../../input/fancycheckbox'
|
||||
import flatPickr from 'vue-flatpickr-component'
|
||||
import 'flatpickr/dist/flatpickr.css'
|
||||
|
||||
import {formatISO} from 'date-fns'
|
||||
import PrioritySelect from '@/components/tasks/partials/prioritySelect'
|
||||
import PercentDoneSelect from '@/components/tasks/partials/percentDoneSelect'
|
||||
|
||||
export default {
|
||||
name: 'filters',
|
||||
components: {
|
||||
PrioritySelect,
|
||||
Fancycheckbox,
|
||||
flatPickr,
|
||||
PercentDoneSelect,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
@ -44,10 +115,19 @@ export default {
|
||||
filter_by: [],
|
||||
filter_value: [],
|
||||
filter_comparator: [],
|
||||
filter_include_nulls: true,
|
||||
filter_concat: 'or',
|
||||
},
|
||||
filters: {
|
||||
done: false,
|
||||
dueDate: '',
|
||||
requireAllFilters: false,
|
||||
priority: 0,
|
||||
usePriority: false,
|
||||
startDate: '',
|
||||
endDate: '',
|
||||
percentDone: 0,
|
||||
usePercentDone: false,
|
||||
},
|
||||
flatPickerConfig: {
|
||||
altFormat: 'j M Y H:i',
|
||||
@ -61,7 +141,8 @@ export default {
|
||||
},
|
||||
mounted() {
|
||||
this.params = this.value
|
||||
this.prepareDone()
|
||||
this.filters.requireAllFilters = this.params.filter_concat === 'and'
|
||||
this.prepareFilters()
|
||||
},
|
||||
props: {
|
||||
value: {
|
||||
@ -71,7 +152,7 @@ export default {
|
||||
watch: {
|
||||
value(newVal) {
|
||||
this.$set(this, 'params', newVal)
|
||||
this.prepareDone()
|
||||
this.prepareFilters()
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
@ -79,42 +160,29 @@ export default {
|
||||
this.$emit('input', this.params)
|
||||
this.$emit('change', this.params)
|
||||
},
|
||||
prepareDone() {
|
||||
// Set filters.done based on params
|
||||
if (typeof this.params.filter_by !== 'undefined') {
|
||||
let foundDone = false
|
||||
this.params.filter_by.forEach((f, i) => {
|
||||
if (f === 'done') {
|
||||
foundDone = i
|
||||
}
|
||||
})
|
||||
if (foundDone === false) {
|
||||
this.filters.done = true
|
||||
prepareFilters() {
|
||||
this.prepareDone()
|
||||
this.prepareDueDate()
|
||||
this.prepareStartDate()
|
||||
this.prepareEndDate()
|
||||
this.preparePriority()
|
||||
this.preparePercentDone()
|
||||
},
|
||||
removePropertyFromFilter(propertyName) {
|
||||
for (const i in this.params.filter_by) {
|
||||
if (this.params.filter_by[i] === propertyName) {
|
||||
this.params.filter_by.splice(i, 1)
|
||||
this.params.filter_comparator.splice(i, 1)
|
||||
this.params.filter_value.splice(i, 1)
|
||||
break
|
||||
}
|
||||
}
|
||||
},
|
||||
setDoneFilter() {
|
||||
if (this.filters.done) {
|
||||
for (const i in this.params.filter_by) {
|
||||
if (this.params.filter_by[i] === 'done') {
|
||||
this.params.filter_by.splice(i, 1)
|
||||
this.params.filter_comparator.splice(i, 1)
|
||||
this.params.filter_value.splice(i, 1)
|
||||
break
|
||||
}
|
||||
}
|
||||
} else {
|
||||
this.params.filter_by.push('done')
|
||||
this.params.filter_comparator.push('equals')
|
||||
this.params.filter_value.push('false')
|
||||
}
|
||||
this.change()
|
||||
},
|
||||
setDueDateFilter() {
|
||||
setDateFilter(filterName, variableName) {
|
||||
// Only filter if we have a start and end due date
|
||||
if (this.filters.dueDate !== '') {
|
||||
if (this.filters[variableName] !== '') {
|
||||
|
||||
const parts = this.filters.dueDate.split(' to ')
|
||||
const parts = this.filters[variableName].split(' to ')
|
||||
|
||||
if (parts.length < 2) {
|
||||
return
|
||||
@ -124,29 +192,173 @@ export default {
|
||||
let foundStart = false
|
||||
let foundEnd = false
|
||||
this.params.filter_by.forEach((f, i) => {
|
||||
if (f === 'due_date' && this.params.filter_comparator[i] === 'greater_equals') {
|
||||
if (f === filterName && this.params.filter_comparator[i] === 'greater_equals') {
|
||||
foundStart = true
|
||||
this.params.filter_value[i] = +new Date(parts[0]) / 1000
|
||||
this.$set(this.params.filter_value, i, formatISO(new Date(parts[0])))
|
||||
}
|
||||
if (f === 'due_date' && this.params.filter_comparator[i] === 'less_equals') {
|
||||
if (f === filterName && this.params.filter_comparator[i] === 'less_equals') {
|
||||
foundEnd = true
|
||||
this.params.filter_value[i] = +new Date(parts[1]) / 1000
|
||||
this.$set(this.params.filter_value, i, formatISO(new Date(parts[1])))
|
||||
}
|
||||
})
|
||||
|
||||
if (!foundStart) {
|
||||
this.params.filter_by.push('due_date')
|
||||
this.params.filter_by.push(filterName)
|
||||
this.params.filter_comparator.push('greater_equals')
|
||||
this.params.filter_value.push(+new Date(parts[0]) / 1000)
|
||||
this.params.filter_value.push(formatISO(new Date(parts[0])))
|
||||
}
|
||||
if (!foundEnd) {
|
||||
this.params.filter_by.push('due_date')
|
||||
this.params.filter_by.push(filterName)
|
||||
this.params.filter_comparator.push('less_equals')
|
||||
this.params.filter_value.push(+new Date(parts[1]) / 1000)
|
||||
this.params.filter_value.push(formatISO(new Date(parts[1])))
|
||||
}
|
||||
this.change()
|
||||
}
|
||||
},
|
||||
prepareDate(filterName, variableName) {
|
||||
if (typeof this.params.filter_by === 'undefined') {
|
||||
return
|
||||
}
|
||||
|
||||
let foundDateStart = false
|
||||
let foundDateEnd = false
|
||||
for (const i in this.params.filter_by) {
|
||||
if (this.params.filter_by[i] === filterName && this.params.filter_comparator[i] === 'greater_equals') {
|
||||
foundDateStart = i
|
||||
}
|
||||
if (this.params.filter_by[i] === filterName && this.params.filter_comparator[i] === 'less_equals') {
|
||||
foundDateEnd = i
|
||||
}
|
||||
|
||||
if (foundDateStart !== false && foundDateEnd !== false) {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if (foundDateStart !== false && foundDateEnd !== false) {
|
||||
const start = new Date(this.params.filter_value[foundDateStart])
|
||||
const end = new Date(this.params.filter_value[foundDateEnd])
|
||||
this.filters[variableName] = `${start.getFullYear()}-${start.getMonth() + 1}-${start.getDate()} to ${end.getFullYear()}-${end.getMonth() + 1}-${end.getDate()}`
|
||||
}
|
||||
},
|
||||
setSingleValueFilter(filterName, variableName, useVariableName) {
|
||||
if (!this.filters[useVariableName]) {
|
||||
this.removePropertyFromFilter(filterName)
|
||||
return
|
||||
}
|
||||
|
||||
let found = false
|
||||
this.params.filter_by.forEach((f, i) => {
|
||||
if (f === filterName) {
|
||||
found = true
|
||||
this.$set(this.params.filter_value, i, this.filters[variableName])
|
||||
}
|
||||
})
|
||||
|
||||
if (!found) {
|
||||
this.params.filter_by.push(filterName)
|
||||
this.params.filter_comparator.push('equals')
|
||||
this.params.filter_value.push(this.filters[variableName])
|
||||
}
|
||||
|
||||
this.change()
|
||||
},
|
||||
prepareSingleValue(filterName, variableName, useVariableName, isNumber = false) {
|
||||
let found = false
|
||||
for (const i in this.params.filter_by) {
|
||||
if (this.params.filter_by[i] === filterName) {
|
||||
found = i
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if (found === false) {
|
||||
this.filters[useVariableName] = false
|
||||
return
|
||||
}
|
||||
|
||||
if (isNumber) {
|
||||
this.filters[variableName] = Number(this.params.filter_value[found])
|
||||
} else {
|
||||
this.filters[variableName] = this.params.filter_value[found]
|
||||
}
|
||||
|
||||
this.filters[useVariableName] = true
|
||||
},
|
||||
prepareDone() {
|
||||
// Set filters.done based on params
|
||||
if (typeof this.params.filter_by === 'undefined') {
|
||||
return
|
||||
}
|
||||
|
||||
let foundDone = false
|
||||
this.params.filter_by.forEach((f, i) => {
|
||||
if (f === 'done') {
|
||||
foundDone = i
|
||||
}
|
||||
})
|
||||
if (foundDone === false) {
|
||||
this.$set(this.filters, 'done', true)
|
||||
}
|
||||
},
|
||||
setDoneFilter() {
|
||||
if (this.filters.done) {
|
||||
this.removePropertyFromFilter('done')
|
||||
} else {
|
||||
this.params.filter_by.push('done')
|
||||
this.params.filter_comparator.push('equals')
|
||||
this.params.filter_value.push('false')
|
||||
}
|
||||
this.change()
|
||||
},
|
||||
setFilterConcat() {
|
||||
if (this.filters.requireAllFilters) {
|
||||
this.params.filter_concat = 'and'
|
||||
} else {
|
||||
this.params.filter_concat = 'or'
|
||||
}
|
||||
},
|
||||
setDueDateFilter() {
|
||||
this.setDateFilter('due_date', 'dueDate')
|
||||
},
|
||||
setPriority() {
|
||||
this.setSingleValueFilter('priority', 'priority', 'usePriority')
|
||||
},
|
||||
setStartDateFilter() {
|
||||
this.setDateFilter('start_date', 'startDate')
|
||||
},
|
||||
setEndDateFilter() {
|
||||
this.setDateFilter('end_date', 'endDate')
|
||||
},
|
||||
setPercentDoneFilter() {
|
||||
this.setSingleValueFilter('percent_done', 'percentDone', 'usePercentDone')
|
||||
},
|
||||
prepareDueDate() {
|
||||
this.prepareDate('due_date', 'dueDate')
|
||||
},
|
||||
preparePriority() {
|
||||
this.prepareSingleValue('priority', 'priority', 'usePriority', true)
|
||||
},
|
||||
prepareStartDate() {
|
||||
this.prepareDate('start_date', 'startDate')
|
||||
},
|
||||
prepareEndDate() {
|
||||
this.prepareDate('end_date', 'endDate')
|
||||
},
|
||||
preparePercentDone() {
|
||||
this.prepareSingleValue('percent_done', 'percentDone', 'usePercentDone', true)
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.single-value-control {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.fancycheckbox {
|
||||
margin-left: .5rem;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
Reference in New Issue
Block a user