mirror of
https://github.com/johannesjo/super-productivity.git
synced 2026-07-17 16:37:43 +00:00
refactor(tasks): extract shared task ordering helpers (#8926)
* refactor(tasks): extract shared task ordering helpers Extract getReorderedSubTaskIds (membership check + move shared by moveSubTaskUp/Down/ToTop/ToBottom) and moveValidIdsToFront (shared by removeTasksFromTodayTag and localRemoveOverdueFromToday) into pure, tested utils. No behavior change. Closes #7912 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * refactor(tasks): drop getReorderedSubTaskIds, inline check in reorderSubTask Review feedback (#8926): the moveSubTask* actions already funnel through the single reorderSubTask helper, so the extraction added no dedup value. Keep moveValidIdsToFront, which removes real duplication. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
962c5bbeb1
commit
f9d65debe9
3 changed files with 77 additions and 9 deletions
|
|
@ -52,6 +52,7 @@ import {
|
|||
} from '../../time-tracking/store/time-tracking.actions';
|
||||
import { TaskLog } from '../../../core/log';
|
||||
import { devError } from '../../../util/dev-error';
|
||||
import { moveValidIdsToFront } from '../util/move-valid-ids-to-front';
|
||||
|
||||
export { taskAdapter };
|
||||
|
||||
|
|
@ -141,6 +142,7 @@ const reorderSubTask = (
|
|||
TaskLog.err(`Parent task ${parentId} not found`);
|
||||
return state;
|
||||
}
|
||||
|
||||
const parentSubTaskIds = parentTask.subTaskIds;
|
||||
|
||||
// Check if the subtask is actually in the parent's subtask list
|
||||
|
|
@ -699,25 +701,31 @@ export const taskReducer = createReducer<TaskState>(
|
|||
}),
|
||||
|
||||
on(TaskSharedActions.removeTasksFromTodayTag, (state, { taskIds }) => {
|
||||
const validTaskIds = taskIds.filter((id) => !!state.entities[id]);
|
||||
if (validTaskIds.length !== taskIds.length) {
|
||||
devError(
|
||||
`removeTasksFromTodayTag: ${taskIds.length - validTaskIds.length} orphan ID(s) filtered`,
|
||||
);
|
||||
// we do this to maintain the order of tasks when they are moved to overdue
|
||||
const { ids, invalidCount } = moveValidIdsToFront(
|
||||
state.ids as string[],
|
||||
taskIds,
|
||||
(id) => !!state.entities[id],
|
||||
);
|
||||
if (invalidCount > 0) {
|
||||
devError(`removeTasksFromTodayTag: ${invalidCount} orphan ID(s) filtered`);
|
||||
}
|
||||
return {
|
||||
...state,
|
||||
// we do this to maintain the order of tasks when they are moved to overdue
|
||||
ids: [...validTaskIds, ...state.ids.filter((id) => !taskIds.includes(id))],
|
||||
ids,
|
||||
};
|
||||
}),
|
||||
|
||||
// Same reordering for the non-persistent variant (#6992)
|
||||
on(TaskSharedActions.localRemoveOverdueFromToday, (state, { taskIds }) => {
|
||||
const validTaskIds = taskIds.filter((id) => !!state.entities[id]);
|
||||
const { ids } = moveValidIdsToFront(
|
||||
state.ids as string[],
|
||||
taskIds,
|
||||
(id) => !!state.entities[id],
|
||||
);
|
||||
return {
|
||||
...state,
|
||||
ids: [...validTaskIds, ...state.ids.filter((id) => !taskIds.includes(id))],
|
||||
ids,
|
||||
};
|
||||
}),
|
||||
);
|
||||
|
|
|
|||
37
src/app/features/tasks/util/move-valid-ids-to-front.spec.ts
Normal file
37
src/app/features/tasks/util/move-valid-ids-to-front.spec.ts
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
import { moveValidIdsToFront } from './move-valid-ids-to-front';
|
||||
|
||||
describe('moveValidIdsToFront', () => {
|
||||
it('moves all ids to the front when all are valid, preserving relative order', () => {
|
||||
const result = moveValidIdsToFront(
|
||||
['t1', 't2', 't3', 't4'],
|
||||
['t2', 't4'],
|
||||
() => true,
|
||||
);
|
||||
|
||||
expect(result.ids).toEqual(['t2', 't4', 't1', 't3']);
|
||||
expect(result.invalidCount).toBe(0);
|
||||
});
|
||||
|
||||
it('filters out invalid ids and only moves the valid ones', () => {
|
||||
const isValid = (id: string): boolean => id !== 'nonexistent';
|
||||
const result = moveValidIdsToFront(
|
||||
['t1', 't2', 't3', 't4'],
|
||||
['t2', 'nonexistent', 't4'],
|
||||
isValid,
|
||||
);
|
||||
|
||||
expect(result.ids).toEqual(['t2', 't4', 't1', 't3']);
|
||||
expect(result.invalidCount).toBe(1);
|
||||
});
|
||||
|
||||
it('reports every id invalid and leaves order unchanged when none are valid', () => {
|
||||
const result = moveValidIdsToFront(
|
||||
['t1', 't2'],
|
||||
['nonexistent1', 'nonexistent2'],
|
||||
() => false,
|
||||
);
|
||||
|
||||
expect(result.ids).toEqual(['t1', 't2']);
|
||||
expect(result.invalidCount).toBe(2);
|
||||
});
|
||||
});
|
||||
23
src/app/features/tasks/util/move-valid-ids-to-front.ts
Normal file
23
src/app/features/tasks/util/move-valid-ids-to-front.ts
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
/**
|
||||
* Moves the subset of `idsToMove` that pass `isValidId` to the front of
|
||||
* `allIds`, preserving their relative order, while leaving the remaining ids
|
||||
* in their original order. Shared by removeTasksFromTodayTag and
|
||||
* localRemoveOverdueFromToday in task.reducer.ts so tasks removed from Today
|
||||
* keep a stable position when they reappear (e.g. as overdue). See #6992.
|
||||
*/
|
||||
export interface MoveValidIdsToFrontResult {
|
||||
ids: string[];
|
||||
invalidCount: number;
|
||||
}
|
||||
|
||||
export const moveValidIdsToFront = (
|
||||
allIds: string[],
|
||||
idsToMove: string[],
|
||||
isValidId: (id: string) => boolean,
|
||||
): MoveValidIdsToFrontResult => {
|
||||
const validIds = idsToMove.filter(isValidId);
|
||||
return {
|
||||
ids: [...validIds, ...allIds.filter((id) => !idsToMove.includes(id))],
|
||||
invalidCount: idsToMove.length - validIds.length,
|
||||
};
|
||||
};
|
||||
Loading…
Add table
Add a link
Reference in a new issue