web: delete locked notes on vault delete

Signed-off-by: 01zulfi <85733202+01zulfi@users.noreply.github.com>
This commit is contained in:
01zulfi
2026-02-13 17:52:53 +05:00
parent b7b474b245
commit 4942e2cbce
10 changed files with 2173 additions and 2129 deletions

View File

@@ -193,4 +193,16 @@ export class SettingsViewModel {
.locator("input");
await titleFormatInput.fill(format);
}
async deleteVault(password: string) {
const item = await this.navigation.findItem("Vault");
await item?.click();
const deleteVaultButton = this.page
.locator(getTestId("setting-delete-vault"))
.locator("button");
await deleteVaultButton.click();
await fillPasswordDialog(this.page, password);
}
}

View File

@@ -192,6 +192,21 @@ export async function createHistorySession(page: Page, locked = false) {
};
}
function randomWord(length = 5) {
const chars = "abcdefghijklmnopqrstuvwxyz";
return Array.from(
{ length },
() => chars[Math.floor(Math.random() * chars.length)]
).join("");
}
function randomNote(): Note {
return {
title: `${randomWord()} ${randomWord()}`,
content: Array.from({ length: 5 }, () => randomWord()).join(" ")
};
}
export {
USER,
NOTE,
@@ -207,5 +222,6 @@ export {
orderByOptions,
sortByOptions,
groupByOptions,
APP_LOCK_PASSWORD
APP_LOCK_PASSWORD,
randomNote
};

View File

@@ -19,7 +19,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
import { test, expect } from "@playwright/test";
import { AppModel } from "./models/app.model";
import { getTestId, NOTE, PASSWORD } from "./utils";
import { getTestId, NOTE, PASSWORD, randomNote, USER } from "./utils";
test("locking a note should show vault unlocked status", async ({ page }) => {
const app = new AppModel(page);
@@ -125,3 +125,28 @@ test("clicking on vault unlocked status should lock the readonly note", async ({
expect(await note?.isLockedNotePasswordFieldVisible()).toBe(true);
});
test("deleting the vault should permanently delete locked notes", async ({
page
}) => {
const app = new AppModel(page);
await app.auth.goto();
await app.auth.login(USER.CURRENT);
const noteData = randomNote();
let notes = await app.goToNotes();
let note = await notes.createNote(noteData);
await note?.contextMenu.lock(PASSWORD);
const settings = await app.goToSettings();
await settings.deleteVault(USER.CURRENT.password!);
await settings.close();
notes = await app.goToNotes();
note = await notes.findNote(noteData);
expect(note).toBeUndefined();
const trash = await app.goToTrash();
const trashNote = await trash.findItem(noteData.title);
expect(trashNote).toBeUndefined();
});

View File

@@ -22,6 +22,7 @@ import { showPasswordDialog } from "../dialogs/password-dialog";
import { showToast } from "../utils/toast";
import { VAULT_ERRORS } from "@notesnook/core";
import { strings } from "@notesnook/intl";
import { useStore as useAppStore } from "../stores/app-store";
class Vault {
static async createVault() {
@@ -34,6 +35,7 @@ class Vault {
},
validate: async ({ password }) => {
await db.vault.create(password);
useAppStore.getState().setIsVaultCreated(true);
showToast("success", strings.vaultCreated());
return true;
}
@@ -63,25 +65,19 @@ class Vault {
if (!(await db.vault.exists())) return false;
const result = await showPasswordDialog({
title: strings.deleteVault(),
subtitle: strings.deleteVaultDesc(),
message: strings.deleteVaultDesc(),
inputs: {
password: {
label: strings.accountPassword(),
autoComplete: "current-password"
}
},
checks: {
deleteAllLockedNotes: {
text: strings.deleteAllNotes(),
default: false
}
},
validate: ({ password }) => {
return db.user.verifyPassword(password);
}
});
if (result) {
await db.vault.delete(result.deleteAllLockedNotes);
await db.vault.delete();
return true;
}
return false;

View File

@@ -42,9 +42,7 @@ export const VaultSettings: SettingsGroup[] = [
type: "button",
title: strings.create(),
action: () => {
Vault.createVault().then((res) => {
useAppStore.getState().setIsVaultCreated(res);
});
Vault.createVault();
},
variant: "secondary"
}

View File

@@ -206,7 +206,7 @@ test("clear vault", () =>
expect(await db.relations.from(vault, "note").has(id)).toBe(false);
}));
test("delete vault without deleting all locked notes", () =>
test("delete vault", () =>
noteTest().then(async ({ db, id }) => {
await db.vault.create("password");
await db.vault.add(id);
@@ -214,18 +214,6 @@ test("delete vault without deleting all locked notes", () =>
await db.vault.delete();
expect(await db.relations.from(vault, "note").has(id)).toBe(false);
expect(await db.vaults.default()).toBeUndefined();
}));
test("delete vault and delete all locked notes", () =>
noteTest().then(async ({ db, id }) => {
await db.vault.create("password");
await db.vault.add(id);
const vault = await db.vaults.default();
await db.vault.delete(true);
expect(await db.relations.from(vault, "note").has(id)).toBe(false);
expect(await db.notes.exists(id)).toBe(false);
expect(await db.vaults.default()).toBeUndefined();

View File

@@ -154,15 +154,13 @@ export default class Vault {
}
}
async delete(deleteAllLockedNotes = false) {
async delete() {
const vault = await this.db.vaults.default();
if (!vault) return;
if (deleteAllLockedNotes) {
const relations = await this.db.relations.from(vault, "note").get();
const lockedIds = relations.map((r) => r.toId);
await this.db.notes.remove(...lockedIds);
}
const relations = await this.db.relations.from(vault, "note").get();
const lockedIds = relations.map((r) => r.toId);
await this.db.notes.remove(...lockedIds);
await this.db.vaults.remove(vault.id);
this.password = undefined;

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1173,7 +1173,9 @@ $day$: Current day (eg. Monday)`,
changeVaultPasswordDesc: () =>
t`All locked notes will be re-encrypted with the new password.`,
clearVaultDesc: () => t`Remove all notes from the vault.`,
deleteVaultDesc: () => t`Delete vault (and optionally remove all notes).`,
deleteVaultDesc: () => t`All locked notes will be PERMANENTLY DELETED.
If you want to keep them, remove locked notes from the vault.`,
biometricUnlock: () => t`Biometric unlocking`,
biometricUnlockDesc: () => t`Unlock your vault with biometric authentication`,
revokeBiometricUnlock: () => t`Revoke biometric unlocking`,