global: add demo data seed

This commit is contained in:
Ammar Ahmed
2026-08-13 08:25:16 +05:00
parent b181655edc
commit bc2c31938b
8 changed files with 3879 additions and 6 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -448,7 +448,7 @@ export const ReferencesList = ({ item, close }: ReferencesListProps) => {
);
return (
<View style={{ height: "100%" }}>
<View style={{ height: "50%" }}>
<SheetProvider context="local" />
<View

View File

@@ -1848,6 +1848,126 @@ export const settingsGroups: SettingSection[] = [
}
},
description: getVersion()
},
// TEMPORARY — demo data seeder for the App Store / Play Store screenshots.
// Delete this section and app/common/seed-demo.ts once they are captured.
{
id: "seed-demo-account",
name: "Seed demo account",
icon: "database-plus",
description:
"Fills this account with the persona, notebooks, 44 notes, tags, colours, reminders and vault note used for the store screenshots. Run once, on an empty account.",
hidden: () => !__DEV__,
modifer: async () => {
presentDialog({
title: "Seed demo account",
paragraph:
"This adds 44 notes and creates a vault. Only run it on a fresh, empty account — it does not clean up after itself.",
positiveText: "Seed",
negativeText: strings.cancel(),
positivePress: async () => {
setTimeout(async () => {
startProgress({
title: "Seeding demo account",
paragraph: "Please wait, this takes about a minute."
});
try {
const { seedDemoAccount } = await import(
"../../common/seed-demo"
);
const result = await seedDemoAccount((message) => {
DatabaseLogger.info(`[seed] ${message}`);
startProgress({
title: "Seeding demo account",
paragraph: message
});
});
await refreshAllStores();
endProgress();
ToastManager.show({
heading: `Created ${result.notes} notes`,
message: "Vault password: demo-vault-2026",
type: "success",
context: "global"
});
} catch (e) {
endProgress();
DatabaseLogger.error(e);
ToastManager.error(
e as Error,
"Failed to seed demo account",
"global"
);
}
}, 300);
}
});
}
},
{
id: "clear-demo-data",
type: "danger",
name: "Delete all items",
icon: "database-remove",
description:
"Permanently deletes every note, notebook, tag, colour, reminder and the vault, then empties the trash. The account itself is kept. Cannot be undone.",
hidden: () => !__DEV__,
modifer: async () => {
presentDialog({
title: "Delete all items",
paragraph:
"This permanently deletes everything in this account — not just the demo data — and empties the trash. It cannot be undone. Type DELETE to confirm.",
input: true,
inputPlaceholder: "DELETE",
positiveText: strings.delete(),
negativeText: strings.cancel(),
positiveType: "errorShade",
positivePress: async (value) => {
if (value?.trim() !== "DELETE") {
ToastManager.error(
new Error("Type DELETE to confirm"),
undefined,
"local"
);
return false;
}
setTimeout(async () => {
startProgress({
title: "Deleting all items",
paragraph: "Please wait."
});
try {
const { clearAllData } = await import(
"../../common/seed-demo"
);
const counts = await clearAllData((message) => {
DatabaseLogger.info(`[seed] ${message}`);
startProgress({
title: "Deleting all items",
paragraph: message
});
});
await refreshAllStores();
endProgress();
ToastManager.show({
heading: `Deleted ${counts.notes} notes`,
message: `${counts.notebooks} notebooks, ${counts.tags} tags, ${counts.reminders} reminders`,
type: "success",
context: "global"
});
} catch (e) {
endProgress();
DatabaseLogger.error(e);
ToastManager.error(
e as Error,
"Failed to delete all items",
"global"
);
}
}, 300);
}
});
}
}
]
}

View File

@@ -1,12 +1,12 @@
{
"name": "@notesnook/mobile",
"version": "3.4.5",
"version": "3.4.7",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@notesnook/mobile",
"version": "3.4.5",
"version": "3.4.7",
"hasInstallScript": true,
"license": "GPL-3.0-or-later",
"dependencies": {
@@ -191,6 +191,7 @@
"version": "2.1.3",
"license": "GPL-3.0-or-later",
"dependencies": {
"@notesnook/common": "^2.1.3",
"@notesnook/core": "file:../core",
"@readme/data-urls": "^3.0.0",
"dayjs": "1.11.13",
@@ -333,7 +334,10 @@
"papaparse": "^5.5.3",
"prism-themes": "^1.9.0",
"prosemirror-codemark": "^0.4.2",
"prosemirror-view": "1.34.2",
"prosemirror-model": "1.25.11",
"prosemirror-state": "1.4.4",
"prosemirror-transform": "1.12.0",
"prosemirror-view": "1.42.2",
"re-resizable": "^6.9.18",
"react-colorful": "^5.6.1",
"redent": "^4.0.0",

File diff suppressed because it is too large Load Diff

View File

@@ -30,6 +30,13 @@ import { strings } from "@notesnook/intl";
import { desktop } from "../../common/desktop-bridge";
import { TaskManager } from "../../common/task-manager";
import { useStore as useSettingStore } from "../../stores/setting-store";
// TEMPORARY — used only by the demo data group at the bottom of this file.
import { ConfirmDialog } from "../confirm";
import { useStore as useAppStore } from "../../stores/app-store";
import { useStore as useNoteStore } from "../../stores/note-store";
import { useStore as useNotebookStore } from "../../stores/notebook-store";
import { useStore as useTagStore } from "../../stores/tag-store";
import { useStore as useReminderStore } from "../../stores/reminder-store";
export const AboutSettings: SettingsGroup[] = [
{
@@ -419,9 +426,118 @@ export const SupportSettings: SettingsGroup[] = [
]
}
]
},
// TEMPORARY — demo data seeder for producing App Store / Play Store
// screenshots. Delete this group and src/common/seed-demo.ts once the store
// assets are captured.
{
key: "demo-data",
section: "about",
header: "Demo data",
isHidden: () => !import.meta.env.DEV,
settings: [
{
key: "seed-demo-account",
title: "Seed demo account",
description:
"Fills this account with the persona, notebooks, notes, tags, colours, reminders and vault notes the marketing site shows. Run once, on an empty account. Open the notes with pictures afterwards so the images download and become attachments.",
components: [
{
type: "button",
action: async () => {
const { seedDemoAccount } = await import("../../common/seed-demo");
await TaskManager.startTask({
type: "modal",
title: "Seeding demo account",
subtitle: "This takes about a minute. Do not close the app.",
action: async (report) => {
await seedDemoAccount((message) => {
console.log("[seed]", message);
report({ text: message });
});
}
});
await refreshAfterBulkChange();
showToast("success", "Demo data created. Sync, then capture.");
},
title: "Seed",
variant: "secondary"
}
]
},
{
key: "clear-demo-data",
title: "Delete all items",
description:
"Permanently deletes every note, notebook, tag, colour, reminder and the vault, then empties the trash. The account itself is kept. Cannot be undone.",
components: [
{
type: "button",
action: async () => {
// Typed confirmation, not a yes/no: this deletes everything in
// the account, including anything that was not seeded.
const result = await ConfirmDialog.show({
title: "Delete all items",
message:
"This permanently deletes everything in this account — not just the demo data — and empties the trash. It cannot be undone.",
inputs: {
confirmation: {
title: 'Type DELETE to confirm',
required: true
}
},
positiveButtonText: strings.delete(),
negativeButtonText: strings.cancel()
});
if (!result) return;
if (result.inputs?.confirmation?.trim() !== "DELETE") {
showToast("error", "Type DELETE to confirm.");
return;
}
const { clearAllData } = await import("../../common/seed-demo");
let counts: Awaited<ReturnType<typeof clearAllData>> | undefined;
await TaskManager.startTask({
type: "modal",
title: "Deleting all items",
subtitle: "Please wait.",
action: async (report) => {
counts = await clearAllData((message) => {
console.log("[seed]", message);
report({ text: message });
});
}
});
await refreshAfterBulkChange();
showToast(
"success",
counts
? `Deleted ${counts.notes} notes, ${counts.notebooks} notebooks, ${counts.tags} tags, ${counts.reminders} reminders.`
: "Account cleared."
);
},
title: "Delete",
variant: "error"
}
]
}
]
}
];
/**
* Both demo actions rewrite the whole database underneath the UI. The stores
* read from a cache that does not know that happened, so without this the app
* keeps rendering the previous account until a reload.
*/
async function refreshAfterBulkChange() {
await useAppStore.getState().refreshNavItems();
await useNoteStore.getState().refresh();
await useNotebookStore.getState().refresh();
await useTagStore.getState().refresh();
await useReminderStore.getState().refresh();
}
async function switchReleaseTrack(track: string) {
const registration = await navigator.serviceWorker.getRegistration();
if (!registration) return;

View File

@@ -44,7 +44,7 @@ if (theme) {
if (stylesheet) stylesheet.innerHTML = css;
} else stylesheet?.remove();
const locale = import.meta.env.DEV
const locale = !import.meta.env.DEV
? import("@notesnook/intl/locales/$pseudo-LOCALE.json")
: import("@notesnook/intl/locales/$en.json");
locale.then(({ default: locale }) => {

View File

@@ -40,6 +40,7 @@
"version": "2.1.3",
"license": "GPL-3.0-or-later",
"dependencies": {
"@notesnook/common": "^2.1.3",
"@notesnook/core": "file:../core",
"@readme/data-urls": "^3.0.0",
"dayjs": "1.11.13",
@@ -106,7 +107,10 @@
"papaparse": "^5.5.3",
"prism-themes": "^1.9.0",
"prosemirror-codemark": "^0.4.2",
"prosemirror-view": "1.34.2",
"prosemirror-model": "1.25.11",
"prosemirror-state": "1.4.4",
"prosemirror-transform": "1.12.0",
"prosemirror-view": "1.42.2",
"re-resizable": "^6.9.18",
"react-colorful": "^5.6.1",
"redent": "^4.0.0",