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.
Files changed (107) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/dist/components/FederatedFolder/FederatedFolderModal.js +10 -12
  3. package/dist/components/FederatedFolder/FederatedFolderModal.spec.js +2 -2
  4. package/dist/components/Recipient/DowngradePermissionConfirmDialog.js +3 -12
  5. package/dist/components/Recipient/GroupRecipient.js +1 -4
  6. package/dist/components/Recipient/GroupRecipient.stories.js +3 -1
  7. package/dist/components/Recipient/GroupRecipientDetailWithAccess.js +1 -4
  8. package/dist/components/Recipient/GroupRecipientPermissions.js +5 -8
  9. package/dist/components/Recipient/GroupRecipientPermissions.stories.js +2 -0
  10. package/dist/components/Recipient/LinkRecipient.js +2 -6
  11. package/dist/components/Recipient/LinkRecipient.stories.js +4 -0
  12. package/dist/components/Recipient/LinkRecipientPermissions.js +13 -12
  13. package/dist/components/Recipient/LinkRecipientPermissions.stories.js +5 -1
  14. package/dist/components/Recipient/MemberRecipient.js +7 -6
  15. package/dist/components/Recipient/MemberRecipient.spec.js +7 -12
  16. package/dist/components/Recipient/MemberRecipientPermissions.js +28 -13
  17. package/dist/components/Recipient/MemberRecipientPermissions.spec.js +5 -14
  18. package/dist/components/Recipient/MemberRecipientPermissions.stories.js +2 -1
  19. package/dist/components/Recipient/OwnerRecipient.js +4 -17
  20. package/dist/components/Recipient/OwnerRecipient.stories.js +3 -1
  21. package/dist/components/Recipient/OwnerRecipientDefaultLite.js +1 -1
  22. package/dist/components/Recipient/PermissionTypeMenu.js +32 -155
  23. package/dist/components/Recipient/PermissionTypeMenuWrapper.js +37 -0
  24. package/dist/components/Recipient/{PermissionTypeMenu.spec.js → PermissionTypeMenuWrapper.spec.js} +2 -2
  25. package/dist/components/Recipient/RecipientList.js +10 -0
  26. package/dist/components/Recipient/RecipientList.stories.js +3 -0
  27. package/dist/components/{ShareRecipientsInput.js → ShareAutosuggestWrapper.js} +12 -54
  28. package/dist/components/{ShareRecipientsInput.spec.js → ShareAutosuggestWrapper.spec.js} +3 -3
  29. package/dist/components/ShareByEmail.js +2 -2
  30. package/dist/components/ShareDialogCozyToCozy.js +20 -19
  31. package/dist/components/ShareDialogCozyToCozy.spec.js +3 -0
  32. package/dist/components/ShareDialogOnlyByLink.js +3 -5
  33. package/dist/components/ShareDialogOnlyByLink.spec.js +0 -1
  34. package/dist/components/ShareModal/SharingDetailsModal.js +2 -2
  35. package/dist/components/SharedDrive/EditSharedDriveModal.js +11 -10
  36. package/dist/components/SharedDrive/useSharedDrive.js +8 -11
  37. package/dist/components/SharingBanner/components/PublicBanner.js +8 -6
  38. package/dist/components/SharingBanner/components/PublicBanner.spec.js +1 -9
  39. package/dist/components/SharingBanner/components/SharingBanner.js +3 -0
  40. package/dist/components/SharingBanner/index.js +3 -0
  41. package/dist/components/SharingContent.js +3 -5
  42. package/dist/components/WhoHasAccess.js +27 -11
  43. package/dist/components/WhoHasAccessWrapper.js +122 -0
  44. package/dist/helpers/contacts.js +79 -1
  45. package/dist/helpers/contacts.spec.js +122 -1
  46. package/dist/helpers/recipients.js +46 -0
  47. package/dist/helpers/recipients.spec.js +89 -0
  48. package/dist/hooks/useMemberPermissionType.js +191 -0
  49. package/dist/hooks/useResolveRecipients.js +53 -0
  50. package/dist/hooks/useResolveRecipients.spec.js +140 -0
  51. package/dist/index.js +1 -1
  52. package/docs/share-modal-architecture.md +2 -2
  53. package/package.json +3 -3
  54. package/src/components/FederatedFolder/FederatedFolderModal.jsx +6 -12
  55. package/src/components/FederatedFolder/FederatedFolderModal.spec.jsx +1 -0
  56. package/src/components/Recipient/DowngradePermissionConfirmDialog.jsx +3 -10
  57. package/src/components/Recipient/GroupRecipient.jsx +1 -5
  58. package/src/components/Recipient/GroupRecipient.stories.jsx +3 -1
  59. package/src/components/Recipient/GroupRecipientDetailWithAccess.jsx +1 -4
  60. package/src/components/Recipient/GroupRecipientPermissions.jsx +5 -5
  61. package/src/components/Recipient/GroupRecipientPermissions.stories.jsx +2 -0
  62. package/src/components/Recipient/LinkRecipient.jsx +2 -4
  63. package/src/components/Recipient/LinkRecipient.stories.jsx +4 -0
  64. package/src/components/Recipient/LinkRecipientPermissions.jsx +16 -12
  65. package/src/components/Recipient/LinkRecipientPermissions.stories.jsx +5 -1
  66. package/src/components/Recipient/MemberRecipient.jsx +4 -4
  67. package/src/components/Recipient/MemberRecipient.spec.jsx +7 -10
  68. package/src/components/Recipient/MemberRecipientPermissions.jsx +29 -13
  69. package/src/components/Recipient/MemberRecipientPermissions.spec.jsx +5 -11
  70. package/src/components/Recipient/MemberRecipientPermissions.stories.jsx +2 -1
  71. package/src/components/Recipient/OwnerRecipient.jsx +4 -17
  72. package/src/components/Recipient/OwnerRecipient.stories.jsx +1 -1
  73. package/src/components/Recipient/OwnerRecipientDefaultLite.jsx +1 -1
  74. package/src/components/Recipient/PermissionTypeMenu.jsx +21 -81
  75. package/src/components/Recipient/PermissionTypeMenuWrapper.jsx +32 -0
  76. package/src/components/Recipient/{PermissionTypeMenu.spec.jsx → PermissionTypeMenuWrapper.spec.jsx} +2 -2
  77. package/src/components/Recipient/RecipientList.jsx +10 -0
  78. package/src/components/Recipient/RecipientList.stories.jsx +3 -0
  79. package/src/components/{ShareRecipientsInput.jsx → ShareAutosuggestWrapper.jsx} +14 -65
  80. package/src/components/{ShareRecipientsInput.spec.jsx → ShareAutosuggestWrapper.spec.jsx} +3 -3
  81. package/src/components/ShareByEmail.jsx +2 -2
  82. package/src/components/ShareDialogCozyToCozy.jsx +10 -11
  83. package/src/components/ShareDialogCozyToCozy.spec.jsx +1 -0
  84. package/src/components/ShareDialogOnlyByLink.jsx +2 -4
  85. package/src/components/ShareDialogOnlyByLink.spec.jsx +0 -1
  86. package/src/components/ShareModal/SharingDetailsModal.jsx +2 -2
  87. package/src/components/SharedDrive/EditSharedDriveModal.jsx +6 -11
  88. package/src/components/SharedDrive/useSharedDrive.js +4 -11
  89. package/src/components/SharingBanner/components/PublicBanner.jsx +6 -6
  90. package/src/components/SharingBanner/components/PublicBanner.spec.jsx +1 -8
  91. package/src/components/SharingBanner/components/SharingBanner.jsx +7 -1
  92. package/src/components/SharingBanner/index.jsx +4 -0
  93. package/src/components/SharingContent.jsx +2 -4
  94. package/src/components/WhoHasAccess.jsx +26 -12
  95. package/src/components/WhoHasAccessWrapper.jsx +117 -0
  96. package/src/helpers/contacts.js +83 -0
  97. package/src/helpers/contacts.spec.js +78 -1
  98. package/src/helpers/recipients.js +44 -0
  99. package/src/helpers/recipients.spec.js +82 -0
  100. package/src/hooks/useMemberPermissionType.js +110 -0
  101. package/src/hooks/useResolveRecipients.js +38 -0
  102. package/src/hooks/useResolveRecipients.spec.js +70 -0
  103. package/src/index.jsx +1 -1
  104. package/dist/components/Recipient/OwnerRecipientDefault.js +0 -27
  105. package/dist/components/Recipient/OwnerRecipientDefault.stories.js +0 -10
  106. package/src/components/Recipient/OwnerRecipientDefault.jsx +0 -37
  107. package/src/components/Recipient/OwnerRecipientDefault.stories.jsx +0 -13
@@ -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 { PermissionTypeMenu } from './PermissionTypeMenu'
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
- instance,
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
- !contactIsOwner &&
38
- ((instanceMatchesClient && !isOwner) || canManageSharing)
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 (instanceMatchesClient && !isOwner) {
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
- instanceMatchesClient,
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
- instance: 'http://cozy.local:8080',
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
- instance: 'http://other-cozy.local:8080'
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
- instance: 'http://cozy.local:8080'
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
- instance: 'http://alice.cozy.localhost:8080'
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 = ({ recipients, isOrgSharedDrive }) => {
8
- const ownerRecipient = recipients.find(
9
- recipient => recipient.status === 'owner'
10
- )
6
+ const OwnerRecipient = ({ owner }) => {
7
+ if (!owner) return null
11
8
 
12
- if (ownerRecipient) {
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
- recipients: PropTypes.array.isRequired,
26
- isOrgSharedDrive: PropTypes.bool
13
+ owner: PropTypes.object
27
14
  }
28
15
 
29
16
  export default OwnerRecipient
@@ -4,7 +4,7 @@ import { recipients } from '../../../.storybook/fixtures/recipients'
4
4
  const meta = {
5
5
  component: OwnerRecipient,
6
6
  args: {
7
- recipients
7
+ owner: recipients.find(recipient => recipient.status === 'owner')
8
8
  }
9
9
  }
10
10
 
@@ -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 OwnerRecipientDefault: show the instance public avatar (with an initials
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 PermissionTypeMenuComponent = ({
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, { withAncestors = false } = {}) => {
37
+ async (newType, options) => {
48
38
  try {
49
- if (withAncestors) {
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
- export const PermissionTypeMenu = withLocales(PermissionTypeMenuComponent)
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)
@@ -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 { PermissionTypeMenu } from './PermissionTypeMenu'
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
- <PermissionTypeMenu {...defaultProps} {...props} />
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}
@@ -9,6 +9,9 @@ const meta = {
9
9
  isOwner: false,
10
10
  onRevoke: () => {},
11
11
  onRevokeSelf: () => {},
12
+ onRevokeGroup: () => {},
13
+ onLeaveGroup: () => {},
14
+ onSetMemberType: () => {},
12
15
  verifyRecipient: () => true
13
16
  }
14
17
  }
@@ -2,27 +2,22 @@ import PropTypes from 'prop-types'
2
2
  import React from 'react'
3
3
 
4
4
  import { useQueryAll, isQueryLoading } from 'cozy-client'
5
- import { models } from 'cozy-client'
6
5
  import flag from 'cozy-flags'
7
6
 
8
7
  import ShareAutosuggest from './ShareAutosuggest'
9
- import { getContactsFromGroupId } from '../helpers/contacts'
8
+ import { computeContactsAndGroups } from '../helpers/contacts'
10
9
  import {
11
10
  buildReachableContactsQuery,
12
11
  buildContactGroupsQuery,
13
12
  buildUnreachableContactsWithGroupsQuery
14
13
  } from '../queries/queries'
15
14
 
16
- const ContactModel = models.contact
17
-
18
15
  /**
19
- * ShareRecipientsInput is responsible for fetching contacts and groups.
16
+ * ShareAutosuggestWrapper is responsible for fetching contacts and groups.
20
17
  * We retrieve all the contacts that are reachable and the groups they belong to.
21
18
  * In order to display the total number of members in each group, we also retrieve the contacts that are not reachable.
22
19
  */
23
- const isCurrentUser = contact => contact.me === true
24
-
25
- const ShareRecipientsInput = ({
20
+ const ShareAutosuggestWrapper = ({
26
21
  currentRecipients,
27
22
  recipients,
28
23
  placeholder,
@@ -64,60 +59,14 @@ const ShareRecipientsInput = ({
64
59
  (isQueryLoading(unreachableContactsWithGroupsResult) ||
65
60
  unreachableContactsWithGroupsResult.hasMore))
66
61
 
67
- const reachableContacts = (reachableContactsResult.data || []).filter(
68
- contact =>
69
- !isCurrentUser(contact) &&
70
- // We do not want contact already in the sharing
71
- !currentRecipients.find(
72
- r => r.email === ContactModel.getPrimaryEmail(contact)
73
- ) &&
74
- // We do not want contact currently in pending contacts (in chips)
75
- !recipients.find(r => r._id === contact._id)
76
- )
77
-
78
- const unreachableContactsWithGroups = (
79
- unreachableContactsWithGroupsResult.data || []
80
- ).filter(contact => !isCurrentUser(contact))
81
- const currentRecipientGroups = currentRecipients
82
- .map(({ id }) => id)
83
- .filter(Boolean)
84
- const contactGroups = (contactGroupsResult.data || [])
85
- .filter(
86
- ({ _id }) =>
87
- !flag('sharing.show-recipient-groups') ||
88
- !currentRecipientGroups.includes(_id)
89
- )
90
- .map(contactGroup => {
91
- const reachableMembers = getContactsFromGroupId(
92
- reachableContacts,
93
- contactGroup.id
94
- ).map(contact => ({
95
- ...contact,
96
- isReachable: true
97
- }))
98
-
99
- if (flag('sharing.show-recipient-groups') !== true) {
100
- return {
101
- ...contactGroup,
102
- members: reachableMembers
103
- }
104
- }
105
-
106
- const unreachableMembers = getContactsFromGroupId(
107
- unreachableContactsWithGroups,
108
- contactGroup.id
109
- ).map(contact => ({
110
- ...contact,
111
- isReachable: false
112
- }))
113
-
114
- return {
115
- ...contactGroup,
116
- members: [...reachableMembers, ...unreachableMembers]
117
- }
118
- })
119
-
120
- const contactsAndGroups = [...reachableContacts, ...contactGroups]
62
+ const contactsAndGroups = computeContactsAndGroups({
63
+ reachableContacts: reachableContactsResult.data || [],
64
+ unreachableContactsWithGroups:
65
+ unreachableContactsWithGroupsResult.data || [],
66
+ contactGroups: contactGroupsResult.data || [],
67
+ currentRecipients,
68
+ pendingRecipients: recipients
69
+ })
121
70
 
122
71
  return (
123
72
  <ShareAutosuggest
@@ -135,7 +84,7 @@ const ShareRecipientsInput = ({
135
84
  )
136
85
  }
137
86
 
138
- ShareRecipientsInput.propTypes = {
87
+ ShareAutosuggestWrapper.propTypes = {
139
88
  currentRecipients: PropTypes.array,
140
89
  recipients: PropTypes.array,
141
90
  placeholder: PropTypes.string,
@@ -147,9 +96,9 @@ ShareRecipientsInput.propTypes = {
147
96
  endAdornment: PropTypes.node
148
97
  }
149
98
 
150
- ShareRecipientsInput.defaultProps = {
99
+ ShareAutosuggestWrapper.defaultProps = {
151
100
  currentRecipients: [],
152
101
  recipients: []
153
102
  }
154
103
 
155
- export default ShareRecipientsInput
104
+ export default ShareAutosuggestWrapper
@@ -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 ShareRecipientsInput from './ShareRecipientsInput'
7
+ import ShareAutosuggestWrapper from './ShareAutosuggestWrapper'
8
8
  import AppLike from './SharingBanner/test/AppLike'
9
9
 
10
10
  jest.mock('cozy-flags', () => ({
@@ -37,7 +37,7 @@ jest.mock('./ShareAutosuggest', () => ({
37
37
  }
38
38
  }))
39
39
 
40
- describe('ShareRecipientsInput component', () => {
40
+ describe('ShareAutosuggestWrapper component', () => {
41
41
  const setup = (
42
42
  { contacts, contactGroups, unreachableContact },
43
43
  { currentRecipients, recipients } = {}
@@ -60,7 +60,7 @@ describe('ShareRecipientsInput component', () => {
60
60
  })
61
61
  render(
62
62
  <AppLike client={mockClient}>
63
- <ShareRecipientsInput
63
+ <ShareAutosuggestWrapper
64
64
  onPick={() => {}}
65
65
  onRemove={() => {}}
66
66
  placeholder="Enter recipients here"