+
+
+
+
+
+
+ Pulse v6 RC testing
+
+
+ {V6_RC_ANNOUNCEMENT.tag}
+
+
+
+
+ 5.1.x
+ {' '}
+ remains the stable line. If you can, test v6 in a staging or
+ non-production environment and use the changelog before upgrading so the
+ move from v5 is deliberate rather than guesswork.
+
+
+
+
+
+
+
{/* Version Status Section */}
{/* Version Grid */}
diff --git a/frontend-modern/src/constants/__tests__/releaseAnnouncements.test.ts b/frontend-modern/src/constants/__tests__/releaseAnnouncements.test.ts
new file mode 100644
index 000000000..f41e8bc7c
--- /dev/null
+++ b/frontend-modern/src/constants/__tests__/releaseAnnouncements.test.ts
@@ -0,0 +1,64 @@
+import { describe, expect, it } from 'vitest';
+import type { SecurityStatus } from '@/types/config';
+import {
+ canSeeAdminReleaseAnnouncement,
+ isV5ReleaseLine,
+ shouldShowV6RcAnnouncement,
+} from '@/constants/releaseAnnouncements';
+
+describe('releaseAnnouncements', () => {
+ it('detects the v5 release line from semver strings', () => {
+ expect(isV5ReleaseLine('v5.1.27')).toBe(true);
+ expect(isV5ReleaseLine('5.1.28')).toBe(true);
+ expect(isV5ReleaseLine('v6.0.0-rc.1')).toBe(false);
+ expect(isV5ReleaseLine('')).toBe(false);
+ });
+
+ it('allows the announcement for non-proxy-auth sessions', () => {
+ const status = {
+ hasProxyAuth: false,
+ proxyAuthIsAdmin: false,
+ } as SecurityStatus;
+
+ expect(canSeeAdminReleaseAnnouncement(status)).toBe(true);
+ });
+
+ it('blocks the announcement for non-admin proxy-auth sessions', () => {
+ const status = {
+ hasProxyAuth: true,
+ proxyAuthIsAdmin: false,
+ } as SecurityStatus;
+
+ expect(canSeeAdminReleaseAnnouncement(status)).toBe(false);
+ });
+
+ it('shows the announcement only on the supported v5 surfaces', () => {
+ expect(
+ shouldShowV6RcAnnouncement({
+ version: 'v5.1.27',
+ pathname: '/proxmox/overview',
+ }),
+ ).toBe(true);
+
+ expect(
+ shouldShowV6RcAnnouncement({
+ version: 'v5.1.27',
+ pathname: '/settings/updates',
+ }),
+ ).toBe(true);
+
+ expect(
+ shouldShowV6RcAnnouncement({
+ version: 'v5.1.27',
+ pathname: '/alerts/overview',
+ }),
+ ).toBe(false);
+
+ expect(
+ shouldShowV6RcAnnouncement({
+ version: 'v6.0.0-rc.1',
+ pathname: '/settings/updates',
+ }),
+ ).toBe(false);
+ });
+});
diff --git a/frontend-modern/src/constants/releaseAnnouncements.ts b/frontend-modern/src/constants/releaseAnnouncements.ts
new file mode 100644
index 000000000..1e0fe3d6f
--- /dev/null
+++ b/frontend-modern/src/constants/releaseAnnouncements.ts
@@ -0,0 +1,60 @@
+import type { SecurityStatus } from '@/types/config';
+
+export const V6_RC_ANNOUNCEMENT = {
+ id: 'v6-rc-testing-v6.0.0-rc.1',
+ tag: 'v6.0.0-rc.1',
+ releaseUrl: 'https://github.com/rcourtman/Pulse/releases/tag/v6.0.0-rc.1',
+ changelogUrl: 'https://github.com/rcourtman/Pulse/blob/pulse/v6-release/docs/releases/V6_CHANGELOG.md',
+ demoUrl: 'https://v6-demo.pulserelay.pro',
+} as const;
+
+function parseMajorVersion(version?: string | null): number | null {
+ const match = String(version || '').trim().match(/^v?(\d+)/i);
+ if (!match) {
+ return null;
+ }
+
+ const major = Number(match[1]);
+ return Number.isFinite(major) ? major : null;
+}
+
+export function isV5ReleaseLine(version?: string | null): boolean {
+ return parseMajorVersion(version) === 5;
+}
+
+export function canSeeAdminReleaseAnnouncement(
+ securityStatus?: SecurityStatus | null,
+): boolean {
+ if (!securityStatus) {
+ return true;
+ }
+
+ if (!securityStatus.hasProxyAuth) {
+ return true;
+ }
+
+ return securityStatus.proxyAuthIsAdmin === true;
+}
+
+export function shouldShowV6RcAnnouncement(opts: {
+ version?: string | null;
+ pathname?: string | null;
+ securityStatus?: SecurityStatus | null;
+}): boolean {
+ if (!isV5ReleaseLine(opts.version)) {
+ return false;
+ }
+
+ if (!canSeeAdminReleaseAnnouncement(opts.securityStatus)) {
+ return false;
+ }
+
+ const path = opts.pathname || '';
+ return (
+ path === '/' ||
+ path === '/proxmox' ||
+ path === '/proxmox/overview' ||
+ path === '/settings' ||
+ path.startsWith('/settings/')
+ );
+}
diff --git a/frontend-modern/src/utils/localStorage.ts b/frontend-modern/src/utils/localStorage.ts
index a0c13e0a0..3ee237c57 100644
--- a/frontend-modern/src/utils/localStorage.ts
+++ b/frontend-modern/src/utils/localStorage.ts
@@ -164,6 +164,7 @@ export const STORAGE_KEYS = {
// Feature discovery
DISMISSED_FEATURE_TIPS: 'pulse-dismissed-feature-tips',
+ RELEASE_ANNOUNCEMENT_DISMISSED: 'pulse-release-announcement-dismissed',
// GitHub star prompt
GITHUB_STAR_DISMISSED: 'pulse-github-star-dismissed',