chore: align version display with Pro release standard
This commit is contained in:
@@ -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
@@ -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;
|
||||||
|
|||||||
+90
-21
@@ -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];
|
||||||
|
return /^\d+(?:\.\d+){1,3}$/.test(core) ? core : '';
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatDisplayVersion(version, fallbackFamily = VERSION_FAMILY_LEGACY) {
|
||||||
|
const core = extractVersionCore(version);
|
||||||
if (!core) {
|
if (!core) {
|
||||||
return [0];
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
return core.split('.').map((part) => {
|
const family = getVersionFamily(version, fallbackFamily);
|
||||||
const numeric = Number.parseInt(part, 10);
|
return `${family === VERSION_FAMILY_PRO ? 'Pro' : 'v'}${core}`;
|
||||||
return Number.isFinite(numeric) ? numeric : 0;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function compareVersions(left, right) {
|
function parseVersionMeta(version, fallbackFamily = VERSION_FAMILY_LEGACY) {
|
||||||
const leftParts = parseVersionParts(left);
|
const family = getVersionFamily(version, fallbackFamily);
|
||||||
const rightParts = parseVersionParts(right);
|
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);
|
||||||
|
return Number.isFinite(numeric) ? numeric : 0;
|
||||||
|
})
|
||||||
|
: [0],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function getVersionFamilyRank(family) {
|
||||||
|
return family === VERSION_FAMILY_PRO ? 2 : 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
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,
|
||||||
|
|||||||
Reference in New Issue
Block a user