diff --git a/PR.md b/PR.md new file mode 100644 index 00000000..5213be6a --- /dev/null +++ b/PR.md @@ -0,0 +1,32 @@ +# fix/project-card-refresh + +## Refresh project cards after subtask edits + +Project cards now refresh immediately when subtasks are added or removed via the edit modal. This ensures the project indicator and subtask list update without requiring a manual reload. + +Examples (illustrative): + +- Assigning subtasks to a task now turns it into a project card right after Save. +- Removing the last subtask now returns the card to a normal task immediately. + +## Changelog + +- Invalidate the project index after subtask edits in the task edit modal. +- Emit a task-updated event for the parent task to refresh visible views. + +## Risks / Notes + +- This is a minimal fix and does not address the broader, system-wide refresh architecture. A more robust approach is under discussion in: https://github.com/callumalpass/tasknotes/issues/1423 +- The project index invalidation is global, which can be more expensive in large vaults. This is an intentional trade-off for immediate correctness. + +## Tests + +- `npm run i18n:sync` +- `npm run lint` (warnings only; matches `upstream/main`) +- `node generate-release-notes-import.mjs` +- `npm run typecheck` +- `npm run test:ci -- --verbose` (fails in `upstream/main`: `tests/unit/issues/due-date-timezone-inconsistency.test.ts`) +- `npm run test:integration` +- `npm run test:performance` (no tests found) +- `npm run build` (missing OAuth IDs: `GOOGLE_OAUTH_CLIENT_ID`, `MICROSOFT_OAUTH_CLIENT_ID`) +- `npm run test:build` diff --git a/src/modals/TaskEditModal.ts b/src/modals/TaskEditModal.ts index a0252dd5..ccc11657 100644 --- a/src/modals/TaskEditModal.ts +++ b/src/modals/TaskEditModal.ts @@ -2,7 +2,7 @@ import { App, Notice, TFile, TAbstractFile, setIcon, setTooltip } from "obsidian"; import TaskNotesPlugin from "../main"; import { TaskModal } from "./TaskModal"; -import { TaskDependency, TaskInfo } from "../types"; +import { TaskDependency, TaskInfo, EVENT_TASK_UPDATED } from "../types"; import { getCurrentTimestamp, formatDateForStorage, @@ -691,6 +691,15 @@ export class TaskEditModal extends TaskModal { if (hasSubtaskChanges) { await this.applySubtaskChanges(updatedTask); + this.plugin.projectSubtasksService?.invalidateProjectIndex(); + if (!hasTaskChanges) { + this.plugin.emitter.trigger(EVENT_TASK_UPDATED, { + path: updatedTask.path, + task: updatedTask, + taskInfo: updatedTask, + updatedTask, + }); + } } if (this.unresolvedBlockingEntries.length > 0) { diff --git a/src/services/ProjectSubtasksService.ts b/src/services/ProjectSubtasksService.ts index f1ca1bc2..21f83c01 100644 --- a/src/services/ProjectSubtasksService.ts +++ b/src/services/ProjectSubtasksService.ts @@ -238,6 +238,14 @@ export class ProjectSubtasksService { } } + /** + * Mark the project index as stale so it rebuilds on next access. + */ + invalidateProjectIndex(): void { + this.projectIndex.clear(); + this.indexLastBuilt = 0; + } + /** * Cleanup when service is destroyed */