cozy-sharing 40.1.6 → 40.1.8
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/FederatedFolder/FederatedFolderModal.spec.js +2 -2
- 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/{ShareRecipientsInput.js → ShareAutosuggestWrapper.js} +12 -54
- package/dist/components/{ShareRecipientsInput.spec.js → ShareAutosuggestWrapper.spec.js} +3 -3
- package/dist/components/ShareByEmail.js +2 -2
- 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/SharingBanner/components/PublicBanner.js +8 -6
- package/dist/components/SharingBanner/components/PublicBanner.spec.js +1 -9
- package/dist/components/SharingBanner/components/SharingBanner.js +3 -0
- package/dist/components/SharingBanner/index.js +3 -0
- package/dist/components/SharingContent.js +3 -5
- package/dist/components/WhoHasAccess.js +27 -11
- package/dist/components/WhoHasAccessWrapper.js +122 -0
- package/dist/helpers/contacts.js +79 -1
- package/dist/helpers/contacts.spec.js +122 -1
- 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/docs/share-modal-architecture.md +2 -2
- package/package.json +3 -3
- package/src/components/FederatedFolder/FederatedFolderModal.jsx +6 -12
- package/src/components/FederatedFolder/FederatedFolderModal.spec.jsx +1 -0
- 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/{ShareRecipientsInput.jsx → ShareAutosuggestWrapper.jsx} +14 -65
- package/src/components/{ShareRecipientsInput.spec.jsx → ShareAutosuggestWrapper.spec.jsx} +3 -3
- package/src/components/ShareByEmail.jsx +2 -2
- 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/SharingBanner/components/PublicBanner.jsx +6 -6
- package/src/components/SharingBanner/components/PublicBanner.spec.jsx +1 -8
- package/src/components/SharingBanner/components/SharingBanner.jsx +7 -1
- package/src/components/SharingBanner/index.jsx +4 -0
- package/src/components/SharingContent.jsx +2 -4
- package/src/components/WhoHasAccess.jsx +26 -12
- package/src/components/WhoHasAccessWrapper.jsx +117 -0
- package/src/helpers/contacts.js +83 -0
- package/src/helpers/contacts.spec.js +78 -1
- 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
|
@@ -4,7 +4,7 @@ import React from 'react'
|
|
|
4
4
|
import flag from 'cozy-flags'
|
|
5
5
|
import { useI18n } from 'twake-i18n'
|
|
6
6
|
|
|
7
|
-
import
|
|
7
|
+
import ShareAutosuggestWrapper from './ShareAutosuggestWrapper'
|
|
8
8
|
import ShareTypeSelect from './Sharetypeselect'
|
|
9
9
|
import {
|
|
10
10
|
mergeRecipients,
|
|
@@ -60,7 +60,7 @@ export const ShareByEmail = ({
|
|
|
60
60
|
return (
|
|
61
61
|
<div className={styles['coz-form-group']}>
|
|
62
62
|
<div className={styles['coz-form']}>
|
|
63
|
-
<
|
|
63
|
+
<ShareAutosuggestWrapper
|
|
64
64
|
placeholder={
|
|
65
65
|
pendingRecipients.length === 0
|
|
66
66
|
? t(`${documentType}.share.shareByEmail.emailPlaceholder`)
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import PropTypes from 'prop-types'
|
|
2
2
|
import React, { useCallback, useMemo, useState } from 'react'
|
|
3
3
|
|
|
4
|
-
import { useClient } from 'cozy-client'
|
|
5
4
|
import Button from 'cozy-ui/transpiled/react/Buttons'
|
|
6
5
|
import { useAlert } from 'cozy-ui/transpiled/react/providers/Alert'
|
|
7
6
|
import { useI18n } from 'twake-i18n'
|
|
@@ -10,10 +9,10 @@ import { default as DumbShareByLink } from './ShareByLink'
|
|
|
10
9
|
import ShareDialogTwoStepsConfirmationContainer from './ShareDialogTwoStepsConfirmationContainer'
|
|
11
10
|
import { ShareRecipientsLimitModal } from './ShareRecipientsLimitModal'
|
|
12
11
|
import SharingContent from './SharingContent'
|
|
13
|
-
import { getOrCreateFromArray } from '../helpers/contacts'
|
|
14
12
|
import { hasReachRecipientsLimit } from '../helpers/recipients'
|
|
15
13
|
import { getErrorMessage, getSuccessMessage } from '../helpers/share'
|
|
16
14
|
import { usePendingRecipients } from '../hooks/usePendingRecipients'
|
|
15
|
+
import { useResolveRecipients } from '../hooks/useResolveRecipients'
|
|
17
16
|
import { useSharingContext } from '../hooks/useSharingContext'
|
|
18
17
|
|
|
19
18
|
const SharingTitleFunction = ({ documentType, document }) =>
|
|
@@ -39,7 +38,7 @@ const ShareDialogCozyToCozy = ({
|
|
|
39
38
|
...props
|
|
40
39
|
}) => {
|
|
41
40
|
const { t } = useI18n()
|
|
42
|
-
const
|
|
41
|
+
const resolveRecipients = useResolveRecipients()
|
|
43
42
|
const { showAlert } = useAlert()
|
|
44
43
|
const { getSharingLink } = useSharingContext()
|
|
45
44
|
|
|
@@ -67,13 +66,13 @@ const ShareDialogCozyToCozy = ({
|
|
|
67
66
|
|
|
68
67
|
setSubmitting(true)
|
|
69
68
|
try {
|
|
70
|
-
const
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
const
|
|
69
|
+
const { recipients: readWriteRecipients, readOnlyRecipients } =
|
|
70
|
+
await resolveRecipients(
|
|
71
|
+
pendingRecipients,
|
|
72
|
+
selectedOption,
|
|
73
|
+
createContact
|
|
74
|
+
)
|
|
75
|
+
const contacts = [...readWriteRecipients, ...readOnlyRecipients]
|
|
77
76
|
|
|
78
77
|
await onShare({
|
|
79
78
|
document,
|
|
@@ -109,7 +108,7 @@ const ShareDialogCozyToCozy = ({
|
|
|
109
108
|
}, [
|
|
110
109
|
pendingRecipients,
|
|
111
110
|
selectedOption,
|
|
112
|
-
|
|
111
|
+
resolveRecipients,
|
|
113
112
|
showAlert,
|
|
114
113
|
t,
|
|
115
114
|
recipients,
|
|
@@ -17,6 +17,7 @@ jest.mock('cozy-client', () => ({
|
|
|
17
17
|
jest.mock('../hooks/useSharingContext', () => ({
|
|
18
18
|
useSharingContext: () => ({
|
|
19
19
|
getSharingLink: jest.fn(() => null),
|
|
20
|
+
getDocumentPermissions: jest.fn(() => []),
|
|
20
21
|
updateSharingMemberType: jest.fn(),
|
|
21
22
|
isOrgSharedDrive: jest.fn(() => false)
|
|
22
23
|
})
|
|
@@ -8,7 +8,7 @@ import { useI18n } from 'twake-i18n'
|
|
|
8
8
|
|
|
9
9
|
import AntivirusAlert from './AntivirusAlert'
|
|
10
10
|
import { default as DumbShareByLink } from './ShareByLink'
|
|
11
|
-
import
|
|
11
|
+
import WhoHasAccessWrapper from './WhoHasAccessWrapper'
|
|
12
12
|
import { useSharingContext } from '../hooks/useSharingContext'
|
|
13
13
|
|
|
14
14
|
const ShareDialogOnlyByLink = ({
|
|
@@ -19,7 +19,6 @@ const ShareDialogOnlyByLink = ({
|
|
|
19
19
|
document,
|
|
20
20
|
documentType,
|
|
21
21
|
onClose,
|
|
22
|
-
permissions,
|
|
23
22
|
showGenerateLinkButton,
|
|
24
23
|
autoOpenShareRestriction
|
|
25
24
|
}) => {
|
|
@@ -46,7 +45,7 @@ const ShareDialogOnlyByLink = ({
|
|
|
46
45
|
>
|
|
47
46
|
{t('Share.contacts.whoHasAccess')}
|
|
48
47
|
</Typography>
|
|
49
|
-
<
|
|
48
|
+
<WhoHasAccessWrapper
|
|
50
49
|
document={document}
|
|
51
50
|
documentType={documentType}
|
|
52
51
|
isOwner={isOwner}
|
|
@@ -54,7 +53,6 @@ const ShareDialogOnlyByLink = ({
|
|
|
54
53
|
onRevokeSelf={onRevokeSelf}
|
|
55
54
|
recipients={recipients}
|
|
56
55
|
link={displayedLink}
|
|
57
|
-
permissions={permissions}
|
|
58
56
|
/>
|
|
59
57
|
<div
|
|
60
58
|
className={cx(
|
|
@@ -7,7 +7,7 @@ import { useI18n } from 'twake-i18n'
|
|
|
7
7
|
import { useSharingContext } from '../../hooks/useSharingContext'
|
|
8
8
|
import styles from '../../styles/share.styl'
|
|
9
9
|
import ShareByLink from '../ShareByLink'
|
|
10
|
-
import
|
|
10
|
+
import WhoHasAccessWrapper from '../WhoHasAccessWrapper'
|
|
11
11
|
|
|
12
12
|
export const SharingDetailsModal = ({
|
|
13
13
|
recipients,
|
|
@@ -34,7 +34,7 @@ export const SharingDetailsModal = ({
|
|
|
34
34
|
title={t(`${documentType}.share.details.title`)}
|
|
35
35
|
content={
|
|
36
36
|
<div className={styles['share-modal-content']}>
|
|
37
|
-
<
|
|
37
|
+
<WhoHasAccessWrapper
|
|
38
38
|
canManageMembers={false}
|
|
39
39
|
canManageLink={isSharedDrive}
|
|
40
40
|
isSharedDrive={isSharedDrive}
|
|
@@ -10,13 +10,13 @@ import { useSubmitWithLoader } from 'cozy-ui/transpiled/react/hooks/useSubmitWit
|
|
|
10
10
|
import { useI18n } from 'twake-i18n'
|
|
11
11
|
|
|
12
12
|
import SharedDriveHeader from './SharedDriveHeader'
|
|
13
|
-
import { getOrCreateFromArray } from '../../helpers/contacts'
|
|
14
13
|
import withLocales from '../../hoc/withLocales'
|
|
15
14
|
import { usePendingRecipients } from '../../hooks/usePendingRecipients'
|
|
15
|
+
import { useResolveRecipients } from '../../hooks/useResolveRecipients'
|
|
16
16
|
import { useSharingContext } from '../../hooks/useSharingContext'
|
|
17
17
|
import styles from '../../styles/share.styl'
|
|
18
18
|
import { default as DumbShareByEmail } from '../ShareByEmail'
|
|
19
|
-
import
|
|
19
|
+
import WhoHasAccessWrapper from '../WhoHasAccessWrapper'
|
|
20
20
|
|
|
21
21
|
export const EditSharedDriveModal = withLocales(({ onClose, document }) => {
|
|
22
22
|
const client = useClient()
|
|
@@ -29,18 +29,13 @@ export const EditSharedDriveModal = withLocales(({ onClose, document }) => {
|
|
|
29
29
|
setSelectedOption
|
|
30
30
|
} = usePendingRecipients()
|
|
31
31
|
const { onSubmit, isLoading } = useSubmitWithLoader()
|
|
32
|
+
const resolveRecipients = useResolveRecipients()
|
|
32
33
|
|
|
33
34
|
const [driveName, setDriveName] = useState(document.name)
|
|
34
35
|
|
|
35
36
|
const onSave = async () => {
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
client,
|
|
39
|
-
pendingRecipients,
|
|
40
|
-
contact => client.create('io.cozy.contacts', contact)
|
|
41
|
-
)
|
|
42
|
-
const readWriteRecipients = selectedOption === 'readOnly' ? [] : contacts
|
|
43
|
-
const readOnlyRecipients = selectedOption === 'readOnly' ? contacts : []
|
|
37
|
+
const { recipients: readWriteRecipients, readOnlyRecipients } =
|
|
38
|
+
await resolveRecipients(pendingRecipients, selectedOption)
|
|
44
39
|
|
|
45
40
|
await share({
|
|
46
41
|
document: document,
|
|
@@ -100,7 +95,7 @@ export const EditSharedDriveModal = withLocales(({ onClose, document }) => {
|
|
|
100
95
|
onSelectedOptionChange={setSelectedOption}
|
|
101
96
|
/>
|
|
102
97
|
</div>
|
|
103
|
-
<
|
|
98
|
+
<WhoHasAccessWrapper
|
|
104
99
|
isOwner
|
|
105
100
|
isSharedDrive
|
|
106
101
|
showOwner={false}
|
|
@@ -2,12 +2,12 @@ import { useState } from 'react'
|
|
|
2
2
|
|
|
3
3
|
import { useClient } from 'cozy-client'
|
|
4
4
|
|
|
5
|
-
import { getOrCreateFromArray } from '../../helpers/contacts'
|
|
6
5
|
import { usePendingRecipients } from '../../hooks/usePendingRecipients'
|
|
7
|
-
import {
|
|
6
|
+
import { useResolveRecipients } from '../../hooks/useResolveRecipients'
|
|
8
7
|
|
|
9
8
|
export const useSharedDrive = () => {
|
|
10
9
|
const client = useClient()
|
|
10
|
+
const resolveRecipients = useResolveRecipients()
|
|
11
11
|
|
|
12
12
|
const [sharedDriveName, setSharedDriveName] = useState('')
|
|
13
13
|
const {
|
|
@@ -21,16 +21,9 @@ export const useSharedDrive = () => {
|
|
|
21
21
|
setSharedDriveName(event.target.value)
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
-
const createContact = contact => client.create(DOCTYPE_CONTACTS, contact)
|
|
25
|
-
|
|
26
24
|
const onCreate = async () => {
|
|
27
|
-
const
|
|
28
|
-
|
|
29
|
-
pendingRecipients,
|
|
30
|
-
createContact
|
|
31
|
-
)
|
|
32
|
-
const readWriteRecipients = selectedOption === 'readOnly' ? [] : contacts
|
|
33
|
-
const readOnlyRecipients = selectedOption === 'readOnly' ? contacts : []
|
|
25
|
+
const { recipients: readWriteRecipients, readOnlyRecipients } =
|
|
26
|
+
await resolveRecipients(pendingRecipients, selectedOption)
|
|
34
27
|
|
|
35
28
|
await client.collection('io.cozy.sharings').createSharedDrive({
|
|
36
29
|
name: sharedDriveName,
|
|
@@ -3,7 +3,6 @@ import React from 'react'
|
|
|
3
3
|
import snarkdown from 'snarkdown'
|
|
4
4
|
|
|
5
5
|
import { Icon, SyncCozy, ToTheCloud } from '@linagora/twake-icons'
|
|
6
|
-
import { useClient } from 'cozy-client'
|
|
7
6
|
import flag from 'cozy-flags'
|
|
8
7
|
import Alert from 'cozy-ui/transpiled/react/Alert'
|
|
9
8
|
import Avatar from 'cozy-ui/transpiled/react/Avatar'
|
|
@@ -17,11 +16,9 @@ import styles from '../../../styles/publicBanner.styl'
|
|
|
17
16
|
const getPublicNameFromSharing = sharing =>
|
|
18
17
|
sharing.attributes.members[0].public_name
|
|
19
18
|
|
|
20
|
-
const PublicBannerCozyToCozyContent = ({ sharing }) => {
|
|
19
|
+
const PublicBannerCozyToCozyContent = ({ sharing, avatarURL }) => {
|
|
21
20
|
const { t } = useI18n()
|
|
22
|
-
const client = useClient()
|
|
23
21
|
const name = getPublicNameFromSharing(sharing)
|
|
24
|
-
const avatarURL = `${client.options.uri}/public/avatar?fallback=initials`
|
|
25
22
|
|
|
26
23
|
const withAvatar = snarkdown(
|
|
27
24
|
t('Share.banner.shared_from', {
|
|
@@ -43,13 +40,15 @@ const PublicBannerCozyToCozyContent = ({ sharing }) => {
|
|
|
43
40
|
)
|
|
44
41
|
}
|
|
45
42
|
PublicBannerCozyToCozyContent.propTypes = {
|
|
46
|
-
sharing: PropTypes.object.isRequired
|
|
43
|
+
sharing: PropTypes.object.isRequired,
|
|
44
|
+
avatarURL: PropTypes.string.isRequired
|
|
47
45
|
}
|
|
48
46
|
|
|
49
47
|
const openExternalLink = url => (window.location = url)
|
|
50
48
|
|
|
51
49
|
const SharingBannerCozyToCozy = ({
|
|
52
50
|
sharing,
|
|
51
|
+
avatarURL,
|
|
53
52
|
isSharingShortcutCreated,
|
|
54
53
|
addSharingLink,
|
|
55
54
|
onClose
|
|
@@ -90,7 +89,7 @@ const SharingBannerCozyToCozy = ({
|
|
|
90
89
|
</>
|
|
91
90
|
}
|
|
92
91
|
>
|
|
93
|
-
<PublicBannerCozyToCozyContent sharing={sharing} />
|
|
92
|
+
<PublicBannerCozyToCozyContent sharing={sharing} avatarURL={avatarURL} />
|
|
94
93
|
</Alert>
|
|
95
94
|
)
|
|
96
95
|
}
|
|
@@ -162,6 +161,7 @@ SharingBannerByLink.propTypes = {
|
|
|
162
161
|
}
|
|
163
162
|
SharingBannerCozyToCozy.propTypes = {
|
|
164
163
|
sharing: PropTypes.object.isRequired,
|
|
164
|
+
avatarURL: PropTypes.string.isRequired,
|
|
165
165
|
isSharingShortcutCreated: PropTypes.bool.isRequired,
|
|
166
166
|
addSharingLink: PropTypes.string.isRequired,
|
|
167
167
|
onClose: PropTypes.func.isRequired
|
|
@@ -1,22 +1,14 @@
|
|
|
1
1
|
import { render } from '@testing-library/react'
|
|
2
2
|
import React from 'react'
|
|
3
3
|
|
|
4
|
-
import { useClient } from 'cozy-client'
|
|
5
4
|
import { BreakpointsProvider } from 'cozy-ui/transpiled/react/providers/Breakpoints'
|
|
6
5
|
import { useI18n } from 'twake-i18n'
|
|
7
6
|
|
|
8
7
|
import { SharingBannerCozyToCozy } from './PublicBanner'
|
|
9
8
|
|
|
10
9
|
jest.mock('twake-i18n')
|
|
11
|
-
jest.mock('cozy-client')
|
|
12
10
|
|
|
13
11
|
describe('PublicBanner', () => {
|
|
14
|
-
beforeEach(() => {
|
|
15
|
-
useClient.mockReturnValue({
|
|
16
|
-
options: { uri: 'http://cozy.localhost:8080' }
|
|
17
|
-
})
|
|
18
|
-
})
|
|
19
|
-
|
|
20
12
|
it('should not add dangerous html', () => {
|
|
21
13
|
// Given
|
|
22
14
|
useI18n.mockReturnValue({
|
|
@@ -35,6 +27,7 @@ describe('PublicBanner', () => {
|
|
|
35
27
|
<BreakpointsProvider>
|
|
36
28
|
<SharingBannerCozyToCozy
|
|
37
29
|
sharing={sharing}
|
|
30
|
+
avatarURL="http://cozy.localhost:8080/public/avatar?fallback=initials"
|
|
38
31
|
isSharingShortcutCreated={true}
|
|
39
32
|
addSharingLink="discoveryLink"
|
|
40
33
|
onClose={() => {}}
|
|
@@ -3,7 +3,11 @@ import React, { useState, useCallback } from 'react'
|
|
|
3
3
|
|
|
4
4
|
import { SharingBannerByLink, SharingBannerCozyToCozy } from './PublicBanner'
|
|
5
5
|
|
|
6
|
-
export const SharingBanner = ({
|
|
6
|
+
export const SharingBanner = ({
|
|
7
|
+
sharingInfos,
|
|
8
|
+
avatarURL,
|
|
9
|
+
hideCreateCozyAction
|
|
10
|
+
}) => {
|
|
7
11
|
const [isOpened, setIsOpened] = useState(true)
|
|
8
12
|
const onClose = useCallback(() => setIsOpened(false), [setIsOpened])
|
|
9
13
|
|
|
@@ -22,6 +26,7 @@ export const SharingBanner = ({ sharingInfos, hideCreateCozyAction }) => {
|
|
|
22
26
|
<SharingBannerCozyToCozy
|
|
23
27
|
isSharingShortcutCreated={isSharingShortcutCreated}
|
|
24
28
|
sharing={sharing}
|
|
29
|
+
avatarURL={avatarURL}
|
|
25
30
|
addSharingLink={addSharingLink}
|
|
26
31
|
onClose={onClose}
|
|
27
32
|
/>
|
|
@@ -31,6 +36,7 @@ export const SharingBanner = ({ sharingInfos, hideCreateCozyAction }) => {
|
|
|
31
36
|
|
|
32
37
|
SharingBanner.propTypes = {
|
|
33
38
|
sharingInfos: PropTypes.object,
|
|
39
|
+
avatarURL: PropTypes.string,
|
|
34
40
|
hideCreateCozyAction: PropTypes.bool
|
|
35
41
|
}
|
|
36
42
|
|
|
@@ -1,15 +1,19 @@
|
|
|
1
1
|
import PropTypes from 'prop-types'
|
|
2
2
|
import React from 'react'
|
|
3
3
|
|
|
4
|
+
import { useClient } from 'cozy-client'
|
|
5
|
+
|
|
4
6
|
import { SharingBanner } from './components/SharingBanner'
|
|
5
7
|
import { useSharingInfos } from './hooks/useSharingInfos'
|
|
6
8
|
import withLocales from '../../hoc/withLocales'
|
|
7
9
|
|
|
8
10
|
const Plugin = ({ previewPath, hideCreateCozyAction }) => {
|
|
11
|
+
const client = useClient()
|
|
9
12
|
const sharingInfos = useSharingInfos(previewPath)
|
|
10
13
|
return (
|
|
11
14
|
<SharingBanner
|
|
12
15
|
sharingInfos={sharingInfos}
|
|
16
|
+
avatarURL={`${client.options.uri}/public/avatar?fallback=initials`}
|
|
13
17
|
hideCreateCozyAction={hideCreateCozyAction}
|
|
14
18
|
/>
|
|
15
19
|
)
|
|
@@ -7,7 +7,7 @@ import { useI18n } from 'twake-i18n'
|
|
|
7
7
|
|
|
8
8
|
import AntivirusAlert from './AntivirusAlert'
|
|
9
9
|
import { default as DumbShareByEmail } from './ShareByEmail'
|
|
10
|
-
import
|
|
10
|
+
import WhoHasAccessWrapper from './WhoHasAccessWrapper'
|
|
11
11
|
import styles from '../styles/share.styl'
|
|
12
12
|
|
|
13
13
|
const SharingContent = ({
|
|
@@ -25,7 +25,6 @@ const SharingContent = ({
|
|
|
25
25
|
recipientsToBeConfirmed,
|
|
26
26
|
verifyRecipient,
|
|
27
27
|
link,
|
|
28
|
-
permissions,
|
|
29
28
|
pendingRecipients,
|
|
30
29
|
onPendingRecipientsChange,
|
|
31
30
|
selectedOption,
|
|
@@ -74,7 +73,7 @@ const SharingContent = ({
|
|
|
74
73
|
)}
|
|
75
74
|
</div>
|
|
76
75
|
{showWhoHasAccess && (
|
|
77
|
-
<
|
|
76
|
+
<WhoHasAccessWrapper
|
|
78
77
|
document={document}
|
|
79
78
|
documentType={documentType}
|
|
80
79
|
isOwner={isOwner}
|
|
@@ -84,7 +83,6 @@ const SharingContent = ({
|
|
|
84
83
|
recipientsToBeConfirmed={recipientsToBeConfirmed}
|
|
85
84
|
verifyRecipient={verifyRecipient}
|
|
86
85
|
link={link}
|
|
87
|
-
permissions={permissions}
|
|
88
86
|
/>
|
|
89
87
|
)}
|
|
90
88
|
</div>
|
|
@@ -8,7 +8,6 @@ import LinkRecipient from './Recipient/LinkRecipient'
|
|
|
8
8
|
import OwnerRecipient from './Recipient/OwnerRecipient'
|
|
9
9
|
import { RecipientList } from './Recipient/RecipientList'
|
|
10
10
|
import { usePrevious } from '../helpers/hooks'
|
|
11
|
-
import { useSharingContext } from '../hooks/useSharingContext'
|
|
12
11
|
|
|
13
12
|
/**
|
|
14
13
|
* Displays a warning if some contacts are waiting for confirmation of their sharing
|
|
@@ -35,6 +34,9 @@ const WhoHasAccess = ({
|
|
|
35
34
|
canManageMembers = !isReadOnly,
|
|
36
35
|
canManageLink = canManageMembers,
|
|
37
36
|
showOwner = true,
|
|
37
|
+
owner,
|
|
38
|
+
isInsideSharedParent = false,
|
|
39
|
+
sharedParentName,
|
|
38
40
|
recipients,
|
|
39
41
|
recipientsToBeConfirmed = [],
|
|
40
42
|
document,
|
|
@@ -42,15 +44,17 @@ const WhoHasAccess = ({
|
|
|
42
44
|
className,
|
|
43
45
|
onRevoke,
|
|
44
46
|
onRevokeSelf,
|
|
45
|
-
|
|
47
|
+
onRevokeGroup,
|
|
48
|
+
onLeaveGroup,
|
|
49
|
+
onSetMemberType,
|
|
50
|
+
onUpdateLinkPermissions,
|
|
51
|
+
onRevokeLink,
|
|
46
52
|
verifyRecipient,
|
|
47
53
|
link,
|
|
48
54
|
permissions
|
|
49
55
|
}) => {
|
|
50
56
|
const previousLink = usePrevious(link)
|
|
51
57
|
const linkHasBeenJustCreated = link && previousLink === null
|
|
52
|
-
const { isOrgSharedDrive } = useSharingContext()
|
|
53
|
-
const isOrgDrive = isOrgSharedDrive(document?._id)
|
|
54
58
|
|
|
55
59
|
return (
|
|
56
60
|
<div className={className}>
|
|
@@ -66,16 +70,13 @@ const WhoHasAccess = ({
|
|
|
66
70
|
onRevoke={onRevoke}
|
|
67
71
|
onRevokeSelf={onRevokeSelf}
|
|
68
72
|
permissions={permissions}
|
|
73
|
+
onUpdateLinkPermissions={onUpdateLinkPermissions}
|
|
74
|
+
onRevokeLink={onRevokeLink}
|
|
69
75
|
fadeIn={linkHasBeenJustCreated}
|
|
70
76
|
/>
|
|
71
77
|
)}
|
|
72
78
|
|
|
73
|
-
{showOwner &&
|
|
74
|
-
<OwnerRecipient
|
|
75
|
-
recipients={recipients}
|
|
76
|
-
isOrgSharedDrive={isOrgDrive}
|
|
77
|
-
/>
|
|
78
|
-
)}
|
|
79
|
+
{showOwner && <OwnerRecipient owner={owner} />}
|
|
79
80
|
|
|
80
81
|
<RecipientList
|
|
81
82
|
recipients={recipients}
|
|
@@ -86,9 +87,13 @@ const WhoHasAccess = ({
|
|
|
86
87
|
isSharedDrive={isSharedDrive}
|
|
87
88
|
document={document}
|
|
88
89
|
documentType={documentType}
|
|
90
|
+
isInsideSharedParent={isInsideSharedParent}
|
|
91
|
+
sharedParentName={sharedParentName}
|
|
89
92
|
onRevoke={onRevoke}
|
|
90
93
|
onRevokeSelf={onRevokeSelf}
|
|
91
|
-
|
|
94
|
+
onRevokeGroup={onRevokeGroup}
|
|
95
|
+
onLeaveGroup={onLeaveGroup}
|
|
96
|
+
onSetMemberType={onSetMemberType}
|
|
92
97
|
verifyRecipient={verifyRecipient}
|
|
93
98
|
/>
|
|
94
99
|
</List>
|
|
@@ -102,6 +107,9 @@ WhoHasAccess.propTypes = {
|
|
|
102
107
|
canManageMembers: PropTypes.bool,
|
|
103
108
|
canManageLink: PropTypes.bool,
|
|
104
109
|
showOwner: PropTypes.bool,
|
|
110
|
+
owner: PropTypes.object,
|
|
111
|
+
isInsideSharedParent: PropTypes.bool,
|
|
112
|
+
sharedParentName: PropTypes.string,
|
|
105
113
|
recipients: PropTypes.array.isRequired,
|
|
106
114
|
recipientsToBeConfirmed: PropTypes.arrayOf(
|
|
107
115
|
PropTypes.shape({
|
|
@@ -112,6 +120,12 @@ WhoHasAccess.propTypes = {
|
|
|
112
120
|
documentType: PropTypes.string.isRequired,
|
|
113
121
|
onRevoke: PropTypes.func.isRequired,
|
|
114
122
|
onRevokeSelf: PropTypes.func,
|
|
115
|
-
|
|
123
|
+
onRevokeGroup: PropTypes.func.isRequired,
|
|
124
|
+
onLeaveGroup: PropTypes.func.isRequired,
|
|
125
|
+
onSetMemberType: PropTypes.func.isRequired,
|
|
126
|
+
onUpdateLinkPermissions: PropTypes.func.isRequired,
|
|
127
|
+
onRevokeLink: PropTypes.func.isRequired,
|
|
128
|
+
verifyRecipient: PropTypes.func,
|
|
129
|
+
permissions: PropTypes.arrayOf(PropTypes.object)
|
|
116
130
|
}
|
|
117
131
|
export default WhoHasAccess
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
|
|
3
|
+
import { useClient, useQuery, hasQueryBeenLoaded } from 'cozy-client'
|
|
4
|
+
|
|
5
|
+
import WhoHasAccess from './WhoHasAccess'
|
|
6
|
+
import { hasMemberActions, markCurrentUser } from '../helpers/recipients'
|
|
7
|
+
import { useMemberPermissionType } from '../hooks/useMemberPermissionType'
|
|
8
|
+
import { useSharingContext } from '../hooks/useSharingContext'
|
|
9
|
+
import { buildInstanceSettingsQuery } from '../queries/queries'
|
|
10
|
+
|
|
11
|
+
// When the owner is not part of a sharing's members (eg. the folder only has
|
|
12
|
+
// a link), there is no per-sharing avatar to reference. The instance's public
|
|
13
|
+
// avatar still holds the owner's picture. fallback=initials makes the stack
|
|
14
|
+
// serve a generated initials avatar (instead of the app icon) when no picture
|
|
15
|
+
// has been uploaded, matching how avatars are rendered everywhere else.
|
|
16
|
+
const OWNER_PUBLIC_AVATAR_PATH = '/public/avatar?fallback=initials'
|
|
17
|
+
|
|
18
|
+
const WhoHasAccessWrapper = ({
|
|
19
|
+
isOwner = false,
|
|
20
|
+
canManageSharing = isOwner,
|
|
21
|
+
isSharedDrive,
|
|
22
|
+
isReadOnly,
|
|
23
|
+
canManageMembers = !isReadOnly,
|
|
24
|
+
canManageLink,
|
|
25
|
+
showOwner = true,
|
|
26
|
+
recipients,
|
|
27
|
+
recipientsToBeConfirmed = [],
|
|
28
|
+
document,
|
|
29
|
+
documentType,
|
|
30
|
+
className,
|
|
31
|
+
onRevoke,
|
|
32
|
+
onRevokeSelf,
|
|
33
|
+
verifyRecipient,
|
|
34
|
+
link
|
|
35
|
+
}) => {
|
|
36
|
+
const client = useClient()
|
|
37
|
+
const {
|
|
38
|
+
isOrgSharedDrive,
|
|
39
|
+
getDocumentPermissions,
|
|
40
|
+
updateDocumentPermissions,
|
|
41
|
+
revokeSharingLink,
|
|
42
|
+
revokeGroup,
|
|
43
|
+
revokeSelf
|
|
44
|
+
} = useSharingContext()
|
|
45
|
+
|
|
46
|
+
const instanceUri = client.options.uri
|
|
47
|
+
const markedRecipients = markCurrentUser(recipients, instanceUri)
|
|
48
|
+
const hasMemberMenus = markedRecipients.some(
|
|
49
|
+
recipient =>
|
|
50
|
+
!recipient.members &&
|
|
51
|
+
!recipientsToBeConfirmed.some(user => user.email === recipient.email) &&
|
|
52
|
+
hasMemberActions({
|
|
53
|
+
status: recipient.status,
|
|
54
|
+
isCurrentUser: recipient.isCurrentUser,
|
|
55
|
+
isOwner,
|
|
56
|
+
canManageSharing,
|
|
57
|
+
canManageMembers
|
|
58
|
+
})
|
|
59
|
+
)
|
|
60
|
+
const { isInsideSharedParent, sharedParentName, setMemberType } =
|
|
61
|
+
useMemberPermissionType(document, { shouldFetchPath: hasMemberMenus })
|
|
62
|
+
const ownerRecipient = markedRecipients.find(
|
|
63
|
+
recipient => recipient.status === 'owner'
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
const instanceSettingsQuery = buildInstanceSettingsQuery()
|
|
67
|
+
const instanceSettingsResult = useQuery(instanceSettingsQuery.definition, {
|
|
68
|
+
...instanceSettingsQuery.options,
|
|
69
|
+
enabled: showOwner && !ownerRecipient
|
|
70
|
+
})
|
|
71
|
+
|
|
72
|
+
const defaultOwner = hasQueryBeenLoaded(instanceSettingsResult)
|
|
73
|
+
? {
|
|
74
|
+
isOwner: true,
|
|
75
|
+
status: 'owner',
|
|
76
|
+
instance: instanceUri,
|
|
77
|
+
avatarPath: OWNER_PUBLIC_AVATAR_PATH,
|
|
78
|
+
public_name: instanceSettingsResult.data?.attributes?.public_name
|
|
79
|
+
}
|
|
80
|
+
: null
|
|
81
|
+
|
|
82
|
+
const owner = ownerRecipient
|
|
83
|
+
? { ...ownerRecipient, isOrgSharedDrive: isOrgSharedDrive(document?._id) }
|
|
84
|
+
: defaultOwner
|
|
85
|
+
|
|
86
|
+
return (
|
|
87
|
+
<WhoHasAccess
|
|
88
|
+
isOwner={isOwner}
|
|
89
|
+
canManageSharing={canManageSharing}
|
|
90
|
+
isSharedDrive={isSharedDrive}
|
|
91
|
+
isReadOnly={isReadOnly}
|
|
92
|
+
canManageMembers={canManageMembers}
|
|
93
|
+
canManageLink={canManageLink}
|
|
94
|
+
showOwner={showOwner}
|
|
95
|
+
owner={owner}
|
|
96
|
+
isInsideSharedParent={isInsideSharedParent}
|
|
97
|
+
sharedParentName={sharedParentName}
|
|
98
|
+
recipients={markedRecipients}
|
|
99
|
+
recipientsToBeConfirmed={recipientsToBeConfirmed}
|
|
100
|
+
document={document}
|
|
101
|
+
documentType={documentType}
|
|
102
|
+
className={className}
|
|
103
|
+
onRevoke={onRevoke}
|
|
104
|
+
onRevokeSelf={onRevokeSelf}
|
|
105
|
+
onRevokeGroup={revokeGroup}
|
|
106
|
+
onLeaveGroup={revokeSelf}
|
|
107
|
+
onSetMemberType={setMemberType}
|
|
108
|
+
onUpdateLinkPermissions={updateDocumentPermissions}
|
|
109
|
+
onRevokeLink={revokeSharingLink}
|
|
110
|
+
verifyRecipient={verifyRecipient}
|
|
111
|
+
link={link}
|
|
112
|
+
permissions={getDocumentPermissions(document?._id)}
|
|
113
|
+
/>
|
|
114
|
+
)
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
export default WhoHasAccessWrapper
|