improved cache cleanup for offline mode

This commit is contained in:
Dmitri 2026-04-14 20:28:58 +04:00
parent ff36f318fc
commit c47adfa7fa
3 changed files with 53 additions and 12 deletions

View File

@ -481,9 +481,24 @@ export function useOfflineMode(
const deleteOfflineData = useCallback(async () => { const deleteOfflineData = useCallback(async () => {
if (!projectId) return; if (!projectId) return;
// Get storage keys before deleting (to clear in-memory blob URLs)
const assets = discoverAssets();
const storageKeys = assets.map((a) => a.storageKey);
// Clear in-memory blob URLs for this project's assets
downloadManager.clearBlobUrlsForKeys(storageKeys);
// Delete from persistent storage
await StorageManager.deleteProjectAssets(projectId); await StorageManager.deleteProjectAssets(projectId);
await OfflineDbManager.deleteProject(projectId); await OfflineDbManager.deleteProject(projectId);
// Reset refs used for progress tracking
assetsRef.current = [];
downloadedCountRef.current = 0;
downloadedBytesRef.current = 0;
// Reset state
setDiscoveredAssets([]);
setProjectInfo(null); setProjectInfo(null);
setStatus('not_downloaded'); setStatus('not_downloaded');
setProgress(0); setProgress(0);
@ -491,7 +506,7 @@ export function useOfflineMode(
setTotalAssets(0); setTotalAssets(0);
setDownloadedBytes(0); setDownloadedBytes(0);
setTotalBytes(0); setTotalBytes(0);
}, [projectId]); }, [projectId, discoverAssets]);
// Check for updates by comparing discovered assets with stored project // Check for updates by comparing discovered assets with stored project
const checkForUpdates = useCallback(async (): Promise<boolean> => { const checkForUpdates = useCallback(async (): Promise<boolean> => {

View File

@ -756,6 +756,20 @@ class DownloadManagerClass {
} }
} }
/**
* Clear blob URLs for specific storage keys (call when deleting project offline data)
*/
clearBlobUrlsForKeys(storageKeys: string[]): void {
for (const key of storageKeys) {
const blobUrl = this.readyBlobUrls.get(key);
if (blobUrl) {
URL.revokeObjectURL(blobUrl);
this.readyBlobUrls.delete(key);
}
this.partialDownloadsReady.delete(key);
}
}
/** /**
* Check if URL is an image based on extension * Check if URL is an image based on extension
*/ */

View File

@ -9,6 +9,7 @@ import { OFFLINE_CONFIG } from '../../config/offline.config';
import { PRELOAD_CONFIG } from '../../config/preload.config'; import { PRELOAD_CONFIG } from '../../config/preload.config';
import { OfflineDbManager } from '../offlineDb/OfflineDbManager'; import { OfflineDbManager } from '../offlineDb/OfflineDbManager';
import { extractStoragePath } from '../assetUrl'; import { extractStoragePath } from '../assetUrl';
import { logger } from '../logger';
import type { import type {
OfflineAsset, OfflineAsset,
AssetVariantType, AssetVariantType,
@ -260,23 +261,34 @@ export class StorageManager {
// Delete from IndexedDB // Delete from IndexedDB
await OfflineDbManager.deleteProjectAssets(projectId); await OfflineDbManager.deleteProjectAssets(projectId);
// Cache API cleanup is more complex - we'd need to track URLs // Delete from Cache API - iterate through cache and delete entries for this project
// For now, we rely on the service worker to handle this if (typeof caches !== 'undefined') {
try {
const cache = await caches.open(OFFLINE_CONFIG.cacheNames.assets);
const keys = await cache.keys();
for (const request of keys) {
const response = await cache.match(request);
if (response) {
const cachedProjectId = response.headers.get('X-Project-Id');
if (cachedProjectId === projectId) {
await cache.delete(request);
}
}
}
} catch (error) {
logger.error('[StorageManager] Failed to clear Cache API:', error);
}
}
} }
/** /**
* Get total storage used * Get total storage used
*/ */
static async getTotalStorageUsed(): Promise<number> { static async getTotalStorageUsed(): Promise<number> {
let total = 0; // IndexedDB storage (primary tracking)
const total = await OfflineDbManager.getTotalAssetsSize();
// IndexedDB storage // Note: Cache API size is included in browser's quota.usage but not tracked separately
total += await OfflineDbManager.getTotalAssetsSize();
// Cache API storage (approximate from quota)
const quota = await this.getStorageQuota();
// Note: quota.usage includes all storage, not just our caches
return total; return total;
} }