support caching map data when map_data_fetch_proxy is set true
This commit is contained in:
@@ -34,6 +34,7 @@ import { ThemeType } from '@/core/theme.ts';
|
|||||||
import { isProduction } from '@/lib/version.ts';
|
import { isProduction } from '@/lib/version.ts';
|
||||||
import { initMapProvider } from '@/lib/map/index.ts';
|
import { initMapProvider } from '@/lib/map/index.ts';
|
||||||
import { isUserLogined, isUserUnlocked } from '@/lib/userstate.ts';
|
import { isUserLogined, isUserUnlocked } from '@/lib/userstate.ts';
|
||||||
|
import { updateMapCacheExpiration } from '@/lib/cache.ts';
|
||||||
import { getSystemTheme, setExpenseAndIncomeAmountColor } from '@/lib/ui/common.ts';
|
import { getSystemTheme, setExpenseAndIncomeAmountColor } from '@/lib/ui/common.ts';
|
||||||
|
|
||||||
const { tt, getCurrentLanguageInfo, setLanguage, initLocale } = useI18n();
|
const { tt, getCurrentLanguageInfo, setLanguage, initLocale } = useI18n();
|
||||||
@@ -77,6 +78,16 @@ onMounted(() => {
|
|||||||
const languageInfo = getCurrentLanguageInfo();
|
const languageInfo = getCurrentLanguageInfo();
|
||||||
initMapProvider(languageInfo?.alternativeLanguageTag);
|
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) => {
|
watch(currentNotificationContent, (newValue) => {
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ import { isProduction } from '@/lib/version.ts';
|
|||||||
import { getTheme, isEnableSwipeBack, isEnableAnimate } from '@/lib/settings.ts';
|
import { getTheme, isEnableSwipeBack, isEnableAnimate } from '@/lib/settings.ts';
|
||||||
import { initMapProvider } from '@/lib/map/index.ts';
|
import { initMapProvider } from '@/lib/map/index.ts';
|
||||||
import { isUserLogined, isUserUnlocked } from '@/lib/userstate.ts';
|
import { isUserLogined, isUserUnlocked } from '@/lib/userstate.ts';
|
||||||
|
import { updateMapCacheExpiration } from '@/lib/cache.ts';
|
||||||
import { setExpenseAndIncomeAmountColor } from '@/lib/ui/common.ts';
|
import { setExpenseAndIncomeAmountColor } from '@/lib/ui/common.ts';
|
||||||
import { isiOSHomeScreenMode, isModalShowing, setAppFontSize } from '@/lib/ui/mobile.ts';
|
import { isiOSHomeScreenMode, isModalShowing, setAppFontSize } from '@/lib/ui/mobile.ts';
|
||||||
|
|
||||||
@@ -180,6 +181,16 @@ onMounted(() => {
|
|||||||
const languageInfo = getCurrentLanguageInfo();
|
const languageInfo = getCurrentLanguageInfo();
|
||||||
initMapProvider(languageInfo?.alternativeLanguageTag);
|
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) => {
|
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_ASSETS_CACHE_NAME: string = 'ezbookkeeping-assets-cache';
|
||||||
export const SW_CODE_CACHE_NAME: string = 'ezbookkeeping-code-cache';
|
export const SW_CODE_CACHE_NAME: string = 'ezbookkeeping-code-cache';
|
||||||
export const SW_MAP_CACHE_NAME: string = 'ezbookkeeping-map-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;
|
||||||
|
|||||||
+7
-2
@@ -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 name: string;
|
||||||
readonly value: string;
|
readonly value: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface NameNumeralValue {
|
export interface NameNumeralValue extends GenericNameValue<number> {
|
||||||
readonly name: string;
|
readonly name: string;
|
||||||
readonly value: number;
|
readonly value: number;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,3 +5,10 @@ export interface BrowserCacheStatistics {
|
|||||||
readonly mapCacheSize: number;
|
readonly mapCacheSize: number;
|
||||||
readonly othersCacheSize: 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;
|
hideCategoriesWithoutAccounts: boolean;
|
||||||
// Exchange Rates Data Page
|
// Exchange Rates Data Page
|
||||||
currencySortByInExchangeRatesPage: number;
|
currencySortByInExchangeRatesPage: number;
|
||||||
|
// Browser Cache Settings
|
||||||
|
mapCacheExpiration: number,
|
||||||
// Statistics Settings
|
// Statistics Settings
|
||||||
statistics: {
|
statistics: {
|
||||||
defaultChartDataType: number;
|
defaultChartDataType: number;
|
||||||
@@ -187,6 +189,8 @@ export const DEFAULT_APPLICATION_SETTINGS: ApplicationSettings = {
|
|||||||
hideCategoriesWithoutAccounts: false,
|
hideCategoriesWithoutAccounts: false,
|
||||||
// Exchange Rates Data Page
|
// Exchange Rates Data Page
|
||||||
currencySortByInExchangeRatesPage: CurrencySortingType.Default.type,
|
currencySortByInExchangeRatesPage: CurrencySortingType.Default.type,
|
||||||
|
// Browser Cache Settings
|
||||||
|
mapCacheExpiration: -1,
|
||||||
// Statistics Settings
|
// Statistics Settings
|
||||||
statistics: {
|
statistics: {
|
||||||
defaultChartDataType: ChartDataType.Default.type,
|
defaultChartDataType: ChartDataType.Default.type,
|
||||||
|
|||||||
+65
-3
@@ -1,5 +1,6 @@
|
|||||||
import type {
|
import type {
|
||||||
BrowserCacheStatistics
|
BrowserCacheStatistics,
|
||||||
|
SWMapCacheConfig
|
||||||
} from '@/core/cache.ts';
|
} from '@/core/cache.ts';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
@@ -7,10 +8,14 @@ import {
|
|||||||
SW_RUNTIME_CACHE_NAME_PREFIX,
|
SW_RUNTIME_CACHE_NAME_PREFIX,
|
||||||
SW_ASSETS_CACHE_NAME,
|
SW_ASSETS_CACHE_NAME,
|
||||||
SW_CODE_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';
|
} from '@/consts/cache.ts';
|
||||||
|
|
||||||
import { isFunction, isObject, isNumber } from './common.ts';
|
import { isFunction, isObject, isNumber } from './common.ts';
|
||||||
|
import services from './services.ts';
|
||||||
import logger from './logger.ts';
|
import logger from './logger.ts';
|
||||||
|
|
||||||
function findFirstCacheName(prefix: string): Promise<string> {
|
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> {
|
export function clearAllBrowserCaches(): Promise<void> {
|
||||||
if (!window.caches) {
|
if (!window.caches) {
|
||||||
logger.error('caches API is not supported in this browser');
|
logger.error('caches API is not supported in this browser');
|
||||||
@@ -142,7 +204,7 @@ export function clearAllBrowserCaches(): Promise<void> {
|
|||||||
resolve();
|
resolve();
|
||||||
});
|
});
|
||||||
}).catch(error => {
|
}).catch(error => {
|
||||||
logger.warn("failed to clear cache", error);
|
logger.error("failed to clear cache", error);
|
||||||
reject(error);
|
reject(error);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
+9
-3
@@ -1,5 +1,11 @@
|
|||||||
import { keys, keysIfValueEquals, values } from '@/core/base.ts';
|
import {
|
||||||
import type { NameValue, TypeAndName, TypeAndDisplayName} from '@/core/base.ts';
|
type GenericNameValue,
|
||||||
|
type TypeAndName,
|
||||||
|
type TypeAndDisplayName,
|
||||||
|
keys,
|
||||||
|
keysIfValueEquals,
|
||||||
|
values
|
||||||
|
} from '@/core/base.ts';
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
|
||||||
export function isFunction(val: unknown): val is Function {
|
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;
|
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) {
|
for (const item of items) {
|
||||||
if (item.value === value) {
|
if (item.value === value) {
|
||||||
return item.name;
|
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 {
|
export function getMapWebsite(): string {
|
||||||
return mapProvider?.getWebsite() || '';
|
return mapProvider?.getWebsite() || '';
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -831,6 +831,12 @@ export default {
|
|||||||
generateQrCodeUrl: (qrCodeName: string): string => {
|
generateQrCodeUrl: (qrCodeName: string): string => {
|
||||||
return `${getBasePath()}${BASE_QRCODE_PATH}/${qrCodeName}.png`;
|
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 => {
|
generateMapProxyTileImageUrl: (mapProvider: string, language: string): string => {
|
||||||
const token = getCurrentToken();
|
const token = getCurrentToken();
|
||||||
let url = `${getBasePath()}${BASE_PROXY_URL_PATH}/map/tile/{z}/{x}/{y}.png?provider=${mapProvider}&token=${token}`;
|
let url = `${getBasePath()}${BASE_PROXY_URL_PATH}/map/tile/{z}/{x}/{y}.png?provider=${mapProvider}&token=${token}`;
|
||||||
|
|||||||
+7
-3
@@ -2512,9 +2512,13 @@
|
|||||||
"Resource Files": "Resource Files",
|
"Resource Files": "Resource Files",
|
||||||
"Map Data": "Map Data",
|
"Map Data": "Map Data",
|
||||||
"Others": "Others",
|
"Others": "Others",
|
||||||
"Failed to load browser cache statistics": "Failed to load browser cache statistics",
|
"Cache Expiration Time": "Cache Expiration Time",
|
||||||
"Clear File Cache": "Clear File Cache",
|
"Cache Expiration for Map Data": "Cache Expiration for Map Data",
|
||||||
"Are you sure you want to clear file cache?": "Are you sure you want to clear file cache?",
|
"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?",
|
"Are you sure you want to re-login?": "Sind Sie sicher, dass Sie sich erneut anmelden möchten?",
|
||||||
"Exchange Rates Data": "Wechselkursdaten",
|
"Exchange Rates Data": "Wechselkursdaten",
|
||||||
"User Custom": "User Custom",
|
"User Custom": "User Custom",
|
||||||
|
|||||||
+7
-3
@@ -2512,9 +2512,13 @@
|
|||||||
"Resource Files": "Resource Files",
|
"Resource Files": "Resource Files",
|
||||||
"Map Data": "Map Data",
|
"Map Data": "Map Data",
|
||||||
"Others": "Others",
|
"Others": "Others",
|
||||||
"Failed to load browser cache statistics": "Failed to load browser cache statistics",
|
"Cache Expiration Time": "Cache Expiration Time",
|
||||||
"Clear File Cache": "Clear File Cache",
|
"Cache Expiration for Map Data": "Cache Expiration for Map Data",
|
||||||
"Are you sure you want to clear file cache?": "Are you sure you want to clear file cache?",
|
"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?",
|
"Are you sure you want to re-login?": "Are you sure you want to re-login?",
|
||||||
"Exchange Rates Data": "Exchange Rates Data",
|
"Exchange Rates Data": "Exchange Rates Data",
|
||||||
"User Custom": "User Custom",
|
"User Custom": "User Custom",
|
||||||
|
|||||||
+7
-3
@@ -2512,9 +2512,13 @@
|
|||||||
"Resource Files": "Resource Files",
|
"Resource Files": "Resource Files",
|
||||||
"Map Data": "Map Data",
|
"Map Data": "Map Data",
|
||||||
"Others": "Others",
|
"Others": "Others",
|
||||||
"Failed to load browser cache statistics": "Failed to load browser cache statistics",
|
"Cache Expiration Time": "Cache Expiration Time",
|
||||||
"Clear File Cache": "Clear File Cache",
|
"Cache Expiration for Map Data": "Cache Expiration for Map Data",
|
||||||
"Are you sure you want to clear file cache?": "Are you sure you want to clear file cache?",
|
"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?",
|
"Are you sure you want to re-login?": "¿Seguro que deseas volver a iniciar sesión?",
|
||||||
"Exchange Rates Data": "Tipos de Cambio",
|
"Exchange Rates Data": "Tipos de Cambio",
|
||||||
"User Custom": "User Custom",
|
"User Custom": "User Custom",
|
||||||
|
|||||||
+7
-3
@@ -2512,9 +2512,13 @@
|
|||||||
"Resource Files": "Resource Files",
|
"Resource Files": "Resource Files",
|
||||||
"Map Data": "Map Data",
|
"Map Data": "Map Data",
|
||||||
"Others": "Others",
|
"Others": "Others",
|
||||||
"Failed to load browser cache statistics": "Failed to load browser cache statistics",
|
"Cache Expiration Time": "Cache Expiration Time",
|
||||||
"Clear File Cache": "Clear File Cache",
|
"Cache Expiration for Map Data": "Cache Expiration for Map Data",
|
||||||
"Are you sure you want to clear file cache?": "Are you sure you want to clear file cache?",
|
"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 ?",
|
"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",
|
"Exchange Rates Data": "Données de taux de change",
|
||||||
"User Custom": "Personnalisé utilisateur",
|
"User Custom": "Personnalisé utilisateur",
|
||||||
|
|||||||
+7
-3
@@ -2512,9 +2512,13 @@
|
|||||||
"Resource Files": "Resource Files",
|
"Resource Files": "Resource Files",
|
||||||
"Map Data": "Map Data",
|
"Map Data": "Map Data",
|
||||||
"Others": "Others",
|
"Others": "Others",
|
||||||
"Failed to load browser cache statistics": "Failed to load browser cache statistics",
|
"Cache Expiration Time": "Cache Expiration Time",
|
||||||
"Clear File Cache": "Clear File Cache",
|
"Cache Expiration for Map Data": "Cache Expiration for Map Data",
|
||||||
"Are you sure you want to clear file cache?": "Are you sure you want to clear file cache?",
|
"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?",
|
"Are you sure you want to re-login?": "Sei sicuro di voler accedere di nuovo?",
|
||||||
"Exchange Rates Data": "Dati tassi di cambio",
|
"Exchange Rates Data": "Dati tassi di cambio",
|
||||||
"User Custom": "User Custom",
|
"User Custom": "User Custom",
|
||||||
|
|||||||
+7
-3
@@ -2512,9 +2512,13 @@
|
|||||||
"Resource Files": "Resource Files",
|
"Resource Files": "Resource Files",
|
||||||
"Map Data": "Map Data",
|
"Map Data": "Map Data",
|
||||||
"Others": "Others",
|
"Others": "Others",
|
||||||
"Failed to load browser cache statistics": "Failed to load browser cache statistics",
|
"Cache Expiration Time": "Cache Expiration Time",
|
||||||
"Clear File Cache": "Clear File Cache",
|
"Cache Expiration for Map Data": "Cache Expiration for Map Data",
|
||||||
"Are you sure you want to clear file cache?": "Are you sure you want to clear file cache?",
|
"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",
|
"User Custom": "User Custom",
|
||||||
|
|||||||
+7
-3
@@ -2512,9 +2512,13 @@
|
|||||||
"Resource Files": "Resource Files",
|
"Resource Files": "Resource Files",
|
||||||
"Map Data": "Map Data",
|
"Map Data": "Map Data",
|
||||||
"Others": "Others",
|
"Others": "Others",
|
||||||
"Failed to load browser cache statistics": "Failed to load browser cache statistics",
|
"Cache Expiration Time": "Cache Expiration Time",
|
||||||
"Clear File Cache": "Clear File Cache",
|
"Cache Expiration for Map Data": "Cache Expiration for Map Data",
|
||||||
"Are you sure you want to clear file cache?": "Are you sure you want to clear file cache?",
|
"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": "ಬಳಕೆದಾರ ಕಸ್ಟಮ್",
|
||||||
|
|||||||
+7
-3
@@ -2512,9 +2512,13 @@
|
|||||||
"Resource Files": "Resource Files",
|
"Resource Files": "Resource Files",
|
||||||
"Map Data": "Map Data",
|
"Map Data": "Map Data",
|
||||||
"Others": "Others",
|
"Others": "Others",
|
||||||
"Failed to load browser cache statistics": "Failed to load browser cache statistics",
|
"Cache Expiration Time": "Cache Expiration Time",
|
||||||
"Clear File Cache": "Clear File Cache",
|
"Cache Expiration for Map Data": "Cache Expiration for Map Data",
|
||||||
"Are you sure you want to clear file cache?": "Are you sure you want to clear file cache?",
|
"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": "사용자 정의",
|
||||||
|
|||||||
+7
-3
@@ -2512,9 +2512,13 @@
|
|||||||
"Resource Files": "Resource Files",
|
"Resource Files": "Resource Files",
|
||||||
"Map Data": "Map Data",
|
"Map Data": "Map Data",
|
||||||
"Others": "Others",
|
"Others": "Others",
|
||||||
"Failed to load browser cache statistics": "Failed to load browser cache statistics",
|
"Cache Expiration Time": "Cache Expiration Time",
|
||||||
"Clear File Cache": "Clear File Cache",
|
"Cache Expiration for Map Data": "Cache Expiration for Map Data",
|
||||||
"Are you sure you want to clear file cache?": "Are you sure you want to clear file cache?",
|
"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?",
|
"Are you sure you want to re-login?": "Weet je zeker dat je opnieuw wilt inloggen?",
|
||||||
"Exchange Rates Data": "Wisselkoersgegevens",
|
"Exchange Rates Data": "Wisselkoersgegevens",
|
||||||
"User Custom": "Gebruiker aangepast",
|
"User Custom": "Gebruiker aangepast",
|
||||||
|
|||||||
@@ -2512,9 +2512,13 @@
|
|||||||
"Resource Files": "Resource Files",
|
"Resource Files": "Resource Files",
|
||||||
"Map Data": "Map Data",
|
"Map Data": "Map Data",
|
||||||
"Others": "Others",
|
"Others": "Others",
|
||||||
"Failed to load browser cache statistics": "Failed to load browser cache statistics",
|
"Cache Expiration Time": "Cache Expiration Time",
|
||||||
"Clear File Cache": "Clear File Cache",
|
"Cache Expiration for Map Data": "Cache Expiration for Map Data",
|
||||||
"Are you sure you want to clear file cache?": "Are you sure you want to clear file cache?",
|
"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?",
|
"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",
|
"Exchange Rates Data": "Dados de Taxas de Câmbio",
|
||||||
"User Custom": "Personalização do Usuário",
|
"User Custom": "Personalização do Usuário",
|
||||||
|
|||||||
+7
-3
@@ -2512,9 +2512,13 @@
|
|||||||
"Resource Files": "Resource Files",
|
"Resource Files": "Resource Files",
|
||||||
"Map Data": "Map Data",
|
"Map Data": "Map Data",
|
||||||
"Others": "Others",
|
"Others": "Others",
|
||||||
"Failed to load browser cache statistics": "Failed to load browser cache statistics",
|
"Cache Expiration Time": "Cache Expiration Time",
|
||||||
"Clear File Cache": "Clear File Cache",
|
"Cache Expiration for Map Data": "Cache Expiration for Map Data",
|
||||||
"Are you sure you want to clear file cache?": "Are you sure you want to clear file cache?",
|
"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": "Пользовательские настройки",
|
||||||
|
|||||||
+7
-3
@@ -2512,9 +2512,13 @@
|
|||||||
"Resource Files": "Resource Files",
|
"Resource Files": "Resource Files",
|
||||||
"Map Data": "Map Data",
|
"Map Data": "Map Data",
|
||||||
"Others": "Others",
|
"Others": "Others",
|
||||||
"Failed to load browser cache statistics": "Failed to load browser cache statistics",
|
"Cache Expiration Time": "Cache Expiration Time",
|
||||||
"Clear File Cache": "Clear File Cache",
|
"Cache Expiration for Map Data": "Cache Expiration for Map Data",
|
||||||
"Are you sure you want to clear file cache?": "Are you sure you want to clear file cache?",
|
"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?",
|
"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",
|
"Exchange Rates Data": "Podatki o menjalnih tečajih",
|
||||||
"User Custom": "Uporabniške nastavitve po meri",
|
"User Custom": "Uporabniške nastavitve po meri",
|
||||||
|
|||||||
+7
-3
@@ -2512,9 +2512,13 @@
|
|||||||
"Resource Files": "Resource Files",
|
"Resource Files": "Resource Files",
|
||||||
"Map Data": "Map Data",
|
"Map Data": "Map Data",
|
||||||
"Others": "Others",
|
"Others": "Others",
|
||||||
"Failed to load browser cache statistics": "Failed to load browser cache statistics",
|
"Cache Expiration Time": "Cache Expiration Time",
|
||||||
"Clear File Cache": "Clear File Cache",
|
"Cache Expiration for Map Data": "Cache Expiration for Map Data",
|
||||||
"Are you sure you want to clear file cache?": "Are you sure you want to clear file cache?",
|
"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": "தனிப்பயன்",
|
||||||
|
|||||||
+7
-3
@@ -2512,9 +2512,13 @@
|
|||||||
"Resource Files": "Resource Files",
|
"Resource Files": "Resource Files",
|
||||||
"Map Data": "Map Data",
|
"Map Data": "Map Data",
|
||||||
"Others": "Others",
|
"Others": "Others",
|
||||||
"Failed to load browser cache statistics": "Failed to load browser cache statistics",
|
"Cache Expiration Time": "Cache Expiration Time",
|
||||||
"Clear File Cache": "Clear File Cache",
|
"Cache Expiration for Map Data": "Cache Expiration for Map Data",
|
||||||
"Are you sure you want to clear file cache?": "Are you sure you want to clear file cache?",
|
"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": "กำหนดเองโดยผู้ใช้",
|
||||||
|
|||||||
+7
-3
@@ -2512,9 +2512,13 @@
|
|||||||
"Resource Files": "Resource Files",
|
"Resource Files": "Resource Files",
|
||||||
"Map Data": "Map Data",
|
"Map Data": "Map Data",
|
||||||
"Others": "Others",
|
"Others": "Others",
|
||||||
"Failed to load browser cache statistics": "Failed to load browser cache statistics",
|
"Cache Expiration Time": "Cache Expiration Time",
|
||||||
"Clear File Cache": "Clear File Cache",
|
"Cache Expiration for Map Data": "Cache Expiration for Map Data",
|
||||||
"Are you sure you want to clear file cache?": "Are you sure you want to clear file cache?",
|
"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?",
|
"Are you sure you want to re-login?": "Tekrar giriş yapmak istediğinize emin misiniz?",
|
||||||
"Exchange Rates Data": "Döviz Kuru Verileri",
|
"Exchange Rates Data": "Döviz Kuru Verileri",
|
||||||
"User Custom": "Kullanıcı Özel",
|
"User Custom": "Kullanıcı Özel",
|
||||||
|
|||||||
+7
-3
@@ -2512,9 +2512,13 @@
|
|||||||
"Resource Files": "Resource Files",
|
"Resource Files": "Resource Files",
|
||||||
"Map Data": "Map Data",
|
"Map Data": "Map Data",
|
||||||
"Others": "Others",
|
"Others": "Others",
|
||||||
"Failed to load browser cache statistics": "Failed to load browser cache statistics",
|
"Cache Expiration Time": "Cache Expiration Time",
|
||||||
"Clear File Cache": "Clear File Cache",
|
"Cache Expiration for Map Data": "Cache Expiration for Map Data",
|
||||||
"Are you sure you want to clear file cache?": "Are you sure you want to clear file cache?",
|
"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",
|
"User Custom": "User Custom",
|
||||||
|
|||||||
+7
-3
@@ -2512,9 +2512,13 @@
|
|||||||
"Resource Files": "Resource Files",
|
"Resource Files": "Resource Files",
|
||||||
"Map Data": "Map Data",
|
"Map Data": "Map Data",
|
||||||
"Others": "Others",
|
"Others": "Others",
|
||||||
"Failed to load browser cache statistics": "Failed to load browser cache statistics",
|
"Cache Expiration Time": "Cache Expiration Time",
|
||||||
"Clear File Cache": "Clear File Cache",
|
"Cache Expiration for Map Data": "Cache Expiration for Map Data",
|
||||||
"Are you sure you want to clear file cache?": "Are you sure you want to clear file cache?",
|
"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?",
|
"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",
|
"Exchange Rates Data": "Dữ liệu tỷ giá hối đoái",
|
||||||
"User Custom": "User Custom",
|
"User Custom": "User Custom",
|
||||||
|
|||||||
@@ -2512,9 +2512,13 @@
|
|||||||
"Resource Files": "资源文件",
|
"Resource Files": "资源文件",
|
||||||
"Map Data": "地图数据",
|
"Map Data": "地图数据",
|
||||||
"Others": "其他",
|
"Others": "其他",
|
||||||
"Failed to load browser cache statistics": "加载浏览器缓存统计数据失败",
|
"Cache Expiration Time": "缓存过期时间",
|
||||||
"Clear File Cache": "清除文件缓存",
|
"Cache Expiration for Map Data": "地图数据缓存过期时间",
|
||||||
"Are you sure you want to clear file cache?": "您确定要清除文件缓存?",
|
"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?": "您确定要重新登录?",
|
"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": "載入瀏覽器快取統計資料失敗",
|
"Cache Expiration Time": "快取過期時間",
|
||||||
"Clear File Cache": "清除檔案快取",
|
"Cache Expiration for Map Data": "地圖資料快取過期時間",
|
||||||
"Are you sure you want to clear file cache?": "您確定要清除檔案快取?",
|
"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?": "您確定要重新登入?",
|
"Are you sure you want to re-login?": "您確定要重新登入?",
|
||||||
"Exchange Rates Data": "匯率資料",
|
"Exchange Rates Data": "匯率資料",
|
||||||
"User Custom": "使用者自訂",
|
"User Custom": "使用者自訂",
|
||||||
|
|||||||
@@ -310,6 +310,12 @@ export const useSettingsStore = defineStore('settings', () => {
|
|||||||
updateUserApplicationCloudSettingValue('currencySortByInExchangeRatesPage', value);
|
updateUserApplicationCloudSettingValue('currencySortByInExchangeRatesPage', value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Browser Cache Settings
|
||||||
|
function setMapCacheExpiration(value: number): void {
|
||||||
|
updateApplicationSettingsValue('mapCacheExpiration', value);
|
||||||
|
appSettings.value.mapCacheExpiration = value;
|
||||||
|
}
|
||||||
|
|
||||||
// Statistics Settings
|
// Statistics Settings
|
||||||
function setStatisticsDefaultChartDataType(value: number): void {
|
function setStatisticsDefaultChartDataType(value: number): void {
|
||||||
updateApplicationSettingsSubValue('statistics', 'defaultChartDataType', value);
|
updateApplicationSettingsSubValue('statistics', 'defaultChartDataType', value);
|
||||||
@@ -531,6 +537,8 @@ export const useSettingsStore = defineStore('settings', () => {
|
|||||||
setHideCategoriesWithoutAccounts,
|
setHideCategoriesWithoutAccounts,
|
||||||
// -- Exchange Rates Data Page
|
// -- Exchange Rates Data Page
|
||||||
setCurrencySortByInExchangeRatesPage,
|
setCurrencySortByInExchangeRatesPage,
|
||||||
|
// -- Browser Cache Settings
|
||||||
|
setMapCacheExpiration,
|
||||||
// -- Statistics Settings
|
// -- Statistics Settings
|
||||||
setStatisticsDefaultChartDataType,
|
setStatisticsDefaultChartDataType,
|
||||||
setStatisticsDefaultTimezoneType,
|
setStatisticsDefaultTimezoneType,
|
||||||
|
|||||||
@@ -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>
|
<template>
|
||||||
<v-row>
|
<v-row>
|
||||||
<v-col cols="12">
|
<v-col cols="12" v-if="isSupportedFileCache">
|
||||||
<v-card :class="{ 'disabled': loadingCacheStatistics }">
|
<v-card :class="{ 'disabled': loading }">
|
||||||
<template #title>
|
<template #title>
|
||||||
<div class="d-flex align-center">
|
<div class="d-flex align-center">
|
||||||
<span>{{ tt('File Cache') }}</span>
|
<span>{{ tt('File Cache') }}</span>
|
||||||
<v-btn density="compact" color="default" variant="text" size="24"
|
<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>
|
<template #loader>
|
||||||
<v-progress-circular indeterminate size="20"/>
|
<v-progress-circular indeterminate size="20"/>
|
||||||
</template>
|
</template>
|
||||||
@@ -16,14 +16,10 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</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>
|
<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-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>
|
||||||
</v-card-text>
|
<span class="text-xl ms-1" v-if="!loading">{{ fileCacheStatistics ? formatVolumeToLocalizedNumerals(fileCacheStatistics.totalCacheSize, 2) : '-' }}</span>
|
||||||
|
|
||||||
<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-card-text>
|
</v-card-text>
|
||||||
|
|
||||||
<v-card-text>
|
<v-card-text>
|
||||||
@@ -63,8 +59,8 @@
|
|||||||
|
|
||||||
<div class="d-flex flex-column">
|
<div class="d-flex flex-column">
|
||||||
<span class="text-caption">{{ tt(item.title) }}</span>
|
<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>
|
<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="!loadingCacheStatistics">{{ item.count }}</span>
|
<span class="text-xl" v-if="!loading">{{ item.count }}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</v-col>
|
</v-col>
|
||||||
@@ -72,9 +68,13 @@
|
|||||||
</v-card-text>
|
</v-card-text>
|
||||||
|
|
||||||
<v-card-text class="mt-2">
|
<v-card-text class="mt-2">
|
||||||
<v-btn color="gray" variant="tonal"
|
<v-btn color="secondary" variant="tonal"
|
||||||
:disabled="loadingCacheStatistics || !fileCacheStatistics" @click="clearFileCache()">
|
:disabled="loading || !isSupportedFileCache || !fileCacheStatistics" @click="clearMapCache()">
|
||||||
{{ tt('Clear File Cache') }}
|
{{ 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-btn>
|
||||||
</v-card-text>
|
</v-card-text>
|
||||||
</v-card>
|
</v-card>
|
||||||
@@ -90,29 +90,49 @@
|
|||||||
|
|
||||||
<v-card-text>
|
<v-card-text>
|
||||||
<span class="text-body-1">{{ tt('Used storage') }}</span>
|
<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-text>
|
||||||
</v-card>
|
</v-card>
|
||||||
</v-col>
|
</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>
|
</v-row>
|
||||||
|
|
||||||
<confirm-dialog ref="confirmDialog"/>
|
<confirm-dialog ref="confirmDialog"/>
|
||||||
<snack-bar ref="snackbar" />
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import ConfirmDialog from '@/components/desktop/ConfirmDialog.vue';
|
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 { 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 { isMapProviderUseExternalSDK } from '@/lib/map/index.ts';
|
||||||
|
import { getMapProvider, isMapDataFetchProxyEnabled } from '@/lib/server_settings.ts';
|
||||||
import { loadBrowserCacheStatistics, clearAllBrowserCaches } from '@/lib/cache.ts';
|
|
||||||
|
|
||||||
import {
|
import {
|
||||||
mdiRefresh,
|
mdiRefresh,
|
||||||
@@ -123,39 +143,41 @@ import {
|
|||||||
} from '@mdi/js';
|
} from '@mdi/js';
|
||||||
|
|
||||||
type ConfirmDialogType = InstanceType<typeof ConfirmDialog>;
|
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 confirmDialog = useTemplateRef<ConfirmDialogType>('confirmDialog');
|
||||||
const snackbar = useTemplateRef<SnackBarType>('snackbar');
|
|
||||||
|
|
||||||
const loadingCacheStatistics = ref<boolean>(true);
|
function clearMapCache(): void {
|
||||||
const fileCacheStatistics = ref<BrowserCacheStatistics | undefined>(undefined);
|
confirmDialog.value?.open('Are you sure you want to clear map data cache?').then(() => {
|
||||||
const exchangeRatesCacheSize = ref<number | undefined>(undefined);
|
clearMapDataCache().then(() => {
|
||||||
|
loadCacheStatistics();
|
||||||
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 clearFileCache(): void {
|
function clearAllFileCache(): void {
|
||||||
confirmDialog.value?.open('Are you sure you want to clear file cache?').then(() => {
|
confirmDialog.value?.open('Are you sure you want to clear all file cache?').then(() => {
|
||||||
clearAllBrowserCaches().then(() => {
|
clearAllBrowserCaches().then(() => {
|
||||||
location.reload();
|
location.reload();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
reloadCacheStatistics();
|
loadCacheStatistics();
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
<template>
|
<template>
|
||||||
<f7-page>
|
<f7-page ptr @ptr:refresh="reloadCacheStatistics">
|
||||||
<f7-navbar>
|
<f7-navbar>
|
||||||
<f7-nav-left :class="{ 'disabled': loading }" :back-link="tt('Back')"></f7-nav-left>
|
<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-title :title="tt('Browser Cache Management')"></f7-nav-title>
|
||||||
<f7-nav-right :class="{ 'disabled': loading }">
|
<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-nav-right>
|
||||||
</f7-navbar>
|
</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">
|
<f7-list-item group-title :sortable="false">
|
||||||
<small>{{ tt('File Cache') }}</small>
|
<small>{{ tt('File Cache') }}</small>
|
||||||
</f7-list-item>
|
</f7-list-item>
|
||||||
@@ -26,7 +26,14 @@
|
|||||||
<f7-list-item title="Used storage" after="Count"></f7-list-item>
|
<f7-list-item title="Used storage" after="Count"></f7-list-item>
|
||||||
</f7-list>
|
</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">
|
<f7-list-item group-title :sortable="false">
|
||||||
<small>{{ tt('File Cache') }}</small>
|
<small>{{ tt('File Cache') }}</small>
|
||||||
</f7-list-item>
|
</f7-list-item>
|
||||||
@@ -44,10 +51,38 @@
|
|||||||
<f7-list-item :title="tt('Used storage')" :after="formatVolumeToLocalizedNumerals(exchangeRatesCacheSize ?? 0, 2)"></f7-list-item>
|
<f7-list-item :title="tt('Used storage')" :after="formatVolumeToLocalizedNumerals(exchangeRatesCacheSize ?? 0, 2)"></f7-list-item>
|
||||||
</f7-list>
|
</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 close-by-outside-click close-on-escape :opened="showMoreActionSheet" @actions:closed="showMoreActionSheet = false">
|
||||||
<f7-actions-group>
|
<f7-actions-group v-if="isSupportedFileCache && fileCacheStatistics">
|
||||||
<f7-actions-button :class="{ 'disabled': loading || !fileCacheStatistics }"
|
<f7-actions-button :class="{ 'disabled': loading || !isSupportedFileCache || !fileCacheStatistics }"
|
||||||
@click="clearFileCache">{{ tt('Clear File Cache') }}</f7-actions-button>
|
@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-group>
|
<f7-actions-group>
|
||||||
<f7-actions-button bold close>{{ tt('Cancel') }}</f7-actions-button>
|
<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 { useI18n } from '@/locales/helpers.ts';
|
||||||
import { useI18nUIComponents } from '@/lib/ui/mobile.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 { findNameByValue } from '@/lib/common.ts';
|
||||||
|
import { isMapProviderUseExternalSDK } from '@/lib/map/index.ts';
|
||||||
import { loadBrowserCacheStatistics, clearAllBrowserCaches } from '@/lib/cache.ts';
|
import { getMapProvider, isMapDataFetchProxyEnabled } from '@/lib/server_settings.ts';
|
||||||
|
|
||||||
const { tt, formatVolumeToLocalizedNumerals } = useI18n();
|
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 showMoreActionSheet = ref<boolean>(false);
|
||||||
const fileCacheStatistics = ref<BrowserCacheStatistics | undefined>(undefined);
|
|
||||||
const exchangeRatesCacheSize = ref<number | undefined>(undefined);
|
|
||||||
|
|
||||||
function reloadCacheStatistics(): void {
|
function reloadCacheStatistics(done?: () => void): void {
|
||||||
loading.value = true;
|
loadCacheStatistics().then(() => {
|
||||||
|
if (done) {
|
||||||
loadBrowserCacheStatistics().then(statistics => {
|
done();
|
||||||
fileCacheStatistics.value = statistics;
|
}
|
||||||
exchangeRatesCacheSize.value = exchangeRatesStore.getExchangeRatesCacheSize();
|
|
||||||
loading.value = false;
|
|
||||||
}).catch(() => {
|
}).catch(() => {
|
||||||
loading.value = false;
|
if (done) {
|
||||||
showToast('Failed to load browser cache statistics');
|
done();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function clearFileCache(): void {
|
function clearMapCache(): void {
|
||||||
showConfirm('Are you sure you want to clear file cache?', () => {
|
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(() => {
|
clearAllBrowserCaches().then(() => {
|
||||||
location.reload();
|
location.reload();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
reloadCacheStatistics();
|
loadCacheStatistics();
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
+1
-1
@@ -2,7 +2,7 @@
|
|||||||
"extends": "@vue/tsconfig/tsconfig.dom.json",
|
"extends": "@vue/tsconfig/tsconfig.dom.json",
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"target": "ES2022",
|
"target": "ES2022",
|
||||||
"lib": ["DOM", "ES2022"],
|
"lib": ["DOM", "ES2022", "WebWorker"],
|
||||||
"types": ["vite/client"],
|
"types": ["vite/client"],
|
||||||
"strict": true,
|
"strict": true,
|
||||||
"noImplicitReturns": true,
|
"noImplicitReturns": true,
|
||||||
|
|||||||
+6
-41
@@ -112,10 +112,11 @@ export default defineConfig(() => {
|
|||||||
vueTsc: true
|
vueTsc: true
|
||||||
}),
|
}),
|
||||||
VitePWA({
|
VitePWA({
|
||||||
filename: 'sw.js',
|
strategies: 'injectManifest',
|
||||||
manifestFilename: 'manifest.json',
|
srcDir: './',
|
||||||
strategies: 'generateSW',
|
filename: 'sw.ts',
|
||||||
injectRegister: false,
|
injectRegister: false,
|
||||||
|
manifestFilename: 'manifest.json',
|
||||||
manifest: {
|
manifest: {
|
||||||
name: 'ezBookkeeping',
|
name: 'ezBookkeeping',
|
||||||
short_name: 'ezBookkeeping',
|
short_name: 'ezBookkeeping',
|
||||||
@@ -140,7 +141,7 @@ export default defineConfig(() => {
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
workbox: {
|
injectManifest: {
|
||||||
globDirectory: 'dist/',
|
globDirectory: 'dist/',
|
||||||
globPatterns: ['**/*.{js,css,html,ico,png,jpg,jpeg,gif,tiff,bmp,ttf,woff,woff2,svg,eot}'],
|
globPatterns: ['**/*.{js,css,html,ico,png,jpg,jpeg,gif,tiff,bmp,ttf,woff,woff2,svg,eot}'],
|
||||||
globIgnores: [
|
globIgnores: [
|
||||||
@@ -156,43 +157,7 @@ export default defineConfig(() => {
|
|||||||
'css/*.css',
|
'css/*.css',
|
||||||
'js/*.js'
|
'js/*.js'
|
||||||
],
|
],
|
||||||
runtimeCaching: [
|
maximumFileSizeToCacheInBytes: 5 * 1024 * 1024, // 5 MB
|
||||||
{
|
|
||||||
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
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
],
|
],
|
||||||
|
|||||||
Reference in New Issue
Block a user