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
3 changed files with 64 additions and 62 deletions
Showing only changes of commit 932f1774ec - Show all commits

View File

@ -1,37 +1,46 @@
<template>
<div class="datepicker-with-range">
<div class="selections">
<button @click="setDateRange(datesToday)" :class="{'is-active': dateRange === datesToday}">
{{ $t('task.show.today') }}
</button>
<button @click="setDateRange(datesThisWeek)" :class="{'is-active': dateRange === datesThisWeek}">
{{ $t('task.show.thisWeek') }}
</button>
<button @click="setDateRange(datesNextWeek)" :class="{'is-active': dateRange === datesNextWeek}">
{{ $t('task.show.nextWeek') }}
</button>
<button @click="setDateRange(datesNext7Days)" :class="{'is-active': dateRange === datesNext7Days}">
{{ $t('task.show.next7Days') }}
</button>
<button @click="setDateRange(datesThisMonth)" :class="{'is-active': dateRange === datesThisMonth}">
{{ $t('task.show.thisMonth') }}
</button>
<button @click="setDateRange(datesNextMonth)" :class="{'is-active': dateRange === datesNextMonth}">
{{ $t('task.show.nextMonth') }}
</button>
<button @click="setDateRange(datesNext30Days)" :class="{'is-active': dateRange === datesNext30Days}">
{{ $t('task.show.next30Days') }}
</button>
<button @click="setDateRange('')" :class="{'is-active': customRangeActive}">
{{ $t('misc.custom') }}
</button>
</div>
<div class="flatpickr-container">
<flat-pickr
:config="flatPickerConfig"
v-model="dateRange"
/>
</div>
<a @click="showPopup = !showPopup">
{{ $t('task.show.select') }}
</a>
konrad marked this conversation as resolved Outdated

Provide buttonText as slot prop aswell

Provide `buttonText` as slot prop aswell

Done.

Done.
<div class="datepicker-with-range-container">
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.
<transition name="fade">
<div class="datepicker-with-range" v-if="showPopup">
<div class="selections">
<button @click="setDateRange(datesToday)" :class="{'is-active': dateRange === datesToday}">
{{ $t('task.show.today') }}
</button>
<button @click="setDateRange(datesThisWeek)" :class="{'is-active': dateRange === datesThisWeek}">
{{ $t('task.show.thisWeek') }}
konrad marked this conversation as resolved Outdated

Use BaseButton

Use BaseButton

Done.

Done.
</button>
<button @click="setDateRange(datesNextWeek)" :class="{'is-active': dateRange === datesNextWeek}">
{{ $t('task.show.nextWeek') }}
konrad marked this conversation as resolved Outdated

Use BaseButton

Use BaseButton

Done.

Done.
</button>
<button @click="setDateRange(datesNext7Days)" :class="{'is-active': dateRange === datesNext7Days}">
{{ $t('task.show.next7Days') }}
</button>
<button @click="setDateRange(datesThisMonth)" :class="{'is-active': dateRange === datesThisMonth}">
{{ $t('task.show.thisMonth') }}
</button>
<button @click="setDateRange(datesNextMonth)" :class="{'is-active': dateRange === datesNextMonth}">
{{ $t('task.show.nextMonth') }}
</button>
<button @click="setDateRange(datesNext30Days)"
:class="{'is-active': dateRange === datesNext30Days}">
{{ $t('task.show.next30Days') }}
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.
</button>
<button @click="setDateRange('')" :class="{'is-active': customRangeActive}">
{{ $t('misc.custom') }}
</button>
</div>
<div class="flatpickr-container">
<flat-pickr
:config="flatPickerConfig"
v-model="dateRange"
/>
</div>
</div>
</transition>
</div>
</template>
@ -61,6 +70,7 @@ const flatPickerConfig = computed(() => ({
},
}))
const showPopup = ref<Boolean>(false)
const dateRange = ref<string>('')
watch(
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.
@ -189,6 +199,11 @@ const customRangeActive = computed<Boolean>(() => {
</script>
<style lang="scss" scoped>
.datepicker-with-range-container {
position: relative;
z-index: 10;
}
.datepicker-with-range {
border-radius: $radius;
border: 1px solid var(--grey-200);
@ -196,6 +211,7 @@ const customRangeActive = computed<Boolean>(() => {
box-shadow: $shadow;
display: flex;
width: 500px;
position: absolute;
:deep(.flatpickr-calendar) {

I think this is a good usecase for a reactive.

I think this is a good usecase for a reactive.

What would be the advantage over a ref?

What would be the advantage over a ref?

Both values can be changed at the same time
=> watchers aren't triggered twice when you change stuff shortly after each other.

Both values can be changed at the same time => watchers aren't triggered twice when you change stuff shortly after each other.

How do I type it properly? If I only pass a string into a reactive it complains I should pass in an object instead.

Edit: using String (capital S) seems to work.

How do I type it properly? If I only pass a string into a reactive it complains I should pass in an object instead. Edit: using `String` (capital S) seems to work.

Okay even with the typing solved it still complains when trying to set it: Because we do const from = ... I won't be able to do from = fromDate. Any idea how to solve this?

Okay even with the typing solved it still complains when trying to set it: Because we do `const from = ...` I won't be able to do `from = fromDate`. Any idea how to solve this?
margin: 0 auto 8px;
@ -216,6 +232,7 @@ const customRangeActive = computed<Boolean>(() => {
width: 30%;
display: flex;
flex-direction: column;
padding-top: .5rem;
button {
display: block;

View File

@ -535,7 +535,7 @@
"noDates": "Show tasks without dates",
"overdue": "Show overdue tasks",
"fromuntil": "Tasks from {from} until {until}",
"select": "Select a range:",
"select": "Select a date range",
"today": "Today",
"thisWeek": "This Week",
"nextWeek": "Next Week",

View File

@ -1,26 +1,25 @@
<template>
<div class="is-max-width-desktop show-tasks">
<div class="is-max-width-desktop has-text-left ">
<h3 class="mb-2">
{{ pageTitle }}
</h3>
<p v-if="!showAll">
<fancycheckbox @change="setShowNulls">
<p v-if="!showAll" class="show-tasks-options">
<datepicker-with-range @dateChanged="setDate"/>
<fancycheckbox @change="setShowNulls" class="mr-2">
{{ $t('task.show.noDates') }}
</fancycheckbox>
<fancycheckbox @change="setShowOverdue">
{{ $t('task.show.overdue') }}
</fancycheckbox>
{{ $t('task.show.select') }}
<datepicker-with-range @dateChanged="setDate"/>
</p>
<template v-if="!loading && (!tasks || tasks.length === 0) && showNothingToDo">
<h3 class="nothing">{{ $t('task.show.noTasks') }}</h3>
<LlamaCool class="llama-cool"/>
<h3 class="has-text-centered mt-6">{{ $t('task.show.noTasks') }}</h3>
<LlamaCool class="mt-5"/>
</template>
<div :class="{ 'is-loading': loading}" class="spinner"></div>
<card :padding="false" class="has-overflow" :has-content="false" v-if="tasks && tasks.length > 0">
<div class="tasks">
<div class="p-2">
<single-task-in-list
v-for="t in tasksSorted"
:key="t.id"
@ -212,26 +211,12 @@ export default {
</script>
konrad marked this conversation as resolved Outdated

Instead of creating the params already in snake_case:
Wait until the last moment (ideally abstracted away from a apiClient) until you convert params from camelCase to snake_case, needed by the api. This way we use consequently use camelCase in most areas of the frontend – which is what you usually do in JS.

Instead of creating the params already in snake_case: Wait until the last moment (ideally abstracted away from a apiClient) until you convert params from camelCase to snake_case, needed by the api. This way we use consequently use camelCase in most areas of the frontend – which is what you usually do in JS.

I agree. However, this whole filter thing is a mess right now, not only here. I'd like to fix this everywhere at once at some point, simplifying the filter handling in the process as well.

That being said, I've changed there here for now.

I agree. However, this whole filter thing is a mess right now, not only here. I'd like to fix this everywhere at once at some point, simplifying the filter handling in the process as well. That being said, I've changed there here for now.
<style lang="scss" scoped>
h3 {
text-align: left;
&.nothing {
text-align: center;
margin-top: 3rem;
.show-tasks-options {
display: flex;
flex-direction: column;
> :deep(a) {
margin-right: .5rem;
}
:deep(.input) {
width: 190px;
vertical-align: middle;
margin: .5rem 0;
}
}
.tasks {
padding: .5rem;
}
.llama-cool {
margin-top: 2rem;
}
</style>