Save and load task notes

This commit is contained in:
2026-02-27 23:42:44 +01:00
parent deb8c86d0d
commit 13f6fe2c3f
5 changed files with 29 additions and 8 deletions
+5 -2
View File
@@ -33,13 +33,16 @@ export default function Router({
switch (entity.type) { switch (entity.type) {
case "todo": { case "todo": {
const createTask = (statusId: string) => { const createTask = (statusId: string) => {
const now = new Date().getTime();
const task: Task = { const task: Task = {
id: id("task"), id: id("task"),
title: "New task", title: "New task",
statusId, statusId,
tagIds: [], tagIds: [],
createdAt: new Date().getTime(), // initialize empty rich document notes
updatedAt: new Date().getTime(), doc: { version: "2.28.0", time: now, blocks: [] },
createdAt: now,
updatedAt: now,
}; };
updateEntity(entityId, (e) => ({ updateEntity(entityId, (e) => ({
+10 -5
View File
@@ -26,11 +26,16 @@ export default function DocDialog({
tags: Record<TagId, Tag>; tags: Record<TagId, Tag>;
children: React.ReactNode; children: React.ReactNode;
}) { }) {
const [doc, setDoc] = useState<OutputData>({ // if there is an existing document on the task use it, otherwise start with a blank one
version: "2.28.0", const doc = task.doc || { version: "2.28.0", time: Date.now(), blocks: [] };
time: Date.now(),
blocks: [], const handleDocChange = (newDoc: OutputData) => {
setTask({
...task,
doc: newDoc,
updatedAt: Date.now(),
}); });
};
return ( return (
<Dialog> <Dialog>
@@ -62,7 +67,7 @@ export default function DocDialog({
</DialogHeader> </DialogHeader>
<ScrollArea className="h-[60vh]"> <ScrollArea className="h-[60vh]">
<DocView key={0} doc={doc} setDoc={setDoc} /> <DocView key={task.id} doc={doc} setDoc={handleDocChange} />
</ScrollArea> </ScrollArea>
</DialogContent> </DialogContent>
</Dialog> </Dialog>
+5
View File
@@ -168,6 +168,7 @@ export function exportTodoAsCsv(todo: TodoEntity): string {
const headers = [ const headers = [
"Title", "Title",
"Description", "Description",
"Doc",
"Status", "Status",
"Tags", "Tags",
"Created", "Created",
@@ -176,6 +177,7 @@ export function exportTodoAsCsv(todo: TodoEntity): string {
const rows = Object.values(todo.tasks).map((task) => [ const rows = Object.values(todo.tasks).map((task) => [
task.title, task.title,
task.description || "", task.description || "",
task.doc ? JSON.stringify(task.doc) : "",
todo.config.statuses.find((s) => s.id === task.statusId)?.name || "", todo.config.statuses.find((s) => s.id === task.statusId)?.name || "",
task.tagIds.map((id) => todo.tags[id]?.name || "").join(";"), task.tagIds.map((id) => todo.tags[id]?.name || "").join(";"),
new Date(task.createdAt).toISOString(), new Date(task.createdAt).toISOString(),
@@ -228,6 +230,9 @@ export function exportTodoAsMarkdown(todo: TodoEntity): string {
if (task.description) { if (task.description) {
markdown += `\n - ${task.description}`; markdown += `\n - ${task.description}`;
} }
if (task.doc) {
markdown += `\n\n${docToMarkdown(task.doc)}`;
}
markdown += "\n"; markdown += "\n";
} }
} }
+5
View File
@@ -96,6 +96,7 @@ export function importTodoFromCsv(
const descriptionIndex = headers.indexOf("description"); const descriptionIndex = headers.indexOf("description");
const statusIndex = headers.indexOf("status"); const statusIndex = headers.indexOf("status");
const tagsIndex = headers.indexOf("tags"); const tagsIndex = headers.indexOf("tags");
const docIndex = headers.indexOf("doc");
if (titleIndex === -1) { if (titleIndex === -1) {
errors.push("CSV must have a 'Title' column"); errors.push("CSV must have a 'Title' column");
@@ -145,6 +146,10 @@ export function importTodoFromCsv(
id: taskId, id: taskId,
title, title,
description: descriptionIndex !== -1 ? values[descriptionIndex] : "", description: descriptionIndex !== -1 ? values[descriptionIndex] : "",
doc:
docIndex !== -1 && values[docIndex]
? JSON.parse(values[docIndex])
: undefined,
statusId, statusId,
tagIds, tagIds,
createdAt: Date.now(), createdAt: Date.now(),
+3
View File
@@ -70,6 +70,9 @@ export interface Task {
title: string; title: string;
description?: string; description?: string;
/** rich notes/documentation for the task */
doc?: OutputData;
statusId: string; statusId: string;
tagIds: TagId[]; tagIds: TagId[];