From 2c078de2c0957a452df6cccbc731faff037296c1 Mon Sep 17 00:00:00 2001 From: Ammar Ahmed Date: Sat, 10 Jan 2026 11:01:51 +0500 Subject: [PATCH] core: save note title in note session history item --- packages/core/__tests__/note-history.test.js | 40 +++++++++++++++++++ packages/core/src/collections/note-history.ts | 14 +++++-- packages/core/src/collections/notes.ts | 7 ++++ .../core/src/collections/session-content.ts | 36 ++++++++++++----- packages/core/src/database/migrations.ts | 9 ++++- packages/core/src/types.ts | 1 + 6 files changed, 93 insertions(+), 14 deletions(-) diff --git a/packages/core/__tests__/note-history.test.js b/packages/core/__tests__/note-history.test.js index c53ac86be..66f3ed062 100644 --- a/packages/core/__tests__/note-history.test.js +++ b/packages/core/__tests__/note-history.test.js @@ -199,3 +199,43 @@ test("locking an old note should clear its history", () => expect(await db.noteHistory.get(id).count()).toBe(0); } )); + +test("note history item can be created by setting note title", () => + noteTest({ title: "Test note", sessionId: "notesession" }).then( + async ({ db, id }) => { + expect(await db.noteHistory.get(id).count()).toBe(1); + const history = await db.noteHistory.get(id); + const items = await history.items(); + const content = await db.noteHistory.sessionContent.get( + items[0].sessionContentId + ); + expect(content.title).toBe("Test note"); + } + )); + +test("note history item can be created by setting note title and content both", () => + noteTest({ title: "Test note", ...TEST_NOTE, sessionId: "notesession" }).then( + async ({ db, id }) => { + expect(await db.noteHistory.get(id).count()).toBe(1); + const history = db.noteHistory.get(id); + const items = await history.items(); + const content = await db.noteHistory.sessionContent.get( + items[0].sessionContentId + ); + expect(await db.noteHistory.sessionContent.collection.count()).toBe(1); + expect(content.data).toBe(TEST_NOTE.content.data); + expect(content.title).toBe("Test note"); + await db.notes.add({ + id: id, + content: TEST_NOTE.content + }); + expect(content.data).toBe(TEST_NOTE.content.data); + expect(content.title).toBe("Test note"); + await db.notes.add({ + id: id, + title: "Test note" + }); + expect(content.data).toBe(TEST_NOTE.content.data); + expect(content.title).toBe("Test note"); + } + )); diff --git a/packages/core/src/collections/note-history.ts b/packages/core/src/collections/note-history.ts index f56da3afb..bd8275baa 100644 --- a/packages/core/src/collections/note-history.ts +++ b/packages/core/src/collections/note-history.ts @@ -74,13 +74,19 @@ export class NoteHistory implements ICollection { async add( sessionId: string, - content: NoteContent & { noteId: string; locked: boolean } + content: Partial> & { + noteId: string; + locked?: boolean; + title?: string; + } ) { const { noteId, locked } = content; sessionId = `${noteId}_${sessionId}`; if (await this.collection.exists(sessionId)) { - await this.collection.update([sessionId], { locked }); + await this.collection.update([sessionId], { + locked + }); } else { await this.collection.upsert({ type: "session", @@ -93,7 +99,9 @@ export class NoteHistory implements ICollection { locked }); } + await this.sessionContent.add(sessionId, content, locked); + await this.cleanup(noteId); return sessionId; @@ -189,7 +197,7 @@ export class NoteHistory implements ICollection { data: content.data, type: content.type }); - } else if (content.data && !isCipher(content.data)) { + } else if (content.data && content.type && !isCipher(content.data)) { await this.db.notes.add({ id: session.noteId, sessionId: `${Date.now()}`, diff --git a/packages/core/src/collections/notes.ts b/packages/core/src/collections/notes.ts index 03085d14c..7d3364f4d 100644 --- a/packages/core/src/collections/notes.ts +++ b/packages/core/src/collections/notes.ts @@ -205,6 +205,13 @@ export class Notes implements ICollection { }); this.totalNotes++; } + + if (item.sessionId) { + await this.db.noteHistory.add(item.sessionId, { + title: item.title, + noteId: id + }); + } }); return id; } diff --git a/packages/core/src/collections/session-content.ts b/packages/core/src/collections/session-content.ts index 9f41de393..1931b0f7f 100644 --- a/packages/core/src/collections/session-content.ts +++ b/packages/core/src/collections/session-content.ts @@ -44,30 +44,45 @@ export class SessionContent implements ICollection { async add( sessionId: string, - content: NoteContent, - locked: TLocked + content: Partial> & { title?: string }, + locked?: TLocked ) { if (!sessionId || !content) return; // const data = // locked || isCipher(content.data) // ? content.data // : await this.db.compressor().compress(content.data); - await this.collection.upsert({ + + const sessionContentItemId = makeSessionContentId(sessionId); + const sessionItem: Partial = { type: "sessioncontent", - id: makeSessionContentId(sessionId), - data: content.data, - contentType: content.type, + id: sessionContentItemId, compressed: false, localOnly: true, - locked, + locked: locked || false, dateCreated: Date.now(), dateModified: Date.now() - }); + }; + + if (content.data && content.type) { + sessionItem.data = content.data; + sessionItem.contentType = content.type; + } + + if (content.title) { + sessionItem.title = content.title; + } + + if (await this.collection.exists(sessionContentItemId)) { + this.collection.update([sessionContentItemId], sessionItem); + } else { + await this.collection.upsert(sessionItem as SessionContentItem); + } } async get( sessionContentId: string - ): Promise | undefined> { + ): Promise & { title: string }> | undefined> { const session = await this.collection.get(sessionContentId); if (!session || isDeleted(session)) return; @@ -90,7 +105,8 @@ export class SessionContent implements ICollection { session.compressed && !isCipher(session.data) ? await compressor.decompress(session.data) : session.data, - type: session.contentType + type: session.contentType, + title: session.title }; } diff --git a/packages/core/src/database/migrations.ts b/packages/core/src/database/migrations.ts index 9abf52e73..738fd6fe0 100644 --- a/packages/core/src/database/migrations.ts +++ b/packages/core/src/database/migrations.ts @@ -414,7 +414,14 @@ export class NNMigrationProvider implements MigrationProvider { await db.schema .createIndex("note_expiry_date") .on("notes") - .expression(sql`expiryDate ->> '$.value'`) + .expression(sql`expiryDate ->> '$.value'`); + } + }, + "a-2026-01-09": { + async up(db) { + await db.schema + .alterTable("sessioncontent") + .addColumn("title", "text") .execute(); } } diff --git a/packages/core/src/types.ts b/packages/core/src/types.ts index 6ea861fbe..75c6bb0a3 100644 --- a/packages/core/src/types.ts +++ b/packages/core/src/types.ts @@ -433,6 +433,7 @@ export interface SessionContentItem extends BaseItem<"sessioncontent"> { compressed: boolean; localOnly: boolean; locked: boolean; + title: string; } export type TrashCleanupInterval = 1 | 7 | 30 | 365 | -1;