diff --git a/electron/electronAPI.d.ts b/electron/electronAPI.d.ts index 7b7f906a42..3c70d155c2 100644 --- a/electron/electronAPI.d.ts +++ b/electron/electronAPI.d.ts @@ -48,7 +48,7 @@ export interface ElectronAPI { fileSyncRemove(args: { filePath: string }): Promise; - fileSyncListFiles(args: { dirPath: string }): Promise; // NEW + fileSyncListFiles(args: { dirPath: string }): Promise; checkDirExists(args: { dirPath: string }): Promise; diff --git a/electron/local-file-sync.ts b/electron/local-file-sync.ts index 100abfc7d5..63c69d0a03 100644 --- a/electron/local-file-sync.ts +++ b/electron/local-file-sync.ts @@ -112,6 +112,36 @@ export const initLocalFileSyncAdapter = (): void => { return true; } catch (e) { log('ERR: error while checking dir ' + dirPath); + if ((e as NodeJS.ErrnoException).code === 'EACCES') { + log( + 'ERR: Permission denied. If running as a snap, ensure the "home" or "removable-media" interface is connected.', + ); + } + error(e); + return e instanceof Error ? e : new Error(String(e)); + } + }, + ); + + ipcMain.handle( + IPC.FILE_SYNC_LIST_FILES, + ( + ev, + { + dirPath, + }: { + dirPath: string; + }, + ): string[] | Error => { + try { + return readdirSync(dirPath); + } catch (e) { + log('ERR: Sync error while listing files in ' + dirPath); + if ((e as NodeJS.ErrnoException).code === 'EACCES') { + log( + 'ERR: Permission denied. If running as a snap, ensure the "home" or "removable-media" interface is connected.', + ); + } error(e); return e instanceof Error ? e : new Error(String(e)); } diff --git a/electron/preload.ts b/electron/preload.ts index 990dab9349..e5ff6b287b 100644 --- a/electron/preload.ts +++ b/electron/preload.ts @@ -49,8 +49,8 @@ const ea: ElectronAPI = { dataStr: string | undefined; }>, fileSyncRemove: (filePath) => _invoke('FILE_SYNC_REMOVE', filePath) as Promise, - fileSyncListFiles: ({ dirPath }) => - _invoke('FILE_SYNC_LIST_FILES', dirPath) as Promise, + fileSyncListFiles: (args) => + _invoke('FILE_SYNC_LIST_FILES', args) as Promise, checkDirExists: (dirPath) => _invoke('CHECK_DIR_EXISTS', dirPath) as Promise, diff --git a/electron/shared-with-frontend/ipc-events.const.ts b/electron/shared-with-frontend/ipc-events.const.ts index b0d5ac251d..85998c2cee 100644 --- a/electron/shared-with-frontend/ipc-events.const.ts +++ b/electron/shared-with-frontend/ipc-events.const.ts @@ -43,7 +43,7 @@ export enum IPC { FILE_SYNC_LOAD = 'FILE_SYNC_LOAD', FILE_SYNC_SAVE = 'FILE_SYNC_SAVE', FILE_SYNC_REMOVE = 'FILE_SYNC_REMOVE', - FILE_SYNC_LIST_FILES = 'FILE_SYNC_LIST_FILES', // NEW + FILE_SYNC_LIST_FILES = 'FILE_SYNC_LIST_FILES', FILE_SYNC_GET_REV_AND_CLIENT_UPDATE = 'FILE_SYNC_GET_REV_AND_CLIENT_UPDATE', CHECK_DIR_EXISTS = 'CHECK_DIR_EXISTS', diff --git a/src/app/op-log/sync-providers/file-based/local-file/file-adapter.interface.ts b/src/app/op-log/sync-providers/file-based/local-file/file-adapter.interface.ts index 51511a8aa7..70f174c22f 100644 --- a/src/app/op-log/sync-providers/file-based/local-file/file-adapter.interface.ts +++ b/src/app/op-log/sync-providers/file-based/local-file/file-adapter.interface.ts @@ -3,5 +3,5 @@ export interface FileAdapter { writeFile(filePath: string, dataStr: string): Promise; deleteFile(filePath: string): Promise; checkDirExists?(dirPath: string): Promise; - listFiles?(dirPath: string): Promise; // NEW + listFiles?(dirPath: string): Promise; }