diff --git a/src/data/diagnostics.ts b/src/data/diagnostics.ts new file mode 100644 index 0000000000..d49554bf76 --- /dev/null +++ b/src/data/diagnostics.ts @@ -0,0 +1,18 @@ +import { HomeAssistant } from "../types"; + +interface DiagnosticInfo { + domain: string; + handlers: { + config_entry: boolean; + }; +} + +export const fetchDiagnosticHandlers = ( + hass: HomeAssistant +): Promise => + hass.callWS({ + type: "diagnostics/list", + }); + +export const getConfigEntryDiagnosticsDownloadUrl = (entry_id: string) => + `/api/diagnostics/config_entry/${entry_id}`; diff --git a/src/panels/config/integrations/ha-config-integrations.ts b/src/panels/config/integrations/ha-config-integrations.ts index 34a1d9e68a..686eeaaa60 100644 --- a/src/panels/config/integrations/ha-config-integrations.ts +++ b/src/panels/config/integrations/ha-config-integrations.ts @@ -61,6 +61,7 @@ import "./ha-config-flow-card"; import "./ha-ignored-config-entry-card"; import "./ha-integration-card"; import type { HaIntegrationCard } from "./ha-integration-card"; +import { fetchDiagnosticHandlers } from "../../../data/diagnostics"; export interface ConfigEntryUpdatedEvent { entry: ConfigEntry; @@ -138,6 +139,8 @@ class HaConfigIntegrations extends SubscribeMixin(LitElement) { @state() private _filter?: string; + @state() private _diagnosticHandlers?: Record; + public hassSubscribe(): UnsubscribeFunc[] { return [ subscribeEntityRegistry(this.hass.connection, (entries) => { @@ -252,6 +255,15 @@ class HaConfigIntegrations extends SubscribeMixin(LitElement) { this._handleAdd(localizePromise); } this._scanUSBDevices(); + if (isComponentLoaded(this.hass, "diagnostics")) { + fetchDiagnosticHandlers(this.hass).then((infos) => { + const handlers = {}; + for (const info of infos) { + handlers[info.domain] = info.handlers.config_entry; + } + this._diagnosticHandlers = handlers; + }); + } } protected updated(changed: PropertyValues) { @@ -423,6 +435,9 @@ class HaConfigIntegrations extends SubscribeMixin(LitElement) { .manifest=${this._manifests[domain]} .entityRegistryEntries=${this._entityRegistryEntries} .deviceRegistryEntries=${this._deviceRegistryEntries} + .supportsDiagnostics=${this._diagnosticHandlers + ? this._diagnosticHandlers[domain] + : false} >` ) : this._filter && diff --git a/src/panels/config/integrations/ha-integration-card.ts b/src/panels/config/integrations/ha-integration-card.ts index 0c0f727754..51f5b26c80 100644 --- a/src/panels/config/integrations/ha-integration-card.ts +++ b/src/panels/config/integrations/ha-integration-card.ts @@ -20,6 +20,7 @@ import "../../../components/ha-card"; import "../../../components/ha-icon-button"; import "../../../components/ha-icon-next"; import "../../../components/ha-svg-icon"; +import { getSignedPath } from "../../../data/auth"; import { ConfigEntry, deleteConfigEntry, @@ -31,6 +32,7 @@ import { ERROR_STATES, } from "../../../data/config_entries"; import type { DeviceRegistryEntry } from "../../../data/device_registry"; +import { getConfigEntryDiagnosticsDownloadUrl } from "../../../data/diagnostics"; import type { EntityRegistryEntry } from "../../../data/entity_registry"; import type { IntegrationManifest } from "../../../data/integration"; import { integrationIssuesUrl } from "../../../data/integration"; @@ -73,6 +75,8 @@ export class HaIntegrationCard extends LitElement { @property({ type: Boolean }) public disabled = false; + @property({ type: Boolean }) public supportsDiagnostics = false; + protected render(): TemplateResult { let item = this._selectededConfigEntry; @@ -357,6 +361,19 @@ export class HaIntegrationCard extends LitElement { )} ` : ""} + ${this.supportsDiagnostics + ? html` + + ${this.hass.localize( + "ui.panel.config.integrations.config_entry.download_diagnostics" + )} + + ` + : ""} ${item.disabled_by === "user" ? html` ${this.hass.localize("ui.common.enable")} @@ -623,6 +640,16 @@ export class HaIntegrationCard extends LitElement { fireEvent(this, "entry-updated", { entry: result.config_entry }); } + private async _signUrl(ev) { + const anchor = ev.target.closest("a"); + ev.preventDefault(); + const signedUrl = await getSignedPath( + this.hass, + anchor.getAttribute("href") + ); + document.location.assign(signedUrl.path); + } + static get styles(): CSSResultGroup { return [ haStyle, diff --git a/src/translations/en.json b/src/translations/en.json index 19736ff509..8f32e732b2 100755 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -2440,6 +2440,7 @@ "configure": "Configure", "system_options": "System options", "documentation": "Documentation", + "download_diagnostics": "Download diagnostics", "known_issues": "Known issues", "delete": "Delete", "delete_confirm": "Are you sure you want to delete the {title} integration?",