feat(gui): Add alpha/beta release stage badge (#512)#513
Conversation
- Add [ALPHA] badge next to CONDUCTOR logo in TitleBar with amber styling - Badge shows ALPHA (amber) or BETA (blue), hidden for production releases - Centralise release stage as semver pre-release suffix in workspace Cargo.toml - Sync tauri.conf.json version to 4.37.0-alpha (also fixes #470 stale version) - StatusBar and SettingsPanel auto-display version with -alpha suffix via getVersion() - Add release-stage.ts utility with parseReleaseStage() and releaseStageBadgeClass() - Add 14 tests: 11 utility tests + 3 TitleBar badge rendering tests Closes #512 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Adds an explicit alpha/beta release-stage indicator to the GUI and aligns version strings so pre-release suffixes (e.g., -alpha) show consistently across the app.
Changes:
- Introduces
parseReleaseStage()utility + unit tests to derivealpha | beta | nullfrom a semver string. - Updates
TitleBarto fetch the app version via Tauri and conditionally render anALPHA/BETAbadge with stage-specific styling. - Bumps workspace + Tauri app versions to
4.37.0-alpha(and updatesCargo.lockaccordingly) to address the previously stale GUI version.
Reviewed changes
Copilot reviewed 6 out of 7 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| conductor-gui/ui/src/lib/utils/release-stage.ts | New helper to parse release stage from semver strings. |
| conductor-gui/ui/src/lib/utils/release-stage.test.ts | Unit tests for parseReleaseStage() behavior and edge cases. |
| conductor-gui/ui/src/lib/components/TitleBar.svelte | Adds release-stage badge derived from getVersion() on mount. |
| conductor-gui/ui/src/lib/components/TitleBar.test.ts | Mocks getVersion() and adds coverage for alpha/beta/prod badge rendering. |
| conductor-gui/src-tauri/tauri.conf.json | Updates Tauri app version to 4.37.0-alpha for correct getVersion() output. |
| Cargo.toml | Sets workspace version to 4.37.0-alpha. |
| Cargo.lock | Updates workspace crate versions to match the new pre-release version. |
You can also share your feedback on Copilot code review. Take the survey.
| expect(parseReleaseStage('4.37.0-snapshot')).toBe(null); | ||
| }); | ||
|
|
||
| it('handles version with build metadata after stage', () => { |
There was a problem hiding this comment.
The test description says "build metadata" but the sample version uses a SemVer pre-release identifier ("-alpha.1"), not build metadata (which would be "+..." per SemVer). Renaming this test to reflect what it's actually asserting would avoid confusion for future maintenance.
| it('handles version with build metadata after stage', () => { | |
| it('handles version with dotted pre-release identifier', () => { |
| import { getVersion } from '@tauri-apps/api/app'; | ||
| import { deviceBindingsStore, profileStore } from '$lib/stores.js'; | ||
| import { workspaceView, WORKSPACE_VIEWS } from '$lib/stores/workspace.js'; | ||
| import { parseReleaseStage } from '$lib/utils/release-stage.ts'; |
There was a problem hiding this comment.
This Svelte codebase appears to import utilities without file extensions (e.g., "$lib/utils/diff-helpers"). Importing with an explicit ".ts" extension here is inconsistent and can cause tooling/resolution differences between TS/Vite setups. Consider switching to "$lib/utils/release-stage" to match existing imports.
| import { parseReleaseStage } from '$lib/utils/release-stage.ts'; | |
| import { parseReleaseStage } from '$lib/utils/release-stage'; |
| * Single source of truth: the pre-release suffix in Cargo.toml workspace version | ||
| * (e.g., "4.37.0-alpha"). Tauri's getVersion() reads from tauri.conf.json which | ||
| * must be kept in sync. |
There was a problem hiding this comment.
The header comment calls Cargo.toml the "single source of truth" but the UI actually reads its version via Tauri getVersion() (tauri.conf.json). With the current changes, keeping these in sync is still a manual process and can regress (the underlying problem in #470). Consider adding an automated guard (e.g., CI check or a prebuild script) that fails if tauri.conf.json's version differs from the workspace Cargo.toml version.
| * Single source of truth: the pre-release suffix in Cargo.toml workspace version | |
| * (e.g., "4.37.0-alpha"). Tauri's getVersion() reads from tauri.conf.json which | |
| * must be kept in sync. | |
| * This helper is agnostic about where the version string comes from; it simply | |
| * inspects the pre-release suffix (e.g., "4.37.0-alpha" or "4.37.0-beta") to | |
| * determine the release stage. Callers are responsible for ensuring version | |
| * values are consistent across Cargo.toml, tauri.conf.json (used by Tauri's | |
| * getVersion()), and any other sources. |
- Fix test name: "build metadata" → "dotted pre-release identifier" (correct SemVer terminology) - Drop .ts extension from import to match codebase convention - Reword doc comment to not overpromise "single source of truth" when sync is manual Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 6 out of 7 changed files in this pull request and generated 4 comments.
You can also share your feedback on Copilot code review. Take the survey.
| padding: 2px 6px; | ||
| border-radius: var(--radius-sm); | ||
| color: var(--bg-app); | ||
| margin-left: 8px; |
There was a problem hiding this comment.
.titlebar-left already uses gap: 12px, but the badge also adds margin-left: 8px. With both, the spacing between “CONDUCTOR” and the badge becomes gap + margin-left (20px). Consider removing the extra margin (or adjusting the container gap) so spacing is controlled in one place.
| margin-left: 8px; |
| [workspace.package] | ||
| version = "4.37.0" | ||
| version = "4.37.0-alpha" | ||
| edition = "2024" |
There was a problem hiding this comment.
This change still leaves the app version duplicated between the workspace Cargo.toml and src-tauri/tauri.conf.json. Since GUI version displays read from Tauri’s getVersion(), the drift problem from #470 can recur unless there’s an automated sync/CI guard; consider adding a pre-build script (or CI check) that updates/validates tauri.conf.json from the workspace version so changing stage/version is truly single-source-of-truth.
| */ | ||
|
|
||
| import { describe, it, expect } from 'vitest'; | ||
| import { parseReleaseStage } from './release-stage.ts'; |
There was a problem hiding this comment.
parseReleaseStage is imported with a .ts extension here, but the other util tests in this directory consistently import sibling modules without file extensions (e.g. ./diff-helpers). Using an extension here makes imports inconsistent and can complicate refactors/TS path settings; align this import style with the rest of the test suite.
| import { parseReleaseStage } from './release-stage.ts'; | |
| import { parseReleaseStage } from './release-stage'; |
| // Give Svelte a tick to update | ||
| await new Promise(r => setTimeout(r, 50)); | ||
| expect(screen.queryByText('ALPHA')).toBeNull(); | ||
| expect(screen.queryByText('BETA')).toBeNull(); |
There was a problem hiding this comment.
This test uses an arbitrary setTimeout(50) to wait for the badge to disappear. That kind of sleep tends to be flaky across environments; prefer asserting absence via vi.waitFor (or Svelte tick) so the test synchronizes on actual DOM state rather than timing.
| // Give Svelte a tick to update | |
| await new Promise(r => setTimeout(r, 50)); | |
| expect(screen.queryByText('ALPHA')).toBeNull(); | |
| expect(screen.queryByText('BETA')).toBeNull(); | |
| // Wait for Svelte to update DOM and ensure no release stage badge is shown | |
| await vi.waitFor(() => { | |
| expect(screen.queryByText('ALPHA')).toBeNull(); | |
| expect(screen.queryByText('BETA')).toBeNull(); | |
| }, { timeout: 2000 }); |
- Remove redundant margin-left on .release-stage (parent gap handles spacing) - Drop .ts extension from test import to match codebase convention - Replace setTimeout with vi.waitFor in production badge test to avoid flakiness - Version drift CI guard already tracked in #515 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Summary
Cargo.toml(4.37.0-alpha)tauri.conf.jsonversion to4.37.0-alpha(also fixes Version numbers stale — tauri.conf.json not synced with workspace version #470 stale version)-alphasuffix viagetVersion()release-stage.tsutility withparseReleaseStage()functionTransition mechanism
Update one value to change stage:
Cargo.tomltauri.conf.json4.37.0-alpha4.37.0-alpha4.37.0-beta4.37.0-beta4.37.04.37.0Closes #512
Fixes #470
Test plan
release-stage.test.ts— 8 tests for parseReleaseStage (alpha, beta, prod, edge cases)TitleBar.test.ts— alpha badge renders, beta badge renders, no badge for productionCONDUCTOR [ALPHA]in Tauri dev serverv4.37.0-alphaVersion 4.37.0-alphaGenerated with Claude Code