mirror of
https://github.com/streetwriters/notesnook.git
synced 2026-02-24 04:00:59 +01:00
web: add 'move to top' for sub-notebooks (#8066)
Signed-off-by: 01zulfi <85733202+01zulfi@users.noreply.github.com>
This commit is contained in:
@@ -113,4 +113,11 @@ export class NotebookItemModel extends BaseItemModel {
|
||||
await this.contextMenu.open(this.locator);
|
||||
await new ToggleModel(this.page, "menu-button-set-as-default").on();
|
||||
}
|
||||
|
||||
async isMoveToTopVisible() {
|
||||
await this.contextMenu.open(this.locator);
|
||||
return this.contextMenu.menuContainer
|
||||
.locator(getTestId("menu-button-move-to-top"))
|
||||
.isVisible();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -324,3 +324,30 @@ test("when default notebook is set, created note in colors context should go to
|
||||
|
||||
expect(await openedNotebook?.findNote(coloredNote)).toBeDefined();
|
||||
});
|
||||
|
||||
test("move to top option should not be available for root notebook", async ({
|
||||
page
|
||||
}) => {
|
||||
const app = new AppModel(page);
|
||||
await app.goto();
|
||||
const notebooks = await app.goToNotebooks();
|
||||
|
||||
const notebook = await notebooks.createNotebook(NOTEBOOK);
|
||||
|
||||
expect(await notebook?.isMoveToTopVisible()).toBe(false);
|
||||
});
|
||||
|
||||
test("move to top option should be available for sub-notebook", async ({
|
||||
page
|
||||
}) => {
|
||||
const app = new AppModel(page);
|
||||
await app.goto();
|
||||
const notebooks = await app.goToNotebooks();
|
||||
|
||||
const notebook = await notebooks.createNotebook(NOTEBOOK);
|
||||
const subNotebook = await notebook?.createSubnotebook({
|
||||
title: "Subnotebook 1"
|
||||
});
|
||||
|
||||
expect(await subNotebook?.isMoveToTopVisible()).toBe(true);
|
||||
});
|
||||
|
||||
@@ -229,7 +229,8 @@ import {
|
||||
mdiArrowCollapseRight,
|
||||
mdiHamburger,
|
||||
mdiNotePlus,
|
||||
mdiNoteEditOutline
|
||||
mdiNoteEditOutline,
|
||||
mdiArrowUp
|
||||
} from "@mdi/js";
|
||||
import { useTheme } from "@emotion/react";
|
||||
import { Theme } from "@notesnook/theme";
|
||||
@@ -582,3 +583,4 @@ export const SessionHistory = createIcon(mdiHistory);
|
||||
export const ColorRemove = createIcon(mdiCloseCircleOutline);
|
||||
export const ExpandSidebar = createIcon(mdiArrowCollapseRight);
|
||||
export const HamburgerMenu = createIcon(mdiMenu);
|
||||
export const ArrowUp = createIcon(mdiArrowUp);
|
||||
|
||||
@@ -25,12 +25,12 @@ import {
|
||||
ChevronDown,
|
||||
ChevronRight,
|
||||
NotebookEdit,
|
||||
Pin,
|
||||
Plus,
|
||||
RemoveShortcutLink,
|
||||
Shortcut,
|
||||
Trash,
|
||||
Notebook as NotebookIcon
|
||||
Notebook as NotebookIcon,
|
||||
ArrowUp
|
||||
} from "../icons";
|
||||
import { MenuItem } from "@notesnook/ui";
|
||||
import { hashNavigate, navigate } from "../../navigation";
|
||||
@@ -44,6 +44,7 @@ import { Multiselect } from "../../common/multi-select";
|
||||
import { strings } from "@notesnook/intl";
|
||||
import { db } from "../../common/db";
|
||||
import { createSetDefaultHomepageMenuItem } from "../../common";
|
||||
import { useStore as useNotebookStore } from "../../stores/notebook-store";
|
||||
|
||||
type NotebookProps = {
|
||||
item: NotebookType;
|
||||
@@ -163,7 +164,7 @@ export function Notebook(props: NotebookProps) {
|
||||
</Text>
|
||||
}
|
||||
menuItems={notebookMenuItems}
|
||||
context={{ refresh }}
|
||||
context={{ refresh, isRoot: depth === 0 }}
|
||||
sx={{
|
||||
mb: "small",
|
||||
borderRadius: "default",
|
||||
@@ -176,7 +177,7 @@ export function Notebook(props: NotebookProps) {
|
||||
export const notebookMenuItems: (
|
||||
notebook: NotebookType,
|
||||
ids?: string[],
|
||||
context?: { refresh?: () => void }
|
||||
context?: { refresh?: () => void; isRoot?: boolean }
|
||||
) => MenuItem[] = (notebook, ids = [], context) => {
|
||||
const defaultNotebook = db.settings.getDefaultNotebook();
|
||||
return [
|
||||
@@ -190,8 +191,7 @@ export const notebookMenuItems: (
|
||||
res ? context?.refresh?.() : null
|
||||
)
|
||||
},
|
||||
{ type: "separator", key: "sepep2" },
|
||||
|
||||
{ type: "separator", key: "sep0" },
|
||||
{
|
||||
type: "button",
|
||||
key: "edit",
|
||||
@@ -231,7 +231,31 @@ export const notebookMenuItems: (
|
||||
: strings.addShortcut(),
|
||||
onClick: () => appStore.addToShortcuts(notebook)
|
||||
},
|
||||
{ key: "sep", type: "separator" },
|
||||
{ key: "sep1", type: "separator" },
|
||||
{
|
||||
type: "button",
|
||||
key: "move-to-top",
|
||||
icon: ArrowUp.path,
|
||||
title: strings.moveToTop(),
|
||||
isHidden: context?.isRoot,
|
||||
onClick: async () => {
|
||||
if (context?.isRoot) return;
|
||||
|
||||
const parentId = await db.notebooks.parentId(notebook.id);
|
||||
if (!parentId) return;
|
||||
|
||||
await db.relations.unlink(
|
||||
{
|
||||
type: "notebook",
|
||||
id: parentId
|
||||
},
|
||||
notebook
|
||||
);
|
||||
await useNotebookStore.getState().refresh();
|
||||
},
|
||||
multiSelect: false
|
||||
},
|
||||
{ key: "sep2", type: "separator", isHidden: context?.isRoot },
|
||||
{
|
||||
type: "button",
|
||||
key: "movetotrash",
|
||||
|
||||
@@ -326,7 +326,10 @@ async function getActiveNotebookCommands() {
|
||||
|
||||
const commands: Command[] = [];
|
||||
|
||||
const menuItems = notebookMenuItems(notebook, [notebook.id]);
|
||||
const parentId = await db.notebooks.parentId(notebook.id);
|
||||
const menuItems = notebookMenuItems(notebook, [notebook.id], {
|
||||
isRoot: !parentId
|
||||
});
|
||||
for (const menuItem of menuItems) {
|
||||
commands.push(...menuItemToCommands(menuItem, group, "active-notebook"));
|
||||
}
|
||||
|
||||
@@ -51,3 +51,14 @@ test("updating notebook with empty title should throw", () =>
|
||||
notebookTest().then(async ({ db, id }) => {
|
||||
await expect(db.notebooks.add({ id, title: "" })).rejects.toThrow();
|
||||
}));
|
||||
|
||||
test("parentId() returns parentId if notebook is a subnotebook", () =>
|
||||
notebookTest().then(async ({ db, id }) => {
|
||||
const subId = await db.notebooks.add({ title: "Sub", id });
|
||||
expect(db.notebooks.parentId(subId)).toBe(id);
|
||||
}));
|
||||
|
||||
test("parentId() returns undefined if notebook is not a subnotebook", () =>
|
||||
notebookTest().then(async ({ db, id }) => {
|
||||
expect(db.notebooks.parentId(id)).toBeUndefined();
|
||||
}));
|
||||
|
||||
@@ -291,4 +291,17 @@ export class Notebooks implements ICollection {
|
||||
await this.collection.softDelete(ids);
|
||||
});
|
||||
}
|
||||
|
||||
async parentId(id: string): Promise<string | undefined> {
|
||||
const relation = await this.db.relations
|
||||
.to(
|
||||
{
|
||||
id: id,
|
||||
type: "notebook"
|
||||
},
|
||||
"notebook"
|
||||
)
|
||||
.get();
|
||||
return relation[0]?.fromId;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user