Skip to content

Commit

Permalink
Merge pull request obsidian-tasks-group#3016 from obsidian-tasks-grou…
Browse files Browse the repository at this point in the history
…p/add-keep-completion-action

feat: Add 'keep' option to 'On Completion'
  • Loading branch information
claremacrae authored Aug 7, 2024
2 parents 34ff778 + 1d2c4e5 commit 814beb3
Show file tree
Hide file tree
Showing 10 changed files with 55 additions and 23 deletions.
20 changes: 8 additions & 12 deletions docs/Getting Started/On Completion.md
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -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
> ```
Expand All @@ -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.
Expand Down
2 changes: 2 additions & 0 deletions docs/Reference/Task Formats/Dataview Format.md
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,8 @@ For more information, see [[Recurring Tasks]].

<!-- snippet: DocsSamplesForTaskFormats.test.Serializer_OnCompletion_dataview-snippet.approved.md -->
```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]
```
Expand Down
2 changes: 2 additions & 0 deletions docs/Reference/Task Formats/Tasks Emoji Format.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ For more information, see [[Recurring Tasks]].

<!-- snippet: DocsSamplesForTaskFormats.test.Serializer_OnCompletion_tasksPluginEmoji-snippet.approved.md -->
```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
```
Expand Down
9 changes: 8 additions & 1 deletion src/Task/OnCompletion.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,16 @@ import type { Task } from './Task';

export enum OnCompletion {
Ignore = '',
Keep = 'keep', // Like Ignore, but is visible on task lines
Delete = 'delete',
}

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;
}
Expand All @@ -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];
Expand Down
18 changes: 18 additions & 0 deletions tests/Task/OnCompletion.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
<!-- placeholder to force blank line before included text -->

- [ ] #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]

Expand Down
Original file line number Diff line number Diff line change
@@ -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]
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
<!-- placeholder to force blank line before included text -->

- [ ] #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

Expand Down
Original file line number Diff line number Diff line change
@@ -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
19 changes: 9 additions & 10 deletions tests/TestingTools/SampleTasks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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());
}
}

0 comments on commit 814beb3

Please sign in to comment.