Commit graph

11 commits

Author SHA1 Message Date
Benjamin
07ec51b1a5
feat(plugins): add onReady() API with IPC ping + fix consent write delay (#7578)
* feat(plugins): add onReady() API with IPC ping + fix consent write delay #7326

- Remove setTimeout(5000) from _getNodeExecutionConsent; write consent immediately
- Add plugin.onReady(fn) to PluginAPI — fires after plugin.js evaluation and IPC bridge confirmation
- Add _pingNodeBridge() in plugin.service.ts with 3-attempt retry (1s, 2s delays)
- Add triggerReady() and pingNodeBridge() to PluginRunner
- Show snack + set error state if IPC bridge unavailable after retries
- Add NODE_EXECUTION_BRIDGE_UNAVAILABLE translation key
- Add focused tests for onReady, triggerReady, pingNodeBridge, consent persistence
- Update plugin-development.md with onReady usage and nodeExecution guidance

* test(plugins): fix unused variable lint errors in spec files

* fix(plugins): guard triggerReady on instance.loaded; fix doc numbering

* fix(plugins): remove _triggerReady from public API, route ping via bridge, add retry tests

* fix(electron): add paths for @sp/sync-providers subpath exports (node moduleResolution compat)

* fix(plugins): centralize onReady, tear down runtime on activation error, add iframe onReady

Address review on #7578:
- All plugin load paths (startup, upload, reload, lazy) now go through _fireOnReady,
  ensuring the IPC ping + onReady fire on every successful load — not just lazy.
- activatePlugin error path now unloads the plugin runtime (hooks, buttons, side
  effects) before setting status='error', preventing partially-running plugins.
- Iframe PluginAPI now exposes onReady (fires on next microtask after plugin.js
  evaluates), matching the host-side contract for typed iframe plugins.

* fix(plugins): clean up half-loaded plugins on onReady error, test real retry util

Self-review followups:
- _fireOnReadyWithCleanup wraps the 3 non-activatePlugin load paths and tears
  down the plugin (unloadPlugin + remove from list + status='error' + snack)
  if the IPC ping or onReady callback throws. Previously, those paths only
  logged and rethrew, leaving partially-running plugins.
- Extracted retry loop into pure pingWithRetry utility; spec now exercises
  production code instead of an inline-replicated stub. Removed the old
  plugin-ping-node-bridge.spec.ts which was just testing its own copy of
  the logic.
- Documented iframe onReady semantic (fires on microtask, no ping) in both
  the source comment and docs/plugin-development.md, since cold-boot is not
  a concern for iframe plugins (rendered on demand).

* ci(plugins): use npm i for root install to tolerate override drift

The root lockfile pins app-builder-lib's transitive minimatch via the
`overrides` field. npm 10.9.7 (bundled with Node 22 in setup-node@v6)
flags this as drift and fails `npm ci`, while npm 11 accepts it.
ci.yml's main test job uses `npm i`, which tolerates the drift without
mutating the lockfile on disk.

Plugin-Tests has been red on every PR since 2026-05-08 for this reason.
The inner `npm ci` for plugin-specific deps stays strict.

* fix(plugins): make onReady optional, assert callback isolation in spec

- packages/plugin-api/src/types.ts: mark onReady? optional on the public
  PluginAPI interface so existing plugin TypeScript typings (and any
  third-party PluginAPI implementations) remain assignable after upgrade.
  The host runtime already treats onReady as optional (no-op if no
  registration callback is provided), so this aligns the type with the
  actual contract.

- src/app/plugins/plugin-runner.spec.ts: the previous isolation test only
  asserted that triggerReady() resolved for both plugins; it would still
  pass if triggerReady fired every registered callback. The updated test
  wires per-plugin Jasmine spies through globalThis (the same context the
  plugin code's `new Function` runs in) and asserts call counts before
  and after each triggerReady, actually proving isolation.

* refactor(plugins): test real consent logic; scope startup snacks; tighten ping timeout

Address review feedback on PR #7578:

- Extract consent decision into pure `decideNodeExecutionConsent` util so the
  spec exercises real code instead of a reimplemented stub. Delete the
  stub-based plugin-consent.spec.ts and plugin-fire-on-ready.spec.ts (the
  latter was orchestration glue already covered by plugin-runner.spec.ts and
  ping-with-retry.util.spec.ts).
- Reduce per-ping timeout 5000ms -> 1500ms. Worst-case cold-boot bridge-down
  detection drops from ~17s to ~7.5s; in-process vm script returning true
  doesn't need 5s.
- Add PLUGIN_LOAD_FAILED translation wrapping plugin name + error. Strip the
  now-redundant pluginName from NODE_EXECUTION_BRIDGE_UNAVAILABLE.
- Scope activation-failure snack to manual activations only — startup
  auto-activation failures stay silent (plugin tile shows error state).
  _handleReadyFailure still snacks unconditionally since onReady failure
  leaves a partially-loaded runtime that the user needs to see.

---------

Co-authored-by: Benjamin <1159333+benjaminburzan@users.noreply.github.com>
Co-authored-by: Johannes Millan <johannes.millan@gmail.com>
2026-05-14 13:41:01 +02:00
Johannes Millan
4d22a64955
Feat/plugin UI kit (#6362)
* fix(e2e): stabilize undo task delete sync test

Two flakiness sources fixed:
- Click on task element could activate title inline editor, causing
  Backspace to edit text instead of triggering delete. Now clicks the
  drag handle which calls focusSelf() without entering edit mode.
- Replaced deleteTask helper with inline sequence to avoid wasting
  2s of the 5s undo snackbar window on dialog-detection timeout.

* refactor: address code review findings from 2026-02-03

- Extract getBreakCycle helper to replace error-prone `cycle - 1 || 1`
  pattern at 3 call sites
- Add clarifying comment on intentionally broad 'timed out' match
- Reduce Pomodoro E2E test from 9 to 5 sessions (sufficient coverage)
- Remove dead _isTransientNetworkError wrapper from DropboxApi
- Extract stubWindowConfirm helper in task reducer tests

* fix(sync): prevent Formly from clearing provider config on show (#6345)

resetOnHide: true caused Formly to reset field values when provider
fieldGroups transitioned from hidden to visible, discarding user input
if sync was enabled before selecting a provider.

* fix(tasks): fix huge space between emoji and text in tag/project menus

Use matMenuItemIcon attribute on emoji spans so they project into the
icon slot of mat-menu-item instead of the text slot. Update emoji icon
sizing to 24x24px to match mat-icon and add overflow: hidden.

Closes #5977

* fix(tasks): guard against undefined task entities in selectors and archive (#6359)

Prevent TypeError crashes (reading 'dueWithTime', 'dueDay', 'issueProviderId') caused
by orphaned IDs in NgRx state. Fix archive merge to deduplicate IDs, filter orphans,
and use correct entity precedence (young over old). Add defensive null guards to
selectors and archive/task service methods.

* fix(tasks): guard against undefined task in mainListTasksInProject$ (#6360)

* fix(tasks): detect and sanitize orphaned task IDs to prevent startup crashes (#6359, #6360)

Orphaned task IDs (entries in task.ids without matching entities) caused
TypeError on app startup. Fix addresses three layers: validation now
flags orphaned IDs instead of silently skipping them, loadAllData
sanitizes IDs on load as a safety net, and data repair no longer crashes
when encountering orphaned IDs it's trying to fix.

* fix(sync): prevent recurring task duplication across clients

Remove SuperSync special-case that bypassed initial sync wait, causing
repeatable task effects to fire before sync completed. Add post-sync
cleanup effect that detects and removes stale duplicate repeat instances
when multiple active instances exist for the same repeat config.

* fix(sync): restore WebDAV provider compatibility warning text

* feat(sync): mark WebDAV and LocalFile sync options as experimental

* feat(plugins): add UI Kit with inject-first CSS strategy for iframe plugins

Introduce a lightweight CSS reset (UI Kit) that auto-styles basic HTML
elements in plugin iframes to match the host app theme. Injected after
<head> so plugin styles always win by source order.

UI Kit provides: element resets (body, headings, buttons, inputs, tables,
links, code, lists, hr), .btn-primary/.btn-outline button variants, and
.card/.card-clickable components.

All bundled plugins updated to use UI Kit classes, removing redundant
custom CSS (-542 lines net). Pico CSS removed from automations plugin.
sync-md converted from hardcoded colors to host theme variables.

* feat(plugins): extract shared CSS utilities into UI Kit

Move .text-muted, .text-primary, .page-fade and @keyframes fadeIn from
plugin CSS into the UI Kit so all iframe plugins get them automatically.
Add box-shadow focus ring to input:focus for better accessibility.
Remove per-plugin focus overrides now covered by the UI Kit.
2026-02-04 18:18:22 +01:00
Johannes Millan
24d3fb6fab Merge remote-tracking branch 'origin/master'
* origin/master:
  add QuestArc to community plugins list
  Fixing Plugin API doc on persistence
2026-01-05 17:36:12 +01:00
Johannes Millan
1a79592aca build: update links to match our new organization 2026-01-05 14:45:06 +01:00
Florian Bachmann
3bc5bb28cd
Fixing Plugin API doc on persistence 2026-01-05 08:03:07 +01:00
Mustache Games
273a1077d7 docs(plugin-dev): improve whitespaces
- Blank lines in Quick Start JS (after log/notification/counter)
- Spacing in Data Operations subsections (Tasks/Projects/Tags/Simple Counters)
2025-11-17 21:08:02 +02:00
Mustache Games
afa2f60450 docs(plugin-dev): document simple counters API
- Add "Simple Counters" subsection with basic/full model tables, validation/examples (regex, dates)
- Integrate counter demo in Quick Start (`plugin.js`: set/inc on button, snack update)
- Tie-in Hooks ACTION example: increment counter on task add
- List community plugins in Resources (`counter-tester-plugin`, `sp-reporter`)
- Clean Data Operations formatting
2025-11-17 20:55:11 +02:00
Johannes Millan
922196c541 docs: add vibe coding tipps 2025-07-03 14:01:07 +02:00
Johannes Millan
0a55fa2823 docs: update plugin development guide 2025-07-03 12:49:59 +02:00
Johannes Millan
48c761fb2b docs: update plugin docs 2025-06-30 21:49:23 +02:00
Johannes Millan
591fc72ec3 docs: add plugin development guide v1 2025-06-30 21:46:58 +02:00