diff --git a/apps/web/src/dialogs/move-note-dialog.tsx b/apps/web/src/dialogs/move-note-dialog.tsx
index 20a89933d..94e30dc4a 100644
--- a/apps/web/src/dialogs/move-note-dialog.tsx
+++ b/apps/web/src/dialogs/move-note-dialog.tsx
@@ -17,41 +17,42 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
-import { useCallback, useEffect, useState } from "react";
-import { Box, Button, Flex, Input, Text } from "@theme-ui/components";
+import { useCallback, useEffect, useRef } from "react";
+import { Button, Flex, Text } from "@theme-ui/components";
import {
Plus,
ChevronDown,
- ChevronUp,
Circle,
CheckCircleOutline,
CheckIntermediate,
CheckRemove,
- CircleEmpty
+ CircleEmpty,
+ ChevronRight
} from "../components/icons";
import { db } from "../common/db";
import Dialog from "../components/dialog";
-import { useStore, store } from "../stores/notebook-store";
-import { store as notestore } from "../stores/note-store";
-import { Perform } from "../common/dialog-controller";
+import { useStore } from "../stores/notebook-store";
+import { store as noteStore } from "../stores/note-store";
+import { store as notebookStore } from "../stores/notebook-store";
+import { Perform, showAddNotebookDialog } from "../common/dialog-controller";
import { showToast } from "../utils/toast";
import { isMac } from "../utils/platform";
import { create } from "zustand";
-import { FilteredList } from "../components/filtered-list";
+import { Notebook, isGroupHeader } from "@notesnook/core/dist/types";
import {
- Notebook,
- GroupHeader,
- isGroupHeader
-} from "@notesnook/core/dist/types";
+ UncontrolledTreeEnvironment,
+ Tree,
+ TreeItemIndex
+} from "react-complex-tree";
+import { FlexScrollContainer } from "../components/scroll-container";
+import { pluralize } from "@notesnook/common";
type MoveDialogProps = { onClose: Perform; noteIds: string[] };
type NotebookReference = {
id: string;
- //topic?: string;
new: boolean;
op: "add" | "remove";
};
-type Item = Notebook | GroupHeader;
interface ISelectionStore {
selected: NotebookReference[];
@@ -70,17 +71,17 @@ function MoveDialog({ onClose, noteIds }: MoveDialogProps) {
const setSelected = useSelectionStore((store) => store.setSelected);
const setIsMultiselect = useSelectionStore((store) => store.setIsMultiselect);
const isMultiselect = useSelectionStore((store) => store.isMultiselect);
-
const refreshNotebooks = useStore((store) => store.refresh);
const notebooks = useStore((store) => store.notebooks);
- const getAllNotebooks = useCallback(async () => {
- await refreshNotebooks();
- return (store.get().notebooks?.ids.filter((a) => !isGroupHeader(a)) ||
- []) as string[];
- }, [refreshNotebooks]);
+ const reloadItem = useRef<(changedItemIds: TreeItemIndex[]) => void>();
useEffect(() => {
- if (!notebooks) return;
+ if (!notebooks) {
+ (async function () {
+ await refreshNotebooks();
+ })();
+ return;
+ }
// for (const notebook of notebooks.ids) {
// if (isGroupHeader(notebook)) continue;
@@ -138,7 +139,7 @@ function MoveDialog({ onClose, noteIds }: MoveDialogProps) {
// new: false
// });
// }
- }, [noteIds, notebooks, setSelected, setIsMultiselect]);
+ }, [noteIds, notebooks, refreshNotebooks, setSelected, setIsMultiselect]);
const _onClose = useCallback(
(result: boolean) => {
@@ -175,15 +176,16 @@ function MoveDialog({ onClose, noteIds }: MoveDialogProps) {
}
}
- notestore.refresh();
+ await noteStore.refresh();
+ await notebookStore.refresh();
- // const stringified = stringifySelected(selected);
- // if (stringified) {
- // showToast(
- // "success",
- // `${pluralize(noteIds.length, "note")} ${stringified}`
- // );
- // }
+ const stringified = stringifySelected(selected);
+ if (stringified) {
+ showToast(
+ "success",
+ `${pluralize(noteIds.length, "note")} ${stringified}`
+ );
+ }
_onClose(true);
}
@@ -204,202 +206,226 @@ function MoveDialog({ onClose, noteIds }: MoveDialogProps) {
setSelected(originalSelection);
setIsMultiselect(originalSelection.length > 1);
}}
- sx={{ textDecoration: "none", mt: 1 }}
+ sx={{ textDecoration: "none", mb: 2 }}
>
Reset selection
)}
-
- []
+ {notebooks && (
+
+ !isGroupHeader(t)
+ ) as string[]
+ };
+ }
- //db.lookup.notebooks(notebooks, query) || []
- }
- onCreateNewItem={async (title) => {
- await db.notebooks.add({
- title
- });
- }}
- renderItem={(notebook, _index, refresh, isSearching) => (
- notebooks?.item(id)}
- isSearching={isSearching}
- onCreateItem={async (title) => {
- // await db.notebooks.topics(notebook).add({ title });
- // refresh();
- }}
- />
- )}
- />
-
+ const notebook = (await db.notebooks.notebook(
+ itemId as string
+ ))!;
+ const children = await db.relations
+ .from({ type: "notebook", id: itemId as string }, "notebook")
+ .get();
+ return {
+ index: itemId,
+ data: notebook,
+ children: children.map((i) => i.toId),
+ isFolder: children.length > 0
+ };
+ },
+ async getTreeItems(itemIds) {
+ const records = await db.notebooks.all.records(
+ itemIds as string[],
+ db.settings.getGroupOptions("notebooks")
+ );
+ const children = await db.relations
+ .from(
+ { type: "notebook", ids: itemIds as string[] },
+ "notebook"
+ )
+ .get();
+ console.log(itemIds, notebooks?.ids);
+ return itemIds.filter(Boolean).map((id) => {
+ if (id === "root") {
+ return {
+ data: { title: "Root" },
+ index: id,
+ isFolder: true,
+ canMove: false,
+ canRename: false,
+ children: notebooks.ids.filter(
+ (t) => !isGroupHeader(t)
+ ) as string[]
+ };
+ }
+
+ const notebook = records[id];
+ const subNotebooks = children
+ .filter((r) => r.fromId === id)
+ .map((r) => r.toId);
+ // const totalNotes = allChildren.filter(
+ // (r) => r.fromId === id && r.toType === "note"
+ // ).length;
+ return {
+ index: id,
+ data: notebook,
+ children: subNotebooks,
+ isFolder: subNotebooks.length > 0
+ };
+ });
+ }
+ }}
+ renderItem={(props) => (
+ <>
+ reloadItem.current?.([props.item.index])}
+ />
+
+ {props.children}
+ >
+ )}
+ getItemTitle={(item) => item.data.title}
+ viewState={{}}
+ >
+
+
+
+ )}
);
}
-
+function calculateIndentation(
+ expandable: boolean,
+ depth: number,
+ base: number
+) {
+ if (expandable && depth > 0) return depth * 7 + base;
+ else if (depth === 0) return 0;
+ else return depth * 12 + base;
+}
function NotebookItem(props: {
- id: string;
- isSearching: boolean;
- resolve: (id: string) => Promise | undefined;
- onCreateItem: (title: string) => void;
+ notebook: Notebook;
+ isExpanded: boolean;
+ isExpandable: boolean;
+ toggle: () => void;
+ depth: number;
+ onCreateItem: () => void;
}) {
- const { id, resolve, isSearching, onCreateItem } = props;
-
- const [isCreatingNew, setIsCreatingNew] = useState(false);
- const [notebook, setNotebook] = useState();
+ const { notebook, isExpanded, toggle, depth, isExpandable, onCreateItem } =
+ props;
const setIsMultiselect = useSelectionStore((store) => store.setIsMultiselect);
const setSelected = useSelectionStore((store) => store.setSelected);
const isMultiselect = useSelectionStore((store) => store.isMultiselect);
- useEffect(() => {
- (async function () {
- setNotebook(await resolve(id));
- })();
- }, [id, resolve]);
+ const check: React.MouseEventHandler = useCallback(
+ (e) => {
+ e.stopPropagation();
+ e.preventDefault();
+
+ const { selected } = useSelectionStore.getState();
+
+ const isCtrlPressed = e.ctrlKey || e.metaKey;
+ if (isCtrlPressed) setIsMultiselect(true);
+
+ if (isMultiselect || isCtrlPressed) {
+ setSelected(selectMultiple(notebook, selected));
+ } else {
+ setSelected(selectSingle(notebook, selected));
+ }
+ },
+ [isMultiselect, notebook, setIsMultiselect, setSelected]
+ );
- if (!notebook) return null;
return (
-
-
- {
+ if (!isExpandable) {
+ check(e);
+ return;
+ }
+ e.stopPropagation();
+ e.preventDefault();
+ toggle();
+ }}
+ >
+
+ {isExpandable ? (
+ isExpanded ? (
+
+ ) : (
+
+ )
+ ) : null}
+
+
- {
- e.preventDefault();
- e.stopPropagation();
- const { selected } = useSelectionStore.getState();
-
- const isCtrlPressed = e.ctrlKey || e.metaKey;
- if (isCtrlPressed) setIsMultiselect(true);
-
- if (isMultiselect || isCtrlPressed) {
- setSelected(selectMultiple(notebook, selected));
- } else {
- setSelected(selectSingle(notebook, selected));
- }
- }}
- >
-
-
- {notebook.title}
- {/*
+ {notebook.title}
+ {/*
{" "}
({pluralize(notebook.topics.length, "topic")})
*/}
-
-
-
-
-
-
-
-
-
-
+
+
+
+
-
-
+ {
+ e.stopPropagation();
+ await showAddNotebookDialog(notebook.id);
+ onCreateItem();
+ }}
+ />
+
+
+
);
}
@@ -412,54 +438,16 @@ function TopicSelectionIndicator({ notebook }: { notebook: Notebook }) {
return ;
}
-// function TopicItem(props: { topic: Topic }) {
-// const { topic } = props;
-
-// const setSelected = useSelectionStore((store) => store.setSelected);
-// const setIsMultiselect = useSelectionStore((store) => store.setIsMultiselect);
-// const isMultiselect = useSelectionStore((store) => store.isMultiselect);
-
-// return (
-// {
-// const { selected } = useSelectionStore.getState();
-
-// const isCtrlPressed = e.ctrlKey || e.metaKey;
-// if (isCtrlPressed) setIsMultiselect(true);
-
-// if (isMultiselect || isCtrlPressed) {
-// setSelected(selectMultiple(topic, selected));
-// } else {
-// setSelected(selectSingle(topic, selected));
-// }
-// }}
-// >
-//
-//
-// {topic.title}
-//
-//
-// );
-// }
-
export default MoveDialog;
function SelectedCheck({
item,
- size = 20
+ size = 20,
+ onClick
}: {
item?: Notebook;
size?: number;
+ onClick?: React.MouseEventHandler;
}) {
const selectedItems = useSelectionStore((store) => store.selected);
@@ -469,17 +457,28 @@ function SelectedCheck({
selectedItem?.op === "remove" ? "remove" : selectedItem?.op === "add";
return selected === true ? (
-
+
) : selected === null ? (
) : selected === "remove" ? (
-
+
) : (
-
+
);
}
@@ -537,31 +536,29 @@ function selectSingle(topic: Notebook, array: NotebookReference[]) {
return selected;
}
-// function stringifySelected(suggestion: NotebookReference[]) {
-// const added = suggestion
-// .filter((a) => a.new && a.op === "add")
-// .map(resolveReference)
-// .filter(Boolean);
-// const removed = suggestion
-// .filter((a) => a.op === "remove")
-// .map(resolveReference)
-// .filter(Boolean);
-// if (!added.length && !removed.length) return;
+function stringifySelected(suggestion: NotebookReference[]) {
+ const added = suggestion.filter((a) => a.new && a.op === "add");
+ // .map(resolveReference)
+ // .filter(Boolean);
+ const removed = suggestion.filter((a) => a.op === "remove");
+ // .map(resolveReference)
+ // .filter(Boolean);
+ if (!added.length && !removed.length) return;
-// const parts = [];
-// if (added.length > 0) parts.push("added to");
-// if (added.length >= 1) parts.push(added[0]);
-// if (added.length > 1) parts.push(`and ${added.length - 1} others`);
+ const parts = [];
+ if (added.length > 0)
+ parts.push(`added to ${pluralize(added.length, "notebook")}`);
+ // if (added.length >= 1) parts.push(added[0]);
+ // if (added.length > 1) parts.push(`and ${added.length - 1} others`);
-// if (removed.length >= 1) {
-// if (parts.length > 0) parts.push("&");
-// parts.push("removed from");
-// parts.push(removed[0]);
-// }
-// if (removed.length > 1) parts.push(`and ${removed.length - 1} others`);
+ if (removed.length >= 1) {
+ if (parts.length > 0) parts.push("&");
+ parts.push(`removed from ${pluralize(added.length, "notebook")}`);
+ }
+ // if (removed.length > 1) parts.push(`and ${removed.length - 1} others`);
-// return parts.join(" ") + ".";
-// }
+ return parts.join(" ") + ".";
+}
// function resolveReference(ref: NotebookReference): string | undefined {
// const notebook = db.notebooks.notebook(ref.id);