Commit graph

3 commits

Author SHA1 Message Date
Johannes Millan
5e63eeb294
fix(plugins): stop leaked timers on plugin disable via onUnload hook (#8286)
* feat(sync): show actionable error on persistent WebDAV 409

When a WebDAV PUT keeps returning 409 Conflict even after the parent
collection is created, the Base URL / Sync Folder Path is misconfigured
(the classic Synology / raw-WebDAV setup mistake). Previously the raw
"HTTP 409 Conflict" (or a bare "Unknown error") reached the user with no
hint at the cause.

Throw a dedicated WebDavSyncFolderUnusableSPError with a privacy-safe,
actionable message (no path, no response body) at the spot that already
detects this condition. Mirrors NetworkUnavailableSPError: a fixed
user-facing message matched by instanceof.

* ci(release): revive contributors section in release notes

* fix(plugins): stop leaked timers on plugin disable via onUnload hook

* fix(plugins): harden onUnload teardown hook after review

* refactor(plugins): group lifecycle registers into options object

* fix(plugins): close onReady stale-guard gap and timer interleave race
2026-06-12 17:09:28 +02:00
Johannes Millan
f94a46decf feat(plugin-automations): add taskStarted/taskStopped triggers and removeTag action
Adds two new triggers and a new action to the bundled automations plugin,
along with the host-side and validator changes needed to make them
reliable end to end.

Plugin

- New triggers TriggerTaskStarted / TriggerTaskStopped that fire on timer
  start / stop. Switching from task A to task B emits taskStopped(A) and
  then taskStarted(B), so a rule subscribed to either trigger gets the
  full lifecycle. The trigger descriptions document this explicitly.
- New ActionRemoveTag mirroring ActionAddTag, with a shared resolveTagId
  helper covering id/title lookup, missing-tag warning, and idempotent
  short-circuiting.
- Import goes through a new RuleRegistry.addRules(rules[]) + addRules
  message, so the host's 1 call/sec persistDataSynced rate limit no
  longer rejects multi-rule imports.
- Validators in core/rule-registry.ts and utils/rule-validator.ts share a
  set of `as const` arrays guarded by a TS _AssertEq exhaustiveness check
  against the union types in types.ts. The arrays are duplicated rather
  than exported from types.ts because that would turn types.ts into a
  shared runtime chunk and break plugin.js (which the host evaluates via
  `new Function`, not as an ES module).
- Import validator no longer requires a truthy rule name — the UI saves
  empty-named rules, the load-path accepts them, and the import path
  needed to match.
- ActionDialog gets a removeTag placeholder. Manifest's hooks list is
  updated to include the hooks the plugin actually registers
  (taskCreated, currentTaskChange) so the permission disclosure UI is
  accurate.

Host

- plugin-hooks.effects.ts onCurrentTaskChange$ now observes
  selectCurrentTask directly instead of only setCurrentTask /
  unsetCurrentTask actions. This catches transitions through reducer
  paths that don't dispatch those actions (loadAllData, deleteProject,
  bulk task delete via the shared CRUD meta-reducer).
- The payload changes from the raw new Task to { current, previous },
  matching the long-declared CurrentTaskChangePayload shape. The effect
  uses pairwise on the selector and filters same-id pairs at the event
  boundary (not via distinctUntilChanged on the source) so the
  `previous` task always carries the latest snapshot — including
  in-place updates a plugin made while the task was running. Without
  this, addTag-on-start / removeTag-on-stop only worked every other
  cycle because `previous` reflected the pre-mutation snapshot.

Other plugins consuming currentTaskChange (voice-reminder, api-test-plugin)
read payload.current instead of the raw Task.
2026-05-14 21:14:00 +02:00
Johannes Millan
7fcf2fa213 refactor(voice-reminder): extract voice reminder to standalone plugin
Move the voice reminder (domina mode) feature from a built-in Angular
feature into a self-contained plugin with its own manifest, i18n, and
config dialog. Add registerConfigHandler plugin API for settings button
on plugin cards. Include migration logic to auto-enable the plugin and
transfer config for users who had domina mode enabled.

- Fix currentTaskChange hook to dispatch full Task object instead of ID
- Extract shared BUNDLED_PLUGIN_PATHS constant to eliminate duplication
- Use firstValueFrom instead of deprecated .toPromise()
- Add voice name fallback matching for migrated configs
- Mark DominaModeConfig and selector as @deprecated
- Add unit tests for onCurrentTaskChange and config handler
2026-03-20 21:36:30 +01:00