feat: add RC badge to header for release candidate versions

The Pulse logo now displays an orange "RC" badge when running a release
candidate version. This helps users identify when they're testing pre-release
versions.

- Backend now detects RC versions and sets channel field accordingly
- Frontend displays RC badge next to Pulse logo when channel is "rc"
- Works for both git-based and VERSION file-based builds
This commit is contained in:
Pulse Monitor 2025-08-12 14:47:21 +00:00
parent e42c1ab4e8
commit ef3789e9e0
6 changed files with 51 additions and 6 deletions

View file

@ -113,6 +113,9 @@ function App() {
<circle class="pulse-center fill-white dark:fill-[#dbeafe]" cx="128" cy="128" r="26"/>
</svg>
<span class="text-lg font-medium text-gray-800 dark:text-gray-200">Pulse</span>
<Show when={versionInfo()?.channel === 'rc'}>
<span class="text-xs px-1.5 py-0.5 bg-orange-500 text-white rounded font-bold">RC</span>
</Show>
</div>
<div class="header-controls flex justify-end items-center gap-4 md:flex-1">
<button

View file

@ -6,8 +6,8 @@
<meta name="theme-color" content="#000000" />
<link rel="icon" type="image/svg+xml" href="/logo.svg" />
<title>Pulse</title>
<script type="module" crossorigin src="/assets/index-Dt2XQ68J.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-Dn2FcXYT.css">
<script type="module" crossorigin src="/assets/index-Dw5R8pC-.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-CqoxKn9z.css">
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>

View file

@ -48,6 +48,17 @@ export function Dashboard(props: DashboardProps) {
// Create tooltip system
const TooltipComponent = createTooltipSystem();
// Create a mapping from node name to host URL
const nodeHostMap = createMemo(() => {
const map: Record<string, string> = {};
props.nodes.forEach(node => {
if (node.host) {
map[node.name] = node.host;
}
});
return map;
});
// Persist filter states to localStorage
createEffect(() => {
localStorage.setItem('dashboardViewMode', viewMode());
@ -642,7 +653,7 @@ export function Dashboard(props: DashboardProps) {
<tr class="node-header bg-gray-50 dark:bg-gray-700/50 font-semibold text-gray-700 dark:text-gray-300 text-xs">
<td class="px-2 py-1 text-xs font-medium text-gray-500 dark:text-gray-400 w-[200px]">
<a
href={`https://${node}:8006`}
href={nodeHostMap()[node] || (node.includes(':') ? `https://${node}` : `https://${node}:8006`)}
target="_blank"
rel="noopener noreferrer"
class="text-gray-500 dark:text-gray-400 hover:text-blue-600 dark:hover:text-blue-400 transition-colors duration-150 cursor-pointer"

View file

@ -21,6 +21,17 @@ const Storage: Component = () => {
// Create tooltip system
const TooltipComponent = createTooltipSystem();
// Create a mapping from node name to host URL
const nodeHostMap = createMemo(() => {
const map: Record<string, string> = {};
(state.nodes || []).forEach(node => {
if (node.host) {
map[node.name] = node.host;
}
});
return map;
});
// Load preferences from localStorage
createEffect(() => {
const savedViewMode = localStorage.getItem('storageViewMode');
@ -335,7 +346,7 @@ const Storage: Component = () => {
<tr class="bg-gray-50 dark:bg-gray-700/50 font-semibold text-gray-700 dark:text-gray-300 text-xs">
<td class="px-2 py-1 text-xs font-medium text-gray-500 dark:text-gray-400">
<a
href={`https://${groupName}:8006`}
href={nodeHostMap()[groupName] || (groupName.includes(':') ? `https://${groupName}` : `https://${groupName}:8006`)}
target="_blank"
rel="noopener noreferrer"
class="text-gray-500 dark:text-gray-400 hover:text-blue-600 dark:hover:text-blue-400 transition-colors duration-150 cursor-pointer"

View file

@ -21,6 +21,7 @@ export interface Node {
id: string;
name: string;
instance: string;
host: string;
status: string;
type: string;
cpu: number;

View file

@ -118,10 +118,16 @@ func GetCurrentVersion() (*VersionInfo, error) {
// Try to get version from git first (development)
gitVersion, err := getGitVersion()
if err == nil && gitVersion != "" {
// Determine channel from git version
channel := "stable"
if strings.Contains(strings.ToLower(gitVersion), "rc") {
channel = "rc"
}
return &VersionInfo{
Version: gitVersion,
Build: "development",
Runtime: "go",
Channel: channel,
IsDevelopment: true,
IsDocker: isDockerEnvironment(),
}, nil
@ -137,10 +143,17 @@ func GetCurrentVersion() (*VersionInfo, error) {
for _, path := range versionPaths {
versionBytes, err := os.ReadFile(path)
if err == nil {
version := strings.TrimSpace(string(versionBytes))
// Determine channel from version string
channel := "stable"
if strings.Contains(strings.ToLower(version), "rc") {
channel = "rc"
}
return &VersionInfo{
Version: strings.TrimSpace(string(versionBytes)),
Version: version,
Build: "release",
Runtime: "go",
Channel: channel,
IsDevelopment: false,
IsDocker: isDockerEnvironment(),
}, nil
@ -148,10 +161,16 @@ func GetCurrentVersion() (*VersionInfo, error) {
}
// Final fallback
version := "4.3.1-rc.1"
channel := "stable"
if strings.Contains(strings.ToLower(version), "rc") {
channel = "rc"
}
return &VersionInfo{
Version: "4.3.1-rc.1",
Version: version,
Build: "release",
Runtime: "go",
Channel: channel,
IsDevelopment: false,
IsDocker: isDockerEnvironment(),
}, nil