From 18a0e78f129b65fa18d0b6c052fca1ac29bb6c44 Mon Sep 17 00:00:00 2001 From: Johannes Millan Date: Mon, 22 Dec 2025 15:11:50 +0100 Subject: [PATCH] fix(sync): show context-aware permission error for Flatpak/Snap Add isFlatpak() detection to Electron API and show environment-specific error messages when file permission errors occur during sync: - Flatpak users see Flatseal and ~/.var/app/ guidance - Snap users see 'snap connect' and ~/snap/... guidance - Other users see generic permission error Addresses #4078 --- electron/electronAPI.d.ts | 2 ++ electron/preload.ts | 1 + src/app/imex/sync/sync-wrapper.service.ts | 13 ++++++++++++- src/app/t.const.ts | 2 ++ src/assets/i18n/en.json | 4 +++- 5 files changed, 20 insertions(+), 2 deletions(-) diff --git a/electron/electronAPI.d.ts b/electron/electronAPI.d.ts index 7a0788abc..44450a7ee 100644 --- a/electron/electronAPI.d.ts +++ b/electron/electronAPI.d.ts @@ -83,6 +83,8 @@ export interface ElectronAPI { isSnap(): boolean; + isFlatpak(): boolean; + // SEND // ---- reloadMainWin(): void; diff --git a/electron/preload.ts b/electron/preload.ts index 17a305aa8..8d7650084 100644 --- a/electron/preload.ts +++ b/electron/preload.ts @@ -59,6 +59,7 @@ const ea: ElectronAPI = { isLinux: () => process.platform === 'linux', isMacOS: () => process.platform === 'darwin', isSnap: () => process && process.env && !!process.env.SNAP, + isFlatpak: () => process && process.env && !!process.env.FLATPAK_ID, // SEND // ---- diff --git a/src/app/imex/sync/sync-wrapper.service.ts b/src/app/imex/sync/sync-wrapper.service.ts index 5fb27f063..54150d886 100644 --- a/src/app/imex/sync/sync-wrapper.service.ts +++ b/src/app/imex/sync/sync-wrapper.service.ts @@ -35,6 +35,7 @@ import { DialogIncoherentTimestampsErrorComponent } from './dialog-incoherent-ti import { SyncLog } from '../../core/log'; import { promiseTimeout } from '../../util/promise-timeout'; import { devError } from '../../util/dev-error'; +import { IS_ELECTRON } from '../../app.constants'; @Injectable({ providedIn: 'root', @@ -244,7 +245,7 @@ export class SyncWrapperService { return 'HANDLED_ERROR'; } else if (this._isPermissionError(error)) { this._snackService.open({ - msg: T.F.SYNC.S.ERROR_PERMISSION, + msg: this._getPermissionErrorMessage(), type: 'ERROR', config: { duration: 12000 }, }); @@ -388,6 +389,16 @@ export class SyncWrapperService { return /EROFS|EACCES|EPERM|read-only file system|permission denied/i.test(errStr); } + private _getPermissionErrorMessage(): string { + if (IS_ELECTRON && window.ea?.isFlatpak?.()) { + return T.F.SYNC.S.ERROR_PERMISSION_FLATPAK; + } + if (IS_ELECTRON && window.ea?.isSnap?.()) { + return T.F.SYNC.S.ERROR_PERMISSION_SNAP; + } + return T.F.SYNC.S.ERROR_PERMISSION; + } + private lastConflictDialog?: MatDialogRef; private _openConflictDialog$( diff --git a/src/app/t.const.ts b/src/app/t.const.ts index 3265c9925..1598eee94 100644 --- a/src/app/t.const.ts +++ b/src/app/t.const.ts @@ -1179,6 +1179,8 @@ const T = { ERROR_DATA_IS_CURRENTLY_WRITTEN: 'F.SYNC.S.ERROR_DATA_IS_CURRENTLY_WRITTEN', ERROR_FALLBACK_TO_BACKUP: 'F.SYNC.S.ERROR_FALLBACK_TO_BACKUP', ERROR_PERMISSION: 'F.SYNC.S.ERROR_PERMISSION', + ERROR_PERMISSION_FLATPAK: 'F.SYNC.S.ERROR_PERMISSION_FLATPAK', + ERROR_PERMISSION_SNAP: 'F.SYNC.S.ERROR_PERMISSION_SNAP', ERROR_INVALID_DATA: 'F.SYNC.S.ERROR_INVALID_DATA', ERROR_NO_REV: 'F.SYNC.S.ERROR_NO_REV', ERROR_UNABLE_TO_READ_REMOTE_DATA: 'F.SYNC.S.ERROR_UNABLE_TO_READ_REMOTE_DATA', diff --git a/src/assets/i18n/en.json b/src/assets/i18n/en.json index d9ae34a48..360d3f215 100644 --- a/src/assets/i18n/en.json +++ b/src/assets/i18n/en.json @@ -1159,7 +1159,9 @@ "BTN_FORCE_OVERWRITE": "Force Overwrite", "ERROR_CORS": "WebDAV Sync Error: Network request failed.\n\nThis might be a CORS issue. Please ensure:\n• Your WebDAV server allows Cross-Origin requests\n• The server URL is correct and accessible\n• You have a working internet connection", "ERROR_DATA_IS_CURRENTLY_WRITTEN": "Remote Data is currently being written", - "ERROR_PERMISSION": "File access denied. If using Flatpak/Snap, grant filesystem permission via Flatseal or use a path inside ~/.var/app/", + "ERROR_PERMISSION": "File access denied. Please check your filesystem permissions.", + "ERROR_PERMISSION_FLATPAK": "File access denied. Grant filesystem permission via Flatseal or use a path inside ~/.var/app/", + "ERROR_PERMISSION_SNAP": "File access denied. Run 'snap connect super-productivity:home' or use a path inside ~/snap/super-productivity/common/", "ERROR_FALLBACK_TO_BACKUP": "Something went wrong while importing the data. Falling back to local backup.", "ERROR_INVALID_DATA": "Error while syncing. Invalid data", "ERROR_NO_REV": "No valid rev for remote file",