From 01eb6249b233401af272fb26698337cf8cd6488e Mon Sep 17 00:00:00 2001 From: joan vicens Date: Wed, 10 Jan 2024 10:15:23 +0100 Subject: [PATCH 1/4] fix: ignore duplicated nodes --- .../items/application/Traverser.ts | 70 +++++++++---------- .../virtual-drive/items/domain/FolderNode.ts | 3 +- 2 files changed, 37 insertions(+), 36 deletions(-) diff --git a/src/context/virtual-drive/items/application/Traverser.ts b/src/context/virtual-drive/items/application/Traverser.ts index 53c964a71..681bf8a02 100644 --- a/src/context/virtual-drive/items/application/Traverser.ts +++ b/src/context/virtual-drive/items/application/Traverser.ts @@ -1,14 +1,5 @@ +import * as Sentry from '@sentry/electron/renderer'; import Logger from 'electron-log'; -import { - FolderStatus, - FolderStatuses, -} from '../../folders/domain/FolderStatus'; -import { Folder } from '../../folders/domain/Folder'; -import { EitherTransformer } from '../../shared/application/EitherTransformer'; -import { createFileFromServerFile } from '../../files/application/FileCreatorFromServerFile'; -import { createFolderFromServerFolder } from '../../folders/application/FolderCreatorFromServerFolder'; -import { NameDecrypt } from '../domain/NameDecrypt'; -import { Tree } from '../domain/Tree'; import { ServerFile, ServerFileStatus, @@ -17,6 +8,16 @@ import { ServerFolder, ServerFolderStatus, } from '../../../shared/domain/ServerFolder'; +import { createFileFromServerFile } from '../../files/application/FileCreatorFromServerFile'; +import { createFolderFromServerFolder } from '../../folders/application/FolderCreatorFromServerFolder'; +import { Folder } from '../../folders/domain/Folder'; +import { + FolderStatus, + FolderStatuses, +} from '../../folders/domain/FolderStatus'; +import { EitherTransformer } from '../../shared/application/EitherTransformer'; +import { NameDecrypt } from '../domain/NameDecrypt'; +import { Tree } from '../domain/Tree'; type Items = { files: Array; @@ -69,17 +70,17 @@ export class Traverser { return folder.parentId === currentFolder.id; }); - filesInThisFolder.forEach((file) => { - if (!this.fileStatusesToFilter.includes(file.status)) { + filesInThisFolder.forEach((serverFile) => { + if (!this.fileStatusesToFilter.includes(serverFile.status)) { return; } const decryptedName = this.decrypt.decryptName( - file.name, - file.folderId.toString(), - file.encrypt_version + serverFile.name, + serverFile.folderId.toString(), + serverFile.encrypt_version ); - const extensionToAdd = file.type ? `.${file.type}` : ''; + const extensionToAdd = serverFile.type ? `.${serverFile.type}` : ''; const relativeFilePath = `${currentFolder.path}/${decryptedName}${extensionToAdd}`.replaceAll( @@ -87,17 +88,16 @@ export class Traverser { '/' ); - EitherTransformer.handleWithEither(() => - createFileFromServerFile(file, relativeFilePath) - ).fold( - (error) => { - Logger.warn( - `[Traverser] File with path ${relativeFilePath} could not be created: `, - error - ); + EitherTransformer.handleWithEither(() => { + const file = createFileFromServerFile(serverFile, relativeFilePath); + tree.addFile(currentFolder, file); + }).fold( + (error): void => { + Logger.warn('[Traverser] Error adding file:', error); + Sentry.captureException(error); }, - (file) => { - tree.addFile(currentFolder, file); + () => { + // no-op } ); }); @@ -118,18 +118,18 @@ export class Traverser { return; } - EitherTransformer.handleWithEither(() => - createFolderFromServerFolder(serverFolder, name) - ).fold( + EitherTransformer.handleWithEither(() => { + const folder = createFolderFromServerFolder(serverFolder, name); + + tree.addFolder(currentFolder, folder); + + return folder; + }).fold( (error) => { - Logger.warn( - `[Traverser] Folder with path ${name} could not be created: `, - error - ); + Logger.warn(`[Traverser] Error adding folder: ${error} `); + Sentry.captureException(error); }, (folder) => { - tree.addFolder(currentFolder, folder); - if (folder.hasStatus(FolderStatuses.EXISTS)) { // The folders and the files inside trashed or deleted folders // will have the status "EXISTS", to avoid filtering witch folders and files diff --git a/src/context/virtual-drive/items/domain/FolderNode.ts b/src/context/virtual-drive/items/domain/FolderNode.ts index f14c98718..3a2565cfd 100644 --- a/src/context/virtual-drive/items/domain/FolderNode.ts +++ b/src/context/virtual-drive/items/domain/FolderNode.ts @@ -1,6 +1,7 @@ import { Folder } from '../../folders/domain/Folder'; import { FileNode } from './FileNode'; import { Node } from './Node'; + export class FolderNode { private constructor( public readonly folder: Folder, @@ -17,7 +18,7 @@ export class FolderNode { addChild(node: Node): void { if (this.children.has(node.id)) { - throw new Error('Child already exists'); + throw new Error(`Duplicated node detected: ${node.id}`); } this.children.set(node.id, node); From e674d84f00d7a322d21739a9e95d51282c04530f Mon Sep 17 00:00:00 2001 From: joan vicens Date: Wed, 10 Jan 2024 12:07:48 +0100 Subject: [PATCH 2/4] feat: comunicate the traverser error to user --- .../background-processes/process-issues.ts | 10 +++++++ src/apps/main/fordwardToWindows.ts | 8 +++++ src/apps/renderer/localize/locales/en.json | 8 +++-- src/apps/renderer/localize/locales/es.json | 6 ++-- src/apps/renderer/localize/locales/fr.json | 6 ++-- src/apps/renderer/messages/process-error.ts | 2 ++ src/apps/renderer/pages/Widget/Item.tsx | 9 ++++-- src/apps/shared/IPC/events/sync-engine.ts | 4 +++ src/apps/shared/types.ts | 8 +++-- .../dependency-injection/common/traverser.ts | 7 ++++- .../dependency-injection/items/builder.ts | 2 ++ .../items/application/Traverser.ts | 29 +++++++++++++++++-- 12 files changed, 83 insertions(+), 16 deletions(-) diff --git a/src/apps/main/background-processes/process-issues.ts b/src/apps/main/background-processes/process-issues.ts index f62c58376..fbbcd4570 100644 --- a/src/apps/main/background-processes/process-issues.ts +++ b/src/apps/main/background-processes/process-issues.ts @@ -72,6 +72,16 @@ ipcMain.on('SYNC_INFO_UPDATE', (_, payload: ProcessInfoUpdatePayload) => { } }); +ipcMain.on('SYNC_PROBLEM', (_, payload) => { + addProcessIssue({ + action: 'GENERATE_TREE', + process: 'SYNC', + errorName: 'DUPLICATED_NODE', + kind: 'LOCAL', + name: payload.additionalData.name, + }); +}); + ipcMain.on('BACKUP_ISSUE', (_, issue: ProcessIssue) => { addProcessIssue(issue); }); diff --git a/src/apps/main/fordwardToWindows.ts b/src/apps/main/fordwardToWindows.ts index b0cc9f986..a592cef9a 100644 --- a/src/apps/main/fordwardToWindows.ts +++ b/src/apps/main/fordwardToWindows.ts @@ -1,5 +1,6 @@ import { broadcastToWindows } from './windows'; import { ipcMainDrive } from './ipcs/mainDrive'; +import { ipcMainSyncEngine } from './ipcs/ipcMainSyncEngine'; import { FileErrorInfo } from '../shared/IPC/events/drive'; ipcMainDrive.on('FILE_DELETED', (_, payload) => { @@ -130,3 +131,10 @@ ipcMainDrive.on('FILE_DELETION_ERROR', (_, payload: FileErrorInfo) => { name: nameWithExtension, }); }); + +ipcMainSyncEngine.on('SYNC_PROBLEM', (_, payload) => { + broadcastToWindows('sync-info-update', { + action: 'SYNC_PROBLEM', + name: payload.additionalData.name, + }); +}); diff --git a/src/apps/renderer/localize/locales/en.json b/src/apps/renderer/localize/locales/en.json index 95b1a0527..228ebbdbe 100644 --- a/src/apps/renderer/localize/locales/en.json +++ b/src/apps/renderer/localize/locales/en.json @@ -321,7 +321,8 @@ "no-permission": "Insufficient permissions", "file-does-not-exist": "File doesn't exist", "file-too-big": "Max upload size is 20GB. Please try smaller files.", - "file-non-extension": "Files without extensions are not supported." + "file-non-extension": "Files without extensions are not supported.", + "duplicated-node": "There is a conflict with the element" }, "error-messages": { "no-internet": "Looks like you are not connected to the internet, we'll try again later", @@ -334,9 +335,10 @@ "unknown": "An unknown error ocurred while trying to sync your files", "empty-file": "We don't support files with a size of 0 bytes because of our processes of sharding and encryption", "bad-response": "We got a bad response from our servers while processing this file. Please, try starting the sync process again.", - "file-does-not-exist": "This file was present when we compared your local folder with your Internxt drive but dissapeared when we tried to access it. If you deleted this file, don't worry, this error should dissapear the next time the sync process starts.", + "file-does-not-exist": "This file was present when we compared your local folder with your Internxt drive but disappeared when we tried to access it. If you deleted this file, don't worry, this error should dissapear the next time the sync process starts.", "file-too-big": "Max upload size is 20GB. Please try smaller files.", - "file-non-extension": "Files without extensions are not supported. Not synchronized." + "file-non-extension": "Files without extensions are not supported. Not synchronized.", + "duplicated-node": "There are two elements (file or folder) with the same name on a folder. Rename one of them to sync them both" }, "report-modal": { "actions": { diff --git a/src/apps/renderer/localize/locales/es.json b/src/apps/renderer/localize/locales/es.json index 99c0e4fde..e66dd663f 100644 --- a/src/apps/renderer/localize/locales/es.json +++ b/src/apps/renderer/localize/locales/es.json @@ -320,7 +320,8 @@ "no-permission": "Permisos insuficientes", "file-does-not-exist": "El archivo no existe", "file-too-big": "El tamaño máximo de carga es de 20GB. Por favor, intenta con archivos más pequeños.", - "file-non-extension": "Archivos sin extensión no son soportados" + "file-non-extension": "Archivos sin extensión no son soportados", + "duplicated-node": "Hay un conflicto con el elemento" }, "error-messages": { "no-internet": "No estás conectado a Internet, lo intentaremos más tarde", @@ -335,7 +336,8 @@ "bad-response": "Error de servidor al procesar este archivo. Por favor, intente iniciar de nuevo el proceso de sincronización", "file-does-not-exist": "Este archivo estaba presente cuando comparamos su carpeta local con su unidad Internxt, pero desapareció cuando intentamos acceder a él. Si has eliminado este archivo, no te preocupes, este error debería desaparecer la próxima vez que se inicie el proceso de sincronización", "file-too-big": "El tamaño máximo de carga es de 20GB. Por favor, intenta con archivos más pequeños.", - "file-non-extension": "Los archivos sin extensiones no son soportados. No sincronizado" + "file-non-extension": "Los archivos sin extensiones no son soportados. No sincronizado", + "duplicated-node": "Hay dos elementos (archivo o carpeta) con el mismo nombre en una carpeta. Cambia el nombre de uno de ellos para sincronizar ambos." }, "report-modal": { "actions": { diff --git a/src/apps/renderer/localize/locales/fr.json b/src/apps/renderer/localize/locales/fr.json index d34615e7b..b57c8821c 100644 --- a/src/apps/renderer/localize/locales/fr.json +++ b/src/apps/renderer/localize/locales/fr.json @@ -314,7 +314,8 @@ "no-internet-connection": "Pas de connexion internet", "no-permission": "Permissions insuffisantes", "file-does-not-exist": "Le fichier n'existe pas", - "file-too-big": "La taille maximale de téléchargement est de 20 GB. Veuillez essayer des fichiers plus petits." + "file-too-big": "La taille maximale de téléchargement est de 20 GB. Veuillez essayer des fichiers plus petits.", + "duplicated-node": "Il y a un conflit avec l'élément." }, "error-messages": { "no-internet": "Il semble que vous ne soyez pas connecté à l'internet, nous réessayerons plus tard", @@ -329,7 +330,8 @@ "bad-response": "Nous avons reçu une mauvaise réponse de nos serveurs lors du traitement de ce fichier. Veuillez essayer de relancer le processus de synchronisation.", "file-does-not-exist": "Ce fichier était présent lorsque nous avons comparé votre dossier local avec votre disque interne, mais il a disparu lorsque nous avons essayé d'y accéder. Si vous avez supprimé ce fichier, ne vous inquiétez pas, cette erreur devrait disparaître au prochain démarrage du processus de synchronisation.", "file-too-big": "La taille maximale de téléchargement est de 20 GB. Veuillez essayer des fichiers plus petits.", - "file-non-extension": "Les archives sans extensions ne sont pas supportées. Non synchronisées" + "file-non-extension": "Les archives sans extensions ne sont pas supportées. Non synchronisées", + "duplicated-node": "Il y a deux éléments (fichier ou dossier) avec le même nom dans un dossier. Renommez l'un d'eux pour les synchroniser tous les deux." }, "report-modal": { "actions": { diff --git a/src/apps/renderer/messages/process-error.ts b/src/apps/renderer/messages/process-error.ts index 34df86b4a..d381f4d8c 100644 --- a/src/apps/renderer/messages/process-error.ts +++ b/src/apps/renderer/messages/process-error.ts @@ -12,6 +12,7 @@ export const shortMessages: ProcessErrorMessages = { UNKNOWN: 'issues.short-error-messages.unknown', FILE_TOO_BIG: 'issues.short-error-messages.file-too-big', FILE_NON_EXTENSION: 'issues.short-error-messages.file-non-extension', + DUPLICATED_NODE: 'issues.short-error-messages.duplicated-node', }; export const longMessages: ProcessErrorMessages = { @@ -25,4 +26,5 @@ export const longMessages: ProcessErrorMessages = { UNKNOWN: 'issues.error-messages.unknown', FILE_TOO_BIG: 'issues.error-messages.file-too-big', FILE_NON_EXTENSION: 'issues.error-messages.file-non-extension', + DUPLICATED_NODE: 'issues.error-messages.duplicated-node', }; diff --git a/src/apps/renderer/pages/Widget/Item.tsx b/src/apps/renderer/pages/Widget/Item.tsx index 5bd6f9ab8..f1397d12a 100644 --- a/src/apps/renderer/pages/Widget/Item.tsx +++ b/src/apps/renderer/pages/Widget/Item.tsx @@ -68,7 +68,8 @@ export function Item({ action === 'DOWNLOAD_ERROR' || action === 'UPLOAD_ERROR' || action === 'RENAME_ERROR' || - action === 'METADATA_READ_ERROR') + action === 'METADATA_READ_ERROR' || + action === 'GENERATE_TREE') ? 'text-red' : undefined }`} @@ -78,7 +79,8 @@ export function Item({ action === 'DOWNLOAD_ERROR' || action === 'UPLOAD_ERROR' || action === 'RENAME_ERROR' || - action === 'METADATA_READ_ERROR') + action === 'METADATA_READ_ERROR' || + action === 'GENERATE_TREE') ? description : undefined } @@ -123,7 +125,8 @@ export function Item({ action === 'DOWNLOAD_ERROR' || action === 'UPLOAD_ERROR' || action === 'RENAME_ERROR' || - action === 'METADATA_READ_ERROR') && ( + action === 'METADATA_READ_ERROR' || + action === 'GENERATE_TREE') && ( )} diff --git a/src/apps/shared/IPC/events/sync-engine.ts b/src/apps/shared/IPC/events/sync-engine.ts index bf09401ed..2b9494796 100644 --- a/src/apps/shared/IPC/events/sync-engine.ts +++ b/src/apps/shared/IPC/events/sync-engine.ts @@ -128,6 +128,10 @@ export type SyncEngineInvocableFunctions = { // TODO: change how errors are reported to the ui export type ProcessInfoUpdate = { SYNC_INFO_UPDATE: (payload: ProcessInfoUpdatePayload) => void; + SYNC_PROBLEM: (payload: { + key: string; + additionalData: Record; + }) => void; }; export type FromProcess = FilesEvents & diff --git a/src/apps/shared/types.ts b/src/apps/shared/types.ts index 8c204661b..d77562c62 100644 --- a/src/apps/shared/types.ts +++ b/src/apps/shared/types.ts @@ -149,7 +149,10 @@ export type ProcessErrorName = | 'FILE_NON_EXTENSION' // Unknown error - | 'UNKNOWN'; + | 'UNKNOWN' + + // Duplicated node path + | 'DUPLICATED_NODE'; export class ProcessError extends Error { details: ErrorDetails; @@ -213,7 +216,8 @@ export type ProcessIssue = ProcessInfoBase & { | 'DOWNLOAD_ERROR' | 'RENAME_ERROR' | 'DELETE_ERROR' - | 'METADATA_READ_ERROR'; + | 'METADATA_READ_ERROR' + | 'GENERATE_TREE'; errorName: ProcessErrorName; process: 'SYNC' | 'BACKUPS'; diff --git a/src/apps/sync-engine/dependency-injection/common/traverser.ts b/src/apps/sync-engine/dependency-injection/common/traverser.ts index b25de6491..be17a4e0c 100644 --- a/src/apps/sync-engine/dependency-injection/common/traverser.ts +++ b/src/apps/sync-engine/dependency-injection/common/traverser.ts @@ -1,6 +1,7 @@ import crypt from '../../../../context/shared/infrastructure/crypt'; import { Traverser } from '../../../../context/virtual-drive/items/application/Traverser'; import { DependencyInjectionUserProvider } from './user'; +import { ipcRendererSyncEngine } from '../../ipcRendererSyncEngine'; export class DependencyInjectionTraverserProvider { private static traverser: Traverser; @@ -12,7 +13,11 @@ export class DependencyInjectionTraverserProvider { const user = DependencyInjectionUserProvider.get(); - const traverser = Traverser.existingItems(crypt, user.root_folder_id); + const traverser = Traverser.existingItems( + crypt, + ipcRendererSyncEngine, + user.root_folder_id + ); DependencyInjectionTraverserProvider.traverser = traverser; diff --git a/src/apps/sync-engine/dependency-injection/items/builder.ts b/src/apps/sync-engine/dependency-injection/items/builder.ts index c6f66a759..20a7c7ffd 100644 --- a/src/apps/sync-engine/dependency-injection/items/builder.ts +++ b/src/apps/sync-engine/dependency-injection/items/builder.ts @@ -19,10 +19,12 @@ export function buildItemsContainer(): ItemsContainer { const existingItemsTraverser = Traverser.existingItems( nameDecryptor, + ipcRendererSyncEngine, user.root_folder_id ); const allStatusesTraverser = Traverser.allItems( nameDecryptor, + ipcRendererSyncEngine, user.root_folder_id ); const treeBuilder = new TreeBuilder( diff --git a/src/context/virtual-drive/items/application/Traverser.ts b/src/context/virtual-drive/items/application/Traverser.ts index 681bf8a02..f6a312553 100644 --- a/src/context/virtual-drive/items/application/Traverser.ts +++ b/src/context/virtual-drive/items/application/Traverser.ts @@ -1,5 +1,6 @@ import * as Sentry from '@sentry/electron/renderer'; import Logger from 'electron-log'; +import { SyncEngineIpc } from '../../../../apps/sync-engine/ipcRendererSyncEngine'; import { ServerFile, ServerFileStatus, @@ -27,22 +28,32 @@ type Items = { export class Traverser { constructor( private readonly decrypt: NameDecrypt, + private readonly ipc: SyncEngineIpc, private readonly baseFolderId: number, private readonly fileStatusesToFilter: Array, private readonly folderStatusesToFilter: Array ) {} - static existingItems(decrypt: NameDecrypt, baseFolderId: number): Traverser { + static existingItems( + decrypt: NameDecrypt, + ipc: SyncEngineIpc, + baseFolderId: number + ): Traverser { return new Traverser( decrypt, + ipc, baseFolderId, [ServerFileStatus.EXISTS], [ServerFolderStatus.EXISTS] ); } - static allItems(decrypt: NameDecrypt, baseFolderId: number): Traverser { - return new Traverser(decrypt, baseFolderId, [], []); + static allItems( + decrypt: NameDecrypt, + ipc: SyncEngineIpc, + baseFolderId: number + ): Traverser { + return new Traverser(decrypt, ipc, baseFolderId, [], []); } private createRootFolder(): Folder { @@ -95,6 +106,12 @@ export class Traverser { (error): void => { Logger.warn('[Traverser] Error adding file:', error); Sentry.captureException(error); + this.ipc.send('SYNC_PROBLEM', { + key: 'node-duplicated', + additionalData: { + name: serverFile.plainName, + }, + }); }, () => { // no-op @@ -128,6 +145,12 @@ export class Traverser { (error) => { Logger.warn(`[Traverser] Error adding folder: ${error} `); Sentry.captureException(error); + this.ipc.send('SYNC_PROBLEM', { + key: 'node-duplicated', + additionalData: { + name, + }, + }); }, (folder) => { if (folder.hasStatus(FolderStatuses.EXISTS)) { From 26760f0a00bc8ed5b14228f1685c5eb2c7e0ff9c Mon Sep 17 00:00:00 2001 From: joan vicens Date: Wed, 10 Jan 2024 12:56:54 +0100 Subject: [PATCH 3/4] test: update traverser test --- .../virtual-drive/items/application/Traverser.test.ts | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/tests/context/virtual-drive/items/application/Traverser.test.ts b/tests/context/virtual-drive/items/application/Traverser.test.ts index 62adf56d4..7c98bce10 100644 --- a/tests/context/virtual-drive/items/application/Traverser.test.ts +++ b/tests/context/virtual-drive/items/application/Traverser.test.ts @@ -8,10 +8,12 @@ import { } from '../../../../../src/context/shared/domain/ServerFolder'; import { Traverser } from '../../../../../src/context/virtual-drive/items/application/Traverser'; import { ContentsIdMother } from '../../contents/domain/ContentsIdMother'; +import { IpcRendererSyncEngineMock } from '../../shared/__mock__/IpcRendererSyncEngineMock'; import { FakeNameDecrypt } from '../infrastructure/FakeNameDecrypt'; describe('Traverser', () => { const nameDecrypt = new FakeNameDecrypt(); + const ipc = new IpcRendererSyncEngineMock(); it('first level files starts with /', () => { const baseFolderId = 6; @@ -29,6 +31,7 @@ describe('Traverser', () => { }; const SUT = new Traverser( nameDecrypt, + ipc, baseFolderId, [ServerFileStatus.EXISTS, ServerFileStatus.TRASHED], [ServerFolderStatus.EXISTS] @@ -64,6 +67,7 @@ describe('Traverser', () => { }; const SUT = new Traverser( nameDecrypt, + ipc, baseFolderId, [ServerFileStatus.EXISTS, ServerFileStatus.TRASHED], [ServerFolderStatus.EXISTS] @@ -91,6 +95,7 @@ describe('Traverser', () => { }; const SUT = new Traverser( nameDecrypt, + ipc, baseFolderId, [ServerFileStatus.EXISTS, ServerFileStatus.TRASHED], [ServerFolderStatus.EXISTS] @@ -124,6 +129,7 @@ describe('Traverser', () => { }; const SUT = new Traverser( nameDecrypt, + ipc, baseFolderId, [ServerFileStatus.EXISTS, ServerFileStatus.TRASHED], [ServerFolderStatus.EXISTS] @@ -157,6 +163,7 @@ describe('Traverser', () => { }; const SUT = new Traverser( nameDecrypt, + ipc, baseFolderId, [ServerFileStatus.EXISTS, ServerFileStatus.TRASHED], [ServerFolderStatus.EXISTS] @@ -197,6 +204,7 @@ describe('Traverser', () => { }; const SUT = new Traverser( nameDecrypt, + ipc, baseFolderId, [ServerFileStatus.EXISTS, ServerFileStatus.TRASHED], [ServerFolderStatus.EXISTS] @@ -224,6 +232,7 @@ describe('Traverser', () => { }; const SUT = new Traverser( nameDecrypt, + ipc, baseFolderId, [ServerFileStatus.EXISTS, ServerFileStatus.TRASHED], [ServerFolderStatus.EXISTS] @@ -259,6 +268,7 @@ describe('Traverser', () => { }; const SUT = new Traverser( nameDecrypt, + ipc, baseFolderId, [ServerFileStatus.EXISTS, ServerFileStatus.TRASHED], [ServerFolderStatus.EXISTS] @@ -294,6 +304,7 @@ describe('Traverser', () => { }; const SUT = new Traverser( nameDecrypt, + ipc, baseFolderId, [ServerFileStatus.EXISTS, ServerFileStatus.TRASHED], [ServerFolderStatus.EXISTS] From 03f9e0b9e9df864a8e23e8dcf84e33849f74f7f0 Mon Sep 17 00:00:00 2001 From: joan vicens Date: Wed, 10 Jan 2024 17:10:13 +0100 Subject: [PATCH 4/4] chore: allow long error messages --- src/apps/renderer/localize/locales/en.json | 2 +- src/apps/renderer/pages/ProcessIssues/List.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/apps/renderer/localize/locales/en.json b/src/apps/renderer/localize/locales/en.json index 228ebbdbe..04b2169f6 100644 --- a/src/apps/renderer/localize/locales/en.json +++ b/src/apps/renderer/localize/locales/en.json @@ -322,7 +322,7 @@ "file-does-not-exist": "File doesn't exist", "file-too-big": "Max upload size is 20GB. Please try smaller files.", "file-non-extension": "Files without extensions are not supported.", - "duplicated-node": "There is a conflict with the element" + "duplicated-node": "It appears that there are duplicate file or folder names in this directory. Please rename one of them to ensure synchronization" }, "error-messages": { "no-internet": "Looks like you are not connected to the internet, we'll try again later", diff --git a/src/apps/renderer/pages/ProcessIssues/List.tsx b/src/apps/renderer/pages/ProcessIssues/List.tsx index a6887aade..eee9a0e82 100644 --- a/src/apps/renderer/pages/ProcessIssues/List.tsx +++ b/src/apps/renderer/pages/ProcessIssues/List.tsx @@ -202,7 +202,7 @@ function Item({

{translate(shortMessages[errorName])}