Use manfiests to render doc urls (#5549)

* Use manfiests to render doc urls

* Update UI
This commit is contained in:
Paulus Schoutsen 2020-04-15 13:36:25 -07:00 committed by GitHub
parent ff81536463
commit 66f33ad497
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 143 additions and 50 deletions

View File

@ -1,10 +1,32 @@
import { LocalizeFunc } from "../common/translations/localize";
import { HomeAssistant } from "../types";
export const integrationDocsUrl = (domain: string) =>
`https://www.home-assistant.io/integrations/${domain}`;
export interface IntegrationManifest {
is_built_in: boolean;
domain: string;
name: string;
config_flow: boolean;
documentation: string;
dependencies?: string[];
after_dependencies?: string[];
codeowners?: string[];
requirements?: string[];
ssdp?: Array<{ manufacturer?: string; modelName?: string; st?: string }>;
zeroconf?: string[];
homekit?: { models: string[] };
quality_scale?: string;
}
export const integrationIssuesUrl = (domain: string) =>
`https://github.com/home-assistant/home-assistant/issues?q=is%3Aissue+is%3Aopen+label%3A%22integration%3A+${domain}%22`;
export const domainToName = (localize: LocalizeFunc, domain: string) =>
localize(`domain.${domain}`) || domain;
export const fetchIntegrationManifests = (hass: HomeAssistant) =>
hass.callWS<IntegrationManifest[]>({ type: "manifest/list" });
export const fetchIntegrationManifest = (
hass: HomeAssistant,
integration: string
) => hass.callWS<IntegrationManifest>({ type: "manifest/get", integration });

View File

@ -19,4 +19,6 @@ export const fetchSystemLog = (hass: HomeAssistant) =>
export const getLoggedErrorIntegration = (item: LoggedError) =>
item.name.startsWith("homeassistant.components.")
? item.name.split(".")[2]
: item.name.startsWith("custom_components.")
? item.name.split(".")[1]
: undefined;

View File

@ -9,8 +9,9 @@ import {
} from "lit-element";
import memoizeOne from "memoize-one";
import {
integrationDocsUrl,
integrationIssuesUrl,
IntegrationManifest,
fetchIntegrationManifests,
} from "../../../data/integration";
import { HomeAssistant } from "../../../types";
@ -18,46 +19,67 @@ import { HomeAssistant } from "../../../types";
class IntegrationsCard extends LitElement {
@property() public hass!: HomeAssistant;
@property() private _manifests?: { [domain: string]: IntegrationManifest };
private _sortedIntegrations = memoizeOne((components: string[]) => {
return components.filter((comp) => !comp.includes(".")).sort();
});
firstUpdated(changedProps) {
super.firstUpdated(changedProps);
this._fetchManifests();
}
protected render(): TemplateResult {
return html`
<ha-card header="Integrations">
<table class="card-content">
<tbody>
${this._sortedIntegrations(this.hass!.config.components).map(
(domain) => html`
<tr>
<td>
<img
loading="lazy"
src="https://brands.home-assistant.io/_/${domain}/icon.png"
referrerpolicy="no-referrer"
/>
</td>
<td>${domain}</td>
<td>
<a
href=${integrationDocsUrl(domain)}
target="_blank"
rel="noreferrer"
>
Documentation
</a>
</td>
<td>
<a
href=${integrationIssuesUrl(domain)}
target="_blank"
rel="noreferrer"
>
Issues
</a>
</td>
</tr>
`
(domain) => {
const manifest = this._manifests && this._manifests[domain];
return html`
<tr>
<td>
<img
loading="lazy"
src="https://brands.home-assistant.io/_/${domain}/icon.png"
referrerpolicy="no-referrer"
/>
</td>
<td class="name">
${manifest?.name}<br />
<span class="domain">${domain}</span>
</td>
${!manifest
? ""
: html`
<td>
<a
href=${manifest.documentation}
target="_blank"
rel="noreferrer"
>
Documentation
</a>
</td>
${!manifest.is_built_in
? ""
: html`
<td>
<a
href=${integrationIssuesUrl(domain)}
target="_blank"
rel="noreferrer"
>
Issues
</a>
</td>
`}
`}
</tr>
`;
}
)}
</tbody>
</table>
@ -65,19 +87,32 @@ class IntegrationsCard extends LitElement {
`;
}
private async _fetchManifests() {
const manifests = {};
for (const manifest of await fetchIntegrationManifests(this.hass)) {
manifests[manifest.domain] = manifest;
}
this._manifests = manifests;
}
static get styles(): CSSResult {
return css`
td {
line-height: 2em;
padding: 0 8px;
}
td:first-child {
padding-left: 0;
}
td.name {
padding: 8px;
}
.domain {
color: var(--secondary-text-color);
}
img {
display: block;
max-height: 24px;
max-width: 24px;
max-height: 40px;
max-width: 40px;
}
a {
color: var(--primary-color);

View File

@ -10,8 +10,9 @@ import {
import "../../../components/dialog/ha-paper-dialog";
import {
domainToName,
integrationDocsUrl,
integrationIssuesUrl,
IntegrationManifest,
fetchIntegrationManifest,
} from "../../../data/integration";
import { getLoggedErrorIntegration } from "../../../data/system_log";
import { PolymerChangedEvent } from "../../../polymer-types";
@ -25,11 +26,25 @@ class DialogSystemLogDetail extends LitElement {
@property() private _params?: SystemLogDetailDialogParams;
@property() private _manifest?: IntegrationManifest;
public async showDialog(params: SystemLogDetailDialogParams): Promise<void> {
this._params = params;
this._manifest = undefined;
await this.updateComplete;
}
protected updated(changedProps) {
super.updated(changedProps);
if (!changedProps.has("_params") || !this._params) {
return;
}
const integration = getLoggedErrorIntegration(this._params.item);
if (integration) {
this._fetchManifest(integration);
}
}
protected render(): TemplateResult {
if (!this._params) {
return html``;
@ -58,19 +73,30 @@ class DialogSystemLogDetail extends LitElement {
${integration
? html`
<br />
Integration: ${domainToName(this.hass.localize, integration)}
(<a
href=${integrationDocsUrl(integration)}
target="_blank"
rel="noreferrer"
>documentation</a
>,
<a
href=${integrationIssuesUrl(integration)}
target="_blank"
rel="noreferrer"
>issues</a
>)
Integration:
${this._manifest
? this._manifest.name
: domainToName(this.hass.localize, integration)}
${!this._manifest ||
// Can happen with custom integrations
!this._manifest.documentation
? ""
: html`
(<a
href=${this._manifest.documentation}
target="_blank"
rel="noreferrer"
>documentation</a
>${!this._manifest.is_built_in
? ""
: html`,
<a
href=${integrationIssuesUrl(integration)}
target="_blank"
rel="noreferrer"
>issues</a
>`})
`}
`
: ""}
<br />
@ -100,6 +126,14 @@ class DialogSystemLogDetail extends LitElement {
`;
}
private async _fetchManifest(integration: string) {
try {
this._manifest = await fetchIntegrationManifest(this.hass, integration);
} catch (err) {
// Ignore if loading manifest fails. Probably bad JSON in manifest
}
}
private _openedChanged(ev: PolymerChangedEvent<boolean>): void {
if (!(ev.detail as any).value) {
this._params = undefined;