mirror of
https://github.com/mayswind/ezbookkeeping
synced 2026-04-21 13:37:43 +00:00
support caching map data when map_data_fetch_proxy is set true
This commit is contained in:
parent
d5dfdc8c05
commit
247181830c
35 changed files with 740 additions and 179 deletions
|
|
@ -34,6 +34,7 @@ import { ThemeType } from '@/core/theme.ts';
|
|||
import { isProduction } from '@/lib/version.ts';
|
||||
import { initMapProvider } from '@/lib/map/index.ts';
|
||||
import { isUserLogined, isUserUnlocked } from '@/lib/userstate.ts';
|
||||
import { updateMapCacheExpiration } from '@/lib/cache.ts';
|
||||
import { getSystemTheme, setExpenseAndIncomeAmountColor } from '@/lib/ui/common.ts';
|
||||
|
||||
const { tt, getCurrentLanguageInfo, setLanguage, initLocale } = useI18n();
|
||||
|
|
@ -77,6 +78,16 @@ onMounted(() => {
|
|||
const languageInfo = getCurrentLanguageInfo();
|
||||
initMapProvider(languageInfo?.alternativeLanguageTag);
|
||||
});
|
||||
|
||||
if ('serviceWorker' in navigator) {
|
||||
navigator.serviceWorker.addEventListener('controllerchange', () => {
|
||||
updateMapCacheExpiration(settingsStore.appSettings.mapCacheExpiration);
|
||||
});
|
||||
|
||||
if (navigator.serviceWorker.controller) {
|
||||
updateMapCacheExpiration(settingsStore.appSettings.mapCacheExpiration);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
watch(currentNotificationContent, (newValue) => {
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ import { isProduction } from '@/lib/version.ts';
|
|||
import { getTheme, isEnableSwipeBack, isEnableAnimate } from '@/lib/settings.ts';
|
||||
import { initMapProvider } from '@/lib/map/index.ts';
|
||||
import { isUserLogined, isUserUnlocked } from '@/lib/userstate.ts';
|
||||
import { updateMapCacheExpiration } from '@/lib/cache.ts';
|
||||
import { setExpenseAndIncomeAmountColor } from '@/lib/ui/common.ts';
|
||||
import { isiOSHomeScreenMode, isModalShowing, setAppFontSize } from '@/lib/ui/mobile.ts';
|
||||
|
||||
|
|
@ -180,6 +181,16 @@ onMounted(() => {
|
|||
const languageInfo = getCurrentLanguageInfo();
|
||||
initMapProvider(languageInfo?.alternativeLanguageTag);
|
||||
});
|
||||
|
||||
if ('serviceWorker' in navigator) {
|
||||
navigator.serviceWorker.addEventListener('controllerchange', () => {
|
||||
updateMapCacheExpiration(settingsStore.appSettings.mapCacheExpiration);
|
||||
});
|
||||
|
||||
if (navigator.serviceWorker.controller) {
|
||||
updateMapCacheExpiration(settingsStore.appSettings.mapCacheExpiration);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
watch(currentNotificationContent, (newValue) => {
|
||||
|
|
|
|||
|
|
@ -3,3 +3,8 @@ export const SW_RUNTIME_CACHE_NAME_PREFIX: string = 'workbox-runtime-';
|
|||
export const SW_ASSETS_CACHE_NAME: string = 'ezbookkeeping-assets-cache';
|
||||
export const SW_CODE_CACHE_NAME: string = 'ezbookkeeping-code-cache';
|
||||
export const SW_MAP_CACHE_NAME: string = 'ezbookkeeping-map-cache';
|
||||
|
||||
export const SW_MESSAGE_TYPE_UPDATE_MAP_CACHE_CONFIG: string = 'UPDATE_MAP_CACHE_CONFIG';
|
||||
export const SW_MESSAGE_TYPE_UPDATE_MAP_CACHE_CONFIG_RESPONSE: string = 'UPDATE_MAP_CACHE_CONFIG_RESPONSE';
|
||||
|
||||
export const MAP_CACHE_MAX_ENTRIES: number = 1000;
|
||||
|
|
|
|||
|
|
@ -65,12 +65,17 @@ export function* values<K extends string | number | symbol, V>(obj: Record<K, V>
|
|||
}
|
||||
}
|
||||
|
||||
export interface NameValue {
|
||||
export interface GenericNameValue<T> {
|
||||
readonly name: string;
|
||||
readonly value: T;
|
||||
}
|
||||
|
||||
export interface NameValue extends GenericNameValue<string> {
|
||||
readonly name: string;
|
||||
readonly value: string;
|
||||
}
|
||||
|
||||
export interface NameNumeralValue {
|
||||
export interface NameNumeralValue extends GenericNameValue<number> {
|
||||
readonly name: string;
|
||||
readonly value: number;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,3 +5,10 @@ export interface BrowserCacheStatistics {
|
|||
readonly mapCacheSize: number;
|
||||
readonly othersCacheSize: number;
|
||||
}
|
||||
|
||||
export interface SWMapCacheConfig {
|
||||
enabled: boolean;
|
||||
patterns: string[];
|
||||
maxEntries: number;
|
||||
maxAgeMilliseconds: number;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -62,6 +62,8 @@ export interface ApplicationSettings extends BaseApplicationSetting {
|
|||
hideCategoriesWithoutAccounts: boolean;
|
||||
// Exchange Rates Data Page
|
||||
currencySortByInExchangeRatesPage: number;
|
||||
// Browser Cache Settings
|
||||
mapCacheExpiration: number,
|
||||
// Statistics Settings
|
||||
statistics: {
|
||||
defaultChartDataType: number;
|
||||
|
|
@ -187,6 +189,8 @@ export const DEFAULT_APPLICATION_SETTINGS: ApplicationSettings = {
|
|||
hideCategoriesWithoutAccounts: false,
|
||||
// Exchange Rates Data Page
|
||||
currencySortByInExchangeRatesPage: CurrencySortingType.Default.type,
|
||||
// Browser Cache Settings
|
||||
mapCacheExpiration: -1,
|
||||
// Statistics Settings
|
||||
statistics: {
|
||||
defaultChartDataType: ChartDataType.Default.type,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import type {
|
||||
BrowserCacheStatistics
|
||||
BrowserCacheStatistics,
|
||||
SWMapCacheConfig
|
||||
} from '@/core/cache.ts';
|
||||
|
||||
import {
|
||||
|
|
@ -7,10 +8,14 @@ import {
|
|||
SW_RUNTIME_CACHE_NAME_PREFIX,
|
||||
SW_ASSETS_CACHE_NAME,
|
||||
SW_CODE_CACHE_NAME,
|
||||
SW_MAP_CACHE_NAME
|
||||
SW_MAP_CACHE_NAME,
|
||||
SW_MESSAGE_TYPE_UPDATE_MAP_CACHE_CONFIG,
|
||||
SW_MESSAGE_TYPE_UPDATE_MAP_CACHE_CONFIG_RESPONSE,
|
||||
MAP_CACHE_MAX_ENTRIES
|
||||
} from '@/consts/cache.ts';
|
||||
|
||||
import { isFunction, isObject, isNumber } from './common.ts';
|
||||
import services from './services.ts';
|
||||
import logger from './logger.ts';
|
||||
|
||||
function findFirstCacheName(prefix: string): Promise<string> {
|
||||
|
|
@ -113,6 +118,63 @@ export function loadBrowserCacheStatistics(): Promise<BrowserCacheStatistics> {
|
|||
});
|
||||
}
|
||||
|
||||
export function updateMapCacheExpiration(expireSeconds: number): Promise<void> {
|
||||
const config: SWMapCacheConfig = {
|
||||
enabled: expireSeconds >= 0,
|
||||
patterns: services.getMapProxyTileImageAndAnnotationImageUrlPatterns(),
|
||||
maxEntries: MAP_CACHE_MAX_ENTRIES,
|
||||
maxAgeMilliseconds: expireSeconds * 1000
|
||||
};
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
if (!navigator.serviceWorker || !navigator.serviceWorker.controller) {
|
||||
reject(new Error('Service worker is not supported or not active'));
|
||||
return;
|
||||
}
|
||||
|
||||
const controller = navigator.serviceWorker.controller;
|
||||
|
||||
navigator.serviceWorker.ready.then(() => {
|
||||
const messageChannel = new MessageChannel();
|
||||
|
||||
messageChannel.port1.onmessage = (event) => {
|
||||
if (event.data && event.data.type === SW_MESSAGE_TYPE_UPDATE_MAP_CACHE_CONFIG_RESPONSE) {
|
||||
logger.info('Map cache config updated successfully in service worker: ' + JSON.stringify(event.data.payload));
|
||||
resolve();
|
||||
} else {
|
||||
logger.error('cannot update map cache config, invalid response from service worker', event);
|
||||
reject(new Error('Invalid response from service worker'));
|
||||
}
|
||||
};
|
||||
|
||||
controller.postMessage({
|
||||
type: SW_MESSAGE_TYPE_UPDATE_MAP_CACHE_CONFIG,
|
||||
payload: config
|
||||
}, [messageChannel.port2]);
|
||||
}).catch(error => {
|
||||
logger.error('failed to update map cache config', error);
|
||||
reject(error);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export function clearMapDataCache(): Promise<void> {
|
||||
if (!window.caches) {
|
||||
logger.error('caches API is not supported in this browser');
|
||||
return Promise.reject();
|
||||
}
|
||||
|
||||
return window.caches.delete(SW_MAP_CACHE_NAME).then(success => {
|
||||
if (success) {
|
||||
logger.info(`cache "${SW_MAP_CACHE_NAME}" cleared successfully`);
|
||||
} else {
|
||||
logger.warn(`failed to clear cache "${SW_MAP_CACHE_NAME}"`);
|
||||
}
|
||||
}).catch(error => {
|
||||
logger.error(`failed to clear cache "${SW_MAP_CACHE_NAME}"`, error);
|
||||
});
|
||||
}
|
||||
|
||||
export function clearAllBrowserCaches(): Promise<void> {
|
||||
if (!window.caches) {
|
||||
logger.error('caches API is not supported in this browser');
|
||||
|
|
@ -142,7 +204,7 @@ export function clearAllBrowserCaches(): Promise<void> {
|
|||
resolve();
|
||||
});
|
||||
}).catch(error => {
|
||||
logger.warn("failed to clear cache", error);
|
||||
logger.error("failed to clear cache", error);
|
||||
reject(error);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,5 +1,11 @@
|
|||
import { keys, keysIfValueEquals, values } from '@/core/base.ts';
|
||||
import type { NameValue, TypeAndName, TypeAndDisplayName} from '@/core/base.ts';
|
||||
import {
|
||||
type GenericNameValue,
|
||||
type TypeAndName,
|
||||
type TypeAndDisplayName,
|
||||
keys,
|
||||
keysIfValueEquals,
|
||||
values
|
||||
} from '@/core/base.ts';
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
|
||||
export function isFunction(val: unknown): val is Function {
|
||||
|
|
@ -285,7 +291,7 @@ export function getItemByKeyValue<T>(src: Record<string, T>[] | Record<string, R
|
|||
return null;
|
||||
}
|
||||
|
||||
export function findNameByValue(items: NameValue[], value: string): string | null {
|
||||
export function findNameByValue<T>(items: GenericNameValue<T>[], value: T): string | null {
|
||||
for (const item of items) {
|
||||
if (item.value === value) {
|
||||
return item.name;
|
||||
|
|
|
|||
|
|
@ -27,6 +27,20 @@ export function initMapProvider(language?: string): void {
|
|||
}
|
||||
}
|
||||
|
||||
export function isMapProviderUseExternalSDK(): boolean {
|
||||
const mapProviderType = getMapProvider();
|
||||
|
||||
if (mapProviderType === 'googlemap') {
|
||||
return true;
|
||||
} else if (mapProviderType === 'baidumap') {
|
||||
return true;
|
||||
} else if (mapProviderType === 'amap') {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
export function getMapWebsite(): string {
|
||||
return mapProvider?.getWebsite() || '';
|
||||
}
|
||||
|
|
|
|||
|
|
@ -831,6 +831,12 @@ export default {
|
|||
generateQrCodeUrl: (qrCodeName: string): string => {
|
||||
return `${getBasePath()}${BASE_QRCODE_PATH}/${qrCodeName}.png`;
|
||||
},
|
||||
getMapProxyTileImageAndAnnotationImageUrlPatterns(): string[] {
|
||||
return [
|
||||
`.*${BASE_PROXY_URL_PATH}/map/tile/[^/]+/[^/]+/[^/]+\\.png\\?provider=[^&]+.*$`,
|
||||
`.*${BASE_PROXY_URL_PATH}/map/annotation/[^/]+/[^/]+/[^/]+\\.png\\?provider=[^&]+.*$`
|
||||
];
|
||||
},
|
||||
generateMapProxyTileImageUrl: (mapProvider: string, language: string): string => {
|
||||
const token = getCurrentToken();
|
||||
let url = `${getBasePath()}${BASE_PROXY_URL_PATH}/map/tile/{z}/{x}/{y}.png?provider=${mapProvider}&token=${token}`;
|
||||
|
|
|
|||
|
|
@ -2512,9 +2512,13 @@
|
|||
"Resource Files": "Resource Files",
|
||||
"Map Data": "Map Data",
|
||||
"Others": "Others",
|
||||
"Failed to load browser cache statistics": "Failed to load browser cache statistics",
|
||||
"Clear File Cache": "Clear File Cache",
|
||||
"Are you sure you want to clear file cache?": "Are you sure you want to clear file cache?",
|
||||
"Cache Expiration Time": "Cache Expiration Time",
|
||||
"Cache Expiration for Map Data": "Cache Expiration for Map Data",
|
||||
"Disable Map Cache": "Disable Map Cache",
|
||||
"Clear All File Cache": "Clear All File Cache",
|
||||
"Are you sure you want to clear all file cache?": "Are you sure you want to clear all file cache?",
|
||||
"Clear Map Data Cache": "Clear Map Data Cache",
|
||||
"Are you sure you want to clear map data cache?": "Are you sure you want to clear map data cache?",
|
||||
"Are you sure you want to re-login?": "Sind Sie sicher, dass Sie sich erneut anmelden möchten?",
|
||||
"Exchange Rates Data": "Wechselkursdaten",
|
||||
"User Custom": "User Custom",
|
||||
|
|
|
|||
|
|
@ -2512,9 +2512,13 @@
|
|||
"Resource Files": "Resource Files",
|
||||
"Map Data": "Map Data",
|
||||
"Others": "Others",
|
||||
"Failed to load browser cache statistics": "Failed to load browser cache statistics",
|
||||
"Clear File Cache": "Clear File Cache",
|
||||
"Are you sure you want to clear file cache?": "Are you sure you want to clear file cache?",
|
||||
"Cache Expiration Time": "Cache Expiration Time",
|
||||
"Cache Expiration for Map Data": "Cache Expiration for Map Data",
|
||||
"Disable Map Cache": "Disable Map Cache",
|
||||
"Clear All File Cache": "Clear All File Cache",
|
||||
"Are you sure you want to clear all file cache?": "Are you sure you want to clear all file cache?",
|
||||
"Clear Map Data Cache": "Clear Map Data Cache",
|
||||
"Are you sure you want to clear map data cache?": "Are you sure you want to clear map data cache?",
|
||||
"Are you sure you want to re-login?": "Are you sure you want to re-login?",
|
||||
"Exchange Rates Data": "Exchange Rates Data",
|
||||
"User Custom": "User Custom",
|
||||
|
|
|
|||
|
|
@ -2512,9 +2512,13 @@
|
|||
"Resource Files": "Resource Files",
|
||||
"Map Data": "Map Data",
|
||||
"Others": "Others",
|
||||
"Failed to load browser cache statistics": "Failed to load browser cache statistics",
|
||||
"Clear File Cache": "Clear File Cache",
|
||||
"Are you sure you want to clear file cache?": "Are you sure you want to clear file cache?",
|
||||
"Cache Expiration Time": "Cache Expiration Time",
|
||||
"Cache Expiration for Map Data": "Cache Expiration for Map Data",
|
||||
"Disable Map Cache": "Disable Map Cache",
|
||||
"Clear All File Cache": "Clear All File Cache",
|
||||
"Are you sure you want to clear all file cache?": "Are you sure you want to clear all file cache?",
|
||||
"Clear Map Data Cache": "Clear Map Data Cache",
|
||||
"Are you sure you want to clear map data cache?": "Are you sure you want to clear map data cache?",
|
||||
"Are you sure you want to re-login?": "¿Seguro que deseas volver a iniciar sesión?",
|
||||
"Exchange Rates Data": "Tipos de Cambio",
|
||||
"User Custom": "User Custom",
|
||||
|
|
|
|||
|
|
@ -2512,9 +2512,13 @@
|
|||
"Resource Files": "Resource Files",
|
||||
"Map Data": "Map Data",
|
||||
"Others": "Others",
|
||||
"Failed to load browser cache statistics": "Failed to load browser cache statistics",
|
||||
"Clear File Cache": "Clear File Cache",
|
||||
"Are you sure you want to clear file cache?": "Are you sure you want to clear file cache?",
|
||||
"Cache Expiration Time": "Cache Expiration Time",
|
||||
"Cache Expiration for Map Data": "Cache Expiration for Map Data",
|
||||
"Disable Map Cache": "Disable Map Cache",
|
||||
"Clear All File Cache": "Clear All File Cache",
|
||||
"Are you sure you want to clear all file cache?": "Are you sure you want to clear all file cache?",
|
||||
"Clear Map Data Cache": "Clear Map Data Cache",
|
||||
"Are you sure you want to clear map data cache?": "Are you sure you want to clear map data cache?",
|
||||
"Are you sure you want to re-login?": "Êtes-vous sûr de vouloir vous reconnecter ?",
|
||||
"Exchange Rates Data": "Données de taux de change",
|
||||
"User Custom": "Personnalisé utilisateur",
|
||||
|
|
|
|||
|
|
@ -2512,9 +2512,13 @@
|
|||
"Resource Files": "Resource Files",
|
||||
"Map Data": "Map Data",
|
||||
"Others": "Others",
|
||||
"Failed to load browser cache statistics": "Failed to load browser cache statistics",
|
||||
"Clear File Cache": "Clear File Cache",
|
||||
"Are you sure you want to clear file cache?": "Are you sure you want to clear file cache?",
|
||||
"Cache Expiration Time": "Cache Expiration Time",
|
||||
"Cache Expiration for Map Data": "Cache Expiration for Map Data",
|
||||
"Disable Map Cache": "Disable Map Cache",
|
||||
"Clear All File Cache": "Clear All File Cache",
|
||||
"Are you sure you want to clear all file cache?": "Are you sure you want to clear all file cache?",
|
||||
"Clear Map Data Cache": "Clear Map Data Cache",
|
||||
"Are you sure you want to clear map data cache?": "Are you sure you want to clear map data cache?",
|
||||
"Are you sure you want to re-login?": "Sei sicuro di voler accedere di nuovo?",
|
||||
"Exchange Rates Data": "Dati tassi di cambio",
|
||||
"User Custom": "User Custom",
|
||||
|
|
|
|||
|
|
@ -2512,9 +2512,13 @@
|
|||
"Resource Files": "Resource Files",
|
||||
"Map Data": "Map Data",
|
||||
"Others": "Others",
|
||||
"Failed to load browser cache statistics": "Failed to load browser cache statistics",
|
||||
"Clear File Cache": "Clear File Cache",
|
||||
"Are you sure you want to clear file cache?": "Are you sure you want to clear file cache?",
|
||||
"Cache Expiration Time": "Cache Expiration Time",
|
||||
"Cache Expiration for Map Data": "Cache Expiration for Map Data",
|
||||
"Disable Map Cache": "Disable Map Cache",
|
||||
"Clear All File Cache": "Clear All File Cache",
|
||||
"Are you sure you want to clear all file cache?": "Are you sure you want to clear all file cache?",
|
||||
"Clear Map Data Cache": "Clear Map Data Cache",
|
||||
"Are you sure you want to clear map data cache?": "Are you sure you want to clear map data cache?",
|
||||
"Are you sure you want to re-login?": "再ログインしますか?",
|
||||
"Exchange Rates Data": "為替レートデータ",
|
||||
"User Custom": "User Custom",
|
||||
|
|
|
|||
|
|
@ -2512,9 +2512,13 @@
|
|||
"Resource Files": "Resource Files",
|
||||
"Map Data": "Map Data",
|
||||
"Others": "Others",
|
||||
"Failed to load browser cache statistics": "Failed to load browser cache statistics",
|
||||
"Clear File Cache": "Clear File Cache",
|
||||
"Are you sure you want to clear file cache?": "Are you sure you want to clear file cache?",
|
||||
"Cache Expiration Time": "Cache Expiration Time",
|
||||
"Cache Expiration for Map Data": "Cache Expiration for Map Data",
|
||||
"Disable Map Cache": "Disable Map Cache",
|
||||
"Clear All File Cache": "Clear All File Cache",
|
||||
"Are you sure you want to clear all file cache?": "Are you sure you want to clear all file cache?",
|
||||
"Clear Map Data Cache": "Clear Map Data Cache",
|
||||
"Are you sure you want to clear map data cache?": "Are you sure you want to clear map data cache?",
|
||||
"Are you sure you want to re-login?": "ಮತ್ತೆ ಲಾಗಿನ್ ಮಾಡಲು ನೀವು ಖಚಿತವೇ?",
|
||||
"Exchange Rates Data": "ವಿನಿಮಯ ದರ ಡೇಟಾ",
|
||||
"User Custom": "ಬಳಕೆದಾರ ಕಸ್ಟಮ್",
|
||||
|
|
|
|||
|
|
@ -2512,9 +2512,13 @@
|
|||
"Resource Files": "Resource Files",
|
||||
"Map Data": "Map Data",
|
||||
"Others": "Others",
|
||||
"Failed to load browser cache statistics": "Failed to load browser cache statistics",
|
||||
"Clear File Cache": "Clear File Cache",
|
||||
"Are you sure you want to clear file cache?": "Are you sure you want to clear file cache?",
|
||||
"Cache Expiration Time": "Cache Expiration Time",
|
||||
"Cache Expiration for Map Data": "Cache Expiration for Map Data",
|
||||
"Disable Map Cache": "Disable Map Cache",
|
||||
"Clear All File Cache": "Clear All File Cache",
|
||||
"Are you sure you want to clear all file cache?": "Are you sure you want to clear all file cache?",
|
||||
"Clear Map Data Cache": "Clear Map Data Cache",
|
||||
"Are you sure you want to clear map data cache?": "Are you sure you want to clear map data cache?",
|
||||
"Are you sure you want to re-login?": "다시 로그인하시겠습니까?",
|
||||
"Exchange Rates Data": "환율 데이터",
|
||||
"User Custom": "사용자 정의",
|
||||
|
|
|
|||
|
|
@ -2512,9 +2512,13 @@
|
|||
"Resource Files": "Resource Files",
|
||||
"Map Data": "Map Data",
|
||||
"Others": "Others",
|
||||
"Failed to load browser cache statistics": "Failed to load browser cache statistics",
|
||||
"Clear File Cache": "Clear File Cache",
|
||||
"Are you sure you want to clear file cache?": "Are you sure you want to clear file cache?",
|
||||
"Cache Expiration Time": "Cache Expiration Time",
|
||||
"Cache Expiration for Map Data": "Cache Expiration for Map Data",
|
||||
"Disable Map Cache": "Disable Map Cache",
|
||||
"Clear All File Cache": "Clear All File Cache",
|
||||
"Are you sure you want to clear all file cache?": "Are you sure you want to clear all file cache?",
|
||||
"Clear Map Data Cache": "Clear Map Data Cache",
|
||||
"Are you sure you want to clear map data cache?": "Are you sure you want to clear map data cache?",
|
||||
"Are you sure you want to re-login?": "Weet je zeker dat je opnieuw wilt inloggen?",
|
||||
"Exchange Rates Data": "Wisselkoersgegevens",
|
||||
"User Custom": "Gebruiker aangepast",
|
||||
|
|
|
|||
|
|
@ -2512,9 +2512,13 @@
|
|||
"Resource Files": "Resource Files",
|
||||
"Map Data": "Map Data",
|
||||
"Others": "Others",
|
||||
"Failed to load browser cache statistics": "Failed to load browser cache statistics",
|
||||
"Clear File Cache": "Clear File Cache",
|
||||
"Are you sure you want to clear file cache?": "Are you sure you want to clear file cache?",
|
||||
"Cache Expiration Time": "Cache Expiration Time",
|
||||
"Cache Expiration for Map Data": "Cache Expiration for Map Data",
|
||||
"Disable Map Cache": "Disable Map Cache",
|
||||
"Clear All File Cache": "Clear All File Cache",
|
||||
"Are you sure you want to clear all file cache?": "Are you sure you want to clear all file cache?",
|
||||
"Clear Map Data Cache": "Clear Map Data Cache",
|
||||
"Are you sure you want to clear map data cache?": "Are you sure you want to clear map data cache?",
|
||||
"Are you sure you want to re-login?": "Tem certeza de que deseja fazer login novamente?",
|
||||
"Exchange Rates Data": "Dados de Taxas de Câmbio",
|
||||
"User Custom": "Personalização do Usuário",
|
||||
|
|
|
|||
|
|
@ -2512,9 +2512,13 @@
|
|||
"Resource Files": "Resource Files",
|
||||
"Map Data": "Map Data",
|
||||
"Others": "Others",
|
||||
"Failed to load browser cache statistics": "Failed to load browser cache statistics",
|
||||
"Clear File Cache": "Clear File Cache",
|
||||
"Are you sure you want to clear file cache?": "Are you sure you want to clear file cache?",
|
||||
"Cache Expiration Time": "Cache Expiration Time",
|
||||
"Cache Expiration for Map Data": "Cache Expiration for Map Data",
|
||||
"Disable Map Cache": "Disable Map Cache",
|
||||
"Clear All File Cache": "Clear All File Cache",
|
||||
"Are you sure you want to clear all file cache?": "Are you sure you want to clear all file cache?",
|
||||
"Clear Map Data Cache": "Clear Map Data Cache",
|
||||
"Are you sure you want to clear map data cache?": "Are you sure you want to clear map data cache?",
|
||||
"Are you sure you want to re-login?": "Вы уверены, что хотите войти снова?",
|
||||
"Exchange Rates Data": "Данные о курсах валют",
|
||||
"User Custom": "Пользовательские настройки",
|
||||
|
|
|
|||
|
|
@ -2512,9 +2512,13 @@
|
|||
"Resource Files": "Resource Files",
|
||||
"Map Data": "Map Data",
|
||||
"Others": "Others",
|
||||
"Failed to load browser cache statistics": "Failed to load browser cache statistics",
|
||||
"Clear File Cache": "Clear File Cache",
|
||||
"Are you sure you want to clear file cache?": "Are you sure you want to clear file cache?",
|
||||
"Cache Expiration Time": "Cache Expiration Time",
|
||||
"Cache Expiration for Map Data": "Cache Expiration for Map Data",
|
||||
"Disable Map Cache": "Disable Map Cache",
|
||||
"Clear All File Cache": "Clear All File Cache",
|
||||
"Are you sure you want to clear all file cache?": "Are you sure you want to clear all file cache?",
|
||||
"Clear Map Data Cache": "Clear Map Data Cache",
|
||||
"Are you sure you want to clear map data cache?": "Are you sure you want to clear map data cache?",
|
||||
"Are you sure you want to re-login?": "Ali ste prepričani, da se želite ponovno prijaviti?",
|
||||
"Exchange Rates Data": "Podatki o menjalnih tečajih",
|
||||
"User Custom": "Uporabniške nastavitve po meri",
|
||||
|
|
|
|||
|
|
@ -2512,9 +2512,13 @@
|
|||
"Resource Files": "Resource Files",
|
||||
"Map Data": "Map Data",
|
||||
"Others": "Others",
|
||||
"Failed to load browser cache statistics": "Failed to load browser cache statistics",
|
||||
"Clear File Cache": "Clear File Cache",
|
||||
"Are you sure you want to clear file cache?": "Are you sure you want to clear file cache?",
|
||||
"Cache Expiration Time": "Cache Expiration Time",
|
||||
"Cache Expiration for Map Data": "Cache Expiration for Map Data",
|
||||
"Disable Map Cache": "Disable Map Cache",
|
||||
"Clear All File Cache": "Clear All File Cache",
|
||||
"Are you sure you want to clear all file cache?": "Are you sure you want to clear all file cache?",
|
||||
"Clear Map Data Cache": "Clear Map Data Cache",
|
||||
"Are you sure you want to clear map data cache?": "Are you sure you want to clear map data cache?",
|
||||
"Are you sure you want to re-login?": "மீண்டும் உள்நுழை செய்ய நீங்கள் உறுதியா?",
|
||||
"Exchange Rates Data": "மாற்று விகிதம் தரவு",
|
||||
"User Custom": "தனிப்பயன்",
|
||||
|
|
|
|||
|
|
@ -2512,9 +2512,13 @@
|
|||
"Resource Files": "Resource Files",
|
||||
"Map Data": "Map Data",
|
||||
"Others": "Others",
|
||||
"Failed to load browser cache statistics": "Failed to load browser cache statistics",
|
||||
"Clear File Cache": "Clear File Cache",
|
||||
"Are you sure you want to clear file cache?": "Are you sure you want to clear file cache?",
|
||||
"Cache Expiration Time": "Cache Expiration Time",
|
||||
"Cache Expiration for Map Data": "Cache Expiration for Map Data",
|
||||
"Disable Map Cache": "Disable Map Cache",
|
||||
"Clear All File Cache": "Clear All File Cache",
|
||||
"Are you sure you want to clear all file cache?": "Are you sure you want to clear all file cache?",
|
||||
"Clear Map Data Cache": "Clear Map Data Cache",
|
||||
"Are you sure you want to clear map data cache?": "Are you sure you want to clear map data cache?",
|
||||
"Are you sure you want to re-login?": "คุณแน่ใจหรือว่าต้องการเข้าสู่ระบบอีกครั้ง?",
|
||||
"Exchange Rates Data": "ข้อมูลอัตราแลกเปลี่ยน",
|
||||
"User Custom": "กำหนดเองโดยผู้ใช้",
|
||||
|
|
|
|||
|
|
@ -2512,9 +2512,13 @@
|
|||
"Resource Files": "Resource Files",
|
||||
"Map Data": "Map Data",
|
||||
"Others": "Others",
|
||||
"Failed to load browser cache statistics": "Failed to load browser cache statistics",
|
||||
"Clear File Cache": "Clear File Cache",
|
||||
"Are you sure you want to clear file cache?": "Are you sure you want to clear file cache?",
|
||||
"Cache Expiration Time": "Cache Expiration Time",
|
||||
"Cache Expiration for Map Data": "Cache Expiration for Map Data",
|
||||
"Disable Map Cache": "Disable Map Cache",
|
||||
"Clear All File Cache": "Clear All File Cache",
|
||||
"Are you sure you want to clear all file cache?": "Are you sure you want to clear all file cache?",
|
||||
"Clear Map Data Cache": "Clear Map Data Cache",
|
||||
"Are you sure you want to clear map data cache?": "Are you sure you want to clear map data cache?",
|
||||
"Are you sure you want to re-login?": "Tekrar giriş yapmak istediğinize emin misiniz?",
|
||||
"Exchange Rates Data": "Döviz Kuru Verileri",
|
||||
"User Custom": "Kullanıcı Özel",
|
||||
|
|
|
|||
|
|
@ -2512,9 +2512,13 @@
|
|||
"Resource Files": "Resource Files",
|
||||
"Map Data": "Map Data",
|
||||
"Others": "Others",
|
||||
"Failed to load browser cache statistics": "Failed to load browser cache statistics",
|
||||
"Clear File Cache": "Clear File Cache",
|
||||
"Are you sure you want to clear file cache?": "Are you sure you want to clear file cache?",
|
||||
"Cache Expiration Time": "Cache Expiration Time",
|
||||
"Cache Expiration for Map Data": "Cache Expiration for Map Data",
|
||||
"Disable Map Cache": "Disable Map Cache",
|
||||
"Clear All File Cache": "Clear All File Cache",
|
||||
"Are you sure you want to clear all file cache?": "Are you sure you want to clear all file cache?",
|
||||
"Clear Map Data Cache": "Clear Map Data Cache",
|
||||
"Are you sure you want to clear map data cache?": "Are you sure you want to clear map data cache?",
|
||||
"Are you sure you want to re-login?": "Ви впевнені, що хочете увійти знову?",
|
||||
"Exchange Rates Data": "Дані про курси валют",
|
||||
"User Custom": "User Custom",
|
||||
|
|
|
|||
|
|
@ -2512,9 +2512,13 @@
|
|||
"Resource Files": "Resource Files",
|
||||
"Map Data": "Map Data",
|
||||
"Others": "Others",
|
||||
"Failed to load browser cache statistics": "Failed to load browser cache statistics",
|
||||
"Clear File Cache": "Clear File Cache",
|
||||
"Are you sure you want to clear file cache?": "Are you sure you want to clear file cache?",
|
||||
"Cache Expiration Time": "Cache Expiration Time",
|
||||
"Cache Expiration for Map Data": "Cache Expiration for Map Data",
|
||||
"Disable Map Cache": "Disable Map Cache",
|
||||
"Clear All File Cache": "Clear All File Cache",
|
||||
"Are you sure you want to clear all file cache?": "Are you sure you want to clear all file cache?",
|
||||
"Clear Map Data Cache": "Clear Map Data Cache",
|
||||
"Are you sure you want to clear map data cache?": "Are you sure you want to clear map data cache?",
|
||||
"Are you sure you want to re-login?": "Bạn có chắc chắn muốn đăng nhập lại không?",
|
||||
"Exchange Rates Data": "Dữ liệu tỷ giá hối đoái",
|
||||
"User Custom": "User Custom",
|
||||
|
|
|
|||
|
|
@ -2512,9 +2512,13 @@
|
|||
"Resource Files": "资源文件",
|
||||
"Map Data": "地图数据",
|
||||
"Others": "其他",
|
||||
"Failed to load browser cache statistics": "加载浏览器缓存统计数据失败",
|
||||
"Clear File Cache": "清除文件缓存",
|
||||
"Are you sure you want to clear file cache?": "您确定要清除文件缓存?",
|
||||
"Cache Expiration Time": "缓存过期时间",
|
||||
"Cache Expiration for Map Data": "地图数据缓存过期时间",
|
||||
"Disable Map Cache": "禁用地图缓存",
|
||||
"Clear All File Cache": "清除所有文件缓存",
|
||||
"Are you sure you want to clear all file cache?": "您确定要清除所有文件缓存?",
|
||||
"Clear Map Data Cache": "清除地图数据缓存",
|
||||
"Are you sure you want to clear map data cache?": "您确定要清除地图数据缓存?",
|
||||
"Are you sure you want to re-login?": "您确定要重新登录?",
|
||||
"Exchange Rates Data": "汇率数据",
|
||||
"User Custom": "用户自定义",
|
||||
|
|
|
|||
|
|
@ -2512,9 +2512,13 @@
|
|||
"Resource Files": "資源檔案",
|
||||
"Map Data": "地圖資料",
|
||||
"Others": "其他",
|
||||
"Failed to load browser cache statistics": "載入瀏覽器快取統計資料失敗",
|
||||
"Clear File Cache": "清除檔案快取",
|
||||
"Are you sure you want to clear file cache?": "您確定要清除檔案快取?",
|
||||
"Cache Expiration Time": "快取過期時間",
|
||||
"Cache Expiration for Map Data": "地圖資料快取過期時間",
|
||||
"Disable Map Cache": "停用地圖快取",
|
||||
"Clear All File Cache": "清除所有檔案快取",
|
||||
"Are you sure you want to clear all file cache?": "您確定要清除所有檔案快取?",
|
||||
"Clear Map Data Cache": "清除地圖資料快取",
|
||||
"Are you sure you want to clear map data cache?": "您確定要清除地圖資料快取?",
|
||||
"Are you sure you want to re-login?": "您確定要重新登入?",
|
||||
"Exchange Rates Data": "匯率資料",
|
||||
"User Custom": "使用者自訂",
|
||||
|
|
|
|||
|
|
@ -310,6 +310,12 @@ export const useSettingsStore = defineStore('settings', () => {
|
|||
updateUserApplicationCloudSettingValue('currencySortByInExchangeRatesPage', value);
|
||||
}
|
||||
|
||||
// Browser Cache Settings
|
||||
function setMapCacheExpiration(value: number): void {
|
||||
updateApplicationSettingsValue('mapCacheExpiration', value);
|
||||
appSettings.value.mapCacheExpiration = value;
|
||||
}
|
||||
|
||||
// Statistics Settings
|
||||
function setStatisticsDefaultChartDataType(value: number): void {
|
||||
updateApplicationSettingsSubValue('statistics', 'defaultChartDataType', value);
|
||||
|
|
@ -531,6 +537,8 @@ export const useSettingsStore = defineStore('settings', () => {
|
|||
setHideCategoriesWithoutAccounts,
|
||||
// -- Exchange Rates Data Page
|
||||
setCurrencySortByInExchangeRatesPage,
|
||||
// -- Browser Cache Settings
|
||||
setMapCacheExpiration,
|
||||
// -- Statistics Settings
|
||||
setStatisticsDefaultChartDataType,
|
||||
setStatisticsDefaultTimezoneType,
|
||||
|
|
|
|||
309
src/sw.ts
Normal file
309
src/sw.ts
Normal file
|
|
@ -0,0 +1,309 @@
|
|||
import { clientsClaim } from 'workbox-core';
|
||||
import type {
|
||||
WorkboxPlugin,
|
||||
CacheDidUpdateCallbackParam,
|
||||
CacheKeyWillBeUsedCallbackParam,
|
||||
CacheWillUpdateCallbackParam,
|
||||
CachedResponseWillBeUsedCallbackParam
|
||||
} from 'workbox-core/types';
|
||||
import { cleanupOutdatedCaches, precacheAndRoute } from 'workbox-precaching';
|
||||
import { registerRoute } from 'workbox-routing';
|
||||
import { CacheFirst, NetworkFirst, StaleWhileRevalidate } from 'workbox-strategies';
|
||||
|
||||
interface CacheTimestampEntry {
|
||||
request: Request;
|
||||
time: number;
|
||||
}
|
||||
|
||||
class DynamicExpirationPlugin implements WorkboxPlugin {
|
||||
private static readonly SW_CACHE_TIME_HEADER: string = 'ezbookkeeping-sw-cache-time';
|
||||
private maxEntries: number;
|
||||
private maxAgeMilliseconds: number;
|
||||
private cleaningCache: boolean = false;
|
||||
|
||||
constructor(maxEntries: number, maxAgeMilliseconds: number) {
|
||||
this.maxEntries = maxEntries;
|
||||
this.maxAgeMilliseconds = maxAgeMilliseconds;
|
||||
}
|
||||
|
||||
public getMaxEntries(): number {
|
||||
return this.maxEntries;
|
||||
}
|
||||
|
||||
public setMaxEntries(maxEntries: number): void {
|
||||
this.maxEntries = maxEntries;
|
||||
}
|
||||
|
||||
public getMaxAgeMilliseconds(): number {
|
||||
return this.maxAgeMilliseconds;
|
||||
}
|
||||
|
||||
public setMaxAgeMilliseconds(maxAgeMilliseconds: number): void {
|
||||
this.maxAgeMilliseconds = maxAgeMilliseconds;
|
||||
}
|
||||
|
||||
public async cacheWillUpdate(param: CacheWillUpdateCallbackParam): Promise<Response | null> {
|
||||
const response = param.response;
|
||||
|
||||
if (!response || response.status < 200 || response.status >= 300 || response.type === 'opaque') {
|
||||
return null;
|
||||
}
|
||||
|
||||
const body = await response.blob();
|
||||
const headers = new Headers(response.headers);
|
||||
headers.set(DynamicExpirationPlugin.SW_CACHE_TIME_HEADER, Date.now().toString());
|
||||
|
||||
return new Response(body, {
|
||||
status: response.status,
|
||||
statusText: response.statusText,
|
||||
headers: headers
|
||||
});
|
||||
}
|
||||
|
||||
public async cachedResponseWillBeUsed(param: CachedResponseWillBeUsedCallbackParam): Promise<Response | null> {
|
||||
const cachedResponse = param.cachedResponse;
|
||||
|
||||
if (!cachedResponse) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const cacheTime: string | null = cachedResponse.headers.get(DynamicExpirationPlugin.SW_CACHE_TIME_HEADER);
|
||||
|
||||
if (!cacheTime) {
|
||||
return cachedResponse;
|
||||
}
|
||||
|
||||
const age: number = Date.now() - Number(cacheTime);
|
||||
|
||||
if (this.maxAgeMilliseconds > 0 && age >= this.maxAgeMilliseconds) {
|
||||
if (param.cacheName) {
|
||||
const cache = await caches.open(param.cacheName);
|
||||
await cache.delete(param.request);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
return cachedResponse;
|
||||
}
|
||||
|
||||
public async cacheDidUpdate(param: CacheDidUpdateCallbackParam): Promise<void> {
|
||||
if (this.cleaningCache || !param.cacheName) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.cleaningCache = true;
|
||||
|
||||
const cache: Cache = await caches.open(param.cacheName);
|
||||
const requests: readonly Request[] = await cache.keys();
|
||||
|
||||
if (requests.length <= this.maxEntries) {
|
||||
this.cleaningCache = false;
|
||||
return;
|
||||
}
|
||||
|
||||
const entries: CacheTimestampEntry[] = [];
|
||||
|
||||
for (const request of requests) {
|
||||
const response: Response | undefined = await cache.match(request);
|
||||
|
||||
if (!response) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const cacheTime: string | null = response.headers.get(DynamicExpirationPlugin.SW_CACHE_TIME_HEADER);
|
||||
let time: number = cacheTime ? Number(cacheTime) : 0;
|
||||
|
||||
if (Number.isFinite(time)) {
|
||||
const age: number = Date.now() - time;
|
||||
|
||||
if (this.maxAgeMilliseconds > 0 && age >= this.maxAgeMilliseconds) {
|
||||
await cache.delete(request);
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
time = 0;
|
||||
}
|
||||
|
||||
entries.push({
|
||||
request: request,
|
||||
time: time
|
||||
});
|
||||
}
|
||||
|
||||
if (entries.length <= this.maxEntries) {
|
||||
this.cleaningCache = false;
|
||||
return;
|
||||
}
|
||||
|
||||
entries.sort((a, b) => a.time - b.time);
|
||||
|
||||
const removeCount: number = entries.length - this.maxEntries;
|
||||
|
||||
for (let i = 0; i < removeCount; i++) {
|
||||
const entry = entries[i];
|
||||
|
||||
if (entry && entry.request) {
|
||||
await cache.delete(entry.request);
|
||||
}
|
||||
}
|
||||
|
||||
this.cleaningCache = false;
|
||||
}
|
||||
}
|
||||
|
||||
class MapDataRequestStripTokenPlugin implements WorkboxPlugin {
|
||||
public async cacheKeyWillBeUsed(param: CacheKeyWillBeUsedCallbackParam): Promise<Request> {
|
||||
const url = new URL(param.request.url);
|
||||
|
||||
if (url.searchParams.has('token')) {
|
||||
url.searchParams.delete('token');
|
||||
return new Request(url.href, param.request);
|
||||
}
|
||||
|
||||
return param.request;
|
||||
}
|
||||
}
|
||||
|
||||
interface MapCacheConfig {
|
||||
enabled: boolean;
|
||||
patterns: RegExp[];
|
||||
mapDataRequestStripTokenPlugin: MapDataRequestStripTokenPlugin;
|
||||
expirationPlugin: DynamicExpirationPlugin;
|
||||
}
|
||||
|
||||
declare const self: ServiceWorkerGlobalScope;
|
||||
|
||||
const SW_ASSETS_CACHE_NAME: string = 'ezbookkeeping-assets-cache';
|
||||
const SW_CODE_CACHE_NAME: string = 'ezbookkeeping-code-cache';
|
||||
const SW_MAP_CACHE_NAME: string = 'ezbookkeeping-map-cache';
|
||||
|
||||
const SW_MESSAGE_TYPE_UPDATE_MAP_CACHE_CONFIG: string = 'UPDATE_MAP_CACHE_CONFIG';
|
||||
const SW_MESSAGE_TYPE_UPDATE_MAP_CACHE_CONFIG_RESPONSE: string = 'UPDATE_MAP_CACHE_CONFIG_RESPONSE';
|
||||
|
||||
const DEFAULT_MAP_CACHE_MAX_ENTRIES: number = 1000;
|
||||
const DEFAULT_MAP_CACHE_MAX_AGE_MILLISECONDS: number = 30 * 24 * 60 * 60 * 1000;
|
||||
|
||||
const mapCacheConfig: MapCacheConfig = {
|
||||
enabled: false,
|
||||
patterns: [],
|
||||
mapDataRequestStripTokenPlugin: new MapDataRequestStripTokenPlugin(),
|
||||
expirationPlugin: new DynamicExpirationPlugin(DEFAULT_MAP_CACHE_MAX_ENTRIES, DEFAULT_MAP_CACHE_MAX_AGE_MILLISECONDS)
|
||||
};
|
||||
|
||||
self.skipWaiting();
|
||||
clientsClaim();
|
||||
precacheAndRoute(self.__WB_MANIFEST);
|
||||
cleanupOutdatedCaches();
|
||||
|
||||
registerRoute(
|
||||
/.*\/img\/desktop\/.*\.(png|jpg|jpeg|gif|tiff|bmp|svg)/,
|
||||
new StaleWhileRevalidate({
|
||||
cacheName: SW_ASSETS_CACHE_NAME,
|
||||
})
|
||||
);
|
||||
|
||||
registerRoute(
|
||||
/.*\/fonts\/.*\.(eot|ttf|svg|woff)/,
|
||||
new CacheFirst({
|
||||
cacheName: SW_ASSETS_CACHE_NAME,
|
||||
})
|
||||
);
|
||||
|
||||
registerRoute(
|
||||
/.*\/(mobile|mobile\/|desktop|desktop\/)$/,
|
||||
new NetworkFirst({
|
||||
cacheName: SW_CODE_CACHE_NAME,
|
||||
})
|
||||
);
|
||||
|
||||
registerRoute(
|
||||
/.*\/(mobile|mobile\/)#!\//,
|
||||
new NetworkFirst({
|
||||
cacheName: SW_CODE_CACHE_NAME,
|
||||
})
|
||||
);
|
||||
|
||||
registerRoute(
|
||||
/.*\/(desktop|desktop\/)#\//,
|
||||
new NetworkFirst({
|
||||
cacheName: SW_CODE_CACHE_NAME,
|
||||
})
|
||||
);
|
||||
|
||||
registerRoute(
|
||||
/.*\/(index\.html|mobile\.html|desktop\.html)/,
|
||||
new NetworkFirst({
|
||||
cacheName: SW_CODE_CACHE_NAME,
|
||||
})
|
||||
);
|
||||
|
||||
registerRoute(
|
||||
/.*\/css\/.*\.css/,
|
||||
new CacheFirst({
|
||||
cacheName: SW_CODE_CACHE_NAME,
|
||||
})
|
||||
);
|
||||
|
||||
registerRoute(
|
||||
/.*\/js\/.*\.js/,
|
||||
new CacheFirst({
|
||||
cacheName: SW_CODE_CACHE_NAME,
|
||||
})
|
||||
);
|
||||
|
||||
registerRoute(
|
||||
({ url }) => {
|
||||
if (!mapCacheConfig.enabled || mapCacheConfig.patterns.length < 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (const pattern of mapCacheConfig.patterns) {
|
||||
if (pattern.test && pattern.test(url.href)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
new CacheFirst({
|
||||
cacheName: SW_MAP_CACHE_NAME,
|
||||
plugins: [
|
||||
mapCacheConfig.mapDataRequestStripTokenPlugin,
|
||||
mapCacheConfig.expirationPlugin
|
||||
]
|
||||
})
|
||||
);
|
||||
|
||||
self.addEventListener('message', (event: ExtendableMessageEvent) => {
|
||||
try {
|
||||
if (event.data && event.data.type === SW_MESSAGE_TYPE_UPDATE_MAP_CACHE_CONFIG && 'payload' in event.data) {
|
||||
mapCacheConfig.enabled = !!event.data.payload['enabled'];
|
||||
mapCacheConfig.patterns = [];
|
||||
mapCacheConfig.expirationPlugin.setMaxEntries(event.data.payload['maxEntries'] ?? DEFAULT_MAP_CACHE_MAX_ENTRIES);
|
||||
mapCacheConfig.expirationPlugin.setMaxAgeMilliseconds(event.data.payload['maxAgeMilliseconds'] ?? DEFAULT_MAP_CACHE_MAX_AGE_MILLISECONDS);
|
||||
|
||||
if (event.data.payload['patterns'] && Array.isArray(event.data.payload['patterns'])) {
|
||||
for (const pattern of event.data.payload['patterns']) {
|
||||
if (pattern) {
|
||||
mapCacheConfig.patterns.push(new RegExp(pattern as string));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (event.ports && event.ports[0] && typeof event.ports[0].postMessage === 'function') {
|
||||
event.ports[0].postMessage({
|
||||
type: SW_MESSAGE_TYPE_UPDATE_MAP_CACHE_CONFIG_RESPONSE,
|
||||
payload: {
|
||||
enabled: mapCacheConfig.enabled,
|
||||
patterns: event.data.payload['patterns'],
|
||||
maxEntries: mapCacheConfig.expirationPlugin.getMaxEntries(),
|
||||
maxAgeMilliseconds: mapCacheConfig.expirationPlugin.getMaxAgeMilliseconds()
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
} catch (ex) {
|
||||
console.error('failed to process message in service worker', ex);
|
||||
}
|
||||
});
|
||||
|
|
@ -1,12 +1,12 @@
|
|||
<template>
|
||||
<v-row>
|
||||
<v-col cols="12">
|
||||
<v-card :class="{ 'disabled': loadingCacheStatistics }">
|
||||
<v-col cols="12" v-if="isSupportedFileCache">
|
||||
<v-card :class="{ 'disabled': loading }">
|
||||
<template #title>
|
||||
<div class="d-flex align-center">
|
||||
<span>{{ tt('File Cache') }}</span>
|
||||
<v-btn density="compact" color="default" variant="text" size="24"
|
||||
class="ms-2" :icon="true" :loading="loadingCacheStatistics" @click="reloadCacheStatistics()">
|
||||
class="ms-2" :icon="true" :loading="loading" @click="loadCacheStatistics()">
|
||||
<template #loader>
|
||||
<v-progress-circular indeterminate size="20"/>
|
||||
</template>
|
||||
|
|
@ -16,14 +16,10 @@
|
|||
</div>
|
||||
</template>
|
||||
|
||||
<v-card-text class="mt-1" v-if="loadingCacheStatistics">
|
||||
<v-card-text class="d-flex align-end" style="height: 3rem">
|
||||
<span class="text-body-1">{{ tt('Used storage') }}</span>
|
||||
<v-skeleton-loader class="d-inline-block skeleton-no-margin ml-1 pt-1 pb-1" type="text" style="width: 100px; height: 24px" :loading="true" v-if="loadingCacheStatistics"></v-skeleton-loader>
|
||||
</v-card-text>
|
||||
|
||||
<v-card-text v-else-if="!loadingCacheStatistics">
|
||||
<span class="text-body-1">{{ tt('Used storage') }}</span>
|
||||
<span class="text-xl ml-1" v-if="!loadingCacheStatistics">{{ fileCacheStatistics ? formatVolumeToLocalizedNumerals(fileCacheStatistics.totalCacheSize, 2) : '-' }}</span>
|
||||
<v-skeleton-loader class="d-inline-block skeleton-no-margin ms-1 pt-1 pb-1" type="text" style="width: 100px" :loading="true" v-if="loading"></v-skeleton-loader>
|
||||
<span class="text-xl ms-1" v-if="!loading">{{ fileCacheStatistics ? formatVolumeToLocalizedNumerals(fileCacheStatistics.totalCacheSize, 2) : '-' }}</span>
|
||||
</v-card-text>
|
||||
|
||||
<v-card-text>
|
||||
|
|
@ -63,8 +59,8 @@
|
|||
|
||||
<div class="d-flex flex-column">
|
||||
<span class="text-caption">{{ tt(item.title) }}</span>
|
||||
<v-skeleton-loader class="skeleton-no-margin pt-2 pb-2" type="text" style="width: 100px" :loading="true" v-if="loadingCacheStatistics"></v-skeleton-loader>
|
||||
<span class="text-xl" v-if="!loadingCacheStatistics">{{ item.count }}</span>
|
||||
<v-skeleton-loader class="skeleton-no-margin pt-2 pb-2" type="text" style="width: 100px" :loading="true" v-if="loading"></v-skeleton-loader>
|
||||
<span class="text-xl" v-if="!loading">{{ item.count }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</v-col>
|
||||
|
|
@ -72,9 +68,13 @@
|
|||
</v-card-text>
|
||||
|
||||
<v-card-text class="mt-2">
|
||||
<v-btn color="gray" variant="tonal"
|
||||
:disabled="loadingCacheStatistics || !fileCacheStatistics" @click="clearFileCache()">
|
||||
{{ tt('Clear File Cache') }}
|
||||
<v-btn color="secondary" variant="tonal"
|
||||
:disabled="loading || !isSupportedFileCache || !fileCacheStatistics" @click="clearMapCache()">
|
||||
{{ tt('Clear Map Data Cache') }}
|
||||
</v-btn>
|
||||
<v-btn class="ms-2" color="secondary" variant="tonal"
|
||||
:disabled="loading || !isSupportedFileCache || !fileCacheStatistics" @click="clearAllFileCache()">
|
||||
{{ tt('Clear All File Cache') }}
|
||||
</v-btn>
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
|
|
@ -90,29 +90,49 @@
|
|||
|
||||
<v-card-text>
|
||||
<span class="text-body-1">{{ tt('Used storage') }}</span>
|
||||
<span class="text-xl ml-1">{{ formatVolumeToLocalizedNumerals(exchangeRatesCacheSize ?? 0, 2) }}</span>
|
||||
<span class="text-xl ms-1">{{ formatVolumeToLocalizedNumerals(exchangeRatesCacheSize ?? 0, 2) }}</span>
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
</v-col>
|
||||
|
||||
<v-col cols="12">
|
||||
<v-card :title="tt('Cache Expiration Time')">
|
||||
<v-form>
|
||||
<v-card-text>
|
||||
<v-row>
|
||||
<v-col cols="12" sm="6" v-if="getMapProvider()">
|
||||
<v-select
|
||||
item-title="name"
|
||||
item-value="value"
|
||||
persistent-placeholder
|
||||
:disabled="loading || !isSupportedFileCache || !fileCacheStatistics || isMapProviderUseExternalSDK() || !isMapDataFetchProxyEnabled()"
|
||||
:label="tt('Cache Expiration for Map Data')"
|
||||
:placeholder="tt('Cache Expiration for Map Data')"
|
||||
:items="allMapCacheExpirationOptions"
|
||||
v-model="mapCacheExpiration"
|
||||
/>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</v-card-text>
|
||||
</v-form>
|
||||
</v-card>
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<confirm-dialog ref="confirmDialog"/>
|
||||
<snack-bar ref="snackbar" />
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import ConfirmDialog from '@/components/desktop/ConfirmDialog.vue';
|
||||
import SnackBar from '@/components/desktop/SnackBar.vue';
|
||||
|
||||
import { ref, useTemplateRef } from 'vue';
|
||||
import { useTemplateRef } from 'vue';
|
||||
|
||||
import { useI18n } from '@/locales/helpers.ts';
|
||||
|
||||
import { useExchangeRatesStore } from '@/stores/exchangeRates.ts';
|
||||
import { useAppBrowserCacheSettingPageBase } from '@/views/base/settings/AppBrowserCacheSettingPageBase.ts';
|
||||
|
||||
import { type BrowserCacheStatistics } from '@/core/cache.ts';
|
||||
|
||||
import { loadBrowserCacheStatistics, clearAllBrowserCaches } from '@/lib/cache.ts';
|
||||
import { isMapProviderUseExternalSDK } from '@/lib/map/index.ts';
|
||||
import { getMapProvider, isMapDataFetchProxyEnabled } from '@/lib/server_settings.ts';
|
||||
|
||||
import {
|
||||
mdiRefresh,
|
||||
|
|
@ -123,39 +143,41 @@ import {
|
|||
} from '@mdi/js';
|
||||
|
||||
type ConfirmDialogType = InstanceType<typeof ConfirmDialog>;
|
||||
type SnackBarType = InstanceType<typeof SnackBar>;
|
||||
|
||||
const { tt, formatVolumeToLocalizedNumerals } = useI18n();
|
||||
const {
|
||||
tt,
|
||||
formatVolumeToLocalizedNumerals
|
||||
} = useI18n();
|
||||
|
||||
const exchangeRatesStore = useExchangeRatesStore();
|
||||
const {
|
||||
isSupportedFileCache,
|
||||
loading,
|
||||
fileCacheStatistics,
|
||||
exchangeRatesCacheSize,
|
||||
allMapCacheExpirationOptions,
|
||||
mapCacheExpiration,
|
||||
loadCacheStatistics,
|
||||
clearMapDataCache,
|
||||
clearAllBrowserCaches
|
||||
} = useAppBrowserCacheSettingPageBase();
|
||||
|
||||
const confirmDialog = useTemplateRef<ConfirmDialogType>('confirmDialog');
|
||||
const snackbar = useTemplateRef<SnackBarType>('snackbar');
|
||||
|
||||
const loadingCacheStatistics = ref<boolean>(true);
|
||||
const fileCacheStatistics = ref<BrowserCacheStatistics | undefined>(undefined);
|
||||
const exchangeRatesCacheSize = ref<number | undefined>(undefined);
|
||||
|
||||
function reloadCacheStatistics(): void {
|
||||
loadingCacheStatistics.value = true;
|
||||
|
||||
loadBrowserCacheStatistics().then(statistics => {
|
||||
fileCacheStatistics.value = statistics;
|
||||
exchangeRatesCacheSize.value = exchangeRatesStore.getExchangeRatesCacheSize();
|
||||
loadingCacheStatistics.value = false;
|
||||
}).catch(() => {
|
||||
loadingCacheStatistics.value = false;
|
||||
snackbar.value?.showError('Failed to load browser cache statistics');
|
||||
function clearMapCache(): void {
|
||||
confirmDialog.value?.open('Are you sure you want to clear map data cache?').then(() => {
|
||||
clearMapDataCache().then(() => {
|
||||
loadCacheStatistics();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function clearFileCache(): void {
|
||||
confirmDialog.value?.open('Are you sure you want to clear file cache?').then(() => {
|
||||
function clearAllFileCache(): void {
|
||||
confirmDialog.value?.open('Are you sure you want to clear all file cache?').then(() => {
|
||||
clearAllBrowserCaches().then(() => {
|
||||
location.reload();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
reloadCacheStatistics();
|
||||
loadCacheStatistics();
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -1,14 +1,14 @@
|
|||
<template>
|
||||
<f7-page>
|
||||
<f7-page ptr @ptr:refresh="reloadCacheStatistics">
|
||||
<f7-navbar>
|
||||
<f7-nav-left :class="{ 'disabled': loading }" :back-link="tt('Back')"></f7-nav-left>
|
||||
<f7-nav-title :title="tt('Browser Cache Management')"></f7-nav-title>
|
||||
<f7-nav-right :class="{ 'disabled': loading }">
|
||||
<f7-link icon-f7="ellipsis" :class="{ 'disabled': loading || !fileCacheStatistics }" @click="showMoreActionSheet = true"></f7-link>
|
||||
<f7-link icon-f7="ellipsis" :class="{ 'disabled': loading || !isSupportedFileCache || !fileCacheStatistics }" @click="showMoreActionSheet = true"></f7-link>
|
||||
</f7-nav-right>
|
||||
</f7-navbar>
|
||||
|
||||
<f7-list strong inset dividers class="margin-vertical skeleton-text" v-if="loading">
|
||||
<f7-list strong inset dividers class="margin-vertical skeleton-text" v-if="loading && isSupportedFileCache">
|
||||
<f7-list-item group-title :sortable="false">
|
||||
<small>{{ tt('File Cache') }}</small>
|
||||
</f7-list-item>
|
||||
|
|
@ -26,7 +26,14 @@
|
|||
<f7-list-item title="Used storage" after="Count"></f7-list-item>
|
||||
</f7-list>
|
||||
|
||||
<f7-list strong inset dividers class="margin-vertical" v-if="!loading">
|
||||
<f7-list strong inset dividers class="margin-vertical skeleton-text" v-if="loading">
|
||||
<f7-list-item group-title :sortable="false">
|
||||
<small>{{ tt('Cache Expiration Time') }}</small>
|
||||
</f7-list-item>
|
||||
<f7-list-item title="Map Data" after="Disable Map Cache" v-if="getMapProvider()"></f7-list-item>
|
||||
</f7-list>
|
||||
|
||||
<f7-list strong inset dividers class="margin-vertical" v-if="!loading && isSupportedFileCache">
|
||||
<f7-list-item group-title :sortable="false">
|
||||
<small>{{ tt('File Cache') }}</small>
|
||||
</f7-list-item>
|
||||
|
|
@ -44,10 +51,38 @@
|
|||
<f7-list-item :title="tt('Used storage')" :after="formatVolumeToLocalizedNumerals(exchangeRatesCacheSize ?? 0, 2)"></f7-list-item>
|
||||
</f7-list>
|
||||
|
||||
<f7-list strong inset dividers class="margin-vertical" v-if="!loading">
|
||||
<f7-list-item group-title :sortable="false">
|
||||
<small>{{ tt('Cache Expiration Time') }}</small>
|
||||
</f7-list-item>
|
||||
<f7-list-item
|
||||
link="#"
|
||||
:class="{ 'disabled': loading || !isSupportedFileCache || !fileCacheStatistics || isMapProviderUseExternalSDK() || !isMapDataFetchProxyEnabled() }"
|
||||
:title="tt('Map Data')"
|
||||
:after="findNameByValue(allMapCacheExpirationOptions, mapCacheExpiration)"
|
||||
@click="showMapDataCacheExpirationPopup = true"
|
||||
v-if="getMapProvider()"
|
||||
>
|
||||
<list-item-selection-popup value-type="item"
|
||||
key-field="value" value-field="value"
|
||||
title-field="name"
|
||||
:title="tt('Cache Expiration for Map Data')"
|
||||
:enable-filter="true"
|
||||
:filter-placeholder="tt('Expiration Time')"
|
||||
:filter-no-items-text="tt('No results')"
|
||||
:items="allMapCacheExpirationOptions"
|
||||
v-model:show="showMapDataCacheExpirationPopup"
|
||||
v-model="mapCacheExpiration">
|
||||
</list-item-selection-popup>
|
||||
</f7-list-item>
|
||||
</f7-list>
|
||||
|
||||
<f7-actions close-by-outside-click close-on-escape :opened="showMoreActionSheet" @actions:closed="showMoreActionSheet = false">
|
||||
<f7-actions-group>
|
||||
<f7-actions-button :class="{ 'disabled': loading || !fileCacheStatistics }"
|
||||
@click="clearFileCache">{{ tt('Clear File Cache') }}</f7-actions-button>
|
||||
<f7-actions-group v-if="isSupportedFileCache && fileCacheStatistics">
|
||||
<f7-actions-button :class="{ 'disabled': loading || !isSupportedFileCache || !fileCacheStatistics }"
|
||||
@click="clearMapCache">{{ tt('Clear Map Data Cache') }}</f7-actions-button>
|
||||
<f7-actions-button :class="{ 'disabled': loading || !isSupportedFileCache || !fileCacheStatistics }"
|
||||
@click="clearAllFileCache">{{ tt('Clear All File Cache') }}</f7-actions-button>
|
||||
</f7-actions-group>
|
||||
<f7-actions-group>
|
||||
<f7-actions-button bold close>{{ tt('Cancel') }}</f7-actions-button>
|
||||
|
|
@ -62,42 +97,57 @@ import { ref } from 'vue';
|
|||
import { useI18n } from '@/locales/helpers.ts';
|
||||
import { useI18nUIComponents } from '@/lib/ui/mobile.ts';
|
||||
|
||||
import { useExchangeRatesStore } from '@/stores/exchangeRates.ts';
|
||||
import { useAppBrowserCacheSettingPageBase } from '@/views/base/settings/AppBrowserCacheSettingPageBase.ts';
|
||||
|
||||
import { type BrowserCacheStatistics } from '@/core/cache.ts';
|
||||
|
||||
import { loadBrowserCacheStatistics, clearAllBrowserCaches } from '@/lib/cache.ts';
|
||||
import { findNameByValue } from '@/lib/common.ts';
|
||||
import { isMapProviderUseExternalSDK } from '@/lib/map/index.ts';
|
||||
import { getMapProvider, isMapDataFetchProxyEnabled } from '@/lib/server_settings.ts';
|
||||
|
||||
const { tt, formatVolumeToLocalizedNumerals } = useI18n();
|
||||
const { showConfirm, showToast } = useI18nUIComponents();
|
||||
const { showConfirm } = useI18nUIComponents();
|
||||
|
||||
const exchangeRatesStore = useExchangeRatesStore();
|
||||
const {
|
||||
isSupportedFileCache,
|
||||
loading,
|
||||
fileCacheStatistics,
|
||||
exchangeRatesCacheSize,
|
||||
allMapCacheExpirationOptions,
|
||||
mapCacheExpiration,
|
||||
loadCacheStatistics,
|
||||
clearMapDataCache,
|
||||
clearAllBrowserCaches
|
||||
} = useAppBrowserCacheSettingPageBase();
|
||||
|
||||
const loading = ref<boolean>(true);
|
||||
const showMapDataCacheExpirationPopup = ref<boolean>(false);
|
||||
const showMoreActionSheet = ref<boolean>(false);
|
||||
const fileCacheStatistics = ref<BrowserCacheStatistics | undefined>(undefined);
|
||||
const exchangeRatesCacheSize = ref<number | undefined>(undefined);
|
||||
|
||||
function reloadCacheStatistics(): void {
|
||||
loading.value = true;
|
||||
|
||||
loadBrowserCacheStatistics().then(statistics => {
|
||||
fileCacheStatistics.value = statistics;
|
||||
exchangeRatesCacheSize.value = exchangeRatesStore.getExchangeRatesCacheSize();
|
||||
loading.value = false;
|
||||
function reloadCacheStatistics(done?: () => void): void {
|
||||
loadCacheStatistics().then(() => {
|
||||
if (done) {
|
||||
done();
|
||||
}
|
||||
}).catch(() => {
|
||||
loading.value = false;
|
||||
showToast('Failed to load browser cache statistics');
|
||||
if (done) {
|
||||
done();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function clearFileCache(): void {
|
||||
showConfirm('Are you sure you want to clear file cache?', () => {
|
||||
function clearMapCache(): void {
|
||||
showConfirm('Are you sure you want to clear map data cache?', () => {
|
||||
clearMapDataCache().then(() => {
|
||||
loadCacheStatistics();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function clearAllFileCache(): void {
|
||||
showConfirm('Are you sure you want to clear all file cache?', () => {
|
||||
clearAllBrowserCaches().then(() => {
|
||||
location.reload();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
reloadCacheStatistics();
|
||||
loadCacheStatistics();
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
"extends": "@vue/tsconfig/tsconfig.dom.json",
|
||||
"compilerOptions": {
|
||||
"target": "ES2022",
|
||||
"lib": ["DOM", "ES2022"],
|
||||
"lib": ["DOM", "ES2022", "WebWorker"],
|
||||
"types": ["vite/client"],
|
||||
"strict": true,
|
||||
"noImplicitReturns": true,
|
||||
|
|
|
|||
|
|
@ -112,10 +112,11 @@ export default defineConfig(() => {
|
|||
vueTsc: true
|
||||
}),
|
||||
VitePWA({
|
||||
filename: 'sw.js',
|
||||
manifestFilename: 'manifest.json',
|
||||
strategies: 'generateSW',
|
||||
strategies: 'injectManifest',
|
||||
srcDir: './',
|
||||
filename: 'sw.ts',
|
||||
injectRegister: false,
|
||||
manifestFilename: 'manifest.json',
|
||||
manifest: {
|
||||
name: 'ezBookkeeping',
|
||||
short_name: 'ezBookkeeping',
|
||||
|
|
@ -140,7 +141,7 @@ export default defineConfig(() => {
|
|||
}
|
||||
]
|
||||
},
|
||||
workbox: {
|
||||
injectManifest: {
|
||||
globDirectory: 'dist/',
|
||||
globPatterns: ['**/*.{js,css,html,ico,png,jpg,jpeg,gif,tiff,bmp,ttf,woff,woff2,svg,eot}'],
|
||||
globIgnores: [
|
||||
|
|
@ -156,43 +157,7 @@ export default defineConfig(() => {
|
|||
'css/*.css',
|
||||
'js/*.js'
|
||||
],
|
||||
runtimeCaching: [
|
||||
{
|
||||
urlPattern: /.*\/(mobile|mobile\/|desktop|desktop\/)$/,
|
||||
handler: 'NetworkFirst'
|
||||
},
|
||||
{
|
||||
urlPattern: /.*\/(mobile|mobile\/)#!\//,
|
||||
handler: 'NetworkFirst'
|
||||
},
|
||||
{
|
||||
urlPattern: /.*\/(desktop|desktop\/)#\//,
|
||||
handler: 'NetworkFirst'
|
||||
},
|
||||
{
|
||||
urlPattern: /.*\/(index\.html|mobile\.html|desktop\.html)/,
|
||||
handler: 'NetworkFirst'
|
||||
},
|
||||
{
|
||||
urlPattern: /.*\/img\/desktop\/.*\.(png|jpg|jpeg|gif|tiff|bmp|svg)/,
|
||||
handler: 'StaleWhileRevalidate'
|
||||
},
|
||||
{
|
||||
urlPattern: /.*\/fonts\/.*\.(eot|ttf|svg|woff)/,
|
||||
handler: 'CacheFirst'
|
||||
},
|
||||
{
|
||||
urlPattern: /.*\/css\/.*\.css/,
|
||||
handler: 'CacheFirst'
|
||||
},
|
||||
{
|
||||
urlPattern: /.*\/js\/.*\.js/,
|
||||
handler: 'CacheFirst'
|
||||
}
|
||||
],
|
||||
navigateFallback: '',
|
||||
skipWaiting: true,
|
||||
clientsClaim: true
|
||||
maximumFileSizeToCacheInBytes: 5 * 1024 * 1024, // 5 MB
|
||||
}
|
||||
})
|
||||
],
|
||||
|
|
|
|||
Loading…
Reference in a new issue