Skip to content

Commit

Permalink
feat: adds read-only mode to sharing menu
Browse files Browse the repository at this point in the history
* fix: removes invite user field for non-admin users

* fix: delete user button is hidden for non-admin users

* fix: removes actions header for non admin users

* fix: removes document visibility selection for non-admin

* fix: removes selection and makes permission selection to text

* fix: hides actions, invitations and make selection read only in pending inv

* refactor: cleans up the code for read-only authorised table

* fix: adds missing import statement

* test: adds test for viewing authorised members read-only mode

* test: adds test for email, permission and delete button invitation table read-only mode

* refactor: removes code duplication

* refactor: removes usage of current_user in membership test

* docs: adds todo comment for test of no invitation button

* test: adds test for permission in pending invitations table

* test: adds tests to check if resend invitation button exists or not

* docs: removes todo comment from test
  • Loading branch information
MalinSvenberg authored Mar 7, 2023
1 parent 621da11 commit def82e5
Show file tree
Hide file tree
Showing 10 changed files with 258 additions and 30 deletions.
58 changes: 55 additions & 3 deletions cypress/e2e/invitations/viewInvitation.cy.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
import { buildItemPath } from '../../../src/config/paths';
import {
ITEM_MEMBERSHIP_PERMISSION_SELECT_CLASS,
ITEM_RESEND_INVITATION_BUTTON_CLASS,
buildInvitationTableRowSelector,
buildItemInvitationRowDeleteButtonId,
buildShareButtonId,
} from '../../../src/config/selectors';
import { ITEMS_WITH_INVITATIONS } from '../../fixtures/invitations';
import {
ITEMS_WITH_INVITATIONS,
ITEM_WITH_INVITATIONS_WRITE_ACCESS,
} from '../../fixtures/invitations';

describe('View Invitations', () => {
beforeEach(() => {
Expand All @@ -17,16 +22,63 @@ describe('View Invitations', () => {
cy.visit(buildItemPath(item.id));
cy.get(`#${buildShareButtonId(item.id)}`).click();

invitations.forEach(({ itemPath, id, email }) => {
invitations.forEach(({ itemPath, id, email, permission }) => {
cy.get(buildInvitationTableRowSelector(id)).should('contain', email);

if (itemPath !== item.path) {
cy.get(`#${buildItemInvitationRowDeleteButtonId(id)}`).should(
'be.disabled',
);
}
cy.get(
`${buildInvitationTableRowSelector(
id,
)} .${ITEM_MEMBERSHIP_PERMISSION_SELECT_CLASS} input`,
).should('have.value', permission);

cy.get(
`${buildInvitationTableRowSelector(
id,
)} .${ITEM_RESEND_INVITATION_BUTTON_CLASS}`,
).should('exist');
});
});
});

// todo: check permission
describe('View Invitations Read-Only Mode', () => {
beforeEach(() => {
cy.setUpApi({ ...ITEM_WITH_INVITATIONS_WRITE_ACCESS });
});

it('view invitation in share item modal read-only mode', () => {
const item = ITEM_WITH_INVITATIONS_WRITE_ACCESS.items[0];
const { invitations } = item;
cy.visit(buildItemPath(item.id));
cy.get(`#${buildShareButtonId(item.id)}`).click();

invitations.forEach(({ id, email, permission }) => {
cy.get(buildInvitationTableRowSelector(id))
.should('contain', email)
.should('contain', permission);

// delete invitation button should not exist
cy.get(`#${buildItemInvitationRowDeleteButtonId(id)}`).should(
'not.exist',
);

// check no permission select component exists
cy.get(
`${buildInvitationTableRowSelector(
id,
)} .${ITEM_MEMBERSHIP_PERMISSION_SELECT_CLASS} input`,
).should('not.exist');

// resend invitation button should not exist
cy.get(
`${buildInvitationTableRowSelector(
id,
)} .${ITEM_RESEND_INVITATION_BUTTON_CLASS}`,
).should('not.exist');
});
});
});
46 changes: 45 additions & 1 deletion cypress/e2e/memberships/viewMemberships.cy.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
import { buildItemPath } from '../../../src/config/paths';
import {
ITEM_MEMBERSHIP_PERMISSION_SELECT_CLASS,
buildItemMembershipRowDeleteButtonId,
buildItemMembershipRowSelector,
buildMemberAvatarClass,
buildShareButtonId,
} from '../../../src/config/selectors';
import { membershipsWithoutUser } from '../../../src/utils/membership';
import { CURRENT_USER, MEMBERS } from '../../fixtures/members';
import { ITEMS_WITH_MEMBERSHIPS } from '../../fixtures/memberships';
import {
ITEMS_WITH_MEMBERSHIPS,
ITEM_WITH_WRITE_ACCESS,
} from '../../fixtures/memberships';

describe('View Memberships', () => {
beforeEach(() => {
Expand Down Expand Up @@ -62,8 +66,48 @@ describe('View Memberships', () => {
id,
)} .${ITEM_MEMBERSHIP_PERMISSION_SELECT_CLASS} input`,
).should('have.value', permission);

// check delete button exists
cy.get(`#${buildItemMembershipRowDeleteButtonId(id)}`).should('exist');
}

// todo: check permission level
});
});

describe('View Memberships Read-Only Mode', () => {
beforeEach(() => {
cy.setUpApi({ ...ITEM_WITH_WRITE_ACCESS });
});

it('view membership in settings read-only mode', () => {
const [item] = ITEM_WITH_WRITE_ACCESS.items;
const { memberships } = item;
cy.visit(buildItemPath(item.id));
cy.get(`#${buildShareButtonId(item.id)}`).click();

// check contains member avatar
for (const { permission, memberId, id } of memberships) {
const { name, email } = Object.values(MEMBERS).find(
({ id: mId }) => mId === memberId,
);
// check name, mail and permission
cy.get(buildItemMembershipRowSelector(id))
.should('contain', name)
.should('contain', email)
.should('contain', permission);

// check no permission select component exists
cy.get(
`${buildItemMembershipRowSelector(
id,
)} .${ITEM_MEMBERSHIP_PERMISSION_SELECT_CLASS} input`,
).should('not.exist');

// check no delete button exists
cy.get(`#${buildItemMembershipRowDeleteButtonId(id)}`).should(
'not.exist',
);
}
});
});
46 changes: 46 additions & 0 deletions cypress/fixtures/invitations.js
Original file line number Diff line number Diff line change
Expand Up @@ -72,3 +72,49 @@ export const ITEMS_WITH_INVITATIONS = {
],
members: [MEMBERS.FANNY, MEMBERS.ANNA, MEMBERS.EVAN],
};

export const ITEM_WITH_INVITATIONS_WRITE_ACCESS = {
items: [
{
...DEFAULT_FOLDER_ITEM,
id: 'ecafbd2a-5688-11eb-ae93-0242ac130002',
name: 'own_item_name1',
creator: MEMBERS.BOB.id,
path: 'bcafbd2a_5688_11eb_ae93_0242ac130002.ecafbd2a_5688_11eb_ae93_0242ac130002',
extra: {
image: 'someimageurl',
},
// for tests only
memberships: [
{
id: 'ecafbd2a-5688-11eb-be93-0242ac130002',
itemPath: 'bcafbd2a_5688_11eb_ae93_0242ac130002',
permission: PERMISSION_LEVELS.WRITE,
memberId: MEMBERS.ANNA.id,
},
{
id: 'ecafbd2a-5688-11eb-be93-0242ac130004',
itemPath: 'bcafbd2a_5688_11eb_ae93_0242ac130002',
permission: PERMISSION_LEVELS.ADMIN,
email: MEMBERS.BOB.email,
},
],
invitations: [
{
id: 'ecafbd2a-5688-11eb-be92-0242ac130005',
itemPath: 'bcafbd2a_5688_11eb_ae93_0242ac130002',
permission: PERMISSION_LEVELS.WRITE,
email: MEMBERS.CEDRIC.email,
},
{
id: 'ecafbd1a-5688-11eb-be93-0242ac130006',
itemPath:
'bcafbd2a_5688_11eb_ae93_0242ac130002.ecafbd2a_5688_11eb_ae93_0242ac130002',
permission: PERMISSION_LEVELS.READ,
email: MEMBERS.DAVID.email,
},
],
},
],
members: [MEMBERS.ANNA, MEMBERS.BOB],
};
35 changes: 35 additions & 0 deletions cypress/fixtures/memberships.js
Original file line number Diff line number Diff line change
Expand Up @@ -74,3 +74,38 @@ export const ITEMS_WITH_MEMBERSHIPS = {
},
],
};

export const ITEM_WITH_WRITE_ACCESS = {
items: [
{
...DEFAULT_FOLDER_ITEM,
id: 'ecafbd2a-5688-11eb-ae93-0242ac130002',
creator: MEMBERS.BOB.id,
name: 'own_item_name1',
path: 'ecafbd2a_5688_11eb_ae93_0242ac130002',
extra: {
image: 'someimageurl',
},
memberships: [
{
id: 'ecafbd2a-5688-11eb-be93-0242ac130002',
itemPath: 'ecafbd2a_5688_11eb_ae93_0242ac130002',
permission: PERMISSION_LEVELS.ADMIN,
memberId: MEMBERS.BOB.id,
},
{
id: 'ecafbd2a-5688-11eb-be92-0242ac130002',
itemPath: 'ecafbd2a_5688_11eb_ae93_0242ac130002',
permission: PERMISSION_LEVELS.WRITE,
memberId: MEMBERS.ANNA.id,
},
{
id: 'ecafbd1a-5688-11eb-be93-0242ac130002',
itemPath: 'ecafbd2a_5688_11eb_ae93_0242ac130002',
permission: PERMISSION_LEVELS.READ,
memberId: MEMBERS.CEDRIC.id,
},
],
},
],
};
33 changes: 25 additions & 8 deletions src/components/item/sharing/InvitationsTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,14 @@ type Props = {
item: ItemRecord;
invitations: List<Invitation>;
emptyMessage?: string;
readOnly?: boolean;
};

const InvitationsTable = ({
invitations,
item,
emptyMessage,
readOnly = false,
}: Props): JSX.Element => {
const { t: translateBuilder } = useBuilderTranslation();
const { mutate: editInvitation } = useMutation<
Expand Down Expand Up @@ -92,6 +94,7 @@ const InvitationsTable = ({
],
});
},
readOnly,
});

const InvitationRenderer = ResendInvitationRenderer(item.id);
Expand All @@ -100,8 +103,8 @@ const InvitationsTable = ({
const columnDefs = useMemo(
() => [
{
headerCheckboxSelection: true,
checkboxSelection: true,
headerCheckboxSelection: !readOnly,
checkboxSelection: !readOnly,
comparator: GraaspTable.textComparator,
headerName: translateBuilder(BUILDER.INVITATIONS_TABLE_EMAIL_HEADER),
field: 'email',
Expand All @@ -114,10 +117,10 @@ const InvitationsTable = ({
BUILDER.INVITATIONS_TABLE_INVITATION_HEADER,
),
sortable: false,
cellRenderer: InvitationRenderer,
cellRenderer: readOnly ? null : InvitationRenderer,
cellStyle: rowStyle,
flex: 1,
field: 'email',
field: readOnly ? null : 'email',
},
{
headerName: translateBuilder(
Expand All @@ -127,11 +130,19 @@ const InvitationsTable = ({
comparator: GraaspTable.textComparator,
type: 'rightAligned',
field: 'permission',
cellStyle: readOnly
? {
display: 'flex',
justifyContent: 'right',
}
: null,
},
{
field: 'actions',
cellRenderer: ActionRenderer,
headerName: translateBuilder(BUILDER.INVITATIONS_TABLE_ACTIONS_HEADER),
field: readOnly ? null : 'actions',
cellRenderer: readOnly ? null : ActionRenderer,
headerName: readOnly
? null
: translateBuilder(BUILDER.INVITATIONS_TABLE_ACTIONS_HEADER),
colId: 'actions',
type: 'rightAligned',
sortable: false,
Expand All @@ -143,7 +154,13 @@ const InvitationsTable = ({
},
],
// eslint-disable-next-line react-hooks/exhaustive-deps
[translateBuilder, InvitationRenderer, PermissionRenderer, ActionRenderer],
[
translateBuilder,
InvitationRenderer,
PermissionRenderer,
ActionRenderer,
readOnly,
],
);

const countTextFunction = (selected) =>
Expand Down
Loading

0 comments on commit def82e5

Please sign in to comment.