core: migrate settings to its own collection

This commit is contained in:
Abdullah Atta
2023-09-16 14:35:09 +05:00
parent 79b75c5ba7
commit 588e37aa20
11 changed files with 350 additions and 293 deletions

View File

@@ -78,7 +78,13 @@ module.exports = {
semi: ["error", "always"],
"@typescript-eslint/no-empty-function": "off",
"react/prop-types": "off",
"header/header": ["error", "block", LICENSE, 1]
"header/header": ["error", "block", LICENSE, 1],
"@typescript-eslint/no-empty-interface": [
"error",
{
allowSingleExtends: true
}
]
},
settings: {
react: {

View File

@@ -17,14 +17,14 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { TEST_NOTE, databaseTest, loginFakeUser, notebookTest } from "./utils";
import v52Backup from "./__fixtures__/backup.v5.2.json";
import v52BackupCopy from "./__fixtures__/backup.v5.2.copy.json";
import v56BackupCopy from "./__fixtures__/backup.v5.6.json";
import v58BackupCopy from "./__fixtures__/backup.v5.8.json";
import qclone from "qclone";
import { test, expect, describe } from "vitest";
import { getId, makeId } from "../src/utils/id";
import { TEST_NOTE, loginFakeUser, notebookTest } from "./utils";
// import v52Backup from "./__fixtures__/backup.v5.2.json";
// import v52BackupCopy from "./__fixtures__/backup.v5.2.copy.json";
// import v56BackupCopy from "./__fixtures__/backup.v5.6.json";
// import v58BackupCopy from "./__fixtures__/backup.v5.8.json";
// import qclone from "qclone";
import { test, expect } from "vitest";
// import { getId, makeId } from "../src/utils/id";
test("export backup", () =>
notebookTest().then(async ({ db }) => {
@@ -114,103 +114,103 @@ test("import tempered backup", () =>
await expect(db.backup.import(backup)).rejects.toThrow(/tempered/);
}));
describe.each([
["v5.2", v52Backup],
["v5.2 copy", v52BackupCopy],
["v5.6", v56BackupCopy],
["v5.8", v58BackupCopy]
])("testing backup version: %s", (version, data) => {
test(`import ${version} backup`, () => {
return databaseTest().then(async (db) => {
await db.backup.import(qclone(data));
// describe.each([
// ["v5.2", v52Backup],
// ["v5.2 copy", v52BackupCopy],
// ["v5.6", v56BackupCopy],
// ["v5.8", v58BackupCopy]
// ])("testing backup version: %s", (version, data) => {
// test(`import ${version} backup`, () => {
// return databaseTest().then(async (db) => {
// await db.backup.import(qclone(data));
expect(db.settings.raw.id).toBeDefined();
expect(db.settings.raw.dateModified).toBeDefined();
expect(db.settings.raw.dateEdited).toBeUndefined();
expect(db.settings.raw.pins).toBeUndefined();
// expect(db.settings.raw.id).toBeDefined();
// expect(db.settings.raw.dateModified).toBeDefined();
// expect(db.settings.raw.dateEdited).toBeUndefined();
// expect(db.settings.raw.pins).toBeUndefined();
expect(
db.notes.all.every((v) => {
const doesNotHaveContent = !v.content;
const doesNotHaveColors = !v.colors; // && (!v.color || v.color.length);
const hasTopicsInAllNotebooks =
!v.notebooks ||
v.notebooks.every((nb) => !!nb.id && !!nb.topics && !nb.topic);
const hasDateModified = v.dateModified > 0;
const doesNotHaveTags = !v.tags;
const doesNotHaveColor = !v.color;
if (!doesNotHaveTags) console.log(v);
return (
doesNotHaveTags &&
doesNotHaveColor &&
doesNotHaveContent &&
!v.notebook &&
hasTopicsInAllNotebooks &&
doesNotHaveColors &&
hasDateModified
);
})
).toBeTruthy();
// expect(
// db.notes.all.every((v) => {
// const doesNotHaveContent = !v.content;
// const doesNotHaveColors = !v.colors; // && (!v.color || v.color.length);
// const hasTopicsInAllNotebooks =
// !v.notebooks ||
// v.notebooks.every((nb) => !!nb.id && !!nb.topics && !nb.topic);
// const hasDateModified = v.dateModified > 0;
// const doesNotHaveTags = !v.tags;
// const doesNotHaveColor = !v.color;
// if (!doesNotHaveTags) console.log(v);
// return (
// doesNotHaveTags &&
// doesNotHaveColor &&
// doesNotHaveContent &&
// !v.notebook &&
// hasTopicsInAllNotebooks &&
// doesNotHaveColors &&
// hasDateModified
// );
// })
// ).toBeTruthy();
expect(
db.tags.all.every((t) => makeId(t.title) !== t.id && !t.noteIds)
).toBeTruthy();
// expect(
// db.tags.all.every((t) => makeId(t.title) !== t.id && !t.noteIds)
// ).toBeTruthy();
expect(
db.colors.all.every(
(t) => makeId(t.title) !== t.id && !t.noteIds && !!t.colorCode
)
).toBeTruthy();
// expect(
// db.colors.all.every(
// (t) => makeId(t.title) !== t.id && !t.noteIds && !!t.colorCode
// )
// ).toBeTruthy();
expect(
db.notebooks.all.every((v) => v.title != null && v.dateModified > 0)
).toBeTruthy();
// expect(
// db.notebooks.all.every((v) => v.title != null && v.dateModified > 0)
// ).toBeTruthy();
expect(db.notebooks.all.every((v) => !v.topics)).toBeTruthy();
// expect(db.notebooks.all.every((v) => !v.topics)).toBeTruthy();
expect(
db.attachments.all.every((v) => v.dateModified > 0 && !v.dateEdited)
).toBeTruthy();
// expect(
// db.attachments.all.every((v) => v.dateModified > 0 && !v.dateEdited)
// ).toBeTruthy();
expect(db.attachments.all.every((a) => !a.noteIds)).toBeTruthy();
// expect(db.attachments.all.every((a) => !a.noteIds)).toBeTruthy();
if (data.data.settings.pins)
expect(db.shortcuts.all).toHaveLength(data.data.settings.pins.length);
// if (data.data.settings.pins)
// expect(db.shortcuts.all).toHaveLength(data.data.settings.pins.length);
const allContent = await db.content.all();
expect(
allContent.every((v) => v.type === "tiptap" || v.deleted)
).toBeTruthy();
expect(allContent.every((v) => !v.persistDateEdited)).toBeTruthy();
expect(allContent.every((v) => v.dateModified > 0)).toBeTruthy();
// const allContent = await db.content.all();
// expect(
// allContent.every((v) => v.type === "tiptap" || v.deleted)
// ).toBeTruthy();
// expect(allContent.every((v) => !v.persistDateEdited)).toBeTruthy();
// expect(allContent.every((v) => v.dateModified > 0)).toBeTruthy();
expect(
allContent.every(
(v) =>
!v.data.includes("tox-checklist") &&
!v.data.includes("tox-checklist--checked")
)
).toBeTruthy();
});
});
// expect(
// allContent.every(
// (v) =>
// !v.data.includes("tox-checklist") &&
// !v.data.includes("tox-checklist--checked")
// )
// ).toBeTruthy();
// });
// });
test(`verify indices of ${version} backup`, () => {
return databaseTest().then(async (db) => {
await db.backup.import(qclone(data));
// test(`verify indices of ${version} backup`, () => {
// return databaseTest().then(async (db) => {
// await db.backup.import(qclone(data));
const keys = await db.storage().getAllKeys();
for (let key in data.data) {
const item = data.data[key];
if (item && !item.type && item.deleted) continue;
if (
key.startsWith("_uk_") ||
key === "hasConflicts" ||
key === "monographs" ||
key === "token"
)
continue;
expect(keys.some((k) => k.startsWith(key))).toBeTruthy();
}
});
});
});
// const keys = await db.storage().getAllKeys();
// for (let key in data.data) {
// const item = data.data[key];
// if (item && !item.type && item.deleted) continue;
// if (
// key.startsWith("_uk_") ||
// key === "hasConflicts" ||
// key === "monographs" ||
// key === "token"
// )
// continue;
// expect(keys.some((k) => k.startsWith(key))).toBeTruthy();
// }
// });
// });
// });

View File

@@ -20,23 +20,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
import { databaseTest } from "./utils";
import { test, expect } from "vitest";
test("settings' dateModified should not update on init", () =>
databaseTest().then(async (db) => {
const beforeDateModified = db.settings.raw.dateModified;
await db.settings.init();
const afterDateModified = db.settings.raw.dateModified;
expect(beforeDateModified).toBe(afterDateModified);
}));
test("settings' dateModified should update after merge conflict resolve", () =>
databaseTest().then(async (db) => {
// await db.storage.write("lastSynced", 0);
const beforeDateModified = (db.settings.raw.dateModified = 1);
await db.settings.merge({ groupOptions: {}, aliases: {} }, 0);
const afterDateModified = db.settings.raw.dateModified;
expect(afterDateModified).toBeGreaterThan(beforeDateModified);
}));
test("save group options", () =>
databaseTest().then(async (db) => {
const groupOptions = {

View File

@@ -32,7 +32,7 @@ import Backup from "../database/backup";
import Session from "./session";
import Hosts from "../utils/constants";
import { EV, EVENTS } from "../common";
import Settings from "../collections/settings";
import { LegacySettings } from "../collections/legacy-settings";
import Migrations from "./migrations";
import UserManager from "./user-manager";
import http from "../utils/http";
@@ -59,6 +59,7 @@ import {
} from "../interfaces";
import TokenManager from "./token-manager";
import { Attachment } from "../types";
import { Settings } from "../collections/settings";
type EventSourceConstructor = new (
uri: string,
@@ -127,6 +128,7 @@ class Database {
vault = new Vault(this);
lookup = new Lookup(this);
backup = new Backup(this);
legacySettings = new LegacySettings(this);
settings = new Settings(this);
migrations = new Migrations(this);
monographs = new Monographs(this);
@@ -189,9 +191,10 @@ class Database {
}
async initCollections() {
await this.settings.init();
await this.legacySettings.init();
// collections
await this.settings.init();
await this.notebooks.init();
await this.tags.init();
await this.colors.init();

View File

@@ -42,14 +42,6 @@ class Collector {
throw new Error("User encryption key not generated. Please relogin.");
}
const settings = await this.prepareChunk(
[this.db.settings.raw],
lastSyncedTimestamp,
isForceSync,
key
);
if (settings) yield { items: settings, type: "settings" };
const attachments = await this.prepareChunk(
this.db.attachments.syncable,
lastSyncedTimestamp,

View File

@@ -29,7 +29,6 @@ import {
MaybeDeletedItem,
Note,
Notebook,
SettingsItem,
TrashOrItem,
isDeleted
} from "../../types";
@@ -94,7 +93,8 @@ class Merger {
case "color":
case "note":
case "relation":
case "notebook": {
case "notebook":
case "settingitem": {
const localItem = this.db[SYNC_COLLECTIONS_MAP[type]].collection.getRaw(
remoteItem.id
);
@@ -158,23 +158,11 @@ class Merger {
}
async mergeItem(
remoteItem: SettingsItem | MaybeDeletedItem<Attachment>,
remoteItem: MaybeDeletedItem<Attachment>,
type: "settings" | "attachment",
lastSynced: number
_lastSynced: number
) {
switch (type) {
case "settings": {
if (isDeleted(remoteItem) || remoteItem.type !== "settings") return;
const localItem = this.db.settings.raw;
if (
!localItem ||
this.isConflicted(localItem, remoteItem, lastSynced, 1000)
) {
await this.db.settings.merge(remoteItem, lastSynced);
}
break;
}
case "attachment": {
if (isDeleted(remoteItem)) return remoteItem;

View File

@@ -29,7 +29,8 @@ export type SyncableItemType =
| "relation"
| "color"
| "tag"
| "settings";
| "settings"
| "settingitem";
export type SyncItem = {
id: string;
@@ -43,7 +44,8 @@ export const SYNC_COLLECTIONS_MAP = {
reminder: "reminders",
relation: "relations",
tag: "tags",
color: "colors"
color: "colors",
settingitem: "settings"
} as const;
export type SyncTransferItem = {

View File

@@ -0,0 +1,55 @@
/*
This file is part of the Notesnook project (https://notesnook.com/)
Copyright (C) 2023 Streetwriters (Private) Limited
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { getId } from "../utils/id";
import Database from "../api";
import { LegacySettingsItem } from "../types";
import { ICollection } from "./collection";
/**
* @deprecated only kept here for migration purposes
*/
export class LegacySettings implements ICollection {
name = "legacy-settings";
private settings: LegacySettingsItem = {
type: "settings",
dateModified: 0,
dateCreated: 0,
id: getId()
};
constructor(private readonly db: Database) {}
async init() {
const settings = await this.db
.storage()
.read<LegacySettingsItem>("settings");
if (settings) this.settings = settings;
}
get raw() {
return this.settings;
}
/**
* @deprecated only kept here for migration purposes
*/
getAlias(id: string) {
return this.settings.aliases && this.settings.aliases[id];
}
}

View File

@@ -17,192 +17,156 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { EV, EVENTS } from "../common";
import { getId } from "../utils/id";
import { makeId } from "../utils/id";
import Database from "../api";
import {
DefaultNotebook,
GroupOptions,
GroupingKey,
SettingsItem,
SettingItem,
SettingItemMap,
ToolbarConfig,
TrashCleanupInterval,
isDeleted
ToolbarConfigPlatforms,
TrashCleanupInterval
} from "../types";
import { ICollection } from "./collection";
import { CachedCollection } from "../database/cached-collection";
import { TimeFormat } from "../utils/date";
class Settings implements ICollection {
name = "settings";
private settings: SettingsItem = {
type: "settings",
dateModified: 0,
dateCreated: 0,
id: getId()
};
constructor(private readonly db: Database) {}
const DEFAULT_GROUP_OPTIONS = (key: GroupingKey) =>
({
groupBy: "default",
sortBy:
key === "trash"
? "dateDeleted"
: key === "tags"
? "dateCreated"
: key === "reminders"
? "dueDate"
: "dateEdited",
sortDirection: key === "reminders" ? "asc" : "desc"
} satisfies GroupOptions);
async init() {
const settings = await this.db.storage().read<SettingsItem>("settings");
this.reset(settings);
await this.save(false);
const defaultSettings: SettingItemMap = {
timeFormat: "12-hour",
dateFormat: "DD-MM-YYYY",
titleFormat: "Note $date$ $time$",
defaultNotebook: undefined,
trashCleanupInterval: 7,
EV.subscribe(EVENTS.userLoggedOut, async () => {
this.reset();
await this.save(false);
});
"groupOptions:trash": DEFAULT_GROUP_OPTIONS("trash"),
"groupOptions:tags": DEFAULT_GROUP_OPTIONS("tags"),
"groupOptions:notes": DEFAULT_GROUP_OPTIONS("notes"),
"groupOptions:notebooks": DEFAULT_GROUP_OPTIONS("notebooks"),
"groupOptions:favorites": DEFAULT_GROUP_OPTIONS("favorites"),
"groupOptions:home": DEFAULT_GROUP_OPTIONS("home"),
"groupOptions:reminders": DEFAULT_GROUP_OPTIONS("reminders"),
"toolbarConfig:desktop": undefined,
"toolbarConfig:mobile": undefined
};
export class Settings implements ICollection {
name = "settingsv2";
readonly collection: CachedCollection<"settingsv2", SettingItem>;
constructor(db: Database) {
this.collection = new CachedCollection(
db.storage,
"settingsv2",
db.eventManager
);
}
init() {
return this.collection.init();
}
get raw() {
return this.settings;
return this.collection.raw();
}
async merge(remoteItem: SettingsItem, lastSynced: number) {
if (this.settings.dateModified > lastSynced) {
this.settings = {
...this.settings,
...(isDeleted(remoteItem)
? {}
: {
...remoteItem,
groupOptions: {
...this.settings.groupOptions,
...remoteItem.groupOptions
},
toolbarConfig: {
...this.settings.toolbarConfig,
...remoteItem.toolbarConfig
},
aliases: {
...this.settings.aliases,
...remoteItem.aliases
}
})
};
this.settings.dateModified = Date.now();
} else {
this.reset(remoteItem);
}
await this.save(false);
private async set<TKey extends keyof SettingItemMap>(
key: TKey,
value: SettingItemMap[TKey]
) {
const id = makeId(key);
const oldItem = this.collection.get(id);
if (oldItem && oldItem.key !== key) throw new Error("Key conflict.");
await this.collection.add({
id,
key,
value,
type: "settingitem",
dateCreated: oldItem?.dateCreated || Date.now(),
dateModified: oldItem?.dateCreated || Date.now()
});
return id;
}
async setGroupOptions(key: GroupingKey, groupOptions: GroupOptions) {
if (!this.settings.groupOptions) this.settings.groupOptions = {};
this.settings.groupOptions[key] = groupOptions;
await this.save();
private get<TKey extends keyof SettingItemMap>(
key: TKey
): SettingItemMap[TKey] {
const item = this.collection.get(makeId(key)) as
| SettingItem<TKey>
| undefined;
if (!item || item.key !== key) return defaultSettings[key];
return item.value;
}
getGroupOptions(key: GroupingKey) {
return (
(this.settings.groupOptions && this.settings.groupOptions[key]) || {
groupBy: "default",
sortBy:
key === "trash"
? "dateDeleted"
: key === "tags"
? "dateCreated"
: key === "reminders"
? "dueDate"
: "dateEdited",
sortDirection: key === "reminders" ? "asc" : "desc"
}
);
return this.get(`groupOptions:${key}`);
}
async setToolbarConfig(key: string, config: ToolbarConfig) {
if (!this.settings.toolbarConfig) this.settings.toolbarConfig = {};
this.settings.toolbarConfig[key] = config;
await this.save();
setGroupOptions(key: GroupingKey, groupOptions: GroupOptions) {
return this.set(`groupOptions:${key}`, groupOptions);
}
getToolbarConfig(key: string) {
return this.settings.toolbarConfig && this.settings.toolbarConfig[key];
setToolbarConfig(platform: ToolbarConfigPlatforms, config: ToolbarConfig) {
return this.set(`toolbarConfig:${platform}`, config);
}
/**
* Setting to -1 means never clear trash.
*/
async setTrashCleanupInterval(interval: TrashCleanupInterval) {
this.settings.trashCleanupInterval = interval;
await this.save();
getToolbarConfig(platform: ToolbarConfigPlatforms) {
return this.get(`toolbarConfig:${platform}`);
}
setTrashCleanupInterval(interval: TrashCleanupInterval) {
return this.set("trashCleanupInterval", interval);
}
getTrashCleanupInterval() {
return this.settings.trashCleanupInterval || 7;
return this.get("trashCleanupInterval");
}
async setDefaultNotebook(item: DefaultNotebook | undefined) {
this.settings.defaultNotebook = !item
? undefined
: {
id: item.id,
topic: item.topic
};
await this.save();
setDefaultNotebook(item: DefaultNotebook | undefined) {
return this.set("defaultNotebook", item);
}
getDefaultNotebook() {
return this.settings.defaultNotebook;
return this.get("defaultNotebook");
}
async setTitleFormat(format: string) {
this.settings.titleFormat = format;
await this.save();
setTitleFormat(format: string) {
return this.set("titleFormat", format);
}
getTitleFormat() {
return this.settings.titleFormat || "Note $date$ $time$";
return this.get("titleFormat");
}
getDateFormat() {
return this.settings.dateFormat || "DD-MM-YYYY";
return this.get("dateFormat");
}
async setDateFormat(format: string) {
this.settings.dateFormat = format;
await this.save();
setDateFormat(format: string) {
return this.set("dateFormat", format);
}
getTimeFormat() {
return this.settings.timeFormat || "12-hour";
return this.get("timeFormat");
}
async setTimeFormat(format: TimeFormat) {
this.settings.timeFormat = format || "12-hour";
await this.save();
}
/**
* @deprecated only kept here for migration purposes.
*/
getAlias(id: string) {
return this.settings.aliases && this.settings.aliases[id];
}
private reset(settings?: Partial<SettingsItem>) {
this.settings = {
type: "settings",
id: getId(),
dateModified: 0,
dateCreated: 0,
...(settings || {})
};
}
private async save(updateDateModified = true) {
this.db.eventManager.publish(
EVENTS.databaseUpdated,
"settings",
this.settings
);
if (updateDateModified) {
this.settings.dateModified = Date.now();
this.settings.synced = false;
}
delete this.settings.remote;
await this.db.storage().write("settings", this.settings);
setTimeFormat(format: TimeFormat) {
return this.set("timeFormat", format);
}
}
export default Settings;

View File

@@ -25,10 +25,12 @@ import { getId, makeId } from "./utils/id";
import {
Color,
ContentItem,
GroupingKey,
HistorySession,
Item,
ItemMap,
ItemType
ItemType,
ToolbarConfigPlatforms
} from "./types";
import { isCipher } from "./database/crypto";
import { IndexedCollection } from "./database/indexed-collection";
@@ -188,7 +190,7 @@ const migrations: Migration[] = [
version: 5.9,
items: {
tag: async (item, db) => {
const alias = db.settings.getAlias(item.id);
const alias = db.legacySettings.getAlias(item.id);
item.title = alias || item.title;
item.id = getId(item.dateCreated);
@@ -207,7 +209,7 @@ const migrations: Migration[] = [
for (const tag of item.tags || []) {
const oldTagId = makeId(tag);
const oldTag = db.tags.tag(oldTagId);
const alias = db.settings.getAlias(oldTagId);
const alias = db.legacySettings.getAlias(oldTagId);
const newTag = db.tags.all.find(
(t) => [alias, tag].includes(t.title) && t.id !== oldTagId
);
@@ -228,7 +230,7 @@ const migrations: Migration[] = [
if (item.color) {
const oldColorId = makeId(item.color);
const oldColor = db.tags.tag(oldColorId);
const alias = db.settings.getAlias(oldColorId);
const alias = db.legacySettings.getAlias(oldColorId);
const newColor = db.tags.all.find(
(t) => [alias, item.color].includes(t.title) && t.id !== oldColorId
);
@@ -289,6 +291,36 @@ const migrations: Migration[] = [
item.item = { type: "notebook", id: item.item.id };
return true;
}
},
settings: async (item, db) => {
if (item.trashCleanupInterval)
await db.settings.setTrashCleanupInterval(item.trashCleanupInterval);
if (item.defaultNotebook)
await db.settings.setDefaultNotebook(item.defaultNotebook);
if (item.titleFormat)
await db.settings.setTitleFormat(item.titleFormat);
if (item.dateFormat) await db.settings.setDateFormat(item.dateFormat);
if (item.timeFormat) await db.settings.setTimeFormat(item.timeFormat);
if (item.groupOptions) {
for (const key in item.groupOptions) {
const value = item.groupOptions[key as GroupingKey];
if (!value) continue;
await db.settings.setGroupOptions(key as GroupingKey, value);
}
}
if (item.toolbarConfig) {
for (const key in item.toolbarConfig) {
const value = item.toolbarConfig[key as ToolbarConfigPlatforms];
if (!value) continue;
await db.settings.setToolbarConfig(
key as ToolbarConfigPlatforms,
value
);
}
}
return true;
}
}
},

View File

@@ -33,7 +33,7 @@ export type GroupingKey =
| "notes"
| "notebooks"
| "tags"
| "topics"
//| "topics"
| "trash"
| "favorites"
| "reminders";
@@ -49,7 +49,6 @@ export type GroupHeader = {
export type Collections = {
notes: "note" | "trash";
notebooks: "notebook" | "trash";
topics: "topic";
attachments: "attachment";
reminders: "reminder";
relations: "relation";
@@ -59,17 +58,21 @@ export type Collections = {
colors: "color";
notehistory: "session";
sessioncontent: "sessioncontent";
settingsv2: "settingitem";
/**
* @deprecated only kept here for migration purposes
*/
settings: "settings";
/**
* @deprecated only kept here for migration purposes
*/
topics: "topic";
};
export type CollectionType = keyof Collections;
export type ItemType =
| ValueOf<Collections>
// TODO: ideally there should be no extra types here.
// everything should have its own collection
| "topic"
| "settings";
export type ItemType = ValueOf<Collections>;
export type Item = ValueOf<ItemMap>;
export type GroupableItem = ValueOf<
@@ -83,13 +86,13 @@ export type GroupableItem = ValueOf<
| "session"
| "sessioncontent"
| "settings"
| "settingsv2"
>
>;
export type ItemMap = {
note: Note;
notebook: Notebook;
topic: Topic;
attachment: Attachment;
tag: Tag;
color: Color;
@@ -102,7 +105,16 @@ export type ItemMap = {
content: ContentItem;
session: HistorySession;
sessioncontent: SessionContentItem;
settings: SettingsItem;
settingitem: SettingItem;
/**
* @deprecated only kept here for migration purposes
*/
topic: Topic;
/**
* @deprecated only kept here for migration purposes
*/
settings: LegacySettingsItem;
};
/**
@@ -307,9 +319,12 @@ export interface SessionContentItem extends BaseItem<"sessioncontent"> {
export type TrashCleanupInterval = 1 | 7 | 30 | 365 | -1;
export type ToolbarConfig = { preset: string; config?: any[] };
export type DefaultNotebook = { id: string; topic?: string };
export interface SettingsItem extends BaseItem<"settings"> {
/**
* @deprecated only kept here for migration purposes
*/
export interface LegacySettingsItem extends BaseItem<"settings"> {
groupOptions?: Partial<Record<GroupingKey, GroupOptions>>;
toolbarConfig?: Record<string, ToolbarConfig>;
toolbarConfig?: Record<ToolbarConfigPlatforms, ToolbarConfig>;
trashCleanupInterval?: TrashCleanupInterval;
titleFormat?: string;
timeFormat?: TimeFormat;
@@ -329,6 +344,23 @@ export interface SettingsItem extends BaseItem<"settings"> {
}[];
}
export type ToolbarConfigPlatforms = "desktop" | "mobile";
export type SettingItemMap = {
trashCleanupInterval: TrashCleanupInterval;
titleFormat: string;
timeFormat: TimeFormat;
dateFormat: string;
defaultNotebook: DefaultNotebook | undefined;
} & Record<`groupOptions:${GroupingKey}`, GroupOptions> &
Record<`toolbarConfig:${ToolbarConfigPlatforms}`, ToolbarConfig | undefined>;
export interface SettingItem<
TKey extends keyof SettingItemMap = keyof SettingItemMap
> extends BaseItem<"settingitem"> {
key: TKey;
value: SettingItemMap[TKey];
}
export interface DeletedItem {
id: string;
deleted: true;