mirror of
https://github.com/aliasvault/aliasvault.git
synced 2026-05-09 15:56:11 -04:00
Add email error suppression during active sync or isDirty flags (#1473)
This commit is contained in:
@@ -156,14 +156,30 @@ export const EmailPreview: React.FC<EmailPreviewProps> = ({ email }) => {
|
||||
}
|
||||
return prevEmails;
|
||||
});
|
||||
|
||||
// Clear any previous error on successful load
|
||||
setError(null);
|
||||
}
|
||||
} catch {
|
||||
// Try to parse as error response instead
|
||||
const apiErrorResponse = response as ApiErrorResponse;
|
||||
|
||||
// Suppress errors while vault has unsynced changes (e.g., after item creation)
|
||||
// The server may not know about newly created items/aliases yet
|
||||
if (dbContext.shouldSuppressEmailErrors()) {
|
||||
// Don't set error, keep loading state - will retry on next interval
|
||||
return;
|
||||
}
|
||||
|
||||
setError(t('emails.apiErrors.' + apiErrorResponse?.code));
|
||||
return;
|
||||
}
|
||||
} catch {
|
||||
// Suppress errors while vault has unsynced changes
|
||||
if (dbContext.shouldSuppressEmailErrors()) {
|
||||
return;
|
||||
}
|
||||
|
||||
setError(t('common.errors.unknownError'));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -44,6 +44,12 @@ type DbContextType = {
|
||||
* Set the syncing state.
|
||||
*/
|
||||
setIsSyncing: (syncing: boolean) => void;
|
||||
/**
|
||||
* Check if email errors should be suppressed.
|
||||
* Errors are suppressed when vault has local changes not yet synced,
|
||||
* as the server may not know about newly created items/aliases yet.
|
||||
*/
|
||||
shouldSuppressEmailErrors: () => boolean;
|
||||
/**
|
||||
* Load a decrypted vault into memory (SQLite client).
|
||||
*/
|
||||
@@ -107,6 +113,15 @@ export const DbProvider: React.FC<{ children: React.ReactNode }> = ({ children }
|
||||
*/
|
||||
const [serverRevision, setServerRevision] = useState(0);
|
||||
|
||||
/**
|
||||
* Check if email errors should be suppressed.
|
||||
* Errors are suppressed when vault has local changes not yet synced,
|
||||
* as the server may not know about newly created items/aliases yet.
|
||||
*/
|
||||
const shouldSuppressEmailErrors = useCallback(() => {
|
||||
return isDirty || isSyncing;
|
||||
}, [isDirty, isSyncing]);
|
||||
|
||||
/**
|
||||
* Set the offline mode state and persist it to local storage.
|
||||
* Updates both ref (sync) and state (triggers re-render).
|
||||
@@ -277,6 +292,7 @@ export const DbProvider: React.FC<{ children: React.ReactNode }> = ({ children }
|
||||
serverRevision,
|
||||
setIsOffline,
|
||||
setIsSyncing,
|
||||
shouldSuppressEmailErrors,
|
||||
loadDatabase,
|
||||
loadStoredDatabase,
|
||||
storeEncryptionKey,
|
||||
@@ -285,7 +301,7 @@ export const DbProvider: React.FC<{ children: React.ReactNode }> = ({ children }
|
||||
getVaultMetadata,
|
||||
refreshSyncState,
|
||||
hasPendingMigrations,
|
||||
}), [sqliteClient, dbInitialized, dbAvailable, isOffline, getIsOffline, isDirty, isSyncing, serverRevision, setIsOffline, loadDatabase, loadStoredDatabase, storeEncryptionKey, storeEncryptionKeyDerivationParams, clearDatabase, getVaultMetadata, refreshSyncState, hasPendingMigrations]);
|
||||
}), [sqliteClient, dbInitialized, dbAvailable, isOffline, getIsOffline, isDirty, isSyncing, serverRevision, setIsOffline, shouldSuppressEmailErrors, loadDatabase, loadStoredDatabase, storeEncryptionKey, storeEncryptionKeyDerivationParams, clearDatabase, getVaultMetadata, refreshSyncState, hasPendingMigrations]);
|
||||
|
||||
return (
|
||||
<DbContext.Provider value={contextValue}>
|
||||
|
||||
@@ -204,10 +204,23 @@ export const EmailPreview: React.FC<EmailPreviewProps> = ({ email }) : React.Rea
|
||||
} catch {
|
||||
// Try to parse as error response instead
|
||||
const apiErrorResponse = response as ApiErrorResponse;
|
||||
|
||||
// Suppress errors while vault has unsynced changes (e.g., after item creation)
|
||||
// The server may not know about newly created items/aliases yet
|
||||
if (dbContext.shouldSuppressEmailErrors()) {
|
||||
// Don't set error, keep loading state - will retry on next interval
|
||||
return;
|
||||
}
|
||||
|
||||
setError(t(`apiErrors.${apiErrorResponse?.code}`));
|
||||
return;
|
||||
}
|
||||
} catch {
|
||||
// Suppress errors while vault has unsynced changes
|
||||
if (dbContext.shouldSuppressEmailErrors()) {
|
||||
return;
|
||||
}
|
||||
|
||||
setError(t('items.emailLoadError'));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,12 @@ type DbContextType = {
|
||||
isOffline: boolean;
|
||||
setIsSyncing: (syncing: boolean) => void;
|
||||
setIsOffline: (offline: boolean) => Promise<void>;
|
||||
/**
|
||||
* Check if email errors should be suppressed.
|
||||
* Errors are suppressed when vault has local changes not yet synced,
|
||||
* as the server may not know about newly created items/aliases yet.
|
||||
*/
|
||||
shouldSuppressEmailErrors: () => boolean;
|
||||
refreshSyncState: () => Promise<void>;
|
||||
storeEncryptionKey: (derivedKey: string) => Promise<void>;
|
||||
storeEncryptionKeyDerivationParams: (keyDerivationParams: EncryptionKeyDerivationParams) => Promise<void>;
|
||||
@@ -63,6 +69,15 @@ export const DbProvider: React.FC<{ children: React.ReactNode }> = ({ children }
|
||||
*/
|
||||
const [isOffline, setIsOfflineState] = useState(false);
|
||||
|
||||
/**
|
||||
* Check if email errors should be suppressed.
|
||||
* Errors are suppressed when vault has local changes not yet synced,
|
||||
* as the server may not know about newly created items/aliases yet.
|
||||
*/
|
||||
const shouldSuppressEmailErrors = useCallback(() => {
|
||||
return isDirty || isSyncing;
|
||||
}, [isDirty, isSyncing]);
|
||||
|
||||
/**
|
||||
* Unlock the vault in the native module which will decrypt the database using the stored encryption key
|
||||
* and load it into memory.
|
||||
@@ -246,6 +261,7 @@ export const DbProvider: React.FC<{ children: React.ReactNode }> = ({ children }
|
||||
isOffline,
|
||||
setIsSyncing,
|
||||
setIsOffline,
|
||||
shouldSuppressEmailErrors,
|
||||
refreshSyncState,
|
||||
hasPendingMigrations,
|
||||
clearDatabase,
|
||||
@@ -256,7 +272,7 @@ export const DbProvider: React.FC<{ children: React.ReactNode }> = ({ children }
|
||||
storeEncryptionKeyDerivationParams,
|
||||
checkStoredVault,
|
||||
setDatabaseAvailable,
|
||||
}), [sqliteClient, dbInitialized, dbAvailable, isDirty, isSyncing, isOffline, setIsSyncing, setIsOffline, refreshSyncState, hasPendingMigrations, clearDatabase, getVaultMetadata, testDatabaseConnection, unlockVault, storeEncryptionKey, storeEncryptionKeyDerivationParams, checkStoredVault, setDatabaseAvailable]);
|
||||
}), [sqliteClient, dbInitialized, dbAvailable, isDirty, isSyncing, isOffline, setIsSyncing, setIsOffline, shouldSuppressEmailErrors, refreshSyncState, hasPendingMigrations, clearDatabase, getVaultMetadata, testDatabaseConnection, unlockVault, storeEncryptionKey, storeEncryptionKeyDerivationParams, checkStoredVault, setDatabaseAvailable]);
|
||||
|
||||
return (
|
||||
<DbContext.Provider value={contextValue}>
|
||||
|
||||
@@ -141,6 +141,9 @@ public class VaultController(ILogger<VaultController> logger, IAliasServerDbCont
|
||||
return Unauthorized();
|
||||
}
|
||||
|
||||
// Simulate a delay to test the email error suppression logic.
|
||||
await Task.Delay(10000);
|
||||
|
||||
// Compare the logged-in username with the username in the provided vault model.
|
||||
// If they do not match reject the request. This is important because it's
|
||||
// possible that a user has logged in with a different username than the one
|
||||
|
||||
Reference in New Issue
Block a user