cozy-sharing 40.1.5 → 40.1.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +8 -0
- package/dist/components/FederatedFolder/FederatedFolderModal.js +10 -12
- package/dist/components/Recipient/DowngradePermissionConfirmDialog.js +3 -12
- package/dist/components/Recipient/GroupRecipient.js +1 -4
- package/dist/components/Recipient/GroupRecipient.stories.js +3 -1
- package/dist/components/Recipient/GroupRecipientDetailWithAccess.js +1 -4
- package/dist/components/Recipient/GroupRecipientPermissions.js +5 -8
- package/dist/components/Recipient/GroupRecipientPermissions.stories.js +2 -0
- package/dist/components/Recipient/LinkRecipient.js +2 -6
- package/dist/components/Recipient/LinkRecipient.stories.js +4 -0
- package/dist/components/Recipient/LinkRecipientPermissions.js +13 -12
- package/dist/components/Recipient/LinkRecipientPermissions.stories.js +5 -1
- package/dist/components/Recipient/MemberRecipient.js +7 -6
- package/dist/components/Recipient/MemberRecipient.spec.js +7 -12
- package/dist/components/Recipient/MemberRecipientPermissions.js +28 -13
- package/dist/components/Recipient/MemberRecipientPermissions.spec.js +5 -14
- package/dist/components/Recipient/MemberRecipientPermissions.stories.js +2 -1
- package/dist/components/Recipient/OwnerRecipient.js +4 -17
- package/dist/components/Recipient/OwnerRecipient.stories.js +3 -1
- package/dist/components/Recipient/OwnerRecipientDefaultLite.js +1 -1
- package/dist/components/Recipient/PermissionTypeMenu.js +32 -155
- package/dist/components/Recipient/PermissionTypeMenuWrapper.js +37 -0
- package/dist/components/Recipient/{PermissionTypeMenu.spec.js → PermissionTypeMenuWrapper.spec.js} +2 -2
- package/dist/components/Recipient/RecipientList.js +10 -0
- package/dist/components/Recipient/RecipientList.stories.js +3 -0
- package/dist/components/ShareDialogCozyToCozy.js +20 -19
- package/dist/components/ShareDialogCozyToCozy.spec.js +3 -0
- package/dist/components/ShareDialogOnlyByLink.js +3 -5
- package/dist/components/ShareDialogOnlyByLink.spec.js +0 -1
- package/dist/components/ShareModal/SharingDetailsModal.js +2 -2
- package/dist/components/SharedDrive/EditSharedDriveModal.js +11 -10
- package/dist/components/SharedDrive/useSharedDrive.js +8 -11
- package/dist/components/SharingContent.js +3 -5
- package/dist/components/WhoHasAccess.js +27 -11
- package/dist/components/WhoHasAccessWrapper.js +122 -0
- package/dist/helpers/recipients.js +46 -0
- package/dist/helpers/recipients.spec.js +89 -0
- package/dist/hooks/useMemberPermissionType.js +191 -0
- package/dist/hooks/useResolveRecipients.js +53 -0
- package/dist/hooks/useResolveRecipients.spec.js +140 -0
- package/dist/index.js +1 -1
- package/package.json +3 -3
- package/src/components/FederatedFolder/FederatedFolderModal.jsx +6 -12
- package/src/components/Recipient/DowngradePermissionConfirmDialog.jsx +3 -10
- package/src/components/Recipient/GroupRecipient.jsx +1 -5
- package/src/components/Recipient/GroupRecipient.stories.jsx +3 -1
- package/src/components/Recipient/GroupRecipientDetailWithAccess.jsx +1 -4
- package/src/components/Recipient/GroupRecipientPermissions.jsx +5 -5
- package/src/components/Recipient/GroupRecipientPermissions.stories.jsx +2 -0
- package/src/components/Recipient/LinkRecipient.jsx +2 -4
- package/src/components/Recipient/LinkRecipient.stories.jsx +4 -0
- package/src/components/Recipient/LinkRecipientPermissions.jsx +16 -12
- package/src/components/Recipient/LinkRecipientPermissions.stories.jsx +5 -1
- package/src/components/Recipient/MemberRecipient.jsx +4 -4
- package/src/components/Recipient/MemberRecipient.spec.jsx +7 -10
- package/src/components/Recipient/MemberRecipientPermissions.jsx +29 -13
- package/src/components/Recipient/MemberRecipientPermissions.spec.jsx +5 -11
- package/src/components/Recipient/MemberRecipientPermissions.stories.jsx +2 -1
- package/src/components/Recipient/OwnerRecipient.jsx +4 -17
- package/src/components/Recipient/OwnerRecipient.stories.jsx +1 -1
- package/src/components/Recipient/OwnerRecipientDefaultLite.jsx +1 -1
- package/src/components/Recipient/PermissionTypeMenu.jsx +21 -81
- package/src/components/Recipient/PermissionTypeMenuWrapper.jsx +32 -0
- package/src/components/Recipient/{PermissionTypeMenu.spec.jsx → PermissionTypeMenuWrapper.spec.jsx} +2 -2
- package/src/components/Recipient/RecipientList.jsx +10 -0
- package/src/components/Recipient/RecipientList.stories.jsx +3 -0
- package/src/components/ShareDialogCozyToCozy.jsx +10 -11
- package/src/components/ShareDialogCozyToCozy.spec.jsx +1 -0
- package/src/components/ShareDialogOnlyByLink.jsx +2 -4
- package/src/components/ShareDialogOnlyByLink.spec.jsx +0 -1
- package/src/components/ShareModal/SharingDetailsModal.jsx +2 -2
- package/src/components/SharedDrive/EditSharedDriveModal.jsx +6 -11
- package/src/components/SharedDrive/useSharedDrive.js +4 -11
- package/src/components/SharingContent.jsx +2 -4
- package/src/components/WhoHasAccess.jsx +26 -12
- package/src/components/WhoHasAccessWrapper.jsx +117 -0
- package/src/helpers/recipients.js +44 -0
- package/src/helpers/recipients.spec.js +82 -0
- package/src/hooks/useMemberPermissionType.js +110 -0
- package/src/hooks/useResolveRecipients.js +38 -0
- package/src/hooks/useResolveRecipients.spec.js +70 -0
- package/src/index.jsx +1 -1
- package/dist/components/Recipient/OwnerRecipientDefault.js +0 -27
- package/dist/components/Recipient/OwnerRecipientDefault.stories.js +0 -10
- package/src/components/Recipient/OwnerRecipientDefault.jsx +0 -37
- package/src/components/Recipient/OwnerRecipientDefault.stories.jsx +0 -13
|
@@ -15,21 +15,20 @@ import { setReadOnlySharedPermission } from './actions/setReadOnlySharedPermissi
|
|
|
15
15
|
import { setReadWriteSharedPermission } from './actions/setReadWriteSharedPermission'
|
|
16
16
|
import { isOnlyReadOnlyLinkAllowed } from '../../helpers/link'
|
|
17
17
|
import { checkIsReadOnlyPermissions } from '../../helpers/permissions'
|
|
18
|
-
import { useSharingContext } from '../../hooks/useSharingContext'
|
|
19
18
|
import { WRITE_PERMS, READ_ONLY_PERMS } from '../ShareRestrictionModal/helpers'
|
|
20
19
|
|
|
21
|
-
const LinkRecipientPermissions = ({
|
|
20
|
+
const LinkRecipientPermissions = ({
|
|
21
|
+
document,
|
|
22
|
+
documentType,
|
|
23
|
+
isReadOnly,
|
|
24
|
+
permissions,
|
|
25
|
+
onUpdateLinkPermissions,
|
|
26
|
+
onRevokeLink
|
|
27
|
+
}) => {
|
|
22
28
|
const { t } = useI18n()
|
|
23
29
|
const buttonRef = useRef()
|
|
24
30
|
const [isMenuDisplayed, setMenuDisplayed] = useState(false)
|
|
25
|
-
const {
|
|
26
|
-
updateDocumentPermissions,
|
|
27
|
-
revokeSharingLink,
|
|
28
|
-
documentType,
|
|
29
|
-
getDocumentPermissions
|
|
30
|
-
} = useSharingContext()
|
|
31
31
|
|
|
32
|
-
const permissions = getDocumentPermissions(document._id)
|
|
33
32
|
const isReadOnlyPermissions = checkIsReadOnlyPermissions(permissions)
|
|
34
33
|
const type = isReadOnlyPermissions ? 'one-way' : 'two-way'
|
|
35
34
|
|
|
@@ -38,11 +37,11 @@ const LinkRecipientPermissions = ({ document, isReadOnly }) => {
|
|
|
38
37
|
|
|
39
38
|
const handleSetType = newType => {
|
|
40
39
|
const verbs = newType === 'one-way' ? READ_ONLY_PERMS : WRITE_PERMS
|
|
41
|
-
|
|
40
|
+
onUpdateLinkPermissions(document, { verbs })
|
|
42
41
|
hideMenu()
|
|
43
42
|
}
|
|
44
43
|
|
|
45
|
-
const handleRevocation = () =>
|
|
44
|
+
const handleRevocation = () => onRevokeLink(document)
|
|
46
45
|
|
|
47
46
|
const actionsToShow = [setReadOnlySharedPermission]
|
|
48
47
|
if (!isOnlyReadOnlyLinkAllowed({ documentType })) {
|
|
@@ -87,7 +86,12 @@ const LinkRecipientPermissions = ({ document, isReadOnly }) => {
|
|
|
87
86
|
}
|
|
88
87
|
|
|
89
88
|
LinkRecipientPermissions.propTypes = {
|
|
90
|
-
document: PropTypes.object.isRequired
|
|
89
|
+
document: PropTypes.object.isRequired,
|
|
90
|
+
documentType: PropTypes.string.isRequired,
|
|
91
|
+
isReadOnly: PropTypes.bool,
|
|
92
|
+
permissions: PropTypes.arrayOf(PropTypes.object).isRequired,
|
|
93
|
+
onUpdateLinkPermissions: PropTypes.func.isRequired,
|
|
94
|
+
onRevokeLink: PropTypes.func.isRequired
|
|
91
95
|
}
|
|
92
96
|
|
|
93
97
|
export default LinkRecipientPermissions
|
|
@@ -3,7 +3,11 @@ import LinkRecipientPermissions from './LinkRecipientPermissions'
|
|
|
3
3
|
const meta = {
|
|
4
4
|
component: LinkRecipientPermissions,
|
|
5
5
|
args: {
|
|
6
|
-
document: { _id: '123' }
|
|
6
|
+
document: { _id: '123' },
|
|
7
|
+
documentType: 'Files',
|
|
8
|
+
permissions: [],
|
|
9
|
+
onUpdateLinkPermissions: () => {},
|
|
10
|
+
onRevokeLink: () => {}
|
|
7
11
|
}
|
|
8
12
|
}
|
|
9
13
|
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import PropTypes from 'prop-types'
|
|
2
2
|
import React from 'react'
|
|
3
3
|
|
|
4
|
-
import { useClient } from 'cozy-client'
|
|
5
4
|
import Fade from 'cozy-ui/transpiled/react/Fade'
|
|
6
5
|
import ListItem from 'cozy-ui/transpiled/react/ListItem'
|
|
7
6
|
import ListItemIcon from 'cozy-ui/transpiled/react/ListItemIcon'
|
|
@@ -22,13 +21,13 @@ import { MemberAvatar } from '../Avatar/MemberAvatar'
|
|
|
22
21
|
|
|
23
22
|
const MemberRecipient = props => {
|
|
24
23
|
const { t } = useI18n()
|
|
25
|
-
const client = useClient()
|
|
26
24
|
const { isMobile } = useBreakpoints()
|
|
27
25
|
|
|
28
26
|
const {
|
|
29
27
|
instance,
|
|
30
28
|
isOwner,
|
|
31
29
|
status,
|
|
30
|
+
isCurrentUser = false,
|
|
32
31
|
recipientConfirmationData,
|
|
33
32
|
verifyRecipient,
|
|
34
33
|
fadeIn,
|
|
@@ -36,8 +35,7 @@ const MemberRecipient = props => {
|
|
|
36
35
|
...rest
|
|
37
36
|
} = props
|
|
38
37
|
|
|
39
|
-
const isMe =
|
|
40
|
-
(isOwner && status === 'owner') || instance === client.options.uri
|
|
38
|
+
const isMe = (isOwner && status === 'owner') || isCurrentUser
|
|
41
39
|
const defaultDisplayName = t(DEFAULT_DISPLAY_NAME)
|
|
42
40
|
const name = getDisplayName(rest, defaultDisplayName)
|
|
43
41
|
|
|
@@ -52,6 +50,7 @@ const MemberRecipient = props => {
|
|
|
52
50
|
instance={instance}
|
|
53
51
|
isOwner={isOwner}
|
|
54
52
|
status={status}
|
|
53
|
+
isCurrentUser={isCurrentUser}
|
|
55
54
|
/>
|
|
56
55
|
)
|
|
57
56
|
|
|
@@ -88,6 +87,7 @@ MemberRecipient.propTypes = {
|
|
|
88
87
|
instance: PropTypes.string,
|
|
89
88
|
isOwner: PropTypes.bool,
|
|
90
89
|
status: PropTypes.string,
|
|
90
|
+
isCurrentUser: PropTypes.bool,
|
|
91
91
|
recipientConfirmationData: PropTypes.object,
|
|
92
92
|
verifyRecipient: PropTypes.func,
|
|
93
93
|
isOrgSharedDrive: PropTypes.bool
|
|
@@ -6,16 +6,6 @@ import { createMockClient } from 'cozy-client'
|
|
|
6
6
|
import MemberRecipient from './MemberRecipient'
|
|
7
7
|
import AppLike from '../../../test/AppLike'
|
|
8
8
|
|
|
9
|
-
const mockUpdateDocumentPermissions = jest.fn()
|
|
10
|
-
const mockUpdateSharingMemberType = jest.fn()
|
|
11
|
-
|
|
12
|
-
jest.mock('../../hooks/useSharingContext', () => ({
|
|
13
|
-
useSharingContext: () => ({
|
|
14
|
-
updateDocumentPermissions: mockUpdateDocumentPermissions,
|
|
15
|
-
updateSharingMemberType: mockUpdateSharingMemberType
|
|
16
|
-
})
|
|
17
|
-
}))
|
|
18
|
-
|
|
19
9
|
describe('MemberRecipient component', () => {
|
|
20
10
|
const client = createMockClient({})
|
|
21
11
|
client.options = {
|
|
@@ -51,6 +41,7 @@ describe('MemberRecipient component', () => {
|
|
|
51
41
|
it('should render if isMe ', () => {
|
|
52
42
|
const { getByText } = setup({
|
|
53
43
|
instance: 'foo.mycozy.cloud',
|
|
44
|
+
isCurrentUser: true,
|
|
54
45
|
status: 'ready',
|
|
55
46
|
type: 'two-way'
|
|
56
47
|
})
|
|
@@ -61,6 +52,7 @@ describe('MemberRecipient component', () => {
|
|
|
61
52
|
it('should match snapshot if isOwner', () => {
|
|
62
53
|
const { getByText } = setup({
|
|
63
54
|
instance: 'foo.mycozy.cloud',
|
|
55
|
+
isCurrentUser: true,
|
|
64
56
|
status: 'ready',
|
|
65
57
|
type: 'two-way',
|
|
66
58
|
isOwner: true
|
|
@@ -75,6 +67,7 @@ describe('MemberRecipient component', () => {
|
|
|
75
67
|
|
|
76
68
|
const { getByLabelText } = setup({
|
|
77
69
|
instance: 'foo.mycozy.cloud',
|
|
70
|
+
isCurrentUser: true,
|
|
78
71
|
status: 'ready',
|
|
79
72
|
type: 'two-way',
|
|
80
73
|
documentType: 'Files',
|
|
@@ -93,6 +86,7 @@ describe('MemberRecipient component', () => {
|
|
|
93
86
|
|
|
94
87
|
const { getByLabelText } = setup({
|
|
95
88
|
instance: 'foo.mycozy.cloud',
|
|
89
|
+
isCurrentUser: true,
|
|
96
90
|
status: 'ready',
|
|
97
91
|
type: 'two-way',
|
|
98
92
|
isOwner: true,
|
|
@@ -112,6 +106,7 @@ describe('MemberRecipient component', () => {
|
|
|
112
106
|
|
|
113
107
|
const { getByText } = setup({
|
|
114
108
|
instance: 'foo.mycozy.cloud',
|
|
109
|
+
isCurrentUser: true,
|
|
115
110
|
status: 'ready',
|
|
116
111
|
type: 'two-way',
|
|
117
112
|
isOwner: false,
|
|
@@ -132,6 +127,7 @@ describe('MemberRecipient component', () => {
|
|
|
132
127
|
|
|
133
128
|
const { queryByText } = setup({
|
|
134
129
|
instance: 'foo.mycozy.cloud',
|
|
130
|
+
isCurrentUser: true,
|
|
135
131
|
status: 'ready',
|
|
136
132
|
type: 'two-way',
|
|
137
133
|
isOwner: false,
|
|
@@ -149,6 +145,7 @@ describe('MemberRecipient component', () => {
|
|
|
149
145
|
|
|
150
146
|
const { getByText } = setup({
|
|
151
147
|
instance: 'foo.mycozy.cloud',
|
|
148
|
+
isCurrentUser: true,
|
|
152
149
|
status: 'ready',
|
|
153
150
|
type: 'two-way',
|
|
154
151
|
isOwner: false,
|
|
@@ -1,46 +1,50 @@
|
|
|
1
1
|
import React, { useState, useCallback } from 'react'
|
|
2
2
|
|
|
3
3
|
import { Icon, CrossCircleOutline } from '@linagora/twake-icons'
|
|
4
|
-
import { useClient } from 'cozy-client'
|
|
5
4
|
import IconButton from 'cozy-ui/transpiled/react/IconButton'
|
|
6
5
|
import Spinner from 'cozy-ui/transpiled/react/Spinner'
|
|
7
6
|
import Typography from 'cozy-ui/transpiled/react/Typography'
|
|
8
7
|
import { useI18n } from 'twake-i18n'
|
|
9
8
|
|
|
10
|
-
import
|
|
9
|
+
import PermissionTypeMenu from './PermissionTypeMenu'
|
|
10
|
+
import { hasMemberActions } from '../../helpers/recipients'
|
|
11
11
|
|
|
12
12
|
const MemberRecipientPermissions = ({
|
|
13
13
|
isOwner,
|
|
14
14
|
canManageSharing = isOwner,
|
|
15
15
|
canManageMembers = true,
|
|
16
16
|
status,
|
|
17
|
-
|
|
17
|
+
isCurrentUser = false,
|
|
18
18
|
type,
|
|
19
19
|
document,
|
|
20
|
+
isInsideSharedParent,
|
|
21
|
+
sharedParentName,
|
|
20
22
|
onRevoke,
|
|
21
23
|
onRevokeSelf,
|
|
24
|
+
onSetMemberType,
|
|
22
25
|
sharingId,
|
|
23
26
|
memberIndex,
|
|
24
27
|
...recipient
|
|
25
28
|
}) => {
|
|
26
29
|
const { t } = useI18n()
|
|
27
|
-
const client = useClient()
|
|
28
30
|
|
|
29
31
|
const [revoking, setRevoking] = useState(false)
|
|
30
32
|
|
|
31
|
-
const instanceMatchesClient =
|
|
32
|
-
instance !== undefined && instance === client.options.uri
|
|
33
33
|
const contactIsOwner = status === 'owner'
|
|
34
34
|
const shouldShowMenu =
|
|
35
|
-
canManageMembers &&
|
|
36
35
|
!revoking &&
|
|
37
|
-
|
|
38
|
-
|
|
36
|
+
hasMemberActions({
|
|
37
|
+
status,
|
|
38
|
+
isCurrentUser,
|
|
39
|
+
isOwner,
|
|
40
|
+
canManageSharing,
|
|
41
|
+
canManageMembers
|
|
42
|
+
})
|
|
39
43
|
|
|
40
44
|
const handleRevocation = useCallback(async () => {
|
|
41
45
|
setRevoking(true)
|
|
42
46
|
try {
|
|
43
|
-
if (
|
|
47
|
+
if (isCurrentUser && !isOwner) {
|
|
44
48
|
await onRevokeSelf(document)
|
|
45
49
|
} else {
|
|
46
50
|
await onRevoke(document, sharingId, memberIndex)
|
|
@@ -50,7 +54,7 @@ const MemberRecipientPermissions = ({
|
|
|
50
54
|
}
|
|
51
55
|
}, [
|
|
52
56
|
document,
|
|
53
|
-
|
|
57
|
+
isCurrentUser,
|
|
54
58
|
isOwner,
|
|
55
59
|
memberIndex,
|
|
56
60
|
onRevoke,
|
|
@@ -71,11 +75,23 @@ const MemberRecipientPermissions = ({
|
|
|
71
75
|
{shouldShowMenu && (
|
|
72
76
|
<>
|
|
73
77
|
<PermissionTypeMenu
|
|
74
|
-
sharingId={sharingId}
|
|
75
|
-
memberIndex={memberIndex}
|
|
76
78
|
type={type ?? 'one-way'}
|
|
77
79
|
document={document}
|
|
78
80
|
recipient={recipient}
|
|
81
|
+
isInsideSharedParent={isInsideSharedParent}
|
|
82
|
+
sharedParentName={sharedParentName}
|
|
83
|
+
onSetType={(newType, options) =>
|
|
84
|
+
onSetMemberType(
|
|
85
|
+
{
|
|
86
|
+
sharingId,
|
|
87
|
+
memberIndex,
|
|
88
|
+
type: type ?? 'one-way',
|
|
89
|
+
recipient
|
|
90
|
+
},
|
|
91
|
+
newType,
|
|
92
|
+
options
|
|
93
|
+
)
|
|
94
|
+
}
|
|
79
95
|
/>
|
|
80
96
|
<IconButton
|
|
81
97
|
onClick={handleRevocation}
|
|
@@ -6,15 +6,8 @@ import { createMockClient } from 'cozy-client'
|
|
|
6
6
|
import MemberRecipientPermissions from './MemberRecipientPermissions'
|
|
7
7
|
import AppLike from '../../../test/AppLike'
|
|
8
8
|
|
|
9
|
-
const mockUpdateSharingMemberType = jest.fn()
|
|
10
9
|
const mockShowAlert = jest.fn()
|
|
11
10
|
|
|
12
|
-
jest.mock('../../hooks/useSharingContext', () => ({
|
|
13
|
-
useSharingContext: () => ({
|
|
14
|
-
updateSharingMemberType: mockUpdateSharingMemberType
|
|
15
|
-
})
|
|
16
|
-
}))
|
|
17
|
-
|
|
18
11
|
jest.mock('cozy-ui/transpiled/react/providers/Alert', () => ({
|
|
19
12
|
__esModule: true,
|
|
20
13
|
default: ({ children }) => children,
|
|
@@ -33,13 +26,14 @@ describe('MemberRecipientPermissions component', () => {
|
|
|
33
26
|
isOwner: true,
|
|
34
27
|
isSharedDrive: false,
|
|
35
28
|
status: 'ready',
|
|
36
|
-
|
|
29
|
+
isCurrentUser: true,
|
|
37
30
|
type: 'two-way',
|
|
38
31
|
document: { id: 'doc-123', type: 'io.cozy.files', path: '/test' },
|
|
39
32
|
sharingId: 'sharing-123',
|
|
40
33
|
memberIndex: 1,
|
|
41
34
|
onRevoke: jest.fn(),
|
|
42
|
-
onRevokeSelf: jest.fn()
|
|
35
|
+
onRevokeSelf: jest.fn(),
|
|
36
|
+
onSetMemberType: jest.fn()
|
|
43
37
|
}
|
|
44
38
|
|
|
45
39
|
beforeEach(() => {
|
|
@@ -75,7 +69,7 @@ describe('MemberRecipientPermissions component', () => {
|
|
|
75
69
|
it('should not render menu when user is not owner and not the shared drive contact', () => {
|
|
76
70
|
const { queryByRole } = setup({
|
|
77
71
|
isOwner: false,
|
|
78
|
-
|
|
72
|
+
isCurrentUser: false
|
|
79
73
|
})
|
|
80
74
|
|
|
81
75
|
expect(queryByRole('button', { name: 'Editor' })).not.toBeInTheDocument()
|
|
@@ -91,7 +85,7 @@ describe('MemberRecipientPermissions component', () => {
|
|
|
91
85
|
it('should render menu for the user themselves', () => {
|
|
92
86
|
const { getByRole } = setup({
|
|
93
87
|
isOwner: false,
|
|
94
|
-
|
|
88
|
+
isCurrentUser: true
|
|
95
89
|
})
|
|
96
90
|
|
|
97
91
|
expect(getByRole('button', { name: 'Editor' })).toBeInTheDocument()
|
|
@@ -5,6 +5,7 @@ const meta = {
|
|
|
5
5
|
args: {
|
|
6
6
|
onRevoke: () => {},
|
|
7
7
|
onRevokeSelf: () => {},
|
|
8
|
+
onSetMemberType: () => {},
|
|
8
9
|
type: 'two-way',
|
|
9
10
|
status: 'ready'
|
|
10
11
|
},
|
|
@@ -35,6 +36,6 @@ export const Self = {
|
|
|
35
36
|
name: 'Self',
|
|
36
37
|
args: {
|
|
37
38
|
isOwner: false,
|
|
38
|
-
|
|
39
|
+
isCurrentUser: true
|
|
39
40
|
}
|
|
40
41
|
}
|
|
@@ -2,28 +2,15 @@ import PropTypes from 'prop-types'
|
|
|
2
2
|
import React from 'react'
|
|
3
3
|
|
|
4
4
|
import MemberRecipient from './MemberRecipient'
|
|
5
|
-
import OwnerRecipientDefault from './OwnerRecipientDefault'
|
|
6
5
|
|
|
7
|
-
const OwnerRecipient = ({
|
|
8
|
-
|
|
9
|
-
recipient => recipient.status === 'owner'
|
|
10
|
-
)
|
|
6
|
+
const OwnerRecipient = ({ owner }) => {
|
|
7
|
+
if (!owner) return null
|
|
11
8
|
|
|
12
|
-
|
|
13
|
-
return (
|
|
14
|
-
<MemberRecipient
|
|
15
|
-
{...ownerRecipient}
|
|
16
|
-
isOrgSharedDrive={isOrgSharedDrive}
|
|
17
|
-
/>
|
|
18
|
-
)
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
return <OwnerRecipientDefault />
|
|
9
|
+
return <MemberRecipient {...owner} />
|
|
22
10
|
}
|
|
23
11
|
|
|
24
12
|
OwnerRecipient.propTypes = {
|
|
25
|
-
|
|
26
|
-
isOrgSharedDrive: PropTypes.bool
|
|
13
|
+
owner: PropTypes.object
|
|
27
14
|
}
|
|
28
15
|
|
|
29
16
|
export default OwnerRecipient
|
|
@@ -6,7 +6,7 @@ import MemberRecipientLite from './MemberRecipientLite'
|
|
|
6
6
|
import withLocales from '../../hoc/withLocales'
|
|
7
7
|
import { buildInstanceSettingsQuery } from '../../queries/queries'
|
|
8
8
|
|
|
9
|
-
// See
|
|
9
|
+
// See containers/WhoHasAccess: show the instance public avatar (with an initials
|
|
10
10
|
// fallback) when the owner has no per-sharing avatar to reference.
|
|
11
11
|
const OWNER_PUBLIC_AVATAR_PATH = '/public/avatar?fallback=initials'
|
|
12
12
|
|
|
@@ -1,7 +1,6 @@
|
|
|
1
|
+
import PropTypes from 'prop-types'
|
|
1
2
|
import React, { useCallback, useRef, useState } from 'react'
|
|
2
3
|
|
|
3
|
-
import { useClient } from 'cozy-client'
|
|
4
|
-
import flag from 'cozy-flags'
|
|
5
4
|
import minilog from 'cozy-minilog'
|
|
6
5
|
import ActionsMenu from 'cozy-ui/transpiled/react/ActionsMenu'
|
|
7
6
|
import { makeActions } from 'cozy-ui/transpiled/react/ActionsMenu/Actions'
|
|
@@ -12,86 +11,32 @@ import { useI18n } from 'twake-i18n'
|
|
|
12
11
|
import DowngradePermissionConfirmDialog from './DowngradePermissionConfirmDialog'
|
|
13
12
|
import { setReadOnlySharedPermission } from './actions/setReadOnlySharedPermission'
|
|
14
13
|
import { setReadWriteSharedPermission } from './actions/setReadWriteSharedPermission'
|
|
15
|
-
import { getOrCreateFromArray } from '../../helpers/contacts'
|
|
16
|
-
import withLocales from '../../hoc/withLocales'
|
|
17
|
-
import { useFetchDocumentPath } from '../../hooks/useFetchDocumentPath'
|
|
18
|
-
import { useSharingContext } from '../../hooks/useSharingContext'
|
|
19
|
-
import { getSharingDocIds } from '../../state'
|
|
20
14
|
|
|
21
15
|
const log = minilog('PermissionTypeMenu')
|
|
22
16
|
|
|
23
|
-
const
|
|
24
|
-
sharingId,
|
|
25
|
-
memberIndex,
|
|
17
|
+
const PermissionTypeMenu = ({
|
|
26
18
|
type,
|
|
27
19
|
document,
|
|
28
|
-
recipient
|
|
20
|
+
recipient,
|
|
21
|
+
isInsideSharedParent,
|
|
22
|
+
sharedParentName,
|
|
23
|
+
onSetType
|
|
29
24
|
}) => {
|
|
30
25
|
const { t } = useI18n()
|
|
31
|
-
const client = useClient()
|
|
32
26
|
const buttonRef = useRef()
|
|
33
|
-
const { hasSharedParent, updateSharingMemberType, getSharingById, share } =
|
|
34
|
-
useSharingContext()
|
|
35
27
|
const { showAlert } = useAlert()
|
|
36
28
|
|
|
37
29
|
const [isMenuDisplayed, setMenuDisplayed] = useState(false)
|
|
38
30
|
const [pendingType, setPendingType] = useState(null)
|
|
39
31
|
|
|
40
|
-
const documentPath = useFetchDocumentPath(client, document)
|
|
41
|
-
|
|
42
32
|
const hideMenu = useCallback(() => {
|
|
43
33
|
setMenuDisplayed(false)
|
|
44
34
|
}, [])
|
|
45
35
|
|
|
46
36
|
const applyType = useCallback(
|
|
47
|
-
async (newType,
|
|
37
|
+
async (newType, options) => {
|
|
48
38
|
try {
|
|
49
|
-
|
|
50
|
-
// Ancestors first: only the target's own update refetches its
|
|
51
|
-
// effective recipients, which must already see them downgraded.
|
|
52
|
-
const ancestors = (recipient?.sources || []).filter(
|
|
53
|
-
s => s.kind === 'ancestor' && !s.read_only
|
|
54
|
-
)
|
|
55
|
-
for (const ancestor of ancestors) {
|
|
56
|
-
await updateSharingMemberType(
|
|
57
|
-
ancestor.sharing_id,
|
|
58
|
-
ancestor.member_index,
|
|
59
|
-
newType
|
|
60
|
-
)
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
const documentId = document?._id || document?.id
|
|
65
|
-
if (
|
|
66
|
-
flag('drive.federated-shared-folder.enabled') &&
|
|
67
|
-
type === 'one-way' &&
|
|
68
|
-
newType === 'two-way' &&
|
|
69
|
-
documentId
|
|
70
|
-
) {
|
|
71
|
-
const sourceSharing = getSharingById(sharingId)
|
|
72
|
-
if (
|
|
73
|
-
sourceSharing &&
|
|
74
|
-
!getSharingDocIds(sourceSharing).includes(documentId)
|
|
75
|
-
) {
|
|
76
|
-
const contacts = await getOrCreateFromArray(
|
|
77
|
-
client,
|
|
78
|
-
[recipient],
|
|
79
|
-
contact => client.create('io.cozy.contacts', contact)
|
|
80
|
-
)
|
|
81
|
-
if (!contacts[0]) throw new Error('Recipient contact not found')
|
|
82
|
-
await share({
|
|
83
|
-
document: { ...document, id: documentId },
|
|
84
|
-
description: document.name,
|
|
85
|
-
recipients: contacts,
|
|
86
|
-
readOnlyRecipients: [],
|
|
87
|
-
sharedDrive: true,
|
|
88
|
-
openSharing: false
|
|
89
|
-
})
|
|
90
|
-
return
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
await updateSharingMemberType(sharingId, memberIndex, newType, document)
|
|
39
|
+
await onSetType(newType, options)
|
|
95
40
|
} catch (error) {
|
|
96
41
|
log.error('Failed to change member permission type', error)
|
|
97
42
|
showAlert({
|
|
@@ -101,27 +46,12 @@ const PermissionTypeMenuComponent = ({
|
|
|
101
46
|
})
|
|
102
47
|
}
|
|
103
48
|
},
|
|
104
|
-
[
|
|
105
|
-
client,
|
|
106
|
-
document,
|
|
107
|
-
getSharingById,
|
|
108
|
-
memberIndex,
|
|
109
|
-
recipient,
|
|
110
|
-
share,
|
|
111
|
-
sharingId,
|
|
112
|
-
showAlert,
|
|
113
|
-
t,
|
|
114
|
-
type,
|
|
115
|
-
updateSharingMemberType
|
|
116
|
-
]
|
|
49
|
+
[onSetType, showAlert, t]
|
|
117
50
|
)
|
|
118
51
|
|
|
119
52
|
// Downgrading to viewer on a folder inside a shared parent also reduces
|
|
120
53
|
// the member's rights on the parent: require explicit confirmation first.
|
|
121
|
-
const shouldConfirmDowngrade =
|
|
122
|
-
type === 'two-way' &&
|
|
123
|
-
Boolean(documentPath) &&
|
|
124
|
-
hasSharedParent?.(documentPath)
|
|
54
|
+
const shouldConfirmDowngrade = type === 'two-way' && isInsideSharedParent
|
|
125
55
|
|
|
126
56
|
const setType = useCallback(
|
|
127
57
|
newType => {
|
|
@@ -177,6 +107,7 @@ const PermissionTypeMenuComponent = ({
|
|
|
177
107
|
<DowngradePermissionConfirmDialog
|
|
178
108
|
document={document}
|
|
179
109
|
recipient={recipient}
|
|
110
|
+
sharedParentName={sharedParentName}
|
|
180
111
|
onCancel={handleCancelDowngrade}
|
|
181
112
|
onConfirm={handleConfirmDowngrade}
|
|
182
113
|
/>
|
|
@@ -185,4 +116,13 @@ const PermissionTypeMenuComponent = ({
|
|
|
185
116
|
)
|
|
186
117
|
}
|
|
187
118
|
|
|
188
|
-
|
|
119
|
+
PermissionTypeMenu.propTypes = {
|
|
120
|
+
type: PropTypes.oneOf(['one-way', 'two-way']),
|
|
121
|
+
document: PropTypes.object,
|
|
122
|
+
recipient: PropTypes.object,
|
|
123
|
+
isInsideSharedParent: PropTypes.bool,
|
|
124
|
+
sharedParentName: PropTypes.string,
|
|
125
|
+
onSetType: PropTypes.func.isRequired
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
export default PermissionTypeMenu
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
|
|
3
|
+
import PermissionTypeMenu from './PermissionTypeMenu'
|
|
4
|
+
import withLocales from '../../hoc/withLocales'
|
|
5
|
+
import { useMemberPermissionType } from '../../hooks/useMemberPermissionType'
|
|
6
|
+
|
|
7
|
+
const PermissionTypeMenuWrapper = ({
|
|
8
|
+
sharingId,
|
|
9
|
+
memberIndex,
|
|
10
|
+
type,
|
|
11
|
+
document,
|
|
12
|
+
recipient
|
|
13
|
+
}) => {
|
|
14
|
+
const { isInsideSharedParent, sharedParentName, setMemberType } =
|
|
15
|
+
useMemberPermissionType(document)
|
|
16
|
+
|
|
17
|
+
const handleSetType = (newType, options) =>
|
|
18
|
+
setMemberType({ sharingId, memberIndex, type, recipient }, newType, options)
|
|
19
|
+
|
|
20
|
+
return (
|
|
21
|
+
<PermissionTypeMenu
|
|
22
|
+
type={type}
|
|
23
|
+
document={document}
|
|
24
|
+
recipient={recipient}
|
|
25
|
+
isInsideSharedParent={isInsideSharedParent}
|
|
26
|
+
sharedParentName={sharedParentName}
|
|
27
|
+
onSetType={handleSetType}
|
|
28
|
+
/>
|
|
29
|
+
)
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export default withLocales(PermissionTypeMenuWrapper)
|
package/src/components/Recipient/{PermissionTypeMenu.spec.jsx → PermissionTypeMenuWrapper.spec.jsx}
RENAMED
|
@@ -4,7 +4,7 @@ import React from 'react'
|
|
|
4
4
|
import { createMockClient } from 'cozy-client'
|
|
5
5
|
import flag from 'cozy-flags'
|
|
6
6
|
|
|
7
|
-
import
|
|
7
|
+
import PermissionTypeMenuWrapper from './PermissionTypeMenuWrapper'
|
|
8
8
|
import AppLike from '../../../test/AppLike'
|
|
9
9
|
|
|
10
10
|
const mockUpdateSharingMemberType = jest.fn()
|
|
@@ -56,7 +56,7 @@ describe('PermissionTypeMenu component', () => {
|
|
|
56
56
|
const setup = props => {
|
|
57
57
|
return render(
|
|
58
58
|
<AppLike client={client}>
|
|
59
|
-
<
|
|
59
|
+
<PermissionTypeMenuWrapper {...defaultProps} {...props} />
|
|
60
60
|
</AppLike>
|
|
61
61
|
)
|
|
62
62
|
}
|
|
@@ -14,8 +14,13 @@ const RecipientList = ({
|
|
|
14
14
|
isSharedDrive,
|
|
15
15
|
document,
|
|
16
16
|
documentType,
|
|
17
|
+
isInsideSharedParent,
|
|
18
|
+
sharedParentName,
|
|
17
19
|
onRevoke,
|
|
18
20
|
onRevokeSelf,
|
|
21
|
+
onRevokeGroup,
|
|
22
|
+
onLeaveGroup,
|
|
23
|
+
onSetMemberType,
|
|
19
24
|
verifyRecipient
|
|
20
25
|
}) => {
|
|
21
26
|
const previousRecipients = usePrevious(recipients)
|
|
@@ -41,6 +46,8 @@ const RecipientList = ({
|
|
|
41
46
|
documentType={documentType}
|
|
42
47
|
onRevoke={onRevoke}
|
|
43
48
|
onRevokeSelf={onRevokeSelf}
|
|
49
|
+
onRevokeGroup={onRevokeGroup}
|
|
50
|
+
onLeaveGroup={onLeaveGroup}
|
|
44
51
|
fadeIn={recipient.hasBeenJustAdded}
|
|
45
52
|
/>
|
|
46
53
|
)
|
|
@@ -56,8 +63,11 @@ const RecipientList = ({
|
|
|
56
63
|
isSharedDrive={isSharedDrive}
|
|
57
64
|
document={document}
|
|
58
65
|
documentType={documentType}
|
|
66
|
+
isInsideSharedParent={isInsideSharedParent}
|
|
67
|
+
sharedParentName={sharedParentName}
|
|
59
68
|
onRevoke={onRevoke}
|
|
60
69
|
onRevokeSelf={onRevokeSelf}
|
|
70
|
+
onSetMemberType={onSetMemberType}
|
|
61
71
|
recipientConfirmationData={recipientConfirmationData}
|
|
62
72
|
verifyRecipient={verifyRecipient}
|
|
63
73
|
fadeIn={recipient.hasBeenJustAdded}
|