From aa5c207a2aa278fce5b4a2592e8efffbb6bbccf0 Mon Sep 17 00:00:00 2001 From: Christopher Loverich <1010084+cloverich@users.noreply.github.com> Date: Sun, 22 Dec 2024 07:17:01 -0800 Subject: [PATCH] fix DATABASE_URL, default journal, navigate; track saves - remove legacy CACHE_DIR key; update DATABSE_URL reference - fix issue with default journal setting on import - fix navigate back from loading screen - track and log documents saves Future change should be smarter about saving documents, reducing fs writes and alllowing user to leave note view while save runs in background --- src/electron/userFilesInit.js | 1 - src/preload/client/documents.ts | 10 +++++++--- src/preload/client/index.ts | 4 ++++ src/preload/client/preferences.ts | 4 ++-- src/preload/client/sync.ts | 11 ++++++++--- src/views/edit/EditableDocument.ts | 13 ++++++++++--- src/views/edit/loading.tsx | 6 ++++-- src/views/edit/useEditableDocument.ts | 9 ++++++++- src/views/preferences/index.tsx | 2 +- 9 files changed, 44 insertions(+), 16 deletions(-) diff --git a/src/electron/userFilesInit.js b/src/electron/userFilesInit.js index 38f5bd4..c038cb1 100644 --- a/src/electron/userFilesInit.js +++ b/src/electron/userFilesInit.js @@ -13,7 +13,6 @@ const { ensureDir } = require("./ensureDir"); */ exports.initUserFilesDir = (userDataDir) => { initDir("NOTES_DIR", path.join(userDataDir, "/notes")); - initDir("CACHE_DIR", userDataDir); initDir("SETTINGS_DIR", userDataDir); }; diff --git a/src/preload/client/documents.ts b/src/preload/client/documents.ts index 09dfd70..769a1b2 100644 --- a/src/preload/client/documents.ts +++ b/src/preload/client/documents.ts @@ -214,13 +214,16 @@ export class DocumentsClient { if (!args.id) throw new Error("id required to update document"); args.frontMatter.tags = Array.from(new Set(args.frontMatter.tags)); + // todo: I think we accept this from the client now and just expect + // callers to update updatedAt, to support importers and sync manually configuring + // this... args.frontMatter.updatedAt = args.frontMatter.updatedAt || new Date().toISOString(); const content = this.prependFrontMatter(args.content, args.frontMatter); - const origDoc = await this.findById({ id: args.id! }); - await this.files.uploadDocument({ id: args.id!, content }, args.journal); + const origDoc = await this.findById({ id: args.id }); + await this.files.uploadDocument({ id: args.id, content }, args.journal); // sigh; this is a bit of a mess. if (origDoc.journal !== args.journal) { @@ -233,7 +236,7 @@ export class DocumentsClient { } await this.updateIndex({ - id: args.id!, + id: args.id, content, journal: args.journal, frontMatter: args.frontMatter, @@ -338,6 +341,7 @@ export class DocumentsClient { ); } + await trx("document_links").where({ documentId: id }).del(); await this.addNoteLinks(trx, id!, content); }); }; diff --git a/src/preload/client/index.ts b/src/preload/client/index.ts index 0aabc77..0221604 100644 --- a/src/preload/client/index.ts +++ b/src/preload/client/index.ts @@ -27,6 +27,10 @@ const knex = Knex({ connection: { filename: settings.get("DATABASE_URL") as string, }, + // https://knexjs.org/guide/query-builder.html#insert + // don't replace undefined with "DEFAULT" in insert statements; replace + // it with NULL instead (SQLite raises otherwise) + useNullAsDefault: true, }); export { GetDocumentResponse } from "./types"; diff --git a/src/preload/client/preferences.ts b/src/preload/client/preferences.ts index ca80a39..cc2f65e 100644 --- a/src/preload/client/preferences.ts +++ b/src/preload/client/preferences.ts @@ -2,7 +2,7 @@ import { ipcRenderer } from "electron"; import Store from "electron-store"; export interface Preferences { - CACHE_DIR: string; + DATABASE_URL: string; DEFAULT_JOURNAL: string | null; ARCHIVED_JOURNALS: Record; NOTES_DIR: string; @@ -10,7 +10,7 @@ export interface Preferences { } const defaults = (): Preferences => ({ - CACHE_DIR: "", + DATABASE_URL: "", DEFAULT_JOURNAL: null, ARCHIVED_JOURNALS: {}, NOTES_DIR: "", diff --git a/src/preload/client/sync.ts b/src/preload/client/sync.ts index c0a3a43..f0301c8 100644 --- a/src/preload/client/sync.ts +++ b/src/preload/client/sync.ts @@ -136,14 +136,19 @@ export class SyncClient { } } - // Ensure default journal exists; attempt to declare one otherwise + // Ensure default journal exists; attempt to declare one. Otherwise, + // new documents will default to a journal that does not exist, and fail + // to create. const defaultJournal = await this.preferences.get("DEFAULT_JOURNAL"); if (!defaultJournal || !(defaultJournal in journals)) { console.log("updating default journal", defaultJournal, journals); - if (journals.length) { - await this.preferences.set("DEFAULT_JOURNAL", journals[0]); + if (Object.keys(journals).length) { + await this.preferences.set("DEFAULT_JOURNAL", Object.keys(journals)[0]); + } else { + await this.journals.create({ name: "default_journal" }); + await this.preferences.set("DEFAULT_JOURNAL", "default_journal"); } } diff --git a/src/views/edit/EditableDocument.ts b/src/views/edit/EditableDocument.ts index ad1f4fb..cdd2849 100644 --- a/src/views/edit/EditableDocument.ts +++ b/src/views/edit/EditableDocument.ts @@ -55,6 +55,11 @@ export class EditableDocument { slateContent: SlateCustom.SlateNode[]; @observable private changeCount = 0; + // todo: save queue. I'm saving too often, but need to do this until I allow exiting note + // while save is in progress; track and report saveCount to discover if this is a major issue + // or not. + saveCount = 0; + // reaction clean-up when component unmounts; see constructor teardown?: IReactionDisposer; @@ -135,13 +140,15 @@ export class EditableDocument { journal: this.journal, content: this.content, id: this.id, - frontMatter: this.frontMatter, + frontMatter: toJS(this.frontMatter), }), ); + this.saveCount++; } catch (err) { this.saving = false; this.dirty = true; wasError = true; + console.error("Error saving document", err); toaster.danger(JSON.stringify(err)); } finally { this.saving = false; @@ -151,8 +158,8 @@ export class EditableDocument { if (this.dirty && !wasError) this.save(); } }, - 5000, - { trailing: true }, + 3000, + { leading: true }, ); del = async () => { diff --git a/src/views/edit/loading.tsx b/src/views/edit/loading.tsx index 85299c2..20103dd 100644 --- a/src/views/edit/loading.tsx +++ b/src/views/edit/loading.tsx @@ -23,7 +23,7 @@ export const EditLoadingComponent = observer((props: LoadingComponentProps) => { border="none" icon={ChevronLeftIcon} className="drag-none" - onClick={() => {}} + onClick={() => navigate(-1)} marginRight={8} > Back to documents @@ -32,7 +32,9 @@ export const EditLoadingComponent = observer((props: LoadingComponentProps) => { - + + {props.error && props.error?.message} + diff --git a/src/views/edit/useEditableDocument.ts b/src/views/edit/useEditableDocument.ts index 6c42481..ca65941 100644 --- a/src/views/edit/useEditableDocument.ts +++ b/src/views/edit/useEditableDocument.ts @@ -66,7 +66,14 @@ export function useEditableDocument(documentId: string) { load(); return () => { - if (state.document?.teardown) state.document.teardown(); + if (state.document?.teardown) { + console.log( + `save count for ${state.document.id}: ${state.document.saveCount}`, + ); + state.document.teardown(); + } + if (state.document?.saveCount) + console.log("saved", state.document.saveCount, "times"); }; }, [documentId]); diff --git a/src/views/preferences/index.tsx b/src/views/preferences/index.tsx index a4a4763..a58aff0 100644 --- a/src/views/preferences/index.tsx +++ b/src/views/preferences/index.tsx @@ -194,7 +194,7 @@ const Preferences = observer(() => {

The current Chronicles cache is located at{" "} - {store.preferences.CACHE_DIR} + {store.preferences.DATABASE_URL}