fix: reload list view when marking recurring task done (#1457)

This commit is contained in:
kolaente
2025-09-11 08:56:08 +02:00
committed by GitHub
parent a1e9578971
commit 6914badeb7
4 changed files with 65 additions and 7 deletions

View File

@@ -215,6 +215,7 @@
:task="task"
:loading="taskUpdating[task.id] ?? false"
:project-id="projectId"
@taskCompletedRecurring="handleRecurringTaskCompletion"
/>
</div>
</template>
@@ -303,7 +304,7 @@ import {
} from '@/helpers/saveCollapsedBucketState'
import {calculateItemPosition} from '@/helpers/calculateItemPosition'
import {isSavedFilter} from '@/services/savedFilter'
import {isSavedFilter, useSavedFilter} from '@/services/savedFilter'
import {success} from '@/message'
import {useProjectStore} from '@/stores/projects'
import type {TaskFilterParams} from '@/services/taskCollection'
@@ -342,6 +343,9 @@ const projectStore = useProjectStore()
const taskPositionService = ref(new TaskPositionService())
const taskBucketService = ref(new TaskBucketService())
// Saved filter composable for accessing filter data
const {filter: savedFilter} = useSavedFilter(() => props.projectId)
const taskContainerRefs = ref<{ [id: IBucket['id']]: HTMLElement }>({})
const bucketLimitInputRef = ref<HTMLInputElement | null>(null)
@@ -664,6 +668,22 @@ function updateBuckets(value: IBucket[]) {
kanbanStore.setBuckets(value)
}
function handleRecurringTaskCompletion() {
// Only reload if we're in a saved filter and the filter contains date fields
if (!isSavedFilter(project.value)) {
return
}
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)
}
}
// TODO: fix type
function updateBucketPosition(e: { newIndex: number }) {
// (2) bucket positon is changed

View File

@@ -112,7 +112,8 @@ import {useTaskList} from '@/composables/useTaskList'
import {PERMISSIONS as Permissions} from '@/constants/permissions'
import {calculateItemPosition} from '@/helpers/calculateItemPosition'
import type {ITask} from '@/modelTypes/ITask'
import {isSavedFilter} from '@/services/savedFilter'
import {isSavedFilter, useSavedFilter} from '@/services/savedFilter'
import {TASK_REPEAT_MODES} from '@/types/IRepeatMode'
import {useBaseStore} from '@/stores/base'
@@ -152,6 +153,9 @@ const {
const taskPositionService = ref(new TaskPositionService())
// Saved filter composable for accessing filter data
const {filter: savedFilter} = useSavedFilter(() => props.projectId)
const tasks = ref<ITask[]>([])
watch(
allTasks,
@@ -216,9 +220,30 @@ function updateTaskList(task: ITask) {
function updateTasks(updatedTask: ITask) {
if (props.projectId < 0) {
// 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)
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
}
}
return
}

View File

@@ -128,6 +128,7 @@ import AssigneeList from '@/components/tasks/partials/AssigneeList.vue'
import {playPopSound} from '@/helpers/playPop'
import {isEditorContentEmpty} from '@/helpers/editorContentEmpty'
import {useProjectStore} from '@/stores/projects'
import {TASK_REPEAT_MODES} from '@/types/IRepeatMode'
const props = withDefaults(defineProps<{
task: ITask,
@@ -137,6 +138,10 @@ const props = withDefaults(defineProps<{
loading: false,
})
const emit = defineEmits<{
'taskCompletedRecurring': [task: ITask]
}>()
const router = useRouter()
const loadingInternal = ref(false)
@@ -165,6 +170,9 @@ const isOverdue = computed(() => (
))
async function toggleTaskDone(task: ITask) {
const isRecurringTask = task.repeatAfter.amount > 0 || task.repeatMode === TASK_REPEAT_MODES.REPEAT_MODE_MONTH
const wasBeingMarkedDone = !task.done
loadingInternal.value = true
try {
const updatedTask = await useTaskStore().update({
@@ -175,6 +183,11 @@ async function toggleTaskDone(task: ITask) {
if (updatedTask.done) {
playPopSound()
}
// Emit event if this was a recurring task being marked as done
if (isRecurringTask && wasBeingMarkedDone && updatedTask.done) {
emit('taskCompletedRecurring', updatedTask)
}
} finally {
loadingInternal.value = false
}

View File

@@ -37,8 +37,8 @@ export function getSavedFilterIdFromProjectId(projectId: IProject['id']) {
return filterId
}
export function isSavedFilter(project: IProject) {
return getSavedFilterIdFromProjectId(project?.id) > 0
export function isSavedFilter(project: IProject | undefined | null) {
return getSavedFilterIdFromProjectId(project?.id || 0) > 0
}
export default class SavedFilterService extends AbstractService<ISavedFilter> {