From 3678842f5a3ec786d9dc8f0d605b014d51785fc5 Mon Sep 17 00:00:00 2001 From: Daniil Pokrovsky Date: Tue, 18 Aug 2026 15:59:05 +0700 Subject: [PATCH] feat: implement DEV-72 - Show the current app version in the pm-desktop window title --- packages/pm-desktop/src/main/window.ts | 19 +++++++++++++++- packages/pm-desktop/src/shared/about.test.ts | 24 +++++++++++++++++++- packages/pm-desktop/src/shared/about.ts | 8 ++++++- 3 files changed, 48 insertions(+), 3 deletions(-) diff --git a/packages/pm-desktop/src/main/window.ts b/packages/pm-desktop/src/main/window.ts index 6332c18..e2a13b4 100644 --- a/packages/pm-desktop/src/main/window.ts +++ b/packages/pm-desktop/src/main/window.ts @@ -4,6 +4,7 @@ import { join } from "node:path"; import { BrowserWindow, app, nativeImage, shell } from "electron"; +import { APP_DISPLAY_NAME, formatAppWindowTitle } from "../shared/about.ts"; const isDev = !!process.env.ELECTRON_RENDERER_URL; @@ -16,9 +17,18 @@ export function resolveAppIconPath(): string { return join(app.getAppPath(), "build/icon.png"); } +function resolveWindowTitle(): string { + try { + return formatAppWindowTitle(app.getVersion()); + } catch { + return APP_DISPLAY_NAME; + } +} + export function createWindow(): BrowserWindow { const iconPath = resolveAppIconPath(); const icon = nativeImage.createFromPath(iconPath); + const title = resolveWindowTitle(); // macOS packaged apps use the .icns from the bundle; still set icon for // Linux window chrome and unpackaged / Windows previews. const window = new BrowserWindow({ @@ -26,7 +36,7 @@ export function createWindow(): BrowserWindow { height: 840, minWidth: 900, minHeight: 600, - title: "DevIntern PM", + title, show: false, ...(icon.isEmpty() ? {} : { icon }), webPreferences: { @@ -37,6 +47,13 @@ export function createWindow(): BrowserWindow { }, }); + // Keep the renderer's static HTML title from replacing the versioned native + // title after navigation or reload. + window.on("page-title-updated", (event) => { + event.preventDefault(); + window.setTitle(title); + }); + // Unpackaged macOS still shows the Electron dock icon unless we override. if (process.platform === "darwin" && !app.isPackaged && !icon.isEmpty()) { app.dock?.setIcon(icon); diff --git a/packages/pm-desktop/src/shared/about.test.ts b/packages/pm-desktop/src/shared/about.test.ts index a60a7e0..5accb15 100644 --- a/packages/pm-desktop/src/shared/about.test.ts +++ b/packages/pm-desktop/src/shared/about.test.ts @@ -1,5 +1,10 @@ import { describe, expect, test } from "bun:test"; -import { ABOUT_PRODUCT_NAME, ABOUT_WEBSITE_URL, APP_DISPLAY_NAME } from "./about.ts"; +import { + ABOUT_PRODUCT_NAME, + ABOUT_WEBSITE_URL, + APP_DISPLAY_NAME, + formatAppWindowTitle, +} from "./about.ts"; describe("ABOUT_WEBSITE_URL", () => { test("points at the DevIntern homepage with desktop about UTMs", () => { @@ -15,3 +20,20 @@ describe("About copy constants", () => { expect(APP_DISPLAY_NAME).toBe("DevIntern PM"); }); }); + +describe("formatAppWindowTitle", () => { + test("includes the product name and running app version", () => { + expect(formatAppWindowTitle("0.9.11")).toBe("DevIntern PM v0.9.11"); + }); + + test("normalizes surrounding version whitespace", () => { + expect(formatAppWindowTitle(" 1.2.3-beta.1 ")).toBe("DevIntern PM v1.2.3-beta.1"); + }); + + test.each([undefined, null, "", " ", 123])( + "falls back to the product name for unavailable version %p", + (version) => { + expect(formatAppWindowTitle(version)).toBe("DevIntern PM"); + }, + ); +}); diff --git a/packages/pm-desktop/src/shared/about.ts b/packages/pm-desktop/src/shared/about.ts index ba4a707..e949069 100644 --- a/packages/pm-desktop/src/shared/about.ts +++ b/packages/pm-desktop/src/shared/about.ts @@ -5,9 +5,15 @@ /** Product name shown in the About title and modal. */ export const ABOUT_PRODUCT_NAME = "DevIntern"; -/** Window / menu product label (matches BrowserWindow title). */ +/** Base product label used by the window title and application menu. */ export const APP_DISPLAY_NAME = "DevIntern PM"; +/** Build a native window title, omitting the suffix when no usable version is available. */ +export function formatAppWindowTitle(version: unknown): string { + const normalizedVersion = typeof version === "string" ? version.trim() : ""; + return normalizedVersion ? `${APP_DISPLAY_NAME} v${normalizedVersion}` : APP_DISPLAY_NAME; +} + /** * Public homepage opened from About. UTM tags match other pm-desktop surfaces * (e.g. code discovery) so desktop referral traffic stays attributable.