feat: add date math for filters #1342
|
@ -0,0 +1,134 @@
|
|||
<template>
|
||||
<div class="datepicker-with-range">
|
||||
<div class="selections">
|
||||
<a @click="setDatesToToday">Today</a>
|
||||
<a @click="setDatesToNextWeek">Next Week</a>
|
||||
konrad marked this conversation as resolved
Outdated
|
||||
<a @click="setDatesToNextMonth">Next Month</a>
|
||||
konrad marked this conversation as resolved
Outdated
dpschen
commented
The styles (=props) selected for the button are hightly specific and create an indirect dependency to its indented use case. The latter might change in the future and then we have to remember this dependency. This is why I think it makes sense to remove at least the specific use case of this button. Since we wouldn't use it then at all anymore (since you need to overwrite the default slot) it might make it simpler to only define the slot. The styles (=props) selected for the button are hightly specific and create an indirect dependency to its indented use case. The latter might change in the future and then we have to remember this dependency. This is why I think it makes sense to remove at least the specific use case of this button. Since we wouldn't use it then at all anymore (since you need to overwrite the default slot) it might make it simpler to only define the slot.
konrad
commented
Moved everything to a slot. Moved everything to a slot.
|
||||
<a>Custom</a>
|
||||
</div>
|
||||
<div class="flatpickr-container">
|
||||
<flat-pickr
|
||||
:config="flatPickerConfig"
|
||||
v-model="dateRange"
|
||||
/>
|
||||
{{ dateRange }}
|
||||
konrad marked this conversation as resolved
Outdated
dpschen
commented
Use BaseButton Use BaseButton
konrad
commented
Done. Done.
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
konrad marked this conversation as resolved
Outdated
dpschen
commented
Use BaseButton Use BaseButton
konrad
commented
Done. Done.
|
||||
|
||||
<script setup>
|
||||
import flatPickr from 'vue-flatpickr-component'
|
||||
import 'flatpickr/dist/flatpickr.css'
|
||||
import {computed, ref, watch} from 'vue'
|
||||
import {useI18n} from 'vue-i18n'
|
||||
import {store} from '@/store'
|
||||
import {format} from 'date-fns'
|
||||
|
||||
const {t} = useI18n()
|
||||
|
||||
const emit = defineEmits(['dateChanged'])
|
||||
|
||||
konrad marked this conversation as resolved
Outdated
dpschen
commented
Instead of calling Instead of calling `inputChanged` from here better watch the `from` and below the `to` value.
This prevents future mistakes
konrad
commented
Changed. I kept Changed. I kept `inputChanged` though because I need to watchers.
|
||||
const weekStart = computed(() => store.state.auth.settings.weekStart)
|
||||
const flatPickerConfig = computed(() => ({
|
||||
altFormat: t('date.altFormatLong'),
|
||||
altInput: true,
|
||||
dateFormat: 'Y-m-d H:i',
|
||||
enableTime: true,
|
||||
time_24hr: true,
|
||||
inline: true,
|
||||
mode: 'range',
|
||||
locale: {
|
||||
// FIXME: This seems to always contain the default value
|
||||
firstDayOfWeek: weekStart,
|
||||
},
|
||||
}))
|
||||
|
||||
const dateRange = ref('')
|
||||
|
||||
watch(
|
||||
() => dateRange.value,
|
||||
newVal => {
|
||||
const [fromDate, toDate] = newVal.split(' to ')
|
||||
|
||||
if (typeof fromDate === 'undefined' || typeof toDate === 'undefined') {
|
||||
return
|
||||
}
|
||||
konrad marked this conversation as resolved
dpschen
commented
Use BaseButton Use BaseButton
konrad
commented
Done. Done.
|
||||
|
||||
emit('dateChanged', {
|
||||
dateFrom: new Date(fromDate),
|
||||
dateTo: new Date(toDate),
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
function formatDate(date) {
|
||||
return format(date, 'yyyy-MM-dd HH:mm')
|
||||
konrad marked this conversation as resolved
Outdated
dpschen
commented
The whole explanation card should be its own component. The whole explanation card should be its own component.
konrad
commented
Done! Done!
|
||||
}
|
||||
|
||||
function setDatesToToday() {
|
||||
const startDate = new Date()
|
||||
const endDate = new Date((new Date()).setDate((new Date()).getDate() + 1))
|
||||
dateRange.value = `${formatDate(startDate)} to ${formatDate(endDate)}`
|
||||
}
|
||||
|
||||
function setDatesToNextWeek() {
|
||||
const startDate = new Date()
|
||||
const endDate = new Date((new Date()).getTime() + 7 * 24 * 60 * 60 * 1000)
|
||||
dpschen marked this conversation as resolved
Outdated
dpschen
commented
I think it's really cool, that we support this, but it would be cool, if we could break this down and explain it in our / simpler terms. I think it's really cool, that we support this, but it would be cool, if we could break this down and explain it in our / simpler terms.
konrad
commented
I think I'm already doing that but wanted to highlight for people who know the syntax from Elasticsearch or Grafana they can use it here as well. Was there anything in the explanation you noticed as not quite understandable? I think I'm already doing that but wanted to highlight for people who know the syntax from Elasticsearch or Grafana they can use it here as well.
Was there anything in the explanation you noticed as not quite understandable?
dpschen
commented
I didn't even check to be honest. I didn't even check to be honest.
Was just something I though of while reading this.
|
||||
dateRange.value = `${formatDate(startDate)} to ${formatDate(endDate)}`
|
||||
}
|
||||
|
||||
function setDatesToNextMonth() {
|
||||
const startDate = new Date()
|
||||
const endDate = new Date((new Date()).setMonth((new Date()).getMonth() + 1))
|
||||
dateRange.value = `${formatDate(startDate)} to ${formatDate(endDate)}`
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.datepicker-with-range {
|
||||
border-radius: $radius;
|
||||
border: 1px solid var(--grey-200);
|
||||
background-color: var(--white);
|
||||
box-shadow: $shadow;
|
||||
display: flex;
|
||||
width: 500px;
|
||||
|
||||
:deep(.flatpickr-calendar) {
|
||||
margin: 0 auto 8px;
|
||||
box-shadow: none;
|
||||
}
|
||||
}
|
||||
|
||||
.flatpickr-container {
|
||||
width: 70%;
|
||||
border-left: 1px solid var(--grey-200);
|
||||
|
||||
:deep(input.input) {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.selections {
|
||||
width: 30%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
a {
|
||||
display: block;
|
||||
width: 100%;
|
||||
text-align: left;
|
||||
konrad marked this conversation as resolved
Outdated
dpschen
commented
Why do we need to reset this every time? Why do we need to reset this every time?
konrad
commented
I don't think we have to. I've checked and it looks like this doesn't really break anything so I've removed it. Lets us get rid of I don't think we have to. I've checked and it looks like this doesn't really break anything so I've removed it. Lets us get rid of `inputChanged`.
|
||||
padding: .5rem 1rem;
|
||||
dpschen
commented
Called here! Called here!
|
||||
transition: $transition;
|
||||
font-size: .9rem;
|
||||
color: var(--text);
|
||||
|
||||
&.active {
|
||||
color: var(--primary);
|
||||
}
|
||||
|
||||
&:hover, &.active {
|
||||
background-color: var(--grey-100);
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -12,7 +12,7 @@
|
|||
{{ pageTitle }}
|
||||
</h3>
|
||||
<!-- FIXME: Styling, maybe in combination with the buttons? -->
|
||||
<p class="is-flex" v-if="!showAll">
|
||||
<p v-if="!showAll">
|
||||
{{ $t('task.show.select') }}
|
||||
<flat-pickr
|
||||
:class="{ 'disabled': loading}"
|
||||
|
@ -21,6 +21,7 @@
|
|||
@on-close="setDate"
|
||||
v-model="dateRange"
|
||||
/>
|
||||
<datepicker-with-range @dateChanged="setDate"/>
|
||||
</p>
|
||||
<div v-if="!showAll" class="mb-4 mt-2">
|
||||
<x-button type="secondary" @click="showTodaysTasks()" class="mr-2">
|
||||
|
@ -62,6 +63,7 @@ import Fancycheckbox from '@/components/input/fancycheckbox'
|
|||
import {LOADING, LOADING_MODULE} from '@/store/mutation-types'
|
||||
|
||||
import LlamaCool from '@/assets/llama-cool.svg?component'
|
||||
import DatepickerWithRange from '@/components/date/datepickerWithRange'
|
||||
|
||||
function formatDate(date) {
|
||||
return `${date.getFullYear()}-${date.getMonth() + 1}-${date.getDate()} ${date.getHours()}:${date.getMinutes()}`
|
||||
|
@ -70,6 +72,7 @@ function formatDate(date) {
|
|||
export default {
|
||||
name: 'ShowTasks',
|
||||
components: {
|
||||
DatepickerWithRange,
|
||||
konrad marked this conversation as resolved
Outdated
dpschen
commented
Wouldn't it be better to make showAll a computed that gets autoset when dateFrom and dateTo doesn't contain a value? Wouldn't it be better to make showAll a computed that gets autoset when dateFrom and dateTo doesn't contain a value?
konrad
commented
Excellent idea. Changed it! Excellent idea. Changed it!
|
||||
Fancycheckbox,
|
||||
SingleTaskInList,
|
||||
flatPickr,
|
||||
|
@ -81,6 +84,7 @@ export default {
|
|||
showNulls: true,
|
||||
showOverdue: false,
|
||||
|
||||
// TODO: Set the date range based on the default (to make sure it shows up in the picker) -> maybe also use a computed which depends on dateFrom and dateTo?
|
||||
konrad marked this conversation as resolved
Outdated
dpschen
commented
get value from props to remove dependency on route. Removing dependency from router makes the components easier reusable nested inside another view (which is what we do). get value from props to remove dependency on route. Removing dependency from router makes the components easier reusable nested inside another view (which is what we do).
|
||||
dateRange: null,
|
||||
|
||||
showNothingToDo: false,
|
||||
|
@ -150,18 +154,12 @@ export default {
|
|||
}),
|
||||
},
|
||||
methods: {
|
||||
setDate() {
|
||||
if (this.dateRange === null) {
|
||||
return
|
||||
}
|
||||
|
||||
const [fromDate, toDate] = this.dateRange.split(' to ')
|
||||
|
||||
setDate({dateFrom, dateTo}) {
|
||||
this.$router.push({
|
||||
name: this.$route.name,
|
||||
query: {
|
||||
from: +new Date(fromDate),
|
||||
to: +new Date(toDate),
|
||||
from: +new Date(dateFrom),
|
||||
to: +new Date(dateTo),
|
||||
showOverdue: this.showOverdue,
|
||||
showNulls: this.showNulls,
|
||||
},
|
||||
|
|
Provide
buttonText
as slot prop aswellDone.