Skip to content

Commit b284023

Browse files
committed
feat: Implement duplicating files in shared drive ✨
1 parent 7ad546d commit b284023

7 files changed

Lines changed: 125 additions & 5 deletions

File tree

‎src/components/FolderPicker/types.ts‎

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,15 @@
11
import { IOCozyFile, NextcloudFile } from 'cozy-client/types/types'
22

3-
export type File = IOCozyFile | NextcloudFile
3+
export type File = (IOCozyFile | NextcloudFile) & {
4+
cozyMetadata?: {
5+
createdOn?: string
6+
}
7+
attributes?: {
8+
cozyMetadata?: {
9+
createdOn?: string
10+
}
11+
}
12+
}
413

514
export interface FolderPickerEntry {
615
_id?: string
@@ -11,4 +20,5 @@ export interface FolderPickerEntry {
1120
dir_id?: string
1221
class?: string
1322
path?: string
23+
driveId?: string
1424
}

‎src/declarations.d.ts‎

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,21 @@ declare module 'cozy-client/dist/models/file' {
101101
filename: string,
102102
driveId: string
103103
) => Promise<string>
104+
export const moveRelateToSharedDrive: (
105+
client: import('cozy-client/types/CozyClient').CozyClient,
106+
source: {
107+
instance?: string
108+
sharing_id?: string
109+
file_id?: string
110+
dir_id?: string
111+
},
112+
dest: {
113+
instance?: string
114+
sharing_id?: string
115+
dir_id: string
116+
},
117+
isCopy?: boolean
118+
) => Promise<void>
104119
}
105120

106121
declare module 'cozy-client/dist/models/note' {

‎src/modules/duplicate/components/DuplicateModal.tsx‎

Lines changed: 42 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,12 @@ import React, { FC, useState } from 'react'
22
import { useNavigate } from 'react-router-dom'
33

44
import { useClient } from 'cozy-client'
5-
import { copy } from 'cozy-client/dist/models/file'
5+
import {
6+
copy,
7+
isDirectory,
8+
moveRelateToSharedDrive
9+
} from 'cozy-client/dist/models/file'
10+
import { IOCozyFile } from 'cozy-client/types/types'
611
import { useAlert } from 'cozy-ui/transpiled/react/providers/Alert'
712
import { useI18n } from 'cozy-ui/transpiled/react/providers/I18n'
813

@@ -18,13 +23,17 @@ interface DuplicateModalProps {
1823
currentFolder: File
1924
onClose: () => void | Promise<void>
2025
showNextcloudFolder?: boolean
26+
showSharedDriveFolder?: boolean
27+
driveId?: string
2128
}
2229

2330
const DuplicateModal: FC<DuplicateModalProps> = ({
2431
entries,
2532
currentFolder,
2633
onClose,
27-
showNextcloudFolder
34+
showNextcloudFolder,
35+
showSharedDriveFolder,
36+
driveId
2837
}) => {
2938
const { t } = useI18n()
3039
const { showAlert } = useAlert()
@@ -39,7 +48,7 @@ const DuplicateModal: FC<DuplicateModalProps> = ({
3948
setBusy(true)
4049
await Promise.all(
4150
entries.map(async entry => {
42-
await registerCancelable(copy(client, entry as Partial<File>, folder))
51+
await registerCancelable(handleCopyApi(client, entry, folder))
4352
})
4453
)
4554

@@ -73,6 +82,35 @@ const DuplicateModal: FC<DuplicateModalProps> = ({
7382
}
7483
}
7584

85+
const handleCopyApi = async (
86+
client: unknown,
87+
entry: FolderPickerEntry,
88+
folder: File
89+
): Promise<void> => {
90+
if (driveId || entry.driveId || (folder as IOCozyFile).driveId) {
91+
return await moveRelateToSharedDrive(
92+
client,
93+
{
94+
instance: entry.driveId
95+
? currentFolder.attributes?.cozyMetadata?.createdOn
96+
: '',
97+
file_id: !isDirectory(entry) ? entry._id : '',
98+
dir_id: isDirectory(entry) ? entry._id : '',
99+
sharing_id: entry.driveId
100+
},
101+
{
102+
instance: (folder as IOCozyFile).driveId
103+
? folder.cozyMetadata?.createdOn
104+
: '',
105+
sharing_id: (folder as IOCozyFile).driveId,
106+
dir_id: folder._id
107+
},
108+
true
109+
)
110+
}
111+
return await copy(client, entry, folder)
112+
}
113+
76114
/**
77115
* The content from nextcloud queries must be refreshed when coping files
78116
* This is only a proxy to Nextcloud queries so we don't have real-time or mutations updates
@@ -88,6 +126,7 @@ const DuplicateModal: FC<DuplicateModalProps> = ({
88126
return (
89127
<FolderPicker
90128
showNextcloudFolder={showNextcloudFolder}
129+
showSharedDriveFolder={showSharedDriveFolder}
91130
currentFolder={currentFolder}
92131
entries={entries}
93132
// eslint-disable-next-line @typescript-eslint/no-misused-promises

‎src/modules/navigation/AppRoute.jsx‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ import FileOpenerExternal from '@/modules/viewer/FileOpenerExternal'
3535
import { KonnectorRoutes } from '@/modules/views/Drive/KonnectorRoutes'
3636
import { FavoritesView } from '@/modules/views/Favorites/FavoritesView'
3737
import { FolderDuplicateView } from '@/modules/views/Folder/FolderDuplicateView'
38+
import { SharedDriveDuplicateView } from '@/modules/views/Folder/SharedDriveDuplicateView'
3839
import { MoveFilesView } from '@/modules/views/Modal/MoveFilesView'
3940
import { QualifyFileView } from '@/modules/views/Modal/QualifyFileView'
4041
import { ShareDisplayedFolderView } from '@/modules/views/Modal/ShareDisplayedFolderView'
@@ -141,6 +142,8 @@ const AppRoute = () => (
141142
/>
142143
<Route path="file/:fileId/revision" element={<FileHistory />} />
143144
<Route path="file/:fileId/v/revision" element={<FileHistory />} />
145+
<Route path="share" element={<ShareDisplayedFolderView />} />
146+
<Route path="duplicate" element={<SharedDriveDuplicateView />} />
144147
</Route>
145148
</>
146149
) : null}

‎src/modules/shareddrives/components/SharedDriveFolderBody.jsx‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import { useI18n } from 'cozy-ui/transpiled/react/providers/I18n'
1212

1313
import { useModalContext } from '@/lib/ModalContext'
1414
import { download, infos, versions, rename, trash, hr } from '@/modules/actions'
15+
import { duplicateTo } from '@/modules/actions/components/duplicateTo'
1516
import { FolderBody } from '@/modules/folder/components/FolderBody'
1617

1718
const SharedDriveFolderBody = ({
@@ -51,7 +52,7 @@ const SharedDriveFolderBody = ({
5152
refresh
5253
}
5354
const actions = makeActions(
54-
[download, hr, rename, infos, hr, versions, hr, trash],
55+
[download, hr, rename, duplicateTo, infos, hr, versions, hr, trash],
5556
actionsOptions
5657
)
5758

‎src/modules/views/Folder/FolderDuplicateView.tsx‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import flag from 'cozy-flags'
88
import { LoaderModal } from '@/components/LoaderModal'
99
import useDisplayedFolder from '@/hooks/useDisplayedFolder'
1010
import { DuplicateModal } from '@/modules/duplicate/components/DuplicateModal'
11+
import { useSharedDrives } from '@/modules/shareddrives/hooks/useSharedDrives'
1112
import { buildParentsByIdsQuery } from '@/queries'
1213

1314
const FolderDuplicateView: FC = () => {
@@ -16,6 +17,7 @@ const FolderDuplicateView: FC = () => {
1617
state: { fileIds?: string[] }
1718
}
1819
const { displayedFolder } = useDisplayedFolder()
20+
const { sharedDrives } = useSharedDrives()
1921

2022
const hasFileIds = state.fileIds != undefined
2123

@@ -39,6 +41,7 @@ const FolderDuplicateView: FC = () => {
3941
return (
4042
<DuplicateModal
4143
showNextcloudFolder={!flag('drive.hide-nextcloud-dev')}
44+
showSharedDriveFolder={sharedDrives.length > 0}
4245
currentFolder={displayedFolder}
4346
entries={fileResult.data}
4447
onClose={onClose}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import React, { FC } from 'react'
2+
import { Navigate, useLocation, useNavigate } from 'react-router-dom'
3+
4+
import flag from 'cozy-flags'
5+
6+
import { LoaderModal } from '@/components/LoaderModal'
7+
import useDisplayedFolder from '@/hooks/useDisplayedFolder'
8+
import { DuplicateModal } from '@/modules/duplicate/components/DuplicateModal'
9+
import { useQueryMultipleSharedDriveFolders } from '@/modules/shareddrives/hooks/useQueryMultipleSharedDriveFolders'
10+
11+
const SharedDriveDuplicateView: FC = () => {
12+
const navigate = useNavigate()
13+
const { state } = useLocation() as {
14+
state: { fileIds?: string[] }
15+
}
16+
const { displayedFolder } = useDisplayedFolder()
17+
18+
const hasFileIds = state.fileIds != undefined
19+
20+
const { sharedDriveResults } = useQueryMultipleSharedDriveFolders({
21+
folderIds: state.fileIds ?? [],
22+
driveId: displayedFolder?.driveId ?? ''
23+
})
24+
25+
if (!hasFileIds) {
26+
return <Navigate to=".." replace={true} />
27+
}
28+
29+
if (sharedDriveResults && displayedFolder) {
30+
const onClose = (): void => {
31+
navigate('..', { replace: true })
32+
}
33+
34+
return (
35+
<DuplicateModal
36+
showNextcloudFolder={!flag('drive.hide-nextcloud-dev')}
37+
showSharedDriveFolder={true}
38+
currentFolder={displayedFolder}
39+
entries={sharedDriveResults}
40+
onClose={onClose}
41+
driveId={displayedFolder.driveId}
42+
/>
43+
)
44+
}
45+
46+
return <LoaderModal />
47+
}
48+
49+
export { SharedDriveDuplicateView }

0 commit comments

Comments
 (0)