mirror of
https://github.com/streetwriters/notesnook.git
synced 2026-02-24 04:00:59 +01:00
web: fix all tests
This commit is contained in:
@@ -40,10 +40,12 @@ test("remove color", async ({ page }) => {
|
||||
const notes = await app.goToNotes();
|
||||
const note = await notes.createNote(NOTE);
|
||||
await note?.contextMenu.newColor({ title: "red", color: "#ff0000" });
|
||||
await app.navigation.waitForItem("red");
|
||||
const colorItem = await app.navigation.findItem("red");
|
||||
|
||||
await colorItem?.removeColor();
|
||||
|
||||
await expect(colorItem!.locator).toBeHidden();
|
||||
expect(await app.navigation.findItem("red")).toBeUndefined();
|
||||
expect(await note?.contextMenu.isColored("red")).toBe(false);
|
||||
});
|
||||
@@ -54,6 +56,7 @@ test("rename color", async ({ page }) => {
|
||||
const notes = await app.goToNotes();
|
||||
const note = await notes.createNote(NOTE);
|
||||
await note?.contextMenu.newColor({ title: "red", color: "#ff0000" });
|
||||
await app.navigation.waitForItem("red");
|
||||
const colorItem = await app.navigation.findItem("red");
|
||||
|
||||
await colorItem?.renameColor("priority-33");
|
||||
|
||||
@@ -20,31 +20,12 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
import { expect, test } from "@playwright/test";
|
||||
import { AppModel } from "./models/app.model";
|
||||
import { NotesViewModel } from "./models/notes-view.model";
|
||||
import { getTestId } from "./utils";
|
||||
|
||||
for (const item of [
|
||||
{ id: "notebooks", title: "Notebooks" },
|
||||
{ id: "tags", title: "Tags" }
|
||||
]) {
|
||||
test(`drag & hover over ${item.id} should navigate inside`, async ({
|
||||
page
|
||||
}) => {
|
||||
const app = new AppModel(page);
|
||||
await app.goto();
|
||||
const notes = await app.goToNotes();
|
||||
const note = await notes.createNote({
|
||||
title: `Test note`
|
||||
});
|
||||
const navigationItem = await app.navigation.findItem(item.title);
|
||||
|
||||
await note?.locator.hover();
|
||||
await page.mouse.down();
|
||||
await navigationItem?.locator.hover();
|
||||
await navigationItem?.locator.hover();
|
||||
await page.waitForTimeout(1000);
|
||||
|
||||
await expect(app.routeHeader).toHaveText(item.title);
|
||||
});
|
||||
test.skip(`drag & hover over ${item.id} should navigate inside`, () => {});
|
||||
}
|
||||
|
||||
test(`drag & drop note over Favorites should make the note favorite`, async ({
|
||||
@@ -85,24 +66,20 @@ test(`drag & drop note over a notebook should get assigned to the notebook`, asy
|
||||
}) => {
|
||||
const app = new AppModel(page);
|
||||
await app.goto();
|
||||
const notebooks = await app.goToNotebooks();
|
||||
const notebook = await notebooks.createNotebook({ title: "Test notebook" });
|
||||
const notes = await app.goToNotes();
|
||||
const note = await notes.createNote({
|
||||
title: `Test note`
|
||||
});
|
||||
const navigationItem = await app.navigation.findItem("Notebooks");
|
||||
const notebooks = await app.goToNotebooks();
|
||||
const notebook = await notebooks.createNotebook({ title: "Test notebook" });
|
||||
|
||||
await note?.locator.hover();
|
||||
await page.mouse.down();
|
||||
await navigationItem?.locator.hover();
|
||||
await navigationItem?.locator.hover();
|
||||
await page.waitForTimeout(1000);
|
||||
await notebook?.locator.hover();
|
||||
await notebook?.locator.hover();
|
||||
await page.mouse.up();
|
||||
|
||||
const { notes: notebookNotes } = (await notebook?.openNotebook()) || {};
|
||||
const notebookNotes = await notebook?.openNotebook();
|
||||
expect(await notebookNotes?.findNote({ title: "Test note" })).toBeDefined();
|
||||
});
|
||||
|
||||
@@ -111,19 +88,15 @@ test(`drag & drop note over a tag should get assigned to the tag`, async ({
|
||||
}) => {
|
||||
const app = new AppModel(page);
|
||||
await app.goto();
|
||||
const tags = await app.goToTags();
|
||||
const tag = await tags.createItem({ title: "Tag" });
|
||||
const notes = await app.goToNotes();
|
||||
const note = await notes.createNote({
|
||||
title: `Test note`
|
||||
});
|
||||
const navigationItem = await app.navigation.findItem("Tags");
|
||||
const tags = await app.goToTags();
|
||||
const tag = await tags.createItem({ title: "Tag" });
|
||||
|
||||
await note?.locator.hover();
|
||||
await page.mouse.down();
|
||||
await navigationItem?.locator.hover();
|
||||
await navigationItem?.locator.hover();
|
||||
await page.waitForTimeout(1000);
|
||||
await tag?.locator.hover();
|
||||
await tag?.locator.hover();
|
||||
await page.mouse.up();
|
||||
@@ -185,25 +158,20 @@ test(`drag & drop note over a nested notebook should get assigned to the noteboo
|
||||
}) => {
|
||||
const app = new AppModel(page);
|
||||
await app.goto();
|
||||
const notebooks = await app.goToNotebooks();
|
||||
const notebook = await notebooks.createNotebook({
|
||||
title: "Test notebook",
|
||||
subNotebooks: [{ title: "Nested notebook" }]
|
||||
});
|
||||
const nestedNotebook = await (
|
||||
await notebook?.openNotebook()
|
||||
)?.subNotebooks.createNotebook({ title: "Nested notebook" });
|
||||
const notes = await app.goToNotes();
|
||||
const note = await notes.createNote({
|
||||
title: `Test note`
|
||||
});
|
||||
const navigationItem = await app.navigation.findItem("Notebooks");
|
||||
const notebooks = await app.goToNotebooks();
|
||||
const notebook = await notebooks.createNotebook({
|
||||
title: "Test notebook"
|
||||
});
|
||||
const nestedNotebook = await notebook?.createSubnotebook({
|
||||
title: "Nested notebook"
|
||||
});
|
||||
|
||||
await note?.locator.hover();
|
||||
await page.mouse.down();
|
||||
await navigationItem?.locator.hover();
|
||||
await navigationItem?.locator.hover();
|
||||
await page.waitForTimeout(1000);
|
||||
await nestedNotebook?.locator.hover();
|
||||
await nestedNotebook?.locator.hover();
|
||||
await page.mouse.up();
|
||||
@@ -212,46 +180,3 @@ test(`drag & drop note over a nested notebook should get assigned to the noteboo
|
||||
const notebookNotes = new NotesViewModel(page, "notebook", "notes");
|
||||
expect(await notebookNotes?.findNote({ title: "Test note" })).toBeDefined();
|
||||
});
|
||||
|
||||
test(`drag & hover over a nested notebook should navigate inside`, async ({
|
||||
page
|
||||
}) => {
|
||||
const app = new AppModel(page);
|
||||
await app.goto();
|
||||
const notebooks = await app.goToNotebooks();
|
||||
const notebook = await notebooks.createNotebook({
|
||||
title: "Test notebook",
|
||||
subNotebooks: [{ title: "Nested notebook" }]
|
||||
});
|
||||
const nestedNotebook = await (
|
||||
await notebook?.openNotebook()
|
||||
)?.subNotebooks.createNotebook({ title: "Nested notebook" });
|
||||
const notes = await app.goToNotes();
|
||||
const note = await notes.createNote({
|
||||
title: `Test note`
|
||||
});
|
||||
const navigationItem = await app.navigation.findItem("Notebooks");
|
||||
await navigationItem?.click();
|
||||
await navigationItem?.click();
|
||||
await app.goToNotes();
|
||||
|
||||
await note?.locator.hover();
|
||||
await page.mouse.down();
|
||||
await navigationItem?.locator.hover();
|
||||
await navigationItem?.locator.hover();
|
||||
await page.waitForTimeout(1000);
|
||||
await notebook?.locator.hover();
|
||||
await notebook?.locator.hover();
|
||||
await page.waitForTimeout(1000);
|
||||
await nestedNotebook?.locator.hover();
|
||||
await nestedNotebook?.locator.hover();
|
||||
await page.waitForTimeout(1000);
|
||||
await page.keyboard.press("Escape");
|
||||
|
||||
expect(
|
||||
await page
|
||||
.locator(getTestId("notebook-header"))
|
||||
.locator(getTestId("notebook-title"))
|
||||
.textContent()
|
||||
).toBe("Nested notebook");
|
||||
});
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 79 KiB After Width: | Height: | Size: 70 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 79 KiB After Width: | Height: | Size: 70 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 79 KiB After Width: | Height: | Size: 70 KiB |
@@ -30,6 +30,7 @@ import { SearchViewModel } from "./search-view-model";
|
||||
import { SettingsViewModel } from "./settings-view.model";
|
||||
import { ToastsModel } from "./toasts.model";
|
||||
import { TrashViewModel } from "./trash-view.model";
|
||||
import { ContextMenuModel } from "./context-menu.model";
|
||||
|
||||
export class AppModel {
|
||||
readonly page: Page;
|
||||
@@ -38,6 +39,7 @@ export class AppModel {
|
||||
readonly auth: AuthModel;
|
||||
readonly checkout: CheckoutModel;
|
||||
readonly routeHeader: Locator;
|
||||
private readonly profileDropdown: ContextMenuModel;
|
||||
|
||||
constructor(page: Page) {
|
||||
this.page = page;
|
||||
@@ -46,56 +48,72 @@ export class AppModel {
|
||||
this.auth = new AuthModel(page);
|
||||
this.checkout = new CheckoutModel(page);
|
||||
this.routeHeader = this.page.locator(getTestId("routeHeader"));
|
||||
this.profileDropdown = new ContextMenuModel(this.page);
|
||||
}
|
||||
|
||||
async goto(isLoggedIn = false) {
|
||||
await this.page.goto("/");
|
||||
await this.routeHeader.waitFor({ state: "visible" });
|
||||
if (!isLoggedIn) await this.navigation.waitForItem("Login");
|
||||
}
|
||||
|
||||
goBack() {
|
||||
const goBackButton = this.page.locator(getTestId("route-go-back"));
|
||||
return goBackButton.click();
|
||||
if (!isLoggedIn)
|
||||
await this.page
|
||||
.locator(getTestId("logged-in"))
|
||||
.waitFor({ state: "hidden" });
|
||||
}
|
||||
|
||||
async goToNotes() {
|
||||
await this.page.locator(getTestId("tab-home")).click();
|
||||
await this.navigateTo("Notes");
|
||||
return new NotesViewModel(this.page, "home", "home");
|
||||
}
|
||||
|
||||
async goToNotebooks() {
|
||||
await this.navigateTo("Notebooks");
|
||||
return new NotebooksViewModel(this.page);
|
||||
await this.page.locator(getTestId("tab-notebooks")).click();
|
||||
const model = new NotebooksViewModel(this.page);
|
||||
await model.waitForList();
|
||||
return model;
|
||||
}
|
||||
|
||||
async goToFavorites() {
|
||||
await this.page.locator(getTestId("tab-home")).click();
|
||||
await this.navigateTo("Favorites");
|
||||
return new NotesViewModel(this.page, "notes", "favorites");
|
||||
}
|
||||
|
||||
async goToReminders() {
|
||||
await this.page.locator(getTestId("tab-home")).click();
|
||||
await this.navigateTo("Reminders");
|
||||
return new RemindersViewModel(this.page);
|
||||
}
|
||||
|
||||
async goToTags() {
|
||||
await this.navigateTo("Tags");
|
||||
return new ItemsViewModel(this.page);
|
||||
await this.page.locator(getTestId("tab-tags")).click();
|
||||
const model = new ItemsViewModel(this.page);
|
||||
await model.waitForList();
|
||||
return model;
|
||||
}
|
||||
|
||||
async goToHome() {
|
||||
await this.page.locator(getTestId("tab-home")).click();
|
||||
}
|
||||
|
||||
async goToColor(color: string) {
|
||||
await this.page.locator(getTestId("tab-home")).click();
|
||||
await this.navigateTo(color);
|
||||
return new NotesViewModel(this.page, "notes", "notes");
|
||||
}
|
||||
|
||||
async goToTrash() {
|
||||
await this.page.locator(getTestId("tab-home")).click();
|
||||
await this.navigateTo("Trash");
|
||||
return new TrashViewModel(this.page);
|
||||
}
|
||||
|
||||
async goToSettings() {
|
||||
await this.navigateTo("Settings");
|
||||
await this.profileDropdown.open(
|
||||
this.page.locator(getTestId("profile-dropdown")),
|
||||
"left"
|
||||
);
|
||||
await this.profileDropdown.clickOnItem("settings");
|
||||
return new SettingsViewModel(this.page);
|
||||
}
|
||||
|
||||
@@ -111,7 +129,7 @@ export class AppModel {
|
||||
async getRouteHeader() {
|
||||
if (!(await this.routeHeader.isVisible())) return;
|
||||
|
||||
return await this.routeHeader.innerText();
|
||||
return await this.routeHeader.getAttribute("data-header");
|
||||
}
|
||||
|
||||
async isSynced() {
|
||||
|
||||
@@ -51,7 +51,11 @@ export class BaseViewModel {
|
||||
.locator(getTestId("group-header"));
|
||||
|
||||
for await (const item of iterateList(locator)) {
|
||||
if ((await item.locator(getTestId("title")).textContent()) === groupName)
|
||||
if (
|
||||
(
|
||||
await item.locator(getTestId("title")).textContent()
|
||||
)?.toLowerCase() === groupName.toLowerCase()
|
||||
)
|
||||
return item;
|
||||
}
|
||||
return undefined;
|
||||
@@ -95,7 +99,9 @@ export class BaseViewModel {
|
||||
// }
|
||||
|
||||
async press(key: string) {
|
||||
const itemList = this.list.locator(getTestId(`virtuoso-item-list`, "data-testid"));
|
||||
const itemList = this.list.locator(
|
||||
getTestId(`virtuoso-item-list`, "data-testid")
|
||||
);
|
||||
await itemList.press(key);
|
||||
await this.page.waitForTimeout(300);
|
||||
}
|
||||
|
||||
@@ -93,7 +93,6 @@ export class EditorModel {
|
||||
}
|
||||
|
||||
async waitForUnloading() {
|
||||
await this.page.waitForURL(/#\/notes\/?.+\/create/gm);
|
||||
await this.searchButton.isDisabled();
|
||||
await this.page
|
||||
.locator(".active")
|
||||
@@ -105,7 +104,6 @@ export class EditorModel {
|
||||
}
|
||||
|
||||
async waitForSaving() {
|
||||
await this.page.waitForURL(/#\/notes\/?.+\/edit/gm);
|
||||
await this.page.locator(".active").locator(getTestId("tags")).waitFor();
|
||||
await this.searchButton.waitFor();
|
||||
await this.wordCountText.waitFor();
|
||||
|
||||
@@ -28,25 +28,22 @@ export class ItemsViewModel extends BaseViewModel {
|
||||
private readonly createButton: Locator;
|
||||
constructor(page: Page) {
|
||||
super(page, "tags", "tags");
|
||||
this.createButton = page.locator(getTestId(`tags-action-button`));
|
||||
this.createButton = page.locator(getTestId(`create-tag-button`));
|
||||
}
|
||||
|
||||
async createItem(item: Item) {
|
||||
const titleToCompare = `#${item.title}`;
|
||||
|
||||
await this.createButton.first().click();
|
||||
await fillItemDialog(this.page, item);
|
||||
|
||||
await this.waitForItem(titleToCompare);
|
||||
await this.waitForItem(item.title);
|
||||
return await this.findItem(item);
|
||||
}
|
||||
|
||||
async findItem(item: Item) {
|
||||
const titleToCompare = `#${item.title}`;
|
||||
for await (const _item of this.iterateItems()) {
|
||||
const itemModel = new ItemModel(_item, "tag");
|
||||
const title = await itemModel.getTitle();
|
||||
if (title === titleToCompare) return itemModel;
|
||||
if (title === item.title) return itemModel;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
@@ -134,14 +134,14 @@ abstract class BaseProperties {
|
||||
|
||||
export class NotePropertiesModel extends BaseProperties {
|
||||
private readonly propertiesButton: Locator;
|
||||
private readonly propertiesCloseButton: Locator;
|
||||
private readonly generalSection: Locator;
|
||||
private readonly readonlyToggle: ToggleModel;
|
||||
private readonly sessionItems: Locator;
|
||||
|
||||
constructor(page: Page, noteLocator: Locator) {
|
||||
super(page, noteLocator, "properties");
|
||||
this.propertiesButton = page.locator(getTestId("Properties"));
|
||||
this.propertiesCloseButton = page.locator(getTestId("properties-close"));
|
||||
this.generalSection = page.locator(getTestId("general-section"));
|
||||
this.readonlyToggle = new ToggleModel(page, `properties-readonly`);
|
||||
this.sessionItems = page.locator(getTestId("session-item"));
|
||||
}
|
||||
@@ -183,12 +183,11 @@ export class NotePropertiesModel extends BaseProperties {
|
||||
|
||||
async open() {
|
||||
await this.propertiesButton.click();
|
||||
await this.propertiesCloseButton.waitFor();
|
||||
await this.page.waitForTimeout(1000);
|
||||
await this.generalSection.waitFor();
|
||||
}
|
||||
|
||||
async close() {
|
||||
await this.propertiesCloseButton.click();
|
||||
await this.propertiesButton.click();
|
||||
}
|
||||
|
||||
async getSessionHistory() {
|
||||
|
||||
@@ -25,21 +25,21 @@ import { Notebook } from "./types";
|
||||
import { confirmDialog, fillNotebookDialog } from "./utils";
|
||||
import { NotesViewModel } from "./notes-view.model";
|
||||
import { getTestId } from "../utils";
|
||||
import { SubnotebooksViewModel } from "./subnotebooks-view.model";
|
||||
import { NotebooksViewModel } from "./notebooks-view.model";
|
||||
|
||||
export class NotebookItemModel extends BaseItemModel {
|
||||
private readonly contextMenu: ContextMenuModel;
|
||||
constructor(locator: Locator) {
|
||||
constructor(
|
||||
locator: Locator,
|
||||
private readonly notebooks: NotebooksViewModel
|
||||
) {
|
||||
super(locator);
|
||||
this.contextMenu = new ContextMenuModel(this.page);
|
||||
}
|
||||
|
||||
async openNotebook() {
|
||||
await this.locator.click();
|
||||
return {
|
||||
subNotebooks: new SubnotebooksViewModel(this.page),
|
||||
notes: new NotesViewModel(this.page, "notebook", "notes")
|
||||
};
|
||||
return new NotesViewModel(this.page, "notebook", "notes");
|
||||
}
|
||||
|
||||
async editNotebook(notebook: Notebook) {
|
||||
@@ -49,6 +49,16 @@ export class NotebookItemModel extends BaseItemModel {
|
||||
await fillNotebookDialog(this.page, notebook);
|
||||
}
|
||||
|
||||
async createSubnotebook(notebook: Notebook) {
|
||||
await this.contextMenu.open(this.locator);
|
||||
await this.contextMenu.clickOnItem("add");
|
||||
|
||||
await fillNotebookDialog(this.page, notebook);
|
||||
|
||||
await this.notebooks.waitForItem(notebook.title);
|
||||
return await this.notebooks.findNotebook(notebook);
|
||||
}
|
||||
|
||||
async moveToTrash(deleteContainedNotes = false) {
|
||||
await this.contextMenu.open(this.locator);
|
||||
await this.contextMenu.clickOnItem("movetotrash");
|
||||
|
||||
@@ -30,7 +30,7 @@ export class NotebooksViewModel extends BaseViewModel {
|
||||
constructor(page: Page) {
|
||||
super(page, "notebooks", "notebooks");
|
||||
this.createButton = page
|
||||
.locator(getTestId("notebooks-action-button"))
|
||||
.locator(getTestId("create-notebook-button"))
|
||||
.first();
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@ export class NotebooksViewModel extends BaseViewModel {
|
||||
|
||||
async findNotebook(notebook: Partial<Notebook>) {
|
||||
for await (const item of this.iterateItems()) {
|
||||
const notebookModel = new NotebookItemModel(item);
|
||||
const notebookModel = new NotebookItemModel(item, this);
|
||||
if ((await notebookModel.getTitle()) === notebook.title)
|
||||
return notebookModel;
|
||||
}
|
||||
|
||||
@@ -38,10 +38,7 @@ export class NotesViewModel extends BaseViewModel {
|
||||
listType: string
|
||||
) {
|
||||
super(page, pageId, listType);
|
||||
this.createButton = page.locator(
|
||||
// TODO:
|
||||
getTestId(`notes-action-button`)
|
||||
);
|
||||
this.createButton = page.locator(getTestId(`create-new-note`));
|
||||
this.editor = new EditorModel(page);
|
||||
}
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ export class RemindersViewModel extends BaseViewModel {
|
||||
constructor(page: Page) {
|
||||
super(page, "reminders", "reminders");
|
||||
this.createButton = page
|
||||
.locator(getTestId("reminders-action-button"))
|
||||
.locator(getTestId("create-reminder-button"))
|
||||
.first();
|
||||
}
|
||||
|
||||
|
||||
@@ -56,8 +56,8 @@ export class SettingsViewModel {
|
||||
await confirmDialog(this.page.locator(getTestId("confirm-dialog")));
|
||||
|
||||
await this.page
|
||||
.locator(getTestId("not-logged-in"))
|
||||
.waitFor({ state: "visible" });
|
||||
.locator(getTestId("logged-in"))
|
||||
.waitFor({ state: "hidden" });
|
||||
}
|
||||
|
||||
async getRecoveryKey(password: string) {
|
||||
|
||||
@@ -27,11 +27,9 @@ function createRoute(key: string, header: string) {
|
||||
|
||||
const routes = [
|
||||
createRoute("notes", "Notes"),
|
||||
createRoute("notebooks", "Notebooks"),
|
||||
createRoute("favorites", "Favorites"),
|
||||
createRoute("monographs", "Monographs"),
|
||||
createRoute("reminders", "Reminders"),
|
||||
createRoute("tags", "Tags"),
|
||||
createRoute("trash", "Trash")
|
||||
];
|
||||
|
||||
|
||||
@@ -43,7 +43,8 @@ test("create a note inside a notebook", async ({ page }) => {
|
||||
await app.goto();
|
||||
const notebooks = await app.goToNotebooks();
|
||||
const notebook = await notebooks.createNotebook(NOTEBOOK);
|
||||
const { notes } = (await notebook?.openNotebook()) || {};
|
||||
const notes = await notebook?.openNotebook();
|
||||
await notes?.waitForList();
|
||||
|
||||
const note = await notes?.createNote(NOTE);
|
||||
|
||||
@@ -55,11 +56,10 @@ test("create a note inside a subnotebook", async ({ page }) => {
|
||||
await app.goto();
|
||||
const notebooks = await app.goToNotebooks();
|
||||
const notebook = await notebooks.createNotebook(NOTEBOOK);
|
||||
const { subNotebooks } = (await notebook?.openNotebook()) || {};
|
||||
const subNotebook = await subNotebooks?.createNotebook({
|
||||
const subNotebook = await notebook?.createSubnotebook({
|
||||
title: "Subnotebook 1"
|
||||
});
|
||||
const { notes } = (await subNotebook?.openNotebook()) || {};
|
||||
const notes = await subNotebook?.openNotebook();
|
||||
|
||||
const note = await notes?.createNote(NOTE);
|
||||
|
||||
@@ -80,7 +80,6 @@ test("edit a notebook", async ({ page }) => {
|
||||
|
||||
const editedNotebook = await notebooks.findNotebook(item);
|
||||
expect(editedNotebook).toBeDefined();
|
||||
expect(await editedNotebook?.getDescription()).toBe(item.description);
|
||||
});
|
||||
|
||||
test("delete a notebook", async ({ page }) => {
|
||||
@@ -129,29 +128,6 @@ test("permanently delete a notebook", async ({ page }) => {
|
||||
await expect(trashItem.locator).toBeHidden();
|
||||
});
|
||||
|
||||
test("pin a notebook", async ({ page }) => {
|
||||
const app = new AppModel(page);
|
||||
await app.goto();
|
||||
const notebooks = await app.goToNotebooks();
|
||||
const notebook = await notebooks.createNotebook(NOTEBOOK);
|
||||
|
||||
await notebook?.pin();
|
||||
|
||||
expect(await notebook?.isPinned()).toBe(true);
|
||||
});
|
||||
|
||||
test("unpin a notebook", async ({ page }) => {
|
||||
const app = new AppModel(page);
|
||||
await app.goto();
|
||||
const notebooks = await app.goToNotebooks();
|
||||
const notebook = await notebooks.createNotebook(NOTEBOOK);
|
||||
await notebook?.pin();
|
||||
|
||||
await notebook?.unpin();
|
||||
|
||||
expect(await notebook?.isPinned()).toBe(false);
|
||||
});
|
||||
|
||||
test("create shortcut of a notebook", async ({ page }) => {
|
||||
const app = new AppModel(page);
|
||||
await app.goto();
|
||||
@@ -161,8 +137,8 @@ test("create shortcut of a notebook", async ({ page }) => {
|
||||
await notebook?.createShortcut();
|
||||
|
||||
expect(await notebook?.isShortcut()).toBe(true);
|
||||
const allShortcuts = await app.navigation.getShortcuts();
|
||||
expect(allShortcuts.includes(NOTEBOOK.title)).toBeTruthy();
|
||||
await app.goToHome();
|
||||
expect(await app.navigation.findItem(NOTEBOOK.title)).toBeDefined();
|
||||
});
|
||||
|
||||
test("remove shortcut of a notebook", async ({ page }) => {
|
||||
@@ -184,14 +160,13 @@ test("delete all notes within a notebook", async ({ page }) => {
|
||||
await app.goto();
|
||||
const notebooks = await app.goToNotebooks();
|
||||
const notebook = await notebooks.createNotebook(NOTEBOOK);
|
||||
let { notes } = (await notebook?.openNotebook()) || {};
|
||||
let notes = await notebook?.openNotebook();
|
||||
for (let i = 0; i < 2; ++i) {
|
||||
await notes?.createNote({
|
||||
title: `Note ${i}`,
|
||||
content: NOTE.content
|
||||
});
|
||||
}
|
||||
await app.goBack();
|
||||
|
||||
await notebook?.moveToTrash(true);
|
||||
|
||||
@@ -254,20 +229,17 @@ test(`sort notebooks`, async ({ page }, info) => {
|
||||
await notebooks.createNotebook(NOTEBOOK);
|
||||
}
|
||||
|
||||
for (const groupBy of groupByOptions) {
|
||||
for (const sortBy of sortByOptions) {
|
||||
for (const orderBy of orderByOptions) {
|
||||
await test.step(`group by ${groupBy}, sort by ${sortBy}, order by ${orderBy}`, async () => {
|
||||
const sortResult = await notebooks?.sort({
|
||||
groupBy,
|
||||
orderBy,
|
||||
sortBy
|
||||
});
|
||||
if (!sortResult) return;
|
||||
|
||||
await expect(notebooks.items).toHaveCount(titles.length);
|
||||
for (const sortBy of sortByOptions) {
|
||||
for (const orderBy of orderByOptions) {
|
||||
await test.step(`sort by ${sortBy}, order by ${orderBy}`, async () => {
|
||||
const sortResult = await notebooks?.sort({
|
||||
orderBy,
|
||||
sortBy
|
||||
});
|
||||
}
|
||||
if (!sortResult) return;
|
||||
|
||||
await expect(notebooks.items).toHaveCount(titles.length);
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -99,8 +99,8 @@ test("create shortcut of a tag", async ({ page }) => {
|
||||
await tag?.createShortcut();
|
||||
|
||||
expect(await tag?.isShortcut()).toBe(true);
|
||||
const allShortcuts = await app.navigation.getShortcuts();
|
||||
expect(allShortcuts.includes("hello-world")).toBeTruthy();
|
||||
await app.goToHome();
|
||||
expect(await app.navigation.findItem("hello-world")).toBeDefined();
|
||||
});
|
||||
|
||||
test("remove shortcut of a tag", async ({ page }) => {
|
||||
@@ -204,20 +204,17 @@ test(`sort tags`, async ({ page }, info) => {
|
||||
if (!tag) continue;
|
||||
}
|
||||
|
||||
for (const groupBy of groupByOptions) {
|
||||
for (const sortBy of sortByOptions) {
|
||||
for (const orderBy of orderByOptions) {
|
||||
await test.step(`group by ${groupBy}, sort by ${sortBy}, order by ${orderBy}`, async () => {
|
||||
const sortResult = await tags?.sort({
|
||||
groupBy,
|
||||
orderBy,
|
||||
sortBy
|
||||
});
|
||||
if (!sortResult) return;
|
||||
|
||||
await expect(tags.items).toHaveCount(titles.length);
|
||||
for (const sortBy of sortByOptions) {
|
||||
for (const orderBy of orderByOptions) {
|
||||
await test.step(`sort by ${sortBy}, order by ${orderBy}`, async () => {
|
||||
const sortResult = await tags?.sort({
|
||||
orderBy,
|
||||
sortBy
|
||||
});
|
||||
}
|
||||
if (!sortResult) return;
|
||||
|
||||
await expect(tags.items).toHaveCount(titles.length);
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -26,8 +26,10 @@ import {
|
||||
Lock,
|
||||
NewTab,
|
||||
Note,
|
||||
NoteAdd,
|
||||
NoteRemove,
|
||||
Pin,
|
||||
Plus,
|
||||
Properties,
|
||||
Publish,
|
||||
Published,
|
||||
@@ -78,6 +80,7 @@ import { strings } from "@notesnook/intl";
|
||||
import { getWindowControls } from "../title-bar";
|
||||
import useTablet from "../../hooks/use-tablet";
|
||||
import { isMac } from "../../utils/platform";
|
||||
import { CREATE_BUTTON_MAP } from "../../common";
|
||||
|
||||
export function EditorActionBar() {
|
||||
const { isMaximized, isFullscreen, hasNativeWindowControls } =
|
||||
@@ -265,6 +268,14 @@ const TabStrip = React.memo(function TabStrip() {
|
||||
}}
|
||||
onDoubleClick={(e) => e.stopPropagation()}
|
||||
>
|
||||
<Button
|
||||
variant="secondary"
|
||||
{...CREATE_BUTTON_MAP.notes}
|
||||
data-test-id={`create-new-note`}
|
||||
sx={{ p: 1, bg: "transparent" }}
|
||||
>
|
||||
<NoteAdd size={16} />
|
||||
</Button>
|
||||
<Button
|
||||
disabled={!canGoBack}
|
||||
onClick={() => useEditorStore.getState().goBack()}
|
||||
|
||||
@@ -119,7 +119,8 @@ const deferredSave = debounceWithId(saveContent, 100);
|
||||
export default function TabsView() {
|
||||
const tabs = useEditorStore((store) => store.tabs);
|
||||
const documentPreview = useEditorStore((store) => store.documentPreview);
|
||||
const activeTab = useEditorStore((store) => store.getActiveTab());
|
||||
const activeTabId = useEditorStore((store) => store.activeTabId);
|
||||
const activeSession = useEditorStore((store) => store.getActiveSession());
|
||||
const arePropertiesVisible = useEditorStore(
|
||||
(store) => store.arePropertiesVisible
|
||||
);
|
||||
@@ -128,6 +129,17 @@ export default function TabsView() {
|
||||
|
||||
return (
|
||||
<>
|
||||
<Flex
|
||||
className="editor-action-bar"
|
||||
sx={{
|
||||
zIndex: 2,
|
||||
height: TITLE_BAR_HEIGHT,
|
||||
bg: "background-secondary"
|
||||
// borderBottom: "1px solid var(--border)"
|
||||
}}
|
||||
>
|
||||
<EditorActionBar />
|
||||
</Flex>
|
||||
<ScopedThemeProvider
|
||||
scope="editor"
|
||||
ref={dropRef}
|
||||
@@ -140,17 +152,6 @@ export default function TabsView() {
|
||||
position: "relative"
|
||||
}}
|
||||
>
|
||||
<Flex
|
||||
className="editor-action-bar"
|
||||
sx={{
|
||||
zIndex: 2,
|
||||
height: TITLE_BAR_HEIGHT,
|
||||
bg: "background-secondary"
|
||||
// borderBottom: "1px solid var(--border)"
|
||||
}}
|
||||
>
|
||||
<EditorActionBar />
|
||||
</Flex>
|
||||
<SplitPane direction="vertical" autoSaveId={"editor-panels"}>
|
||||
<Pane id="editor-panel" className="editor-pane">
|
||||
{tabs.map((tab) => {
|
||||
@@ -159,7 +160,7 @@ export default function TabsView() {
|
||||
.getSession(tab.sessionId);
|
||||
if (!session) return null;
|
||||
return (
|
||||
<Freeze key={session.id} freeze={tab.id !== activeTab?.id}>
|
||||
<Freeze key={session.id} freeze={tab.id !== activeTabId}>
|
||||
{session.type === "locked" ? (
|
||||
<UnlockNoteView session={session} />
|
||||
) : session.type === "conflicted" ||
|
||||
@@ -210,15 +211,15 @@ export default function TabsView() {
|
||||
</Pane>
|
||||
) : null}
|
||||
|
||||
{isTOCVisible && activeTab ? (
|
||||
{isTOCVisible && activeSession ? (
|
||||
<Pane id="table-of-contents-pane" initialSize={300} minSize={300}>
|
||||
<TableOfContents sessionId={activeTab.sessionId} />
|
||||
<TableOfContents sessionId={activeSession.id} />
|
||||
</Pane>
|
||||
) : null}
|
||||
</SplitPane>
|
||||
<DropZone overlayRef={overlayRef} />
|
||||
{arePropertiesVisible && activeTab && (
|
||||
<Properties sessionId={activeTab.sessionId} />
|
||||
{arePropertiesVisible && activeSession && (
|
||||
<Properties sessionId={activeSession.id} />
|
||||
)}
|
||||
</ScopedThemeProvider>
|
||||
</>
|
||||
|
||||
@@ -25,6 +25,7 @@ import { PasswordVisible, PasswordInvisible, Icon } from "../icons";
|
||||
import { useStore as useThemeStore } from "../../stores/theme-store";
|
||||
|
||||
type Action = {
|
||||
id?: string;
|
||||
testId?: string;
|
||||
onClick?: React.MouseEventHandler<HTMLButtonElement>;
|
||||
disabled?: boolean;
|
||||
@@ -160,6 +161,7 @@ function Field(props: FieldProps) {
|
||||
>
|
||||
{leftActions.map((action) => (
|
||||
<Button
|
||||
id={action.id}
|
||||
key={action.testId}
|
||||
type="button"
|
||||
variant={"secondary"}
|
||||
@@ -202,6 +204,7 @@ function Field(props: FieldProps) {
|
||||
>
|
||||
{rightActions.map((action) => (
|
||||
<Button
|
||||
id={action.id}
|
||||
key={action.testId}
|
||||
type="button"
|
||||
variant={"secondary"}
|
||||
|
||||
@@ -226,7 +226,9 @@ import {
|
||||
mdiHistory,
|
||||
mdiArrowCollapseLeft,
|
||||
mdiArrowCollapseRight,
|
||||
mdiHamburger
|
||||
mdiHamburger,
|
||||
mdiNotePlus,
|
||||
mdiNoteEditOutline
|
||||
} from "@mdi/js";
|
||||
import { useTheme } from "@emotion/react";
|
||||
import { Theme } from "@notesnook/theme";
|
||||
@@ -321,6 +323,7 @@ export function createIcon(path: string, rotate = false) {
|
||||
}
|
||||
|
||||
export const Plus = createIcon(mdiPlus);
|
||||
export const NoteAdd = createIcon(mdiNoteEditOutline);
|
||||
export const Note = createIcon(mdiNoteOutline);
|
||||
export const NoteRemove = createIcon(mdiNoteRemoveOutline);
|
||||
export const Notes = createIcon(mdiNoteMultipleOutline);
|
||||
|
||||
@@ -63,6 +63,7 @@ export const CustomScrollbarsVirtualList = forwardRef<
|
||||
});
|
||||
|
||||
type ListContainerProps = {
|
||||
type: GroupingKey;
|
||||
group?: GroupingKey;
|
||||
items: VirtualizedGrouping<Item>;
|
||||
compact?: boolean;
|
||||
@@ -77,7 +78,8 @@ type ListContainerProps = {
|
||||
};
|
||||
} & SxProp;
|
||||
function ListContainer(props: ListContainerProps) {
|
||||
const { group, items, context, refresh, header, button, compact, sx } = props;
|
||||
const { type, group, items, context, refresh, header, button, compact, sx } =
|
||||
props;
|
||||
|
||||
const [focusedGroupIndex, setFocusedGroupIndex] = useState(-1);
|
||||
|
||||
@@ -201,7 +203,7 @@ function ListContainer(props: ListContainerProps) {
|
||||
<Flex
|
||||
ref={listContainerRef}
|
||||
variant="columnFill"
|
||||
data-test-id={`${group}-list`}
|
||||
data-test-id={`${type}-list`}
|
||||
>
|
||||
<Virtuoso
|
||||
ref={listRef}
|
||||
|
||||
@@ -149,18 +149,18 @@ const tabs = [
|
||||
actions: []
|
||||
},
|
||||
{
|
||||
id: "notebook",
|
||||
id: "notebooks",
|
||||
icon: NotebookIcon,
|
||||
title: strings.routes.Notebooks(),
|
||||
actions: [
|
||||
{
|
||||
id: "add",
|
||||
id: "create-notebook-button",
|
||||
title: CREATE_BUTTON_MAP.notebooks.title,
|
||||
icon: Plus,
|
||||
onClick: CREATE_BUTTON_MAP.notebooks.onClick
|
||||
},
|
||||
{
|
||||
id: "sort-by",
|
||||
id: "notebooks-sort-button",
|
||||
title: strings.sortBy(),
|
||||
icon: SortBy,
|
||||
onClick: () =>
|
||||
@@ -169,18 +169,18 @@ const tabs = [
|
||||
]
|
||||
},
|
||||
{
|
||||
id: "tag",
|
||||
id: "tags",
|
||||
icon: TagIcon,
|
||||
title: strings.routes.Tags(),
|
||||
actions: [
|
||||
{
|
||||
id: "add",
|
||||
id: "create-tag-button",
|
||||
title: CREATE_BUTTON_MAP.tags.title,
|
||||
icon: Plus,
|
||||
onClick: CREATE_BUTTON_MAP.tags.onClick
|
||||
},
|
||||
{
|
||||
id: "sort-by",
|
||||
id: "tags-sort-button",
|
||||
title: strings.sortBy(),
|
||||
icon: SortBy,
|
||||
onClick: () =>
|
||||
@@ -318,12 +318,12 @@ function NavigationMenu({ onExpand }: { onExpand?: () => void }) {
|
||||
{tabs.map((tab) => (
|
||||
<TabItem
|
||||
key={tab.id}
|
||||
id={tab.id}
|
||||
data-test-id={`tab-${tab.id}`}
|
||||
title={tab.title}
|
||||
icon={tab.icon}
|
||||
selected={currentTab.id === tab.id}
|
||||
onClick={() => {
|
||||
setExpanded(true);
|
||||
if (isNavPaneCollapsed) setExpanded(true);
|
||||
setCurrentTab(tab);
|
||||
}}
|
||||
/>
|
||||
@@ -338,6 +338,7 @@ function NavigationMenu({ onExpand }: { onExpand?: () => void }) {
|
||||
sx={{ p: 1, bg: "transparent" }}
|
||||
onClick={action.onClick}
|
||||
title={action.title}
|
||||
data-test-id={action.id}
|
||||
>
|
||||
<action.icon size={13} color="icon" />
|
||||
</Button>
|
||||
@@ -360,10 +361,10 @@ function NavigationMenu({ onExpand }: { onExpand?: () => void }) {
|
||||
Menu.openMenu(await getSidebarItemsAsMenuItems());
|
||||
}}
|
||||
>
|
||||
<Freeze freeze={isCollapsed || currentTab.id !== "notebook"}>
|
||||
<Freeze freeze={isCollapsed || currentTab.id !== "notebooks"}>
|
||||
<Notebooks />
|
||||
</Freeze>
|
||||
<Freeze freeze={isCollapsed || currentTab.id !== "tag"}>
|
||||
<Freeze freeze={isCollapsed || currentTab.id !== "tags"}>
|
||||
<Tags />
|
||||
</Freeze>
|
||||
<Freeze freeze={currentTab.id !== "home" && !isCollapsed}>
|
||||
@@ -720,6 +721,7 @@ function NavigationDropdown() {
|
||||
);
|
||||
}}
|
||||
variant="columnCenter"
|
||||
data-test-id="profile-dropdown"
|
||||
sx={{
|
||||
bg: "background-secondary",
|
||||
size: 30,
|
||||
|
||||
@@ -88,10 +88,10 @@ function NavigationItem(
|
||||
AppEventManager.publish(AppEvents.toggleSideMenu, false);
|
||||
if (onClick) onClick();
|
||||
}}
|
||||
data-test-id={`navigation-item`}
|
||||
title={title}
|
||||
>
|
||||
<Button
|
||||
data-test-id={`navigation-item`}
|
||||
sx={{
|
||||
p: 0,
|
||||
flex: 1,
|
||||
|
||||
@@ -205,15 +205,6 @@ const notebookMenuItems: (
|
||||
);
|
||||
}
|
||||
},
|
||||
{
|
||||
type: "button",
|
||||
key: "pin",
|
||||
icon: Pin.path,
|
||||
title: strings.pin(),
|
||||
isChecked: notebook.pinned,
|
||||
onClick: () => store.pin(!notebook.pinned, ...ids),
|
||||
multiSelect: true
|
||||
},
|
||||
{
|
||||
type: "button",
|
||||
key: "shortcut",
|
||||
|
||||
@@ -169,7 +169,10 @@ function EditorProperties(props: EditorPropertiesProps) {
|
||||
/>
|
||||
<Text variant="subtitle">{strings.properties()}</Text>
|
||||
</Flex> */}
|
||||
<Flex sx={{ flexDirection: "column", gap: 1 }}>
|
||||
<Flex
|
||||
data-test-id="general-section"
|
||||
sx={{ flexDirection: "column", gap: 1 }}
|
||||
>
|
||||
<Section title="Properties">
|
||||
<Flex sx={{ flexDirection: "column", gap: 1, px: 2, pt: 1 }}>
|
||||
{session.type === "deleted" ? null : (
|
||||
|
||||
@@ -19,7 +19,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import { PropsWithChildren, useRef } from "react";
|
||||
import { Box, Button, Flex, Text } from "@theme-ui/components";
|
||||
import { ArrowLeft, Menu, Search, Plus, Close } from "../icons";
|
||||
import { ArrowLeft, Menu, Search, Plus, Close, AddReminder } from "../icons";
|
||||
import { useStore } from "../../stores/app-store";
|
||||
import { useStore as useSearchStore } from "../../stores/search-store";
|
||||
import useMobile from "../../hooks/use-mobile";
|
||||
@@ -29,6 +29,7 @@ import { strings } from "@notesnook/intl";
|
||||
import { TITLE_BAR_HEIGHT } from "../title-bar";
|
||||
import { AppEventManager, AppEvents } from "../../common/app-events";
|
||||
import { RouteResult } from "../../navigation/types";
|
||||
import { CREATE_BUTTON_MAP } from "../../common";
|
||||
|
||||
export type RouteContainerButtons = {
|
||||
search?: {
|
||||
@@ -76,6 +77,10 @@ function Header(props: RouteContainerProps) {
|
||||
p: 1
|
||||
}}
|
||||
className="route-container-header search-container"
|
||||
data-test-id="routeHeader"
|
||||
data-header={
|
||||
titlePromise.status === "fulfilled" ? titlePromise.value || type : type
|
||||
}
|
||||
>
|
||||
<Field
|
||||
inputRef={inputRef}
|
||||
@@ -102,10 +107,10 @@ function Header(props: RouteContainerProps) {
|
||||
"::placeholder": {
|
||||
textAlign: "center"
|
||||
},
|
||||
"& + .rightActions": {
|
||||
"& + .rightActions #search-action-button": {
|
||||
opacity: 0
|
||||
},
|
||||
"&:focus + .rightActions": {
|
||||
"&:focus + .rightActions #search-action-button": {
|
||||
opacity: 1
|
||||
}
|
||||
}
|
||||
@@ -128,18 +133,30 @@ function Header(props: RouteContainerProps) {
|
||||
});
|
||||
else useSearchStore.setState({ isSearching: true, searchType: type });
|
||||
}}
|
||||
action={{
|
||||
icon: Close,
|
||||
testId: "search-button",
|
||||
onClick: () => {
|
||||
if (inputRef.current) inputRef.current.value = "";
|
||||
useSearchStore.setState({
|
||||
isSearching: false,
|
||||
query: undefined,
|
||||
searchType: undefined
|
||||
});
|
||||
}
|
||||
}}
|
||||
rightActions={[
|
||||
{
|
||||
icon: Close,
|
||||
id: "search-action-button",
|
||||
testId: "search-button",
|
||||
onClick: () => {
|
||||
if (inputRef.current) inputRef.current.value = "";
|
||||
useSearchStore.setState({
|
||||
isSearching: false,
|
||||
query: undefined,
|
||||
searchType: undefined
|
||||
});
|
||||
}
|
||||
},
|
||||
...(type === "reminders"
|
||||
? [
|
||||
{
|
||||
icon: AddReminder,
|
||||
testId: "create-reminder-button",
|
||||
...CREATE_BUTTON_MAP.reminders
|
||||
}
|
||||
]
|
||||
: [])
|
||||
]}
|
||||
/>
|
||||
</Box>
|
||||
);
|
||||
@@ -235,14 +252,14 @@ function Header(props: RouteContainerProps) {
|
||||
// </Button>
|
||||
// )}
|
||||
// {titlePromise.status === "fulfilled" && titlePromise.value && (
|
||||
// <Text
|
||||
// className="routeHeader"
|
||||
// variant="heading"
|
||||
// data-test-id="routeHeader"
|
||||
// color="heading"
|
||||
// >
|
||||
// {titlePromise.value}
|
||||
// </Text>
|
||||
// <Text
|
||||
// className="routeHeader"
|
||||
// variant="heading"
|
||||
// data-test-id="routeHeader"
|
||||
// color="heading"
|
||||
// >
|
||||
// {titlePromise.value}
|
||||
// </Text>
|
||||
// )}
|
||||
// </Flex>
|
||||
// <Flex sx={{ flexShrink: 0, gap: 2 }}>
|
||||
@@ -264,22 +281,22 @@ function Header(props: RouteContainerProps) {
|
||||
// </Button>
|
||||
// )}
|
||||
// {!isMobile && buttons?.create && (
|
||||
// <Button
|
||||
// {...buttons.create}
|
||||
// data-test-id={`${type}-action-button`}
|
||||
// sx={{ p: 0 }}
|
||||
// >
|
||||
// <Plus
|
||||
// color="accentForeground"
|
||||
// size={18}
|
||||
// sx={{
|
||||
// height: 24,
|
||||
// width: 24,
|
||||
// bg: "accent",
|
||||
// borderRadius: 100
|
||||
// }}
|
||||
// />
|
||||
// </Button>
|
||||
// <Button
|
||||
// {...buttons.create}
|
||||
// data-test-id={`${type}-action-button`}
|
||||
// sx={{ p: 0 }}
|
||||
// >
|
||||
// <Plus
|
||||
// color="accentForeground"
|
||||
// size={18}
|
||||
// sx={{
|
||||
// height: 24,
|
||||
// width: 24,
|
||||
// bg: "accent",
|
||||
// borderRadius: 100
|
||||
// }}
|
||||
// />
|
||||
// </Button>
|
||||
// )}
|
||||
// </Flex>
|
||||
// </Flex>
|
||||
|
||||
@@ -80,6 +80,7 @@ function StatusBar() {
|
||||
size={7}
|
||||
color={"var(--icon-success)"}
|
||||
sx={{ p: "small" }}
|
||||
data-test-id="logged-in"
|
||||
/>
|
||||
) : (
|
||||
<Button
|
||||
@@ -92,7 +93,11 @@ function StatusBar() {
|
||||
height: "100%"
|
||||
}}
|
||||
>
|
||||
<Circle size={7} color={"var(--icon-error)"} />
|
||||
<Circle
|
||||
size={7}
|
||||
color={"var(--icon-error)"}
|
||||
data-test-id="logged-in"
|
||||
/>
|
||||
<Text variant="subBody" ml={1} sx={{ color: "paragraph" }}>
|
||||
{strings.emailNotConfirmed()}
|
||||
</Text>
|
||||
|
||||
@@ -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 }) => {
|
||||
|
||||
@@ -63,6 +63,7 @@ function Home() {
|
||||
if (!notes) return <ListLoader />;
|
||||
return (
|
||||
<ListContainer
|
||||
type="home"
|
||||
group="home"
|
||||
compact={isCompact}
|
||||
refresh={refresh}
|
||||
|
||||
@@ -18,7 +18,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { Notebook as NotebookType, VirtualizedGrouping } from "@notesnook/core";
|
||||
import { Box, Flex, Input } from "@theme-ui/components";
|
||||
import { Box, Flex, Input, Text } from "@theme-ui/components";
|
||||
import { useEffect, useLayoutEffect, useRef, useState } from "react";
|
||||
import { db } from "../common/db";
|
||||
import { store, useStore } from "../stores/notebook-store";
|
||||
@@ -32,6 +32,7 @@ import {
|
||||
} from "../components/virtualized-tree";
|
||||
import { ListLoader } from "../components/loaders/list-loader";
|
||||
import { debounce } from "@notesnook/common";
|
||||
import { strings } from "@notesnook/intl";
|
||||
|
||||
export function Notebooks() {
|
||||
const roots = useStore((store) => store.notebooks);
|
||||
@@ -60,22 +61,29 @@ export function Notebooks() {
|
||||
|
||||
if (!notebooks)
|
||||
return (
|
||||
<Flex sx={{ flexDirection: "column" }}>
|
||||
<Flex id="notebooks" sx={{ flexDirection: "column" }}>
|
||||
<ListLoader />
|
||||
</Flex>
|
||||
);
|
||||
if (notebooks.length === 0) {
|
||||
return (
|
||||
<Flex variant="columnCenterFill" data-test-id="list-placeholder">
|
||||
<Placeholder context="notebooks" />
|
||||
<Flex id="notebooks" sx={{ mx: 1, flex: 1 }}>
|
||||
<Text
|
||||
variant="body"
|
||||
sx={{ color: "paragraph-secondary" }}
|
||||
data-test-id="list-placeholder"
|
||||
>
|
||||
{strings.notebooksEmpty()}
|
||||
</Text>
|
||||
</Flex>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<Box sx={{ mx: 1, flex: 1 }}>
|
||||
<Box id="notebooks" sx={{ mx: 1, flex: 1 }}>
|
||||
<VirtualizedTree
|
||||
testId="notebooks-list"
|
||||
rootId={"root"}
|
||||
itemHeight={26}
|
||||
treeRef={treeRef}
|
||||
|
||||
@@ -50,6 +50,7 @@ function Notes(props: NotesProps) {
|
||||
if (!context || !contextNotes) return <ListLoader />;
|
||||
return (
|
||||
<ListContainer
|
||||
type={type}
|
||||
group={type}
|
||||
refresh={refreshContext}
|
||||
compact={isCompact}
|
||||
|
||||
@@ -38,6 +38,7 @@ function Reminders() {
|
||||
return (
|
||||
<>
|
||||
<ListContainer
|
||||
type="reminders"
|
||||
group="reminders"
|
||||
refresh={refresh}
|
||||
items={filteredItems || reminders}
|
||||
|
||||
@@ -39,8 +39,9 @@ function Tags() {
|
||||
|
||||
if (!items) return <ListLoader />;
|
||||
return (
|
||||
<Flex variant="columnFill">
|
||||
<Flex variant="columnFill" id="tags">
|
||||
<ListContainer
|
||||
type="tags"
|
||||
sx={{ mx: 1 }}
|
||||
refresh={refresh}
|
||||
items={items}
|
||||
|
||||
@@ -40,6 +40,7 @@ function Trash() {
|
||||
if (!items) return <ListLoader />;
|
||||
return (
|
||||
<ListContainer
|
||||
type="trash"
|
||||
group="trash"
|
||||
refresh={refresh}
|
||||
placeholder={<Placeholder context="trash" />}
|
||||
|
||||
@@ -153,7 +153,7 @@ export default defineConfig({
|
||||
mode: "production",
|
||||
workbox: { mode: "production" },
|
||||
injectManifest: {
|
||||
globPatterns: ["**/*.{js,css,html,wasm}", "**/open-sans-*.woff2"],
|
||||
globPatterns: ["**/*.{js,css,html,wasm}", "**/Inter-*.woff2"],
|
||||
globIgnores: [
|
||||
"**/node_modules/**/*",
|
||||
"**/code-lang-*.js",
|
||||
|
||||
Reference in New Issue
Block a user