Skip to content
Merged
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
1 change: 1 addition & 0 deletions src/app/drive/services/downloadManager.service.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -879,6 +879,7 @@ describe('downloadManagerService', () => {
updateProgressCallback: mockUpdateProgress,
abortController: mockTask.abortController,
sharingOptions: mockTask.credentials,
downloadName: mockTask.options.downloadName,
});
});
});
Expand Down
24 changes: 16 additions & 8 deletions src/app/drive/services/downloadManager.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ export type DownloadItem = {
downloadOptions?: {
areSharedItems?: boolean;
showErrors?: boolean;
downloadName?: string;
};
createFoldersIterator?: FolderIterator | SharedFolderIterator;
createFilesIterator?: FileIterator | SharedFileIterator;
Expand Down Expand Up @@ -90,6 +91,13 @@ export type DownloadTask = {
export class DownloadManagerService {
public static readonly instance: DownloadManagerService = new DownloadManagerService();

private getSingleItemName(item: DownloadItem['payload'][0]): string {
if (item.isFolder) {
return item.name;
}
return item.type ? `${item.name}.${item.type}` : item.name;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will the name never include the extension?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, the name/plainName does not include the extension, it's stored separately in the type field.

}

readonly getDownloadCredentialsFromWorkspace = (
selectedWorkspace: WorkspaceData | null,
workspaceCredentials: WorkspaceCredentialsDetails | null,
Expand Down Expand Up @@ -117,14 +125,11 @@ export class DownloadManagerService {
const abort = () => Promise.resolve(uploadFolderAbortController.abort('Download cancelled'));

const formattedDate = date.format(new Date(), 'YYYY-MM-DD_HHmmss');
let downloadName = `Internxt (${formattedDate})`;
if (itemsPayload.length === 1) {
const item = itemsPayload[0];
if (itemsPayload[0].isFolder) {
downloadName = item.name;
} else {
downloadName = item.type ? `${item.name}.${item.type}` : item.name;
}
let downloadName = downloadItem.downloadOptions?.downloadName;

if (!downloadName) {
downloadName =
itemsPayload.length === 1 ? this.getSingleItemName(itemsPayload[0]) : `Internxt (${formattedDate})`;
}

let taskId = downloadItem.taskId;
Expand Down Expand Up @@ -288,6 +293,7 @@ export class DownloadManagerService {
updateProgressCallback,
abortController,
sharingOptions: credentials,
downloadName: options.downloadName,
});

console.timeEnd(`download-file-${file.uuid}`);
Expand Down Expand Up @@ -493,6 +499,7 @@ export class DownloadManagerService {
updateProgressCallback: (progress: number) => void;
abortController?: AbortController;
sharingOptions: { credentials: { user: string; pass: string }; mnemonic: string };
downloadName?: string;
}) => {
const isBrave = !!(navigator.brave && (await navigator.brave.isBrave()));

Expand All @@ -514,6 +521,7 @@ export class DownloadManagerService {
itemData: payload.file,
updateProgressCallback: payload.updateProgressCallback,
abortController: payload.abortController,
downloadName: payload.downloadName,
});
};
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ interface HandleWorkerMessagesPayload {
abortController?: AbortController;
itemData: DriveFileData;
updateProgressCallback: (progress: number) => void;
downloadName?: string;
}

interface HandleMessagesPayload {
Expand All @@ -37,9 +38,10 @@ export class DownloadWorkerHandler {
abortController,
itemData,
updateProgressCallback,
downloadName,
}: HandleWorkerMessagesPayload) {
const fileName = itemData.plainName ?? itemData.name;
const completeFilename = itemData.type ? `${fileName}.${itemData.type}` : fileName;
const completeFilename = downloadName || (itemData.type ? `${fileName}.${itemData.type}` : fileName);
const downloadId = itemData.fileId;
const fileSize = itemData.size;

Expand Down
8 changes: 7 additions & 1 deletion src/app/i18n/locales/de.json
Original file line number Diff line number Diff line change
Expand Up @@ -808,7 +808,13 @@
"restoreSuccess": "Version erfolgreich wiederhergestellt",
"restoreError": "Fehler beim Wiederherstellen der Version",
"deleteSuccess": "Version erfolgreich gelöscht",
"deleteError": "Fehler beim Löschen der Version"
"deleteError": "Fehler beim Löschen der Version",
"lockedFeature": {
"title": "Gesperrte Funktion",
"description": "Stellen Sie frühere Versionen Ihrer Dateien wieder her und verfolgen Sie Änderungen im Laufe der Zeit.",
"supportedFormats": "Verfügbar für PDF-, Word-, Excel- und CSV-Dateien in kostenpflichtigen Plänen.",
"upgradeButton": "Upgrade"
}
},
"shareModal": {
"title": "Aktie \"{{name}}\"",
Expand Down
8 changes: 7 additions & 1 deletion src/app/i18n/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -905,7 +905,13 @@
"restoreSuccess": "Version restored successfully",
"restoreError": "Failed to restore version",
"deleteSuccess": "Version deleted successfully",
"deleteError": "Failed to delete version"
"deleteError": "Failed to delete version",
"lockedFeature": {
"title": "Locked feature",
"description": "Restore previous versions of your files and track changes over time.",
"supportedFormats": "Available for PDF, Word, Excel, and CSV files in paid plans.",
"upgradeButton": "Upgrade"
}
},
"shareModal": {
"title": "Share \"{{name}}\"",
Expand Down
8 changes: 7 additions & 1 deletion src/app/i18n/locales/es.json
Original file line number Diff line number Diff line change
Expand Up @@ -887,7 +887,13 @@
"restoreSuccess": "Versión restaurada exitosamente",
"restoreError": "Error al restaurar la versión",
"deleteSuccess": "Versión eliminada exitosamente",
"deleteError": "Error al eliminar la versión"
"deleteError": "Error al eliminar la versión",
"lockedFeature": {
"title": "Función bloqueada",
"description": "Restaura versiones anteriores de tus archivos y realiza un seguimiento de los cambios a lo largo del tiempo.",
"supportedFormats": "Disponible para archivos PDF, Word, Excel y CSV en planes de pago.",
"upgradeButton": "Mejorar plan"
}
},
"shareModal": {
"title": "Compartir \"{{name}}\"",
Expand Down
8 changes: 7 additions & 1 deletion src/app/i18n/locales/fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -829,7 +829,13 @@
"restoreSuccess": "Version restaurée avec succès",
"restoreError": "Échec de la restauration de la version",
"deleteSuccess": "Version supprimée avec succès",
"deleteError": "Échec de la suppression de la version"
"deleteError": "Échec de la suppression de la version",
"lockedFeature": {
"title": "Fonctionnalité verrouillée",
"description": "Restaurez les versions précédentes de vos fichiers et suivez les modifications au fil du temps.",
"supportedFormats": "Disponible pour les fichiers PDF, Word, Excel et CSV dans les forfaits payants.",
"upgradeButton": "Mettre à niveau"
}
},
"newFolderModal": {
"title": "Nouveau dossier",
Expand Down
8 changes: 7 additions & 1 deletion src/app/i18n/locales/it.json
Original file line number Diff line number Diff line change
Expand Up @@ -941,7 +941,13 @@
"restoreSuccess": "Versione ripristinata con successo",
"restoreError": "Impossibile ripristinare la versione",
"deleteSuccess": "Versione eliminata con successo",
"deleteError": "Impossibile eliminare la versione"
"deleteError": "Impossibile eliminare la versione",
"lockedFeature": {
"title": "Funzione bloccata",
"description": "Ripristina le versioni precedenti dei tuoi file e monitora le modifiche nel tempo.",
"supportedFormats": "Disponibile per file PDF, Word, Excel e CSV nei piani a pagamento.",
"upgradeButton": "Aggiorna"
}
},
"shareModal": {
"title": "Condividi \"{{name}}\"",
Expand Down
8 changes: 7 additions & 1 deletion src/app/i18n/locales/ru.json
Original file line number Diff line number Diff line change
Expand Up @@ -848,7 +848,13 @@
"restoreSuccess": "Версия успешно восстановлена",
"restoreError": "Не удалось восстановить версию",
"deleteSuccess": "Версия успешно удалена",
"deleteError": "Не удалось удалить версию"
"deleteError": "Не удалось удалить версию",
"lockedFeature": {
"title": "Заблокированная функция",
"description": "Восстанавливайте предыдущие версии файлов и отслеживайте изменения со временем.",
"supportedFormats": "Доступно для файлов PDF, Word, Excel и CSV в платных тарифах.",
"upgradeButton": "Обновить"
}
},
"shareModal": {
"title": "Поделиться \"{{name}}\"",
Expand Down
8 changes: 7 additions & 1 deletion src/app/i18n/locales/tw.json
Original file line number Diff line number Diff line change
Expand Up @@ -835,7 +835,13 @@
"restoreSuccess": "版本復原成功",
"restoreError": "復原版本失敗",
"deleteSuccess": "版本刪除成功",
"deleteError": "刪除版本失敗"
"deleteError": "刪除版本失敗",
"lockedFeature": {
"title": "功能已鎖定",
"description": "復原檔案的先前版本並追蹤隨時間的變化。",
"supportedFormats": "適用於付費方案中的PDF、Word、Excel和CSV檔案。",
"upgradeButton": "升級"
}
},
"shareModal": {
"title": "分享“{{name}}”",
Expand Down
8 changes: 7 additions & 1 deletion src/app/i18n/locales/zh.json
Original file line number Diff line number Diff line change
Expand Up @@ -871,7 +871,13 @@
"restoreSuccess": "版本恢复成功",
"restoreError": "恢复版本失败",
"deleteSuccess": "版本删除成功",
"deleteError": "删除版本失败"
"deleteError": "删除版本失败",
"lockedFeature": {
"title": "功能已锁定",
"description": "恢复文件的以前版本并跟踪随时间的变化。",
"supportedFormats": "适用于付费计划中的PDF、Word、Excel和CSV文件。",
"upgradeButton": "升级"
}
},
"shareModal": {
"title": "分享 \"{{name}}\"",
Expand Down
3 changes: 3 additions & 0 deletions src/app/store/slices/fileVersions/fileVersions.selectors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ const fileVersionsSelectors = {
getLimits(state: RootState): FileLimitsResponse | null {
return state.fileVersions.limits;
},
isLimitsLoading(state: RootState): boolean {
return state.fileVersions.isLimitsLoading;
},
getVersionsByFileId(state: RootState, fileId: NonNullable<FileVersion['fileId']>): FileVersion[] {
return state.fileVersions.versionsByFileId[fileId] ?? [];
},
Expand Down
18 changes: 9 additions & 9 deletions src/app/store/slices/fileVersions/index.test.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { beforeEach, describe, expect, it, vi } from 'vitest';
import { FileVersion, FileLimitsResponse } from '@internxt/sdk/dist/drive/storage/types';
import fileVersionService from 'views/Drive/components/VersionHistory/services/fileVersion.service';
import fileVersionService from 'views/Drive/services/fileVersion.service';
import { fileVersionsActions, fileVersionsReducer, fetchFileVersionsThunk, fetchVersionLimitsThunk } from './index';
import { RootState } from '../..';

vi.mock('views/Drive/components/VersionHistory/services/fileVersion.service', () => ({
vi.mock('views/Drive/services/fileVersion.service', () => ({
default: {
getFileVersions: vi.fn(),
getLimits: vi.fn(),
Expand Down Expand Up @@ -54,11 +54,11 @@ describe('File history state', () => {
const getLimitsSpy = vi.spyOn(fileVersionService, 'getLimits').mockResolvedValueOnce(limits);
const dispatch = vi.fn();

const action = await fetchVersionLimitsThunk()(dispatch, () => ({}) as RootState, undefined);
const action = await fetchVersionLimitsThunk({})(dispatch, () => ({}) as RootState, undefined);

expect(getLimitsSpy).toHaveBeenCalled();
expect(action.meta.requestStatus).toBe('fulfilled');
expect(action.payload).toBe(limits);
expect(action.payload).toEqual({ limits, isSilent: false });
});

it('when version limits fail to load, then the error is reported', async () => {
Expand All @@ -67,7 +67,7 @@ describe('File history state', () => {
.mockRejectedValueOnce(new Error('limits unavailable'));
const dispatch = vi.fn();

const action = await fetchVersionLimitsThunk()(dispatch, () => ({}) as RootState, undefined);
const action = await fetchVersionLimitsThunk({})(dispatch, () => ({}) as RootState, undefined);

expect(getLimitsSpy).toHaveBeenCalled();
expect(action.meta.requestStatus).toBe('rejected');
Expand Down Expand Up @@ -138,22 +138,22 @@ describe('File history state', () => {
});

it('when limits are loading or finished, then the loading state updates', () => {
const pendingState = fileVersionsReducer(undefined, fetchVersionLimitsThunk.pending('', undefined));
const pendingState = fileVersionsReducer(undefined, fetchVersionLimitsThunk.pending('', {}));
expect(pendingState.isLimitsLoading).toBe(true);

const limits: FileLimitsResponse = {
versioning: { enabled: true, maxFileSize: 0, retentionDays: 0, maxVersions: 0 },
};
const fulfilledState = fileVersionsReducer(
pendingState,
fetchVersionLimitsThunk.fulfilled(limits, '', undefined),
fetchVersionLimitsThunk.fulfilled({ limits, isSilent: false }, '', {}),
);
expect(fulfilledState.isLimitsLoading).toBe(false);
expect(fulfilledState.limits).toBe(limits);
expect(fulfilledState.limits).toEqual(limits);

const rejectedState = fileVersionsReducer(
pendingState,
fetchVersionLimitsThunk.rejected(new Error('err'), '', undefined),
fetchVersionLimitsThunk.rejected(new Error('err'), '', {}),
);
expect(rejectedState.isLimitsLoading).toBe(false);
});
Expand Down
33 changes: 21 additions & 12 deletions src/app/store/slices/fileVersions/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import { createSlice, PayloadAction, createAsyncThunk } from '@reduxjs/toolkit';
import { FileVersion, FileLimitsResponse } from '@internxt/sdk/dist/drive/storage/types';
import fileVersionService from 'views/Drive/components/VersionHistory/services/fileVersion.service';
import fileVersionService from 'views/Drive/services/fileVersion.service';

export const VERSION_LIMITS_POLL_MAX_ATTEMPTS = 3;
export const VERSION_LIMITS_POLL_DELAYS = [2000, 4000, 6000];

interface FileVersionsState {
versionsByFileId: Record<NonNullable<FileVersion['fileId']>, FileVersion[]>;
Expand Down Expand Up @@ -30,14 +33,17 @@ export const fetchFileVersionsThunk = createAsyncThunk(
},
);

export const fetchVersionLimitsThunk = createAsyncThunk('fileVersions/fetchLimits', async (_, { rejectWithValue }) => {
try {
const limits = await fileVersionService.getLimits();
return limits;
} catch (error) {
return rejectWithValue((error as Error).message);
}
});
export const fetchVersionLimitsThunk = createAsyncThunk(
'fileVersions/fetchLimits',
async ({ isSilent = false }: { isSilent?: boolean } = {}, { rejectWithValue }) => {
try {
const limits = await fileVersionService.getLimits();
return { limits, isSilent };
} catch (error) {
return rejectWithValue((error as Error).message);
}
},
);

export const fileVersionsSlice = createSlice({
name: 'fileVersions',
Expand Down Expand Up @@ -75,11 +81,14 @@ export const fileVersionsSlice = createSlice({
state.isLoadingByFileId[action.meta.arg] = false;
state.errorsByFileId[action.meta.arg] = action.payload as string;
})
.addCase(fetchVersionLimitsThunk.pending, (state) => {
state.isLimitsLoading = true;
.addCase(fetchVersionLimitsThunk.pending, (state, action) => {
const isSilent = action.meta.arg?.isSilent || false;
if (!isSilent) {
state.isLimitsLoading = true;
}
})
.addCase(fetchVersionLimitsThunk.fulfilled, (state, action) => {
state.limits = action.payload;
state.limits = action.payload.limits;
state.isLimitsLoading = false;
})
.addCase(fetchVersionLimitsThunk.rejected, (state) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ import {
} from './DriveItemContextMenu';
import { List } from '@internxt/ui';
import { DownloadManager } from 'app/network/DownloadManager';
import { useVersionHistoryMenuConfig } from '../../VersionHistory/hooks';
import { useVersionHistoryMenuConfig } from 'views/Drive/hooks/useVersionHistoryMenuConfig';

interface DriveExplorerListProps {
folderId: string;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,13 +106,12 @@ const getVersionHistoryMenuItem = (
): MenuItemType<DriveItemData> => {
const isLocked = config?.isLocked ?? false;
const isExtensionAllowed = config?.isExtensionAllowed ?? true;
const onUpgradeClick = config?.onUpgradeClick;

if (isLocked) {
return {
name: t('drive.dropdown.versionHistory') as string,
icon: LockSimple,
action: onUpgradeClick,
action: viewVersionHistory,
disabled: () => false,
node: (
<div
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ import {
} from './DriveItemContextMenu';
import workspacesSelectors from 'app/store/slices/workspaces/workspaces.selectors';
import { DownloadManager } from 'app/network/DownloadManager';
import { useVersionHistoryMenuConfig } from '../../VersionHistory/hooks';
import { useVersionHistoryMenuConfig } from 'views/Drive/hooks/useVersionHistoryMenuConfig';

const DriveTopBarActions = ({
selectedItems,
Expand Down Expand Up @@ -102,10 +102,6 @@ const DriveTopBarActions = ({
};

const onViewVersionHistoryButtonClicked = (): void => {
if (versionHistoryMenuConfig.locked) {
versionHistoryMenuConfig.onLockedClick?.();
return;
}
dispatch(uiActions.setVersionHistoryItem(selectedItems[0]));
dispatch(uiActions.setIsVersionHistorySidebarOpen(true));
};
Expand Down
Loading
Loading