mirror of
https://github.com/home-assistant/frontend.git
synced 2025-04-25 13:57:21 +00:00
Move integrations to System Health (#12504)
This commit is contained in:
parent
011467ece0
commit
591b8cc503
@ -3,12 +3,12 @@ import { property, state } from "lit/decorators";
|
|||||||
import { isComponentLoaded } from "../../../common/config/is_component_loaded";
|
import { isComponentLoaded } from "../../../common/config/is_component_loaded";
|
||||||
import "../../../components/ha-logo-svg";
|
import "../../../components/ha-logo-svg";
|
||||||
import {
|
import {
|
||||||
fetchHassioHostInfo,
|
|
||||||
fetchHassioHassOsInfo,
|
fetchHassioHassOsInfo,
|
||||||
|
fetchHassioHostInfo,
|
||||||
HassioHassOSInfo,
|
HassioHassOSInfo,
|
||||||
HassioHostInfo,
|
HassioHostInfo,
|
||||||
} from "../../../data/hassio/host";
|
} from "../../../data/hassio/host";
|
||||||
import { HassioInfo, fetchHassioInfo } from "../../../data/hassio/supervisor";
|
import { fetchHassioInfo, HassioInfo } from "../../../data/hassio/supervisor";
|
||||||
import "../../../layouts/hass-subpage";
|
import "../../../layouts/hass-subpage";
|
||||||
import { haStyle } from "../../../resources/styles";
|
import { haStyle } from "../../../resources/styles";
|
||||||
import { HomeAssistant, Route } from "../../../types";
|
import { HomeAssistant, Route } from "../../../types";
|
||||||
@ -153,12 +153,6 @@ class HaConfigInfo extends LitElement {
|
|||||||
: ""}
|
: ""}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
|
||||||
<integrations-card
|
|
||||||
.hass=${this.hass}
|
|
||||||
.narrow=${this.narrow}
|
|
||||||
></integrations-card>
|
|
||||||
</div>
|
|
||||||
</hass-subpage>
|
</hass-subpage>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
@ -1,16 +1,23 @@
|
|||||||
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
import "@material/mwc-list/mwc-list";
|
||||||
|
import {
|
||||||
|
css,
|
||||||
|
CSSResultGroup,
|
||||||
|
html,
|
||||||
|
LitElement,
|
||||||
|
PropertyValues,
|
||||||
|
TemplateResult,
|
||||||
|
} from "lit";
|
||||||
import { customElement, property, state } from "lit/decorators";
|
import { customElement, property, state } from "lit/decorators";
|
||||||
import memoizeOne from "memoize-one";
|
|
||||||
import "../../../components/ha-card";
|
import "../../../components/ha-card";
|
||||||
|
import "../../../components/ha-clickable-list-item";
|
||||||
import {
|
import {
|
||||||
domainToName,
|
domainToName,
|
||||||
fetchIntegrationManifests,
|
fetchIntegrationManifests,
|
||||||
fetchIntegrationSetups,
|
fetchIntegrationSetups,
|
||||||
integrationIssuesUrl,
|
|
||||||
IntegrationManifest,
|
IntegrationManifest,
|
||||||
IntegrationSetup,
|
IntegrationSetup,
|
||||||
} from "../../../data/integration";
|
} from "../../../data/integration";
|
||||||
import { HomeAssistant } from "../../../types";
|
import type { HomeAssistant } from "../../../types";
|
||||||
import { brandsUrl } from "../../../util/brands-url";
|
import { brandsUrl } from "../../../util/brands-url";
|
||||||
import { documentationUrl } from "../../../util/documentation-url";
|
import { documentationUrl } from "../../../util/documentation-url";
|
||||||
|
|
||||||
@ -24,120 +31,69 @@ class IntegrationsCard extends LitElement {
|
|||||||
[domain: string]: IntegrationManifest;
|
[domain: string]: IntegrationManifest;
|
||||||
};
|
};
|
||||||
|
|
||||||
@state() private _setups?: {
|
@state() private _setups?: IntegrationSetup[];
|
||||||
[domain: string]: IntegrationSetup;
|
|
||||||
};
|
|
||||||
|
|
||||||
private _sortedIntegrations = memoizeOne((components: string[]) =>
|
protected firstUpdated(changedProps: PropertyValues) {
|
||||||
Array.from(
|
|
||||||
new Set(
|
|
||||||
components.map((comp) =>
|
|
||||||
comp.includes(".") ? comp.split(".")[1] : comp
|
|
||||||
)
|
|
||||||
)
|
|
||||||
).sort()
|
|
||||||
);
|
|
||||||
|
|
||||||
firstUpdated(changedProps) {
|
|
||||||
super.firstUpdated(changedProps);
|
super.firstUpdated(changedProps);
|
||||||
this._fetchManifests();
|
this._fetchManifests();
|
||||||
this._fetchSetups();
|
this._fetchSetups();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected render(): TemplateResult {
|
protected render(): TemplateResult {
|
||||||
|
if (!this._setups) {
|
||||||
|
return html``;
|
||||||
|
}
|
||||||
|
|
||||||
return html`
|
return html`
|
||||||
<ha-card
|
<ha-card
|
||||||
.header=${this.hass.localize("ui.panel.config.info.integrations")}
|
outlined
|
||||||
|
.header=${this.hass.localize(
|
||||||
|
"ui.panel.config.system_health.long_loading_integrations"
|
||||||
|
)}
|
||||||
>
|
>
|
||||||
<table class="card-content">
|
<mwc-list>
|
||||||
<thead>
|
${this._setups?.map((setup) => {
|
||||||
<tr>
|
const manifest = this._manifests && this._manifests[setup.domain];
|
||||||
<th></th>
|
|
||||||
${!this.narrow
|
|
||||||
? html`<th></th>
|
|
||||||
<th></th>
|
|
||||||
<th></th>`
|
|
||||||
: ""}
|
|
||||||
<th>${this.hass.localize("ui.panel.config.info.setup_time")}</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
${this._sortedIntegrations(this.hass!.config.components).map(
|
|
||||||
(domain) => {
|
|
||||||
const manifest = this._manifests && this._manifests[domain];
|
|
||||||
const docLink = manifest
|
const docLink = manifest
|
||||||
? html`<a
|
? manifest.is_built_in
|
||||||
href=${manifest.is_built_in
|
|
||||||
? documentationUrl(
|
? documentationUrl(
|
||||||
this.hass,
|
this.hass,
|
||||||
`/integrations/${manifest.domain}`
|
`/integrations/${manifest.domain}`
|
||||||
)
|
)
|
||||||
: manifest.documentation}
|
: manifest.documentation
|
||||||
target="_blank"
|
|
||||||
rel="noreferrer"
|
|
||||||
>${this.hass.localize(
|
|
||||||
"ui.panel.config.info.documentation"
|
|
||||||
)}</a
|
|
||||||
>`
|
|
||||||
: "";
|
: "";
|
||||||
const issueLink =
|
|
||||||
manifest && (manifest.is_built_in || manifest.issue_tracker)
|
const setupSeconds = setup.seconds?.toFixed(2);
|
||||||
? html`
|
|
||||||
<a
|
|
||||||
href=${integrationIssuesUrl(domain, manifest)}
|
|
||||||
target="_blank"
|
|
||||||
rel="noreferrer"
|
|
||||||
>${this.hass.localize(
|
|
||||||
"ui.panel.config.info.issues"
|
|
||||||
)}</a
|
|
||||||
>
|
|
||||||
`
|
|
||||||
: "";
|
|
||||||
const setupSeconds =
|
|
||||||
this._setups?.[domain]?.seconds?.toFixed(2);
|
|
||||||
return html`
|
return html`
|
||||||
<tr>
|
<ha-clickable-list-item
|
||||||
<td>
|
graphic="avatar"
|
||||||
|
twoline
|
||||||
|
hasMeta
|
||||||
|
@click=${this._entryClicked}
|
||||||
|
href=${docLink}
|
||||||
|
>
|
||||||
<img
|
<img
|
||||||
loading="lazy"
|
loading="lazy"
|
||||||
src=${brandsUrl({
|
src=${brandsUrl({
|
||||||
domain: domain,
|
domain: setup.domain,
|
||||||
type: "icon",
|
type: "icon",
|
||||||
useFallback: true,
|
useFallback: true,
|
||||||
darkOptimized: this.hass.themes?.darkMode,
|
darkOptimized: this.hass.themes?.darkMode,
|
||||||
})}
|
})}
|
||||||
referrerpolicy="no-referrer"
|
referrerpolicy="no-referrer"
|
||||||
|
slot="graphic"
|
||||||
/>
|
/>
|
||||||
</td>
|
<span>
|
||||||
<td class="name">
|
${domainToName(this.hass.localize, setup.domain, manifest)}
|
||||||
${domainToName(
|
</span>
|
||||||
this.hass.localize,
|
<span slot="secondary">${setup.domain}</span>
|
||||||
domain,
|
<div slot="meta">
|
||||||
manifest
|
|
||||||
)}<br />
|
|
||||||
<span class="domain">${domain}</span>
|
|
||||||
${this.narrow
|
|
||||||
? html`<div class="mobile-row">
|
|
||||||
<div>${docLink} ${issueLink}</div>
|
|
||||||
${setupSeconds ? html`${setupSeconds} s` : ""}
|
${setupSeconds ? html`${setupSeconds} s` : ""}
|
||||||
</div>`
|
</div>
|
||||||
: ""}
|
</ha-clickable-list-item>
|
||||||
</td>
|
|
||||||
${this.narrow
|
|
||||||
? ""
|
|
||||||
: html`
|
|
||||||
<td>${docLink}</td>
|
|
||||||
<td>${issueLink}</td>
|
|
||||||
<td class="setup">
|
|
||||||
${setupSeconds ? html`${setupSeconds} s` : ""}
|
|
||||||
</td>
|
|
||||||
`}
|
|
||||||
</tr>
|
|
||||||
`;
|
`;
|
||||||
}
|
})}
|
||||||
)}
|
</mwc-list>
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</ha-card>
|
</ha-card>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
@ -151,54 +107,36 @@ class IntegrationsCard extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async _fetchSetups() {
|
private async _fetchSetups() {
|
||||||
const setups = {};
|
const setups = await fetchIntegrationSetups(this.hass);
|
||||||
for (const setup of await fetchIntegrationSetups(this.hass)) {
|
this._setups = setups.sort((a, b) => {
|
||||||
setups[setup.domain] = setup;
|
if (a.seconds === b.seconds) {
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
this._setups = setups;
|
if (a.seconds === undefined) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (b.seconds === undefined) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return b.seconds - a.seconds;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private _entryClicked(ev) {
|
||||||
|
ev.currentTarget.blur();
|
||||||
}
|
}
|
||||||
|
|
||||||
static get styles(): CSSResultGroup {
|
static get styles(): CSSResultGroup {
|
||||||
return css`
|
return css`
|
||||||
table {
|
ha-clickable-list-item {
|
||||||
width: 100%;
|
--mdc-list-item-meta-size: 48px;
|
||||||
}
|
--mdc-typography-caption-font-size: 12px;
|
||||||
td,
|
|
||||||
th {
|
|
||||||
padding: 0 8px;
|
|
||||||
}
|
|
||||||
td:first-child {
|
|
||||||
padding-left: 0;
|
|
||||||
}
|
|
||||||
td.name {
|
|
||||||
padding: 8px;
|
|
||||||
}
|
|
||||||
td.setup {
|
|
||||||
text-align: right;
|
|
||||||
white-space: nowrap;
|
|
||||||
direction: ltr;
|
|
||||||
}
|
|
||||||
th {
|
|
||||||
text-align: right;
|
|
||||||
}
|
|
||||||
.domain {
|
|
||||||
color: var(--secondary-text-color);
|
|
||||||
}
|
|
||||||
.mobile-row {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
}
|
|
||||||
.mobile-row a:not(:last-of-type) {
|
|
||||||
margin-right: 4px;
|
|
||||||
}
|
}
|
||||||
img {
|
img {
|
||||||
display: block;
|
display: block;
|
||||||
max-height: 40px;
|
max-height: 40px;
|
||||||
max-width: 40px;
|
max-width: 40px;
|
||||||
}
|
}
|
||||||
a {
|
|
||||||
color: var(--primary-color);
|
|
||||||
}
|
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -30,6 +30,7 @@ import { SubscribeMixin } from "../../../mixins/subscribe-mixin";
|
|||||||
import type { HomeAssistant } from "../../../types";
|
import type { HomeAssistant } from "../../../types";
|
||||||
import { documentationUrl } from "../../../util/documentation-url";
|
import { documentationUrl } from "../../../util/documentation-url";
|
||||||
import { showToast } from "../../../util/toast";
|
import { showToast } from "../../../util/toast";
|
||||||
|
import "../info/integrations-card";
|
||||||
|
|
||||||
const sortKeys = (a: string, b: string) => {
|
const sortKeys = (a: string, b: string) => {
|
||||||
if (a === "homeassistant") {
|
if (a === "homeassistant") {
|
||||||
@ -317,6 +318,11 @@ class HaConfigSystemHealth extends SubscribeMixin(LitElement) {
|
|||||||
</div>
|
</div>
|
||||||
</ha-card>
|
</ha-card>
|
||||||
`}
|
`}
|
||||||
|
|
||||||
|
<integrations-card
|
||||||
|
.hass=${this.hass}
|
||||||
|
.narrow=${this.narrow}
|
||||||
|
></integrations-card>
|
||||||
</div>
|
</div>
|
||||||
</hass-subpage>
|
</hass-subpage>
|
||||||
`;
|
`;
|
||||||
@ -450,12 +456,20 @@ class HaConfigSystemHealth extends SubscribeMixin(LitElement) {
|
|||||||
max-width: 1040px;
|
max-width: 1040px;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
}
|
}
|
||||||
|
integrations-card {
|
||||||
|
max-width: 600px;
|
||||||
|
display: block;
|
||||||
|
max-width: 600px;
|
||||||
|
margin: 0 auto;
|
||||||
|
margin-bottom: 24px;
|
||||||
|
margin-bottom: max(24px, env(safe-area-inset-bottom));
|
||||||
|
}
|
||||||
ha-card {
|
ha-card {
|
||||||
display: block;
|
display: block;
|
||||||
max-width: 600px;
|
max-width: 600px;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
padding-bottom: 16px;
|
padding-bottom: 16px;
|
||||||
margin-bottom: max(24px, env(safe-area-inset-bottom));
|
margin-bottom: 24px;
|
||||||
}
|
}
|
||||||
ha-alert {
|
ha-alert {
|
||||||
display: block;
|
display: block;
|
||||||
|
@ -1551,7 +1551,6 @@
|
|||||||
"frontend_version": "Frontend version: {version} - {type}",
|
"frontend_version": "Frontend version: {version} - {type}",
|
||||||
"custom_uis": "Custom UIs:",
|
"custom_uis": "Custom UIs:",
|
||||||
"system_health_error": "System Health component is not loaded. Add 'system_health:' to configuration.yaml",
|
"system_health_error": "System Health component is not loaded. Add 'system_health:' to configuration.yaml",
|
||||||
"integrations": "Integrations",
|
|
||||||
"documentation": "Documentation",
|
"documentation": "Documentation",
|
||||||
"issues": "Issues",
|
"issues": "Issues",
|
||||||
"setup_time": "Setup time",
|
"setup_time": "Setup time",
|
||||||
@ -3164,10 +3163,11 @@
|
|||||||
},
|
},
|
||||||
"system_health": {
|
"system_health": {
|
||||||
"caption": "System Health",
|
"caption": "System Health",
|
||||||
"cpu_usage": "Process Usage",
|
"cpu_usage": "Processor Usage",
|
||||||
"ram_usage": "Memory Usage",
|
"ram_usage": "Memory Usage",
|
||||||
"core_stats": "Core Stats",
|
"core_stats": "Core Stats",
|
||||||
"supervisor_stats": "Supervisor Stats"
|
"supervisor_stats": "Supervisor Stats",
|
||||||
|
"long_loading_integrations": "Long Loading Integrations"
|
||||||
},
|
},
|
||||||
"system_dashboard": {
|
"system_dashboard": {
|
||||||
"confirm_restart_text": "Restarting Home Assistant will stop all your active dashboards, automations and scripts.",
|
"confirm_restart_text": "Restarting Home Assistant will stop all your active dashboards, automations and scripts.",
|
||||||
|
Loading…
x
Reference in New Issue
Block a user