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.jsonand 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.jsoninto per-project.planner-tasks.jsonfiles inside your vault, making task history Git-trackable.data.jsonnow 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 ObsidianNotice: Required by community plugin guidelines. - Canvas event listeners migrated: Replaced manual
addEventListenercalls in DependencyGraphView withregisterDomEvent()for automatic cleanup on view close. anytype annotations removed: Eliminated unsafeanycasts across GridView and TaskSync.- Path traversal sanitization:
projectsBasePathnow 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
dragoverevent 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 aNoticefallback 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
.gitignoreupdated: Removedmain.jsandmain.js.mapfrom ignore list so build outputs are tracked in version control (required by Obsidian plugin registry).isDesktopOnlyset totrue: Plugin uses Nodecryptoand desktop-only APIs — now correctly declared inmanifest.json.- Cross-platform clean script: Replaced PowerShell-only
Remove-Iteminpackage.jsonwith portablerm -rf.
Event Listener & Resource Cleanup
- DependencyGraphView listener leaks: Replaced manual
window.addEventListener("resize")anddocument.addEventListener("mousemove/mouseup")with Obsidian'sregisterDomEvent()for automatic cleanup on view close. - Unsafe TaskDetailView cast: Replaced
as TaskDetailViewcast 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()withcrypto.randomUUID(), eliminating collision risk for imported daily note tasks. - Invalid date handling: Added
isValidDateStr()validation in TaskStore andparseLocalDate()in GanttView — invalid or malformed date strings no longer produceNaNdates or silent rendering errors. createFoldercrash: Wrappedvault.createFolder()calls inmain.tsandTaskSync.tswith try-catch to prevent crashes when the folder already exists.
Performance
- O(1) task lookups: Added
taskIndexMap to TaskStore —getTaskById()now uses Map lookup instead ofArray.find(), improving performance for large task lists. taskIndexnot updated inaddTaskToProject: Fixed a regression where tasks added via DailyNoteTaskScanner were missing from the index, causinggetTaskById()to returnundefined.- 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.tsutility 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
renderVersionguard 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 optionalhourlyRateoverride. - 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 usesgetCachedRawData()to read task data synchronously, preventing concurrent read/write from blanking task buckets. - Task note creation path:
createTaskNotes()now respectsprojectsBasePathsetting instead of always writing to vault root. - TaskSync delete handler: Rebuilt to use a pre-computed
taskIdByPathmap, fixing O(n²) lookup and stale-closure bugs when task markdown files are deleted. - Window listener leaks: GridView and TaskDetailView now clean up
mousemove/mouseuplisteners if the view is closed mid-drag.
Scroll Position Reset
- Stale rAF restore: Added
renderVersioncounter to GridView and BoardView; scroll-restore callbacks are discarded if a newer render has occurred. - Double-save on inline edits: A
let saved = falseguard ensures only one write per edit increateEditableSelectCellandcreateEditableDateOnlyCell. - Horizontal scroll lost:
scrollLeftis now saved and restored alongsidescrollTopin 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
slideInRowCSS animation that caused rows to disappear then pop in; focus now usesrequestAnimationFrameinstead of a 150mssetTimeout. - "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
completedandstatustoupdateTask(). - TaskDetailView effort remaining not saved:
commitCompletedhandler now saves botheffortCompletedandeffortRemainingin a single update. - GanttView checkbox desyncs status: Same fix as BoardView.
- GridView showCompleted filter ignored in renderTableBody: Added
showCompletedfiltering insiderenderTableBody(). - GridView auto-scroll wrong selector: Fixed from
.planner-grid-wrapperto.planner-grid-content. - GanttView resizer listener leak: Added
activeResizerCleanuptracking. - DashboardView modal DOM leak + missing Escape handler: Added
activeModal/activeOverlaytracking anddismissModal()cleanup. - DependencyGraphView double-click opens nothing: Double-click now calls
plugin.openTaskDetail(). - DependencyGraphView stale canvas after drag: Added
needsRefreshflag that triggers redraw on drag end. - TaskDetailView subtask drag corrupts array:
handleSubtaskDropnow clones the subtask array before splice. - TaskDetailView duration local date parsing:
renderDurationRownow 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
updateSortIndicatorscode: Removed unreferenced method. - BoardView bucket drag off-by-one: Adjusted
targetIndexwhen 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
scanFileinstead of per-line calls. - DailyNoteTaskScanner file rename colon split: Now uses
lastIndexOf(':')to safely extract line numbers from paths containing colons.
Changed
TaskStoregainedgetCachedRawData()public accessor andaddTaskAtIndex(title, index, overrides?)method.TaskStore.rollUpParentFields()now aggregates cost data (estimated + actual) from children.- GridView column menu now uses
setChecked()for native checkmark indicators. PlannerTaskinterface extended withcostEstimate,costActual,costType,hourlyRate.PlannerProjectinterface extended withbudgetTotal,defaultHourlyRate,currencySymbol.