silverbullet icon indicating copy to clipboard operation
silverbullet copied to clipboard

Event `task:stateChange` isn't fired for "external" tasks

Open sirlancelot opened this issue 1 year ago • 11 comments

On a page make some tasks:

- [ ] task 1 #shopping
- [ ] task 2 #shopping
- [ ] task 3 #shopping

On a different page, fetch those tasks:

External tasks below:

`` `template
{{#each {task where tags = "shopping"}}}
- [{{state}}] [[{{ref}}]] {{name}}
{{/each}}
`` `

When completing the task on the different page, a related "task:stateChange" event is not fired.

sirlancelot avatar Mar 05 '24 01:03 sirlancelot

But then even is triggered when you actually complete those tasks on that other page, right? What is your use case for having the event also be triggered on pages where these tasks are merely queried?

zefhemel avatar Mar 05 '24 19:03 zefhemel

But then even is triggered when you actually complete those tasks on that other page, right? What is your use case for having the event also be triggered on pages where these tasks are merely queried?

But they aren't merely queried. The tasks can be completed from within the query.

henrikx avatar Mar 07 '24 08:03 henrikx

The event doesn't seem to fire at all when checking off a task from within a query.

I realize it may be difficult to do what I want to do, but on my daily note page I have a query showing all tasks due that day, and I want to be able to mark it complete and have the event append ✅ {{today}} to the source task.

sirlancelot avatar Mar 09 '24 19:03 sirlancelot

Ah, when you toggle the box in the query. Ok right. I think I can make that happen.

zefhemel avatar Mar 09 '24 20:03 zefhemel

Possibly unrelated, but the remote toggle example on https://silverbullet.md/Plugs/Tasks (under "Rendering") doesn't work for me either.

argus-core avatar Apr 05 '24 09:04 argus-core

@argus-core right, yeah that's a bit misleading there. It doesn't work because silverbullet.md is running in read-only mode. I should remove that example probably.

zefhemel avatar Apr 05 '24 10:04 zefhemel

Hi, as an additional input, I find that task:stateChange also doesn't fire if the state is non defaults. I have following script which works to update the task when completed and blank, but not when it is a new state. I think it is easily reproducible on other instance so long you define an addition state change.

My script snippet is as following ( not complete, just showing the approach) :

const appendDate = async (from, emoji) => {
    const now = Temporal.Now.plainDateISO().toString();
    await syscall("editor.dispatch", {
        changes: { from, insert: ` ${emoji} ${now}` },
    });
}


const checkbox = /^\[([^\]]+)]\s+/

const stateChanges = {
  // Completed
  "x": async ({ to, text }) => {
    await appendDate(to, "✅");
  },
  // Cancelled
  "-": async ({ to, text }) => {
    await appendDate(to, "🛑");
  },
  " ": async ({ from, text, to }) => {
    const finalDatesRegex = /\s*(✅|❌)\s*\d{4}-\d{2}-\d{2}/g;
    const insert = text.replace(finalDatesRegex, "").trim();
    if (insert === text) return;
    const [current] = checkbox.exec(text) || [""];
    const offset = current.length;
    await syscall("editor.dispatch", {
      changes: {
        from: from + offset,
        to,
        insert: insert.slice(offset),
      },
    });
  },
}

// Add or remove finalization date when changing a task
silverbullet.registerEventListener(
  { name: "task:stateChange" },
  ({ data }) => stateChanges[data.newState]?.(data)
)

LumenYoung avatar Jul 07 '24 09:07 LumenYoung

Ok, so I looked into this and there's a bit of a design problem. Currently task:stateChange event assumes that the task change happened on the current page (open in the editor) so it passes in a "from" and "to" assuming the same page, which you can use to dispatch CodeMirror changes to. This would not work when triggered from a query, which may (very likely) update a task on some other page not open in the editor, and so wouldn't be able to change it with dispatch.

Although not great, what I can do is add an additional event, e.g. task:stateChangeExternal or similar that specifies the page, the from (or pos), as well as the newState — then your code would have to figure out what to do with that. If you want to make changes you'd have to fetch the page content, manipulate it and write it back which is a bit of work, but can be done. Would that help?

zefhemel avatar Jul 08 '24 06:07 zefhemel

Of course an additional event would help. I just wonder whether it is better to have a meta event of stateChange combining both events ( don't know if this is possible) and move the current stateChange to something like stateChangeInternal so we have better intuition with the name? Otherwise a detail documentation section should be added explaining the difference and nuance, which I could help with.

LumenYoung avatar Jul 09 '24 09:07 LumenYoung