3.6 KiB

SLICE 2 — notebook: option for all gtd block types

State-saving rule: update this file immediately after EVERY completed task (tick the checkbox, update Status and Resume notes) and whenever pausing for input — automatically, without being asked. State on disk must always match reality.

Status

COMPLETE (2026-07-15). SLICE1 done; all tasks landed; 112/112 tests pass.

Goal

Every view block (gtd-calendar, gtd-kanban, gtd-matrix, later gtd-gantt) accepts notebook: <name-or-path-or-id> to root the folder scan at a specific notebook, possibly outside the host note's tree. scope: then applies relative to that notebook.

Design (agreed with user 2026-07-13)

  • Accept, in order of resolution:
    1. A raw 32-char hex folder id.
    2. A Parent/Child/... title path (case-insensitive match on titles).
    3. A bare title — if unique, use it; if ambiguous, warn and fall back to the host folder (consistent with the plugin's warn-don't-fail convention).
  • Unknown notebook → warning + fall back to host folder.
  • Folder titles are needed: extend DataAdapter.getFolders() fields to include title (currently id/parent_id only).

Tasks

  • Extend RawFolder + joplinAdapter.getFolders() with title. Done: RawFolder.title is optional (title?: string) — folder scoping uses id/parent_id only, so scope-only test fixtures don't need it; the real adapter always requests ["id","parent_id","title"].
  • New src/Gtd/resolveNotebook.ts (pure): folders + spec → { folderId, warning }. Resolution order id → path → unique bare title; any miss warns and falls back to the host folder. Also exports parseNotebookOption (shared trim/null normaliser used by all three config parsers).
  • Add notebook key to parseCalendarConfig / parseKanbanConfig / parseMatrixConfig (string | null, default null; "notebook" added to each knownKeys list).
  • Wire in src/index.ts: resolveScanFolder() helper resolves the notebook (or returns host folder) and pushes any warning onto config.warnings; all three handlers pass the resolved id to their collector.
  • Tests: src/tests/Gtd/resolveNotebook.test.ts — resolver (id, unknown id, unique title, ambiguous title, missing title, path, path-disambiguation, unresolvable path, empty), parseNotebookOption, config parsing for all three views, and a collector-level integration (resolved notebook reroots collectEvents' scan). 15 new cases.
  • Docs: README option tables (all three views) + SPEC.md §2.1/§2.3/§2.4 (row + example lines). Workspace planning files remain git-excluded.
  • Full test run: 112 passed, 112 total (10 suites) on 2026-07-15. npx tsc --noEmit clean for src/ (only pre-existing api/ + node_modules lib noise).

Resume notes

SLICE2 complete. Files touched:

  • src/Gtd/types.ts (RawFolder.title?, notebook on all three configs)
  • src/Gtd/resolveNotebook.ts (new; resolver + parseNotebookOption)
  • src/Gtd/parseCalendarConfig.ts, parseKanbanConfig.ts, parseMatrixConfig.ts (notebook key + knownKeys)
  • src/index.ts (getFolders title field, resolveScanFolder, 3 handler wirings)
  • src/tests/Gtd/resolveNotebook.test.ts (new)
  • README.md (3 tables), SPEC.md (§2.1 row + 3 example lines)

Design note: notebook resolution lives in index.ts (needs the folder tree), so collectors stay unchanged — they still take a plain folderId. When notebook: is set, getFolders() is fetched once in the handler and again inside the collector; acceptable (only on notebook use), could be deduped later if it matters. Next: SLICE3 (scope: all).