thombruce / toodles

✅ A super simple todo app
https://toodles.thombruce.com/
GNU General Public License v3.0
0 stars 0 forks source link

Add projects #51

Closed thombruce closed 1 year ago

thombruce commented 1 year ago

closes #4, closes #1

github-actions[bot] commented 1 year ago

Coverage Summary for `./packages/web`

Status Category Percentage Covered / Total
🟢 Lines 93.59% / 60% 877 / 937
🟢 Statements 93.59% / 60% 877 / 937
🟢 Functions 72.52% / 60% 66 / 91
🟢 Branches 90% / 60% 108 / 120
File Coverage
File Stmts % Branch % Funcs % Lines Uncovered Lines
packages/web/src/components/ActiveInterval.vue 100% 100% 100% 100%
packages/web/src/components/CommentCount.vue 95.45% 100% 50% 95.45% 19
packages/web/src/components/IntervalTimer.vue 73.52% 25% 20% 73.52% 17-19, 22-27
packages/web/src/components/StaticInterval.vue 100% 100% 100% 100%
packages/web/src/components/TallyCounter.vue 100% 100% 50% 100%
packages/web/src/components/TodoItem.vue 90.56% 75% 42.85% 90.56% 15-17, 28, 32
packages/web/src/components/TodoList.vue 84.37% 66.66% 33.33% 84.37% 10-14
packages/web/src/models/Base.ts 94.73% 100% 81.81% 94.73% 35-36, 57-58
packages/web/src/models/BaseCollection.ts 100% 100% 100% 100%
packages/web/src/models/Comment.ts 94.73% 100% 66.66% 94.73% 32-33
packages/web/src/models/CommentCollection.ts 100% 100% 100% 100%
packages/web/src/models/Interval.ts 100% 75% 100% 100%
packages/web/src/models/IntervalCollection.ts 100% 100% 100% 100%
packages/web/src/models/Project.ts 83.33% 100% 66.66% 83.33% 40-46, 50-51
packages/web/src/models/ProjectCollection.ts 100% 100% 100% 100%
packages/web/src/models/Projectable.ts 88.23% 100% 57.14% 88.23% 34-35, 38-39, 47-48
packages/web/src/models/ProjectableCollection.ts 100% 100% 100% 100%
packages/web/src/models/Tally.ts 94.73% 100% 66.66% 94.73% 32-33
packages/web/src/models/TallyCollection.ts 100% 100% 100% 100%
packages/web/src/models/Todo.ts 94.33% 94.11% 75% 94.33% 53-54, 57-58, 61-62
packages/web/src/models/TodoCollection.ts 100% 100% 100% 100%
packages/web/src/plugins/loki.ts 100% 100% 100% 100%
packages/web/src/plugins/pinia.ts 100% 100% 100% 100%
packages/web/src/plugins/timepiece.ts 71.42% 60% 50% 71.42% 14-19
packages/web/src/stores/comments.ts 96.96% 100% 100% 96.96% 15
packages/web/src/stores/globals.ts 100% 100% 100% 100%
packages/web/src/stores/intervals.ts 98% 100% 100% 98% 18
packages/web/src/stores/projects.ts 97.29% 100% 100% 97.29% 16
packages/web/src/stores/tallies.ts 97.22% 100% 100% 97.22% 16
packages/web/src/stores/todos.ts 97.29% 100% 100% 97.29% 15
thombruce commented 1 year ago

Must haves:

How do we determine which list to show? How do we determine which list to redirect to after deleting an active list?

Perhaps we can show a global list on the main index, comprised of all todos. When the user adds a new todo, it should be attached to... whatever their default list happens to be.

Later, they should be able to configure their default list.

thombruce commented 1 year ago

Question circling my mind right now is, is that simple enough?

I want to be able to jump in and start adding todos to my list straight away (hence a default list and always showing a list).

What would be nice is to be able to simply type out a todo, and include tags in the text that could be used for sorting into lists... The todo.txt format has a concept of +projects denoted by a plus symbol that can be written inline in a todo, just like that.

Drawback to that todo.txt +project approach... It terminates on whitespace. No project names made up of more than a single word. While techy users will be satisfied with camelCase, snake_case, PascalCase or kebab-case, general users might expect to be able to call their lists things like "My Shopping List", rather than MyShoppingList.

Best way to accommodate both?

  1. Allow users to create a new List via a form UI, giving it a name, selecting it from a dropdown
  2. Allow users to denote project by tagging it inline with the +project syntax (we must recognise and highlight this behaviour)
  3. Create a list whenever an unrecognised +project tag is used
  4. Give any list created via the UI a unique taggable name, emphasising the capability to add a todo to a list with this inline tagging

That sounds pretty good to me.

This does mean that each list has a unique shortname, somewhat making its UUID redundant except... that the UUID might remain useful if the user every connects to a server (having a unique reference distinct from other people's similarly named project tags).

Plus... if we have an additional unique reference (the UUID), we can permit the shortname to be changed by substituting one for the other... right? _If instead of storing +projectName as part of the todo text, we substituted it for +uuid-uuid-uuid-uuid, we wouldn't have to change the tag whenever the project shortName was changed; we would just need to decorate it at display time...?

Alternatively, we could do a broad substitution with searching and replacing when it gets updated but... the decorator approach seems better.

thombruce commented 1 year ago

RegEx ideas, btw... Something like:

/(?<=^|\s)\+\S+/

(?<=^|\s) is a lookbehind, testing for either the beginning of the string ^ or a whitespace character \s before the matched pattern. The matched pattern \+\S+ matches a + followed by any amount of non-whitespace characters.

Actually, the plus itself probably shouldn't be part of the match. Maybe modify to:

/(?<=(?:^|\s)\+)\S+/

This makes the + part of the lookbehind. Does JS support lookbehind? Probably, I'm sure. It's regex support has come a long way since I was last playing extensively with it. This should be trivial.

Any issues? Maybe + itself shouldn't be permitted in the tag string. Maybe we should reduce the tag string to a subset of characters rather than the very, very broad \S non-whitespace check. For certain definitions of "maybe" (i.e. DEFINITELY).

EDIT:

A project or context contains any non-whitespace character.

Source: https://github.com/todotxt/todo.txt

That's what it says. Let's support that initially and maybe add a TODO to give it more consideration a ways down the line. I mean really... ANY non-whitespace character? Really? We might have to put a limit on that if we launch a cloud version, surely... especially with regards to shared lists.

Also it seems more idiomatic to me that the @ symbol tag collaborators. In todo.txt it's a context tag.

thombruce commented 1 year ago

Strictly, the inline project tagging does not need to be part of this PR. We can get lists done with UI support first of all, and deal with that after there actually are these taggable projects (Lists) to support the concept.

Just keep in mind the notion of shortNames. Maybe auto-generate shortNames for users' lists at this time with the promise of them being taggable in the future.

Maybe I should rename this concept "Projects" rather than lists... since the todos tagged like this could ultimately appear on several "lists".

thombruce commented 1 year ago

Well, I'm not changing the branch or issue names. I have just renamed the PR. And I will rename 'List' to 'Project' in the code. The idea is very much to aim for compatibility with todo.txt's +project tags. While such compatibility may not be part of this PR, the idea will be that a user may tag a +project directly in their todo to have the todo be associate with it (we'll do the same for contexts after), and if they do not associate a todo with a +project in the text of the todo, we can append the +project at the end during an export to todo.txt format...

Yeah?

We can add the concept of totally distinct Lists/Workspaces later.

Actually, if a todo isn't associated with a +project via a tag, then it should just be a member of the active list... which right now, in the absence of lists, is none at all. But "Projects" should be navigable in much the same way as I would expect lists to be, so...

We don't need to do both. Not yet.

The user can take or leave the tagging approach, but if they do utilise it then it will be a lot like having distinct lists along with a super list.

We'll do this for +projects and \@contexts and we will consider this enough to mark off those "List" issues for now, with a workspaces concept reserved for future considerations... basically a separate, distinct list space, but far out of scope of what I'm discussing here and largely redundant at this time.

thombruce commented 1 year ago

A todo should:

A project should:

We've got our first many-to-many association here... which probably means we need to add a join table.

Since they're fundamentally a kind of tag, maybe something like a "taggings" or "taggables" collection. Not "tags" as we may reserve that name for the concept of actual tags later.

Such a collection would have a todoId attribute and taggedById and taggedByType attributes. Might hold back on that complexity for now and just have a simpler todoId+projectId collection (this can always be expanded upon and repurposed later). Might call it... projectables, with the idea of contextables and taggables to follow. These aren't names that the user should expect to see in the app in any case.

thombruce commented 1 year ago

Y'know, I'm probably over-engineering this. What I need to do is think less about Toodles and start thinking about how Toodles can serve the todo.txt format as a first priority.

Think about loading in a todo.txt document; this document won't have +uuid-uuid-uuid-uuid formatted project tags. It will have what I describe above as the decorated form: +shortName.

Imagine a todo.txt with a thousand items, and the unnecessary overhead of parsing, generating, substituting, etc. that would go into importing such a document.

I'm saying, forget UUIDs - identify projects by their shortName at this time (we can expand on this later). That way a todo imported from todo.txt is already ready to go. The only decoration we need to do is a little bit of parsing at rendering time.

Todos still need IDs, but let's start simple with Projects and use the shortName concept.


Other thoughts:

I've also thought about tagging todo.txt exported todos with things like their sum interval duration and their tally count. These cannot be converted back to our granular system of date-stamped intervals and tallies, so we should have a way of storing the values directly on the todo, no? A cache of the sum values. Because it's meaningless to record a date-stamped version when we import from such a document.

Also note that we have a similar problem with todo IDs. If we, for example, export to todo.txt and attempt to reimport either what has changed or even just sync with an existing document, unless we add an id tag to the todos, looking something like id:134a8579-1688-4864-892c-4b6556b8a2ff which is a pretty long and hideous string... then we have no way to accurately reimport them.

Also note that without recording an updated timestamp to the exported document, we cannot know which todo has changed more recently... maybe by checking the revision date on the document? This will result in some false positives.

So, certainly we'll add duration and tally caches to todos (and ask ourselves questions about how these might mismatch the granular records). I don't see us exporting an updated timestamp onto todo.txt lines. But it's difficult to conceive of us getting by without the ID. I wonder if there's a shorter alternative to UUIDv4...

thombruce commented 1 year ago

Hey, to that last question... There's nanoid: https://github.com/ai/nanoid

npx nanoid
# rfVDbZtomeGSMAgF4Shcd

Means shorter IDs that could potentially go into a todo.txt document like: id:rfVDbZtomeGSMAgF4Shcd.

Much less cumbersome than the UUID format. Obviously still not readable, but... an ideal compromise for the needs of the project.

thombruce commented 1 year ago

There's a bunch left undone and/or commented out in the recent commit, but we now have Projects being created when added to the text of a todo in the form of +project.

Next up is UI stuff. We need to:

  1. List projects somewhere; allow user to navigate between projects and list associated todos
  2. Highlight project in todo text and link to project page from here
  3. Create projects when use updates todos (either fix save() action to work with updates, or add parse function to update method)
  4. ...
thombruce commented 1 year ago

We can't highlight a project in the todo text right now, because the todo text element is an input - I'll create a separate issue to address this. Should be a div/span instead, that is contenteditable in some regard.

thombruce commented 1 year ago

All that's left to do from my list above is:

  1. Create projects when user updates todos

This won't be a difficult addition. We just utilise the already written parse function again, but we use it on the update action too.

Right now there is no way to delete a project when empty... or to delete a project and all of its associated todos. We'll address these in a future issue.

Gonna:

...and then call this complete.