thombruce / toodles

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

add repetition rules to todos #119

Closed thombruce closed 1 month ago

thombruce commented 1 month ago

Closes #118

By submitting this pull request, you agree to follow our Code of Conduct: https://github.com/thombruce/.github/blob/main/CODE_OF_CONDUCT.md


Internal use. Do not delete.

netlify[bot] commented 1 month ago

Deploy Preview for toodles canceled.

Name Link
Latest commit c62038051414a0606dc820a4e4ae4ff423468ce5
Latest deploy log https://app.netlify.com/sites/toodles/deploys/66b78ab854389f0008f2c039
github-actions[bot] commented 1 month ago

Coverage Summary for `./packages/web`

Status Category Percentage Covered / Total
🟢 Lines 69.78% / 60% 432 / 619
🟢 Statements 69.78% / 60% 432 / 619
🟢 Functions 62.5% / 60% 25 / 40
🟢 Branches 69.84% / 60% 44 / 63
File Coverage
File Stmts % Branch % Funcs % Lines Uncovered Lines
packages/web/src/components/ContextTag.vue 100% 100% 100% 100%
packages/web/src/components/HashTag.vue 20% 100% 0% 20% 4-15
packages/web/src/components/ProgressBar.vue 70.17% 66.66% 100% 70.17% 16-23, 26-34
packages/web/src/components/ProjectTag.vue 20% 100% 0% 20% 4-15
packages/web/src/components/TagTag.vue 71.42% 100% 0% 71.42% 6-7
packages/web/src/components/TodoItem.vue 80.7% 40% 28.57% 80.7% 21, 26-27, 33-40
packages/web/src/components/TodoList.vue 73.68% 100% 100% 73.68% 11-15
packages/web/src/components/TodoPriority.vue 20% 100% 0% 20% 4-15
packages/web/src/components/TodoText.vue 68.08% 60% 85.71% 68.08% 15-18, 21-25, 34-36, 40-42
packages/web/src/models/Todo.ts 89.65% 76.92% 100% 89.65% 35-41, 55-56
packages/web/src/plugins/dexie.ts 55.12% 100% 66.66% 55.12% 38-41, 45-55, 59-78
packages/web/src/plugins/lunr.ts 78.57% 100% 0% 78.57% 10-12
packages/web/src/plugins/timepiece.ts 71.42% 60% 50% 71.42% 14-19
packages/web/src/stores/todos.ts 72.57% 90% 83.33% 72.57% 21, 25, 29-31, 35-37, 41-43, 47-49, 53-55, 59-61, 65-67, 71-73, 77-79, 83-85, 89-91, 95-97, 103, 107-115
thombruce commented 1 month ago

There are some weird bugs cropping up during this implementation, but the core functionality is most of the way there. I can duplicate todos, assigning them a new due date in sequence after of the current one.

This currently works by using the full scope of rrules. You can put any recursion rules you like in there and... it'll loosely work... I think.

I want to simplify. We'll try to maintain the full ruleset implementation as we do this, but I want to be able to infer the ruleset from the existence of a date (be it the due date, created date or the current day) and the existence of an every tag with some value (weekdays should be easy enough to implement first of all).

We will use that inference to construct an object-based rrules consumption, rather than the current from string approach. _This might help to figure out where some of those weird bugs are coming from.

thombruce commented 1 month ago

This is something like what we'll be implementing next:

// Create a rule:
const rule = new RRule({
  freq: RRule.WEEKLY,
  interval: 5,
  byweekday: [RRule.MO, RRule.FR],
  dtstart: datetime(2012, 2, 1, 10, 30),
  until: datetime(2012, 12, 31)
})

This is what the rules object looks like on rrule. We're already inferring dtstart from elsewhere, from which weekday, day of month, etc. can also be inferred. So our primary need is to support values of Yearly, Monthly, Weekly and Daily being interpreted and passed to freq (which is the only required attribute above).

Then we can think about adding Fortnightly, which is freq WEEKLY with an interval of 2.

When it comes to specific weekdays... I do want to support those, but byweekday is still confusing me somewhat. I think that if I say "freq: WEEKLY, byweekday: MO" this is the same as saying "every:Monday"... and there is further information in the docs for targeting "last workday of the month", for example, which my spec might write as... okay, I don't have a good idea about how to write that any simpler; maybe something like every:LastWorkdayMonthly, but that's an advanced case... We'll ignore it for now.

Let's initially...

  1. get DAILY working
  2. then extend that to WEEKLY, MONTHLY and YEARLY
  3. support intervals via every:2days, every:3weeks, every:4months, etc.
  4. add keyword Fortnight for every:2weeks
  5. add support for specific days of week, WEEKLY (because this is most obvious)
  6. make plans to extend that concept to MONTHLY and YEARLY too (bymonth is a thing too right? every:January?)
  7. consider advanced cases
thombruce commented 1 month ago

We still haven't got every:2days style or every:Fortnight, because...

  1. We haven't yet implemented interval
  2. Parsing the interval apart from 2days is not easily supported by current approach... easy enough but requires a little tweaking

I was stressing over this so long too! No matter what I did, the libraries kept on returning the incorrect next date and I could not figure out why until... Well...

dayjs().month() returns an integer-based month from a 0-delimited list!!!

I was out by a whole month every time! So yeah, both systems were in fact working correctly... I was just mishandling one of them, and not the one I thought. In fairness, that isn't an obvious thing... One might think that dates of the month could also be 0-delimited, but they aren't. Just months (and also days of the week - not presently relevant, might be at some point).

It was driving me crazy. Glad to have it resolved.

thombruce commented 1 month ago

Fortnight was just this easy to implement: 6d371aa183ac14a29807394276db980d6d642431

And I've had an idea for supporting those 2days type strings too... They're... the only kind of strings that are going to start with an integer sequence.

All we have to do is match strings which start with an integer and invoke some separate block of code that splits the string (integer half, string half) and then we have the integer separate to be set as the interval... and otherwise proceed as typical.


Another sequence we might support is... every:Monday,Wednesday,Friday <- It's a sequence of specified weekdays, separated by a comma (no space!). We can split these on the comma to then match each item in the new array with a value to be included in the byweekday argument to RRule. freq = DAILY and... just like that, it's a todo that repeats on those specific days.

Useful for me when I'm trying to keep to a Twitch/YouTube schedule.


Also, before we're done here, let's ABSOLUTELY:

We're still not worried about editing todos. I mean, push comes to shove, one can either edit the document or they can delete the todo and recreate it from scratch. But having no way of setting the due date outside of writing it in the document directly kinda takes the wind out of repeatable todos' sails. There are ways to game it, but we shouldn't have to game it - just add a date select to the Todo creation form.

thombruce commented 1 month ago

Huge: 859102c7ca51562f66c6321f6d22b2c837482805

That's arbitrary intervals supported via the every:Xweeks method. That's done.

So there are two key things left to do here... and one of them is inessential.

  1. DO allow the user to set due date when creating a todo
  2. Maybe add support for every:Monday,Wednesday,Thursday style tag

Extending to specific days of month or year and other "advanced" cases, we leave to the future. There are some pretty tricky ideas that could crop up there. Might just look at reenabling support for an rrules style string, which was lost during these convenience developments.

thombruce commented 1 month ago

Okay... one finding is this:

Turns out you cannot add interval: to the rules for rrules, even if you set it to undefined. It hates this. The app freezes up, everything stops working. So we're now constructing the rules a little differently, and we support the every:Monday,Wednesday,Friday style syntax.

Pending review, this is done.