chore: align version display with Pro release standard

This commit is contained in:
QLHazyCoder
2026-04-17 19:34:10 +08:00
parent e643573946
commit 8f0c8581f9
3 changed files with 102 additions and 31 deletions
+1 -1
View File
@@ -22,7 +22,7 @@
</svg> </svg>
<div class="header-version-block"> <div class="header-version-block">
<div class="header-version-main"> <div class="header-version-main">
<div id="extension-update-status" class="header-version-title">v0.0.0</div> <div id="extension-update-status" class="header-version-title">Pro0.0</div>
<button id="btn-release-log" class="header-link-btn" type="button" hidden>更新日志</button> <button id="btn-release-log" class="header-link-btn" type="button" hidden>更新日志</button>
</div> </div>
<span id="extension-version-meta" class="header-version-meta" hidden></span> <span id="extension-version-meta" class="header-version-meta" hidden></span>
+11 -9
View File
@@ -1879,7 +1879,7 @@ function renderUpdateReleaseList(releases = []) {
const version = document.createElement('span'); const version = document.createElement('span');
version.className = 'update-release-version'; version.className = 'update-release-version';
version.textContent = `v${release.version}`; version.textContent = release.displayVersion || `Pro${release.version}`;
titleRow.appendChild(version); titleRow.appendChild(version);
if (release.title) { if (release.title) {
@@ -1933,7 +1933,7 @@ function renderReleaseSnapshot(snapshot) {
extensionUpdateStatus.classList.remove('is-update-available', 'is-check-failed', 'is-version-label'); extensionUpdateStatus.classList.remove('is-update-available', 'is-check-failed', 'is-version-label');
const localVersionText = snapshot?.localVersion ? `v${snapshot.localVersion}` : ''; const localVersionText = snapshot?.localVersion || '';
const logUrl = snapshot?.logUrl || snapshot?.releasesPageUrl || sidepanelUpdateService?.releasesPageUrl || ''; const logUrl = snapshot?.logUrl || snapshot?.releasesPageUrl || sidepanelUpdateService?.releasesPageUrl || '';
if (btnReleaseLog) { if (btnReleaseLog) {
@@ -1955,13 +1955,13 @@ function renderReleaseSnapshot(snapshot) {
updateSection.hidden = false; updateSection.hidden = false;
} }
if (updateCardVersion) { if (updateCardVersion) {
updateCardVersion.textContent = `最新版本 v${snapshot.latestVersion}`; updateCardVersion.textContent = `最新版本 ${snapshot.latestVersion}`;
} }
if (updateCardSummary) { if (updateCardSummary) {
const updateCount = Array.isArray(snapshot.newerReleases) ? snapshot.newerReleases.length : 0; const updateCount = Array.isArray(snapshot.newerReleases) ? snapshot.newerReleases.length : 0;
updateCardSummary.textContent = updateCount > 1 updateCardSummary.textContent = updateCount > 1
? `当前 ${localVersionText},共有 ${updateCount} 个新版本可更新。` ? `当前 ${localVersionText},共有 ${updateCount} 个新版本可更新。`
: `当前 ${localVersionText},可更新到 v${snapshot.latestVersion}`; : `当前 ${localVersionText},可更新到 ${snapshot.latestVersion}`;
} }
renderUpdateReleaseList(snapshot.newerReleases || []); renderUpdateReleaseList(snapshot.newerReleases || []);
if (btnOpenRelease) { if (btnOpenRelease) {
@@ -1973,14 +1973,14 @@ function renderReleaseSnapshot(snapshot) {
} }
case 'latest': { case 'latest': {
extensionUpdateStatus.textContent = localVersionText || 'v0.0.0'; extensionUpdateStatus.textContent = localVersionText || 'Pro0.0';
extensionUpdateStatus.classList.add('is-version-label'); extensionUpdateStatus.classList.add('is-version-label');
resetUpdateCard(); resetUpdateCard();
break; break;
} }
case 'empty': { case 'empty': {
extensionUpdateStatus.textContent = localVersionText || 'v0.0.0'; extensionUpdateStatus.textContent = localVersionText || 'Pro0.0';
extensionUpdateStatus.classList.add('is-version-label'); extensionUpdateStatus.classList.add('is-version-label');
resetUpdateCard(); resetUpdateCard();
break; break;
@@ -1988,7 +1988,7 @@ function renderReleaseSnapshot(snapshot) {
case 'error': case 'error':
default: { default: {
extensionUpdateStatus.textContent = localVersionText || 'v0.0.0'; extensionUpdateStatus.textContent = localVersionText || 'Pro0.0';
extensionUpdateStatus.classList.add('is-version-label', 'is-check-failed'); extensionUpdateStatus.classList.add('is-version-label', 'is-check-failed');
extensionVersionMeta.textContent = snapshot?.errorMessage || 'GitHub Releases 检查失败'; extensionVersionMeta.textContent = snapshot?.errorMessage || 'GitHub Releases 检查失败';
extensionVersionMeta.hidden = false; extensionVersionMeta.hidden = false;
@@ -2009,8 +2009,10 @@ async function initializeReleaseInfo() {
return; return;
} }
const localVersion = sidepanelUpdateService?.stripVersionPrefix?.(chrome.runtime.getManifest()?.version || '') || ''; const localVersion = sidepanelUpdateService?.getLocalVersionLabel?.(chrome.runtime.getManifest())
extensionUpdateStatus.textContent = localVersion ? `v${localVersion}` : 'v0.0.0'; || chrome.runtime.getManifest()?.version_name
|| (chrome.runtime.getManifest()?.version ? `v${chrome.runtime.getManifest().version}` : '');
extensionUpdateStatus.textContent = localVersion || 'Pro0.0';
extensionUpdateStatus.classList.remove('is-update-available', 'is-check-failed'); extensionUpdateStatus.classList.remove('is-update-available', 'is-check-failed');
extensionUpdateStatus.classList.add('is-version-label'); extensionUpdateStatus.classList.add('is-version-label');
extensionVersionMeta.hidden = true; extensionVersionMeta.hidden = true;
+89 -20
View File
@@ -8,26 +8,78 @@
const FETCH_TIMEOUT_MS = 8000; const FETCH_TIMEOUT_MS = 8000;
const MAX_RELEASES = 10; const MAX_RELEASES = 10;
const MAX_NOTES_PER_RELEASE = 5; const MAX_NOTES_PER_RELEASE = 5;
const VERSION_FAMILY_PRO = 'pro';
const VERSION_FAMILY_LEGACY = 'legacy';
function getVersionFamily(version, fallbackFamily = VERSION_FAMILY_LEGACY) {
const trimmed = String(version || '').trim();
if (/^pro/i.test(trimmed)) {
return VERSION_FAMILY_PRO;
}
if (/^v/i.test(trimmed)) {
return VERSION_FAMILY_LEGACY;
}
return fallbackFamily;
}
function stripVersionPrefix(version) { function stripVersionPrefix(version) {
return String(version || '').trim().replace(/^v/i, ''); return String(version || '').trim().replace(/^(?:pro|v)\s*/i, '');
} }
function parseVersionParts(version) { function extractVersionCore(version) {
const core = stripVersionPrefix(version).split('-')[0]; const core = stripVersionPrefix(version).split('-')[0];
if (!core) { return /^\d+(?:\.\d+){1,3}$/.test(core) ? core : '';
return [0];
} }
return core.split('.').map((part) => { function formatDisplayVersion(version, fallbackFamily = VERSION_FAMILY_LEGACY) {
const core = extractVersionCore(version);
if (!core) {
return '';
}
const family = getVersionFamily(version, fallbackFamily);
return `${family === VERSION_FAMILY_PRO ? 'Pro' : 'v'}${core}`;
}
function parseVersionMeta(version, fallbackFamily = VERSION_FAMILY_LEGACY) {
const family = getVersionFamily(version, fallbackFamily);
const core = extractVersionCore(version);
return {
family,
core,
displayVersion: core ? `${family === VERSION_FAMILY_PRO ? 'Pro' : 'v'}${core}` : '',
parts: core
? core.split('.').map((part) => {
const numeric = Number.parseInt(part, 10); const numeric = Number.parseInt(part, 10);
return Number.isFinite(numeric) ? numeric : 0; return Number.isFinite(numeric) ? numeric : 0;
}); })
: [0],
};
} }
function compareVersions(left, right) { function getVersionFamilyRank(family) {
const leftParts = parseVersionParts(left); return family === VERSION_FAMILY_PRO ? 2 : 1;
const rightParts = parseVersionParts(right); }
function parseVersionParts(version, fallbackFamily = VERSION_FAMILY_LEGACY) {
return parseVersionMeta(version, fallbackFamily).parts;
}
function compareVersions(left, right, fallbackFamily = VERSION_FAMILY_LEGACY) {
const leftMeta = parseVersionMeta(left, fallbackFamily);
const rightMeta = parseVersionMeta(right, fallbackFamily);
const leftFamilyRank = getVersionFamilyRank(leftMeta.family);
const rightFamilyRank = getVersionFamilyRank(rightMeta.family);
if (leftFamilyRank > rightFamilyRank) {
return 1;
}
if (leftFamilyRank < rightFamilyRank) {
return -1;
}
const leftParts = leftMeta.parts;
const rightParts = rightMeta.parts;
const maxLength = Math.max(leftParts.length, rightParts.length, 3); const maxLength = Math.max(leftParts.length, rightParts.length, 3);
for (let index = 0; index < maxLength; index += 1) { for (let index = 0; index < maxLength; index += 1) {
@@ -100,26 +152,31 @@
]; ];
for (const candidate of candidates) { for (const candidate of candidates) {
const normalized = stripVersionPrefix(candidate); const meta = parseVersionMeta(candidate);
if (normalized) { if (meta.core) {
return normalized; return meta;
} }
} }
return ''; return null;
} }
function sanitizeRelease(release) { function sanitizeRelease(release) {
const version = normalizeReleaseVersion(release); const versionMeta = normalizeReleaseVersion(release);
if (!version) { if (!versionMeta?.core) {
return null; return null;
} }
const rawTitle = sanitizeInlineMarkdown(release?.name || ''); const rawTitle = sanitizeInlineMarkdown(release?.name || '');
const normalizedTitle = stripVersionPrefix(rawTitle) === version ? '' : rawTitle; const titleMeta = parseVersionMeta(rawTitle, versionMeta.family);
const normalizedTitle = titleMeta.core && titleMeta.displayVersion === versionMeta.displayVersion
? ''
: rawTitle;
return { return {
version, version: versionMeta.core,
displayVersion: versionMeta.displayVersion,
family: versionMeta.family,
title: normalizedTitle, title: normalizedTitle,
url: String(release?.html_url || RELEASES_PAGE_URL), url: String(release?.html_url || RELEASES_PAGE_URL),
publishedAt: String(release?.published_at || release?.created_at || ''), publishedAt: String(release?.published_at || release?.created_at || ''),
@@ -228,11 +285,11 @@
}; };
} }
const newerReleases = releases.filter((release) => compareVersions(release.version, localVersion) > 0); const newerReleases = releases.filter((release) => compareVersions(release.displayVersion, localVersion) > 0);
return { return {
status: newerReleases.length > 0 ? 'update-available' : 'latest', status: newerReleases.length > 0 ? 'update-available' : 'latest',
localVersion, localVersion,
latestVersion: latestRelease.version, latestVersion: latestRelease.displayVersion,
latestRelease, latestRelease,
newerReleases, newerReleases,
logUrl: latestRelease.url || RELEASES_PAGE_URL, logUrl: latestRelease.url || RELEASES_PAGE_URL,
@@ -241,8 +298,18 @@
}; };
} }
function getLocalVersionLabel(manifest = chrome.runtime.getManifest()) {
const versionName = formatDisplayVersion(manifest?.version_name, VERSION_FAMILY_PRO);
if (versionName) {
return versionName;
}
const versionCore = extractVersionCore(manifest?.version || '');
return versionCore ? formatDisplayVersion(`v${versionCore}`, VERSION_FAMILY_LEGACY) : '';
}
async function getReleaseSnapshot(options = {}) { async function getReleaseSnapshot(options = {}) {
const localVersion = stripVersionPrefix(chrome.runtime.getManifest()?.version || '0.0.0'); const localVersion = getLocalVersionLabel(chrome.runtime.getManifest()) || 'v0.0.0';
try { try {
const releases = await loadReleases(options); const releases = await loadReleases(options);
@@ -280,7 +347,9 @@
window.SidepanelUpdateService = { window.SidepanelUpdateService = {
compareVersions, compareVersions,
formatDisplayVersion,
formatReleaseDate, formatReleaseDate,
getLocalVersionLabel,
getReleaseSnapshot, getReleaseSnapshot,
releasesPageUrl: RELEASES_PAGE_URL, releasesPageUrl: RELEASES_PAGE_URL,
stripVersionPrefix, stripVersionPrefix,