core: restoring note history with title

This commit is contained in:
Ammar Ahmed
2026-01-10 12:55:21 +05:00
committed by Abdullah Atta
parent 1e023500be
commit e6eb71a484
5 changed files with 125 additions and 28 deletions

View File

@@ -214,28 +214,90 @@ test("note history item can be created by setting note title", () =>
));
test("note history item can be created by setting note title and content both", () =>
noteTest({ title: "Test note", ...TEST_NOTE, sessionId: "notesession" }).then(
noteTest({
...TEST_NOTE,
title: "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.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,
sessionId: "notesession"
});
expect(content.data).toBe(TEST_NOTE.content.data);
expect(content.title).toBe("Test note");
await db.notes.add({
id: id,
title: "Test note",
sessionId: "notesession"
});
expect(content.data).toBe(TEST_NOTE.content.data);
expect(content.title).toBe("Test note");
}));
test("restoring an old session should replace note's content title", () =>
noteTest({ title: "Test note", sessionId: Date.now() }).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 delay(1000);
let newTitle = "Test note (edited)";
const sessionId = `${Date.now() + 10000}`;
await db.notes.add({
id: id,
content: TEST_NOTE.content
title: newTitle,
sessionId
});
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");
const [, firstVersion] = await db.noteHistory
.get(id)
.items(undefined, { sortBy: "dateModified", sortDirection: "desc" });
expect(firstVersion.id).not.toBe(`${id}_${sessionId}`);
await db.noteHistory.restore(firstVersion.id);
const title = (await db.notes.note(id)).title;
expect(title).toBe("Test note");
}
));
test("restoring an old session should replace note's content and title", () =>
noteTest({ ...TEST_NOTE, title: "Test note", sessionId: Date.now() }).then(
async ({ db, id }) => {
await delay(1000);
let newTitle = "Test note (edited)";
let editedContent = {
data: TEST_NOTE.content.data + "<p>Some new content</p>",
type: "tiptap"
};
const sessionId = `${Date.now() + 10000}`;
await db.notes.add({
id: id,
title: newTitle,
sessionId,
content: editedContent
});
const [, firstVersion] = await db.noteHistory
.get(id)
.items(undefined, { sortBy: "dateModified", sortDirection: "desc" });
expect(firstVersion.id).not.toBe(`${id}_${sessionId}`);
await db.noteHistory.restore(firstVersion.id);
const title = (await db.notes.note(id)).title;
expect(title).toBe("Test note");
const contentId = (await db.notes.note(id)).contentId;
expect((await db.content.get(contentId)).data).toBe(
TEST_NOTE.content.data
);
}
));

View File

@@ -20,7 +20,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
import Database from "../api/index.js";
import { isCipher } from "../utils/crypto.js";
import { FilteredSelector, SQLCollection } from "../database/sql-collection.js";
import { HistorySession, isDeleted, NoteContent } from "../types.js";
import { HistorySession, isDeleted, Note, NoteContent } from "../types.js";
import { makeSessionContentId } from "../utils/id.js";
import { ICollection } from "./collection.js";
import { SessionContent } from "./session-content.js";
@@ -190,22 +190,48 @@ export class NoteHistory implements ICollection {
if (!note || !content) return;
if (session.locked && isCipher(content.data)) {
const sessionId = `${Date.now()}`;
await this.db.content.add({
id: note.contentId,
noteId: session.noteId,
sessionId: `${Date.now()}`,
sessionId: sessionId,
data: content.data,
type: content.type
});
} else if (content.data && content.type && !isCipher(content.data)) {
await this.db.notes.add({
if (content.title) {
await this.db.notes.add({
id: session.noteId,
sessionId: sessionId,
title: content.title
});
}
} else if (
(content.data && content.type && !isCipher(content.data)) ||
content.title
) {
const note: Partial<
Note & {
content: NoteContent<false>;
sessionId: string;
}
> = {
id: session.noteId,
sessionId: `${Date.now()}`,
content: {
sessionId: `${Date.now()}`
};
if (content.data && content.type && !isCipher(content.data)) {
note.content = {
data: content.data,
type: content.type
}
});
};
}
if (content.title) {
note.title = content.title;
}
await this.db.notes.add(note);
}
}

View File

@@ -6552,6 +6552,10 @@ msgstr "This may take a while"
msgid "This must only be used for troubleshooting. Using it regularly for sync is not recommended and will lead to unexpected data loss and other issues. If you are having persistent issues with sync, please report them to us at support@streetwriters.co."
msgstr "This must only be used for troubleshooting. Using it regularly for sync is not recommended and will lead to unexpected data loss and other issues. If you are having persistent issues with sync, please report them to us at support@streetwriters.co."
#: src/strings.ts:2623
msgid "This note is empty"
msgstr "This note is empty"
#: src/strings.ts:1594
msgid "This note is locked"
msgstr "This note is locked"

View File

@@ -6511,6 +6511,10 @@ msgstr ""
msgid "This must only be used for troubleshooting. Using it regularly for sync is not recommended and will lead to unexpected data loss and other issues. If you are having persistent issues with sync, please report them to us at support@streetwriters.co."
msgstr ""
#: src/strings.ts:2623
msgid "This note is empty"
msgstr ""
#: src/strings.ts:1594
msgid "This note is locked"
msgstr ""

View File

@@ -2631,5 +2631,6 @@ Use this if changes from other devices are not appearing on this device. This wi
unsetExpiry: () => t`Unset expiry`,
expiryDate: () => t`Expiry date`,
exportCsv: () => t`Export CSV`,
importCsv: () => t`Import CSV`
importCsv: () => t`Import CSV`,
noContent: () => t`This note is empty`
};