65 lines
3.6 KiB
Markdown

# 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
- [x] 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"]`.
- [x] 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).
- [x] Add `notebook` key to parseCalendarConfig / parseKanbanConfig /
parseMatrixConfig (`string | null`, default null; "notebook" added to each
knownKeys list).
- [x] 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.
- [x] 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.
- [x] Docs: README option tables (all three views) + SPEC.md §2.1/§2.3/§2.4
(row + example lines). Workspace planning files remain git-excluded.
- [x] 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`).