Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Update bookmarks tree move to root features #7586

3 changes: 2 additions & 1 deletion apps/app/public/static/locales/en_US/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -790,7 +790,8 @@
"new_folder": "New Folder",
"delete": "Delete Folder",
"drop_item_here": "Drag and drop item here",
"cancel_bookmark": "Un-bookmark this page"
"cancel_bookmark": "Un-bookmark this page",
"Move to the root": "Move to the root"
},
"v5_page_migration": {
"page_tree_not_avaliable" : "Page tree feature is not available yet.",
Expand Down
3 changes: 2 additions & 1 deletion apps/app/public/static/locales/ja_JP/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -824,7 +824,8 @@
"new_folder": "新しいフォルダ",
"delete": "フォルダを削除",
"drop_item_here": "ルートに配置する",
"cancel_bookmark": "このページのブックマークを解除"
"cancel_bookmark": "このページのブックマークを解除",
"move_to_root": "ルートに配置する"
},
"v5_page_migration": {
"page_tree_not_avaliable" : "Page Tree 機能は現在使用できません。",
Expand Down
3 changes: 2 additions & 1 deletion apps/app/public/static/locales/zh_CN/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -794,7 +794,8 @@
"new_folder": "新建文件夹",
"delete": "删除文件夹",
"drop_item_here": "将项目拖放到此处",
"cancel_bookmark": "取消收藏此页面"
"cancel_bookmark": "取消收藏此页面",
"move_to_root": "移动到根部"
},
"v5_page_migration": {
"page_tree_not_avaliable": "Page Tree 功能不可用",
Expand Down
15 changes: 13 additions & 2 deletions apps/app/src/components/Bookmarks/BookmarkFolderItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import {
import { IPageToDeleteWithMeta } from '~/interfaces/page';
import { onDeletedBookmarkFolderFunction, OnDeletedFunction } from '~/interfaces/ui';
import { useSWRBookmarkInfo, useSWRxCurrentUserBookmarks } from '~/stores/bookmark';
import { useSWRxBookamrkFolderAndChild } from '~/stores/bookmark-folder';
import { useSWRxBookmarkFolderAndChild } from '~/stores/bookmark-folder';
import { useBookmarkFolderDeleteModal, usePageDeleteModal } from '~/stores/modal';
import { useSWRxCurrentPage } from '~/stores/page';

Expand Down Expand Up @@ -49,7 +49,7 @@ export const BookmarkFolderItem: FC<BookmarkFolderItemProps> = (props: BookmarkF

const [targetFolder, setTargetFolder] = useState<string | null>(folderId);
const [isOpen, setIsOpen] = useState(_isOpen);
const { mutate: mutateBookmarkData } = useSWRxBookamrkFolderAndChild();
const { mutate: mutateBookmarkData } = useSWRxBookmarkFolderAndChild();
yuki-takei marked this conversation as resolved.
Show resolved Hide resolved
const { mutate: mutateUserBookmarks } = useSWRxCurrentUserBookmarks();
const [isRenameAction, setIsRenameAction] = useState<boolean>(false);
const [isCreateAction, setIsCreateAction] = useState<boolean>(false);
Expand Down Expand Up @@ -225,6 +225,15 @@ export const BookmarkFolderItem: FC<BookmarkFolderItemProps> = (props: BookmarkF
openDeleteBookmarkFolderModal(bookmarkFolder, { onDeleted: bookmarkFolderDeleteHandler });
}, [bookmarkFolder, mutateBookmarkData, mutateBookmarkInfo, openDeleteBookmarkFolderModal, t]);

const onClickMoveToRootHandler = useCallback(async() => {
try {
await updateBookmarkFolder(bookmarkFolder._id, bookmarkFolder.name, null);
await mutateBookmarkData();
}
catch (err) {
toastError(err);
}
}, [bookmarkFolder._id, bookmarkFolder.name, mutateBookmarkData]);

return (
<div id={`grw-bookmark-folder-item-${folderId}`} className="grw-foldertree-item-container">
Expand Down Expand Up @@ -277,6 +286,8 @@ export const BookmarkFolderItem: FC<BookmarkFolderItemProps> = (props: BookmarkF
<BookmarkFolderItemControl
onClickRename={onClickRenameHandler}
onClickDelete={onClickDeleteHandler}
onClickMoveToRoot={onClickMoveToRootHandler}
isMoveToRoot={bookmarkFolder.parent != null}
>
<div onClick={e => e.stopPropagation()}>
<DropdownToggle color="transparent" className="border-0 rounded btn-page-item-control p-0 grw-visible-on-hover mr-1">
Expand Down
33 changes: 25 additions & 8 deletions apps/app/src/components/Bookmarks/BookmarkFolderItemControl.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,22 @@ import {
Dropdown, DropdownItem, DropdownMenu, DropdownToggle,
} from 'reactstrap';


type BookmarkFolderItemControlProps = {
export const BookmarkFolderItemControl: React.FC<{
children?: React.ReactNode
isMoveToRoot: boolean
onClickRename: () => void
onClickDelete: () => void
}
export const BookmarkFolderItemControl = (props: BookmarkFolderItemControlProps): JSX.Element => {
onClickMoveToRoot: () => void
}> = ({
children,
isMoveToRoot,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

onClickMoveToRoot がセットされているかどうかで代用できるのでは?
代用できないのだとしたら変数名を canMoveToRoot に変更する

onClickRename,
onClickDelete,
onClickMoveToRoot,
}): JSX.Element => {
const { t } = useTranslation();
const { children, onClickRename, onClickDelete } = props;
const [isOpen, setIsOpen] = useState(false);

return (
<Dropdown isOpen={isOpen} toggle={() => setIsOpen(!isOpen)}>
{ children ?? (
Expand All @@ -23,18 +29,29 @@ export const BookmarkFolderItemControl = (props: BookmarkFolderItemControlProps)
</DropdownToggle>
) }
<DropdownMenu
positionFixed
modifiers={{ preventOverflow: { boundariesElement: undefined } }}
right={true}
modifiers={{ preventOverflow: { boundariesElement: 'viewport' } }}
container="body"
style={{ zIndex: 1055 }} /* make it larger than $zindex-modal of bootstrap */
jam411 marked this conversation as resolved.
Show resolved Hide resolved
>
<DropdownItem
onClick={onClickRename}
className="grw-page-control-dropdown-item"
>
<i className="icon-fw icon-action-redo grw-page-control-dropdown-icon"></i>
{t('Rename')}
</DropdownItem>
{isMoveToRoot && (
<DropdownItem
onClick={onClickMoveToRoot}
className="grw-page-control-dropdown-item"
>
<i className="fa fa-fw fa-bookmark-o grw-page-control-dropdown-icon"></i>
{t('bookmark_folder.move_to_root')}
</DropdownItem>
)}

<DropdownItem divider/>

<DropdownItem
className='pt-2 grw-page-control-dropdown-item text-danger'
onClick={onClickDelete}
Expand Down
4 changes: 2 additions & 2 deletions apps/app/src/components/Bookmarks/BookmarkFolderMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { addBookmarkToFolder, addNewFolder, toggleBookmark } from '~/client/util
import { toastError, toastSuccess } from '~/client/util/toastr';
import { BookmarkFolderItems } from '~/interfaces/bookmark-info';
import { useSWRBookmarkInfo, useSWRxCurrentUserBookmarks } from '~/stores/bookmark';
import { useSWRxBookamrkFolderAndChild } from '~/stores/bookmark-folder';
import { useSWRxBookmarkFolderAndChild } from '~/stores/bookmark-folder';
import { useSWRxCurrentPage } from '~/stores/page';

import { FolderIcon } from '../Icons/FolderIcon';
Expand All @@ -28,7 +28,7 @@ export const BookmarkFolderMenu = (props: Props): JSX.Element => {
const { t } = useTranslation();
const { children } = props;
const [isCreateAction, setIsCreateAction] = useState(false);
const { data: bookmarkFolders, mutate: mutateBookmarkFolderData } = useSWRxBookamrkFolderAndChild();
const { data: bookmarkFolders, mutate: mutateBookmarkFolderData } = useSWRxBookmarkFolderAndChild();
const [selectedItem, setSelectedItem] = useState<string | null>(null);
const { data: currentPage } = useSWRxCurrentPage();
const { data: userBookmarkInfo, mutate: mutateBookmarkInfo } = useSWRBookmarkInfo(currentPage?._id);
Expand Down
16 changes: 8 additions & 8 deletions apps/app/src/components/Bookmarks/BookmarkFolderMenuItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import { toastError, toastSuccess } from '~/client/util/toastr';
import { BookmarkFolderItems } from '~/interfaces/bookmark-info';
import { onDeletedBookmarkFolderFunction } from '~/interfaces/ui';
import { useSWRBookmarkInfo, useSWRxCurrentUserBookmarks } from '~/stores/bookmark';
import { useSWRxBookamrkFolderAndChild } from '~/stores/bookmark-folder';
import { useSWRxBookmarkFolderAndChild } from '~/stores/bookmark-folder';
import { useBookmarkFolderDeleteModal } from '~/stores/modal';
import { useSWRxCurrentPage } from '~/stores/page';

Expand All @@ -35,7 +35,7 @@ export const BookmarkFolderMenuItem = (props: Props): JSX.Element => {
} = props;
const { t } = useTranslation();
const [isOpen, setIsOpen] = useState(false);
const { mutate: mutateBookamrkData } = useSWRxBookamrkFolderAndChild();
const { mutate: mutateBookmarkData } = useSWRxBookmarkFolderAndChild();
yuki-takei marked this conversation as resolved.
Show resolved Hide resolved
const [selectedItem, setSelectedItem] = useState<string | null>(null);
const [isCreateAction, setIsCreateAction] = useState<boolean>(false);
const { data: currentPage } = useSWRxCurrentPage();
Expand All @@ -50,15 +50,15 @@ export const BookmarkFolderMenuItem = (props: Props): JSX.Element => {
const onPressEnterHandlerForCreate = useCallback(async(folderName: string) => {
try {
await addNewFolder(folderName, item._id);
await mutateBookamrkData();
await mutateBookmarkData();
setIsCreateAction(false);
toastSuccess(t('toaster.create_succeeded', { target: t('bookmark_folder.bookmark_folder'), ns: 'commons' }));
}
catch (err) {
toastError(err);
}

}, [item._id, mutateBookamrkData, t]);
}, [item._id, mutateBookmarkData, t]);

useEffect(() => {
if (isOpen) {
Expand Down Expand Up @@ -94,15 +94,15 @@ export const BookmarkFolderMenuItem = (props: Props): JSX.Element => {
return;
}
mutateBookmarkInfo();
mutateBookamrkData();
mutateBookmarkData();
toastSuccess(t('toaster.delete_succeeded', { target: t('bookmark_folder.bookmark_folder'), ns: 'commons' }));
};

if (item == null) {
return;
}
openDeleteBookmarkFolderModal(item, { onDeleted: bookmarkFolderDeleteHandler });
}, [item, mutateBookamrkData, mutateBookmarkInfo, openDeleteBookmarkFolderModal, t]);
}, [item, mutateBookmarkData, mutateBookmarkInfo, openDeleteBookmarkFolderModal, t]);

const onClickChildMenuItemHandler = useCallback(async(e, item) => {
e.stopPropagation();
Expand All @@ -117,14 +117,14 @@ export const BookmarkFolderMenuItem = (props: Props): JSX.Element => {
const toaster = isBookmarked ? 'toaster.update_successed' : 'toaster.add_succeeded';
toastSuccess(t(toaster, { target: t('bookmark_folder.bookmark'), ns: 'commons' }));
mutateUserBookmarks();
mutateBookamrkData();
mutateBookmarkData();
setSelectedItem(item._id);
mutateBookmarkInfo();
}
catch (err) {
toastError(err);
}
}, [onSelectedChild, isBookmarked, currentPage, t, mutateUserBookmarks, mutateBookamrkData, mutateBookmarkInfo]);
}, [onSelectedChild, isBookmarked, currentPage, t, mutateUserBookmarks, mutateBookmarkData, mutateBookmarkInfo]);

const renderBookmarkSubMenuItem = useCallback(() => {
if (!isOpen) {
Expand Down
12 changes: 3 additions & 9 deletions apps/app/src/components/Bookmarks/BookmarkFolderTree.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -31,17 +31,11 @@ $grw-bookmark-item-padding-left: 35px;
.list-group-item {
.grw-visible-on-hover {
display: none;

&:hover {
display: block;
}
}

.grw-count-badge {
display: block;

&:hover {
display: none;
&:hover {
.grw-visible-on-hover {
display: block;
}
}

Expand Down
80 changes: 41 additions & 39 deletions apps/app/src/components/Bookmarks/BookmarkFolderTree.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { BookmarkFolderItems, DragItemType, DRAG_ITEM_TYPE } from '~/interfaces/
import { IPageHasId, IPageToDeleteWithMeta } from '~/interfaces/page';
import { OnDeletedFunction } from '~/interfaces/ui';
import { useSWRBookmarkInfo, useSWRxCurrentUserBookmarks } from '~/stores/bookmark';
import { useSWRxBookamrkFolderAndChild } from '~/stores/bookmark-folder';
import { useSWRxBookmarkFolderAndChild } from '~/stores/bookmark-folder';
import { usePageDeleteModal } from '~/stores/modal';
import { useSWRxCurrentPage } from '~/stores/page';

Expand All @@ -35,7 +35,7 @@ export const BookmarkFolderTree = (props: BookmarkFolderTreeProps): JSX.Element
const { t } = useTranslation();
const { isUserHomePage } = props;
const { data: currentPage } = useSWRxCurrentPage();
const { data: bookmarkFolderData, mutate: mutateBookamrkData } = useSWRxBookamrkFolderAndChild();
const { data: bookmarkFolderData, mutate: mutateBookmarkData } = useSWRxBookmarkFolderAndChild();
const { data: userBookmarks, mutate: mutateUserBookmarks } = useSWRxCurrentUserBookmarks();
const { mutate: mutateBookmarkInfo } = useSWRBookmarkInfo(currentPage?._id);

Expand All @@ -61,43 +61,44 @@ export const BookmarkFolderTree = (props: BookmarkFolderTreeProps): JSX.Element
}
mutateUserBookmarks();
mutateBookmarkInfo();
mutateBookamrkData();
mutateBookmarkData();
};
openDeleteModal([pageToDelete], { onDeleted: pageDeletedHandler });
}, [mutateBookmarkInfo, mutateBookamrkData, mutateUserBookmarks, openDeleteModal, t]);

const itemDropHandler = async(item: DragItemDataType, dragType: string | null | symbol) => {
if (dragType === DRAG_ITEM_TYPE.FOLDER) {
try {
await updateBookmarkFolder(item.bookmarkFolder._id, item.bookmarkFolder.name, null);
await mutateBookamrkData();
toastSuccess(t('toaster.update_successed', { target: t('bookmark_folder.bookmark_folder'), ns: 'commons' }));
}
catch (err) {
toastError(err);
}
}
else {
try {
await addBookmarkToFolder(item._id, null);
await mutateUserBookmarks();
toastSuccess(t('toaster.add_succeeded', { target: t('bookmark_folder.bookmark'), ns: 'commons' }));
}
catch (err) {
toastError(err);
}
}

};
const isDroppable = (item: DragItemDataType, dragType: string | null | symbol) => {
if (dragType === DRAG_ITEM_TYPE.FOLDER) {
const isRootFolder = item.level === 0;
return !isRootFolder;
}
const isRootBookmark = item.parentFolder == null;
return !isRootBookmark;

};
}, [mutateBookmarkInfo, mutateBookmarkData, mutateUserBookmarks, openDeleteModal, t]);

/* TODO: update in bookmarks folder v2. */
// const itemDropHandler = async(item: DragItemDataType, dragType: string | null | symbol) => {
// if (dragType === DRAG_ITEM_TYPE.FOLDER) {
// try {
// await updateBookmarkFolder(item.bookmarkFolder._id, item.bookmarkFolder.name, null);
// await mutateBookmarkData();
// toastSuccess(t('toaster.update_successed', { target: t('bookmark_folder.bookmark_folder'), ns: 'commons' }));
// }
// catch (err) {
// toastError(err);
// }
// }
// else {
// try {
// await addBookmarkToFolder(item._id, null);
// await mutateUserBookmarks();
// toastSuccess(t('toaster.add_succeeded', { target: t('bookmark_folder.bookmark'), ns: 'commons' }));
// }
// catch (err) {
// toastError(err);
// }
// }

// };
// const isDroppable = (item: DragItemDataType, dragType: string | null | symbol) => {
// if (dragType === DRAG_ITEM_TYPE.FOLDER) {
// const isRootFolder = item.level === 0;
// return !isRootFolder;
// }
// const isRootBookmark = item.parentFolder == null;
// return !isRootBookmark;

// };
jam411 marked this conversation as resolved.
Show resolved Hide resolved

return (
<div className={`grw-folder-tree-container ${styles['grw-folder-tree-container']}` } >
Expand Down Expand Up @@ -128,7 +129,8 @@ export const BookmarkFolderTree = (props: BookmarkFolderTreeProps): JSX.Element
</div>
))}
</ul>
{bookmarkFolderData != null && bookmarkFolderData.length > 0 && (
{/* TODO: update in bookmarks folder v2. Also delete drop_item_here in translation.json, if don't need it. */}
{/* {bookmarkFolderData != null && bookmarkFolderData.length > 0 && (
<DragAndDropWrapper
useDropMode={true}
type={acceptedTypes}
Expand All @@ -141,7 +143,7 @@ export const BookmarkFolderTree = (props: BookmarkFolderTreeProps): JSX.Element
</div>
</div>
</DragAndDropWrapper>
)}
)} */}
</div>
);
};
8 changes: 4 additions & 4 deletions apps/app/src/components/Bookmarks/BookmarkItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { ValidationTarget } from '~/client/util/input-validator';
import { toastError, toastSuccess } from '~/client/util/toastr';
import { BookmarkFolderItems, DragItemDataType, DRAG_ITEM_TYPE } from '~/interfaces/bookmark-info';
import { IPageHasId, IPageInfoAll, IPageToDeleteWithMeta } from '~/interfaces/page';
import { useSWRxBookamrkFolderAndChild } from '~/stores/bookmark-folder';
import { useSWRxBookmarkFolderAndChild } from '~/stores/bookmark-folder';
import { useSWRxPageInfo } from '~/stores/page';

import ClosableTextInput from '../Common/ClosableTextInput';
Expand Down Expand Up @@ -41,7 +41,7 @@ export const BookmarkItem = (props: Props): JSX.Element => {
const dPagePath = new DevidedPagePath(bookmarkedPage.path, false, true);
const { latter: pageTitle, former: formerPagePath } = dPagePath;
const bookmarkItemId = `bookmark-item-${bookmarkedPage._id}`;
const { mutate: mutateBookamrkData } = useSWRxBookamrkFolderAndChild();
const { mutate: mutateBookmarkData } = useSWRxBookmarkFolderAndChild();
const { data: fetchedPageInfo } = useSWRxPageInfo(bookmarkedPage._id);

const paddingLeft = BASE_BOOKMARK_PADDING + (BASE_FOLDER_PADDING * (level + 1));
Expand All @@ -51,8 +51,8 @@ export const BookmarkItem = (props: Props): JSX.Element => {
};

useEffect(() => {
mutateBookamrkData();
}, [mutateBookamrkData]);
mutateBookmarkData();
}, [mutateBookmarkData]);

const bookmarkMenuItemClickHandler = useCallback(async() => {
await unbookmark(bookmarkedPage._id);
Expand Down
Loading