Skip to content

Commit

Permalink
feat: move menu items tree (#910)
Browse files Browse the repository at this point in the history
  • Loading branch information
LinaYahya authored Jan 12, 2024
1 parent 6a0f7c5 commit f014f13
Show file tree
Hide file tree
Showing 22 changed files with 605 additions and 158 deletions.
4 changes: 2 additions & 2 deletions cypress/e2e/item/copy/gridCopyItem.cy.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { HOME_PATH, buildItemPath } from '../../../../src/config/paths';
import {
HOME_MODAL_ITEM_ID,
ITEM_MENU_COPY_BUTTON_CLASS,
TREE_MODAL_MY_ITEMS_ID,
buildItemCard,
buildItemMenu,
buildItemMenuButtonId,
Expand Down Expand Up @@ -63,7 +63,7 @@ describe('Copy Item in Grid', () => {

// copy
const { id: copyItemId } = SAMPLE_ITEMS.items[2];
const toItemPath = TREE_MODAL_MY_ITEMS_ID;
const toItemPath = HOME_MODAL_ITEM_ID;
copyItem({ id: copyItemId, toItemPath });

cy.wait('@copyItems').then(({ request: { url } }) => {
Expand Down
4 changes: 2 additions & 2 deletions cypress/e2e/item/copy/listCopyItem.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ import {
buildItemPath,
} from '../../../../src/config/paths';
import {
HOME_MODAL_ITEM_ID,
ITEM_MENU_COPY_BUTTON_CLASS,
TREE_MODAL_MY_ITEMS_ID,
TREE_MODAL_SHARED_ITEMS_ID,
buildItemMenu,
buildItemMenuButtonId,
Expand Down Expand Up @@ -77,7 +77,7 @@ describe('Copy Item in List', () => {

// copy
const { id: copyItemId } = SAMPLE_ITEMS.items[2];
copyItem({ id: copyItemId, toItemPath: TREE_MODAL_MY_ITEMS_ID });
copyItem({ id: copyItemId, toItemPath: HOME_MODAL_ITEM_ID });

cy.wait('@copyItems').then(({ request: { url } }) => {
expect(url).to.contain(copyItemId);
Expand Down
4 changes: 2 additions & 2 deletions cypress/e2e/item/copy/listCopyMultiple.cy.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { HOME_PATH, buildItemPath } from '../../../../src/config/paths';
import {
HOME_MODAL_ITEM_ID,
ITEMS_TABLE_COPY_SELECTED_ITEMS_ID,
TREE_MODAL_MY_ITEMS_ID,
buildItemsTableRowIdAttribute,
} from '../../../../src/config/selectors';
import ITEM_LAYOUT_MODES from '../../../../src/enums/itemLayoutModes';
Expand Down Expand Up @@ -74,7 +74,7 @@ describe('Copy items in List', () => {

// copy
const itemIds = [SAMPLE_ITEMS.items[2].id, SAMPLE_ITEMS.items[4].id];
copyItems({ itemIds, toItemPath: TREE_MODAL_MY_ITEMS_ID });
copyItems({ itemIds, toItemPath: HOME_MODAL_ITEM_ID });

cy.wait('@copyItems').then(({ request: { url } }) => {
itemIds.forEach((id) => {
Expand Down
6 changes: 3 additions & 3 deletions cypress/e2e/item/move/gridMoveItem.cy.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { HOME_PATH, buildItemPath } from '../../../../src/config/paths';
import {
HOME_MODAL_ITEM_ID,
ITEM_MENU_MOVE_BUTTON_CLASS,
TREE_MODAL_MY_ITEMS_ID,
buildItemMenu,
buildItemMenuButtonId,
} from '../../../../src/config/selectors';
Expand All @@ -21,7 +21,7 @@ const moveItem = ({
`#${buildItemMenu(movedItemId)} .${ITEM_MENU_MOVE_BUTTON_CLASS}`,
).click();

cy.fillTreeModal(toItemPath);
cy.handleTreeMenu(toItemPath);
};

describe('Move Item in Grid', () => {
Expand Down Expand Up @@ -70,7 +70,7 @@ describe('Move Item in Grid', () => {

// move
const { id: movedItem } = SAMPLE_ITEMS.items[2];
const toItem = TREE_MODAL_MY_ITEMS_ID;
const toItem = HOME_MODAL_ITEM_ID;
moveItem({ id: movedItem, toItemPath: toItem });

cy.wait('@moveItems').then(({ request: { body, url } }) => {
Expand Down
6 changes: 3 additions & 3 deletions cypress/e2e/item/move/listMoveItem.cy.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { HOME_PATH, buildItemPath } from '../../../../src/config/paths';
import {
HOME_MODAL_ITEM_ID,
ITEM_MENU_MOVE_BUTTON_CLASS,
TREE_MODAL_MY_ITEMS_ID,
buildItemMenu,
buildItemMenuButtonId,
} from '../../../../src/config/selectors';
Expand All @@ -25,7 +25,7 @@ const moveItem = ({
`#${buildItemMenu(movedItemId)} .${ITEM_MENU_MOVE_BUTTON_CLASS}`,
).click();

cy.fillTreeModal(toItemPath, rootId);
cy.handleTreeMenu(toItemPath, rootId);
};

describe('Move Item in List', () => {
Expand Down Expand Up @@ -77,7 +77,7 @@ describe('Move Item in List', () => {

// move
const { id: movedItem } = SAMPLE_ITEMS.items[2];
const toItem = TREE_MODAL_MY_ITEMS_ID;
const toItem = HOME_MODAL_ITEM_ID;
moveItem({ id: movedItem, toItemPath: toItem });

cy.wait('@moveItems').then(({ request: { body, url } }) => {
Expand Down
6 changes: 3 additions & 3 deletions cypress/e2e/item/move/listMoveMultiple.cy.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { HOME_PATH, buildItemPath } from '../../../../src/config/paths';
import {
HOME_MODAL_ITEM_ID,
ITEMS_TABLE_MOVE_SELECTED_ITEMS_ID,
TREE_MODAL_MY_ITEMS_ID,
buildItemsTableRowIdAttribute,
} from '../../../../src/config/selectors';
import { ITEM_LAYOUT_MODES } from '../../../../src/enums';
Expand All @@ -23,7 +23,7 @@ const moveItems = ({

cy.wait(TABLE_ITEM_RENDER_TIME);
cy.get(`#${ITEMS_TABLE_MOVE_SELECTED_ITEMS_ID}`).click();
cy.fillTreeModal(toItemPath);
cy.handleTreeMenu(toItemPath);
};

describe('Move Items in List', () => {
Expand Down Expand Up @@ -75,7 +75,7 @@ describe('Move Items in List', () => {

// move
const itemIds = [SAMPLE_ITEMS.items[2].id, SAMPLE_ITEMS.items[4].id];
const toItem = TREE_MODAL_MY_ITEMS_ID;
const toItem = HOME_MODAL_ITEM_ID;
moveItems({ itemIds, toItemPath: toItem });

cy.wait('@moveItems').then(({ request: { body, url } }) => {
Expand Down
5 changes: 5 additions & 0 deletions cypress/fixtures/items.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,11 @@ const sampleItems: DiscriminatedItem[] = [
settings: {
hasThumbnail: false,
},
extra: {
[ItemType.FOLDER]: {
childrenOrder: ['fdf09f5a-5688-11eb-ae93-0242ac130004'],
},
},
},
{
...DEFAULT_FOLDER_ITEM,
Expand Down
42 changes: 39 additions & 3 deletions cypress/support/commands/item.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
CUSTOM_APP_CYPRESS_ID,
CUSTOM_APP_URL_ID,
FOLDER_FORM_DESCRIPTION_ID,
HOME_MODAL_ITEM_ID,
ITEM_FORM_APP_URL_ID,
ITEM_FORM_CONFIRM_BUTTON_ID,
ITEM_FORM_DOCUMENT_TEXT_SELECTOR,
Expand All @@ -13,8 +14,9 @@ import {
SHARE_ITEM_EMAIL_INPUT_ID,
SHARE_ITEM_SHARE_BUTTON_ID,
TREE_MODAL_CONFIRM_BUTTON_ID,
TREE_MODAL_MY_ITEMS_ID,
buildHomeModalItemID,
buildItemFormAppOptionId,
buildItemRowArrowId,
buildPermissionOptionId,
buildTreeItemId,
} from '../../../src/config/selectors';
Expand Down Expand Up @@ -44,9 +46,44 @@ Cypress.Commands.add(
},
);

Cypress.Commands.add(
'handleTreeMenu',
(toItemPath, treeRootId = HOME_MODAL_ITEM_ID) => {
const ids = getParentsIdsFromPath(toItemPath);

cy.wait(TREE_VIEW_PAUSE);

[HOME_MODAL_ITEM_ID, ...ids].forEach((value, idx, array) => {
cy.get(`#${treeRootId}`).then(($tree) => {
// click on the element
if (idx === array.length - 1) {
cy.wrap($tree)
.get(`#${buildHomeModalItemID(value)}`)
.first()
.click();
}
// if can't find children click on parent (current value)
if (
idx !== array.length - 1 &&
!$tree.find(`#${buildTreeItemId(array[idx + 1], treeRootId)}`).length
) {
cy.wrap($tree)
.get(`#${buildHomeModalItemID(value)}`)
.trigger('mouseover')
.get(`#${buildItemRowArrowId(value)}`)
.first()
.click();
}
});
});

cy.get(`#${TREE_MODAL_CONFIRM_BUTTON_ID}`).click();
},
);

Cypress.Commands.add(
'fillTreeModal',
(toItemPath, treeRootId = TREE_MODAL_MY_ITEMS_ID) => {
(toItemPath, treeRootId = HOME_MODAL_ITEM_ID) => {
const ids = getParentsIdsFromPath(toItemPath);

cy.wait(TREE_VIEW_PAUSE);
Expand Down Expand Up @@ -83,7 +120,6 @@ Cypress.Commands.add(
cy.get(`#${TREE_MODAL_CONFIRM_BUTTON_ID}`).click();
},
);

Cypress.Commands.add(
'fillBaseItemModal',
({ name = '' }, { confirm = true } = {}) => {
Expand Down
2 changes: 1 addition & 1 deletion cypress/support/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ declare global {
): void;

fillTreeModal(path: string, rootId?: string): void;

handleTreeMenu(path: string, rootId?: string): void;
switchMode(mode: string): void;
goToItemInGrid(path: string): void;
goToItemInList(path: string): void;
Expand Down
76 changes: 58 additions & 18 deletions src/components/common/MoveButton.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useContext } from 'react';
import { useEffect, useState } from 'react';

import { IconButtonProps } from '@mui/material/IconButton';

Expand All @@ -8,13 +8,18 @@ import {
MoveButton as GraaspMoveButton,
} from '@graasp/ui';

import { validate } from 'uuid';

import { mutations } from '@/config/queryClient';

import { useBuilderTranslation } from '../../config/i18n';
import {
HOME_MODAL_ITEM_ID,
ITEM_MENU_MOVE_BUTTON_CLASS,
ITEM_MOVE_BUTTON_CLASS,
} from '../../config/selectors';
import { BUILDER } from '../../langs/constants';
import { MoveItemModalContext } from '../context/MoveItemModalContext';
import TreeModal, { TreeModalProps } from '../main/MoveTreeModal';

type MoveButtonProps = {
itemIds: string[];
Expand All @@ -25,36 +30,71 @@ type MoveButtonProps = {
};

const MoveButton = ({
itemIds,
itemIds: defaultItemsIds,
color = 'default',
id,
type = ActionButton.ICON_BUTTON,
onClick,
}: MoveButtonProps): JSX.Element | null => {
}: MoveButtonProps): JSX.Element => {
const { t: translateBuilder } = useBuilderTranslation();
const { mutate: moveItems } = mutations.useMoveItems();

const [open, setOpen] = useState(false);
const [itemIds, setItemIds] = useState<string[]>(defaultItemsIds || []);

const openMoveModal = (newItemIds: string[]) => {
setOpen(true);
setItemIds(newItemIds);
};

const { openModal: openMoveModal } = useContext(MoveItemModalContext);
const onClose = () => {
setOpen(false);
};

// TODO: return error?
if (!openMoveModal) {
return null;
}
const onConfirm: TreeModalProps['onConfirm'] = (payload) => {
// change item's root id to null
const newPayload = {
...payload,
to:
payload.to && payload.to !== HOME_MODAL_ITEM_ID && validate(payload.to)
? payload.to
: undefined,
};
moveItems(newPayload);
onClose();
};
useEffect(() => {
// necessary to sync prop with a state because move-many-items' targets are updated dynamically with the table
setItemIds(defaultItemsIds);
}, [defaultItemsIds]);

const handleMove = () => {
openMoveModal(itemIds);
onClick?.();
};

return (
<GraaspMoveButton
color={color}
type={type}
id={id}
onClick={handleMove}
text={translateBuilder(BUILDER.MOVE_BUTTON)}
menuItemClassName={ITEM_MENU_MOVE_BUTTON_CLASS}
iconClassName={ITEM_MOVE_BUTTON_CLASS}
/>
<>
<GraaspMoveButton
color={color}
type={type}
id={id}
onClick={handleMove}
text={translateBuilder(BUILDER.MOVE_BUTTON)}
menuItemClassName={ITEM_MENU_MOVE_BUTTON_CLASS}
iconClassName={ITEM_MOVE_BUTTON_CLASS}
/>

{itemIds.length > 0 && open && (
<TreeModal
onClose={onClose}
open={open}
itemIds={itemIds}
onConfirm={onConfirm}
title={BUILDER.MOVE_ITEM_MODAL_TITLE}
/>
)}
</>
);
};

Expand Down
4 changes: 2 additions & 2 deletions src/components/context/CreateShortcutModalContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {

import { useBuilderTranslation } from '../../config/i18n';
import { mutations } from '../../config/queryClient';
import { TREE_MODAL_MY_ITEMS_ID } from '../../config/selectors';
import { HOME_MODAL_ITEM_ID } from '../../config/selectors';
import { BUILDER } from '../../langs/constants';
import { buildShortcutExtra } from '../../utils/itemExtra';
import TreeModal, { TreeModalProps } from '../main/TreeModal';
Expand Down Expand Up @@ -51,7 +51,7 @@ const CreateShortcutModalProvider = ({ children }: Props): JSX.Element => {
extra: buildShortcutExtra(target),
type: ItemType.SHORTCUT,
// set parent id if not root
parentId: to !== TREE_MODAL_MY_ITEMS_ID ? to : undefined,
parentId: to !== HOME_MODAL_ITEM_ID ? to : undefined,
};
createShortcut(shortcut);

Expand Down
9 changes: 3 additions & 6 deletions src/components/context/ModalProviders.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,15 @@ import { CopyItemModalProvider } from './CopyItemModalContext';
import { CreateShortcutModalProvider } from './CreateShortcutModalContext';
import { FlagItemModalProvider } from './FlagItemModalContext';
import { LayoutContextProvider } from './LayoutContext';
import { MoveItemModalProvider } from './MoveItemModalContext';

type Props = { children: JSX.Element };

const ModalProviders = ({ children }: Props): JSX.Element => (
<LayoutContextProvider>
<CopyItemModalProvider>
<MoveItemModalProvider>
<CreateShortcutModalProvider>
<FlagItemModalProvider>{children}</FlagItemModalProvider>
</CreateShortcutModalProvider>
</MoveItemModalProvider>
<CreateShortcutModalProvider>
<FlagItemModalProvider>{children}</FlagItemModalProvider>
</CreateShortcutModalProvider>
</CopyItemModalProvider>
</LayoutContextProvider>
);
Expand Down
Loading

0 comments on commit f014f13

Please sign in to comment.