cozy-sharing 18.0.0 → 20.0.0
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 +57 -0
- package/dist/SharingProvider.js +16 -9
- package/dist/components/Recipient/LinkRecipient.js +20 -4
- package/dist/components/Recipient/LinkRecipientPermissions.js +18 -129
- package/dist/components/Recipient/actions/editPermissionLink.js +71 -0
- package/dist/components/Recipient/actions/readOnlyPermissionLink.js +63 -0
- package/dist/components/ShareByLink.js +45 -185
- package/dist/components/ShareDialogCozyToCozy.js +2 -6
- package/dist/components/ShareDialogOnlyByLink.js +2 -8
- package/dist/components/ShareDialogTwoStepsConfirmationContainer.js +1 -3
- package/dist/components/ShareModal/EditableSharingModal.js +1 -7
- package/dist/components/ShareModal.js +0 -12
- package/dist/components/ShareRestrictionModal/BoxDate.js +77 -0
- package/dist/components/ShareRestrictionModal/BoxEditingRights.js +83 -0
- package/dist/components/ShareRestrictionModal/BoxPassword.js +155 -0
- package/dist/components/ShareRestrictionModal/ShareRestrictionContentModal.js +118 -0
- package/dist/components/ShareRestrictionModal/ShareRestrictionModal.js +256 -0
- package/dist/components/ShareRestrictionModal/helpers.js +310 -0
- package/dist/components/ShareRestrictionModal/helpers.spec.js +232 -0
- package/dist/components/WhoHasAccess.js +1 -5
- package/dist/helpers/permissions.js +15 -0
- package/locales/en.json +30 -0
- package/locales/fr.json +31 -0
- package/package.json +11 -7
- package/src/SharingProvider.jsx +10 -5
- package/src/components/Recipient/LinkRecipient.jsx +28 -4
- package/src/components/Recipient/LinkRecipientPermissions.jsx +28 -137
- package/src/components/Recipient/actions/editPermissionLink.js +63 -0
- package/src/components/Recipient/actions/readOnlyPermissionLink.js +59 -0
- package/src/components/ShareByLink.jsx +20 -96
- package/src/components/ShareDialogCozyToCozy.jsx +1 -5
- package/src/components/ShareDialogOnlyByLink.jsx +0 -6
- package/src/components/ShareDialogTwoStepsConfirmationContainer.jsx +0 -2
- package/src/components/ShareModal/EditableSharingModal.jsx +1 -7
- package/src/components/ShareModal.jsx +0 -12
- package/src/components/ShareRestrictionModal/BoxDate.jsx +76 -0
- package/src/components/ShareRestrictionModal/BoxEditingRights.jsx +91 -0
- package/src/components/ShareRestrictionModal/BoxPassword.jsx +126 -0
- package/src/components/ShareRestrictionModal/ShareRestrictionContentModal.jsx +124 -0
- package/src/components/ShareRestrictionModal/ShareRestrictionModal.jsx +186 -0
- package/src/components/ShareRestrictionModal/helpers.js +227 -0
- package/src/components/ShareRestrictionModal/helpers.spec.js +159 -0
- package/src/components/WhoHasAccess.jsx +1 -5
- package/src/helpers/permissions.js +12 -0
- package/dist/components/EditLinkPermissionDialog.js +0 -72
- package/dist/components/EditLinkPermissionDialog.spec.js +0 -48
- package/src/components/EditLinkPermissionDialog.jsx +0 -89
- package/src/components/EditLinkPermissionDialog.spec.jsx +0 -53
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cozy-sharing",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "20.0.0",
|
|
4
4
|
"description": "Provides sharing login for React applications.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"author": "Cozy",
|
|
@@ -32,6 +32,7 @@
|
|
|
32
32
|
"classnames": "^2.2.6",
|
|
33
33
|
"cozy-device-helper": "^3.7.1",
|
|
34
34
|
"cozy-doctypes": "^1.97.1",
|
|
35
|
+
"date-fns": "2.30.0",
|
|
35
36
|
"lodash": "^4.17.19",
|
|
36
37
|
"react-autosuggest": "^10.1.0",
|
|
37
38
|
"react-tooltip": "^3.11.1",
|
|
@@ -52,8 +53,11 @@
|
|
|
52
53
|
"babel-jest": "26.6.3",
|
|
53
54
|
"babel-plugin-css-modules-transform": "1.6.2",
|
|
54
55
|
"babel-plugin-inline-react-svg": "1.1.2",
|
|
55
|
-
"cozy-client": "^
|
|
56
|
-
"cozy-
|
|
56
|
+
"cozy-client": "^53.0.0",
|
|
57
|
+
"cozy-device-helper": "^3.7.1",
|
|
58
|
+
"cozy-intent": "^2.29.1",
|
|
59
|
+
"cozy-minilog": "^3.9.1",
|
|
60
|
+
"cozy-ui": "^116.0.0",
|
|
57
61
|
"jest": "26.6.3",
|
|
58
62
|
"jest-environment-jsdom": "26.6.2",
|
|
59
63
|
"react": "16.12.0",
|
|
@@ -62,11 +66,11 @@
|
|
|
62
66
|
"storybook": "7.6.0"
|
|
63
67
|
},
|
|
64
68
|
"peerDependencies": {
|
|
65
|
-
"cozy-client": ">=
|
|
69
|
+
"cozy-client": ">=53.0.0",
|
|
66
70
|
"cozy-device-helper": ">=3.7.1",
|
|
67
71
|
"cozy-intent": ">=2.29.1",
|
|
68
|
-
"cozy-
|
|
69
|
-
"cozy-ui": ">=
|
|
72
|
+
"cozy-minilog": ">=3.9.1",
|
|
73
|
+
"cozy-ui": ">=116.0.0",
|
|
70
74
|
"prop-types": "^15.7.2",
|
|
71
75
|
"react": "^16.12.0",
|
|
72
76
|
"react-router": "^5.0.1"
|
|
@@ -74,5 +78,5 @@
|
|
|
74
78
|
"sideEffects": [
|
|
75
79
|
"*.css"
|
|
76
80
|
],
|
|
77
|
-
"gitHead": "
|
|
81
|
+
"gitHead": "7dbd527d95ca869695120926125905fdcc2413b0"
|
|
78
82
|
}
|
package/src/SharingProvider.jsx
CHANGED
|
@@ -331,25 +331,30 @@ export class SharingProvider extends Component {
|
|
|
331
331
|
* updateDocumentPermissions - Description
|
|
332
332
|
*
|
|
333
333
|
* @param {Object} document A shared document
|
|
334
|
-
* @param {
|
|
334
|
+
* @param {object} options The new verbs to use for the permission, eg. ['GET']
|
|
335
|
+
* @param {string[]} options.verbs The new verbs to use for the permission, eg. ['GET']
|
|
336
|
+
* @param {string} [options.expiresAt] The new expiration date for the permission
|
|
337
|
+
* @param {string} [options.password] The new password for the permission
|
|
335
338
|
*
|
|
336
339
|
* @return {Array}
|
|
337
340
|
*/
|
|
338
|
-
updateDocumentPermissions = async (document,
|
|
341
|
+
updateDocumentPermissions = async (document, options) => {
|
|
342
|
+
const { verbs, expiresAt, password } = options
|
|
339
343
|
const permissions = getDocumentPermissions(this.state, document.id)
|
|
340
344
|
|
|
341
345
|
const responses = await Promise.all(
|
|
342
346
|
permissions.map(async permissionDocument => {
|
|
343
347
|
const updatedPermissions = permissionDocument.attributes.permissions
|
|
344
348
|
Object.keys(updatedPermissions).map(permType => {
|
|
345
|
-
updatedPermissions[permType].verbs =
|
|
349
|
+
updatedPermissions[permType].verbs = verbs
|
|
346
350
|
})
|
|
347
351
|
|
|
348
352
|
const resp = await this.permissionCol.add(
|
|
349
353
|
permissionDocument,
|
|
350
|
-
updatedPermissions
|
|
354
|
+
updatedPermissions,
|
|
355
|
+
{ expiresAt, password }
|
|
351
356
|
)
|
|
352
|
-
this.dispatch(updateSharingLink(resp))
|
|
357
|
+
this.dispatch(updateSharingLink(resp.data))
|
|
353
358
|
return resp
|
|
354
359
|
})
|
|
355
360
|
)
|
|
@@ -14,14 +14,38 @@ import { useI18n } from 'cozy-ui/transpiled/react/providers/I18n'
|
|
|
14
14
|
|
|
15
15
|
import LinkRecipientPermissions from './LinkRecipientPermissions'
|
|
16
16
|
import RecipientConfirm from './RecipientConfirm'
|
|
17
|
+
import {
|
|
18
|
+
checkIsPermissionHasPassword,
|
|
19
|
+
getPermissionExpiresDate
|
|
20
|
+
} from '../../helpers/permissions'
|
|
17
21
|
import { FADE_IN_DURATION } from '../../helpers/recipients'
|
|
22
|
+
import { useSharingContext } from '../../hooks/useSharingContext'
|
|
18
23
|
import styles from '../../styles/recipient.styl'
|
|
19
24
|
|
|
20
25
|
const LinkRecipient = props => {
|
|
21
|
-
const { t } = useI18n()
|
|
26
|
+
const { t, f, lang } = useI18n()
|
|
22
27
|
const { isMobile } = useBreakpoints()
|
|
28
|
+
const { getDocumentPermissions } = useSharingContext()
|
|
23
29
|
|
|
24
|
-
const { recipientConfirmationData, verifyRecipient, link, fadeIn } =
|
|
30
|
+
const { recipientConfirmationData, verifyRecipient, link, fadeIn, document } =
|
|
31
|
+
props
|
|
32
|
+
|
|
33
|
+
const permissions = getDocumentPermissions(document._id)
|
|
34
|
+
const hasPassword = checkIsPermissionHasPassword(permissions)
|
|
35
|
+
const expiresDate = getPermissionExpiresDate(permissions)
|
|
36
|
+
const dateFormatted = expiresDate
|
|
37
|
+
? f(expiresDate, lang === 'fr' ? 'dd/LL/yyyy' : 'LL/dd/yyyy')
|
|
38
|
+
: null
|
|
39
|
+
|
|
40
|
+
const textPrimary = hasPassword
|
|
41
|
+
? t('Share.recipients.linkWithPassword')
|
|
42
|
+
: t('Share.recipients.anyoneWithTheLink')
|
|
43
|
+
|
|
44
|
+
const textSecondary = expiresDate
|
|
45
|
+
? t('Share.recipients.expires', {
|
|
46
|
+
date: dateFormatted
|
|
47
|
+
})
|
|
48
|
+
: link
|
|
25
49
|
|
|
26
50
|
const RightPart = recipientConfirmationData ? (
|
|
27
51
|
<RecipientConfirm
|
|
@@ -43,10 +67,10 @@ const LinkRecipient = props => {
|
|
|
43
67
|
<ListItemText
|
|
44
68
|
primary={
|
|
45
69
|
<Typography className="u-ellipsis" variant="body1">
|
|
46
|
-
{
|
|
70
|
+
{textPrimary}
|
|
47
71
|
</Typography>
|
|
48
72
|
}
|
|
49
|
-
secondary={
|
|
73
|
+
secondary={textSecondary}
|
|
50
74
|
/>
|
|
51
75
|
{RightPart}
|
|
52
76
|
</ListItem>
|
|
@@ -1,156 +1,47 @@
|
|
|
1
|
+
import PropTypes from 'prop-types'
|
|
1
2
|
import React, { useState, useRef } from 'react'
|
|
2
3
|
|
|
3
4
|
import DropdownButton from 'cozy-ui/transpiled/react/DropdownButton'
|
|
4
|
-
import Icon from 'cozy-ui/transpiled/react/Icon'
|
|
5
|
-
import TrashIcon from 'cozy-ui/transpiled/react/Icons/Trash'
|
|
6
|
-
import Spinner from 'cozy-ui/transpiled/react/Spinner'
|
|
7
|
-
import Typography from 'cozy-ui/transpiled/react/Typography'
|
|
8
|
-
import ActionMenu, {
|
|
9
|
-
ActionMenuItem,
|
|
10
|
-
ActionMenuRadio
|
|
11
|
-
} from 'cozy-ui/transpiled/react/deprecated/ActionMenu'
|
|
12
|
-
import Alerter from 'cozy-ui/transpiled/react/deprecated/Alerter'
|
|
13
5
|
import { useI18n } from 'cozy-ui/transpiled/react/providers/I18n'
|
|
14
6
|
|
|
15
|
-
import { isOnlyReadOnlyLinkAllowed } from '../../helpers/link'
|
|
16
7
|
import { checkIsReadOnlyPermissions } from '../../helpers/permissions'
|
|
17
|
-
import
|
|
8
|
+
import { ShareRestrictionModal } from '../ShareRestrictionModal/ShareRestrictionModal'
|
|
18
9
|
|
|
19
|
-
const LinkRecipientPermissions = ({
|
|
20
|
-
className,
|
|
21
|
-
document,
|
|
22
|
-
documentType,
|
|
23
|
-
permissions,
|
|
24
|
-
onChangePermissions,
|
|
25
|
-
onDisable
|
|
26
|
-
}) => {
|
|
10
|
+
const LinkRecipientPermissions = ({ className, document, permissions }) => {
|
|
27
11
|
const { t } = useI18n()
|
|
28
12
|
const buttonRef = useRef()
|
|
29
|
-
const [
|
|
30
|
-
|
|
13
|
+
const [openShareRestrictionModal, setOpenShareRestrictionModal] =
|
|
14
|
+
useState(false)
|
|
31
15
|
|
|
32
16
|
const isReadOnlyPermissions = checkIsReadOnlyPermissions(permissions)
|
|
33
17
|
|
|
34
|
-
const toggleMenu = () => {
|
|
35
|
-
setMenuIsOpen(!menuIsOpen)
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
const deleteShareLink = async () => {
|
|
39
|
-
try {
|
|
40
|
-
setLoading(true)
|
|
41
|
-
await onDisable(document)
|
|
42
|
-
} catch (e) {
|
|
43
|
-
Alerter.error(t(`${documentType}.share.error.revoke`))
|
|
44
|
-
logger.log(e)
|
|
45
|
-
} finally {
|
|
46
|
-
setLoading(false)
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
const updateLinkPermissions = ({ isReadOnly }) => {
|
|
51
|
-
const verbs = isReadOnly ? ['GET'] : ['GET', 'POST', 'PUT', 'PATCH']
|
|
52
|
-
try {
|
|
53
|
-
onChangePermissions(document, verbs)
|
|
54
|
-
} catch (err) {
|
|
55
|
-
Alerter.error(t(`${documentType}.share.shareByLink.permserror`))
|
|
56
|
-
logger.log(err)
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
18
|
return (
|
|
60
19
|
<div className={className}>
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
strategy: 'fixed'
|
|
79
|
-
}}
|
|
80
|
-
anchorElRef={buttonRef}
|
|
81
|
-
>
|
|
82
|
-
<ActionMenuItem
|
|
83
|
-
left={
|
|
84
|
-
<ActionMenuRadio
|
|
85
|
-
name="permissionLinkMenu"
|
|
86
|
-
value="true"
|
|
87
|
-
checked={isReadOnlyPermissions}
|
|
88
|
-
/>
|
|
89
|
-
}
|
|
90
|
-
onClick={() => {
|
|
91
|
-
toggleMenu()
|
|
92
|
-
updateLinkPermissions({ isReadOnly: true })
|
|
93
|
-
}}
|
|
94
|
-
>
|
|
95
|
-
<>
|
|
96
|
-
{document?.type === 'directory'
|
|
97
|
-
? t(`Share.permissionLink.seeFolder`)
|
|
98
|
-
: t(`Share.permissionLink.seeFile`)}
|
|
99
|
-
<Typography
|
|
100
|
-
className="u-mt-half"
|
|
101
|
-
variant="caption"
|
|
102
|
-
color="textSecondary"
|
|
103
|
-
>
|
|
104
|
-
{t('Share.permissionLink.readDescription')}
|
|
105
|
-
</Typography>
|
|
106
|
-
</>
|
|
107
|
-
</ActionMenuItem>
|
|
108
|
-
{!isOnlyReadOnlyLinkAllowed({ documentType }) && (
|
|
109
|
-
<ActionMenuItem
|
|
110
|
-
left={
|
|
111
|
-
<ActionMenuRadio
|
|
112
|
-
name="permissionLinkMenu"
|
|
113
|
-
value="false"
|
|
114
|
-
checked={!isReadOnlyPermissions}
|
|
115
|
-
/>
|
|
116
|
-
}
|
|
117
|
-
onClick={() => {
|
|
118
|
-
toggleMenu()
|
|
119
|
-
updateLinkPermissions({ isReadOnly: false })
|
|
120
|
-
}}
|
|
121
|
-
>
|
|
122
|
-
<>
|
|
123
|
-
{document?.type === 'directory'
|
|
124
|
-
? t(`Share.permissionLink.modifyFolder`)
|
|
125
|
-
: t(`Share.permissionLink.modifyFile`)}
|
|
126
|
-
<Typography
|
|
127
|
-
className="u-mt-half"
|
|
128
|
-
variant="caption"
|
|
129
|
-
color="textSecondary"
|
|
130
|
-
>
|
|
131
|
-
{t('Share.permissionLink.writeDescription')}
|
|
132
|
-
</Typography>
|
|
133
|
-
</>
|
|
134
|
-
</ActionMenuItem>
|
|
135
|
-
)}
|
|
136
|
-
<hr />
|
|
137
|
-
<ActionMenuItem
|
|
138
|
-
left={<Icon icon={TrashIcon} color="var(--errorColor)" />}
|
|
139
|
-
onClick={() => {
|
|
140
|
-
toggleMenu()
|
|
141
|
-
deleteShareLink()
|
|
142
|
-
}}
|
|
143
|
-
>
|
|
144
|
-
<Typography className="u-error" variant="body1">
|
|
145
|
-
{t('Share.permissionLink.deactivate')}
|
|
146
|
-
</Typography>
|
|
147
|
-
</ActionMenuItem>
|
|
148
|
-
</ActionMenu>
|
|
149
|
-
)}
|
|
150
|
-
</>
|
|
151
|
-
)}
|
|
20
|
+
<>
|
|
21
|
+
<DropdownButton
|
|
22
|
+
ref={buttonRef}
|
|
23
|
+
textVariant="body2"
|
|
24
|
+
onClick={() => setOpenShareRestrictionModal(true)}
|
|
25
|
+
>
|
|
26
|
+
{t(
|
|
27
|
+
`Share.type.${isReadOnlyPermissions ? 'one-way' : 'two-way'}`
|
|
28
|
+
).toLowerCase()}
|
|
29
|
+
</DropdownButton>
|
|
30
|
+
{openShareRestrictionModal && (
|
|
31
|
+
<ShareRestrictionModal
|
|
32
|
+
file={document}
|
|
33
|
+
onClose={() => setOpenShareRestrictionModal(false)}
|
|
34
|
+
/>
|
|
35
|
+
)}
|
|
36
|
+
</>
|
|
152
37
|
</div>
|
|
153
38
|
)
|
|
154
39
|
}
|
|
155
40
|
|
|
41
|
+
LinkRecipientPermissions.propTypes = {
|
|
42
|
+
className: PropTypes.string,
|
|
43
|
+
document: PropTypes.object.isRequired,
|
|
44
|
+
permissions: PropTypes.arrayOf(PropTypes.object).isRequired
|
|
45
|
+
}
|
|
46
|
+
|
|
156
47
|
export default LinkRecipientPermissions
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import React, { forwardRef } from 'react'
|
|
2
|
+
|
|
3
|
+
import ActionsMenuItem from 'cozy-ui/transpiled/react/ActionsMenu/ActionsMenuItem'
|
|
4
|
+
import ListItemIcon from 'cozy-ui/transpiled/react/ListItemIcon'
|
|
5
|
+
import ListItemText from 'cozy-ui/transpiled/react/ListItemText'
|
|
6
|
+
import Radios from 'cozy-ui/transpiled/react/Radios'
|
|
7
|
+
|
|
8
|
+
import { isOnlyReadOnlyLinkAllowed } from '../../../helpers/link'
|
|
9
|
+
import { useSharingContext } from '../../../hooks/useSharingContext'
|
|
10
|
+
|
|
11
|
+
const makeComponent = ({ label, desc, editingRights }) => {
|
|
12
|
+
const Component = forwardRef((props, ref) => {
|
|
13
|
+
const { updateDocumentPermissions } = useSharingContext()
|
|
14
|
+
|
|
15
|
+
return (
|
|
16
|
+
<ActionsMenuItem
|
|
17
|
+
{...props}
|
|
18
|
+
ref={ref}
|
|
19
|
+
button={false}
|
|
20
|
+
onClick={() => props.onClick({ updateDocumentPermissions })}
|
|
21
|
+
>
|
|
22
|
+
<ListItemIcon>
|
|
23
|
+
<Radios checked={editingRights === 'write'} />
|
|
24
|
+
</ListItemIcon>
|
|
25
|
+
<ListItemText primary={label} secondary={desc} />
|
|
26
|
+
</ActionsMenuItem>
|
|
27
|
+
)
|
|
28
|
+
})
|
|
29
|
+
Component.displayName = 'EditPermissionLink'
|
|
30
|
+
|
|
31
|
+
return Component
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* @param {boolean} isDirectory - true if the document is a directory
|
|
36
|
+
* @param {function} t - translation function
|
|
37
|
+
* @param {string} editingRights - current editing rights
|
|
38
|
+
* @param {function} setEditingRights - function to set editing rights
|
|
39
|
+
* @param {string} documentType - type of the document
|
|
40
|
+
*/
|
|
41
|
+
export const editPermissionLink = ({
|
|
42
|
+
isDirectory,
|
|
43
|
+
t,
|
|
44
|
+
editingRights,
|
|
45
|
+
setEditingRights,
|
|
46
|
+
documentType
|
|
47
|
+
}) => {
|
|
48
|
+
const label = isDirectory
|
|
49
|
+
? t('Share.permissionLink.modifyFolder')
|
|
50
|
+
: t('Share.permissionLink.modifyFile')
|
|
51
|
+
const desc = t('Share.permissionLink.writeDescription')
|
|
52
|
+
|
|
53
|
+
return {
|
|
54
|
+
name: 'editPermissionLink',
|
|
55
|
+
label,
|
|
56
|
+
icon: null,
|
|
57
|
+
displayCondition: () => !isOnlyReadOnlyLinkAllowed({ documentType }),
|
|
58
|
+
action: () => {
|
|
59
|
+
setEditingRights('write')
|
|
60
|
+
},
|
|
61
|
+
Component: makeComponent({ label, desc, editingRights })
|
|
62
|
+
}
|
|
63
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import React, { forwardRef } from 'react'
|
|
2
|
+
|
|
3
|
+
import ActionsMenuItem from 'cozy-ui/transpiled/react/ActionsMenu/ActionsMenuItem'
|
|
4
|
+
import ListItemIcon from 'cozy-ui/transpiled/react/ListItemIcon'
|
|
5
|
+
import ListItemText from 'cozy-ui/transpiled/react/ListItemText'
|
|
6
|
+
import Radios from 'cozy-ui/transpiled/react/Radios'
|
|
7
|
+
|
|
8
|
+
import { useSharingContext } from '../../../hooks/useSharingContext'
|
|
9
|
+
|
|
10
|
+
const makeComponent = ({ label, desc, editingRights }) => {
|
|
11
|
+
const Component = forwardRef((props, ref) => {
|
|
12
|
+
const { updateDocumentPermissions } = useSharingContext()
|
|
13
|
+
|
|
14
|
+
return (
|
|
15
|
+
<ActionsMenuItem
|
|
16
|
+
{...props}
|
|
17
|
+
ref={ref}
|
|
18
|
+
button={false}
|
|
19
|
+
onClick={() => props.onClick({ updateDocumentPermissions })}
|
|
20
|
+
>
|
|
21
|
+
<ListItemIcon>
|
|
22
|
+
<Radios checked={editingRights === 'readOnly'} />
|
|
23
|
+
</ListItemIcon>
|
|
24
|
+
<ListItemText primary={label} secondary={desc} />
|
|
25
|
+
</ActionsMenuItem>
|
|
26
|
+
)
|
|
27
|
+
})
|
|
28
|
+
Component.displayName = 'ReadOnlyPermissionLink'
|
|
29
|
+
|
|
30
|
+
return Component
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* @param {boolean} isDirectory - true if the document is a directory
|
|
35
|
+
* @param {function} t - translation function
|
|
36
|
+
* @param {string} editingRights - current editing rights
|
|
37
|
+
* @param {function} setEditingRights - function to set editing rights
|
|
38
|
+
*/
|
|
39
|
+
export const readOnlyPermissionLink = ({
|
|
40
|
+
isDirectory,
|
|
41
|
+
t,
|
|
42
|
+
editingRights,
|
|
43
|
+
setEditingRights
|
|
44
|
+
}) => {
|
|
45
|
+
const label = isDirectory
|
|
46
|
+
? t('Share.permissionLink.seeFolder')
|
|
47
|
+
: t('Share.permissionLink.seeFile')
|
|
48
|
+
const desc = t('Share.permissionLink.readDescription')
|
|
49
|
+
|
|
50
|
+
return {
|
|
51
|
+
name: 'readOnlyPermissionLink',
|
|
52
|
+
label,
|
|
53
|
+
icon: null,
|
|
54
|
+
action: () => {
|
|
55
|
+
setEditingRights('readOnly')
|
|
56
|
+
},
|
|
57
|
+
Component: makeComponent({ label, desc, editingRights })
|
|
58
|
+
}
|
|
59
|
+
}
|
|
@@ -1,95 +1,35 @@
|
|
|
1
1
|
import PropTypes from 'prop-types'
|
|
2
|
-
import React, {
|
|
2
|
+
import React, { useReducer } from 'react'
|
|
3
3
|
|
|
4
|
-
import Alert from 'cozy-ui/transpiled/react/Alert'
|
|
5
4
|
import Button from 'cozy-ui/transpiled/react/Buttons'
|
|
6
5
|
import Icon from 'cozy-ui/transpiled/react/Icon'
|
|
7
6
|
import CopyIcon from 'cozy-ui/transpiled/react/Icons/Copy'
|
|
8
7
|
import LinkIcon from 'cozy-ui/transpiled/react/Icons/Link'
|
|
9
|
-
import
|
|
8
|
+
import { useAlert } from 'cozy-ui/transpiled/react/providers/Alert'
|
|
10
9
|
import useBreakpoints from 'cozy-ui/transpiled/react/providers/Breakpoints'
|
|
11
10
|
import { useI18n } from 'cozy-ui/transpiled/react/providers/I18n'
|
|
12
11
|
|
|
13
|
-
import
|
|
14
|
-
import {
|
|
15
|
-
import logger from '../logger'
|
|
12
|
+
import { ShareRestrictionModal } from './ShareRestrictionModal/ShareRestrictionModal'
|
|
13
|
+
import { copyToClipboard } from './ShareRestrictionModal/helpers'
|
|
16
14
|
|
|
17
|
-
const ShareByLink = ({ link, document, documentType
|
|
15
|
+
const ShareByLink = ({ link, document, documentType }) => {
|
|
18
16
|
const { t } = useI18n()
|
|
19
17
|
const { isMobile } = useBreakpoints()
|
|
20
|
-
const
|
|
21
|
-
const [shouldCopyToClipboard, setShouldCopyToClipboard] = useState(false)
|
|
22
|
-
const [alert, setAlert] = useState(false)
|
|
18
|
+
const { showAlert } = useAlert()
|
|
23
19
|
|
|
24
|
-
const
|
|
20
|
+
const showCopyAndSendButtons = link && isMobile && navigator.share
|
|
21
|
+
const showOnlyCopyButton =
|
|
22
|
+
(link && !isMobile) || (link && isMobile && !navigator.share)
|
|
25
23
|
|
|
26
|
-
const
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
await navigator.clipboard.writeText(link)
|
|
30
|
-
setAlert({
|
|
31
|
-
open: true,
|
|
32
|
-
severity: 'success',
|
|
33
|
-
message: t(`${documentType}.share.shareByLink.copied`)
|
|
34
|
-
})
|
|
35
|
-
} catch {
|
|
36
|
-
if (!isAutomaticCopy) {
|
|
37
|
-
// In case of automatic copy, the browser can block the copy request. This is not shown to the user since it is expected and can be circumvented by clicking directly on the copy link
|
|
38
|
-
setAlert({
|
|
39
|
-
open: true,
|
|
40
|
-
severity: 'error',
|
|
41
|
-
message: t(`${documentType}.share.shareByLink.failed`)
|
|
42
|
-
})
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
},
|
|
46
|
-
[documentType, link, t]
|
|
24
|
+
const [isEditDialogOpen, toggleEditDialogOpen] = useReducer(
|
|
25
|
+
state => !state,
|
|
26
|
+
false
|
|
47
27
|
)
|
|
48
28
|
|
|
49
|
-
const
|
|
50
|
-
|
|
51
|
-
setLoading(true)
|
|
52
|
-
await onEnable(document, options)
|
|
53
|
-
} catch (e) {
|
|
54
|
-
setAlert({
|
|
55
|
-
open: true,
|
|
56
|
-
severity: 'error',
|
|
57
|
-
message: t(`${documentType}.share.error.generic`)
|
|
58
|
-
})
|
|
59
|
-
logger.log(e)
|
|
60
|
-
} finally {
|
|
61
|
-
setLoading(false)
|
|
62
|
-
setShouldCopyToClipboard(true)
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
const onCreate = async () => {
|
|
67
|
-
if (isOnlyReadOnlyLinkAllowed({ documentType })) {
|
|
68
|
-
onPermissionsSelected({ verbs: ['GET'] })
|
|
69
|
-
} else {
|
|
70
|
-
setIsEditDialogOpen(true)
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
useEffect(() => {
|
|
75
|
-
if (link && shouldCopyToClipboard) {
|
|
76
|
-
copyLinkToClipboard({ isAutomaticCopy: true })
|
|
77
|
-
setShouldCopyToClipboard(false)
|
|
78
|
-
}
|
|
79
|
-
}, [link, shouldCopyToClipboard, copyLinkToClipboard])
|
|
80
|
-
|
|
81
|
-
const onClose = () => {
|
|
82
|
-
setIsEditDialogOpen(false)
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
const onCloseAlert = () => {
|
|
86
|
-
setAlert({ ...alert, open: false })
|
|
29
|
+
const copyLinkToClipboard = async () => {
|
|
30
|
+
await copyToClipboard(link, { t, showAlert })
|
|
87
31
|
}
|
|
88
32
|
|
|
89
|
-
const showCopyAndSendButtons = link && isMobile && navigator.share
|
|
90
|
-
const showOnlyCopyButton =
|
|
91
|
-
(link && !isMobile) || (link && isMobile && !navigator.share)
|
|
92
|
-
|
|
93
33
|
const shareLink = async () => {
|
|
94
34
|
try {
|
|
95
35
|
const shareData = {
|
|
@@ -100,10 +40,10 @@ const ShareByLink = ({ link, document, documentType, onEnable }) => {
|
|
|
100
40
|
}
|
|
101
41
|
await navigator.share(shareData)
|
|
102
42
|
} catch (error) {
|
|
103
|
-
|
|
104
|
-
|
|
43
|
+
showAlert({
|
|
44
|
+
message: t(`${documentType}.share.error.generic`),
|
|
105
45
|
severity: 'error',
|
|
106
|
-
|
|
46
|
+
variant: 'filled'
|
|
107
47
|
})
|
|
108
48
|
}
|
|
109
49
|
}
|
|
@@ -117,9 +57,8 @@ const ShareByLink = ({ link, document, documentType, onEnable }) => {
|
|
|
117
57
|
size="medium"
|
|
118
58
|
startIcon={<Icon icon={LinkIcon} />}
|
|
119
59
|
className="u-flex-auto"
|
|
120
|
-
busy={loading}
|
|
121
60
|
style={{ position: 'initial' }} // fix z-index bug on iOS when under a BottomDrawer due to relative position
|
|
122
|
-
onClick={
|
|
61
|
+
onClick={toggleEditDialogOpen}
|
|
123
62
|
/>
|
|
124
63
|
)}
|
|
125
64
|
{showCopyAndSendButtons && (
|
|
@@ -151,22 +90,8 @@ const ShareByLink = ({ link, document, documentType, onEnable }) => {
|
|
|
151
90
|
/>
|
|
152
91
|
)}
|
|
153
92
|
{isEditDialogOpen && (
|
|
154
|
-
<
|
|
155
|
-
open
|
|
156
|
-
onClose={onClose}
|
|
157
|
-
document={document}
|
|
158
|
-
onPermissionsSelected={onPermissionsSelected}
|
|
159
|
-
/>
|
|
93
|
+
<ShareRestrictionModal file={document} onClose={toggleEditDialogOpen} />
|
|
160
94
|
)}
|
|
161
|
-
<Snackbar open={alert.open} onClose={onCloseAlert}>
|
|
162
|
-
<Alert
|
|
163
|
-
variant="filled"
|
|
164
|
-
severity={alert.severity}
|
|
165
|
-
onClose={onCloseAlert}
|
|
166
|
-
>
|
|
167
|
-
{alert.message}
|
|
168
|
-
</Alert>
|
|
169
|
-
</Snackbar>
|
|
170
95
|
</div>
|
|
171
96
|
)
|
|
172
97
|
}
|
|
@@ -174,8 +99,7 @@ const ShareByLink = ({ link, document, documentType, onEnable }) => {
|
|
|
174
99
|
ShareByLink.propTypes = {
|
|
175
100
|
link: PropTypes.string,
|
|
176
101
|
document: PropTypes.object.isRequired,
|
|
177
|
-
documentType: PropTypes.string.isRequired
|
|
178
|
-
onEnable: PropTypes.func.isRequired
|
|
102
|
+
documentType: PropTypes.string.isRequired
|
|
179
103
|
}
|
|
180
104
|
|
|
181
105
|
export default ShareByLink
|
|
@@ -33,9 +33,7 @@ const SharingContent = ({
|
|
|
33
33
|
recipientsToBeConfirmed,
|
|
34
34
|
verifyRecipient,
|
|
35
35
|
link,
|
|
36
|
-
permissions
|
|
37
|
-
onUpdateShareLinkPermissions,
|
|
38
|
-
onRevokeLink
|
|
36
|
+
permissions
|
|
39
37
|
}) => {
|
|
40
38
|
const { t } = useI18n()
|
|
41
39
|
const { isMobile } = useBreakpoints()
|
|
@@ -89,8 +87,6 @@ const SharingContent = ({
|
|
|
89
87
|
verifyRecipient={verifyRecipient}
|
|
90
88
|
link={link}
|
|
91
89
|
permissions={permissions}
|
|
92
|
-
onUpdateShareLinkPermissions={onUpdateShareLinkPermissions}
|
|
93
|
-
onRevokeLink={onRevokeLink}
|
|
94
90
|
/>
|
|
95
91
|
)}
|
|
96
92
|
</div>
|
|
@@ -18,9 +18,6 @@ const ShareDialogOnlyByLink = ({
|
|
|
18
18
|
documentType,
|
|
19
19
|
link,
|
|
20
20
|
onClose,
|
|
21
|
-
onRevokeLink,
|
|
22
|
-
onShareByLink,
|
|
23
|
-
onUpdateShareLinkPermissions,
|
|
24
21
|
permissions
|
|
25
22
|
}) => {
|
|
26
23
|
const { t } = useI18n()
|
|
@@ -52,8 +49,6 @@ const ShareDialogOnlyByLink = ({
|
|
|
52
49
|
recipients={recipients}
|
|
53
50
|
link={link}
|
|
54
51
|
permissions={permissions}
|
|
55
|
-
onUpdateShareLinkPermissions={onUpdateShareLinkPermissions}
|
|
56
|
-
onRevokeLink={onRevokeLink}
|
|
57
52
|
/>
|
|
58
53
|
<div
|
|
59
54
|
className={cx(
|
|
@@ -65,7 +60,6 @@ const ShareDialogOnlyByLink = ({
|
|
|
65
60
|
link={link}
|
|
66
61
|
document={document}
|
|
67
62
|
documentType={documentType}
|
|
68
|
-
onEnable={onShareByLink}
|
|
69
63
|
/>
|
|
70
64
|
</div>
|
|
71
65
|
</>
|
|
@@ -98,7 +98,6 @@ const ShareDialogTwoStepsConfirmationContainer = ({
|
|
|
98
98
|
onRevokeLink,
|
|
99
99
|
onRevokeSelf,
|
|
100
100
|
onShare,
|
|
101
|
-
onShareByLink,
|
|
102
101
|
onUpdateShareLinkPermissions,
|
|
103
102
|
permissions,
|
|
104
103
|
recipients,
|
|
@@ -233,7 +232,6 @@ const ShareDialogTwoStepsConfirmationContainer = ({
|
|
|
233
232
|
link={link}
|
|
234
233
|
document={document}
|
|
235
234
|
documentType={documentType}
|
|
236
|
-
onEnable={onShareByLink}
|
|
237
235
|
/>
|
|
238
236
|
) : null
|
|
239
237
|
} else if (status === 'confirmingRecipient') {
|