diff --git a/src/app/features/task-repeat-cfg/dialog-edit-task-repeat-cfg/task-repeat-cfg-form.const.ts b/src/app/features/task-repeat-cfg/dialog-edit-task-repeat-cfg/task-repeat-cfg-form.const.ts index 87c45ea64c..8454ce206e 100644 --- a/src/app/features/task-repeat-cfg/dialog-edit-task-repeat-cfg/task-repeat-cfg-form.const.ts +++ b/src/app/features/task-repeat-cfg/dialog-edit-task-repeat-cfg/task-repeat-cfg-form.const.ts @@ -249,15 +249,6 @@ export const TASK_REPEAT_CFG_FORM_CFG_BEFORE_TAGS: FormlyFieldConfig[] = [ updateOn: 'blur', }, }, - { - key: 'order', - type: 'input', - templateOptions: { - label: T.F.TASK_REPEAT.F.ORDER, - type: 'number', - description: T.F.TASK_REPEAT.F.ORDER_DESCRIPTION, - }, - }, ]; export const TASK_REPEAT_CFG_ADVANCED_FORM_CFG: FormlyFieldConfig[] = [ @@ -290,4 +281,13 @@ export const TASK_REPEAT_CFG_ADVANCED_FORM_CFG: FormlyFieldConfig[] = [ }, className: 'sp-formly-child-option', }, + { + key: 'skipOverdue', + type: 'checkbox', + defaultValue: false, + templateOptions: { + label: T.F.TASK_REPEAT.F.SKIP_OVERDUE, + description: T.F.TASK_REPEAT.F.SKIP_OVERDUE_DESCRIPTION, + }, + }, ]; diff --git a/src/app/features/task-repeat-cfg/store/task-repeat-cfg.effects.ts b/src/app/features/task-repeat-cfg/store/task-repeat-cfg.effects.ts index bd02e13961..f18a7c4ab8 100644 --- a/src/app/features/task-repeat-cfg/store/task-repeat-cfg.effects.ts +++ b/src/app/features/task-repeat-cfg/store/task-repeat-cfg.effects.ts @@ -54,7 +54,6 @@ const SCHEDULE_AFFECTING_FIELDS: (keyof TaskRepeatCfgCopy)[] = [ 'friday', 'saturday', 'sunday', - 'order', // controls top/bottom placement of created tasks, which affects rescheduling behavior 'isPaused', ]; diff --git a/src/app/features/task-repeat-cfg/task-repeat-cfg.model.ts b/src/app/features/task-repeat-cfg/task-repeat-cfg.model.ts index 830f3dff62..62ee45d1ea 100644 --- a/src/app/features/task-repeat-cfg/task-repeat-cfg.model.ts +++ b/src/app/features/task-repeat-cfg/task-repeat-cfg.model.ts @@ -29,6 +29,10 @@ export interface TaskRepeatCfgCopy { lastTaskCreationDay?: string; title: string | null; tagIds: string[]; + /** + * @deprecated No longer configurable via UI. Kept for backwards compatibility. + * order<=0 → task inserted at top; order>0 → task inserted at bottom. + */ order: number; defaultEstimate?: number; startTime?: string; @@ -65,6 +69,8 @@ export interface TaskRepeatCfgCopy { }[]; // Exception list for deleted instances (ISO date strings YYYY-MM-DD) deletedInstanceDates?: string[]; + // When true, missed/overdue instances are silently skipped instead of being created + skipOverdue?: boolean; } export type TaskRepeatCfg = Readonly; @@ -101,4 +107,5 @@ export const DEFAULT_TASK_REPEAT_CFG: Omit = { notes: undefined, shouldInheritSubtasks: false, disableAutoUpdateSubtasks: false, + skipOverdue: false, }; diff --git a/src/app/features/task-repeat-cfg/task-repeat-cfg.service.ts b/src/app/features/task-repeat-cfg/task-repeat-cfg.service.ts index 1a5f3e5dc9..61d0249dcd 100644 --- a/src/app/features/task-repeat-cfg/task-repeat-cfg.service.ts +++ b/src/app/features/task-repeat-cfg/task-repeat-cfg.service.ts @@ -228,6 +228,26 @@ export class TaskRepeatCfgService { if (taskRepeatCfg.deletedInstanceDates?.includes(targetDateStr)) { return []; } + // If skipOverdue is enabled, silently skip instances that are in the past (before today). + // We still dispatch updateTaskRepeatCfg to advance lastTaskCreationDay so that the same + // overdue date is not re-evaluated on every subsequent app open (which would stall progress + // permanently for non-daily or every-N-day schedules where today may not be a scheduled day). + if ( + taskRepeatCfg.skipOverdue && + targetDateStr < getDbDateStr(new Date(targetDayDate)) + ) { + return [ + updateTaskRepeatCfg({ + taskRepeatCfg: { + id: taskRepeatCfg.id, + changes: { + lastTaskCreation: targetCreated.getTime(), + lastTaskCreationDay: targetDateStr, + }, + }, + }), + ]; + } const { task, isAddToBottom } = this._getTaskRepeatTemplate( taskRepeatCfg, diff --git a/src/app/t.const.ts b/src/app/t.const.ts index 034fe7ca1a..1d55bfaa08 100644 --- a/src/app/t.const.ts +++ b/src/app/t.const.ts @@ -1682,8 +1682,6 @@ const T = { INHERIT_SUBTASKS_DESCRIPTION: 'F.TASK_REPEAT.F.INHERIT_SUBTASKS_DESCRIPTION', MONDAY: 'F.TASK_REPEAT.F.MONDAY', NOTES: 'F.TASK_REPEAT.F.NOTES', - ORDER: 'F.TASK_REPEAT.F.ORDER', - ORDER_DESCRIPTION: 'F.TASK_REPEAT.F.ORDER_DESCRIPTION', QUICK_SETTING: 'F.TASK_REPEAT.F.QUICK_SETTING', Q_CUSTOM: 'F.TASK_REPEAT.F.Q_CUSTOM', Q_DAILY: 'F.TASK_REPEAT.F.Q_DAILY', @@ -1699,6 +1697,8 @@ const T = { REPEAT_EVERY: 'F.TASK_REPEAT.F.REPEAT_EVERY', SATURDAY: 'F.TASK_REPEAT.F.SATURDAY', SCHEDULE_TYPE_LABEL: 'F.TASK_REPEAT.F.SCHEDULE_TYPE_LABEL', + SKIP_OVERDUE: 'F.TASK_REPEAT.F.SKIP_OVERDUE', + SKIP_OVERDUE_DESCRIPTION: 'F.TASK_REPEAT.F.SKIP_OVERDUE_DESCRIPTION', START_DATE: 'F.TASK_REPEAT.F.START_DATE', START_TIME: 'F.TASK_REPEAT.F.START_TIME', START_TIME_DESCRIPTION: 'F.TASK_REPEAT.F.START_TIME_DESCRIPTION', diff --git a/src/assets/i18n/en.json b/src/assets/i18n/en.json index 53b2d155f5..0555b9991c 100644 --- a/src/assets/i18n/en.json +++ b/src/assets/i18n/en.json @@ -1635,8 +1635,6 @@ "INHERIT_SUBTASKS_DESCRIPTION": "When enabled, subtasks from the most recent task instance will be recreated with the recurring task", "MONDAY": "Monday", "NOTES": "Default notes", - "ORDER": "Order", - "ORDER_DESCRIPTION": "Creation order of recurring tasks. Only affects recurring tasks created at the same time. A lower value means a task will be created higher up the list; a higher number means it will be further down. A value greater than 0 means tasks are created below normal tasks.", "QUICK_SETTING": "Recurring Config", "Q_CUSTOM": "Custom recurring config", "Q_DAILY": "Every day", @@ -1652,6 +1650,8 @@ "REPEAT_EVERY": "Recur every", "SATURDAY": "Saturday", "SCHEDULE_TYPE_LABEL": "Schedule type", + "SKIP_OVERDUE": "Skip overdue instances", + "SKIP_OVERDUE_DESCRIPTION": "When enabled, if the app is opened after missing a scheduled occurrence (e.g. a weekly task where today is not a scheduled day), the missed instance will be silently skipped instead of being created as an overdue task", "START_DATE": "Start date", "START_TIME": "Scheduled start time", "START_TIME_DESCRIPTION": "E.g. 15:00. Leave blank for an all day task",