mirror of
https://github.com/tiennm99/ccs.git
synced 2026-10-13 14:15:56 +00:00
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:
1 parent
96762a9f6e
commit
d43079b724
3 files changed
+37
-8
No files matched your search
@@ -59,6 +59,7 @@ interface UpdateCheckResult {
|
|||||||
currentVersion: string;
|
currentVersion: string;
|
||||||
latestVersion: string;
|
latestVersion: string;
|
||||||
fromCache: boolean;
|
fromCache: boolean;
|
||||||
|
checkedAt: number; // Unix timestamp of last check
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Default configuration */
|
/** Default configuration */
|
||||||
@@ -172,19 +173,21 @@ export class BinaryManager {
|
|||||||
const currentVersion = this.getInstalledVersion();
|
const currentVersion = this.getInstalledVersion();
|
||||||
|
|
||||||
// Try cache first
|
// Try cache first
|
||||||
const cachedVersion = this.getCachedLatestVersion();
|
const cache = this.getVersionCache();
|
||||||
if (cachedVersion) {
|
if (cache) {
|
||||||
this.log(`Using cached version: ${cachedVersion}`);
|
this.log(`Using cached version: ${cache.latestVersion}`);
|
||||||
return {
|
return {
|
||||||
hasUpdate: this.isNewerVersion(cachedVersion, currentVersion),
|
hasUpdate: this.isNewerVersion(cache.latestVersion, currentVersion),
|
||||||
currentVersion,
|
currentVersion,
|
||||||
latestVersion: cachedVersion,
|
latestVersion: cache.latestVersion,
|
||||||
fromCache: true,
|
fromCache: true,
|
||||||
|
checkedAt: cache.checkedAt,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fetch from GitHub API
|
// Fetch from GitHub API
|
||||||
const latestVersion = await this.fetchLatestVersion();
|
const latestVersion = await this.fetchLatestVersion();
|
||||||
|
const now = Date.now();
|
||||||
this.cacheLatestVersion(latestVersion);
|
this.cacheLatestVersion(latestVersion);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@@ -192,6 +195,7 @@ export class BinaryManager {
|
|||||||
currentVersion,
|
currentVersion,
|
||||||
latestVersion,
|
latestVersion,
|
||||||
fromCache: false,
|
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();
|
const cachePath = this.getVersionCachePath();
|
||||||
if (!fs.existsSync(cachePath)) {
|
if (!fs.existsSync(cachePath)) {
|
||||||
return null;
|
return null;
|
||||||
@@ -301,7 +305,7 @@ export class BinaryManager {
|
|||||||
|
|
||||||
// Check if cache is still valid
|
// Check if cache is still valid
|
||||||
if (Date.now() - cache.checkedAt < VERSION_CACHE_DURATION_MS) {
|
if (Date.now() - cache.checkedAt < VERSION_CACHE_DURATION_MS) {
|
||||||
return cache.latestVersion;
|
return cache;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cache expired
|
// Cache expired
|
||||||
@@ -1001,6 +1005,7 @@ export interface CliproxyUpdateCheckResult {
|
|||||||
currentVersion: string;
|
currentVersion: string;
|
||||||
latestVersion: string;
|
latestVersion: string;
|
||||||
fromCache: boolean;
|
fromCache: boolean;
|
||||||
|
checkedAt: number; // Unix timestamp of last check
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -31,6 +31,17 @@ function formatUptime(startedAt?: string): string {
|
|||||||
return `${minutes}m`;
|
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() {
|
export function ProxyStatusWidget() {
|
||||||
const { data: status, isLoading } = useProxyStatus();
|
const { data: status, isLoading } = useProxyStatus();
|
||||||
const { data: updateCheck } = useCliproxyUpdateCheck();
|
const { data: updateCheck } = useCliproxyUpdateCheck();
|
||||||
@@ -167,6 +178,18 @@ export function ProxyStatusWidget() {
|
|||||||
</Button>
|
</Button>
|
||||||
</div>
|
</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>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -196,6 +196,7 @@ export interface CliproxyUpdateCheckResult {
|
|||||||
currentVersion: string;
|
currentVersion: string;
|
||||||
latestVersion: string;
|
latestVersion: string;
|
||||||
fromCache: boolean;
|
fromCache: boolean;
|
||||||
|
checkedAt: number; // Unix timestamp of last check
|
||||||
}
|
}
|
||||||
|
|
||||||
// API
|
// API
|
||||||
|
|||||||
Reference in new issue
Block a user