diff --git a/docs/Getting Started/On Completion.md b/docs/Getting Started/On Completion.md index cf20b5a36b..575ae82244 100644 --- a/docs/Getting Started/On Completion.md +++ b/docs/Getting Started/On Completion.md @@ -24,10 +24,12 @@ This feature is enabled by adding (*after* the description within a task) a fiel ## Supported actions -At present, two "On Completion" ***actions*** are supported: +At present, these "On Completion" ***actions*** are supported: -1. **Ignore**      Nothing will be done with the just-completed task. (This is the default action.) -2. **Delete**      Removes the completed instance of the task. +| Action | Behaviour | +| ---------- | --------------------------------------------------------------------------------- | +| **Keep** | Nothing will be done with the just-completed task. (This is the default action.) | +| **Delete** | Removes the completed instance of the task. | > [!tip] > Two additional ***actions*** are being considered for future implementation, namely moving a just-completed task to: @@ -47,7 +49,7 @@ At present, two "On Completion" ***actions*** are supported: > ```text > # My Project Tasks > - [ ] Leave me alone -> - [ ] Leave me alone too! 🏁 ignore +> - [ ] Leave me alone too! 🏁 keep > - [ ] Delete me upon completion 🏁 delete > - [ ] Delete my completed instance, leave my next instance 📅 2021-05-20 🔁 every day when done 🏁 delete > ``` @@ -57,21 +59,15 @@ At present, two "On Completion" ***actions*** are supported: > ```text > # My Project Tasks > - [x] Leave me alone -> - [x] Leave me alone too! 🏁 ignore +> - [x] Leave me alone too! 🏁 keep > - [ ] Delete my completed instance, leave my next instance 📅 2021-05-21 🔁 every day when done 🏁 delete > ``` > [!note] Note that > -> - The task assigned the `ignore` action is treated the same as one that has no onCompletion field at all, and +> - The task assigned the `keep` action is treated the same as one that has no onCompletion field at all, and > - The next instance of the recurring task has replaced the original, completed instance. -> [!warning] -> Currently, `🏁 ignore` has some slightly confusing behaviour: -> -> - When viewed in Reading mode, `🏁 ignore` is not shown. -> - When tasks are completed, any `🏁 ignore` text is deleted. - ## Assigning and changing a given task's "On Completion" action At present, the "On Completion" signifier and desired **Action** identifier have to be added to a task manually. diff --git a/docs/Reference/Task Formats/Dataview Format.md b/docs/Reference/Task Formats/Dataview Format.md index 5374641dff..031a5d20c9 100644 --- a/docs/Reference/Task Formats/Dataview Format.md +++ b/docs/Reference/Task Formats/Dataview Format.md @@ -135,6 +135,8 @@ For more information, see [[Recurring Tasks]]. ```md +- [ ] #task Keep this task when done +- [ ] #task Keep this task when done too [onCompletion:: keep] - [ ] #task Remove this task when done [onCompletion:: delete] - [ ] #task Remove completed instance of this recurring task when done [repeat:: every day] [onCompletion:: delete] ``` diff --git a/docs/Reference/Task Formats/Tasks Emoji Format.md b/docs/Reference/Task Formats/Tasks Emoji Format.md index 7ac2042628..a938c26e4c 100644 --- a/docs/Reference/Task Formats/Tasks Emoji Format.md +++ b/docs/Reference/Task Formats/Tasks Emoji Format.md @@ -52,6 +52,8 @@ For more information, see [[Recurring Tasks]]. ```md +- [ ] #task Keep this task when done +- [ ] #task Keep this task when done too 🏁 keep - [ ] #task Remove this task when done 🏁 delete - [ ] #task Remove completed instance of this recurring task when done 🔁 every day 🏁 delete ``` diff --git a/src/Task/OnCompletion.ts b/src/Task/OnCompletion.ts index e83188e1d6..a2c1e92cc6 100644 --- a/src/Task/OnCompletion.ts +++ b/src/Task/OnCompletion.ts @@ -3,6 +3,7 @@ import type { Task } from './Task'; export enum OnCompletion { Ignore = '', + Keep = 'keep', // Like Ignore, but is visible on task lines Delete = 'delete', } @@ -10,6 +11,8 @@ export function parseOnCompletionValue(inputOnCompletionValue: string) { const onCompletionString = inputOnCompletionValue.trim().toLowerCase(); if (onCompletionString === 'delete') { return OnCompletion.Delete; + } else if (onCompletionString === 'keep') { + return OnCompletion.Keep; } else { return OnCompletion.Ignore; } @@ -31,7 +34,11 @@ function keepTasks(originalTask: Task, changedStatusTask: Task) { export function handleOnCompletion(originalTask: Task, newTasks: Task[]): Task[] { const tasksArrayLength = newTasks.length; - if (originalTask.onCompletion === OnCompletion.Ignore || tasksArrayLength === 0) { + if ( + originalTask.onCompletion === OnCompletion.Ignore || + originalTask.onCompletion === OnCompletion.Keep || + tasksArrayLength === 0 + ) { return newTasks; } const changedStatusTask = newTasks[tasksArrayLength - 1]; diff --git a/tests/Task/OnCompletion.test.ts b/tests/Task/OnCompletion.test.ts index 7e6080337a..e78046ffd6 100644 --- a/tests/Task/OnCompletion.test.ts +++ b/tests/Task/OnCompletion.test.ts @@ -40,6 +40,11 @@ describe('OnCompletion - parsing', () => { checkParseOnCompletionValue(input, OnCompletion.Delete); }); + const keeps = ['keep', 'KEEP', ' keep ']; + it.each(keeps)('should parse "%s" as OnCompletion.Keep', (input: string) => { + checkParseOnCompletionValue(input, OnCompletion.Keep); + }); + const ignores = ['', 'unknown']; it.each(ignores)('should parse "%s" as OnCompletion.Ignore', (input: string) => { checkParseOnCompletionValue(input, OnCompletion.Ignore); @@ -125,6 +130,19 @@ describe('OnCompletion - cases where all tasks are retained', () => { }); }); +describe('OnCompletion - "keep" action', () => { + it('should retain a task with "keep" Action upon completion', () => { + // Arrange + const task = makeTask('- [ ] A non-recurring task with "keep" Action 🏁 keep'); + + // Act + const tasks = applyStatusAndOnCompletionAction(task, Status.makeDone()); + + // Assert + expect(tasks.length).toEqual(1); + }); +}); + describe('OnCompletion - "delete" action', () => { it('should retain only the next instance of a recurring task with "delete" Action upon completion', () => { // Arrange diff --git a/tests/TaskSerializer/DocsSamplesForTaskFormats.test.Serializer_OnCompletion_dataview-include.approved.md b/tests/TaskSerializer/DocsSamplesForTaskFormats.test.Serializer_OnCompletion_dataview-include.approved.md index cf9f28e9dd..1c749b01c6 100644 --- a/tests/TaskSerializer/DocsSamplesForTaskFormats.test.Serializer_OnCompletion_dataview-include.approved.md +++ b/tests/TaskSerializer/DocsSamplesForTaskFormats.test.Serializer_OnCompletion_dataview-include.approved.md @@ -1,5 +1,7 @@ +- [ ] #task Keep this task when done +- [ ] #task Keep this task when done too [onCompletion:: keep] - [ ] #task Remove this task when done [onCompletion:: delete] - [ ] #task Remove completed instance of this recurring task when done [repeat:: every day] [onCompletion:: delete] diff --git a/tests/TaskSerializer/DocsSamplesForTaskFormats.test.Serializer_OnCompletion_dataview-snippet.approved.md b/tests/TaskSerializer/DocsSamplesForTaskFormats.test.Serializer_OnCompletion_dataview-snippet.approved.md index d3332c424d..25f85c4829 100644 --- a/tests/TaskSerializer/DocsSamplesForTaskFormats.test.Serializer_OnCompletion_dataview-snippet.approved.md +++ b/tests/TaskSerializer/DocsSamplesForTaskFormats.test.Serializer_OnCompletion_dataview-snippet.approved.md @@ -1,2 +1,4 @@ +- [ ] #task Keep this task when done +- [ ] #task Keep this task when done too [onCompletion:: keep] - [ ] #task Remove this task when done [onCompletion:: delete] - [ ] #task Remove completed instance of this recurring task when done [repeat:: every day] [onCompletion:: delete] diff --git a/tests/TaskSerializer/DocsSamplesForTaskFormats.test.Serializer_OnCompletion_tasksPluginEmoji-include.approved.md b/tests/TaskSerializer/DocsSamplesForTaskFormats.test.Serializer_OnCompletion_tasksPluginEmoji-include.approved.md index 341cd1345a..370a14a6e0 100644 --- a/tests/TaskSerializer/DocsSamplesForTaskFormats.test.Serializer_OnCompletion_tasksPluginEmoji-include.approved.md +++ b/tests/TaskSerializer/DocsSamplesForTaskFormats.test.Serializer_OnCompletion_tasksPluginEmoji-include.approved.md @@ -1,5 +1,7 @@ +- [ ] #task Keep this task when done +- [ ] #task Keep this task when done too 🏁 keep - [ ] #task Remove this task when done 🏁 delete - [ ] #task Remove completed instance of this recurring task when done 🔁 every day 🏁 delete diff --git a/tests/TaskSerializer/DocsSamplesForTaskFormats.test.Serializer_OnCompletion_tasksPluginEmoji-snippet.approved.md b/tests/TaskSerializer/DocsSamplesForTaskFormats.test.Serializer_OnCompletion_tasksPluginEmoji-snippet.approved.md index 64e77907d7..ed9756f752 100644 --- a/tests/TaskSerializer/DocsSamplesForTaskFormats.test.Serializer_OnCompletion_tasksPluginEmoji-snippet.approved.md +++ b/tests/TaskSerializer/DocsSamplesForTaskFormats.test.Serializer_OnCompletion_tasksPluginEmoji-snippet.approved.md @@ -1,2 +1,4 @@ +- [ ] #task Keep this task when done +- [ ] #task Keep this task when done too 🏁 keep - [ ] #task Remove this task when done 🏁 delete - [ ] #task Remove completed instance of this recurring task when done 🔁 every day 🏁 delete diff --git a/tests/TestingTools/SampleTasks.ts b/tests/TestingTools/SampleTasks.ts index a36fa8b222..9ff95b39a6 100644 --- a/tests/TestingTools/SampleTasks.ts +++ b/tests/TestingTools/SampleTasks.ts @@ -290,15 +290,14 @@ export class SampleTasks { dueDate: null, }), }); - const task1 = new TaskBuilder() - .description('#task Remove this task when done') - .onCompletion(OnCompletion.Delete) - .build(); - const task2 = new TaskBuilder() - .description('#task Remove completed instance of this recurring task when done') - .onCompletion(OnCompletion.Delete) - .recurrence(everyDay) - .build(); - return [task1, task2]; + return [ + new TaskBuilder().description('#task Keep this task when done').onCompletion(OnCompletion.Ignore), + new TaskBuilder().description('#task Keep this task when done too').onCompletion(OnCompletion.Keep), + new TaskBuilder().description('#task Remove this task when done').onCompletion(OnCompletion.Delete), + new TaskBuilder() + .description('#task Remove completed instance of this recurring task when done') + .onCompletion(OnCompletion.Delete) + .recurrence(everyDay), + ].map((builder) => builder.build()); } }