add refresh browser cache when client version not match server version
This commit is contained in:
@@ -367,6 +367,9 @@ func startWebServer(c *core.CliContext) error {
|
|||||||
apiV1Route.GET("/exchange_rates/latest.json", bindApi(api.ExchangeRates.LatestExchangeRateHandler))
|
apiV1Route.GET("/exchange_rates/latest.json", bindApi(api.ExchangeRates.LatestExchangeRateHandler))
|
||||||
apiV1Route.POST("/exchange_rates/user_custom/update.json", bindApi(api.ExchangeRates.UserCustomExchangeRateUpdateHandler))
|
apiV1Route.POST("/exchange_rates/user_custom/update.json", bindApi(api.ExchangeRates.UserCustomExchangeRateUpdateHandler))
|
||||||
apiV1Route.POST("/exchange_rates/user_custom/delete.json", bindApi(api.ExchangeRates.UserCustomExchangeRateDeleteHandler))
|
apiV1Route.POST("/exchange_rates/user_custom/delete.json", bindApi(api.ExchangeRates.UserCustomExchangeRateDeleteHandler))
|
||||||
|
|
||||||
|
// System
|
||||||
|
apiV1Route.GET("/systems/version.json", bindApi(api.Systems.VersionHandler))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ var (
|
|||||||
func main() {
|
func main() {
|
||||||
settings.Version = Version
|
settings.Version = Version
|
||||||
settings.CommitHash = CommitHash
|
settings.CommitHash = CommitHash
|
||||||
|
settings.BuildTime = BuildUnixTime
|
||||||
|
|
||||||
cmd := &cli.Command{
|
cmd := &cli.Command{
|
||||||
Name: "ezBookkeeping",
|
Name: "ezBookkeeping",
|
||||||
|
|||||||
@@ -0,0 +1,29 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/mayswind/ezbookkeeping/pkg/core"
|
||||||
|
"github.com/mayswind/ezbookkeeping/pkg/errs"
|
||||||
|
"github.com/mayswind/ezbookkeeping/pkg/settings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// SystemsApi represents system api
|
||||||
|
type SystemsApi struct{}
|
||||||
|
|
||||||
|
// Initialize a system api singleton instance
|
||||||
|
var (
|
||||||
|
Systems = &SystemsApi{}
|
||||||
|
)
|
||||||
|
|
||||||
|
// VersionHandler returns the server version and commit hash
|
||||||
|
func (a *SystemsApi) VersionHandler(c *core.WebContext) (any, *errs.Error) {
|
||||||
|
result := make(map[string]string)
|
||||||
|
|
||||||
|
result["version"] = settings.Version
|
||||||
|
result["commitHash"] = settings.CommitHash
|
||||||
|
|
||||||
|
if settings.BuildTime != "" {
|
||||||
|
result["buildTime"] = settings.BuildTime
|
||||||
|
}
|
||||||
|
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
@@ -9,6 +9,7 @@ type ConfigContainer struct {
|
|||||||
var (
|
var (
|
||||||
Version string
|
Version string
|
||||||
CommitHash string
|
CommitHash string
|
||||||
|
BuildTime string
|
||||||
Container = &ConfigContainer{}
|
Container = &ConfigContainer{}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
export interface VersionInfo {
|
||||||
|
readonly version: string;
|
||||||
|
readonly commitHash: string;
|
||||||
|
readonly buildTime?: string;
|
||||||
|
}
|
||||||
@@ -5,6 +5,9 @@ import type { ApiResponse } from '@/core/api.ts';
|
|||||||
import type {
|
import type {
|
||||||
ApplicationCloudSetting
|
ApplicationCloudSetting
|
||||||
} from '@/core/setting.ts';
|
} from '@/core/setting.ts';
|
||||||
|
import type {
|
||||||
|
VersionInfo
|
||||||
|
} from '@/core/version.ts';
|
||||||
import {
|
import {
|
||||||
TransactionType
|
TransactionType
|
||||||
} from '@/core/transaction.ts';
|
} from '@/core/transaction.ts';
|
||||||
@@ -599,6 +602,9 @@ export default {
|
|||||||
deleteUserCustomExchangeRate: (req: UserCustomExchangeRateDeleteRequest): ApiResponsePromise<boolean> => {
|
deleteUserCustomExchangeRate: (req: UserCustomExchangeRateDeleteRequest): ApiResponsePromise<boolean> => {
|
||||||
return axios.post<ApiResponse<boolean>>('v1/exchange_rates/user_custom/delete.json', req);
|
return axios.post<ApiResponse<boolean>>('v1/exchange_rates/user_custom/delete.json', req);
|
||||||
},
|
},
|
||||||
|
getServerVersion: (): ApiResponsePromise<VersionInfo> => {
|
||||||
|
return axios.get<ApiResponse<VersionInfo>>('v1/systems/version.json');
|
||||||
|
},
|
||||||
generateQrCodeUrl: (qrCodeName: string): string => {
|
generateQrCodeUrl: (qrCodeName: string): string => {
|
||||||
return `${getBasePath()}${BASE_QRCODE_PATH}/${qrCodeName}.png`;
|
return `${getBasePath()}${BASE_QRCODE_PATH}/${qrCodeName}.png`;
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -135,3 +135,39 @@ export function startDownloadFile(fileName: string, fileData: Blob): void {
|
|||||||
|
|
||||||
dataLink.click();
|
dataLink.click();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function clearBrowserCaches(): Promise<void> {
|
||||||
|
if (!window.caches) {
|
||||||
|
logger.error('caches API is not supported in this browser');
|
||||||
|
return Promise.reject();
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
window.caches.keys().then(cacheNames => {
|
||||||
|
const promises = [];
|
||||||
|
|
||||||
|
for (let i = 0; i < cacheNames.length; i++) {
|
||||||
|
const cacheName = cacheNames[i];
|
||||||
|
promises.push(window.caches.delete(cacheName).then(success => {
|
||||||
|
if (success) {
|
||||||
|
logger.info(`cache "${cacheName}" cleared successfully`);
|
||||||
|
return Promise.resolve(cacheName);
|
||||||
|
} else {
|
||||||
|
logger.warn(`failed to clear cache "${cacheName}"`);
|
||||||
|
return Promise.reject(cacheName);
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
Promise.all(promises).then(() => {
|
||||||
|
logger.info("all caches cleared successfully");
|
||||||
|
resolve();
|
||||||
|
}).catch(() => {
|
||||||
|
resolve();
|
||||||
|
});
|
||||||
|
}).catch(error => {
|
||||||
|
logger.warn("failed to clear cache", error);
|
||||||
|
reject(error);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|||||||
+27
-9
@@ -1,13 +1,17 @@
|
|||||||
|
import type { VersionInfo } from '@/core/version.ts';
|
||||||
|
|
||||||
import { getBasePath } from './web.ts';
|
import { getBasePath } from './web.ts';
|
||||||
|
|
||||||
export function isProduction(): boolean {
|
const clientVersionHolder: VersionInfo = {
|
||||||
return __EZBOOKKEEPING_IS_PRODUCTION__;
|
version: __EZBOOKKEEPING_VERSION__,
|
||||||
}
|
commitHash: __EZBOOKKEEPING_BUILD_COMMIT_HASH__,
|
||||||
|
buildTime: __EZBOOKKEEPING_BUILD_UNIX_TIME__
|
||||||
|
};
|
||||||
|
|
||||||
export function getVersion(): string {
|
export function formatDisplayVersion(versionInfo: VersionInfo): string {
|
||||||
const isRelease = !getBuildTime();
|
const isRelease = !versionInfo.buildTime;
|
||||||
const commitHash = __EZBOOKKEEPING_BUILD_COMMIT_HASH__;
|
const commitHash = versionInfo.commitHash;
|
||||||
let version = __EZBOOKKEEPING_VERSION__;
|
let version = versionInfo.version;
|
||||||
|
|
||||||
if (version && (!isRelease || !isProduction())) {
|
if (version && (!isRelease || !isProduction())) {
|
||||||
version += '-dev';
|
version += '-dev';
|
||||||
@@ -15,6 +19,8 @@ export function getVersion(): string {
|
|||||||
|
|
||||||
if (!version) {
|
if (!version) {
|
||||||
version = 'unknown';
|
version = 'unknown';
|
||||||
|
} else {
|
||||||
|
version = 'v' + version;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (commitHash) {
|
if (commitHash) {
|
||||||
@@ -24,8 +30,20 @@ export function getVersion(): string {
|
|||||||
return version;
|
return version;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getBuildTime(): string {
|
export function isProduction(): boolean {
|
||||||
return __EZBOOKKEEPING_BUILD_UNIX_TIME__;
|
return __EZBOOKKEEPING_IS_PRODUCTION__;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getClientVersionInfo(): VersionInfo {
|
||||||
|
return clientVersionHolder;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getClientDisplayVersion(): string {
|
||||||
|
return formatDisplayVersion(clientVersionHolder);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getClientBuildTime(): string {
|
||||||
|
return clientVersionHolder.buildTime || '';
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getMobileVersionPath(): string {
|
export function getMobileVersionPath(): string {
|
||||||
|
|||||||
@@ -2123,6 +2123,9 @@
|
|||||||
"Switch to Desktop Version": "Zur Desktop-Version wechseln",
|
"Switch to Desktop Version": "Zur Desktop-Version wechseln",
|
||||||
"Are you sure you want to switch to desktop version?": "Sind Sie sicher, dass Sie zur Desktop-Version wechseln möchten?",
|
"Are you sure you want to switch to desktop version?": "Sind Sie sicher, dass Sie zur Desktop-Version wechseln möchten?",
|
||||||
"About": "Über",
|
"About": "Über",
|
||||||
|
"Refresh Browser Cache": "Refresh Browser Cache",
|
||||||
|
"Frontend Version": "Frontend Version",
|
||||||
|
"Backend Version": "Backend Version",
|
||||||
"Build Time": "Erstellungszeit",
|
"Build Time": "Erstellungszeit",
|
||||||
"Official Website": "Offizielle Website",
|
"Official Website": "Offizielle Website",
|
||||||
"Report Issue": "Problem melden",
|
"Report Issue": "Problem melden",
|
||||||
|
|||||||
@@ -2123,6 +2123,9 @@
|
|||||||
"Switch to Desktop Version": "Switch to Desktop Version",
|
"Switch to Desktop Version": "Switch to Desktop Version",
|
||||||
"Are you sure you want to switch to desktop version?": "Are you sure you want to switch to desktop version?",
|
"Are you sure you want to switch to desktop version?": "Are you sure you want to switch to desktop version?",
|
||||||
"About": "About",
|
"About": "About",
|
||||||
|
"Refresh Browser Cache": "Refresh Browser Cache",
|
||||||
|
"Frontend Version": "Frontend Version",
|
||||||
|
"Backend Version": "Backend Version",
|
||||||
"Build Time": "Build Time",
|
"Build Time": "Build Time",
|
||||||
"Official Website": "Official Website",
|
"Official Website": "Official Website",
|
||||||
"Report Issue": "Report Issue",
|
"Report Issue": "Report Issue",
|
||||||
|
|||||||
@@ -2123,6 +2123,9 @@
|
|||||||
"Switch to Desktop Version": "Cambiar a la versión de escritorio",
|
"Switch to Desktop Version": "Cambiar a la versión de escritorio",
|
||||||
"Are you sure you want to switch to desktop version?": "¿Estás seguro de que quieres cambiar a la versión de escritorio?",
|
"Are you sure you want to switch to desktop version?": "¿Estás seguro de que quieres cambiar a la versión de escritorio?",
|
||||||
"About": "Acerca de",
|
"About": "Acerca de",
|
||||||
|
"Refresh Browser Cache": "Refresh Browser Cache",
|
||||||
|
"Frontend Version": "Frontend Version",
|
||||||
|
"Backend Version": "Backend Version",
|
||||||
"Build Time": "Tiempo de construcción",
|
"Build Time": "Tiempo de construcción",
|
||||||
"Official Website": "Sitio web oficial",
|
"Official Website": "Sitio web oficial",
|
||||||
"Report Issue": "Informar problema",
|
"Report Issue": "Informar problema",
|
||||||
|
|||||||
@@ -2123,6 +2123,9 @@
|
|||||||
"Switch to Desktop Version": "Passa alla versione desktop",
|
"Switch to Desktop Version": "Passa alla versione desktop",
|
||||||
"Are you sure you want to switch to desktop version?": "Sei sicuro di voler passare alla versione desktop?",
|
"Are you sure you want to switch to desktop version?": "Sei sicuro di voler passare alla versione desktop?",
|
||||||
"About": "Informazioni",
|
"About": "Informazioni",
|
||||||
|
"Refresh Browser Cache": "Refresh Browser Cache",
|
||||||
|
"Frontend Version": "Frontend Version",
|
||||||
|
"Backend Version": "Backend Version",
|
||||||
"Build Time": "Ora di compilazione",
|
"Build Time": "Ora di compilazione",
|
||||||
"Official Website": "Sito ufficiale",
|
"Official Website": "Sito ufficiale",
|
||||||
"Report Issue": "Segnala problema",
|
"Report Issue": "Segnala problema",
|
||||||
|
|||||||
@@ -2123,6 +2123,9 @@
|
|||||||
"Switch to Desktop Version": "デスクトップバージョンに切り替え",
|
"Switch to Desktop Version": "デスクトップバージョンに切り替え",
|
||||||
"Are you sure you want to switch to desktop version?": "デスクトップバージョンに切り替えますか?",
|
"Are you sure you want to switch to desktop version?": "デスクトップバージョンに切り替えますか?",
|
||||||
"About": "About",
|
"About": "About",
|
||||||
|
"Refresh Browser Cache": "Refresh Browser Cache",
|
||||||
|
"Frontend Version": "Frontend Version",
|
||||||
|
"Backend Version": "Backend Version",
|
||||||
"Build Time": "ビルドタイム",
|
"Build Time": "ビルドタイム",
|
||||||
"Official Website": "公式ウェブサイト",
|
"Official Website": "公式ウェブサイト",
|
||||||
"Report Issue": "問題を報告",
|
"Report Issue": "問題を報告",
|
||||||
|
|||||||
@@ -2123,6 +2123,9 @@
|
|||||||
"Switch to Desktop Version": "Mudar para a versão desktop",
|
"Switch to Desktop Version": "Mudar para a versão desktop",
|
||||||
"Are you sure you want to switch to desktop version?": "Tem certeza de que deseja mudar para a versão desktop?",
|
"Are you sure you want to switch to desktop version?": "Tem certeza de que deseja mudar para a versão desktop?",
|
||||||
"About": "Sobre",
|
"About": "Sobre",
|
||||||
|
"Refresh Browser Cache": "Refresh Browser Cache",
|
||||||
|
"Frontend Version": "Frontend Version",
|
||||||
|
"Backend Version": "Backend Version",
|
||||||
"Build Time": "Hora da construção",
|
"Build Time": "Hora da construção",
|
||||||
"Official Website": "Site oficial",
|
"Official Website": "Site oficial",
|
||||||
"Report Issue": "Relatar problema",
|
"Report Issue": "Relatar problema",
|
||||||
|
|||||||
@@ -2123,6 +2123,9 @@
|
|||||||
"Switch to Desktop Version": "Переключиться на десктопную версию",
|
"Switch to Desktop Version": "Переключиться на десктопную версию",
|
||||||
"Are you sure you want to switch to desktop version?": "Вы уверены, что хотите переключиться на десктопную версию?",
|
"Are you sure you want to switch to desktop version?": "Вы уверены, что хотите переключиться на десктопную версию?",
|
||||||
"About": "О программе",
|
"About": "О программе",
|
||||||
|
"Refresh Browser Cache": "Refresh Browser Cache",
|
||||||
|
"Frontend Version": "Frontend Version",
|
||||||
|
"Backend Version": "Backend Version",
|
||||||
"Build Time": "Время сборки",
|
"Build Time": "Время сборки",
|
||||||
"Official Website": "Официальный сайт",
|
"Official Website": "Официальный сайт",
|
||||||
"Report Issue": "Сообщить о проблеме",
|
"Report Issue": "Сообщить о проблеме",
|
||||||
|
|||||||
@@ -2123,6 +2123,9 @@
|
|||||||
"Switch to Desktop Version": "Переключитися на десктопну версію",
|
"Switch to Desktop Version": "Переключитися на десктопну версію",
|
||||||
"Are you sure you want to switch to desktop version?": "Ви впевнені, що хочете перейти на десктопну версію?",
|
"Are you sure you want to switch to desktop version?": "Ви впевнені, що хочете перейти на десктопну версію?",
|
||||||
"About": "Про застосунок",
|
"About": "Про застосунок",
|
||||||
|
"Refresh Browser Cache": "Refresh Browser Cache",
|
||||||
|
"Frontend Version": "Frontend Version",
|
||||||
|
"Backend Version": "Backend Version",
|
||||||
"Build Time": "Час збірки",
|
"Build Time": "Час збірки",
|
||||||
"Official Website": "Офіційний сайт",
|
"Official Website": "Офіційний сайт",
|
||||||
"Report Issue": "Повідомити про проблему",
|
"Report Issue": "Повідомити про проблему",
|
||||||
|
|||||||
@@ -2123,6 +2123,9 @@
|
|||||||
"Switch to Desktop Version": "Chuyển sang phiên bản máy tính để bàn",
|
"Switch to Desktop Version": "Chuyển sang phiên bản máy tính để bàn",
|
||||||
"Are you sure you want to switch to desktop version?": "Are you sure you want to switch to desktop version?",
|
"Are you sure you want to switch to desktop version?": "Are you sure you want to switch to desktop version?",
|
||||||
"About": "Giới thiệu",
|
"About": "Giới thiệu",
|
||||||
|
"Refresh Browser Cache": "Refresh Browser Cache",
|
||||||
|
"Frontend Version": "Frontend Version",
|
||||||
|
"Backend Version": "Backend Version",
|
||||||
"Build Time": "Thời gian xây dựng",
|
"Build Time": "Thời gian xây dựng",
|
||||||
"Official Website": "Trang web chính thức",
|
"Official Website": "Trang web chính thức",
|
||||||
"Report Issue": "Báo cáo sự cố",
|
"Report Issue": "Báo cáo sự cố",
|
||||||
|
|||||||
@@ -2123,6 +2123,9 @@
|
|||||||
"Switch to Desktop Version": "切换到桌面版",
|
"Switch to Desktop Version": "切换到桌面版",
|
||||||
"Are you sure you want to switch to desktop version?": "您确定要切换到桌面版?",
|
"Are you sure you want to switch to desktop version?": "您确定要切换到桌面版?",
|
||||||
"About": "关于",
|
"About": "关于",
|
||||||
|
"Refresh Browser Cache": "刷新浏览器缓存",
|
||||||
|
"Frontend Version": "前端版本",
|
||||||
|
"Backend Version": "后端版本",
|
||||||
"Build Time": "编译时间",
|
"Build Time": "编译时间",
|
||||||
"Official Website": "官方网站",
|
"Official Website": "官方网站",
|
||||||
"Report Issue": "报告问题",
|
"Report Issue": "报告问题",
|
||||||
|
|||||||
@@ -2123,6 +2123,9 @@
|
|||||||
"Switch to Desktop Version": "切換到桌面版",
|
"Switch to Desktop Version": "切換到桌面版",
|
||||||
"Are you sure you want to switch to desktop version?": "您確定要切換到桌面版?",
|
"Are you sure you want to switch to desktop version?": "您確定要切換到桌面版?",
|
||||||
"About": "關於",
|
"About": "關於",
|
||||||
|
"Refresh Browser Cache": "刷新瀏覽器快取",
|
||||||
|
"Frontend Version": "前端版本",
|
||||||
|
"Backend Version": "後端版本",
|
||||||
"Build Time": "建置時間",
|
"Build Time": "建置時間",
|
||||||
"Official Website": "官方網站",
|
"Official Website": "官方網站",
|
||||||
"Report Issue": "回報問題",
|
"Report Issue": "回報問題",
|
||||||
|
|||||||
@@ -0,0 +1,60 @@
|
|||||||
|
import { defineStore } from 'pinia';
|
||||||
|
|
||||||
|
import type { VersionInfo } from '@/core/version.ts';
|
||||||
|
|
||||||
|
import logger from '@/lib/logger.ts';
|
||||||
|
import services from '@/lib/services.ts';
|
||||||
|
import { getClientVersionInfo } from '@/lib/version.ts';
|
||||||
|
|
||||||
|
export const useSystemsStore = defineStore('systems', () => {
|
||||||
|
function checkIfClientVersionMatchServerVersion(): Promise<{ match: boolean, version: VersionInfo }> {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
services.getServerVersion().then(response => {
|
||||||
|
const data = response.data;
|
||||||
|
|
||||||
|
if (!data || !data.success || !data.result) {
|
||||||
|
reject({ message: 'Unable to retrieve server version' });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const clientVersionInfo = getClientVersionInfo();
|
||||||
|
|
||||||
|
if (data.result.version && clientVersionInfo.version !== data.result.version) {
|
||||||
|
logger.warn(`client version \"${clientVersionInfo.version}\" does not match server version \"${data.result.version}\"`);
|
||||||
|
resolve({
|
||||||
|
match: false,
|
||||||
|
version: data.result
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data.result.commitHash && clientVersionInfo.commitHash !== data.result.commitHash) {
|
||||||
|
logger.warn(`client commit hash \"${clientVersionInfo.commitHash}\" does not match server commit hash \"${data.result.commitHash}\"`);
|
||||||
|
resolve({
|
||||||
|
match: false,
|
||||||
|
version: data.result
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
resolve({
|
||||||
|
match: true,
|
||||||
|
version: data.result
|
||||||
|
});
|
||||||
|
}).catch(error => {
|
||||||
|
logger.error('failed to retrieve server version', error);
|
||||||
|
|
||||||
|
if (error.response && error.response.data && error.response.data.errorMessage) {
|
||||||
|
reject({ error: error.response.data });
|
||||||
|
} else if (!error.processed) {
|
||||||
|
reject({ message: 'Unable to retrieve server version' });
|
||||||
|
} else {
|
||||||
|
reject(error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
// functions
|
||||||
|
checkIfClientVersionMatchServerVersion,
|
||||||
|
};
|
||||||
|
});
|
||||||
@@ -1,25 +1,41 @@
|
|||||||
import { computed } from 'vue';
|
import { ref, computed } from 'vue';
|
||||||
|
|
||||||
import { useI18n } from '@/locales/helpers.ts';
|
import { useI18n } from '@/locales/helpers.ts';
|
||||||
|
|
||||||
|
import { useSystemsStore } from '@/stores/system.ts';
|
||||||
import { useExchangeRatesStore } from '@/stores/exchangeRates.ts';
|
import { useExchangeRatesStore } from '@/stores/exchangeRates.ts';
|
||||||
|
|
||||||
|
import type { VersionInfo } from '@/core/version.ts';
|
||||||
|
|
||||||
import type { LatestExchangeRateResponse } from '@/models/exchange_rate.ts';
|
import type { LatestExchangeRateResponse } from '@/models/exchange_rate.ts';
|
||||||
|
|
||||||
import { getMapProvider } from '@/lib/server_settings.ts';
|
import { getMapProvider } from '@/lib/server_settings.ts';
|
||||||
import { getMapWebsite } from '@/lib/map/index.ts';
|
import { getMapWebsite } from '@/lib/map/index.ts';
|
||||||
import { getLicense, getThirdPartyLicenses } from '@/lib/licenses.ts';
|
import { getLicense, getThirdPartyLicenses } from '@/lib/licenses.ts';
|
||||||
import { getVersion, getBuildTime } from '@/lib/version.ts';
|
import { formatDisplayVersion, getClientDisplayVersion, getClientBuildTime } from '@/lib/version.ts';
|
||||||
|
import { clearBrowserCaches } from '@/lib/ui/common.ts';
|
||||||
|
|
||||||
export function useAboutPageBase() {
|
export function useAboutPageBase() {
|
||||||
const { tt, formatUnixTimeToLongDateTime } = useI18n();
|
const { tt, formatUnixTimeToLongDateTime } = useI18n();
|
||||||
|
|
||||||
|
const systemsStore = useSystemsStore();
|
||||||
const exchangeRatesStore = useExchangeRatesStore();
|
const exchangeRatesStore = useExchangeRatesStore();
|
||||||
|
|
||||||
const version = `v${getVersion()}`;
|
const clientVersion = `${getClientDisplayVersion()}`;
|
||||||
|
|
||||||
const buildTime = computed<string>(() => {
|
const serverVersion = ref<VersionInfo | null>(null);
|
||||||
const time = getBuildTime();
|
const clientVersionMatchServerVersion = ref<boolean>(true);
|
||||||
|
|
||||||
|
const serverDisplayVersion = computed<string>(() => {
|
||||||
|
if (!serverVersion.value) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
return formatDisplayVersion(serverVersion.value);
|
||||||
|
});
|
||||||
|
|
||||||
|
const clientBuildTime = computed<string>(() => {
|
||||||
|
const time = getClientBuildTime();
|
||||||
|
|
||||||
if (!time) {
|
if (!time) {
|
||||||
return time;
|
return time;
|
||||||
@@ -40,16 +56,35 @@ export function useAboutPageBase() {
|
|||||||
const licenseLines = computed<string[]>(() => getLicense().replace(/\r/g, '').split('\n'));
|
const licenseLines = computed<string[]>(() => getLicense().replace(/\r/g, '').split('\n'));
|
||||||
const thirdPartyLicenses = computed<LicenseInfo[]>(() => getThirdPartyLicenses());
|
const thirdPartyLicenses = computed<LicenseInfo[]>(() => getThirdPartyLicenses());
|
||||||
|
|
||||||
|
function refreshBrowserCache(): void {
|
||||||
|
clearBrowserCaches().then(() => {
|
||||||
|
location.reload();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function init(): void {
|
||||||
|
systemsStore.checkIfClientVersionMatchServerVersion().then(({ match, version }) => {
|
||||||
|
serverVersion.value = version;
|
||||||
|
clientVersionMatchServerVersion.value = match;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
// constants
|
// constants
|
||||||
version,
|
clientVersion,
|
||||||
|
// states
|
||||||
|
clientVersionMatchServerVersion,
|
||||||
// computed states
|
// computed states
|
||||||
buildTime,
|
serverDisplayVersion,
|
||||||
|
clientBuildTime,
|
||||||
exchangeRatesData,
|
exchangeRatesData,
|
||||||
isUserCustomExchangeRates,
|
isUserCustomExchangeRates,
|
||||||
mapProviderName,
|
mapProviderName,
|
||||||
mapProviderWebsite,
|
mapProviderWebsite,
|
||||||
licenseLines,
|
licenseLines,
|
||||||
thirdPartyLicenses
|
thirdPartyLicenses,
|
||||||
|
// functions
|
||||||
|
refreshBrowserCache,
|
||||||
|
init
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import { useExchangeRatesStore } from '@/stores/exchangeRates.ts';
|
|||||||
import type { AuthResponse } from '@/models/auth_response.ts';
|
import type { AuthResponse } from '@/models/auth_response.ts';
|
||||||
|
|
||||||
import { getLoginPageTips } from '@/lib/server_settings.ts';
|
import { getLoginPageTips } from '@/lib/server_settings.ts';
|
||||||
import { getVersion } from '@/lib/version.ts';
|
import { getClientDisplayVersion } from '@/lib/version.ts';
|
||||||
import { setExpenseAndIncomeAmountColor } from '@/lib/ui/common.ts';
|
import { setExpenseAndIncomeAmountColor } from '@/lib/ui/common.ts';
|
||||||
|
|
||||||
export function useLoginPageBase() {
|
export function useLoginPageBase() {
|
||||||
@@ -19,7 +19,7 @@ export function useLoginPageBase() {
|
|||||||
const settingsStore = useSettingsStore();
|
const settingsStore = useSettingsStore();
|
||||||
const exchangeRatesStore = useExchangeRatesStore();
|
const exchangeRatesStore = useExchangeRatesStore();
|
||||||
|
|
||||||
const version = `v${getVersion()}`;
|
const version = `${getClientDisplayVersion()}`;
|
||||||
|
|
||||||
const username = ref<string>('');
|
const username = ref<string>('');
|
||||||
const password = ref<string>('');
|
const password = ref<string>('');
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import { useExchangeRatesStore } from '@/stores/exchangeRates.ts';
|
|||||||
|
|
||||||
import { isWebAuthnSupported } from '@/lib/webauthn.ts';
|
import { isWebAuthnSupported } from '@/lib/webauthn.ts';
|
||||||
import { hasWebAuthnConfig } from '@/lib/userstate.ts';
|
import { hasWebAuthnConfig } from '@/lib/userstate.ts';
|
||||||
import { getVersion } from '@/lib/version.ts';
|
import { getClientDisplayVersion } from '@/lib/version.ts';
|
||||||
import { setExpenseAndIncomeAmountColor } from '@/lib/ui/common.ts';
|
import { setExpenseAndIncomeAmountColor } from '@/lib/ui/common.ts';
|
||||||
|
|
||||||
export function useUnlockPageBase() {
|
export function useUnlockPageBase() {
|
||||||
@@ -24,7 +24,7 @@ export function useUnlockPageBase() {
|
|||||||
const transactionsStore = useTransactionsStore();
|
const transactionsStore = useTransactionsStore();
|
||||||
const exchangeRatesStore = useExchangeRatesStore();
|
const exchangeRatesStore = useExchangeRatesStore();
|
||||||
|
|
||||||
const version: string = `v${getVersion()}`;
|
const version: string = `${getClientDisplayVersion()}`;
|
||||||
|
|
||||||
const pinCode = ref<string>('');
|
const pinCode = ref<string>('');
|
||||||
|
|
||||||
|
|||||||
@@ -1,22 +1,34 @@
|
|||||||
<template>
|
<template>
|
||||||
<v-row class="match-height">
|
<v-row class="match-height">
|
||||||
<v-col cols="12">
|
<v-col cols="12">
|
||||||
<v-card :title="tt('global.app.title')">
|
<v-card>
|
||||||
|
<template #title>
|
||||||
|
<div class="d-flex align-center">
|
||||||
|
<span>{{ tt('global.app.title') }}</span>
|
||||||
|
<v-btn density="compact" color="default" variant="text" size="24"
|
||||||
|
class="ml-2" :icon="true" @click="refreshBrowserCache"
|
||||||
|
v-if="!clientVersionMatchServerVersion">
|
||||||
|
<v-icon :icon="mdiWebRefresh" size="24" />
|
||||||
|
<v-tooltip activator="parent">{{ tt('Refresh Browser Cache') }}</v-tooltip>
|
||||||
|
</v-btn>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
<v-card-text>
|
<v-card-text>
|
||||||
<v-row no-gutters>
|
<v-row no-gutters>
|
||||||
<v-col cols="12" md="2">
|
<v-col cols="12" md="2">
|
||||||
<span class="text-body-1">{{ tt('Version') }}</span>
|
<span class="text-body-1">{{ tt('Version') }}</span>
|
||||||
</v-col>
|
</v-col>
|
||||||
<v-col cols="12" md="10" class="mb-6">
|
<v-col cols="12" md="10" class="mb-6">
|
||||||
<span class="text-body-1">{{ version }}</span>
|
<span class="text-body-1">{{ clientVersion }}</span>
|
||||||
</v-col>
|
</v-col>
|
||||||
</v-row>
|
</v-row>
|
||||||
<v-row no-gutters v-if="buildTime">
|
<v-row no-gutters v-if="clientBuildTime">
|
||||||
<v-col cols="12" md="2">
|
<v-col cols="12" md="2">
|
||||||
<span class="text-body-1">{{ tt('Build Time') }}</span>
|
<span class="text-body-1">{{ tt('Build Time') }}</span>
|
||||||
</v-col>
|
</v-col>
|
||||||
<v-col cols="12" md="10" class="mb-6">
|
<v-col cols="12" md="10" class="mb-6">
|
||||||
<span class="text-body-1">{{ buildTime }}</span>
|
<span class="text-body-1">{{ clientBuildTime }}</span>
|
||||||
</v-col>
|
</v-col>
|
||||||
</v-row>
|
</v-row>
|
||||||
<v-row no-gutters>
|
<v-row no-gutters>
|
||||||
@@ -123,15 +135,24 @@
|
|||||||
import { useI18n } from '@/locales/helpers.ts';
|
import { useI18n } from '@/locales/helpers.ts';
|
||||||
import { useAboutPageBase } from '@/views/base/AboutPageBase.ts';
|
import { useAboutPageBase } from '@/views/base/AboutPageBase.ts';
|
||||||
|
|
||||||
|
import {
|
||||||
|
mdiWebRefresh
|
||||||
|
} from '@mdi/js';
|
||||||
|
|
||||||
const { tt } = useI18n();
|
const { tt } = useI18n();
|
||||||
const {
|
const {
|
||||||
version,
|
clientVersion,
|
||||||
buildTime,
|
clientVersionMatchServerVersion,
|
||||||
|
clientBuildTime,
|
||||||
exchangeRatesData,
|
exchangeRatesData,
|
||||||
isUserCustomExchangeRates,
|
isUserCustomExchangeRates,
|
||||||
mapProviderName,
|
mapProviderName,
|
||||||
mapProviderWebsite,
|
mapProviderWebsite,
|
||||||
licenseLines,
|
licenseLines,
|
||||||
thirdPartyLicenses
|
thirdPartyLicenses,
|
||||||
|
refreshBrowserCache,
|
||||||
|
init
|
||||||
} = useAboutPageBase();
|
} = useAboutPageBase();
|
||||||
|
|
||||||
|
init();
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -101,7 +101,7 @@ import { useRootStore } from '@/stores/index.ts';
|
|||||||
|
|
||||||
import { APPLICATION_LOGO_PATH } from '@/consts/asset.ts';
|
import { APPLICATION_LOGO_PATH } from '@/consts/asset.ts';
|
||||||
import { ThemeType } from '@/core/theme.ts';
|
import { ThemeType } from '@/core/theme.ts';
|
||||||
import { getVersion } from '@/lib/version.ts';
|
import { getClientDisplayVersion } from '@/lib/version.ts';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
mdiChevronLeft,
|
mdiChevronLeft,
|
||||||
@@ -115,7 +115,7 @@ const { tt } = useI18n();
|
|||||||
|
|
||||||
const rootStore = useRootStore();
|
const rootStore = useRootStore();
|
||||||
|
|
||||||
const version = `v${getVersion()}`;
|
const version = `${getClientDisplayVersion()}`;
|
||||||
|
|
||||||
const snackbar = useTemplateRef<SnackBarType>('snackbar');
|
const snackbar = useTemplateRef<SnackBarType>('snackbar');
|
||||||
|
|
||||||
|
|||||||
@@ -130,7 +130,7 @@ import { useRootStore } from '@/stores/index.ts';
|
|||||||
|
|
||||||
import { APPLICATION_LOGO_PATH } from '@/consts/asset.ts';
|
import { APPLICATION_LOGO_PATH } from '@/consts/asset.ts';
|
||||||
import { ThemeType } from '@/core/theme.ts';
|
import { ThemeType } from '@/core/theme.ts';
|
||||||
import { getVersion } from '@/lib/version.ts';
|
import { getClientDisplayVersion } from '@/lib/version.ts';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
mdiChevronLeft
|
mdiChevronLeft
|
||||||
@@ -150,7 +150,7 @@ const { tt } = useI18n();
|
|||||||
|
|
||||||
const rootStore = useRootStore();
|
const rootStore = useRootStore();
|
||||||
|
|
||||||
const version = `v${getVersion()}`;
|
const version = `${getClientDisplayVersion()}`;
|
||||||
|
|
||||||
const passwordInput = useTemplateRef<VTextField>('passwordInput');
|
const passwordInput = useTemplateRef<VTextField>('passwordInput');
|
||||||
const confirmPasswordInput = useTemplateRef<VTextField>('confirmPasswordInput');
|
const confirmPasswordInput = useTemplateRef<VTextField>('confirmPasswordInput');
|
||||||
|
|||||||
@@ -110,7 +110,7 @@ import { APPLICATION_LOGO_PATH } from '@/consts/asset.ts';
|
|||||||
import { ThemeType } from '@/core/theme.ts';
|
import { ThemeType } from '@/core/theme.ts';
|
||||||
import { isUserVerifyEmailEnabled } from '@/lib/server_settings.ts';
|
import { isUserVerifyEmailEnabled } from '@/lib/server_settings.ts';
|
||||||
import { isUserLogined } from '@/lib/userstate.ts';
|
import { isUserLogined } from '@/lib/userstate.ts';
|
||||||
import { getVersion } from '@/lib/version.ts';
|
import { getClientDisplayVersion } from '@/lib/version.ts';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
mdiChevronLeft
|
mdiChevronLeft
|
||||||
@@ -132,7 +132,7 @@ const { tt, te } = useI18n();
|
|||||||
|
|
||||||
const rootStore = useRootStore();
|
const rootStore = useRootStore();
|
||||||
|
|
||||||
const version = `v${getVersion()}`;
|
const version = `${getClientDisplayVersion()}`;
|
||||||
|
|
||||||
const confirmDialog = useTemplateRef<ConfirmDialogType>('confirmDialog');
|
const confirmDialog = useTemplateRef<ConfirmDialogType>('confirmDialog');
|
||||||
const snackbar = useTemplateRef<SnackBarType>('snackbar');
|
const snackbar = useTemplateRef<SnackBarType>('snackbar');
|
||||||
|
|||||||
@@ -1,11 +1,19 @@
|
|||||||
<template>
|
<template>
|
||||||
<f7-page>
|
<f7-page>
|
||||||
<f7-navbar :title="tt('About')" :back-link="tt('Back')"></f7-navbar>
|
<f7-navbar>
|
||||||
|
<f7-nav-left :back-link="tt('Back')"></f7-nav-left>
|
||||||
|
<f7-nav-title :title="tt('About')"></f7-nav-title>
|
||||||
|
<f7-nav-right>
|
||||||
|
<f7-link icon-f7="" v-if="clientVersionMatchServerVersion && !forceShowRefreshBrowserCacheMenu"/>
|
||||||
|
<f7-link icon-f7="ellipsis" @click="showRefreshBrowserCacheSheet = true"
|
||||||
|
v-else-if="!clientVersionMatchServerVersion || forceShowRefreshBrowserCacheMenu"></f7-link>
|
||||||
|
</f7-nav-right>
|
||||||
|
</f7-navbar>
|
||||||
|
|
||||||
<f7-block-title class="margin-top">{{ tt('global.app.title') }}</f7-block-title>
|
<f7-block-title class="margin-top">{{ tt('global.app.title') }}</f7-block-title>
|
||||||
<f7-list strong inset dividers>
|
<f7-list strong inset dividers>
|
||||||
<f7-list-item :title="tt('Version')" :after="version"></f7-list-item>
|
<f7-list-item :title="tt('Version')" :after="clientVersion" @click="showVersion"></f7-list-item>
|
||||||
<f7-list-item :title="tt('Build Time')" :after="buildTime" v-if="buildTime"></f7-list-item>
|
<f7-list-item :title="tt('Build Time')" :after="clientBuildTime" v-if="clientBuildTime"></f7-list-item>
|
||||||
<f7-list-item external :title="tt('Official Website')" link="https://github.com/mayswind/ezbookkeeping" target="_blank"></f7-list-item>
|
<f7-list-item external :title="tt('Official Website')" link="https://github.com/mayswind/ezbookkeeping" target="_blank"></f7-list-item>
|
||||||
<f7-list-item external :title="tt('Report Issue')" link="https://github.com/mayswind/ezbookkeeping/issues" target="_blank"></f7-list-item>
|
<f7-list-item external :title="tt('Report Issue')" link="https://github.com/mayswind/ezbookkeeping/issues" target="_blank"></f7-list-item>
|
||||||
<f7-list-item external :title="tt('Getting help')" link="https://ezbookkeeping.mayswind.net" target="_blank"></f7-list-item>
|
<f7-list-item external :title="tt('Getting help')" link="https://ezbookkeeping.mayswind.net" target="_blank"></f7-list-item>
|
||||||
@@ -54,24 +62,58 @@
|
|||||||
</f7-block>
|
</f7-block>
|
||||||
</f7-page>
|
</f7-page>
|
||||||
</f7-popup>
|
</f7-popup>
|
||||||
|
|
||||||
|
<f7-actions close-by-outside-click close-on-escape :opened="showRefreshBrowserCacheSheet" @actions:closed="showRefreshBrowserCacheSheet = false">
|
||||||
|
<f7-actions-group>
|
||||||
|
<f7-actions-button @click="refreshBrowserCache">{{ tt('Refresh Browser Cache') }}</f7-actions-button>
|
||||||
|
</f7-actions-group>
|
||||||
|
<f7-actions-group>
|
||||||
|
<f7-actions-button bold close>{{ tt('Cancel') }}</f7-actions-button>
|
||||||
|
</f7-actions-group>
|
||||||
|
</f7-actions>
|
||||||
</f7-page>
|
</f7-page>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
import { ref, computed } from 'vue';
|
||||||
|
|
||||||
import { useI18n } from '@/locales/helpers.ts';
|
import { useI18n } from '@/locales/helpers.ts';
|
||||||
|
import { useI18nUIComponents } from '@/lib/ui/mobile.ts';
|
||||||
import { useAboutPageBase } from '@/views/base/AboutPageBase.ts';
|
import { useAboutPageBase } from '@/views/base/AboutPageBase.ts';
|
||||||
|
|
||||||
const { tt } = useI18n();
|
const { tt } = useI18n();
|
||||||
|
const { showAlert } = useI18nUIComponents();
|
||||||
const {
|
const {
|
||||||
version,
|
clientVersion,
|
||||||
buildTime,
|
clientVersionMatchServerVersion,
|
||||||
|
serverDisplayVersion,
|
||||||
|
clientBuildTime,
|
||||||
exchangeRatesData,
|
exchangeRatesData,
|
||||||
isUserCustomExchangeRates,
|
isUserCustomExchangeRates,
|
||||||
mapProviderName,
|
mapProviderName,
|
||||||
mapProviderWebsite,
|
mapProviderWebsite,
|
||||||
licenseLines,
|
licenseLines,
|
||||||
thirdPartyLicenses
|
thirdPartyLicenses,
|
||||||
|
refreshBrowserCache,
|
||||||
|
init
|
||||||
} = useAboutPageBase();
|
} = useAboutPageBase();
|
||||||
|
|
||||||
|
const showRefreshBrowserCacheSheet = ref<boolean>(false);
|
||||||
|
const versionClickCount = ref<number>(0);
|
||||||
|
const forceShowRefreshBrowserCacheMenu = computed<boolean>(() => versionClickCount.value >= 5);
|
||||||
|
|
||||||
|
function showVersion(): void {
|
||||||
|
let versionMessage = `${tt('Frontend Version')}: ${clientVersion}`;
|
||||||
|
|
||||||
|
if (serverDisplayVersion.value) {
|
||||||
|
versionMessage += `<br/>${tt('Backend Version')}: ${serverDisplayVersion.value}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
versionClickCount.value++;
|
||||||
|
showAlert(versionMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
init();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
|||||||
@@ -101,7 +101,7 @@ import { useUserStore } from '@/stores/user.ts';
|
|||||||
import { useExchangeRatesStore } from '@/stores/exchangeRates.ts';
|
import { useExchangeRatesStore } from '@/stores/exchangeRates.ts';
|
||||||
|
|
||||||
import { findNameByValue } from '@/lib/common.ts';
|
import { findNameByValue } from '@/lib/common.ts';
|
||||||
import { getVersion, getDesktopVersionPath } from '@/lib/version.ts';
|
import { getClientDisplayVersion, getDesktopVersionPath } from '@/lib/version.ts';
|
||||||
import { isUserScheduledTransactionEnabled } from '@/lib/server_settings.ts';
|
import { isUserScheduledTransactionEnabled } from '@/lib/server_settings.ts';
|
||||||
import { setExpenseAndIncomeAmountColor } from '@/lib/ui/common.ts';
|
import { setExpenseAndIncomeAmountColor } from '@/lib/ui/common.ts';
|
||||||
|
|
||||||
@@ -118,7 +118,7 @@ const settingsStore = useSettingsStore();
|
|||||||
const userStore = useUserStore();
|
const userStore = useUserStore();
|
||||||
const exchangeRatesStore = useExchangeRatesStore();
|
const exchangeRatesStore = useExchangeRatesStore();
|
||||||
|
|
||||||
const version = `v${getVersion()}`;
|
const version = `${getClientDisplayVersion()}`;
|
||||||
|
|
||||||
const logouting = ref<boolean>(false);
|
const logouting = ref<boolean>(false);
|
||||||
const showThemePopup = ref<boolean>(false);
|
const showThemePopup = ref<boolean>(false);
|
||||||
|
|||||||
Reference in New Issue
Block a user