Save and load task notes
This commit is contained in:
@@ -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) => ({
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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(),
|
||||||
|
|||||||
@@ -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[];
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user