mirror of
https://github.com/Kpa-clawbot/meshcore-analyzer.git
synced 2026-10-23 02:01:25 +00:00
refine version badge: clickable links, version only on prod
- Commit hash is now an <a> linking to GitHub commit (full hash in URL, 7-char display) - Version tag only shown on prod (port 80/443 or no port), linked to GitHub release - Staging (non-standard port) shows commit + engine only, no version noise - Detect prod vs staging via location.port - Updated tests: 16 cases covering prod/staging/links/edge cases - Bumped cache busters Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
1 parent
a7a280801a
commit
b92e71fa0e
3 files changed
+111
-47
No files matched your search
+11
-2
@@ -107,9 +107,18 @@ function formatEngineBadge(engine) {
|
||||
|
||||
function formatVersionBadge(version, commit, engine) {
|
||||
if (!version && !commit && !engine) return '';
|
||||
var port = (typeof location !== 'undefined' && location.port) || '';
|
||||
var isProd = !port || port === '80' || port === '443';
|
||||
var GH = 'https://github.com/Kpa-clawbot/meshcore-analyzer';
|
||||
var parts = [];
|
||||
if (version) parts.push(version.charAt(0) === 'v' ? version : 'v' + version);
|
||||
if (commit && commit !== 'unknown') parts.push(commit.length > 7 ? commit.slice(0, 7) : commit);
|
||||
if (version && isProd) {
|
||||
var vTag = version.charAt(0) === 'v' ? version : 'v' + version;
|
||||
parts.push('<a href="' + GH + '/releases/tag/' + vTag + '" target="_blank" rel="noopener">' + vTag + '</a>');
|
||||
}
|
||||
if (commit && commit !== 'unknown') {
|
||||
var short = commit.length > 7 ? commit.slice(0, 7) : commit;
|
||||
parts.push('<a href="' + GH + '/commit/' + commit + '" target="_blank" rel="noopener">' + short + '</a>');
|
||||
}
|
||||
if (engine) parts.push('[' + engine + ']');
|
||||
if (parts.length === 0) return '';
|
||||
return ' <span class="version-badge">' + parts.join(' · ') + '</span>';
|
||||
|
||||
+27
-27
@@ -22,9 +22,9 @@
|
||||
<meta name="twitter:title" content="MeshCore Analyzer">
|
||||
<meta name="twitter:description" content="Real-time MeshCore LoRa mesh network analyzer — live packet visualization, node tracking, channel decryption, and route analysis.">
|
||||
<meta name="twitter:image" content="https://raw.githubusercontent.com/Kpa-clawbot/meshcore-analyzer/master/public/og-image.png">
|
||||
<link rel="stylesheet" href="style.css?v=1774630314">
|
||||
<link rel="stylesheet" href="home.css?v=1774630314">
|
||||
<link rel="stylesheet" href="live.css?v=1774630314">
|
||||
<link rel="stylesheet" href="style.css?v=1774630476">
|
||||
<link rel="stylesheet" href="home.css?v=1774630476">
|
||||
<link rel="stylesheet" href="live.css?v=1774630476">
|
||||
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css"
|
||||
integrity="sha256-p4NxAoJBhIIN+hmNHrzRCf9tD/miZyoHS5obTRR9BMY="
|
||||
crossorigin="anonymous">
|
||||
@@ -81,29 +81,29 @@
|
||||
<main id="app" role="main"></main>
|
||||
|
||||
<script src="vendor/qrcode.js"></script>
|
||||
<script src="roles.js?v=1774630314"></script>
|
||||
<script src="customize.js?v=1774630314" onerror="console.error('Failed to load:', this.src)"></script>
|
||||
<script src="region-filter.js?v=1774630314"></script>
|
||||
<script src="hop-resolver.js?v=1774630314"></script>
|
||||
<script src="hop-display.js?v=1774630314"></script>
|
||||
<script src="app.js?v=1774630314"></script>
|
||||
<script src="home.js?v=1774630314"></script>
|
||||
<script src="packet-filter.js?v=1774630314"></script>
|
||||
<script src="packets.js?v=1774630314"></script>
|
||||
<script src="map.js?v=1774630314" onerror="console.error('Failed to load:', this.src)"></script>
|
||||
<script src="channels.js?v=1774630314" onerror="console.error('Failed to load:', this.src)"></script>
|
||||
<script src="nodes.js?v=1774630314" onerror="console.error('Failed to load:', this.src)"></script>
|
||||
<script src="traces.js?v=1774630314" onerror="console.error('Failed to load:', this.src)"></script>
|
||||
<script src="analytics.js?v=1774630314" onerror="console.error('Failed to load:', this.src)"></script>
|
||||
<script src="audio.js?v=1774630314" onerror="console.error('Failed to load:', this.src)"></script>
|
||||
<script src="audio-v1-constellation.js?v=1774630314" onerror="console.error('Failed to load:', this.src)"></script>
|
||||
<script src="audio-v2-constellation.js?v=1774630314" onerror="console.error('Failed to load:', this.src)"></script>
|
||||
<script src="audio-lab.js?v=1774630314" onerror="console.error('Failed to load:', this.src)"></script>
|
||||
<script src="live.js?v=1774630314" onerror="console.error('Failed to load:', this.src)"></script>
|
||||
<script src="observers.js?v=1774630314" onerror="console.error('Failed to load:', this.src)"></script>
|
||||
<script src="observer-detail.js?v=1774630314" onerror="console.error('Failed to load:', this.src)"></script>
|
||||
<script src="compare.js?v=1774630314" onerror="console.error('Failed to load:', this.src)"></script>
|
||||
<script src="node-analytics.js?v=1774630314" onerror="console.error('Failed to load:', this.src)"></script>
|
||||
<script src="perf.js?v=1774630314" onerror="console.error('Failed to load:', this.src)"></script>
|
||||
<script src="roles.js?v=1774630476"></script>
|
||||
<script src="customize.js?v=1774630476" onerror="console.error('Failed to load:', this.src)"></script>
|
||||
<script src="region-filter.js?v=1774630476"></script>
|
||||
<script src="hop-resolver.js?v=1774630476"></script>
|
||||
<script src="hop-display.js?v=1774630476"></script>
|
||||
<script src="app.js?v=1774630476"></script>
|
||||
<script src="home.js?v=1774630476"></script>
|
||||
<script src="packet-filter.js?v=1774630476"></script>
|
||||
<script src="packets.js?v=1774630476"></script>
|
||||
<script src="map.js?v=1774630476" onerror="console.error('Failed to load:', this.src)"></script>
|
||||
<script src="channels.js?v=1774630476" onerror="console.error('Failed to load:', this.src)"></script>
|
||||
<script src="nodes.js?v=1774630476" onerror="console.error('Failed to load:', this.src)"></script>
|
||||
<script src="traces.js?v=1774630476" onerror="console.error('Failed to load:', this.src)"></script>
|
||||
<script src="analytics.js?v=1774630476" onerror="console.error('Failed to load:', this.src)"></script>
|
||||
<script src="audio.js?v=1774630476" onerror="console.error('Failed to load:', this.src)"></script>
|
||||
<script src="audio-v1-constellation.js?v=1774630476" onerror="console.error('Failed to load:', this.src)"></script>
|
||||
<script src="audio-v2-constellation.js?v=1774630476" onerror="console.error('Failed to load:', this.src)"></script>
|
||||
<script src="audio-lab.js?v=1774630476" onerror="console.error('Failed to load:', this.src)"></script>
|
||||
<script src="live.js?v=1774630476" onerror="console.error('Failed to load:', this.src)"></script>
|
||||
<script src="observers.js?v=1774630476" onerror="console.error('Failed to load:', this.src)"></script>
|
||||
<script src="observer-detail.js?v=1774630476" onerror="console.error('Failed to load:', this.src)"></script>
|
||||
<script src="compare.js?v=1774630476" onerror="console.error('Failed to load:', this.src)"></script>
|
||||
<script src="node-analytics.js?v=1774630476" onerror="console.error('Failed to load:', this.src)"></script>
|
||||
<script src="perf.js?v=1774630476" onerror="console.error('Failed to load:', this.src)"></script>
|
||||
</body>
|
||||
</html>
|
||||
+73
-18
@@ -1166,54 +1166,109 @@ console.log('\n=== app.js: formatEngineBadge ===');
|
||||
// ===== APP.JS: formatVersionBadge =====
|
||||
console.log('\n=== app.js: formatVersionBadge ===');
|
||||
{
|
||||
const ctx = makeSandbox();
|
||||
loadInCtx(ctx, 'public/roles.js');
|
||||
loadInCtx(ctx, 'public/app.js');
|
||||
const formatVersionBadge = ctx.formatVersionBadge;
|
||||
function makeBadgeSandbox(port) {
|
||||
const ctx = makeSandbox();
|
||||
ctx.location.port = port || '';
|
||||
loadInCtx(ctx, 'public/roles.js');
|
||||
loadInCtx(ctx, 'public/app.js');
|
||||
return ctx;
|
||||
}
|
||||
const GH = 'https://github.com/Kpa-clawbot/meshcore-analyzer';
|
||||
|
||||
test('returns empty string when all args missing', () => {
|
||||
const { formatVersionBadge } = makeBadgeSandbox('');
|
||||
assert.strictEqual(formatVersionBadge(null, null, null), '');
|
||||
assert.strictEqual(formatVersionBadge(undefined, undefined, undefined), '');
|
||||
assert.strictEqual(formatVersionBadge('', '', ''), '');
|
||||
});
|
||||
test('shows version + commit + engine', () => {
|
||||
const result = formatVersionBadge('2.6.0', 'abc1234def', 'go');
|
||||
|
||||
// --- Prod tests (no port / port 80 / port 443) ---
|
||||
test('prod: shows version + commit + engine with links', () => {
|
||||
const { formatVersionBadge } = makeBadgeSandbox('');
|
||||
const result = formatVersionBadge('2.6.0', 'abc1234def5678', 'node');
|
||||
assert.ok(result.includes('version-badge'), 'should have version-badge class');
|
||||
assert.ok(result.includes('v2.6.0'), 'should show version with v prefix');
|
||||
assert.ok(result.includes('abc1234'), 'should show truncated commit');
|
||||
assert.ok(!result.includes('abc1234d'), 'should truncate commit to 7 chars');
|
||||
assert.ok(result.includes('[go]'), 'should show engine in brackets');
|
||||
assert.ok(result.includes(`href="${GH}/releases/tag/v2.6.0"`), 'version links to release');
|
||||
assert.ok(result.includes('>v2.6.0</a>'), 'version text has v prefix');
|
||||
assert.ok(result.includes(`href="${GH}/commit/abc1234def5678"`), 'commit links to full hash');
|
||||
assert.ok(result.includes('>abc1234</a>'), 'commit display is truncated to 7');
|
||||
assert.ok(result.includes('[node]'), 'should show engine');
|
||||
});
|
||||
test('version already has v prefix', () => {
|
||||
test('prod port 80: shows version', () => {
|
||||
const { formatVersionBadge } = makeBadgeSandbox('80');
|
||||
const result = formatVersionBadge('2.6.0', null, 'node');
|
||||
assert.ok(result.includes('>v2.6.0</a>'), 'port 80 is prod — shows version');
|
||||
});
|
||||
test('prod port 443: shows version', () => {
|
||||
const { formatVersionBadge } = makeBadgeSandbox('443');
|
||||
const result = formatVersionBadge('2.6.0', null, 'node');
|
||||
assert.ok(result.includes('>v2.6.0</a>'), 'port 443 is prod — shows version');
|
||||
});
|
||||
test('prod: version already has v prefix', () => {
|
||||
const { formatVersionBadge } = makeBadgeSandbox('');
|
||||
const result = formatVersionBadge('v2.6.0', null, null);
|
||||
assert.ok(result.includes('v2.6.0'), 'should not double the v prefix');
|
||||
assert.ok(result.includes('>v2.6.0</a>'), 'should not double the v prefix');
|
||||
assert.ok(!result.includes('vv'), 'should not have vv');
|
||||
});
|
||||
|
||||
// --- Staging tests (non-standard port) ---
|
||||
test('staging: hides version, shows commit + engine', () => {
|
||||
const { formatVersionBadge } = makeBadgeSandbox('3000');
|
||||
const result = formatVersionBadge('2.6.0', 'abc1234def5678', 'go');
|
||||
assert.ok(!result.includes('v2.6.0'), 'staging should NOT show version');
|
||||
assert.ok(result.includes('>abc1234</a>'), 'should show commit hash');
|
||||
assert.ok(result.includes(`href="${GH}/commit/abc1234def5678"`), 'commit is linked');
|
||||
assert.ok(result.includes('[go]'), 'should show engine');
|
||||
});
|
||||
test('staging port 81: hides version', () => {
|
||||
const { formatVersionBadge } = makeBadgeSandbox('81');
|
||||
const result = formatVersionBadge('2.6.0', 'abc1234', 'go');
|
||||
assert.ok(!result.includes('v2.6.0'), 'port 81 is staging — no version');
|
||||
assert.ok(result.includes('>abc1234</a>'), 'commit shown');
|
||||
});
|
||||
|
||||
// --- Shared behavior ---
|
||||
test('commit link uses full hash', () => {
|
||||
const { formatVersionBadge } = makeBadgeSandbox('');
|
||||
const result = formatVersionBadge(null, 'abc1234def567890123456789abcdef012345678', 'node');
|
||||
assert.ok(result.includes(`href="${GH}/commit/abc1234def567890123456789abcdef012345678"`), 'link uses full hash');
|
||||
assert.ok(result.includes('>abc1234</a>'), 'display is truncated to 7');
|
||||
});
|
||||
test('skips commit when "unknown"', () => {
|
||||
const { formatVersionBadge } = makeBadgeSandbox('');
|
||||
const result = formatVersionBadge('2.6.0', 'unknown', 'node');
|
||||
assert.ok(result.includes('v2.6.0'), 'should show version');
|
||||
assert.ok(result.includes('>v2.6.0</a>'), 'should show version');
|
||||
assert.ok(!result.includes('unknown'), 'should not show unknown commit');
|
||||
assert.ok(result.includes('[node]'), 'should show engine');
|
||||
});
|
||||
test('skips commit when missing', () => {
|
||||
const { formatVersionBadge } = makeBadgeSandbox('');
|
||||
const result = formatVersionBadge('2.6.0', null, 'go');
|
||||
assert.ok(result.includes('v2.6.0'), 'should show version');
|
||||
assert.ok(result.includes('>v2.6.0</a>'), 'should show version');
|
||||
assert.ok(result.includes('[go]'), 'should show engine');
|
||||
});
|
||||
test('shows only engine when version/commit missing', () => {
|
||||
const { formatVersionBadge } = makeBadgeSandbox('3000');
|
||||
const result = formatVersionBadge(null, null, 'go');
|
||||
assert.ok(result.includes('[go]'), 'should show engine');
|
||||
assert.ok(result.includes('version-badge'), 'should use version-badge class');
|
||||
});
|
||||
test('short commit not truncated', () => {
|
||||
test('short commit not truncated in display', () => {
|
||||
const { formatVersionBadge } = makeBadgeSandbox('');
|
||||
const result = formatVersionBadge('1.0.0', 'abc1234', 'node');
|
||||
assert.ok(result.includes('abc1234'), 'should show full short commit');
|
||||
assert.ok(result.includes('>abc1234</a>'), 'should show full short commit');
|
||||
});
|
||||
test('version only', () => {
|
||||
test('version only on prod', () => {
|
||||
const { formatVersionBadge } = makeBadgeSandbox('');
|
||||
const result = formatVersionBadge('2.6.0', null, null);
|
||||
assert.ok(result.includes('v2.6.0'), 'should show version');
|
||||
assert.ok(result.includes('>v2.6.0</a>'), 'should show version');
|
||||
assert.ok(!result.includes('·'), 'should not have separator for single part');
|
||||
});
|
||||
test('staging: only engine when no commit', () => {
|
||||
const { formatVersionBadge } = makeBadgeSandbox('8080');
|
||||
const result = formatVersionBadge('2.6.0', null, 'go');
|
||||
assert.ok(!result.includes('2.6.0'), 'no version on staging');
|
||||
assert.ok(result.includes('[go]'), 'engine shown');
|
||||
});
|
||||
}
|
||||
|
||||
// ===== SUMMARY =====
|
||||
|
||||
Reference in new issue
Block a user