fix(ui): use Proxmox tag colours from datacenter config

Pulse was generating tag colours from a hash of the tag name instead
of using the colours configured in Proxmox. Now polls /cluster/options
once per PVE instance and merges the tag-style colour map into state,
which the frontend uses as the first-priority colour source for tag
badges. Falls back to the existing special-tag and hash-based colours
when Proxmox hasn't set a custom colour for a tag.
This commit is contained in:
rcourtman 2026-03-15 19:49:46 +00:00
parent da928cd9d3
commit caff845c1a
9 changed files with 98 additions and 3 deletions

View file

@ -2,6 +2,7 @@ import { Component, For, Show } from 'solid-js';
import { getTagColorWithSpecial } from '@/utils/tagColors';
import { useDarkMode } from '@/App';
import { showTooltip, hideTooltip } from '@/components/shared/Tooltip';
import { getGlobalWebSocketStore } from '@/stores/websocket-global';
interface TagBadgesProps {
tags?: string[];
@ -16,12 +17,14 @@ export const TagBadges: Component<TagBadgesProps> = (props) => {
const maxVisible = () => props.maxVisible === 0 ? Infinity : (props.maxVisible ?? 3);
const darkModeSignal = useDarkMode();
const isDark = () => props.isDarkMode ?? darkModeSignal();
const ws = getGlobalWebSocketStore();
const pveTagColors = () => ws.state.pveTagColors;
const visibleTags = () => props.tags?.slice(0, maxVisible()) || [];
const hiddenTags = () => props.tags?.slice(maxVisible()) || [];
const TagDot: Component<{ tag: string }> = (dotProps) => {
const colors = () => getTagColorWithSpecial(dotProps.tag, isDark());
const colors = () => getTagColorWithSpecial(dotProps.tag, isDark(), pveTagColors());
const isActive = () => props.activeSearch?.includes(`tags:${dotProps.tag}`) || false;
return (

View file

@ -83,6 +83,7 @@ export function createWebSocketStore(url: string) {
activeAlerts: [],
recentlyResolved: [],
lastUpdate: '',
pveTagColors: {},
// Unified resources for cross-platform monitoring
resources: [],
});

View file

@ -30,6 +30,7 @@ export interface State {
recentlyResolved: ResolvedAlert[];
lastUpdate: string;
temperatureMonitoringEnabled?: boolean;
pveTagColors?: Record<string, string>;
// Unified resources (new data model - eventually replaces legacy arrays above)
resources?: Resource[];
}

View file

@ -93,14 +93,23 @@ const specialTagColors: Record<string, TagColorTheme> = {
};
/**
* Get color for a tag, checking special colors first
* Get color for a tag.
* Priority: Proxmox-supplied hex color special hardcoded colors hash-based fallback.
* @param colorMap Optional map of lowercase tag name "#rrggbb" from Proxmox datacenter config.
*/
export function getTagColorWithSpecial(
tag: string,
isDarkMode: boolean,
colorMap?: Record<string, string>,
): { bg: string; text: string; border: string } {
const lowerTag = tag.toLowerCase();
// Use Proxmox-supplied colour when available
if (colorMap?.[lowerTag]) {
const hex = colorMap[lowerTag];
return { bg: hex, text: '#ffffff', border: hex };
}
// Check if it's a special tag
if (specialTagColors[lowerTag]) {
return isDarkMode ? specialTagColors[lowerTag].dark : specialTagColors[lowerTag].light;