feat(tasks): dual-write tasks to SQLite alongside localStorage; boot-load from SQLite on startup

This commit is contained in:
2026-04-19 10:46:07 +01:00
parent 8d3d302b17
commit 0bce8e6ec4

View File

@@ -201,6 +201,18 @@ function loadTasks() {
export const tasks = $state(loadTasks());
// On boot in the desktop runtime, load canonical tasks from SQLite.
// localStorage remains the warm cache and fallback.
if (typeof window !== "undefined" && hasTauriRuntime()) {
invoke("list_tasks_cmd")
.then((sqliteTasks) => {
tasks.length = 0;
tasks.push(...sqliteTasks);
saveTasks();
})
.catch(() => {});
}
export function saveTasks() {
try {
localStorage.setItem(TASKS_KEY, JSON.stringify(tasks));
@@ -208,7 +220,7 @@ export function saveTasks() {
}
export function addTask(task) {
tasks.unshift({
const newTask = {
id: crypto.randomUUID(),
text: task.text,
bucket: task.bucket || "inbox",
@@ -220,9 +232,20 @@ export function addTask(task) {
createdAt: new Date().toISOString(),
sourceTranscriptId: task.sourceTranscriptId || null,
notes: "",
});
};
tasks.unshift(newTask);
saveTasks();
broadcastTasks();
if (hasTauriRuntime()) {
invoke("create_task_cmd", {
request: {
id: newTask.id,
text: newTask.text,
bucket: newTask.bucket,
sourceTranscriptId: newTask.sourceTranscriptId,
},
}).catch(() => {});
}
}
export function updateTask(id, updates) {
@@ -240,15 +263,24 @@ export function deleteTask(id) {
tasks.splice(idx, 1);
saveTasks();
broadcastTasks();
if (hasTauriRuntime()) {
invoke("delete_task_cmd", { id }).catch(() => {});
}
}
}
export function completeTask(id) {
updateTask(id, { done: true, doneAt: new Date().toISOString() });
if (hasTauriRuntime()) {
invoke("complete_task_cmd", { id }).catch(() => {});
}
}
export function uncompleteTask(id) {
updateTask(id, { done: false, doneAt: null });
if (hasTauriRuntime()) {
invoke("uncomplete_task_cmd", { id }).catch(() => {});
}
}
// ---- BroadcastChannel for multi-window task sync ----