diff --git a/src/components/TaskDetail.tsx b/src/components/TaskDetail.tsx index d17b067..f51f9fa 100644 --- a/src/components/TaskDetail.tsx +++ b/src/components/TaskDetail.tsx @@ -1,6 +1,6 @@ -import { type Component, createEffect, createSignal, For, createMemo } from "solid-js"; +import { type Component, createEffect, createSignal, For, createMemo, onCleanup } from "solid-js"; import { Sheet, SheetContent } from "@/components/ui/sheet"; -import { type Task, removeTask, restoreTask, updateTask, saveTaskAsTemplate, shareTask, revokeShare, splitTask, loadTaskContent, currentTaskContext } from "@/store"; +import { type Task, removeTask, restoreTask, updateTask, saveTaskAsTemplate, shareTask, revokeShare, splitTask, loadTaskContent, currentTaskContext, cleanupTaskAttachments } from "@/store"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover"; import { ArrowUpCircle, Clock, Calendar, Type, Trash2, X, Copy, MoreHorizontal, Gauge, Share2, UserMinus, GitBranch, Tag, Settings } from "lucide-solid"; @@ -110,9 +110,31 @@ export const TaskDetail: Component = (props) => { }, 1000); }; - // Removed onCleanup to avoid lockup + // Sync activeTaskId for slash commands and run cleanup on unmount/change + createEffect(() => { + const currentTaskId = props.task.id; + onCleanup(() => { + // 1. Immediately flush any pending debounce updates for the outgoing task + if (debounceTimer) { + clearTimeout(debounceTimer); + if (pendingContent !== null) { + updateTask(currentTaskId, { content: pendingContent }); + } + } + // 2. Clear pending state + debounceTimer = undefined; + pendingContent = null; + + // 3. Trigger cleanup after a tiny delay so the updateTask above processes first + if (currentTaskId) { + setTimeout(() => { + cleanupTaskAttachments(currentTaskId).catch(console.error); + }, 100); + } + }); + }); const updateTitle = (val: string) => { setTitle(val); updateTask(props.task.id, { title: val }); diff --git a/src/store/index.ts b/src/store/index.ts index b132adc..d16d137 100644 --- a/src/store/index.ts +++ b/src/store/index.ts @@ -552,6 +552,35 @@ export const cleanupNoteAttachments = async (noteId: string) => { } }; +export const cleanupTaskAttachments = async (taskId: string) => { + if (!pb.authStore.isValid) return; + + try { + const task = store.tasks.find(t => t.id === taskId); + if (!task) return; + + const record = await pb.collection(TASGRID_COLLECTION).getOne(taskId); + if (!record.attachments || record.attachments.length === 0) return; + + const content = task.content || ""; + const filesToDelete: string[] = []; + for (const filename of record.attachments) { + if (!content.includes(filename)) { + filesToDelete.push(filename); + } + } + + if (filesToDelete.length > 0) { + await pb.collection(TASGRID_COLLECTION).update(taskId, { + "attachments-": filesToDelete + }); + console.log(`[CLEANUP] Deleted ${filesToDelete.length} orphaned attachment(s) for task ${taskId}`); + } + } catch (err) { + console.error("[CLEANUP] Failed to clean up orphaned task attachments:", err); + } +}; + const mapRecordToShareRule = (r: any): ShareRule => { return { id: r.id,