diff --git a/src/app/features/tasks/task-context-menu/task-context-menu-inner/task-context-menu-inner.component.spec.ts b/src/app/features/tasks/task-context-menu/task-context-menu-inner/task-context-menu-inner.component.spec.ts index bfb4d1c52f..a4e4bf5f66 100644 --- a/src/app/features/tasks/task-context-menu/task-context-menu-inner/task-context-menu-inner.component.spec.ts +++ b/src/app/features/tasks/task-context-menu/task-context-menu-inner/task-context-menu-inner.component.spec.ts @@ -18,6 +18,8 @@ import { DateAdapter } from '@angular/material/core'; import { of } from 'rxjs'; import { selectTaskByIdWithSubTaskData } from '../../store/task.selectors'; import { addSubTask } from '../../store/task.actions'; +import { TaskSharedActions } from '../../../../root-store/meta/task-shared.actions'; +import { DateService } from '../../../../core/date/date.service'; import { NoopAnimationsModule } from '@angular/platform-browser/animations'; import { AddSubtaskInputService } from '../../add-subtask-input/add-subtask-input.service'; import { Project } from '../../../project/project.model'; @@ -89,6 +91,8 @@ describe('TaskContextMenuInnerComponent', () => { projectInTreeOrder('project-a', 'Project A'), ]), getByIdOnce$: () => of({}), + moveTaskToTodayList: () => {}, + moveTaskToBacklog: () => {}, }, }, { @@ -339,4 +343,51 @@ describe('TaskContextMenuInnerComponent', () => { expect(addSubtaskInputService.requestOpen).toHaveBeenCalledWith('PARENT_ID'); }); }); + + // Moving a task between the backlog and the regular list is a list-position + // change only; it must not touch the task's schedule (issue #8592). + describe('moveToToday() / moveToBacklog() schedule preservation (#8592)', () => { + let projectService: ProjectService; + + beforeEach(() => { + projectService = TestBed.inject(ProjectService); + }); + + it('moveToToday() moves to the regular list without scheduling for today', () => { + const moveSpy = spyOn(projectService, 'moveTaskToTodayList'); + const dispatchSpy = spyOn(store, 'dispatch'); + component.task = { + ...DEFAULT_TASK, + id: 'task-1', + projectId: 'project-current', + } as Task; + + component.moveToToday(); + + expect(moveSpy).toHaveBeenCalledWith('task-1', 'project-current'); + const dispatchedTypes = dispatchSpy.calls + .allArgs() + .map((args) => (args[0] as unknown as { type: string }).type); + expect(dispatchedTypes).not.toContain(TaskSharedActions.planTasksForToday.type); + }); + + it('moveToBacklog() moves to the backlog without clearing a schedule set for today', () => { + const moveSpy = spyOn(projectService, 'moveTaskToBacklog'); + const dispatchSpy = spyOn(store, 'dispatch'); + component.task = { + ...DEFAULT_TASK, + id: 'task-1', + projectId: 'project-current', + dueDay: TestBed.inject(DateService).todayStr(), + } as Task; + + component.moveToBacklog(); + + expect(moveSpy).toHaveBeenCalledWith('task-1', 'project-current'); + const dispatchedTypes = dispatchSpy.calls + .allArgs() + .map((args) => (args[0] as unknown as { type: string }).type); + expect(dispatchedTypes).not.toContain(TaskSharedActions.unscheduleTask.type); + }); + }); }); diff --git a/src/app/features/tasks/task-context-menu/task-context-menu-inner/task-context-menu-inner.component.ts b/src/app/features/tasks/task-context-menu/task-context-menu-inner/task-context-menu-inner.component.ts index 6fd5b32fe8..ba0a8f1d5a 100644 --- a/src/app/features/tasks/task-context-menu/task-context-menu-inner/task-context-menu-inner.component.ts +++ b/src/app/features/tasks/task-context-menu/task-context-menu-inner/task-context-menu-inner.component.ts @@ -674,20 +674,17 @@ export class TaskContextMenuInnerComponent implements AfterViewInit, OnDestroy { moveToBacklog(): void { if (this.task.projectId && !this.task.parentId) { + // Moving to the backlog is a list-position change only; it must not + // alter the task's schedule (#8592). this._projectService.moveTaskToBacklog(this.task.id, this.task.projectId); - if ( - this.task.dueDay === this._dateService.todayStr() || - (this.task.dueWithTime && this._dateService.isToday(this.task.dueWithTime)) - ) { - this.unschedule(); - } } } moveToToday(): void { if (this.task.projectId && !this.task.parentId) { + // Moving to the regular list is a list-position change only; it must not + // schedule the task for today (#8592). this._projectService.moveTaskToTodayList(this.task.id, this.task.projectId); - this.addToMyDay(); } } diff --git a/src/app/features/tasks/task/task.component.ts b/src/app/features/tasks/task/task.component.ts index 24af8dcc1d..2649010b3d 100644 --- a/src/app/features/tasks/task/task.component.ts +++ b/src/app/features/tasks/task/task.component.ts @@ -230,9 +230,6 @@ export class TaskComponent implements OnDestroy, AfterViewInit { return 'chat'; }); - isTaskOnTodayList = computed(() => - this._taskService.todayListSet().has(this.task().id), - ); isTodayListActive = computed(() => this.workContextService.isTodayList); taskIdWithPrefix = computed(() => 't-' + this.task().id); isRepeatTaskCreatedToday = computed( @@ -1335,18 +1332,18 @@ export class TaskComponent implements OnDestroy, AfterViewInit { moveToBacklog(): void { const t = this.task(); if (t.projectId && !t.parentId) { + // Moving to the backlog is a list-position change only; it must not + // alter the task's schedule (#8592). this._projectService.moveTaskToBacklog(t.id, t.projectId); - if (this.isTaskOnTodayList()) { - this.unschedule(); - } } } moveToToday(): void { const t = this.task(); if (t.projectId) { + // Moving to the regular list is a list-position change only; it must not + // schedule the task for today (#8592). this._projectService.moveTaskToTodayList(t.id, t.projectId); - this.addToMyDay(); } }