cozy-sharing 31.0.2 → 31.2.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.
Files changed (81) hide show
  1. package/CHANGELOG.md +30 -0
  2. package/dist/components/FederatedFolder/DumbFederatedFolderModal.js +15 -16
  3. package/dist/components/FederatedFolder/FederatedFolderModal.js +78 -103
  4. package/dist/components/FederatedFolder/FederatedFolderModal.spec.js +102 -292
  5. package/dist/components/Recipient/GroupRecipientPermissions.js +15 -11
  6. package/dist/components/Recipient/LinkRecipient.js +15 -11
  7. package/dist/components/Recipient/LinkRecipientLite.js +1 -1
  8. package/dist/components/Recipient/LinkRecipientPermissions.js +2 -1
  9. package/dist/components/Recipient/MemberRecipient.spec.js +8 -10
  10. package/dist/components/Recipient/MemberRecipientLite.js +1 -1
  11. package/dist/components/Recipient/MemberRecipientPermissions.js +16 -12
  12. package/dist/components/Recipient/MemberRecipientPermissions.spec.js +62 -50
  13. package/dist/components/Recipient/RecipientConfirm.js +0 -5
  14. package/dist/components/ShareAutosuggest.js +9 -4
  15. package/dist/components/ShareByEmail.js +29 -274
  16. package/dist/components/ShareByEmail.spec.js +52 -230
  17. package/dist/components/ShareByLink.js +1 -3
  18. package/dist/components/ShareDialogCozyToCozy.js +169 -35
  19. package/dist/components/ShareDialogCozyToCozy.spec.js +123 -36
  20. package/dist/components/ShareDialogTwoStepsConfirmationContainer.js +13 -3
  21. package/dist/components/ShareModal/SharingDetailsModal.js +0 -5
  22. package/dist/components/ShareRecipientsInput.js +6 -3
  23. package/dist/components/SharedDrive/SharedDriveForm.js +17 -25
  24. package/dist/components/SharedDrive/SharedDriveModal.js +1 -1
  25. package/dist/components/SharedDrive/SharedDriveRecipientPermissions.js +15 -10
  26. package/dist/components/SharedDrive/useSharedDrive.js +33 -57
  27. package/dist/components/SharedDrive/useSharedDrive.spec.js +29 -93
  28. package/dist/components/SharedFolder/DumbBatchSharedFolderModal.js +15 -26
  29. package/dist/components/Sharetypeselect.js +85 -90
  30. package/dist/hooks/usePendingRecipients.js +20 -0
  31. package/dist/hooks/usePendingRecipients.spec.js +30 -0
  32. package/dist/styles/autosuggest.styl +8 -2
  33. package/dist/styles/share.styl +0 -39
  34. package/dist/stylesheet.css +8 -36
  35. package/locales/en.json +14 -44
  36. package/locales/fr.json +14 -44
  37. package/locales/ru.json +14 -44
  38. package/locales/vi.json +14 -42
  39. package/package.json +2 -2
  40. package/src/components/FederatedFolder/DumbFederatedFolderModal.jsx +14 -15
  41. package/src/components/FederatedFolder/FederatedFolderModal.jsx +50 -67
  42. package/src/components/FederatedFolder/FederatedFolderModal.spec.jsx +63 -186
  43. package/src/components/Recipient/GroupRecipientPermissions.jsx +15 -13
  44. package/src/components/Recipient/LinkRecipient.jsx +9 -9
  45. package/src/components/Recipient/LinkRecipientLite.jsx +1 -3
  46. package/src/components/Recipient/LinkRecipientPermissions.jsx +2 -1
  47. package/src/components/Recipient/MemberRecipient.spec.jsx +4 -6
  48. package/src/components/Recipient/MemberRecipientLite.jsx +2 -2
  49. package/src/components/Recipient/MemberRecipientPermissions.jsx +16 -21
  50. package/src/components/Recipient/MemberRecipientPermissions.spec.jsx +21 -23
  51. package/src/components/ShareAutosuggest.jsx +7 -2
  52. package/src/components/ShareByEmail.jsx +35 -186
  53. package/src/components/ShareByEmail.spec.jsx +22 -173
  54. package/src/components/ShareByLink.jsx +1 -7
  55. package/src/components/ShareDialogCozyToCozy.jsx +171 -38
  56. package/src/components/ShareDialogCozyToCozy.spec.jsx +67 -1
  57. package/src/components/ShareDialogTwoStepsConfirmationContainer.jsx +11 -1
  58. package/src/components/ShareRecipientsInput.jsx +5 -2
  59. package/src/components/SharedDrive/SharedDriveForm.jsx +16 -25
  60. package/src/components/SharedDrive/SharedDriveModal.jsx +1 -1
  61. package/src/components/SharedDrive/SharedDriveRecipientPermissions.jsx +15 -17
  62. package/src/components/SharedDrive/useSharedDrive.js +24 -50
  63. package/src/components/SharedDrive/useSharedDrive.spec.js +19 -67
  64. package/src/components/SharedFolder/DumbBatchSharedFolderModal.jsx +15 -29
  65. package/src/components/Sharetypeselect.jsx +75 -58
  66. package/src/hooks/usePendingRecipients.js +13 -0
  67. package/src/hooks/usePendingRecipients.spec.js +21 -0
  68. package/src/styles/autosuggest.styl +8 -2
  69. package/src/styles/share.styl +0 -39
  70. package/dist/components/Recipient/actions/revokeGroup.js +0 -42
  71. package/dist/components/Recipient/actions/revokeMember.js +0 -42
  72. package/dist/components/Recipient/actions/revokeSharedDriveMember.js +0 -41
  73. package/dist/components/SharedDrive/helpers.js +0 -102
  74. package/dist/components/SharedDrive/helpers.spec.js +0 -227
  75. package/dist/components/Sharesubmit.js +0 -28
  76. package/src/components/Recipient/actions/revokeGroup.js +0 -42
  77. package/src/components/Recipient/actions/revokeMember.js +0 -42
  78. package/src/components/Recipient/actions/revokeSharedDriveMember.js +0 -41
  79. package/src/components/SharedDrive/helpers.js +0 -108
  80. package/src/components/SharedDrive/helpers.spec.js +0 -177
  81. package/src/components/Sharesubmit.jsx +0 -31
@@ -1,108 +0,0 @@
1
- import { models } from 'cozy-client'
2
-
3
- const ContactModel = models.contact
4
-
5
- export const RECIPIENT_INDEX_PREFIX = 'virtual-shared-drive-sharing-'
6
-
7
- export const mergeAndDeduplicateRecipients = arrays => {
8
- const combinedArray = arrays.flat().map(item => ({
9
- ...item,
10
- id: item.id || item._id
11
- }))
12
-
13
- const seenIds = new Set()
14
-
15
- const uniqueArray = combinedArray.reduce((acc, item) => {
16
- const id = item.id || item._id
17
-
18
- if (id == null) {
19
- // Recipients without any identifier are kept as-is to avoid silent data loss
20
- acc.push(item)
21
- return acc
22
- }
23
-
24
- if (!seenIds.has(id)) {
25
- seenIds.add(id)
26
- // Ensure both id and _id exist for downstream compatibility
27
- const normalizedItem =
28
- !item.id || !item._id
29
- ? { ...item, id: item.id || item._id, _id: item._id || item.id }
30
- : item
31
- acc.push(normalizedItem)
32
- }
33
-
34
- return acc
35
- }, [])
36
-
37
- return uniqueArray
38
- }
39
-
40
- export const moveRecipientToReadWrite = (federatedRecipients, _id) => {
41
- const recipientToMove = federatedRecipients.readOnlyRecipients.find(
42
- r => r._id === _id
43
- )
44
- if (!recipientToMove) return federatedRecipients
45
-
46
- return {
47
- recipients: [...federatedRecipients.recipients, recipientToMove],
48
- readOnlyRecipients: federatedRecipients.readOnlyRecipients.filter(
49
- r => r._id !== _id
50
- )
51
- }
52
- }
53
-
54
- export const moveRecipientToReadOnly = (federatedRecipients, _id) => {
55
- const recipientToMove = federatedRecipients.recipients.find(
56
- r => r._id === _id
57
- )
58
- if (!recipientToMove) return federatedRecipients
59
-
60
- return {
61
- recipients: federatedRecipients.recipients.filter(r => r._id !== _id),
62
- readOnlyRecipients: [
63
- ...federatedRecipients.readOnlyRecipients,
64
- recipientToMove
65
- ]
66
- }
67
- }
68
-
69
- export const formatRecipients = sharedDriveRecipients => {
70
- const recipients = []
71
-
72
- sharedDriveRecipients.recipients.forEach(r => {
73
- recipients.push({
74
- index: `${RECIPIENT_INDEX_PREFIX}${r._id}`,
75
- email: ContactModel.getPrimaryEmail(r),
76
- public_name: ContactModel.getDisplayName(r),
77
- memberIndex: r._id,
78
- type: 'two-way',
79
- members: r.members
80
- })
81
- })
82
-
83
- sharedDriveRecipients.readOnlyRecipients.forEach(r => {
84
- recipients.push({
85
- index: `${RECIPIENT_INDEX_PREFIX}${r._id}`,
86
- email: ContactModel.getPrimaryEmail(r),
87
- public_name: ContactModel.getDisplayName(r),
88
- memberIndex: r._id,
89
- type: 'one-way',
90
- members: r.members
91
- })
92
- })
93
-
94
- // We need to sort recipients by public_name
95
- // to avoid reording them every time we change
96
- // them from read only to read write.
97
- recipients.sort((a, b) => {
98
- if (a.public_name < b.public_name) {
99
- return -1
100
- }
101
- if (a.public_name > b.public_name) {
102
- return 1
103
- }
104
- return 0
105
- })
106
-
107
- return recipients
108
- }
@@ -1,177 +0,0 @@
1
- import {
2
- mergeAndDeduplicateRecipients,
3
- moveRecipientToReadWrite,
4
- moveRecipientToReadOnly,
5
- formatRecipients,
6
- RECIPIENT_INDEX_PREFIX
7
- } from './helpers'
8
-
9
- describe('mergeAndDeduplicateRecipients', () => {
10
- it('should merge multiple arrays into one', () => {
11
- const result = mergeAndDeduplicateRecipients([
12
- [{ id: '1', name: 'Alice' }],
13
- [{ id: '2', name: 'Bob' }]
14
- ])
15
- expect(result).toEqual([
16
- { id: '1', _id: '1', name: 'Alice' },
17
- { id: '2', _id: '2', name: 'Bob' }
18
- ])
19
- })
20
-
21
- it('should deduplicate recipients with the same id', () => {
22
- const result = mergeAndDeduplicateRecipients([
23
- [{ id: '1', name: 'Alice' }],
24
- [{ id: '1', name: 'Alice' }]
25
- ])
26
- expect(result).toEqual([{ id: '1', _id: '1', name: 'Alice' }])
27
- })
28
-
29
- it('should normalize _id to id for deduplication', () => {
30
- const result = mergeAndDeduplicateRecipients([
31
- [{ _id: '1', name: 'Alice' }],
32
- [{ _id: '2', name: 'Bob' }]
33
- ])
34
- expect(result).toEqual([
35
- { _id: '1', id: '1', name: 'Alice' },
36
- { _id: '2', id: '2', name: 'Bob' }
37
- ])
38
- })
39
-
40
- it('should deduplicate recipients when one has id and the other has _id', () => {
41
- const result = mergeAndDeduplicateRecipients([
42
- [{ id: '1', name: 'Alice' }],
43
- [{ _id: '1', name: 'Alice' }]
44
- ])
45
- expect(result).toEqual([{ id: '1', _id: '1', name: 'Alice' }])
46
- })
47
-
48
- it('should prefer existing id over _id when both are present', () => {
49
- const result = mergeAndDeduplicateRecipients([
50
- [{ id: 'real-id', _id: 'other-id', name: 'Alice' }]
51
- ])
52
- expect(result).toEqual([{ id: 'real-id', _id: 'other-id', name: 'Alice' }])
53
- })
54
-
55
- it('should handle empty arrays', () => {
56
- const result = mergeAndDeduplicateRecipients([[], []])
57
- expect(result).toEqual([])
58
- })
59
- })
60
-
61
- describe('moveRecipientToReadWrite', () => {
62
- it('should move a recipient from readOnly to readWrite', () => {
63
- const state = {
64
- recipients: [{ _id: '1', name: 'Alice' }],
65
- readOnlyRecipients: [{ _id: '2', name: 'Bob' }]
66
- }
67
- const result = moveRecipientToReadWrite(state, '2')
68
- expect(result.recipients).toEqual([
69
- { _id: '1', name: 'Alice' },
70
- { _id: '2', name: 'Bob' }
71
- ])
72
- expect(result.readOnlyRecipients).toEqual([])
73
- })
74
-
75
- it('should return unchanged state if recipient not found', () => {
76
- const state = {
77
- recipients: [{ _id: '1', name: 'Alice' }],
78
- readOnlyRecipients: []
79
- }
80
- const result = moveRecipientToReadWrite(state, '999')
81
- expect(result).toBe(state)
82
- })
83
- })
84
-
85
- describe('moveRecipientToReadOnly', () => {
86
- it('should move a recipient from readWrite to readOnly', () => {
87
- const state = {
88
- recipients: [{ _id: '1', name: 'Alice' }],
89
- readOnlyRecipients: [{ _id: '2', name: 'Bob' }]
90
- }
91
- const result = moveRecipientToReadOnly(state, '1')
92
- expect(result.recipients).toEqual([])
93
- expect(result.readOnlyRecipients).toEqual([
94
- { _id: '2', name: 'Bob' },
95
- { _id: '1', name: 'Alice' }
96
- ])
97
- })
98
-
99
- it('should return unchanged state if recipient not found', () => {
100
- const state = {
101
- recipients: [],
102
- readOnlyRecipients: [{ _id: '1', name: 'Alice' }]
103
- }
104
- const result = moveRecipientToReadOnly(state, '999')
105
- expect(result).toBe(state)
106
- })
107
- })
108
-
109
- describe('formatRecipients', () => {
110
- it('should format readWrite and readOnly recipients with correct types', () => {
111
- const input = {
112
- recipients: [
113
- {
114
- _id: '1',
115
- displayName: 'Alice',
116
- email: [{ address: 'alice@example.com', primary: true }]
117
- }
118
- ],
119
- readOnlyRecipients: [
120
- {
121
- _id: '2',
122
- displayName: 'Bob',
123
- email: [{ address: 'bob@example.com', primary: true }]
124
- }
125
- ]
126
- }
127
- const result = formatRecipients(input)
128
- expect(result).toHaveLength(2)
129
- expect(result[0]).toMatchObject({
130
- index: `${RECIPIENT_INDEX_PREFIX}1`,
131
- type: 'two-way',
132
- public_name: 'Alice'
133
- })
134
- expect(result[1]).toMatchObject({
135
- index: `${RECIPIENT_INDEX_PREFIX}2`,
136
- type: 'one-way',
137
- public_name: 'Bob'
138
- })
139
- })
140
-
141
- it('should flatten an object-shaped contact name into a string public_name', () => {
142
- const input = {
143
- recipients: [
144
- {
145
- _id: '3',
146
- name: { givenName: 'Arya', familyName: 'Stark' },
147
- email: [{ address: 'arya@example.com', primary: true }]
148
- }
149
- ],
150
- readOnlyRecipients: []
151
- }
152
- const result = formatRecipients(input)
153
- expect(typeof result[0].public_name).toBe('string')
154
- expect(result[0].public_name).toBe('Arya Stark')
155
- })
156
-
157
- it('should sort recipients by public_name', () => {
158
- const input = {
159
- recipients: [
160
- {
161
- _id: '1',
162
- displayName: 'Zara',
163
- email: [{ address: 'zara@example.com', primary: true }]
164
- },
165
- {
166
- _id: '2',
167
- displayName: 'Alice',
168
- email: [{ address: 'alice@example.com', primary: true }]
169
- }
170
- ],
171
- readOnlyRecipients: []
172
- }
173
- const result = formatRecipients(input)
174
- expect(result[0].public_name).toBe('Alice')
175
- expect(result[1].public_name).toBe('Zara')
176
- })
177
- })
@@ -1,31 +0,0 @@
1
- import PropTypes from 'prop-types'
2
- import React from 'react'
3
-
4
- import Button from 'cozy-ui/transpiled/react/Buttons'
5
-
6
- const ShareSubmit = props => (
7
- <Button
8
- onClick={() => {
9
- props.onSubmit()
10
- }}
11
- size="large"
12
- busy={props.loading}
13
- label={props.label}
14
- disabled={props.disabled}
15
- variant="ghost"
16
- />
17
- )
18
-
19
- ShareSubmit.propTypes = {
20
- onSubmit: PropTypes.func.isRequired,
21
- label: PropTypes.string,
22
- loading: PropTypes.bool,
23
- disabled: PropTypes.bool
24
- }
25
-
26
- ShareSubmit.defaultProps = {
27
- label: 'Submit',
28
- loading: false
29
- }
30
-
31
- export default ShareSubmit