From 1c8d4afad07bfa25df901d997e26099eee31dd68 Mon Sep 17 00:00:00 2001 From: web Date: Sat, 13 Sep 2025 05:11:23 -0700 Subject: [PATCH] =?UTF-8?q?=F0=9F=90=9B=20fix:=20Update=20billing=20URL=20?= =?UTF-8?q?fetching=20logic=20and=20improve=20version=20handling=20in=20sy?= =?UTF-8?q?stem=20version=20card=20component?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/admin/components/billing.tsx | 6 +- .../dashboard/system-version-card.tsx | 132 +++++++++--------- 2 files changed, 72 insertions(+), 66 deletions(-) diff --git a/apps/admin/components/billing.tsx b/apps/admin/components/billing.tsx index 7de357a..79ab5a7 100644 --- a/apps/admin/components/billing.tsx +++ b/apps/admin/components/billing.tsx @@ -21,12 +21,12 @@ async function getBillingURL() { 'https://api.github.com/repos/perfect-panel/ppanel-assets/commits', ); const json = await response.json(); - const version = json[0]?.sha; - const url = new URL('https://cdn.jsdelivr.net/gh/perfect-panel/ppanel-assets'); + const version = json[0]?.sha || 'latest'; + const url = new URL('https://cdn.jsdmirror.com/gh/perfect-panel/ppanel-assets'); url.pathname += `@${version}/billing/index.json`; return url.toString(); } catch (error) { - return 'https://cdn.jsdelivr.net/gh/perfect-panel/ppanel-assets/billing/index.json'; + return 'https://cdn.jsdmirror.com/gh/perfect-panel/ppanel-assets/billing/index.json'; } } diff --git a/apps/admin/components/dashboard/system-version-card.tsx b/apps/admin/components/dashboard/system-version-card.tsx index fee0ce7..b4c03e0 100644 --- a/apps/admin/components/dashboard/system-version-card.tsx +++ b/apps/admin/components/dashboard/system-version-card.tsx @@ -28,93 +28,99 @@ export default function SystemVersionCard() { const [openRestart, setOpenRestart] = useState(false); const [isRestarting, setIsRestarting] = useState(false); - const { data: latestReleases } = useQuery({ - queryKey: ['getLatestReleases'], + const { data: versionInfo } = useQuery({ + queryKey: ['getVersionInfo'], queryFn: async () => { try { - const [webResponse, serverResponse] = await Promise.all([ - fetch('https://api.github.com/repos/perfect-panel/ppanel-web/releases/latest'), - fetch('https://api.github.com/repos/perfect-panel/server/releases/latest'), + const [webResponse, serverResponse, systemResponse] = await Promise.all([ + fetch( + 'https://data.jsdelivr.com/v1/packages/gh/perfect-panel/ppanel-web/resolved?specifier=latest', + ), + fetch( + 'https://data.jsdelivr.com/v1/packages/gh/perfect-panel/server/resolved?specifier=latest', + ), + getVersion(), ]); const webData = webResponse.ok ? await webResponse.json() : null; const serverData = serverResponse.ok ? await serverResponse.json() : null; + const systemData = systemResponse.data.data; - return { + const rawVersion = (systemData?.version || '').replace(' Develop', '').trim(); + const timeMatch = rawVersion.match(/\(([^)]+)\)/); + const timestamp = timeMatch ? timeMatch[1] : ''; + const versionWithoutTime = rawVersion.replace(/\([^)]*\)/, '').trim(); + + const isDevelopment = !/^[Vv]?\d+\.\d+\.\d+(-[a-zA-Z]+(\.\d+)?)?$/.test(versionWithoutTime); + + let displayVersion = versionWithoutTime; + if ( + !isDevelopment && + !versionWithoutTime.startsWith('V') && + !versionWithoutTime.startsWith('v') + ) { + displayVersion = `V${versionWithoutTime}`; + } + const lastUpdated = formatDate(new Date(timestamp || Date.now())) || ''; + + const systemInfo = { + isRelease: !isDevelopment, + version: displayVersion, + lastUpdated, + }; + + const latestReleases = { web: webData ? { - version: webData.tag_name, - url: webData.html_url, - publishedAt: webData.published_at, + version: webData.version, + url: `https://github.com/perfect-panel/ppanel-web/releases/tag/${webData.version}`, } : null, server: serverData ? { - version: serverData.tag_name, - url: serverData.html_url, - publishedAt: serverData.published_at, + version: serverData.version, + url: `https://github.com/perfect-panel/server/releases/tag/${serverData.version}`, } : null, }; + + const hasNewVersion = + latestReleases.web && + packageJson.version !== latestReleases.web.version.replace(/^v/, ''); + + const hasServerNewVersion = + latestReleases.server && + systemInfo.version && + systemInfo.version.replace(/^V/, '') !== latestReleases.server.version.replace(/^v/, ''); + + return { + systemInfo, + latestReleases, + hasNewVersion, + hasServerNewVersion, + }; } catch (error) { - console.error('Failed to fetch latest releases:', error); - return { web: null, server: null }; + console.error('Failed to fetch version info:', error); + return { + systemInfo: { isRelease: true, version: 'V1.0.0', lastUpdated: '' }, + latestReleases: { web: null, server: null }, + hasNewVersion: false, + hasServerNewVersion: false, + }; } }, - staleTime: 60 * 60 * 1000, + staleTime: 0, retry: 1, retryDelay: 10000, - }); - - const hasNewVersion = - latestReleases?.web && packageJson.version !== latestReleases.web.version.replace(/^v/, ''); - - const { data: systemInfo } = useQuery({ - queryKey: ['getVersion'], - queryFn: async () => { - const { data } = await getVersion(); - - const versionString = (data.data?.version || '').replace(' Develop', '').trim(); - const releaseVersionRegex = /^[Vv]?\d+\.\d+\.\d+(-[a-zA-Z]+(\.\d+)?)?$/; - const timeMatch = versionString.match(/\(([^)]+)\)/); - const timeInBrackets = timeMatch ? timeMatch[1] : ''; - - const versionWithoutTime = versionString.replace(/\([^)]*\)/, '').trim(); - - const isDevelopment = - versionWithoutTime.includes('-dev') || - versionWithoutTime.includes('-debug') || - versionWithoutTime.includes('-nightly') || - versionWithoutTime.includes('dev') || - !releaseVersionRegex.test(versionWithoutTime); - - let baseVersion = versionWithoutTime; - let lastUpdated = ''; - - if (isDevelopment && versionWithoutTime.includes('-')) { - const parts = versionWithoutTime.split('-'); - baseVersion = parts[0] || versionWithoutTime; - } - - lastUpdated = formatDate(new Date(timeInBrackets || Date.now())) || ''; - - const displayVersion = - baseVersion.startsWith('V') || baseVersion.startsWith('v') - ? baseVersion - : `V${baseVersion}`; - - return { - isRelease: !isDevelopment, - version: displayVersion, - lastUpdated, - }; + initialData: { + systemInfo: { isRelease: true, version: 'V1.0.0', lastUpdated: '' }, + latestReleases: { web: null, server: null }, + hasNewVersion: false, + hasServerNewVersion: false, }, }); - const hasServerNewVersion = - latestReleases?.server && - systemInfo && - systemInfo.version.replace(/^V/, '') !== latestReleases.server.version.replace(/^v/, ''); + const { systemInfo, latestReleases, hasNewVersion, hasServerNewVersion } = versionInfo; return (