fix: guard saved filter requests (#1462)

This commit is contained in:
kolaente
2025-09-11 09:36:47 +02:00
committed by GitHub
parent 6914badeb7
commit 4353b1e9c7
2 changed files with 28 additions and 47 deletions

View File

@@ -276,7 +276,7 @@
</template>
<script setup lang="ts">
import {computed, nextTick, ref, watch} from 'vue'
import {computed, nextTick, ref, watch, toRef} from 'vue'
import {useI18n} from 'vue-i18n'
import draggable from 'zhyswan-vuedraggable'
import {klona} from 'klona/lite'
@@ -323,6 +323,8 @@ const props = defineProps<{
viewId: IProjectView['id'],
}>()
const projectId = toRef(props, 'projectId')
const DRAG_OPTIONS = {
// sortable options
animation: 150,
@@ -344,7 +346,7 @@ const taskPositionService = ref(new TaskPositionService())
const taskBucketService = ref(new TaskBucketService())
// Saved filter composable for accessing filter data
const {filter: savedFilter} = useSavedFilter(() => props.projectId)
const savedFilter = useSavedFilter(() => projectId.value < 0 ? projectId.value : undefined).filter
const taskContainerRefs = ref<{ [id: IBucket['id']]: HTMLElement }>({})
const bucketLimitInputRef = ref<HTMLInputElement | null>(null)
@@ -401,10 +403,10 @@ const bucketDraggableComponentData = computed(() => ({
{'dragging-disabled': !canWrite.value},
],
}))
const project = computed(() => props.projectId ? projectStore.projects[props.projectId] : null)
const project = computed(() => projectId.value ? projectStore.projects[projectId.value] : null)
const view = computed(() => project.value?.views.find(v => v.id === props.viewId) as IProjectView || null)
const canWrite = computed(() => baseStore.currentProject?.maxPermission > Permissions.READ && view.value.bucketConfigurationMode === 'manual')
const canCreateTasks = computed(() => canWrite.value && props.projectId > 0)
const canCreateTasks = computed(() => canWrite.value && projectId.value > 0)
const buckets = computed(() => kanbanStore.buckets)
const loading = computed(() => kanbanStore.isLoading)
@@ -413,7 +415,7 @@ const taskLoading = computed(() => taskStore.isLoading || taskPositionService.va
watch(
() => ({
params: params.value,
projectId: props.projectId,
projectId: projectId.value,
viewId: props.viewId,
}),
({params, projectId, viewId}) => {
@@ -445,7 +447,7 @@ function handleTaskContainerScroll(id: IBucket['id'], el: HTMLElement) {
}
kanbanStore.loadNextTasksForBucket(
props.projectId,
projectId.value,
props.viewId,
params.value,
id,
@@ -657,7 +659,7 @@ async function saveBucketTitle(bucketId: IBucket['id'], bucketTitle: string) {
await kanbanStore.updateBucket({
id: bucketId,
title: bucketTitle,
projectId: props.projectId,
projectId: projectId.value,
})
success({message: i18n.global.t('project.kanban.bucketTitleSavedSuccess')})
bucketTitleEditable.value = false
@@ -674,13 +676,13 @@ function handleRecurringTaskCompletion() {
return
}
const filterContainsDateFields = savedFilter.value.filters?.filter?.includes('due_date') ||
savedFilter.value.filters?.filter?.includes('start_date') ||
savedFilter.value.filters?.filter?.includes('end_date')
const filterContainsDateFields = savedFilter.value?.filters?.filter?.includes('due_date') ||
savedFilter.value?.filters?.filter?.includes('start_date') ||
savedFilter.value?.filters?.filter?.includes('end_date')
if (filterContainsDateFields) {
// Reload the kanban board to refresh tasks that now match/don't match the filter
kanbanStore.loadBucketsForProject(props.projectId, props.viewId, params.value)
kanbanStore.loadBucketsForProject(projectId.value, props.viewId, params.value)
}
}
@@ -695,7 +697,7 @@ function updateBucketPosition(e: { newIndex: number }) {
kanbanStore.updateBucket({
id: bucket.id,
projectId: props.projectId,
projectId: projectId.value,
position: calculateItemPosition(
bucketBefore !== null ? bucketBefore.position : null,
bucketAfter !== null ? bucketAfter.position : null,
@@ -710,7 +712,7 @@ async function saveBucketLimit(bucketId: IBucket['id'], limit: number) {
await kanbanStore.updateBucket({
...kanbanStore.getBucketById(bucketId),
projectId: props.projectId,
projectId: projectId.value,
limit,
})
success({message: t('project.kanban.bucketLimitSavedSuccess')})

View File

@@ -96,7 +96,7 @@
<script setup lang="ts">
import {ref, computed, nextTick, onMounted, onBeforeUnmount, watch} from 'vue'
import {ref, computed, nextTick, onMounted, onBeforeUnmount, watch, toRef} from 'vue'
import draggable from 'zhyswan-vuedraggable'
import ProjectWrapper from '@/components/project/ProjectWrapper.vue'
@@ -113,7 +113,6 @@ import {PERMISSIONS as Permissions} from '@/constants/permissions'
import {calculateItemPosition} from '@/helpers/calculateItemPosition'
import type {ITask} from '@/modelTypes/ITask'
import {isSavedFilter, useSavedFilter} from '@/services/savedFilter'
import {TASK_REPEAT_MODES} from '@/types/IRepeatMode'
import {useBaseStore} from '@/stores/base'
@@ -123,11 +122,13 @@ import TaskPositionService from '@/services/taskPosition'
import TaskPositionModel from '@/models/taskPosition'
const props = defineProps<{
isLoadingProject: boolean,
projectId: IProject['id'],
viewId: IProjectView['id'],
isLoadingProject: boolean,
projectId: IProject['id'],
viewId: IProjectView['id'],
}>()
const projectId = toRef(props, 'projectId')
defineOptions({name: 'List'})
const ctaVisible = ref(false)
@@ -143,10 +144,10 @@ const {
params,
sortByParam,
} = useTaskList(
() => props.projectId,
() => projectId.value,
() => props.viewId,
{position: 'asc'},
() => props.projectId === -1
() => projectId.value === -1
? null
: 'subtasks',
)
@@ -154,14 +155,14 @@ const {
const taskPositionService = ref(new TaskPositionService())
// Saved filter composable for accessing filter data
const {filter: savedFilter} = useSavedFilter(() => props.projectId)
const _savedFilter = useSavedFilter(() => projectId.value < 0 ? projectId.value : undefined).filter
const tasks = ref<ITask[]>([])
watch(
allTasks,
() => {
tasks.value = [...allTasks.value]
if (props.projectId < 0) {
if (projectId.value < 0) {
return
}
tasks.value = tasks.value.filter(t => {
@@ -219,31 +220,9 @@ function updateTaskList(task: ITask) {
}
function updateTasks(updatedTask: ITask) {
if (props.projectId < 0) {
const originalTask = allTasks.value.find(t => t.id === updatedTask.id)
const isRecurringTask = originalTask && (originalTask.repeatAfter.amount > 0 || originalTask.repeatMode === TASK_REPEAT_MODES.REPEAT_MODE_MONTH)
const filterContainsDateFields = project.value && isSavedFilter(project.value) &&
project.value.title &&
(savedFilter.value.filters?.filter?.includes('due_date') ||
savedFilter.value.filters?.filter?.includes('start_date') ||
savedFilter.value.filters?.filter?.includes('end_date'))
if (isRecurringTask && filterContainsDateFields) {
// In the case of a filter, we'll reload the filter in the background to avoid tasks which do
// not match the filter show up here
loadTasks(false)
return
}
// For other updates in saved filters, just update the task in place
for (const t in allTasks.value) {
if (allTasks.value[t].id === updatedTask.id) {
allTasks.value[t] = updatedTask
break
}
}
if (projectId.value < 0) {
// Reload tasks to keep saved filter results in sync
loadTasks(false)
return
}