Skip to content
This repository has been archived by the owner on Jan 23, 2025. It is now read-only.

Commit

Permalink
feat: refactor move modal, use accessible with pagination (#951)
Browse files Browse the repository at this point in the history
* feat: refactor move modal, use accessible with pagination
  • Loading branch information
pyphilia authored Jan 16, 2024
1 parent e89800e commit 1f18249
Show file tree
Hide file tree
Showing 22 changed files with 730 additions and 476 deletions.
4 changes: 2 additions & 2 deletions cypress/e2e/item/home/home.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ describe('Home', () => {
);

// visit child
const { id: childChildId } = SAMPLE_ITEMS.items[2];
const { id: childChildId } = SAMPLE_ITEMS.items[3];
cy.goToItemInGrid(childChildId);

// expect no children
Expand Down Expand Up @@ -225,7 +225,7 @@ describe('Home', () => {
});

// visit child
const { id: childChildId } = SAMPLE_ITEMS.items[2];
const { id: childChildId } = SAMPLE_ITEMS.items[3];
cy.goToItemInList(childChildId);

// expect no children
Expand Down
6 changes: 2 additions & 4 deletions cypress/e2e/item/move/gridMoveItem.cy.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { HOME_PATH, buildItemPath } from '../../../../src/config/paths';
import {
HOME_MODAL_ITEM_ID,
ITEM_MENU_MOVE_BUTTON_CLASS,
buildItemMenu,
buildItemMenuButtonId,
Expand Down Expand Up @@ -51,7 +50,7 @@ describe('Move Item in Grid', () => {

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

cy.wait('@moveItems').then(({ request: { body, url } }) => {
Expand All @@ -70,8 +69,7 @@ describe('Move Item in Grid', () => {

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

cy.wait('@moveItems').then(({ request: { body, url } }) => {
expect(body.parentId).to.equal(undefined);
Expand Down
57 changes: 47 additions & 10 deletions cypress/e2e/item/move/listMoveItem.cy.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,24 @@
import { HOME_PATH, buildItemPath } from '../../../../src/config/paths';
import {
HOME_MODAL_ITEM_ID,
ITEM_MENU_MOVE_BUTTON_CLASS,
buildItemMenu,
buildItemMenuButtonId,
buildItemRowArrowId,
buildNavigationModalItemId,
} from '../../../../src/config/selectors';
import { ITEM_LAYOUT_MODES } from '../../../../src/enums';
import { SAMPLE_ITEMS } from '../../../fixtures/items';
import { TABLE_ITEM_RENDER_TIME } from '../../../support/constants';

const openMoveModal = ({ id: movedItemId }: { id: string }) => {
const menuSelector = `#${buildItemMenuButtonId(movedItemId)}`;
cy.wait(TABLE_ITEM_RENDER_TIME);
cy.get(menuSelector).click();
cy.get(
`#${buildItemMenu(movedItemId)} .${ITEM_MENU_MOVE_BUTTON_CLASS}`,
).click();
};

const moveItem = ({
id: movedItemId,
toItemPath,
Expand All @@ -18,12 +28,7 @@ const moveItem = ({
toItemPath: string;
rootId?: string;
}) => {
const menuSelector = `#${buildItemMenuButtonId(movedItemId)}`;
cy.wait(TABLE_ITEM_RENDER_TIME);
cy.get(menuSelector).click();
cy.get(
`#${buildItemMenu(movedItemId)} .${ITEM_MENU_MOVE_BUTTON_CLASS}`,
).click();
openMoveModal({ id: movedItemId });

cy.handleTreeMenu(toItemPath, rootId);
};
Expand Down Expand Up @@ -57,7 +62,7 @@ describe('Move Item in List', () => {

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

cy.wait('@moveItems').then(({ request: { body, url } }) => {
Expand All @@ -66,6 +71,39 @@ describe('Move Item in List', () => {
});
});

it('cannot move inside self children', () => {
cy.setUpApi(SAMPLE_ITEMS);
const { id } = SAMPLE_ITEMS.items[0];

// go to children item
cy.visit(buildItemPath(id));

cy.switchMode(ITEM_LAYOUT_MODES.LIST);

const { id: movedItemId } = SAMPLE_ITEMS.items[2];
const parentId = SAMPLE_ITEMS.items[0].id;
const childId = SAMPLE_ITEMS.items[6].id;
openMoveModal({ id: movedItemId });
// parent is disabled
cy.get(`#${buildNavigationModalItemId(parentId)} button`).should(
'be.disabled',
);
cy.get(`#${buildNavigationModalItemId(parentId)}`).trigger('mouseover');
cy.get(`#${buildItemRowArrowId(parentId)}`).click();

// self is disabled
cy.get(`#${buildNavigationModalItemId(movedItemId)} button`).should(
'be.disabled',
);
cy.get(`#${buildNavigationModalItemId(movedItemId)}`).trigger('mouseover');
cy.get(`#${buildItemRowArrowId(movedItemId)}`).click();

// inner child is disabled
cy.get(`#${buildNavigationModalItemId(childId)} button`).should(
'be.disabled',
);
});

it('move item to Home', () => {
cy.setUpApi(SAMPLE_ITEMS);
const { id } = SAMPLE_ITEMS.items[0];
Expand All @@ -77,8 +115,7 @@ describe('Move Item in List', () => {

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

cy.wait('@moveItems').then(({ request: { body, url } }) => {
expect(body.parentId).to.equal(undefined);
Expand Down
6 changes: 2 additions & 4 deletions cypress/e2e/item/move/listMoveMultiple.cy.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { HOME_PATH, buildItemPath } from '../../../../src/config/paths';
import {
HOME_MODAL_ITEM_ID,
ITEMS_TABLE_MOVE_SELECTED_ITEMS_ID,
buildItemsTableRowIdAttribute,
} from '../../../../src/config/selectors';
Expand Down Expand Up @@ -55,7 +54,7 @@ describe('Move Items in List', () => {

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

cy.wait('@moveItems').then(({ request: { body, url } }) => {
Expand All @@ -75,8 +74,7 @@ describe('Move Items in List', () => {

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

cy.wait('@moveItems').then(({ request: { body, url } }) => {
expect(body.parentId).to.equal(undefined);
Expand Down
23 changes: 23 additions & 0 deletions cypress/fixtures/items.ts
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,15 @@ const sampleItems: DiscriminatedItem[] = [
hasThumbnail: false,
},
},
{
...DEFAULT_FOLDER_ITEM,
id: 'eef09f5a-5688-11eb-ae93-0242ac130003',
name: 'own_item_name7',
path: 'ecafbd2a_5688_11eb_ae93_0242ac130002.fdf09f5a_5688_11eb_ae93_0242ac130003.eef09f5a_5688_11eb_ae93_0242ac130003',
settings: {
hasThumbnail: false,
},
},
];
export const SAMPLE_ITEMS: ApiConfig = {
items: [
Expand Down Expand Up @@ -200,6 +209,20 @@ export const SAMPLE_ITEMS: ApiConfig = {
},
],
},
{
...sampleItems[6],
memberships: [
{
item: sampleItems[6],
permission: PermissionLevel.Admin,
member: MEMBERS.ANNA,
creator: MEMBERS.ANNA,
createdAt: '2021-08-11T12:56:36.834Z',
updatedAt: '2021-08-11T12:56:36.834Z',
id: '2dd4caf9-538a-317a-86d3-99432b223c12',
},
],
},
],
// memberships: [],
};
Expand Down
6 changes: 3 additions & 3 deletions cypress/support/commands/item.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@ import {
SHARE_ITEM_EMAIL_INPUT_ID,
SHARE_ITEM_SHARE_BUTTON_ID,
TREE_MODAL_CONFIRM_BUTTON_ID,
buildHomeModalItemID,
buildItemFormAppOptionId,
buildItemRowArrowId,
buildNavigationModalItemId,
buildPermissionOptionId,
buildTreeItemId,
} from '../../../src/config/selectors';
Expand Down Expand Up @@ -58,7 +58,7 @@ Cypress.Commands.add(
// click on the element
if (idx === array.length - 1) {
cy.wrap($tree)
.get(`#${buildHomeModalItemID(value)}`)
.get(`#${buildNavigationModalItemId(value)}`)
.first()
.click();
}
Expand All @@ -68,7 +68,7 @@ Cypress.Commands.add(
!$tree.find(`#${buildTreeItemId(array[idx + 1], treeRootId)}`).length
) {
cy.wrap($tree)
.get(`#${buildHomeModalItemID(value)}`)
.get(`#${buildNavigationModalItemId(value)}`)
.trigger('mouseover')
.get(`#${buildItemRowArrowId(value)}`)
.first()
Expand Down
2 changes: 1 addition & 1 deletion cypress/support/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export const REDIRECTION_TIME = 500;
export const CAPTION_EDIT_PAUSE = 2000;

export const ROW_HEIGHT = 48;
export const TABLE_ITEM_RENDER_TIME = 8000;
export const TABLE_ITEM_RENDER_TIME = 7000;
export const TABLE_MEMBERSHIP_RENDER_TIME = 3000;
export const FIXTURES_THUMBNAILS_FOLDER = './thumbnails';
export const CHATBOX_LOADING_TIME = 5000;
Expand Down
75 changes: 60 additions & 15 deletions src/components/common/MoveButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,21 @@ import {
MoveButton as GraaspMoveButton,
} from '@graasp/ui';

import { validate } from 'uuid';

import { mutations } from '@/config/queryClient';
import { hooks, mutations } from '@/config/queryClient';
import { applyEllipsisOnLength, getDirectParentId } from '@/utils/item';

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 TreeModal, { TreeModalProps } from '../main/MoveTreeModal';
import { NavigationElement } from '../main/itemSelectionModal/Breadcrumbs';
import ItemSelectionModal, {
ItemSelectionModalProps,
} from '../main/itemSelectionModal/ItemSelectionModal';

const TITLE_MAX_NAME_LENGTH = 15;

type MoveButtonProps = {
itemIds: string[];
Expand All @@ -42,6 +45,8 @@ const MoveButton = ({
const [open, setOpen] = useState(false);
const [itemIds, setItemIds] = useState<string[]>(defaultItemsIds || []);

const { data: items } = hooks.useItems(itemIds);

const openMoveModal = (newItemIds: string[]) => {
setOpen(true);
setItemIds(newItemIds);
Expand All @@ -51,14 +56,11 @@ const MoveButton = ({
setOpen(false);
};

const onConfirm: TreeModalProps['onConfirm'] = (payload) => {
const onConfirm: ItemSelectionModalProps['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,
ids: itemIds,
to: payload,
};
moveItems(newPayload);
onClose();
Expand All @@ -73,6 +75,47 @@ const MoveButton = ({
onClick?.();
};

const isDisabled = (item: NavigationElement, homeId: string) => {
if (items?.data) {
// cannot move inside self and below
const moveInSelf = Object.values(items.data).some((i) =>
item.path.includes(i.path),
);

// cannot move in same direct parent
// todo: not opti because we only have the ids from the table
const directParentIds = Object.values(items.data).map((i) =>
getDirectParentId(i.path),
);
const moveInDirectParent = directParentIds.includes(item.id);

// cannot move to home if was already on home
let moveToHome = false;

if (items?.data) {
moveToHome =
item.id === homeId &&
!getDirectParentId(Object.values(items.data)[0].path);
}
return moveInSelf || moveInDirectParent || moveToHome;
}
return false;
};

const title = items
? translateBuilder(BUILDER.MOVE_ITEM_MODAL_TITLE, {
name: applyEllipsisOnLength(
Object.values(items.data)[0].name,
TITLE_MAX_NAME_LENGTH,
),
// -1 because we show one name
count: itemIds.length - 1,
})
: translateBuilder(BUILDER.MOVE_ITEM_MODAL_TITLE);

const buttonText = (name?: string) =>
translateBuilder(BUILDER.MOVE_BUTTON, { name, count: name ? 1 : 0 });

return (
<>
<GraaspMoveButton
Expand All @@ -85,13 +128,15 @@ const MoveButton = ({
iconClassName={ITEM_MOVE_BUTTON_CLASS}
/>

{itemIds.length > 0 && open && (
<TreeModal
{items?.data && open && (
<ItemSelectionModal
title={title}
isDisabled={isDisabled}
buttonText={buttonText}
onClose={onClose}
open={open}
itemIds={itemIds}
onConfirm={onConfirm}
title={BUILDER.MOVE_ITEM_MODAL_TITLE}
items={Object.values(items.data)}
/>
)}
</>
Expand Down
Loading

0 comments on commit 1f18249

Please sign in to comment.