mirror of
https://github.com/streetwriters/notesnook.git
synced 2026-09-01 19:49:54 +02:00
web: fix notes tests
This commit is contained in:
committed by
Abdullah Atta
parent
a51f84c1f4
commit
fc270459b0
@@ -61,7 +61,7 @@ export class AppModel {
|
||||
|
||||
async goToNotes() {
|
||||
await this.navigateTo("Notes");
|
||||
return new NotesViewModel(this.page, "home");
|
||||
return new NotesViewModel(this.page, "home", "home");
|
||||
}
|
||||
|
||||
async goToNotebooks() {
|
||||
@@ -71,7 +71,7 @@ export class AppModel {
|
||||
|
||||
async goToFavorites() {
|
||||
await this.navigateTo("Favorites");
|
||||
return new NotesViewModel(this.page, "notes");
|
||||
return new NotesViewModel(this.page, "notes", "favorites");
|
||||
}
|
||||
|
||||
async goToReminders() {
|
||||
@@ -86,7 +86,7 @@ export class AppModel {
|
||||
|
||||
async goToColor(color: string) {
|
||||
await this.navigateTo(color);
|
||||
return new NotesViewModel(this.page, "notes");
|
||||
return new NotesViewModel(this.page, "notes", "notes");
|
||||
}
|
||||
|
||||
async goToTrash() {
|
||||
|
||||
@@ -29,12 +29,15 @@ export class BaseViewModel {
|
||||
private readonly listPlaceholder: Locator;
|
||||
private readonly sortByButton: Locator;
|
||||
|
||||
constructor(page: Page, pageId: string, listType: string) {
|
||||
constructor(page: Page, pageId: string, readonly listType: string) {
|
||||
this.page = page;
|
||||
this.list = page.locator(`#${pageId} >> ${getTestId(`${listType}-list`)}`);
|
||||
this.listPlaceholder = page.locator(
|
||||
`#${pageId} >> ${getTestId("list-placeholder")}`
|
||||
);
|
||||
this.list = page
|
||||
.locator(`#${pageId}`)
|
||||
.locator(getTestId(`${listType}-list`));
|
||||
|
||||
this.listPlaceholder = page
|
||||
.locator(`#${pageId}`)
|
||||
.locator(getTestId("list-placeholder"));
|
||||
|
||||
this.sortByButton = this.page.locator(
|
||||
// TODO:
|
||||
@@ -43,9 +46,9 @@ export class BaseViewModel {
|
||||
}
|
||||
|
||||
async findGroup(groupName: string) {
|
||||
const locator = this.list.locator(
|
||||
`${getTestId(`virtuoso-item-list`)} >> ${getTestId("group-header")}`
|
||||
);
|
||||
const locator = this.list
|
||||
.locator(getTestId(`virtualized-list`))
|
||||
.locator(getTestId("group-header"));
|
||||
|
||||
for await (const item of iterateList(locator)) {
|
||||
if ((await item.locator(getTestId("title")).textContent()) === groupName)
|
||||
@@ -56,13 +59,10 @@ export class BaseViewModel {
|
||||
|
||||
protected async *iterateItems() {
|
||||
await this.waitForList();
|
||||
const locator = this.list.locator(
|
||||
`${getTestId(`virtuoso-item-list`)} >> ${getTestId("list-item")}`
|
||||
);
|
||||
|
||||
for await (const _item of iterateList(locator)) {
|
||||
for await (const _item of iterateList(this.items)) {
|
||||
const id = await _item.getAttribute("id");
|
||||
if (!id) return;
|
||||
if (!id) continue;
|
||||
|
||||
yield this.list.locator(`#${id}`);
|
||||
}
|
||||
@@ -82,11 +82,8 @@ export class BaseViewModel {
|
||||
}
|
||||
|
||||
async focus() {
|
||||
const items = this.list.locator(
|
||||
`${getTestId(`virtuoso-item-list`)} >> ${getTestId("list-item")}`
|
||||
);
|
||||
await items.nth(0).click();
|
||||
await items.nth(0).click();
|
||||
await this.items.nth(0).click();
|
||||
await this.items.nth(0).click();
|
||||
}
|
||||
|
||||
// async selectAll() {
|
||||
@@ -98,7 +95,7 @@ export class BaseViewModel {
|
||||
// }
|
||||
|
||||
async press(key: string) {
|
||||
const itemList = this.list.locator(getTestId(`virtuoso-item-list`));
|
||||
const itemList = this.list.locator(getTestId(`virtualized-list`));
|
||||
await itemList.press(key);
|
||||
await this.page.waitForTimeout(300);
|
||||
}
|
||||
@@ -135,11 +132,11 @@ export class BaseViewModel {
|
||||
return true;
|
||||
}
|
||||
|
||||
get items() {
|
||||
return this.list.locator(getTestId("list-item"));
|
||||
}
|
||||
|
||||
async isEmpty() {
|
||||
const items = this.list.locator(
|
||||
`${getTestId(`virtuoso-item-list`)} >> ${getTestId("list-item")}`
|
||||
);
|
||||
const totalItems = await items.count();
|
||||
return totalItems <= 0;
|
||||
return (await this.items.count()) <= 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@ export class EditorModel {
|
||||
this.title = page.locator(getTestId("editor-title"));
|
||||
this.content = page.locator(".ProseMirror");
|
||||
this.tagInput = page.locator(getTestId("editor-tag-input"));
|
||||
this.tags = page.locator(`${getTestId("tags")} > ${getTestId("tag")}`);
|
||||
this.tags = page.locator(`${getTestId("tags")} >> ${getTestId("tag")}`);
|
||||
this.focusModeButton = page.locator(getTestId("Focus mode"));
|
||||
this.normalModeButton = page.locator(getTestId("Normal mode"));
|
||||
this.darkModeButton = page.locator(getTestId("Dark mode"));
|
||||
|
||||
@@ -23,6 +23,7 @@ import { ContextMenuModel } from "./context-menu.model";
|
||||
import { NotesViewModel } from "./notes-view.model";
|
||||
import { Item } from "./types";
|
||||
import { confirmDialog, fillItemDialog } from "./utils";
|
||||
import { getTestId } from "../utils";
|
||||
|
||||
export class ItemModel extends BaseItemModel {
|
||||
private readonly contextMenu: ContextMenuModel;
|
||||
@@ -35,7 +36,8 @@ export class ItemModel extends BaseItemModel {
|
||||
await this.locator.click();
|
||||
return new NotesViewModel(
|
||||
this.page,
|
||||
this.id === "topic" ? "notebook" : "notes"
|
||||
this.id === "topic" ? "notebook" : "notes",
|
||||
"notes"
|
||||
);
|
||||
}
|
||||
|
||||
@@ -53,7 +55,7 @@ export class ItemModel extends BaseItemModel {
|
||||
if (deleteContainedNotes)
|
||||
await this.page.locator("#deleteContainingNotes").check({ force: true });
|
||||
|
||||
await confirmDialog(this.page);
|
||||
await confirmDialog(this.page.locator(getTestId("confirm-dialog")));
|
||||
await this.waitFor("detached");
|
||||
}
|
||||
|
||||
|
||||
@@ -22,7 +22,12 @@ import { downloadAndReadFile, getTestId } from "../utils";
|
||||
import { ContextMenuModel } from "./context-menu.model";
|
||||
import { ToggleModel } from "./toggle.model";
|
||||
import { Notebook } from "./types";
|
||||
import { fillPasswordDialog, iterateList } from "./utils";
|
||||
import {
|
||||
confirmDialog,
|
||||
fillNotebookDialog,
|
||||
fillPasswordDialog,
|
||||
iterateList
|
||||
} from "./utils";
|
||||
|
||||
abstract class BaseProperties {
|
||||
protected readonly page: Page;
|
||||
@@ -248,51 +253,59 @@ export class NoteContextMenuModel extends BaseProperties {
|
||||
}
|
||||
|
||||
async addToNotebook(notebook: Notebook) {
|
||||
async function addSubNotebooks(
|
||||
page: Page,
|
||||
dialog: Locator,
|
||||
item: Locator,
|
||||
notebook: Notebook
|
||||
) {
|
||||
if (notebook.subNotebooks) {
|
||||
const addSubNotebookButton = item.locator(
|
||||
getTestId("add-sub-notebook")
|
||||
);
|
||||
for (const subNotebook of notebook.subNotebooks) {
|
||||
await addSubNotebookButton.click();
|
||||
|
||||
await fillNotebookDialog(page, subNotebook);
|
||||
|
||||
const subNotebookItem = dialog.locator(getTestId("notebook"), {
|
||||
hasText: subNotebook.title
|
||||
});
|
||||
await subNotebookItem.waitFor();
|
||||
|
||||
await page.keyboard.down("Control");
|
||||
await subNotebookItem.click();
|
||||
await page.keyboard.up("Control");
|
||||
|
||||
await addSubNotebooks(page, dialog, subNotebookItem, subNotebook);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
await this.open();
|
||||
|
||||
await this.menu.clickOnItem("notebooks");
|
||||
await this.menu.clickOnItem("link-notebooks");
|
||||
|
||||
const filterInput = this.page.locator(getTestId("filter-input"));
|
||||
await filterInput.type(notebook.title);
|
||||
await filterInput.press("Enter");
|
||||
const dialog = this.page.locator(getTestId("move-note-dialog"));
|
||||
|
||||
await this.page.waitForSelector(getTestId("notebook"), {
|
||||
state: "visible",
|
||||
strict: false
|
||||
await dialog.locator(getTestId("add-new-notebook")).click();
|
||||
|
||||
await fillNotebookDialog(this.page, notebook);
|
||||
|
||||
const notebookItem = dialog.locator(getTestId("notebook"), {
|
||||
hasText: notebook.title
|
||||
});
|
||||
|
||||
const notebookItems = this.page.locator(getTestId("notebook"));
|
||||
for await (const item of iterateList(notebookItems)) {
|
||||
await item.locator(getTestId("notebook-tools")).click();
|
||||
const title = item.locator(getTestId("notebook-title"));
|
||||
const createTopicButton = item.locator(getTestId("create-topic"));
|
||||
const notebookTitle = await title.textContent();
|
||||
await notebookItem.waitFor({ state: "visible" });
|
||||
|
||||
if (notebookTitle?.includes(notebook.title)) {
|
||||
for (const topic of notebook.topics) {
|
||||
await createTopicButton.click();
|
||||
const newItemInput = item.locator(getTestId("new-topic-input"));
|
||||
await this.page.keyboard.down("Control");
|
||||
await notebookItem.click();
|
||||
await this.page.keyboard.up("Control");
|
||||
|
||||
await newItemInput.waitFor({ state: "visible" });
|
||||
await newItemInput.fill(topic);
|
||||
await newItemInput.press("Enter");
|
||||
await addSubNotebooks(this.page, dialog, notebookItem, notebook);
|
||||
|
||||
await item.locator(getTestId("topic"), { hasText: topic }).waitFor();
|
||||
}
|
||||
|
||||
const topicItems = item.locator(getTestId("topic"));
|
||||
for await (const topicItem of iterateList(topicItems)) {
|
||||
await this.page.keyboard.down("Control");
|
||||
await topicItem.click();
|
||||
await this.page.keyboard.up("Control");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const dialogConfirm = this.page.locator(getTestId("dialog-yes"));
|
||||
await dialogConfirm.click();
|
||||
await dialogConfirm.waitFor({ state: "detached" });
|
||||
await confirmDialog(dialog);
|
||||
}
|
||||
|
||||
async open() {
|
||||
|
||||
@@ -25,6 +25,7 @@ import { ItemsViewModel } from "./items-view.model";
|
||||
import { Notebook } from "./types";
|
||||
import { confirmDialog, fillNotebookDialog } from "./utils";
|
||||
import { NotesViewModel } from "./notes-view.model";
|
||||
import { getTestId } from "../utils";
|
||||
|
||||
export class NotebookItemModel extends BaseItemModel {
|
||||
private readonly contextMenu: ContextMenuModel;
|
||||
@@ -37,7 +38,7 @@ export class NotebookItemModel extends BaseItemModel {
|
||||
await this.locator.click();
|
||||
return {
|
||||
topics: new ItemsViewModel(this.page, "topics"),
|
||||
notes: new NotesViewModel(this.page, "notebook")
|
||||
notes: new NotesViewModel(this.page, "notebook", "notes")
|
||||
};
|
||||
}
|
||||
|
||||
@@ -45,7 +46,7 @@ export class NotebookItemModel extends BaseItemModel {
|
||||
await this.contextMenu.open(this.locator);
|
||||
await this.contextMenu.clickOnItem("edit");
|
||||
|
||||
await fillNotebookDialog(this.page, notebook, true);
|
||||
await fillNotebookDialog(this.page, notebook);
|
||||
}
|
||||
|
||||
async moveToTrash(deleteContainedNotes = false) {
|
||||
@@ -55,7 +56,7 @@ export class NotebookItemModel extends BaseItemModel {
|
||||
if (deleteContainedNotes)
|
||||
await this.page.locator("#deleteContainingNotes").check({ force: true });
|
||||
|
||||
await confirmDialog(this.page);
|
||||
await confirmDialog(this.page.locator(getTestId("confirm-dialog")));
|
||||
await this.waitFor("detached");
|
||||
}
|
||||
|
||||
|
||||
@@ -32,8 +32,12 @@ export class NotesViewModel extends BaseViewModel {
|
||||
private readonly createButton: Locator;
|
||||
readonly editor: EditorModel;
|
||||
|
||||
constructor(page: Page, pageId: "home" | "notes" | "notebook") {
|
||||
super(page, pageId, pageId === "home" ? "home" : "notes");
|
||||
constructor(
|
||||
page: Page,
|
||||
pageId: "home" | "notes" | "favorites" | "notebook",
|
||||
listType: string
|
||||
) {
|
||||
super(page, pageId, listType);
|
||||
this.createButton = page.locator(
|
||||
// TODO:
|
||||
getTestId(`notes-action-button`)
|
||||
|
||||
@@ -47,7 +47,7 @@ export class ReminderItemModel extends BaseItemModel {
|
||||
await this.contextMenu.open(this.locator);
|
||||
await this.contextMenu.clickOnItem("delete");
|
||||
|
||||
await confirmDialog(this.page);
|
||||
await confirmDialog(this.page.locator(getTestId("confirm-dialog")));
|
||||
await this.waitFor("detached");
|
||||
}
|
||||
|
||||
|
||||
@@ -52,7 +52,7 @@ export class SettingsViewModel {
|
||||
.locator("button");
|
||||
|
||||
await logoutButton.click();
|
||||
await confirmDialog(this.page);
|
||||
await confirmDialog(this.page.locator(getTestId("confirm-dialog")));
|
||||
|
||||
await this.page
|
||||
.locator(getTestId("not-logged-in"))
|
||||
@@ -75,7 +75,9 @@ export class SettingsViewModel {
|
||||
const key = await this.page
|
||||
.locator(getTestId("recovery-key"))
|
||||
.textContent();
|
||||
await confirmDialog(this.page);
|
||||
|
||||
const dialog = this.page.locator(getTestId("recovery-key-dialog"));
|
||||
await confirmDialog(dialog);
|
||||
return key;
|
||||
}
|
||||
|
||||
|
||||
@@ -19,8 +19,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
export type Notebook = {
|
||||
title: string;
|
||||
topics: string[];
|
||||
description?: string;
|
||||
subNotebooks?: Notebook[];
|
||||
};
|
||||
|
||||
export type Item = {
|
||||
|
||||
@@ -30,42 +30,28 @@ export async function* iterateList(list: Locator) {
|
||||
return null;
|
||||
}
|
||||
|
||||
export async function fillNotebookDialog(
|
||||
page: Page,
|
||||
notebook: Notebook,
|
||||
editing = false
|
||||
) {
|
||||
const titleInput = page.locator(getTestId("title-input"));
|
||||
const descriptionInput = page.locator(getTestId("description-input"));
|
||||
const topicInput = page.locator(getTestId(`edit-topic-input`));
|
||||
const topicInputAction = page.locator(getTestId(`edit-topic-action`));
|
||||
export async function fillNotebookDialog(page: Page, notebook: Notebook) {
|
||||
const dialog = page.locator(getTestId("add-notebook-dialog"));
|
||||
const titleInput = dialog.locator(getTestId("title-input"));
|
||||
const descriptionInput = dialog.locator(getTestId("description-input"));
|
||||
|
||||
await titleInput.waitFor({ state: "visible" });
|
||||
|
||||
await titleInput.fill(notebook.title);
|
||||
if (notebook.description) await descriptionInput.fill(notebook.description);
|
||||
|
||||
const topicItems = page.locator(getTestId("topic-item"));
|
||||
for (let i = 0; i < notebook.topics.length; ++i) {
|
||||
if (editing) {
|
||||
const topicItem = topicItems.nth(i);
|
||||
await topicItem.click();
|
||||
}
|
||||
await topicInput.fill(notebook.topics[i]);
|
||||
await topicInputAction.click();
|
||||
}
|
||||
|
||||
await confirmDialog(page);
|
||||
await confirmDialog(dialog);
|
||||
}
|
||||
|
||||
export async function fillReminderDialog(
|
||||
page: Page,
|
||||
reminder: Partial<Reminder>
|
||||
) {
|
||||
const titleInput = page.locator(getTestId("title-input"));
|
||||
const descriptionInput = page.locator(getTestId("description-input"));
|
||||
const dateInput = page.locator(getTestId("date-input"));
|
||||
const timeInput = page.locator(getTestId("time-input"));
|
||||
const dialog = page.locator(getTestId("reminder-dialog"));
|
||||
const titleInput = dialog.locator(getTestId("title-input"));
|
||||
const descriptionInput = dialog.locator(getTestId("description-input"));
|
||||
const dateInput = dialog.locator(getTestId("date-input"));
|
||||
const timeInput = dialog.locator(getTestId("time-input"));
|
||||
|
||||
if (reminder.title) {
|
||||
await titleInput.waitFor({ state: "visible" });
|
||||
@@ -73,10 +59,10 @@ export async function fillReminderDialog(
|
||||
}
|
||||
if (reminder.description) await descriptionInput.fill(reminder.description);
|
||||
if (reminder.mode)
|
||||
await page.locator(getTestId(`mode-${reminder.mode}`)).click();
|
||||
await dialog.locator(getTestId(`mode-${reminder.mode}`)).click();
|
||||
|
||||
if (reminder.priority)
|
||||
await page.locator(getTestId(`priority-${reminder.priority}`)).click();
|
||||
await dialog.locator(getTestId(`priority-${reminder.priority}`)).click();
|
||||
|
||||
if (reminder.recurringMode && reminder.mode === "repeat") {
|
||||
await page
|
||||
@@ -89,7 +75,7 @@ export async function fillReminderDialog(
|
||||
reminder.recurringMode !== "day"
|
||||
) {
|
||||
for (const day of reminder.selectedDays) {
|
||||
await page.locator(getTestId(`day-${day}`)).click();
|
||||
await dialog.locator(getTestId(`day-${day}`)).click();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -111,25 +97,27 @@ export async function fillReminderDialog(
|
||||
await timeInput.fill(time);
|
||||
}
|
||||
|
||||
await confirmDialog(page);
|
||||
await confirmDialog(dialog);
|
||||
}
|
||||
|
||||
export async function fillItemDialog(page: Page, item: Item) {
|
||||
const titleInput = page.locator(getTestId("title-input"));
|
||||
const dialog = page.locator(getTestId("item-dialog"));
|
||||
const titleInput = dialog.locator(getTestId("title-input"));
|
||||
await titleInput.waitFor({ state: "visible" });
|
||||
|
||||
await titleInput.fill(item.title);
|
||||
|
||||
await confirmDialog(page);
|
||||
await confirmDialog(dialog);
|
||||
}
|
||||
|
||||
export async function fillPasswordDialog(page: Page, password: string) {
|
||||
await page.locator(getTestId("dialog-password")).fill(password);
|
||||
await confirmDialog(page);
|
||||
const dialog = page.locator(getTestId("password-dialog"));
|
||||
await dialog.locator(getTestId("dialog-password")).fill(password);
|
||||
await confirmDialog(dialog);
|
||||
}
|
||||
|
||||
export async function confirmDialog(page: Page) {
|
||||
const dialogConfirm = page.locator(getTestId("dialog-yes"));
|
||||
export async function confirmDialog(dialog: Locator) {
|
||||
const dialogConfirm = dialog.locator(getTestId("dialog-yes"));
|
||||
await dialogConfirm.click();
|
||||
// await dialogConfirm.waitFor({ state: "detached" });
|
||||
}
|
||||
|
||||
@@ -92,12 +92,15 @@ test("add a note to notebook", async ({ page }) => {
|
||||
|
||||
await note?.contextMenu.addToNotebook({
|
||||
title: "Notebook 1",
|
||||
topics: ["Hello", "World", "Did", "what"]
|
||||
subNotebooks: [
|
||||
{ title: "Hello" },
|
||||
{ title: "World", subNotebooks: [{ title: "Did" }, { title: "what" }] }
|
||||
]
|
||||
});
|
||||
|
||||
expect(
|
||||
await app.toasts.waitForToast("1 note added to Hello and 3 others.")
|
||||
).toBe(true);
|
||||
expect(await app.toasts.waitForToast("1 note added to 5 notebooks.")).toBe(
|
||||
true
|
||||
);
|
||||
});
|
||||
|
||||
const actors = ["contextMenu", "properties"] as const;
|
||||
@@ -165,7 +168,7 @@ for (const actor of actors) {
|
||||
|
||||
await note?.[actor].color("red");
|
||||
|
||||
const coloredNotes = await app.goToColor("red");
|
||||
const coloredNotes = await app.goToColor("Red");
|
||||
const coloredNote = await coloredNotes.findNote(NOTE);
|
||||
expect(coloredNote).toBeDefined();
|
||||
expect(await coloredNote?.contextMenu.isColored("red")).toBe(true);
|
||||
@@ -307,7 +310,7 @@ test(`sort notes`, async ({ page }, info) => {
|
||||
});
|
||||
if (!sortResult) return;
|
||||
|
||||
expect(await notes.isEmpty()).toBeFalsy();
|
||||
await expect(notes.items).toHaveCount(titles.length);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
Test 1
|
||||
----------
|
||||
|
||||
This is Test 1Test 1Test 1Test 1Test 1Test 1Test 1Test 1Test 1Test 1
|
||||
|
||||
----------
|
||||
Tags:
|
||||
This is Test 1Test 1Test 1Test 1Test 1Test 1Test 1Test 1Test 1Test 1
|
||||
@@ -20,6 +20,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
import { db } from "./db";
|
||||
import { showPasswordDialog } from "./dialog-controller";
|
||||
import { showToast } from "../utils/toast";
|
||||
import { VAULT_ERRORS } from "@notesnook/core/dist/api/vault";
|
||||
|
||||
class Vault {
|
||||
static async createVault() {
|
||||
@@ -100,9 +101,9 @@ class Vault {
|
||||
.then(resolve)
|
||||
.catch(({ message }) => {
|
||||
switch (message) {
|
||||
case db.vault.ERRORS.noVault:
|
||||
case VAULT_ERRORS.noVault:
|
||||
return Vault.createVault();
|
||||
case db.vault.ERRORS.vaultLocked:
|
||||
case VAULT_ERRORS.vaultLocked:
|
||||
return Vault.unlockVault();
|
||||
default:
|
||||
showToast("error", message);
|
||||
|
||||
@@ -36,6 +36,7 @@ type DialogButtonProps = ButtonProps & {
|
||||
};
|
||||
|
||||
type DialogProps = SxProp & {
|
||||
testId?: string;
|
||||
isOpen?: boolean;
|
||||
onClose?: (
|
||||
event?: React.MouseEvent<Element, MouseEvent> | React.KeyboardEvent<Element>
|
||||
@@ -65,6 +66,9 @@ function BaseDialog(props: React.PropsWithChildren<DialogProps>) {
|
||||
shouldFocusAfterRender
|
||||
onAfterOpen={(e) => onAfterOpen(e, props)}
|
||||
overlayClassName={"theme-scope-dialog"}
|
||||
data={{
|
||||
"test-id": props.testId
|
||||
}}
|
||||
style={{
|
||||
content: {
|
||||
top: 0,
|
||||
|
||||
@@ -44,8 +44,17 @@ export type FieldProps = InputProps & {
|
||||
};
|
||||
|
||||
function Field(props: FieldProps) {
|
||||
const { label, styles, helpText, action, sx, id, type, ...inputProps } =
|
||||
props;
|
||||
const {
|
||||
label,
|
||||
styles,
|
||||
helpText,
|
||||
action,
|
||||
sx,
|
||||
id,
|
||||
type,
|
||||
inputRef,
|
||||
...inputProps
|
||||
} = props;
|
||||
const [isPasswordVisible, setIsPasswordVisible] = useState(false);
|
||||
const colorScheme = useThemeStore((state) => state.colorScheme);
|
||||
|
||||
@@ -87,6 +96,7 @@ function Field(props: FieldProps) {
|
||||
<Flex mt={1} sx={{ position: "relative" }}>
|
||||
<Input
|
||||
{...inputProps}
|
||||
ref={inputRef}
|
||||
id={id}
|
||||
type={isPasswordVisible ? "text" : type || "text"}
|
||||
sx={{
|
||||
|
||||
@@ -85,7 +85,8 @@ import {
|
||||
Color,
|
||||
Note,
|
||||
Notebook as NotebookItem,
|
||||
Tag
|
||||
Tag,
|
||||
DefaultColors
|
||||
} from "@notesnook/core";
|
||||
import { MenuItem } from "@notesnook/ui";
|
||||
import {
|
||||
@@ -413,6 +414,7 @@ const menuItems: (
|
||||
key: "colors",
|
||||
title: "Assign color",
|
||||
icon: Colors.path,
|
||||
multiSelect: true,
|
||||
menu: { items: colorsToMenuItems(context?.color, ids) }
|
||||
},
|
||||
{
|
||||
@@ -574,14 +576,15 @@ function colorsToMenuItems(
|
||||
ids: string[]
|
||||
): MenuItem[] {
|
||||
return COLORS.map((color) => {
|
||||
const isChecked = !!noteColor && noteColor.title === color.title;
|
||||
return {
|
||||
type: "button",
|
||||
key: color.key,
|
||||
title: color.title,
|
||||
icon: Circle.path,
|
||||
styles: { icon: { color: StaticColors[color.key] } },
|
||||
isChecked: noteColor && noteColor.title === color.title,
|
||||
onClick: () => store.setColor(color.title, ...ids)
|
||||
styles: { icon: { color: DefaultColors[color.key] } },
|
||||
isChecked,
|
||||
onClick: () => store.setColor(color, isChecked, ...ids)
|
||||
} satisfies MenuItem;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -204,12 +204,15 @@ function EditorProperties(props: EditorPropertiesProps) {
|
||||
export default React.memo(EditorProperties);
|
||||
|
||||
function Colors({ noteId }: { noteId: string }) {
|
||||
const result = usePromise(async () =>
|
||||
(
|
||||
await db.relations.to({ id: noteId, type: "note" }, "color").resolve(1)
|
||||
).at(0)
|
||||
const color = useStore((store) => store.color);
|
||||
const result = usePromise(
|
||||
async () =>
|
||||
(
|
||||
await db.relations.to({ id: noteId, type: "note" }, "color").resolve(1)
|
||||
).at(0),
|
||||
[color]
|
||||
);
|
||||
|
||||
console.log(result);
|
||||
return (
|
||||
<Flex
|
||||
py={2}
|
||||
@@ -219,38 +222,37 @@ function Colors({ noteId }: { noteId: string }) {
|
||||
justifyContent: "center"
|
||||
}}
|
||||
>
|
||||
{COLORS.map((label) => (
|
||||
<Flex
|
||||
key={label.key}
|
||||
onClick={() => noteStore.get().setColor(label.key, noteId)}
|
||||
sx={{
|
||||
cursor: "pointer",
|
||||
position: "relative",
|
||||
alignItems: "center",
|
||||
justifyContent: "space-between"
|
||||
}}
|
||||
data-test-id={`properties-${label}`}
|
||||
>
|
||||
<Circle
|
||||
size={35}
|
||||
color={DefaultColors[label.key]}
|
||||
data-test-id={`toggle-state-${
|
||||
result.status === "fulfilled" &&
|
||||
label.key === result.value?.colorCode
|
||||
? "on"
|
||||
: "off"
|
||||
}`}
|
||||
/>
|
||||
{result.status === "fulfilled" &&
|
||||
label.key === result.value?.colorCode && (
|
||||
{COLORS.map((label) => {
|
||||
const isChecked =
|
||||
result.status === "fulfilled" &&
|
||||
DefaultColors[label.key] === result.value?.colorCode;
|
||||
return (
|
||||
<Flex
|
||||
key={label.key}
|
||||
onClick={() => noteStore.get().setColor(label, isChecked, noteId)}
|
||||
sx={{
|
||||
cursor: "pointer",
|
||||
position: "relative",
|
||||
alignItems: "center",
|
||||
justifyContent: "space-between"
|
||||
}}
|
||||
data-test-id={`properties-${label.key}`}
|
||||
>
|
||||
<Circle
|
||||
size={35}
|
||||
color={DefaultColors[label.key]}
|
||||
data-test-id={`toggle-state-${isChecked ? "on" : "off"}`}
|
||||
/>
|
||||
{isChecked && (
|
||||
<Checkmark
|
||||
color="white"
|
||||
size={18}
|
||||
sx={{ position: "absolute", left: "8px" }}
|
||||
/>
|
||||
)}
|
||||
</Flex>
|
||||
))}
|
||||
</Flex>
|
||||
);
|
||||
})}
|
||||
</Flex>
|
||||
);
|
||||
}
|
||||
@@ -271,9 +273,9 @@ function Notebooks({ noteId }: { noteId: string }) {
|
||||
mode="fixed"
|
||||
estimatedSize={50}
|
||||
getItemKey={(index) => result.value.getKey(index)}
|
||||
items={result.value.ids}
|
||||
renderItem={(id) => (
|
||||
<ListItemWrapper id={id as string} items={result.value} simplified />
|
||||
items={result.value.ungrouped}
|
||||
renderItem={({ item: id }) => (
|
||||
<ListItemWrapper id={id} items={result.value} simplified />
|
||||
)}
|
||||
/>
|
||||
</Section>
|
||||
@@ -294,9 +296,9 @@ function Reminders({ noteId }: { noteId: string }) {
|
||||
mode="fixed"
|
||||
estimatedSize={54}
|
||||
getItemKey={(index) => result.value.getKey(index)}
|
||||
items={result.value.ids}
|
||||
renderItem={(id) => (
|
||||
<ListItemWrapper id={id as string} items={result.value} simplified />
|
||||
items={result.value.ungrouped}
|
||||
renderItem={({ item: id }) => (
|
||||
<ListItemWrapper id={id} items={result.value} simplified />
|
||||
)}
|
||||
/>
|
||||
</Section>
|
||||
@@ -352,20 +354,18 @@ function SessionHistory({
|
||||
mode="fixed"
|
||||
estimatedSize={28}
|
||||
getItemKey={(index) => result.value.getKey(index)}
|
||||
items={result.value.ids}
|
||||
renderItem={(id) => (
|
||||
<ResolvedItem id={id as string} items={result.value}>
|
||||
{({ item }) =>
|
||||
item.type === "session" ? (
|
||||
<SessionItem
|
||||
noteId={noteId}
|
||||
session={item}
|
||||
dateCreated={dateCreated}
|
||||
isPreviewMode={isPreviewMode}
|
||||
onOpenPreviewSession={onOpenPreviewSession}
|
||||
/>
|
||||
) : null
|
||||
}
|
||||
items={result.value.ungrouped}
|
||||
renderItem={({ item: id }) => (
|
||||
<ResolvedItem type="session" id={id} items={result.value}>
|
||||
{({ item }) => (
|
||||
<SessionItem
|
||||
noteId={noteId}
|
||||
session={item}
|
||||
dateCreated={dateCreated}
|
||||
isPreviewMode={isPreviewMode}
|
||||
onOpenPreviewSession={onOpenPreviewSession}
|
||||
/>
|
||||
)}
|
||||
</ResolvedItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
@@ -24,7 +24,6 @@ import { store } from "../../stores/trash-store";
|
||||
import { Flex, Text } from "@theme-ui/components";
|
||||
import TimeAgo from "../time-ago";
|
||||
import { pluralize, toTitleCase } from "@notesnook/common";
|
||||
import { showUndoableToast } from "../../common/toasts";
|
||||
import { showToast } from "../../utils/toast";
|
||||
import { hashNavigate } from "../../navigation";
|
||||
import { useStore } from "../../stores/note-store";
|
||||
@@ -78,8 +77,8 @@ const menuItems: (item: TrashItem, ids?: string[]) => MenuItem[] = (
|
||||
key: "restore",
|
||||
title: "Restore",
|
||||
icon: Restore.path,
|
||||
onClick: () => {
|
||||
store.restore(ids);
|
||||
onClick: async () => {
|
||||
await store.restore(...ids);
|
||||
showToast("success", `${pluralize(ids.length, "item")} restored`);
|
||||
},
|
||||
multiSelect: true
|
||||
@@ -92,11 +91,10 @@ const menuItems: (item: TrashItem, ids?: string[]) => MenuItem[] = (
|
||||
variant: "dangerous",
|
||||
onClick: async () => {
|
||||
if (!(await showMultiPermanentDeleteConfirmation(ids.length))) return;
|
||||
showUndoableToast(
|
||||
`${pluralize(ids.length, "item")} permanently deleted`,
|
||||
() => store.delete(ids),
|
||||
() => store.delete(ids, true),
|
||||
() => store.refresh()
|
||||
await store.delete(...ids);
|
||||
showToast(
|
||||
"success",
|
||||
`${pluralize(ids.length, "item")} permanently deleted`
|
||||
);
|
||||
},
|
||||
multiSelect: true
|
||||
|
||||
@@ -17,7 +17,7 @@ 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 { useRef, useState, useCallback, useEffect, useMemo } from "react";
|
||||
import { useRef, useState, useCallback, useEffect } from "react";
|
||||
import { Flex, Text, Button } from "@theme-ui/components";
|
||||
import { Lock } from "../icons";
|
||||
import { db } from "../../common/db";
|
||||
@@ -26,6 +26,7 @@ import { useStore as useAppStore } from "../../stores/app-store";
|
||||
import Field from "../field";
|
||||
import { showToast } from "../../utils/toast";
|
||||
import { ErrorText } from "../error-text";
|
||||
import usePromise from "../../hooks/use-promise";
|
||||
|
||||
type UnlockProps = {
|
||||
noteId: string;
|
||||
@@ -35,25 +36,23 @@ function Unlock(props: UnlockProps) {
|
||||
|
||||
const [isWrong, setIsWrong] = useState(false);
|
||||
const [isUnlocking, setIsUnlocking] = useState(false);
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
|
||||
const passwordRef = useRef<HTMLInputElement>();
|
||||
const passwordRef = useRef<HTMLInputElement>(null);
|
||||
|
||||
const note = useMemo(
|
||||
() => (!isLoading ? db.notes.note(noteId)?.data : undefined),
|
||||
[noteId, isLoading]
|
||||
);
|
||||
const note = usePromise(() => db.notes.note(noteId), [noteId]);
|
||||
const openLockedSession = useEditorStore((store) => store.openLockedSession);
|
||||
const openSession = useEditorStore((store) => store.openSession);
|
||||
const setIsEditorOpen = useAppStore((store) => store.setIsEditorOpen);
|
||||
|
||||
const submit = useCallback(async () => {
|
||||
console.log("HELO", passwordRef.current);
|
||||
if (!passwordRef.current) return;
|
||||
setIsUnlocking(true);
|
||||
const password = passwordRef.current.value;
|
||||
try {
|
||||
if (!password) return;
|
||||
const note = await db.vault.open(noteId, password);
|
||||
console.log(note);
|
||||
openLockedSession(note);
|
||||
} catch (e) {
|
||||
if (
|
||||
@@ -72,12 +71,8 @@ function Unlock(props: UnlockProps) {
|
||||
|
||||
useEffect(() => {
|
||||
(async () => {
|
||||
setIsLoading(true);
|
||||
|
||||
await openSession(noteId);
|
||||
setIsEditorOpen(true);
|
||||
|
||||
setIsLoading(false);
|
||||
})();
|
||||
}, [openSession, setIsEditorOpen, noteId]);
|
||||
|
||||
@@ -106,7 +101,9 @@ function Unlock(props: UnlockProps) {
|
||||
mt={25}
|
||||
sx={{ fontSize: 36, textAlign: "center" }}
|
||||
>
|
||||
{note?.title || "Open note"}
|
||||
{note.status === "fulfilled" && note.value
|
||||
? note.value.title
|
||||
: "Open note"}
|
||||
</Text>
|
||||
</Flex>
|
||||
<Text
|
||||
@@ -129,7 +126,7 @@ function Unlock(props: UnlockProps) {
|
||||
sx={{ width: ["95%", "95%", "30%"] }}
|
||||
placeholder="Enter password"
|
||||
type="password"
|
||||
onKeyUp={async (e: KeyboardEvent) => {
|
||||
onKeyUp={async (e) => {
|
||||
if (e.key === "Enter") {
|
||||
await submit();
|
||||
} else if (isWrong) {
|
||||
|
||||
@@ -78,6 +78,7 @@ export function VirtualizedList<T>(props: VirtualizedListProps<T>) {
|
||||
position: "relative",
|
||||
gap: itemGap
|
||||
}}
|
||||
data-test-id="virtualized-list"
|
||||
>
|
||||
{virtualItems.map((row) => (
|
||||
<Box
|
||||
|
||||
@@ -70,6 +70,7 @@ function AddNotebookDialog(props: AddNotebookDialogProps) {
|
||||
}, [props.notebook?.id, props.edit, onClose, parentId]);
|
||||
return (
|
||||
<Dialog
|
||||
testId="add-notebook-dialog"
|
||||
isOpen={true}
|
||||
title={props.edit ? "Edit Notebook" : "Create a Notebook"}
|
||||
description={
|
||||
|
||||
@@ -52,6 +52,7 @@ function ConfirmDialog<TCheckId extends string>(
|
||||
|
||||
return (
|
||||
<Dialog
|
||||
testId="confirm-dialog"
|
||||
isOpen={true}
|
||||
title={title}
|
||||
width={width}
|
||||
|
||||
@@ -24,6 +24,7 @@ import Field from "../components/field";
|
||||
function ItemDialog(props) {
|
||||
return (
|
||||
<Dialog
|
||||
testId="item-dialog"
|
||||
isOpen={true}
|
||||
title={props.title}
|
||||
description={props.subtitle}
|
||||
|
||||
@@ -42,7 +42,8 @@ import { Notebook, isGroupHeader } from "@notesnook/core/dist/types";
|
||||
import {
|
||||
UncontrolledTreeEnvironment,
|
||||
Tree,
|
||||
TreeItemIndex
|
||||
TreeItemIndex,
|
||||
TreeEnvironmentRef
|
||||
} from "react-complex-tree";
|
||||
import { FlexScrollContainer } from "../components/scroll-container";
|
||||
import { pluralize } from "@notesnook/common";
|
||||
@@ -74,6 +75,7 @@ function MoveDialog({ onClose, noteIds }: MoveDialogProps) {
|
||||
const refreshNotebooks = useStore((store) => store.refresh);
|
||||
const notebooks = useStore((store) => store.notebooks);
|
||||
const reloadItem = useRef<(changedItemIds: TreeItemIndex[]) => void>();
|
||||
const treeRef = useRef<TreeEnvironmentRef>(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (!notebooks) {
|
||||
@@ -152,6 +154,7 @@ function MoveDialog({ onClose, noteIds }: MoveDialogProps) {
|
||||
|
||||
return (
|
||||
<Dialog
|
||||
testId="move-note-dialog"
|
||||
isOpen={true}
|
||||
title={"Select notebooks"}
|
||||
description={`Use ${
|
||||
@@ -211,9 +214,10 @@ function MoveDialog({ onClose, noteIds }: MoveDialogProps) {
|
||||
Reset selection
|
||||
</Button>
|
||||
)}
|
||||
{notebooks && (
|
||||
{notebooks && notebooks.ids.length > 0 ? (
|
||||
<FlexScrollContainer>
|
||||
<UncontrolledTreeEnvironment
|
||||
ref={treeRef}
|
||||
dataProvider={{
|
||||
onDidChangeTreeData(listener) {
|
||||
reloadItem.current = listener;
|
||||
@@ -300,7 +304,13 @@ function MoveDialog({ onClose, noteIds }: MoveDialogProps) {
|
||||
isExpandable={props.item.isFolder || false}
|
||||
isExpanded={props.context.isExpanded || false}
|
||||
toggle={props.context.toggleExpandedState}
|
||||
onCreateItem={() => reloadItem.current?.([props.item.index])}
|
||||
onCreateItem={() => {
|
||||
reloadItem.current?.([props.item.index]);
|
||||
treeRef.current?.expandItem(
|
||||
props.item.index,
|
||||
props.info.treeId
|
||||
);
|
||||
}}
|
||||
/>
|
||||
|
||||
{props.children}
|
||||
@@ -312,6 +322,27 @@ function MoveDialog({ onClose, noteIds }: MoveDialogProps) {
|
||||
<Tree treeId={"root"} rootItem="root" treeLabel="Tree Example" />
|
||||
</UncontrolledTreeEnvironment>
|
||||
</FlexScrollContainer>
|
||||
) : (
|
||||
<Flex
|
||||
sx={{
|
||||
my: 2,
|
||||
flexDirection: "column",
|
||||
justifyContent: "center",
|
||||
alignItems: "center"
|
||||
}}
|
||||
>
|
||||
<Text variant="body">
|
||||
Please add a notebook to start linking notes.
|
||||
</Text>
|
||||
<Button
|
||||
data-test-id="add-new-notebook"
|
||||
variant="secondary"
|
||||
sx={{ mt: 2 }}
|
||||
onClick={() => showAddNotebookDialog()}
|
||||
>
|
||||
Add new notebook
|
||||
</Button>
|
||||
</Flex>
|
||||
)}
|
||||
</Dialog>
|
||||
);
|
||||
@@ -388,9 +419,17 @@ function NotebookItem(props: {
|
||||
<Flex sx={{ alignItems: "center" }}>
|
||||
{isExpandable ? (
|
||||
isExpanded ? (
|
||||
<ChevronDown size={20} sx={{ height: "20px" }} />
|
||||
<ChevronDown
|
||||
data-test-id="collapse-notebook"
|
||||
size={20}
|
||||
sx={{ height: "20px" }}
|
||||
/>
|
||||
) : (
|
||||
<ChevronRight size={20} sx={{ height: "20px" }} />
|
||||
<ChevronRight
|
||||
data-test-id="expand-notebook"
|
||||
size={20}
|
||||
sx={{ height: "20px" }}
|
||||
/>
|
||||
)
|
||||
) : null}
|
||||
<SelectedCheck size={20} item={notebook} onClick={check} />
|
||||
@@ -411,7 +450,7 @@ function NotebookItem(props: {
|
||||
<TopicSelectionIndicator notebook={notebook} />
|
||||
<Button
|
||||
variant="secondary"
|
||||
data-test-id="create-topic"
|
||||
data-test-id="add-sub-notebook"
|
||||
sx={{ p: "small" }}
|
||||
>
|
||||
<Plus
|
||||
|
||||
@@ -51,6 +51,7 @@ function PasswordDialog(props) {
|
||||
);
|
||||
return (
|
||||
<Dialog
|
||||
testId="password-dialog"
|
||||
isOpen={true}
|
||||
title={props.title}
|
||||
description={props.subtitle}
|
||||
|
||||
@@ -45,6 +45,7 @@ function RecoveryKeyDialog(props) {
|
||||
|
||||
return (
|
||||
<Dialog
|
||||
testId="recovery-key-dialog"
|
||||
isOpen={true}
|
||||
title="Backup your recovery key"
|
||||
width={400}
|
||||
|
||||
@@ -105,6 +105,7 @@ function ReminderDialog(props) {
|
||||
|
||||
return (
|
||||
<Dialog
|
||||
testId="reminder-dialog"
|
||||
isOpen={true}
|
||||
title={reminder.title}
|
||||
onClose={() => props.onClose(false)}
|
||||
|
||||
@@ -30,6 +30,7 @@ export function useIsUserPremium() {
|
||||
}
|
||||
|
||||
export function isUserPremium(user?: User) {
|
||||
return true;
|
||||
if (IS_TESTING) return true;
|
||||
if (!user) user = userstore.get().user;
|
||||
if (!user) return false;
|
||||
|
||||
@@ -71,7 +71,7 @@ export const getDefaultSession = (sessionId?: string): EditorSession => {
|
||||
|
||||
class EditorStore extends BaseStore<EditorStore> {
|
||||
session = getDefaultSession();
|
||||
color = undefined;
|
||||
color?: string;
|
||||
tags: Tag[] = [];
|
||||
arePropertiesVisible = false;
|
||||
editorMargins = Config.get("editor:margins", true);
|
||||
@@ -326,6 +326,8 @@ class EditorStore extends BaseStore<EditorStore> {
|
||||
name: "favorite" | "pinned" | "readonly" | "localOnly" | "color",
|
||||
value: boolean | string
|
||||
) => {
|
||||
if (name === "color" && typeof value === "string")
|
||||
return this.set({ color: value });
|
||||
return this.saveSession(noteId, { [name]: value });
|
||||
};
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ import { store as selectionStore } from "./selection-store";
|
||||
import Vault from "../common/vault";
|
||||
import BaseStore from ".";
|
||||
import Config from "../utils/config";
|
||||
import { Note, VirtualizedGrouping } from "@notesnook/core";
|
||||
import { DefaultColors, Note, VirtualizedGrouping } from "@notesnook/core";
|
||||
import { Context } from "../components/list-container/types";
|
||||
|
||||
type ViewMode = "detailed" | "compact";
|
||||
@@ -129,23 +129,27 @@ class NoteStore extends BaseStore<NoteStore> {
|
||||
await this.refresh();
|
||||
};
|
||||
|
||||
setColor = async (color: string, ...ids: string[]) => {
|
||||
// try {
|
||||
// let note = db.notes.note(id);
|
||||
// if (!note) return;
|
||||
// const colorId =
|
||||
// db.tags.find(color)?.id || (await db.colors.add({ title: color }));
|
||||
// const isColored =
|
||||
// db.relations.from({ type: "color", id: colorId }, "note").length > 0;
|
||||
setColor = async (
|
||||
color: { key: string; title: string },
|
||||
isChecked: boolean,
|
||||
...ids: string[]
|
||||
) => {
|
||||
await db.relations.to({ type: "note", ids }, "color").unlink();
|
||||
if (!isChecked) {
|
||||
const colorId = await db.colors.add({
|
||||
title: color.title,
|
||||
colorCode: DefaultColors[color.key]
|
||||
});
|
||||
|
||||
// if (isColored)
|
||||
// await db.relations.unlink({ type: "color", id: colorId }, note._note);
|
||||
// else
|
||||
// await db.relations.add({ type: "color", id: colorId }, note._note);
|
||||
// const notes = await db.notes.all.items(ids)
|
||||
// TODO:
|
||||
for (const id of ids) {
|
||||
await db.relations.add(
|
||||
{ type: "color", id: colorId },
|
||||
{ type: "note", id }
|
||||
);
|
||||
}
|
||||
}
|
||||
await appStore.refreshNavItems();
|
||||
this.syncNoteWithEditor(ids, "color", color);
|
||||
this.syncNoteWithEditor(ids, "color", color.key);
|
||||
await this.refresh();
|
||||
};
|
||||
|
||||
|
||||
@@ -36,6 +36,7 @@ import {
|
||||
import {
|
||||
AnyColumnWithTable,
|
||||
ExpressionOrFactory,
|
||||
SelectExpression,
|
||||
SelectQueryBuilder,
|
||||
SqlBool,
|
||||
sql
|
||||
@@ -353,10 +354,29 @@ export class FilteredSelector<T extends Item> {
|
||||
|
||||
async grouped(options: GroupOptions) {
|
||||
console.time("getting items");
|
||||
|
||||
const fields: Array<
|
||||
SelectExpression<DatabaseSchema, keyof DatabaseSchema>
|
||||
> = ["id", "type", options.sortBy];
|
||||
if (this.type === "notes") fields.push("notes.pinned", "notes.conflicted");
|
||||
else if (this.type === "notebooks") fields.push("notebooks.pinned");
|
||||
else if (this.type === "attachments" && options.groupBy === "abc")
|
||||
fields.push("attachments.filename");
|
||||
else if (this.type === "reminders") {
|
||||
fields.push(
|
||||
"reminders.mode",
|
||||
"reminders.date",
|
||||
"reminders.recurringMode",
|
||||
"reminders.selectedDays",
|
||||
"reminders.disabled",
|
||||
"reminders.snoozeUntil"
|
||||
);
|
||||
}
|
||||
|
||||
const items = await this.filter
|
||||
.$if(!!this._limit, (eb) => eb.limit(this._limit))
|
||||
.$call(this.buildSortExpression(options))
|
||||
.select(["id", options.sortBy, "type"])
|
||||
.select(fields)
|
||||
.execute();
|
||||
console.timeEnd("getting items");
|
||||
console.log(items.length);
|
||||
|
||||
@@ -60,7 +60,7 @@ function getKeySelector(
|
||||
|
||||
const date = new Date();
|
||||
if (item.type === "reminder")
|
||||
return "Active"; // isReminderActive(item) ? "Active" : "Inactive";
|
||||
return isReminderActive(item) ? "Active" : "Inactive";
|
||||
else if (options.sortBy === "title")
|
||||
return getFirstCharacter(getTitle(item));
|
||||
else {
|
||||
|
||||
Reference in New Issue
Block a user