Use authenticated brands proxy for repository icons#937
Conversation
The dashboard constructed icon URLs via the upstream `brandsUrl` helper
at a pinned submodule (3ffbd435, Jan 2025) that predates the
brands-proxy API introduced in HA 2026.3. After upstream rewrote
`brands-url.ts` to return `/api/brands/integration/{domain}/icon.png`
with an access token, custom integrations shipping inline brand assets
no longer render (the legacy CDN no longer accepts new custom
integration submissions).
Bump `homeassistant-frontend` to current master, drop the now-removed
`useFallback` parameter, and fetch/schedule the brands access token
from the dashboard's own bundle (module-level token state is
bundle-scoped, so HACS must populate its own copy). Clear the refresh
interval on disconnect.
Fixes hacs/integration#5171
Fixes hacs/integration#5223
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
|
@ludeeus sorry for pinging you, but any chance to take a look at this PR and additionally hacs/integration#5228? We would love to have icons back for integrations. It's fixing hacs/integration#5171 and hacs/integration#5223 Hope to hear from you! |
|
I don't think that will work. If the integration is not installed, the local image will not be available, right? |
|
That is correct @piitaya. |
|
You are right, but that's why I have another PR: hacs/integration#5228 |
|
The solution I had in mind : a HACS endpoint ( @manuveli This PR is only about |
Summary
The HACS dashboard shows "icon not available" for custom integrations that ship inline brand assets (a feature introduced in Home Assistant 2026.3). Root cause is a combination of three things:
homeassistant-frontendsubmodule is pinned to3ffbd435(2025-01-09) — pre-brands-proxy.brandsUrl({...})still returnshttps://brands.home-assistant.io/_/{domain}/icon.png. That CDN no longer accepts new custom-integration submissions (see the brands-proxy API blog post), so custom-integration icons 404.useFallback: true— a parameter that has since been removed from upstreamBrandsOptions, so a naive submodule bump breaks the TypeScript compile.Changes
homeassistant-frontendsubmodule to current upstreammaster— brings in the newbrands-url.tsthat returns/api/brands/integration/{domain}/icon.png?token=…, along withfetchAndScheduleBrandsAccessToken/clearBrandsTokenRefreshexports.useFallback: truefrom thebrandsUrl({...})call insrc/dashboards/hacs-dashboard.ts— the field no longer exists onBrandsOptions. Fallback is now the HA backend's job (stale-while-revalidate through the proxy)._brandsAccessTokeninbrands-url.tsis bundle-scoped, so HACS must populate its own copy; upstream'sfetchAndScheduleBrandsAccessTokensilently swallows failures on older HA backends. Clear the refresh interval indisconnectedCallbackto avoid leaking thesetIntervalwhen the panel unmounts.Fixes hacs/integration#5171
Fixes hacs/integration#5223
A companion PR in the integration repo (hacs/integration) updates the HACS Update entity's
entity_pictureto use the same authenticated proxy path.Test plan
script/bootstrap && script/buildcompiles clean (CI via.github/workflows/test.yml).brand/icon.pnginline: downloads table shows real icons; rendered<img>hassrc=/api/brands/integration/{domain}/icon.png?token=….darkOptimized(filename prefixed withdark_).brands/access_tokenWS command): dashboard renders without thrown errors —fetchAndScheduleBrandsAccessTokencatches silently.🤖 Generated with Claude Code