feat(ui): add version sync timestamp to ProxyStatusWidget

- Show current CLIProxyAPI version (e.g., v6.5.53)
- Display "Synced Xm ago" with full timestamp on hover
- Extend API response to include checkedAt timestamp
This commit is contained in:
kaitranntt
2025-12-18 23:24:15 -05:00
parent 96762a9f6e
commit d43079b724
3 changed files with 37 additions and 8 deletions
+13 -8
View File
@@ -59,6 +59,7 @@ interface UpdateCheckResult {
currentVersion: string;
latestVersion: string;
fromCache: boolean;
checkedAt: number; // Unix timestamp of last check
}
/** Default configuration */
@@ -172,19 +173,21 @@ export class BinaryManager {
const currentVersion = this.getInstalledVersion();
// Try cache first
const cachedVersion = this.getCachedLatestVersion();
if (cachedVersion) {
this.log(`Using cached version: ${cachedVersion}`);
const cache = this.getVersionCache();
if (cache) {
this.log(`Using cached version: ${cache.latestVersion}`);
return {
hasUpdate: this.isNewerVersion(cachedVersion, currentVersion),
hasUpdate: this.isNewerVersion(cache.latestVersion, currentVersion),
currentVersion,
latestVersion: cachedVersion,
latestVersion: cache.latestVersion,
fromCache: true,
checkedAt: cache.checkedAt,
};
}
// Fetch from GitHub API
const latestVersion = await this.fetchLatestVersion();
const now = Date.now();
this.cacheLatestVersion(latestVersion);
return {
@@ -192,6 +195,7 @@ export class BinaryManager {
currentVersion,
latestVersion,
fromCache: false,
checkedAt: now,
};
}
@@ -287,9 +291,9 @@ export class BinaryManager {
}
/**
* Get cached latest version if still valid
* Get version cache data if still valid
*/
private getCachedLatestVersion(): string | null {
private getVersionCache(): VersionCache | null {
const cachePath = this.getVersionCachePath();
if (!fs.existsSync(cachePath)) {
return null;
@@ -301,7 +305,7 @@ export class BinaryManager {
// Check if cache is still valid
if (Date.now() - cache.checkedAt < VERSION_CACHE_DURATION_MS) {
return cache.latestVersion;
return cache;
}
// Cache expired
@@ -1001,6 +1005,7 @@ export interface CliproxyUpdateCheckResult {
currentVersion: string;
latestVersion: string;
fromCache: boolean;
checkedAt: number; // Unix timestamp of last check
}
/**
+23
View File
@@ -31,6 +31,17 @@ function formatUptime(startedAt?: string): string {
return `${minutes}m`;
}
function formatTimeAgo(timestamp?: number): string {
if (!timestamp) return '';
const diff = Date.now() - timestamp;
const minutes = Math.floor(diff / (1000 * 60));
const hours = Math.floor(diff / (1000 * 60 * 60));
if (minutes < 1) return 'just now';
if (minutes < 60) return `${minutes}m ago`;
return `${hours}h ago`;
}
export function ProxyStatusWidget() {
const { data: status, isLoading } = useProxyStatus();
const { data: updateCheck } = useCliproxyUpdateCheck();
@@ -167,6 +178,18 @@ export function ProxyStatusWidget() {
</Button>
</div>
)}
{/* Version sync indicator */}
{updateCheck?.currentVersion && (
<div className="mt-2 pt-2 border-t border-muted flex items-center justify-between text-[10px] text-muted-foreground/70">
<span>v{updateCheck.currentVersion}</span>
{updateCheck.checkedAt && (
<span title={new Date(updateCheck.checkedAt).toLocaleString()}>
Synced {formatTimeAgo(updateCheck.checkedAt)}
</span>
)}
</div>
)}
</div>
);
}
+1
View File
@@ -196,6 +196,7 @@ export interface CliproxyUpdateCheckResult {
currentVersion: string;
latestVersion: string;
fromCache: boolean;
checkedAt: number; // Unix timestamp of last check
}
// API