Skip to content

Commit

Permalink
fix(views): edit views with filters
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
kolaente committed Jun 3, 2024
1 parent 244ca26 commit 68d2336
Show file tree
Hide file tree
Showing 3 changed files with 85 additions and 66 deletions.
10 changes: 5 additions & 5 deletions frontend/src/components/project/partials/FilterInput.vue
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -60,9 +65,6 @@ watch(
},
)
const userService = new UserService()
const projectUserService = new ProjectUserService()
function escapeHtml(unsafe: string): string {
return unsafe
.replace(/&/g, '&amp;')
Expand Down Expand Up @@ -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
Expand Down
121 changes: 75 additions & 46 deletions frontend/src/components/project/views/viewEditForm.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,77 +2,86 @@
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 => {
const transform = filterString => transformFilterStringFromApi(
filterString,
labelId => labelStore.getLabelById(labelId)?.title,
projectId => projectStore.projects[projectId]?.title || null,
)
const transformed = {
...newValue,
filter: transform(newValue.filter),
bucketConfiguration: newValue.bucketConfiguration.map(bc => ({
title: bc.title,
filter: transform(bc.filter),
})),
}
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,
labelTitle => labelStore.filterLabelsByQuery([], labelTitle)[0]?.id || null,
projectTitle => {
const found = projectStore.findProjectByExactname(projectTitle)
return found?.id || null
},
),
})
},
{deep: true},
)
onBeforeMount(() => {
const transform = filterString => transformFilterStringFromApi(
filterString,
labelId => labelStore.getLabelById(labelId)?.title,
projectId => projectStore.projects[projectId]?.title || null,
)
const transformed = {
...modelValue,
filter: transform(modelValue.filter),
bucketConfiguration: modelValue.bucketConfiguration.map(bc => ({
title: bc.title,
filter: transform(bc.filter),
})),
}
if (JSON.stringify(view.value) !== JSON.stringify(transformed)) {
view.value = transformed
}
})
function save() {
const transformFilter = filterQuery => transformFilterStringForApi(
filterQuery,
labelTitle => labelStore.filterLabelsByQuery([], labelTitle)[0]?.id || null,
projectTitle => {
const found = projectStore.findProjectByExactname(projectTitle)
return found?.id || null
},
)
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"
Expand Down Expand Up @@ -130,6 +139,7 @@ function validateTitle() {

<FilterInput
v-model="view.filter"
:project-id="view.projectId"
:input-label="$t('project.views.filter')"
/>

Expand Down Expand Up @@ -199,6 +209,7 @@ function validateTitle() {

<FilterInput
v-model="view.bucketConfiguration[index].filter"
:project-id="view.projectId"
:input-label="$t('project.views.filter')"
/>
</div>
Expand All @@ -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>

Expand Down
20 changes: 5 additions & 15 deletions frontend/src/views/project/settings/views.vue
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ async function saveView() {
>
<XButton
:loading="projectViewService.loading"
:disabled="showCreateForm && newView.title === ''"
@click="createView"
>
{{ $t('project.views.create') }}
Expand Down Expand Up @@ -144,22 +145,11 @@ async function saveView() {
<ViewEditForm
v-model="viewToEdit"
class="mb-4"
:loading="projectViewService.loading"
:show-save-buttons="true"
@cancel="viewToEdit = null"
@update:modelValue="saveView"
/>
<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>
</td>
</template>
<template v-else>
Expand Down

0 comments on commit 68d2336

Please sign in to comment.