Reload entity component icons when missing (#19629)

* Reload entity component icons when missing

* Improve typing, improve caching

* Make copy

* review suggestion

* overload

* Update icons.ts

* Update icons.ts
This commit is contained in:
Bram Kragten 2024-02-02 16:26:47 +01:00 committed by GitHub
parent 682f9a0f04
commit aa400ce6ab
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -8,19 +8,31 @@ import {
EntityRegistryDisplayEntry, EntityRegistryDisplayEntry,
EntityRegistryEntry, EntityRegistryEntry,
} from "./entity_registry"; } from "./entity_registry";
import { isComponentLoaded } from "../common/config/is_component_loaded";
const resources: Record<IconCategory, any> = { const resources: {
entity: Record<string, Promise<PlatformIcons>>;
entity_component: {
domains?: string[];
resources?: Promise<Record<string, ComponentIcons>>;
};
services: {
all?: Promise<Record<string, ServiceIcons>>;
domains: { [domain: string]: ServiceIcons | Promise<ServiceIcons> };
};
} = {
entity: {}, entity: {},
entity_component: undefined, entity_component: {},
services: {}, services: { domains: {} },
}; };
interface IconResources { interface IconResources<
resources: Record<string, string | Record<string, string>>; T extends ComponentIcons | PlatformIcons | ServiceIcons,
> {
resources: Record<string, T>;
} }
interface PlatformIcons { interface PlatformIcons {
[domain: string]: {
[translation_key: string]: { [translation_key: string]: {
state: Record<string, string>; state: Record<string, string>;
state_attributes: Record< state_attributes: Record<
@ -32,7 +44,6 @@ interface PlatformIcons {
>; >;
default: string; default: string;
}; };
};
} }
interface ComponentIcons { interface ComponentIcons {
@ -55,12 +66,18 @@ interface ServiceIcons {
export type IconCategory = "entity" | "entity_component" | "services"; export type IconCategory = "entity" | "entity_component" | "services";
export const getHassIcons = async ( type CategoryType = {
entity: PlatformIcons;
entity_component: ComponentIcons;
services: ServiceIcons;
};
export const getHassIcons = async <T extends IconCategory>(
hass: HomeAssistant, hass: HomeAssistant,
category: IconCategory, category: T,
integration?: string integration?: string
): Promise<IconResources> => ) =>
hass.callWS<{ resources: Record<string, string> }>({ hass.callWS<IconResources<CategoryType[T]>>({
type: "frontend/get_icons", type: "frontend/get_icons",
category, category,
integration, integration,
@ -70,14 +87,17 @@ export const getPlatformIcons = async (
hass: HomeAssistant, hass: HomeAssistant,
integration: string, integration: string,
force = false force = false
): Promise<PlatformIcons> => { ): Promise<PlatformIcons | undefined> => {
if (!force && integration in resources.entity) { if (!force && integration in resources.entity) {
return resources.entity[integration]; return resources.entity[integration];
} }
const result = getHassIcons(hass, "entity", integration); if (!isComponentLoaded(hass, integration)) {
resources.entity[integration] = result.then( return undefined;
}
const result = getHassIcons(hass, "entity", integration).then(
(res) => res?.resources[integration] (res) => res?.resources[integration]
); );
resources.entity[integration] = result;
return resources.entity[integration]; return resources.entity[integration];
}; };
@ -85,45 +105,59 @@ export const getComponentIcons = async (
hass: HomeAssistant, hass: HomeAssistant,
domain: string, domain: string,
force = false force = false
): Promise<ComponentIcons> => { ): Promise<ComponentIcons | undefined> => {
if (!force && resources.entity_component) { if (
return resources.entity_component.then((res) => res[domain]); !force &&
resources.entity_component.resources &&
resources.entity_component.domains?.includes(domain)
) {
return resources.entity_component.resources.then((res) => res[domain]);
} }
resources.entity_component = getHassIcons(hass, "entity_component").then( if (!isComponentLoaded(hass, domain)) {
(result) => result.resources return undefined;
); }
return resources.entity_component.then((res) => res[domain]); resources.entity_component.domains = [...hass.config.components];
resources.entity_component.resources = getHassIcons(
hass,
"entity_component"
).then((result) => result.resources);
return resources.entity_component.resources.then((res) => res[domain]);
}; };
export const getServiceIcons = async ( export const getServiceIcons = async (
hass: HomeAssistant, hass: HomeAssistant,
domain?: string, domain?: string,
force = false force = false
): Promise<ServiceIcons> => { ): Promise<ServiceIcons | Record<string, ServiceIcons> | undefined> => {
if (!domain) { if (!domain) {
if (!force && resources.services.all) { if (!force && resources.services.all) {
return resources.services.all; return resources.services.all;
} }
resources.services.all = getHassIcons(hass, "services", domain).then( resources.services.all = getHassIcons(hass, "services", domain).then(
(res) => { (res) => {
resources.services = res.resources; resources.services.domains = res.resources;
return res?.resources; return res?.resources;
} }
); );
return resources.services.all; return resources.services.all;
} }
if (!force && domain && domain in resources.services) { if (!force && domain in resources.services.domains) {
return resources.services[domain]; return resources.services.domains[domain];
} }
if (resources.services.all && !force) { if (resources.services.all && !force) {
await resources.services.all; await resources.services.all;
if (domain in resources.services) { if (domain in resources.services.domains) {
return resources.services[domain]; return resources.services.domains[domain];
} }
} }
if (!isComponentLoaded(hass, domain)) {
return undefined;
}
const result = getHassIcons(hass, "services", domain); const result = getHassIcons(hass, "services", domain);
resources.services[domain] = result.then((res) => res?.resources[domain]); resources.services.domains[domain] = result.then(
return resources.services[domain]; (res) => res?.resources[domain]
);
return resources.services.domains[domain];
}; };
export const entityIcon = async ( export const entityIcon = async (
@ -238,7 +272,7 @@ export const serviceIcon = async (
const serviceName = computeObjectId(service); const serviceName = computeObjectId(service);
const serviceIcons = await getServiceIcons(hass, domain); const serviceIcons = await getServiceIcons(hass, domain);
if (serviceIcons) { if (serviceIcons) {
icon = serviceIcons[serviceName]; icon = serviceIcons[serviceName] as string;
} }
if (!icon) { if (!icon) {
icon = await domainIcon(hass, domain); icon = await domainIcon(hass, domain);