Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 19 additions & 50 deletions src/app/drive/components/MoveItemsDialog/MoveItemsDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,23 +11,18 @@ import { RootState, store } from 'app/store';
import { useAppDispatch, useAppSelector } from 'app/store/hooks';
import { setItemsToMove, storageActions } from 'app/store/slices/storage';
import storageSelectors from 'app/store/slices/storage/storage.selectors';
import storageThunks from 'app/store/slices/storage/storage.thunks';
import { fetchDialogContentThunk } from 'app/store/slices/storage/storage.thunks/fetchDialogContentThunk';
import { getAncestorsAndSetNamePath } from 'app/store/slices/storage/storage.thunks/goToFolderThunk';
import { uiActions } from 'app/store/slices/ui';
import folderImage from 'assets/icons/light/folder.svg';
import { useEffect, useState } from 'react';
import { useSelector } from 'react-redux';
import {
handleRepeatedUploadingFiles,
handleRepeatedUploadingFolders,
} from 'app/store/slices/storage/storage.thunks/renameItemsThunk';
import { IRoot } from 'app/store/slices/storage/types';
import { DriveFileData, DriveFolderData, DriveItemData, FolderPathDialog } from 'app/drive/types';
import { DriveItemData, FolderPathDialog } from 'app/drive/types';
import { CreateFolderDialog } from 'views/Drive/components';
import workspacesSelectors from 'app/store/slices/workspaces/workspaces.selectors';
import localStorageService from 'services/local-storage.service';
import { STORAGE_KEYS } from 'services/storage-keys';
import { useMoveItems } from 'hooks/moveItems/useMoveItems';

interface MoveItemsDialogProps {
onItemsMoved?: () => void;
Expand All @@ -43,7 +38,6 @@ const MoveItemsDialog = (props: MoveItemsDialogProps): JSX.Element => {
const [currentFolderId, setCurrentFolderId] = useState('');
const [shownFolders, setShownFolders] = useState(props.items);
const [currentFolderName, setCurrentFolderName] = useState('');
const [selectedFolderName, setSelectedFolderName] = useState('');
const arrayOfPaths: FolderPathDialog[] = [];
const [currentNamePaths, setCurrentNamePaths] = useState(arrayOfPaths);
const dispatch = useAppDispatch();
Expand All @@ -54,6 +48,7 @@ const MoveItemsDialog = (props: MoveItemsDialogProps): JSX.Element => {
const isDriveAndCurrentFolder = !props.isTrash && itemParentId === destinationId;
const workspaceSelected = useSelector(workspacesSelectors.getSelectedWorkspace);
const isWorkspaceSelected = !!workspaceSelected;
const { moveItemFromDialog } = useMoveItems();

const onCreateFolderButtonClicked = () => {
dispatch(uiActions.setIsCreateFolderDialogOpen(true));
Expand Down Expand Up @@ -124,7 +119,6 @@ const MoveItemsDialog = (props: MoveItemsDialogProps): JSX.Element => {
} else {
setDestinationId(currentFolderId);
}
name && setSelectedFolderName(name);
};

const onClose = (): void => {
Expand Down Expand Up @@ -167,32 +161,6 @@ const MoveItemsDialog = (props: MoveItemsDialogProps): JSX.Element => {
}
};

const prepareDestinationFolder = (destinationFolderId: string, namePaths: FolderPathDialog[]) => {
if (destinationFolderId !== currentFolderId) {
namePaths.push({ uuid: destinationId, name: selectedFolderName });
}
return destinationFolderId || currentFolderId;
};

const processItemsMove = async (finalDestinationId: string) => {
const files = itemsToMove.filter((item) => item.type !== 'folder') as DriveFileData[];
const folders = itemsToMove.filter((item) => item.type === 'folder') as (IRoot | DriveFolderData)[];

const filesWithoutDuplicates = await handleRepeatedUploadingFiles(files, dispatch, finalDestinationId);
const foldersWithoutDuplicates = await handleRepeatedUploadingFolders(folders, dispatch, finalDestinationId);

const itemsToMoveWithoutDuplicates = [...filesWithoutDuplicates, ...foldersWithoutDuplicates];

if (itemsToMoveWithoutDuplicates.length > 0) {
await dispatch(
storageThunks.moveItemsThunk({
items: itemsToMoveWithoutDuplicates as DriveItemData[],
destinationFolderId: finalDestinationId,
}),
);
}
};

const finalizeMove = () => {
props.onItemsMoved?.();
setIsLoading(false);
Expand All @@ -203,18 +171,19 @@ const MoveItemsDialog = (props: MoveItemsDialogProps): JSX.Element => {
store.dispatch(storageActions.popItemsToDelete(itemsToMove));
};

const onAccept = async (destinationFolderId: string, _: string, namePaths: FolderPathDialog[]): Promise<void> => {
const onAccept = async (destinationFolderId: string): Promise<void> => {
try {
dispatch(storageActions.setMoveDestinationFolderId(destinationFolderId));
setIsLoading(true);

if (itemsToMove.length === 0) {
finalizeMove();
return;
}

const finalDestinationId = prepareDestinationFolder(destinationFolderId, namePaths);
await processItemsMove(finalDestinationId);
await moveItemFromDialog({
finalDestinationId: destinationFolderId,
items: itemsToMove,
});
finalizeMove();
} catch (err: unknown) {
const castedError = errorService.castError(err);
Expand Down Expand Up @@ -261,11 +230,11 @@ const MoveItemsDialog = (props: MoveItemsDialogProps): JSX.Element => {
</div>
) : (
shownFolders
.sort((a, b) => a.name.localeCompare(b.name))
.toSorted((a, b) => a.name.localeCompare(b.name))
.map((folder) => {
return (
<div
className={`cursor-pointer ${
<button
className={`cursor-pointer w-full justify-between ${
destinationId === folder.uuid
? 'bg-primary/10 text-primary dark:bg-primary/20'
: 'hover:bg-gray-1 dark:hover:bg-gray-5'
Expand All @@ -274,15 +243,17 @@ const MoveItemsDialog = (props: MoveItemsDialogProps): JSX.Element => {
onClick={() => onFolderClicked(folder.uuid, folder.name)}
key={folder.id}
>
<img className="flex h-8 w-8" alt="Folder icon" src={folderImage} />
<span className="w-full flex-1 truncate text-base" title={folder.name}>
{folder.name}
</span>
<div className="flex flex-row gap-3 items-center">
<img className="flex h-8 w-8" alt="Folder icon" src={folderImage} />
<span className="w-full flex-1 truncate text-base" title={folder.name}>
{folder.name}
</span>
</div>
<CaretRight
onClick={() => onShowFolderContentClicked(folder.uuid, folder.name)}
className="h-6 w-6"
/>
</div>
</button>
);
})
)}
Expand All @@ -303,9 +274,7 @@ const MoveItemsDialog = (props: MoveItemsDialogProps): JSX.Element => {
<Button
disabled={isLoading || isDriveAndCurrentFolder}
variant="primary"
onClick={() =>
onAccept(destinationId ? destinationId : currentFolderId, currentFolderName, currentNamePaths)
}
onClick={() => onAccept(destinationId ?? currentFolderId)}
>
{!props.isTrash ? translate('actions.move') : translate('actions.restoreHere')}
</Button>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@ import replaceFileService from 'views/Drive/services/replaceFile.service';
import { Network, getEnvironmentConfig } from 'app/drive/services/network.service';
import { fileVersionsActions, fileVersionsSelectors } from 'app/store/slices/fileVersions';
import { isVersioningExtensionAllowed } from 'views/Drive/components/VersionHistory/utils';
import { checkFolderDuplicated } from 'app/store/slices/storage/folderUtils/checkFolderDuplicated';
import { getUniqueFolderName } from 'app/store/slices/storage/folderUtils/getUniqueFolderName';
import { getUniqueFilename } from 'app/store/slices/storage/fileUtils/getUniqueFilename';
import { checkDuplicatedFiles } from 'app/store/slices/storage/fileUtils/checkDuplicatedFiles';
import { MoveItemPayload } from 'app/store/slices/storage/storage.thunks/moveItemsThunk';

type NameCollisionContainerProps = {
currentFolderId: string;
Expand Down Expand Up @@ -107,25 +112,45 @@ const NameCollisionContainer: FC<NameCollisionContainerProps> = ({
dispatch(
storageThunks.moveItemsThunk({
items: itemsToMove,
destinationFolderId: moveDestinationFolderId as string,
destinationFolderId: folderId,
}),
);
};

const keepAndMoveItem = async (itemsToUpload: DriveItemData[]) => {
await dispatch(
storageThunks.renameItemsThunk({
items: itemsToUpload,
destinationFolderId: folderId,
onRenameSuccess: (itemToUpload: DriveItemData) =>
dispatch(
storageThunks.moveItemsThunk({
items: [itemToUpload],
destinationFolderId: moveDestinationFolderId as string,
}),
),
}),
);
for (const item of itemsToUpload) {
let itemParsed: MoveItemPayload;
let finalItemName = item.plainName ?? item.name;

if (item.isFolder) {
const { duplicatedFoldersResponse } = await checkFolderDuplicated([item], folderId);

finalItemName = await getUniqueFolderName(
item.plainName ?? item.name,
duplicatedFoldersResponse as DriveItemData[],
folderId,
);
itemParsed = { ...item, name: finalItemName, plain_name: finalItemName, newItemName: finalItemName };
} else {
const { duplicatedFilesResponse } = await checkDuplicatedFiles([item], folderId);

finalItemName = await getUniqueFilename(item.name, item.type, duplicatedFilesResponse, folderId);
itemParsed = {
...item,
name: finalItemName,
plainName: finalItemName,
plain_name: finalItemName,
newItemName: finalItemName,
};
}

await dispatch(
storageThunks.moveItemsThunk({
items: [itemParsed],
destinationFolderId: folderId,
}),
);
}
};

const uploadFileAndGetFileId = async (file: File, itemToReplace: DriveItemData) => {
Expand Down Expand Up @@ -230,6 +255,10 @@ const NameCollisionContainer: FC<NameCollisionContainerProps> = ({
});
};

const popMovedItemsFromTrash = (movedItems: DriveItemData[]) => {
dispatch(storageActions.popItemsToDelete(movedItems));
};

const triggerSelectedOptinsOnSubmit = async ({
operationType,
operation,
Expand All @@ -239,12 +268,14 @@ const NameCollisionContainer: FC<NameCollisionContainerProps> = ({
switch (operationType + operation) {
case 'move' + 'keep':
await keepAndMoveItem(itemsToUpload as DriveItemData[]);
popMovedItemsFromTrash(itemsToUpload as DriveItemData[]);
break;
case 'move' + 'replace':
await replaceAndMoveItem({
itemsToReplace: itemsToReplace as DriveItemData[],
itemsToMove: itemsToUpload as DriveItemData[],
});
popMovedItemsFromTrash(itemsToUpload as DriveItemData[]);
break;
case 'upload' + 'keep':
await keepAndUploadItem(itemsToUpload as (File | IRoot)[]);
Expand Down
7 changes: 6 additions & 1 deletion src/app/drive/services/file.service/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,15 @@ export function updateMetaData(
return storageClient.updateFileNameWithUUID(payload, resourcesToken);
}

export async function moveFileByUuid(fileUuid: string, destinationFolderUuid: string): Promise<StorageTypes.FileMeta> {
export async function moveFileByUuid(
fileUuid: string,
destinationFolderUuid: string,
newFileName?: string,
): Promise<StorageTypes.FileMeta> {
const storageClient = SdkFactory.getNewApiInstance().createNewStorageClient();
const payload: StorageTypes.MoveFileUuidPayload = {
destinationFolder: destinationFolderUuid,
name: newFileName,
};
return storageClient
.moveFileByUuid(fileUuid, payload)
Expand Down
2 changes: 2 additions & 0 deletions src/app/drive/services/folder.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -527,10 +527,12 @@ export const checkIfCachedSourceIsOlder = ({
export async function moveFolderByUuid(
folderUuid: string,
destinationFolderUuid: string,
newFolderName?: string,
): Promise<StorageTypes.FolderMeta> {
const storageClient = SdkFactory.getNewApiInstance().createNewStorageClient();
const payload: StorageTypes.MoveFolderUuidPayload = {
destinationFolder: destinationFolderUuid,
name: newFolderName,
};

return storageClient.moveFolderByUuid(folderUuid, payload).catch((err) => {
Expand Down
6 changes: 3 additions & 3 deletions src/app/drive/services/storage.service/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@ import { DriveFolderData, DriveItemData } from '../../types';
import fileService from '../file.service';
import folderService from '../folder.service';

export function moveItem(item: DriveItemData, destinationFolderId: string): Promise<void> {
export function moveItem(item: DriveItemData, destinationFolderId: string, newItemName?: string): Promise<void> {
return item.isFolder
? folderService.moveFolderByUuid((item as DriveFolderData).uuid, destinationFolderId).then()
: fileService.moveFileByUuid((item as DriveFileData).uuid, destinationFolderId).then();
? folderService.moveFolderByUuid((item as DriveFolderData).uuid, destinationFolderId, newItemName).then()
: fileService.moveFileByUuid((item as DriveFileData).uuid, destinationFolderId, newItemName).then();
}

const storageService = {
Expand Down
1 change: 1 addition & 0 deletions src/app/drive/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ export type DriveItemData = DriveFileData &
parent?: {
plainName: string;
status: FileStatus;
uuid: string;
};
};

Expand Down
3 changes: 2 additions & 1 deletion src/app/i18n/locales/de.json
Original file line number Diff line number Diff line change
Expand Up @@ -1440,7 +1440,8 @@
"membersUpdatedSuccessfully": "Mitglieder erfolgreich aktualisiert",
"errorModifyingStorage": "Der neue Speicherplatz ist für dieses Mitglied ungültig.",
"generalErrorWhileModifyingStorage": "Beim Ändern des Speicherplatzes ist ein Fehler aufgetreten.",
"restoreItems": "{{itemsToRecover}} verschoben nach {{destination}}",
"restoreItems": "Die Elemente wurden wiederhergestellt",
"goToDrive": "Zu Drive gehen",
"itemDeleted": "{{item}} gelöscht",
"itemsDeleted": "Dateien gelöscht",
"emailNotEmpty": "E-Mail darf nicht leer sein",
Expand Down
3 changes: 2 additions & 1 deletion src/app/i18n/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -1513,7 +1513,8 @@
"copyLink": "Shared link copied to clipboard",
"linkUpdated": "Link updated",
"itemsMovedToTrash": "{{item}} moved to trash",
"restoreItems": "{{itemsToRecover}} restored successfully",
"restoreItems": "The items have been restored",
"goToDrive": "Go to Drive",
"moveItems": "{{itemsToMove}} moved successfully",
"storageModified": "Storage modified successfully",
"membersUpdatedSuccessfully": "Members updated successfully",
Expand Down
3 changes: 2 additions & 1 deletion src/app/i18n/locales/es.json
Original file line number Diff line number Diff line change
Expand Up @@ -1476,7 +1476,8 @@
"copyLink": "Enlace copiado al portapapeles",
"linkUpdated": "Enlace actualizado",
"itemsMovedToTrash": "{{item}} movid{{s}} a la papelera",
"restoreItems": "{{itemsToRecover}} restaurad{{s}} con éxito",
"restoreItems": "Los elementos han sido restaurados",
"goToDrive": "Ir a Drive",
"storageModified": "Almacenamiento modificado con éxito",
"membersUpdatedSuccessfully": "Miembros actualizados con éxito",
"errorModifyingStorage": "El nuevo almacenamiento no es válido para este miembro.",
Expand Down
3 changes: 2 additions & 1 deletion src/app/i18n/locales/fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -1441,7 +1441,8 @@
"copyLink": "Copier le lien dans le presse-papiers",
"linkUpdated": "Lien mis à jour",
"itemsMovedToTrash": "{{item}} déplacé vers la corbeille",
"restoreItems": "{{itemsToRecover}} restauré avec succès",
"restoreItems": "Les éléments ont été restaurés",
"goToDrive": "Aller à Drive",
"storageModified": "Stockage modifié avec succès",
"membersUpdatedSuccessfully": "Membres mis à jour avec succès",
"errorModifyingStorage": "Le nouvel espace de stockage n'est pas valide pour ce membre.",
Expand Down
3 changes: 2 additions & 1 deletion src/app/i18n/locales/it.json
Original file line number Diff line number Diff line change
Expand Up @@ -1548,7 +1548,8 @@
"copyLink": "Link condiviso copiato negli appunti",
"linkUpdated": "Link aggiornato",
"itemsMovedToTrash": "{{item}} spostati nel cestino",
"restoreItems": "{{itemsToRecover}} ripristinato correttamente",
"restoreItems": "Gli elementi sono stati ripristinati",
"goToDrive": "Vai a Drive",
"storageModified": "Archiviazione modificata con successo",
"membersUpdatedSuccessfully": "Membri aggiornati con successo",
"errorModifyingStorage": "Il nuovo spazio di archiviazione non è valido per questo membro.",
Expand Down
3 changes: 2 additions & 1 deletion src/app/i18n/locales/ru.json
Original file line number Diff line number Diff line change
Expand Up @@ -1460,7 +1460,8 @@
"membersUpdatedSuccessfully": "Участники успешно обновлены",
"errorModifyingStorage": "Новый объём хранения недоступен для этого участника.",
"generalErrorWhileModifyingStorage": "Произошла ошибка при изменении объёма хранения.",
"restoreItems": "{{itemsToRecover}} успешно восстановлено",
"restoreItems": "Элементы были восстановлены",
"goToDrive": "Перейти к Drive",
"itemDeleted": "{{item}} удален",
"itemsDeleted": "Файлы удалены",
"emailNotEmpty": "Поле электронной почты не должно быть пустым",
Expand Down
3 changes: 2 additions & 1 deletion src/app/i18n/locales/tw.json
Original file line number Diff line number Diff line change
Expand Up @@ -1443,7 +1443,8 @@
"copyLink": "已複製共享鏈接到剪貼板",
"linkUpdated": "鏈接已更新",
"itemsMovedToTrash": "{{item}} 已移到垃圾桶",
"restoreItems": "{{itemsToRecover}} 成功還原",
"restoreItems": "項目已成功還原",
"goToDrive": "前往 Drive",
"storageModified": "儲存空間修改成功",
"membersUpdatedSuccessfully": "成員更新成功",
"errorModifyingStorage": "新存儲空間對此成員無效。",
Expand Down
3 changes: 2 additions & 1 deletion src/app/i18n/locales/zh.json
Original file line number Diff line number Diff line change
Expand Up @@ -1483,7 +1483,8 @@
"errorModifyingStorage": "新存储空间对该成员无效。",
"generalErrorWhileModifyingStorage": "修改存储时出错。",
"moveItems": "{{itemsToMove}} 成功移动",
"restoreItems": "{{itemsToRecover}} 成功恢复",
"restoreItems": "项目已成功恢复",
"goToDrive": "前往 Drive",
"itemDeleted": "{{item}} 已删除",
"itemsDeleted": "文件已删除",
"emailNotEmpty": "电子邮件不能为空",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ export const checkDuplicatedFiles = async (
duplicatedFilesResponse: [],
filesWithDuplicates: [],
filesWithoutDuplicates: files,
} as DuplicatedFilesResult;
};
}

const parsedFiles = files.map(parseFile);
Expand Down
Loading
Loading