feat: add date math for filters #1342

Merged
konrad merged 88 commits from feature/date-math into main 2022-03-28 17:30:43 +00:00
2 changed files with 142 additions and 10 deletions
Showing only changes of commit 8115563d67 - Show all commits

View File

@ -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

Provide buttonText as slot prop aswell

Provide `buttonText` as slot prop aswell

Done.

Done.
<a @click="setDatesToNextMonth">Next Month</a>
konrad marked this conversation as resolved Outdated

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.

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

Use BaseButton

Use BaseButton

Done.

Done.
</div>
</div>
</template>
konrad marked this conversation as resolved Outdated

Use BaseButton

Use BaseButton

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

Instead of calling inputChanged from here better watch the from and below the to value.
This prevents future mistakes

Instead of calling `inputChanged` from here better watch the `from` and below the `to` value. This prevents future mistakes

Changed. I kept inputChanged though because I need to watchers.

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
Review

Use BaseButton

Use BaseButton
Review

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

The whole explanation card should be its own component.

The whole explanation card should be its own component.

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

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.

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?

I didn't even check to be honest.
Was just something I though of while reading this.

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

Why do we need to reset this every time?

Why do we need to reset this every time?

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.

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;

Called here!

Called here!
transition: $transition;
font-size: .9rem;
color: var(--text);
&.active {
color: var(--primary);
}
&:hover, &.active {
background-color: var(--grey-100);
}
}
}
</style>

View File

@ -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

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?

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

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,
},