Show the real Pulse mark in the branding header preview

With no custom logo, Settings > General > Application branding previewed
the header with a hand-drawn stand-in: a blue circle holding a "●" text
character, which does not look like the Pulse logo. The header itself
falls back to PulseBrandMark (blue disc, white ring, white centre dot),
so the preview misrepresented what the header shows. Render the same
PulseBrandMark at the header's size; it follows the app theme in light
and dark.
This commit is contained in:
rcourtman 2026-09-24 10:02:28 +01:00
parent 3b1b43293e
commit 298660157e
3 changed files with 36 additions and 28 deletions

View file

@ -1,23 +1,16 @@
{
"version": 1,
"base_sha": "4f11deddc728a69f937dcb04777c9e44276c3f95",
"verified_at": "2026-09-23T11:26:00Z",
"base_sha": "3b1b43293e21d06d1286124f96f78b1247443dea",
"verified_at": "2026-09-24T09:02:03Z",
"result": "passed",
"changed_paths": [
"frontend-modern/src/features/proxmox/ProxmoxBackupServersTable.tsx",
"frontend-modern/src/types/resource.ts"
"frontend-modern/src/components/Settings/BrandingSettingsCard.tsx"
],
"content_sha256": {
"frontend-modern/src/features/proxmox/ProxmoxBackupServersTable.tsx": "f6b50e71870ca4a3e0dcfa3e47413542e8444296bc68481c60e15d1a5d921f9f",
"frontend-modern/src/types/resource.ts": "db2509b73b2ed550ea1890aaef34e2a3dfe7d500aa193586562f9e20b95283ab"
"frontend-modern/src/components/Settings/BrandingSettingsCard.tsx": "6516a05aff71b1d96660f81189b6df8bceccf7e94d15d6c3213556e794f2ae40"
},
"routes": [
"/browser-tests/pbs-host-history-correlation.html?topology=guest&order=stable (Proxmox Backups server drawer)",
"/browser-tests/pbs-host-history-correlation.html?topology=guest&order=reordered (Proxmox Backups server drawer)",
"/browser-tests/pbs-host-history-correlation.html?topology=pbs-only&order=stable (Proxmox Backups server drawer)",
"/browser-tests/pbs-host-history-correlation.html?topology=pbs-only&order=reordered (Proxmox Backups server drawer)",
"/browser-tests/pbs-host-history-correlation.html?topology=side-by-side&order=stable (Proxmox Backups server drawer)",
"/browser-tests/pbs-host-history-correlation.html?topology=side-by-side&order=reordered (Proxmox Backups server drawer)"
"/settings/system-general (Application branding card, Header preview)"
],
"viewports": [
{
@ -30,18 +23,15 @@
}
],
"states": [
"PBS connection configured by 10.0.0.5 and linked to the host agent only by the reported pbs.nodeName, across pbs-only, side-by-side and PVE-guest topologies",
"Drawer History tab selected with a populated correlated host series",
"Timer-driven snapshot replacing the datastore inventory in stable and reversed order",
"Snapshot that briefly omits the correlated host row while the PBS server row remains",
"Snapshot that restores the correlated host row on the same selection"
"No custom logo and no custom name: the preview falls back to the default Pulse lockup",
"Light colour scheme at 1280x900 and 390x844",
"Dark colour scheme at 1280x900"
],
"interactions": [
"Expand the Proxmox Backups server row, switch between datastore rows and select History; assert the chart paths render against the host metrics target even though the configured endpoint is not a machine-identity token",
"Apply timer-driven stable and reordered snapshots; assert the drawer is not remounted, the History selection is retained, the chart series survive and the Discovery/Metrics Target rows stay byte-identical",
"Apply a snapshot that omits the correlated host row; assert the Identity rows and History chart stay on the retained host target instead of falling back to the PBS service key",
"Restore the correlated host row; assert the same target is confirmed, and repeat the complete matrix at 1280x900 and 390x844"
"Open Settings > General with the white_label capability present; assert the Header preview renders exactly one svg.pulse-brand-logo (blue disc, white ring, white centre dot) and no \"\u25cf\" text glyph",
"Compare the preview mark with the page header lockup: both render PulseBrandMark at 20px",
"Check the page does not scroll horizontally at 390px wide"
],
"command": "pulse-worker-browser scripts/check-pbs-host-history-correlation.cjs",
"notes": "Chromium 141.0.7390.37 / Playwright 1.56.1. Production ProxmoxBackupServersTable mounted through the real browser fixture with synthetic API responses and an intercepted metrics-history request. Proves the reported-node-name host correlation and its retention across a transient host-row omission, not backend persistence or installed release behaviour. The recorded history requests target agent/agent-proxback and vm/proxmox:100 and never the PBS service target agent/pbs-1. The same check fails on the pre-fix source: the drawer falls back to the PBS service key when the endpoint is not a machine-identity token, and omitting the host row flips the Discovery and Metrics Target rows to agent:pbs-1."
"command": "node verify.mjs (Playwright against a private mock-mode backend on :7681 and Vite on :5199)",
"notes": "Chromium via Playwright 1.56.1 from repos/pulse/node_modules. Real app and backend in PULSE_MOCK_MODE with ALLOW_ADMIN_BYPASS; the only stub is /api/license/runtime-capabilities with white_label added, because the mock install has no white-label entitlement and the card is gated behind it. Before the fix the same preview drew a blue circle containing a \"\u25cf\" text character instead of the Pulse brand mark, as seen in a provider-hosted client workspace on the walkthrough lab. Console errors were only the mock environment's failing update check."
}

View file

@ -1,6 +1,7 @@
import { Show, createSignal, type Accessor, type Component, type Setter } from 'solid-js';
import ImageIcon from 'lucide-solid/icons/image';
import Trash2 from 'lucide-solid/icons/trash-2';
import { PulseBrandMark } from '@/components/Brand/PulseBrandMark';
import { Button } from '@/components/shared/Button';
import { FeatureGateSection } from '@/components/shared/FeatureGateSection';
import { formControl, formHelpText, formLabel } from '@/components/shared/Form';
@ -157,11 +158,7 @@ export const BrandingSettingsCard: Component<BrandingSettingsCardProps> = (props
<div class="mt-3 flex min-h-10 items-center justify-center gap-2 overflow-hidden rounded bg-surface px-3 py-2">
<Show
when={preview()}
fallback={
<span class="flex h-5 w-5 items-center justify-center rounded-full bg-blue-600 text-[10px] text-white">
●
</span>
}
fallback={<PulseBrandMark class="h-5 w-5 shrink-0" decorative />}
>
{(logo) => (
<img

View file

@ -49,6 +49,27 @@ describe('BrandingSettingsCard', () => {
expect(brandingLogoPreview('YWJj', 'png')).toBe('data:image/png;base64,YWJj');
});
// Without a custom logo the preview must show what the header shows: the
// real Pulse brand mark, not a stand-in glyph.
it('previews the default header with the Pulse brand mark', () => {
const { container } = render(() => (
<BrandingSettingsCard
displayName={() => ''}
setDisplayName={() => ''}
logoBase64={() => ''}
setLogoBase64={() => ''}
logoFormat={() => ''}
setLogoFormat={() => ''}
setHasUnsavedChanges={() => false}
/>
));
const mark = container.querySelector('svg.pulse-brand-logo');
expect(mark).not.toBeNull();
expect(mark?.querySelectorAll('circle')).toHaveLength(3);
expect(container.textContent).not.toContain('●');
expect(screen.queryByTestId('branding-logo-preview')).toBeNull();
});
it('updates the application name and marks settings dirty', async () => {
const state = renderCard();