Changelog — v0.8.x

All notable changes introduced in the v0.8.x release series (March – August 2026).


[0.8.3] — 2026-08-24

Fixed

  • Stable project storage keys: Vault folder paths for .planner-tasks.json and markdown task notes now use a stable key set at project creation, so renaming a project no longer orphans existing files.
  • Markdown sync watches all projects: File watchers are now registered for every project folder, not only the active one. Edits, creates, and deletes in non-active project folders were previously invisible to the sync layer.
  • Path helpers accept project ID or display name: Backward-compatible resolution across all sync path helpers.
  • New and duplicated projects register sync watchers immediately: No plugin reload required after adding or duplicating a project when markdown sync is enabled.

Added

  • Duplicate project: Each project in Settings → Projects now has a copy button. Tasks, board buckets, hierarchy, Gantt links, and checklist items are all remapped to fresh UUIDs — the duplicate is fully independent of the original.
  • Board view — Cut, Copy, Paste: Card right-click menu now includes Cut, Copy, and Paste actions, matching Grid view behaviour.
  • Move task between projects: Right-click any task in Grid, Board, or My Tasks to move it to another project. Task Detail gains a Project dropdown when more than one project exists.
  • My Tasks — New Task form: A New Task button opens a slide-in form with auto-focused title input, optional Project selector, and Priority selector. Created tasks are due today and appear immediately.
  • My Tasks — Month view: A third Month tab joins Today and Week. Shows up to 3 priority-coloured task pills per day with overflow counting and full right-click context menu support.
  • My Tasks — Settings section: Set a default view (Today / Week / Month) and toggle the My Tasks ribbon icon.

Changed

  • Per-project vault file storage: Task data moves out of .obsidian/data.json into per-project .planner-tasks.json files inside your vault, making task history Git-trackable. data.json now holds settings only. Migration is automatic on first load — no manual steps required.
  • My Tasks navigation order: My Tasks is now the second entry in the view switcher (Dashboard → My Tasks → Grid → Board → Timeline → Graph).
  • My Tasks week view starts on Sunday.
  • Hover effects standardised across all views.

Bug Fixes

  • Active button highlights now win against Obsidian theme overrides.
  • Priority and status pill text colour no longer overridden to accent colour on hover.
  • Board bucket header hover no longer flashes white on buckets without a custom colour.
  • Adding a child task to My Tasks no longer pulls its parent into the view.

[0.8.2] — 2026-04-17

Bug Fixes

Code Audit — Obsidian Community Plugin Guidelines

  • Browser alert() replaced with Obsidian Notice: Required by community plugin guidelines.
  • Canvas event listeners migrated: Replaced manual addEventListener calls in DependencyGraphView with registerDomEvent() for automatic cleanup on view close.
  • any type annotations removed: Eliminated unsafe any casts across GridView and TaskSync.
  • Path traversal sanitization: projectsBasePath now strips .. segments and leading / to prevent directory traversal.

Resource & Lifecycle Cleanup

  • DashboardView keydown listener leak fixed: Modal keydown handlers are now tracked and removed in dismissModal(), preventing orphaned listeners.
  • DependencyGraphView post-close guard: Animation loop no longer runs after the view is closed.
  • DailyNoteTaskScanner timeout cleanup: Pending scan callbacks are now cleared on plugin unload.
  • GanttView render guard: Overlapping renders can no longer corrupt scroll state.

Performance

  • BoardView dragover optimized: Replaced a full DOM scan on every dragover event with a tracked reference — O(1) class toggle instead of O(n) query.

Input Validation

  • Clipboard API error handling: navigator.clipboard.writeText() is now wrapped in try/catch with a Notice fallback for denied permissions.
  • Numeric settings validation: Budget and hourly rate inputs now reject NaN and negative values.

[0.8.1] — 2026-03-15

Fixed

Obsidian Community Plugin Guidelines

  • .gitignore updated: Removed main.js and main.js.map from ignore list so build outputs are tracked in version control (required by Obsidian plugin registry).
  • isDesktopOnly set to true: Plugin uses Node crypto and desktop-only APIs — now correctly declared in manifest.json.
  • Cross-platform clean script: Replaced PowerShell-only Remove-Item in package.json with portable rm -rf.

Event Listener & Resource Cleanup

  • DependencyGraphView listener leaks: Replaced manual window.addEventListener("resize") and document.addEventListener("mousemove/mouseup") with Obsidian's registerDomEvent() for automatic cleanup on view close.
  • Unsafe TaskDetailView cast: Replaced as TaskDetailView cast with duck-type check ('setTask' in view) to safely handle cases where the view hasn't initialized.

Data Integrity

  • Hash collision in daily note task IDs: Replaced 32-bit hash-based generateStableTaskId() with crypto.randomUUID(), eliminating collision risk for imported daily note tasks.
  • Invalid date handling: Added isValidDateStr() validation in TaskStore and parseLocalDate() in GanttView — invalid or malformed date strings no longer produce NaN dates or silent rendering errors.
  • createFolder crash: Wrapped vault.createFolder() calls in main.ts and TaskSync.ts with try-catch to prevent crashes when the folder already exists.

Performance

  • O(1) task lookups: Added taskIndex Map to TaskStore — getTaskById() now uses Map lookup instead of Array.find(), improving performance for large task lists.
  • taskIndex not updated in addTaskToProject: Fixed a regression where tasks added via DailyNoteTaskScanner were missing from the index, causing getTaskById() to return undefined.
  • Incremental grid rendering: GridView now renders rows in batches of 100 with scroll-triggered loading, reducing initial render time for projects with hundreds of tasks.

Changed

  • View activation deduplicated: Six near-identical view activation methods consolidated into a shared openViewByType() helper.
  • Dead code removed: Deleted unused uuid.ts utility and its test file.

[0.8.0] — 2026-03-06

Added

My Tasks View (Today)

  • New "My Tasks" view accessible from the header navigation (sun icon) and the command palette ("Open My Tasks").
  • Cross-project task aggregation: Shows all tasks due today across every project in a single grid table.
  • Summary bar with task count and progress indicator (X/Y done) with animated fill.
  • Filters: Priority dropdown, text search, and "Show completed" toggle.
  • Sortable rows: Incomplete tasks first, then sorted by priority weight (Critical → Low).
  • Inline actions: Checkbox to toggle completion, clickable title to open Task Detail, right-click context menu.
  • Status & priority pills reusing existing design system styles.
  • Empty states: Distinct messages for "no tasks due today" vs. "all tasks filtered out".
  • Scroll preservation with renderVersion guard to prevent stale restore on rapid re-renders.

My Tasks View (Week)

  • Outlook-style weekly layout: 7 day columns (Monday–Sunday) displayed in a CSS grid.
  • Today/Week segmented toggle in the view header to switch between modes; filters are shared across both.
  • Today highlight: Current day column gets an accent border and the date number displays in an accent-colored circle badge.
  • Compact task cards: Each card shows a checkbox, clickable title, project name, and priority pill.
  • Week navigation: Previous/next chevron buttons and a "This Week" quick-return button in the toolbar.
  • Date range label above the columns (e.g., "March 2 – 8, 2026"), adapts when the week spans two months.
  • Per-column task counts and "Filtered" indicator when all tasks in a day are hidden by filters.

Cost Tracking System

  • Per-task cost fields: costEstimate, costActual, costType ("fixed" or "hourly"), and optional hourlyRate override.
  • Two cost modes:
    • Fixed: User enters estimated and actual cost directly.
    • Hourly: Cost auto-calculated from effort hours × hourly rate (read-only display).
  • TaskDetailView — Cost section: Cost Type dropdown, Estimated/Actual/Variance display, hourly rate override input with project default hint.
  • GridView — Two new columns: "Est. Cost" and "Actual Cost", toggleable from the Columns menu, formatted with project currency symbol.
  • Parent task cost roll-up: Parent tasks automatically aggregate estimated and actual costs from children.
  • Project-level budget settings: Total Budget, Default Hourly Rate, and Currency Symbol fields in plugin settings (per-project).
  • DashboardView — Budget & Cost card: Budget progress bar (green → yellow at 75% → red at 90%), KPI cards for Budget, Estimated, Actual, Remaining, and Over-Budget task count.
  • Cost Report modal: Tabbed breakdown (By Bucket, By Status, By Priority, Over Budget) with totals row and variance coloring; accessible via "View Cost Report" button on Dashboard.
  • costUtils.ts: New utility module with all cost calculation logic — per-task estimated/actual, roll-ups, project summary, breakdown grouping, and currency formatting.
  • Fully backward-compatible: All cost fields are optional; existing data loads without migration.

Fixed

Critical & High Severity

  • Settings save race condition: saveSettings() now uses getCachedRawData() to read task data synchronously, preventing concurrent read/write from blanking task buckets.
  • Task note creation path: createTaskNotes() now respects projectsBasePath setting instead of always writing to vault root.
  • TaskSync delete handler: Rebuilt to use a pre-computed taskIdByPath map, fixing O(n²) lookup and stale-closure bugs when task markdown files are deleted.
  • Window listener leaks: GridView and TaskDetailView now clean up mousemove/mouseup listeners if the view is closed mid-drag.

Scroll Position Reset

  • Stale rAF restore: Added renderVersion counter to GridView and BoardView; scroll-restore callbacks are discarded if a newer render has occurred.
  • Double-save on inline edits: A let saved = false guard ensures only one write per edit in createEditableSelectCell and createEditableDateOnlyCell.
  • Horizontal scroll lost: scrollLeft is now saved and restored alongside scrollTop in GridView.
  • saveScrollPosition() idempotency: The method now only captures scroll coordinates when no save is already pending.

Task Creation UX

  • New task animation glitch: Removed the slideInRow CSS animation that caused rows to disappear then pop in; focus now uses requestAnimationFrame instead of a 150ms setTimeout.
  • "Add Task Above" wrong position: Rewrote to use new addTaskAtIndex() — a single atomic insert replacing the old 3-mutation sequence.

Bug Audit (23 fixes)

  • GanttView UTC date shift: toISODate() now uses local date components, preventing off-by-one day errors near midnight.
  • Cross-project task updates: taskStore.updateTask() now searches across all projects when the task isn't found in the active project.
  • GridView parent drag dropping wrong tasks: Uses recursive getAllDescendants() to collect all nested children, not just direct children.
  • BoardView checkbox desyncs status: Checkbox toggle now passes both completed and status to updateTask().
  • TaskDetailView effort remaining not saved: commitCompleted handler now saves both effortCompleted and effortRemaining in a single update.
  • GanttView checkbox desyncs status: Same fix as BoardView.
  • GridView showCompleted filter ignored in renderTableBody: Added showCompleted filtering inside renderTableBody().
  • GridView auto-scroll wrong selector: Fixed from .planner-grid-wrapper to .planner-grid-content.
  • GanttView resizer listener leak: Added activeResizerCleanup tracking.
  • DashboardView modal DOM leak + missing Escape handler: Added activeModal/activeOverlay tracking and dismissModal() cleanup.
  • DependencyGraphView double-click opens nothing: Double-click now calls plugin.openTaskDetail().
  • DependencyGraphView stale canvas after drag: Added needsRefresh flag that triggers redraw on drag end.
  • TaskDetailView subtask drag corrupts array: handleSubtaskDrop now clones the subtask array before splice.
  • TaskDetailView duration local date parsing: renderDurationRow now parses YYYY-MM-DD as local midnight instead of UTC.
  • uuid.ts fallback not unique: Fallback now generates ${Date.now()}-${Math.random().toString(36).slice(2, 11)}.
  • DashboardView renderVersion counter: Added scroll-preservation guard matching GridView's pattern.
  • GridView duration shows "0 days": Uses Math.max(1, diffDays) — same-day start/due shows "1 day".
  • GridView dead updateSortIndicators code: Removed unreferenced method.
  • BoardView bucket drag off-by-one: Adjusted targetIndex when dragging left-to-right.
  • GanttView scroll sync thrash: Replaced direct scroll assignment with requestAnimationFrame.
  • DependencyGraphView blurry on HiDPI: Canvas now scales by devicePixelRatio.
  • DailyNoteTaskScanner batched saves: Single save at end of scanFile instead of per-line calls.
  • DailyNoteTaskScanner file rename colon split: Now uses lastIndexOf(':') to safely extract line numbers from paths containing colons.

Changed

  • TaskStore gained getCachedRawData() public accessor and addTaskAtIndex(title, index, overrides?) method.
  • TaskStore.rollUpParentFields() now aggregates cost data (estimated + actual) from children.
  • GridView column menu now uses setChecked() for native checkmark indicators.
  • PlannerTask interface extended with costEstimate, costActual, costType, hourlyRate.
  • PlannerProject interface extended with budgetTotal, defaultHourlyRate, currencySymbol.