generated from obsidianmd/obsidian-sample-plugin
-
-
Notifications
You must be signed in to change notification settings - Fork 220
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Implement Task Dependencies (#2568)
* basic chip * deletable chips * addable chips * filters out already added tasks from search results * better input floating * selectable with keyboard * ui and keyboard fixes * lefthook * Old sequential boolean code * rename to id * implement id serializing * implement id deserializing * search results favour tasks in same file * svelte commenting * depends on field * blocking field * Adds dependency on existing id * addDependency returns parent and child * Add id to child task if needed * Doesn't create new task unless it needs to * simplify code * should not create duplicate dependency * doesn't create new parent unless it needs to * simplify code * can remove dependency * break out id checker` * setDependencies test * dont create unnecessary new parent * rename deps function * ensure task has id tests * Refactor task dependency logic * Passing in existing ids * new (probably unique) id can be generated * todo finish id generation * persist new task id working * writing depends on is working! * fixed depends on regex * svelte loads task dependencies * refactor id generation to only happen on submit * add duplicate id checking * EditTask modal shows blocking * EditTask can add and remove blocking * remove unnecessary change to cache.ts * small formatting fixes * Query checkboxes look clickable * Fixed id generation * fixed indexes not being correctly reset * variable name shortening * fixed blocking dependency not being serialized * fixed waitingOn dependency not being serialized * Working dropdown fullwidth * Fix console error spams * task results proximity sorting * highlights first result onfocus * filters out itself from results * reorder file * call correct line number parameter * fiddling with styles * convert dropdowns to buttons * Add access keys * Ignore accessibility warning instead * fix: dropdown now clickable * test blocking filter using id * test blocking filter using dependsOn * make it better with some() * refactor blockingField to own file * created new getFilterParser() function * make fieldCreators private * add allTasks attribute * move fieldCreators inside function * connect is blocking in query * fix: Add @ts-expect-error comments on 3 lines that currently don't compile So I can fix them in separate steps. * test: Add comment explaining why I think EditTask.test.ts tests are failing * comment: Add some TODOs with areas to fix... * re-enable lefthook * fix: Can now add dependencies via Pencil icon in Tasks search results * Make the cache private again in TasksPlugin * fix: Remove need for @ts-expect-error * fix: Remove need for @ts-expect-error * Passed allTasks into FilterParser.ts functions * Query.ts accepts allTasks param * Starting to modify QueryRendererHelper.ts * refactor: Make call to filter.filterFunction() explicit in Query.applyQueryToTasks() * refactor: Make more calls to filter.filterFunction() explicit * refactor: Make more calls to filter.filterFunction() explicit * test: Extract new custom matcher toMatchTaskWithTaskList() * refactor: 'is blocking' command now uses the allTasks list passed in to the filter * refactor: BlockingField no longer needs to receive allTasks via constructor * refactor: No longer need to pass allTasks in to FilterParser functions * refactor: No longer need to pass allTasks in Query constructor * test: Add a test of 'is blocking' with circular dependencies * test: Reduce scope of variables * test: Rename shared filter to clarify its meaning * test: Add missing task to the allTasks list * fix: Make BooleanField work with BlockingField * create is not blocked filter * Filters task with no deps * Filters task if there is an incomplete dep * Case-insensitive deps search * Fix failing svelte test suite * Remove unnecessary packages * Indicate which blocked on are complete and incomplete * fix: search results filters out blocked by and blocking * docs: Beginning of task dependencies explanation * docs: Add blocked by image * fix: dependency results self-filtering * add show/hide for new dependency fields * Add status to task search results and chips * vault: Add 'Dependencies Samples.md' for exploratory testing * test: Add 'is not blocked' to Query.test.ts * vault: Add examples of all the new query instructions * feat: Add CSS for id and dependsOn fields * vault: Add more sample searches in Dependencies Samples.md * docs: Document the generic CSS classes for new fields 'id' and 'dependsOn' * comment: Note required documentation if adding CSS classes & data attributes * docs: first draft of deps documentation * fix: Move 'only future dates' up to rest of dates options * fix: long task names are clipped, with popover containing full name * fix: long task names/file names are clipped in dropdown * fix: small dropdown behaviour issues * fix: more responsive dropdown, removed delay * fix: blocking dropdown not hiding * feat: disable dependency fields if task list is empty * fix: Edge case dropdown visual bug * fix: Grid display bug on mobile widths * Migrate wording from waiting on to blocked by * fix: small visual glitches * fix: task names in same file are full width * feat: search results file name and location popups * feat: expand dropdown to 20 results * refactor: DRY up dropdown code * fix: Edits that should have been included in the merge commit * fix: Edits that should have been included in the merge commit but got lost * fix: Remove empty file VerifyMarkdownTable.ts - remnant of merge * comment: Remove some HTML I accidentally copied from an error message * chore: Update yarn.lock * chore: migrate from dependsOn to blockedBy * chore: migrate blockedBy symbol to ⛔️ * tests: Reinstate tests I disabled during the merge of 'upstream/main' * fix: Correct the layout of Created, Done and Cancelled fields Their CSS classes needed updating, when they were merged in from main. * docs: Update snippets for addition of dependency emojis * refactor: . Extract function symbolAndDateValue() * refactor: . Extract function * refactor: . Extract function symbolAndStringValue() * refactor: . Fix misleading parameter name startDateSymbol * refactor: - Simplify the serialisation of task.blockedBy * fix: Don't render task.blockedBy values in 'short mode' * fix: Don't render task.id value in 'short mode' * refactor: . Remove some wasted work in symbolAndDateValue() * refactor: - Simplify code for serialising recurrence rule * test: Generate sample files of dependency fields in markdown * docs: Add samples of dependency fields to Format reference docs * docs: Minor updates to 'Task Dependencies.md' * docs: Add limitations of dependency feature to 'Known Limitations' page * test: Create table of Task Property values for documentation * docs: Document task properties available for scripting. * test: Fix duplicate test names --------- Co-authored-by: Clare Macrae <github@cfmacrae.fastmail.co.uk>
- Loading branch information
1 parent
a3663e9
commit 3c9383b
Showing
59 changed files
with
1,439 additions
and
69 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
--- | ||
publish: true | ||
--- | ||
|
||
# Task Dependencies | ||
|
||
> [!released] | ||
> Introduced in Tasks X.Y.Z. | ||
## Introduction | ||
|
||
At a high level, task dependencies define the order in which you want to work on a set of tasks. | ||
This can be useful for mapping out projects, where one part needs to be completed before the other. | ||
By specifying these dependencies, Obsidian Tasks can streamline your workflow by displaying only the tasks that are actionable at any given moment. | ||
|
||
> [!NOTE] | ||
> Obsidian tasks exclusively allows for Finish to start (FS) dependencies, meaning Task A needs to be finished before you start on Task B. You can learn more about this concept [on Wikipedia](https://en.wikipedia.org/wiki/Dependency_(project_management)). | ||
## Example | ||
|
||
To illustrate the concept of task dependencies, let's consider a scenario where we are outlining the tasks required to develop an application. Two tasks are identified: | ||
|
||
```text | ||
- [ ] Build a first draft | ||
- [ ] Test with users | ||
``` | ||
|
||
In this scenario, testing with users can only occur after the initial draft is completed. To establish this relationship, you can create a dependency between the two tasks using either of the following methods. | ||
|
||
1. Open the 'Build a first draft' task in the Edit Task Modal and specify 'Test with users' as a 'Blocking' task | ||
2. Alternatively, open the 'Test with users' task in the Edit Task Modal and add 'Build a first draft' as a 'Blocked By' task | ||
![[task-dependencies-blocked-by-example.png]] | ||
|
||
By implementing either of these methods, the task list is updated to reflect the dependency relationship: | ||
|
||
```text | ||
- [ ] Build a first draft 🆔 4ijuhy | ||
- [ ] Test with users ⛔️ 4ijuhy | ||
``` | ||
|
||
Then, if the query `is not blocked` is used | ||
|
||
```tasks | ||
is not blocked | ||
``` | ||
|
||
We only see 'Build a first draft' | ||
|
||
```text | ||
- [ ] Build a first draft 🆔 4ijuhy | ||
``` | ||
|
||
Until this task is marked as complete, at which time Obsidian Tasks sees that 'Test with users' is no longer blocked, and displays it as well | ||
|
||
```text | ||
- [x] Build a first draft 🆔 4ijuhy | ||
- [ ] Test with users ⛔️ 4ijuhyz | ||
``` | ||
|
||
## Nomenclature | ||
|
||
Fields: | ||
|
||
- `blockedBy` | ||
- `id` | ||
|
||
UI: | ||
|
||
- Blocked by [implies an id of another task] | ||
- Blocks | ||
|
||
Query | ||
|
||
- blocking | ||
- blocked | ||
|
||
## Adding Dependencies | ||
|
||
## Searching For Dependencies | ||
|
||
`is not blocked` | ||
|
||
`is blocking` | ||
|
||
![[Pasted image 20231011181837.png]] | ||
|
||
## Known Limitations | ||
|
||
- It's not yet possible to directly navigate from a task to the tasks it depends on. | ||
- Outside of the edit task modal, it is not possible to see the descriptions of the blocking tasks. | ||
- It is not yet possible to visualise the relationships in a graph viewer. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
87 changes: 87 additions & 0 deletions
87
resources/sample_vaults/Tasks-Demo/Manual Testing/Dependencies Samples.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
# Dependencies Samples | ||
|
||
- [ ] #task Choose a topic 🆔 ya44g5 | ||
- [ ] #task Research the subject ⛔️ ya44g5 🆔 g7317o | ||
- [ ] #task Create an outline ⛔️ g7317o 🆔 rot7gb | ||
- [ ] #task Develop main points ⛔️ rot7gb 🆔 mvplec | ||
- [ ] #task Craft a conclusion ⛔️ mvplec 🆔 0wigip | ||
- [ ] #task Proofread and edit ⛔️ 0wigip 🆔 5ti6bf | ||
- [ ] #task Publish the article ⛔️ 5ti6bf | ||
|
||
--- | ||
|
||
## Do Next | ||
|
||
```tasks | ||
((is blocking) AND (is not blocked)) OR (is not blocked) | ||
not done | ||
path includes {{query.file.path}} | ||
explain | ||
``` | ||
|
||
--- | ||
|
||
## Blocking Tasks | ||
|
||
### Blocking Tasks - Any Status | ||
|
||
```tasks | ||
is blocking | ||
path includes {{query.file.path}} | ||
explain | ||
``` | ||
|
||
### Blocking Tasks - Not Done | ||
|
||
```tasks | ||
is blocking | ||
not done | ||
path includes {{query.file.path}} | ||
explain | ||
``` | ||
|
||
--- | ||
|
||
## Blocked Tasks | ||
|
||
### Blocked Tasks - Any Status | ||
|
||
```tasks | ||
is not blocked | ||
path includes {{query.file.path}} | ||
explain | ||
``` | ||
|
||
### Blocked Tasks - Not Done | ||
|
||
```tasks | ||
is not blocked | ||
not done | ||
path includes {{query.file.path}} | ||
explain | ||
``` | ||
|
||
--- | ||
|
||
## Show/Hide Instructions | ||
|
||
### Hide Id | ||
|
||
```tasks | ||
hide id | ||
path includes {{query.file.path}} | ||
explain | ||
``` | ||
|
||
### Hide blockedBy | ||
|
||
```tasks | ||
hide depends on | ||
path includes {{query.file.path}} | ||
explain | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
import type { SearchInfo } from '../SearchInfo'; | ||
import { FilterInstructionsBasedField } from './FilterInstructionsBasedField'; | ||
|
||
export class BlockingField extends FilterInstructionsBasedField { | ||
constructor() { | ||
super(); | ||
this._filters.add('is blocking', (task, searchInfo: SearchInfo) => { | ||
if (task.id === '') return false; | ||
|
||
return searchInfo.allTasks.some((cacheTask) => { | ||
return cacheTask.blockedBy.includes(task.id); | ||
}); | ||
}); | ||
this._filters.add('is not blocked', (task, searchInfo: SearchInfo) => { | ||
if (task.blockedBy.length === 0) return true; | ||
|
||
for (const depId of task.blockedBy) { | ||
const depTask = searchInfo.allTasks.find((task) => task.id === depId); | ||
|
||
if (!depTask) continue; | ||
|
||
if (!depTask.status.isCompleted()) return false; | ||
} | ||
|
||
return true; | ||
}); | ||
} | ||
|
||
fieldName(): string { | ||
return 'blocking'; | ||
} | ||
} |
Oops, something went wrong.