1
0

fix(views): edit views with filters

This change fixes a bug where filter values of views would be transformed in the wrong order, not transformed at all or at the wrong time. Transforming the filters now happens transparently in the background without anything funky happening visible to the user.
This commit is contained in:
kolaente 2024-06-03 22:20:57 +02:00
parent 244ca262df
commit 68d233684f
No known key found for this signature in database
GPG Key ID: F40E70337AB24C9B
3 changed files with 83 additions and 64 deletions

View File

@ -35,6 +35,11 @@ const {
const emit = defineEmits(['update:modelValue', 'blur'])
const userService = new UserService()
const projectUserService = new ProjectUserService()
const labelStore = useLabelStore()
const projectStore = useProjectStore()
const filterQuery = ref<string>('')
const {
textarea: filterInput,
@ -60,9 +65,6 @@ watch(
},
)
const userService = new UserService()
const projectUserService = new ProjectUserService()
function escapeHtml(unsafe: string): string {
return unsafe
.replace(/&/g, '&amp;')
@ -196,8 +198,6 @@ const autocompleteMatchText = ref('')
const autocompleteResultType = ref<'labels' | 'assignees' | 'projects' | null>(null)
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const autocompleteResults = ref<any[]>([])
const labelStore = useLabelStore()
const projectStore = useProjectStore()
function handleFieldInput() {
const cursorPosition = filterInput.value.selectionStart

View File

@ -2,28 +2,29 @@
import type {IProjectView} from '@/modelTypes/IProjectView'
import XButton from '@/components/input/button.vue'
import FilterInput from '@/components/project/partials/FilterInput.vue'
import {ref, watch} from 'vue'
import {ref, onBeforeMount} from 'vue'
import {transformFilterStringForApi, transformFilterStringFromApi} from '@/helpers/filters'
import {useLabelStore} from '@/stores/labels'
import {useProjectStore} from '@/stores/projects'
const {
modelValue,
loading = false,
showSaveButtons = false,
} = defineProps<{
modelValue: IProjectView,
loading?: bool,
showSaveButtons?: bool,
}>()
const emit = defineEmits(['update:modelValue'])
const emit = defineEmits(['update:modelValue', 'cancel'])
const view = ref<IProjectView>()
const labelStore = useLabelStore()
const projectStore = useProjectStore()
watch(
() => modelValue,
newValue => {
onBeforeMount(() => {
const transform = filterString => transformFilterStringFromApi(
filterString,
labelId => labelStore.getLabelById(labelId)?.title,
@ -31,9 +32,9 @@ watch(
)
const transformed = {
...newValue,
filter: transform(newValue.filter),
bucketConfiguration: newValue.bucketConfiguration.map(bc => ({
...modelValue,
filter: transform(modelValue.filter),
bucketConfiguration: modelValue.bucketConfiguration.map(bc => ({
title: bc.title,
filter: transform(bc.filter),
})),
@ -42,37 +43,45 @@ watch(
if (JSON.stringify(view.value) !== JSON.stringify(transformed)) {
view.value = transformed
}
},
{immediate: true, deep: true},
)
})
watch(
() => view.value,
newView => {
emit('update:modelValue', {
...newView,
filter: transformFilterStringForApi(
newView.filter,
function save() {
const transformFilter = filterQuery => transformFilterStringForApi(
filterQuery,
labelTitle => labelStore.filterLabelsByQuery([], labelTitle)[0]?.id || null,
projectTitle => {
const found = projectStore.findProjectByExactname(projectTitle)
return found?.id || null
},
),
})
},
{deep: true},
)
emit('update:modelValue', {
...view.value,
filter: transformFilter(view.value?.filter),
bucketConfiguration: view.value?.bucketConfiguration.map(bc => ({
title: bc.title,
filter: transformFilter(bc.filter),
})),
})
}
const titleValid = ref(true)
function validateTitle() {
titleValid.value = view.value?.title !== ''
}
function handleBubbleSave() {
if (showSaveButtons) {
return
}
save()
}
</script>
<template>
<form>
<form @focusout="handleBubbleSave">
<div class="field">
<label
class="label"
@ -130,6 +139,7 @@ function validateTitle() {
<FilterInput
v-model="view.filter"
:project-id="view.projectId"
:input-label="$t('project.views.filter')"
/>
@ -199,6 +209,7 @@ function validateTitle() {
<FilterInput
v-model="view.bucketConfiguration[index].filter"
:project-id="view.projectId"
:input-label="$t('project.views.filter')"
/>
</div>
@ -214,6 +225,24 @@ function validateTitle() {
</div>
</div>
</div>
<div
v-if="showSaveButtons"
class="is-flex is-justify-content-end"
>
<XButton
variant="tertiary"
class="mr-2"
@click="emit('cancel')"
>
{{ $t('misc.cancel') }}
</XButton>
<XButton
:loading="loading"
@click="save"
>
{{ $t('misc.save') }}
</XButton>
</div>
</form>
</template>

View File

@ -111,6 +111,7 @@ async function saveView() {
>
<XButton
:loading="projectViewService.loading"
:disabled="showCreateForm && newView.title === ''"
@click="createView"
>
{{ $t('project.views.create') }}
@ -144,22 +145,11 @@ async function saveView() {
<ViewEditForm
v-model="viewToEdit"
class="mb-4"
/>
<div class="is-flex is-justify-content-end">
<XButton
variant="tertiary"
class="mr-2"
@click="viewToEdit = null"
>
{{ $t('misc.cancel') }}
</XButton>
<XButton
:loading="projectViewService.loading"
@click="saveView"
>
{{ $t('misc.save') }}
</XButton>
</div>
:show-save-buttons="true"
@cancel="viewToEdit = null"
@update:modelValue="saveView"
/>
</td>
</template>
<template v-else>