* Toggle a recurring task instance as skipped for a specific date * Similar to toggleRecurringTaskComplete but uses skipped_instances array * * When skipping: * - Adds date to skipped_instances * - Removes date from complete_instances (if present) * - Updates scheduled date to next uncom
(task: TaskInfo, date?: Date)
| 1772 | * - Updates scheduled date back to this date (since it's now incomplete) |
| 1773 | */ |
| 1774 | async toggleRecurringTaskSkipped(task: TaskInfo, date?: Date): Promise<TaskInfo> { |
| 1775 | const file = this.plugin.app.vault.getAbstractFileByPath(task.path); |
| 1776 | if (!(file instanceof TFile)) { |
| 1777 | throw new Error(`Cannot find task file: ${task.path}`); |
| 1778 | } |
| 1779 | |
| 1780 | // Get fresh task data to avoid stale data issues |
| 1781 | const freshTask = (await this.plugin.cacheManager.getTaskInfo(task.path)) || task; |
| 1782 | |
| 1783 | if (!freshTask.recurrence) { |
| 1784 | throw new Error("Task is not recurring"); |
| 1785 | } |
| 1786 | |
| 1787 | const recurringPlan = buildRecurringTaskSkippedPlan({ |
| 1788 | freshTask, |
| 1789 | targetDate: this.getRecurringTaskActionDate(freshTask, date), |
| 1790 | currentTimestamp: getCurrentTimestamp(), |
| 1791 | maintainDueDateOffsetInRecurring: this.plugin.settings.maintainDueDateOffsetInRecurring, |
| 1792 | }); |
| 1793 | const { updatedTask, dateStr, newSkipped, targetDate } = recurringPlan; |
| 1794 | |
| 1795 | // Step 3: Persist to file |
| 1796 | await this.plugin.app.fileManager.processFrontMatter(file, (frontmatter) => { |
| 1797 | const skippedField = this.plugin.fieldMapper.toUserField("skippedInstances"); |
| 1798 | const completeField = this.plugin.fieldMapper.toUserField("completeInstances"); |
| 1799 | const dateModifiedField = this.plugin.fieldMapper.toUserField("dateModified"); |
| 1800 | const scheduledField = this.plugin.fieldMapper.toUserField("scheduled"); |
| 1801 | const dueField = this.plugin.fieldMapper.toUserField("due"); |
| 1802 | const googleCalendarExceptionOriginalScheduledField = |
| 1803 | this.plugin.fieldMapper.toUserField("googleCalendarExceptionOriginalScheduled"); |
| 1804 | const googleCalendarMovedOriginalDatesField = this.plugin.fieldMapper.toUserField( |
| 1805 | "googleCalendarMovedOriginalDates" |
| 1806 | ); |
| 1807 | |
| 1808 | applyRecurringTaskSkippedFrontmatterChange({ |
| 1809 | frontmatter, |
| 1810 | skippedField, |
| 1811 | completeField, |
| 1812 | dateModifiedField, |
| 1813 | scheduledField, |
| 1814 | dueField, |
| 1815 | googleCalendarExceptionOriginalScheduledField, |
| 1816 | googleCalendarMovedOriginalDatesField, |
| 1817 | plan: recurringPlan, |
| 1818 | }); |
| 1819 | }); |
| 1820 | |
| 1821 | // Step 4: Wait for fresh data and update cache |
| 1822 | try { |
| 1823 | if (this.plugin.cacheManager.waitForFreshTaskData) { |
| 1824 | await this.plugin.cacheManager.waitForFreshTaskData(file); |
| 1825 | } |
| 1826 | this.plugin.cacheManager.updateTaskInfoInCache(freshTask.path, updatedTask); |
| 1827 | } catch (cacheError) { |
| 1828 | tasknotesLogger.error("Error updating cache for skipped recurring task:", { |
| 1829 | category: "stale-data", |
| 1830 | operation: "updating-cache-skipped-recurring-task", |
| 1831 | error: cacheError, |
no test coverage detected