core: save note title in note session history item

This commit is contained in:
Ammar Ahmed
2026-01-10 11:01:51 +05:00
committed by Abdullah Atta
parent b373881b8b
commit 2c078de2c0
6 changed files with 93 additions and 14 deletions

View File

@@ -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");
}
));

View File

@@ -74,13 +74,19 @@ export class NoteHistory implements ICollection {
async add(
sessionId: string,
content: NoteContent<boolean> & { noteId: string; locked: boolean }
content: Partial<NoteContent<boolean>> & {
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()}`,

View File

@@ -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;
}

View File

@@ -44,30 +44,45 @@ export class SessionContent implements ICollection {
async add<TLocked extends boolean>(
sessionId: string,
content: NoteContent<TLocked>,
locked: TLocked
content: Partial<NoteContent<TLocked>> & { 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<SessionContentItem> = {
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<NoteContent<boolean> | undefined> {
): Promise<Partial<NoteContent<boolean> & { 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
};
}

View File

@@ -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();
}
}

View File

@@ -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;