mirror of
https://github.com/callumalpass/tasknotes.git
synced 2026-07-22 12:50:26 +00:00
fix recurring nlp scheduled times
This commit is contained in:
parent
ef04893eba
commit
bcf1ac3091
3 changed files with 95 additions and 0 deletions
|
|
@ -35,3 +35,4 @@ When a change has user-facing documentation, include a canonical tasknotes.dev l
|
|||
## Fixed
|
||||
|
||||
- (#2007) Fixed a remaining task creation autocomplete case where a status value containing another status label could leave status fragments in the task title. Thanks to @prepare4robots for the follow-up report.
|
||||
- (#2031) Fixed quick task creation failing when natural language input created a recurring task with a scheduled time. Thanks to @rdefaccio for reporting this.
|
||||
|
|
|
|||
|
|
@ -2,15 +2,37 @@ export * from "@tasknotes/model/recurrence";
|
|||
export type { TaskInfo } from "../types";
|
||||
|
||||
import {
|
||||
addDTSTARTToRecurrenceRule as addDTSTARTToRecurrenceRuleModel,
|
||||
addDTSTARTToRecurrenceRuleWithDraggedTime as addDTSTARTToRecurrenceRuleWithDraggedTimeModel,
|
||||
getNextUncompletedOccurrence as getNextUncompletedOccurrenceModel,
|
||||
updateToNextScheduledOccurrence as updateToNextScheduledOccurrenceModel,
|
||||
} from "@tasknotes/model/recurrence";
|
||||
import { getTodayString } from "../utils/dateUtils";
|
||||
|
||||
type AddDTSTARTTaskInput = Parameters<typeof addDTSTARTToRecurrenceRuleModel>[0];
|
||||
type AddDTSTARTWithDraggedTimeTaskInput = Parameters<
|
||||
typeof addDTSTARTToRecurrenceRuleWithDraggedTimeModel
|
||||
>[0];
|
||||
type RecurringTaskInput = Parameters<typeof getNextUncompletedOccurrenceModel>[0];
|
||||
type RecurrenceUpdateTaskInput = Parameters<typeof updateToNextScheduledOccurrenceModel>[0];
|
||||
type RecurrenceUpdateResult = ReturnType<typeof updateToNextScheduledOccurrenceModel>;
|
||||
|
||||
export function addDTSTARTToRecurrenceRule(task: AddDTSTARTTaskInput): string | null {
|
||||
return addDTSTARTToRecurrenceRuleModel(normalizeMinutePrecisionDateInputs(task));
|
||||
}
|
||||
|
||||
export function addDTSTARTToRecurrenceRuleWithDraggedTime(
|
||||
task: AddDTSTARTWithDraggedTimeTaskInput,
|
||||
draggedStart: Date,
|
||||
allDay: boolean
|
||||
): string | null {
|
||||
return addDTSTARTToRecurrenceRuleWithDraggedTimeModel(
|
||||
normalizeMinutePrecisionDateInputs(task),
|
||||
draggedStart,
|
||||
allDay
|
||||
);
|
||||
}
|
||||
|
||||
export function getNextUncompletedOccurrence(task: RecurringTaskInput): Date | null {
|
||||
return getNextUncompletedOccurrenceModel(task, { today: getTodayString() });
|
||||
}
|
||||
|
|
@ -23,3 +45,35 @@ export function updateToNextScheduledOccurrence(
|
|||
today: getTodayString(),
|
||||
});
|
||||
}
|
||||
|
||||
function normalizeMinutePrecisionDateInputs<T extends { scheduled?: string; dateCreated?: string }>(
|
||||
task: T
|
||||
): T {
|
||||
const scheduled = normalizeMinutePrecisionDateTime(task.scheduled);
|
||||
const dateCreated = normalizeMinutePrecisionDateTime(task.dateCreated);
|
||||
|
||||
if (scheduled === task.scheduled && dateCreated === task.dateCreated) {
|
||||
return task;
|
||||
}
|
||||
|
||||
return {
|
||||
...task,
|
||||
scheduled,
|
||||
dateCreated,
|
||||
};
|
||||
}
|
||||
|
||||
function normalizeMinutePrecisionDateTime(value: string | undefined): string | undefined {
|
||||
if (!value) return value;
|
||||
|
||||
const match = value
|
||||
.trim()
|
||||
.match(/^(\d{4}-\d{2}-\d{2})[T ](\d{2}:\d{2})(Z|[+-]\d{2}:\d{2})?$/);
|
||||
|
||||
if (!match) {
|
||||
return value;
|
||||
}
|
||||
|
||||
const [, date, time, zone = ""] = match;
|
||||
return `${date}T${time}:00${zone}`;
|
||||
}
|
||||
|
|
|
|||
40
tests/unit/issues/issue-2031-nlp-recurring-time.test.ts
Normal file
40
tests/unit/issues/issue-2031-nlp-recurring-time.test.ts
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
import type TaskNotesPlugin from "../../../src/main";
|
||||
import { addDTSTARTToRecurrenceRule } from "../../../src/core/recurrence";
|
||||
import { buildTaskCreationDataFromParsed } from "../../../src/services/buildTaskCreationDataFromParsed";
|
||||
import { DEFAULT_SETTINGS } from "../../../src/settings/defaults";
|
||||
import type { ParsedTaskData } from "../../../src/services/NaturalLanguageParser";
|
||||
|
||||
function createPlugin(): TaskNotesPlugin {
|
||||
return {
|
||||
settings: {
|
||||
...DEFAULT_SETTINGS,
|
||||
},
|
||||
} as unknown as TaskNotesPlugin;
|
||||
}
|
||||
|
||||
describe("Issue #2031: NLP recurring task with time", () => {
|
||||
it("adds DTSTART for NLP-created recurring tasks with minute-precision scheduled times", () => {
|
||||
const parsed: ParsedTaskData = {
|
||||
title: "this is a task",
|
||||
scheduledDate: "2026-06-13",
|
||||
scheduledTime: "15:00",
|
||||
recurrence: "FREQ=DAILY",
|
||||
};
|
||||
|
||||
const taskData = buildTaskCreationDataFromParsed(createPlugin(), parsed);
|
||||
|
||||
expect(taskData.scheduled).toBe("2026-06-13T15:00");
|
||||
expect(taskData.recurrence).toBe("FREQ=DAILY");
|
||||
expect(
|
||||
addDTSTARTToRecurrenceRule({
|
||||
title: taskData.title,
|
||||
status: taskData.status,
|
||||
priority: taskData.priority,
|
||||
path: "",
|
||||
archived: false,
|
||||
scheduled: taskData.scheduled,
|
||||
recurrence: taskData.recurrence,
|
||||
})
|
||||
).toBe("DTSTART:20260613T150000Z;FREQ=DAILY");
|
||||
});
|
||||
});
|
||||
Loading…
Reference in a new issue