mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-23 09:16:38 +00:00
Move System Information to Repairs (#13281)
Co-authored-by: Bram Kragten <mail@bramkragten.nl>
This commit is contained in:
parent
f7090583ac
commit
c73677f15d
@ -26,7 +26,7 @@ import {
|
||||
import {
|
||||
UNHEALTHY_REASON_URL,
|
||||
UNSUPPORTED_REASON_URL,
|
||||
} from "../../../src/panels/config/system-health/ha-config-system-health";
|
||||
} from "../../../src/panels/config/repairs/dialog-system-information";
|
||||
import { haStyle } from "../../../src/resources/styles";
|
||||
import { HomeAssistant } from "../../../src/types";
|
||||
import { bytesToString } from "../../../src/util/bytes-to-string";
|
||||
|
@ -6,7 +6,6 @@ import {
|
||||
mdiCog,
|
||||
mdiDatabase,
|
||||
mdiDevices,
|
||||
mdiHeart,
|
||||
mdiInformation,
|
||||
mdiInformationOutline,
|
||||
mdiLifebuoy,
|
||||
@ -322,13 +321,6 @@ export const configSections: { [name: string]: PageNavigation[] } = {
|
||||
iconColor: "#301A8E",
|
||||
component: "hassio",
|
||||
},
|
||||
{
|
||||
path: "/config/system_health",
|
||||
translationKey: "system_health",
|
||||
iconPath: mdiHeart,
|
||||
iconColor: "#507FfE",
|
||||
components: ["system_health", "hassio"],
|
||||
},
|
||||
],
|
||||
about: [
|
||||
{
|
||||
@ -447,10 +439,6 @@ class HaPanelConfig extends HassRouterPage {
|
||||
tag: "ha-config-section-storage",
|
||||
load: () => import("./storage/ha-config-section-storage"),
|
||||
},
|
||||
system_health: {
|
||||
tag: "ha-config-system-health",
|
||||
load: () => import("./system-health/ha-config-system-health"),
|
||||
},
|
||||
updates: {
|
||||
tag: "ha-config-section-updates",
|
||||
load: () => import("./core/ha-config-section-updates"),
|
||||
|
57
src/panels/config/repairs/dialog-integration-startup.ts
Normal file
57
src/panels/config/repairs/dialog-integration-startup.ts
Normal file
@ -0,0 +1,57 @@
|
||||
import "@material/mwc-button/mwc-button";
|
||||
import { CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { fireEvent } from "../../../common/dom/fire_event";
|
||||
import "../../../components/ha-card";
|
||||
import { createCloseHeading } from "../../../components/ha-dialog";
|
||||
import { haStyleDialog } from "../../../resources/styles";
|
||||
import type { HomeAssistant } from "../../../types";
|
||||
import "./integrations-startup-time";
|
||||
|
||||
@customElement("dialog-integration-startup")
|
||||
class DialogIntegrationStartup extends LitElement {
|
||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||
|
||||
@state() private _opened = false;
|
||||
|
||||
public showDialog(): void {
|
||||
this._opened = true;
|
||||
}
|
||||
|
||||
public closeDialog() {
|
||||
this._opened = false;
|
||||
fireEvent(this, "dialog-closed", { dialog: this.localName });
|
||||
}
|
||||
|
||||
protected render(): TemplateResult {
|
||||
if (!this._opened) {
|
||||
return html``;
|
||||
}
|
||||
|
||||
return html`
|
||||
<ha-dialog
|
||||
open
|
||||
@closed=${this.closeDialog}
|
||||
scrimClickAction
|
||||
escapeKeyAction
|
||||
.heading=${createCloseHeading(
|
||||
this.hass,
|
||||
this.hass.localize("ui.panel.config.repairs.integration_startup_time")
|
||||
)}
|
||||
>
|
||||
<integrations-startup-time
|
||||
.hass=${this.hass}
|
||||
narrow
|
||||
></integrations-startup-time>
|
||||
</ha-dialog>
|
||||
`;
|
||||
}
|
||||
|
||||
static styles: CSSResultGroup = haStyleDialog;
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"dialog-integration-startup": DialogIntegrationStartup;
|
||||
}
|
||||
}
|
@ -1,17 +1,15 @@
|
||||
import { ActionDetail } from "@material/mwc-list";
|
||||
import "@material/mwc-list/mwc-list-item";
|
||||
import { mdiContentCopy } from "@mdi/js";
|
||||
import { UnsubscribeFunc } from "home-assistant-js-websocket/dist/types";
|
||||
import "@material/mwc-button/mwc-button";
|
||||
import { UnsubscribeFunc } from "home-assistant-js-websocket";
|
||||
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { isComponentLoaded } from "../../../common/config/is_component_loaded";
|
||||
import { formatDateTime } from "../../../common/datetime/format_date_time";
|
||||
import { fireEvent } from "../../../common/dom/fire_event";
|
||||
import { copyToClipboard } from "../../../common/util/copy-clipboard";
|
||||
import { subscribePollingCollection } from "../../../common/util/subscribe-polling";
|
||||
import "../../../components/ha-alert";
|
||||
import "../../../components/ha-button-menu";
|
||||
import "../../../components/ha-card";
|
||||
import "../../../components/ha-circular-progress";
|
||||
import { createCloseHeading } from "../../../components/ha-dialog";
|
||||
import "../../../components/ha-metric";
|
||||
import { fetchHassioStats, HassioStats } from "../../../data/hassio/common";
|
||||
import {
|
||||
@ -25,12 +23,11 @@ import {
|
||||
SystemHealthInfo,
|
||||
} from "../../../data/system_health";
|
||||
import { showAlertDialog } from "../../../dialogs/generic/show-dialog-box";
|
||||
import "../../../layouts/hass-subpage";
|
||||
import { SubscribeMixin } from "../../../mixins/subscribe-mixin";
|
||||
import { haStyleDialog } from "../../../resources/styles";
|
||||
import type { HomeAssistant } from "../../../types";
|
||||
import { documentationUrl } from "../../../util/documentation-url";
|
||||
import { showToast } from "../../../util/toast";
|
||||
import "./integrations-card";
|
||||
import "../../../components/ha-circular-progress";
|
||||
|
||||
const sortKeys = (a: string, b: string) => {
|
||||
if (a === "homeassistant") {
|
||||
@ -53,28 +50,40 @@ export const UNHEALTHY_REASON_URL = {
|
||||
privileged: "/more-info/unsupported/privileged",
|
||||
};
|
||||
|
||||
@customElement("ha-config-system-health")
|
||||
class HaConfigSystemHealth extends SubscribeMixin(LitElement) {
|
||||
@customElement("dialog-system-information")
|
||||
class DialogSystemInformation extends LitElement {
|
||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||
|
||||
@property({ type: Boolean }) public narrow!: boolean;
|
||||
|
||||
@state() private _info?: SystemHealthInfo;
|
||||
|
||||
@state() private _supervisorStats?: HassioStats;
|
||||
@state() private _systemInfo?: SystemHealthInfo;
|
||||
|
||||
@state() private _resolutionInfo?: HassioResolution;
|
||||
|
||||
@state() private _supervisorStats?: HassioStats;
|
||||
|
||||
@state() private _coreStats?: HassioStats;
|
||||
|
||||
@state() private _error?: { code: string; message: string };
|
||||
@state() private _opened = false;
|
||||
|
||||
public hassSubscribe(): Array<UnsubscribeFunc | Promise<UnsubscribeFunc>> {
|
||||
private _subscriptions?: Array<UnsubscribeFunc | Promise<UnsubscribeFunc>>;
|
||||
|
||||
public showDialog(): void {
|
||||
this._opened = true;
|
||||
this.hass!.loadBackendTranslation("system_health");
|
||||
this._subscribe();
|
||||
}
|
||||
|
||||
public closeDialog() {
|
||||
this._opened = false;
|
||||
this._unsubscribe();
|
||||
fireEvent(this, "dialog-closed", { dialog: this.localName });
|
||||
}
|
||||
|
||||
private _subscribe(): void {
|
||||
const subs: Array<UnsubscribeFunc | Promise<UnsubscribeFunc>> = [];
|
||||
if (isComponentLoaded(this.hass, "system_health")) {
|
||||
subs.push(
|
||||
subscribeSystemHealthInfo(this.hass!, (info) => {
|
||||
this._info = info;
|
||||
this._systemInfo = info;
|
||||
})
|
||||
);
|
||||
}
|
||||
@ -93,149 +102,51 @@ class HaConfigSystemHealth extends SubscribeMixin(LitElement) {
|
||||
10000
|
||||
)
|
||||
);
|
||||
|
||||
fetchHassioResolution(this.hass).then((data) => {
|
||||
this._resolutionInfo = data;
|
||||
});
|
||||
}
|
||||
|
||||
return subs;
|
||||
this._subscriptions = subs;
|
||||
}
|
||||
|
||||
protected firstUpdated(changedProps) {
|
||||
super.firstUpdated(changedProps);
|
||||
private _unsubscribe() {
|
||||
while (this._subscriptions?.length) {
|
||||
const unsub = this._subscriptions.pop()!;
|
||||
if (unsub instanceof Promise) {
|
||||
unsub.then((unsubFunc) => unsubFunc());
|
||||
} else {
|
||||
unsub();
|
||||
}
|
||||
}
|
||||
this._subscriptions = undefined;
|
||||
|
||||
this.hass!.loadBackendTranslation("system_health");
|
||||
this._systemInfo = undefined;
|
||||
this._resolutionInfo = undefined;
|
||||
this._coreStats = undefined;
|
||||
this._supervisorStats = undefined;
|
||||
}
|
||||
|
||||
protected render(): TemplateResult {
|
||||
const sections: TemplateResult[] = [];
|
||||
|
||||
if (!this._info) {
|
||||
sections.push(
|
||||
html`
|
||||
<div class="loading-container">
|
||||
<ha-circular-progress active></ha-circular-progress>
|
||||
</div>
|
||||
`
|
||||
);
|
||||
} else {
|
||||
const domains = Object.keys(this._info).sort(sortKeys);
|
||||
for (const domain of domains) {
|
||||
const domainInfo = this._info[domain];
|
||||
const keys: TemplateResult[] = [];
|
||||
|
||||
for (const key of Object.keys(domainInfo.info)) {
|
||||
let value: unknown;
|
||||
|
||||
if (
|
||||
domainInfo.info[key] &&
|
||||
typeof domainInfo.info[key] === "object"
|
||||
) {
|
||||
const info = domainInfo.info[key] as SystemCheckValueObject;
|
||||
|
||||
if (info.type === "pending") {
|
||||
value = html`
|
||||
<ha-circular-progress active size="tiny"></ha-circular-progress>
|
||||
`;
|
||||
} else if (info.type === "failed") {
|
||||
value = html`
|
||||
<span class="error">${info.error}</span>${!info.more_info
|
||||
? ""
|
||||
: html`
|
||||
–
|
||||
<a
|
||||
href=${info.more_info}
|
||||
target="_blank"
|
||||
rel="noreferrer noopener"
|
||||
>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.info.system_health.more_info"
|
||||
)}
|
||||
</a>
|
||||
`}
|
||||
`;
|
||||
} else if (info.type === "date") {
|
||||
value = formatDateTime(new Date(info.value), this.hass.locale);
|
||||
}
|
||||
} else {
|
||||
value = domainInfo.info[key];
|
||||
}
|
||||
|
||||
keys.push(html`
|
||||
<tr>
|
||||
<td>
|
||||
${this.hass.localize(
|
||||
`component.${domain}.system_health.info.${key}`
|
||||
) || key}
|
||||
</td>
|
||||
<td>${value}</td>
|
||||
</tr>
|
||||
`);
|
||||
}
|
||||
if (domain !== "homeassistant") {
|
||||
sections.push(
|
||||
html`
|
||||
<div class="card-header">
|
||||
<h3>${domainToName(this.hass.localize, domain)}</h3>
|
||||
${!domainInfo.manage_url
|
||||
? ""
|
||||
: html`
|
||||
<a class="manage" href=${domainInfo.manage_url}>
|
||||
<mwc-button>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.info.system_health.manage"
|
||||
)}
|
||||
</mwc-button>
|
||||
</a>
|
||||
`}
|
||||
</div>
|
||||
`
|
||||
);
|
||||
}
|
||||
sections.push(html`
|
||||
<table>
|
||||
${keys}
|
||||
</table>
|
||||
`);
|
||||
}
|
||||
if (!this._opened) {
|
||||
return html``;
|
||||
}
|
||||
|
||||
const sections = this._getSections();
|
||||
|
||||
return html`
|
||||
<hass-subpage
|
||||
.hass=${this.hass}
|
||||
.narrow=${this.narrow}
|
||||
back-path="/config/system"
|
||||
.header=${this.hass.localize("ui.panel.config.system_health.caption")}
|
||||
<ha-dialog
|
||||
open
|
||||
@closed=${this.closeDialog}
|
||||
scrimClickAction
|
||||
escapeKeyAction
|
||||
.heading=${createCloseHeading(
|
||||
this.hass,
|
||||
this.hass.localize("ui.panel.config.repairs.system_information")
|
||||
)}
|
||||
>
|
||||
${this._error
|
||||
? html`
|
||||
<ha-alert alert-type="error"
|
||||
>${this._error.message || this._error.code}</ha-alert
|
||||
>
|
||||
`
|
||||
: ""}
|
||||
${this._info
|
||||
? html`
|
||||
<ha-button-menu
|
||||
corner="BOTTOM_START"
|
||||
slot="toolbar-icon"
|
||||
@action=${this._copyInfo}
|
||||
>
|
||||
<ha-icon-button
|
||||
slot="trigger"
|
||||
.label=${this.hass.localize("ui.panel.config.info.copy_menu")}
|
||||
.path=${mdiContentCopy}
|
||||
></ha-icon-button>
|
||||
<mwc-list-item>
|
||||
${this.hass.localize("ui.panel.config.info.copy_raw")}
|
||||
</mwc-list-item>
|
||||
<mwc-list-item>
|
||||
${this.hass.localize("ui.panel.config.info.copy_github")}
|
||||
</mwc-list-item>
|
||||
</ha-button-menu>
|
||||
`
|
||||
: ""}
|
||||
<div class="content">
|
||||
<div>
|
||||
${this._resolutionInfo
|
||||
? html`${this._resolutionInfo.unhealthy.length
|
||||
? html`<ha-alert alert-type="error">
|
||||
@ -265,66 +176,63 @@ class HaConfigSystemHealth extends SubscribeMixin(LitElement) {
|
||||
: ""} `
|
||||
: ""}
|
||||
|
||||
<ha-card outlined>
|
||||
<div class="card-content">${sections}</div>
|
||||
</ha-card>
|
||||
<div>${sections}</div>
|
||||
|
||||
${!this._coreStats && !this._supervisorStats
|
||||
? ""
|
||||
: html`
|
||||
<ha-card outlined>
|
||||
<div class="card-content">
|
||||
${this._coreStats
|
||||
? html`
|
||||
<h3>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.system_health.core_stats"
|
||||
)}
|
||||
</h3>
|
||||
<ha-metric
|
||||
.heading=${this.hass.localize(
|
||||
"ui.panel.config.system_health.cpu_usage"
|
||||
)}
|
||||
.value=${this._coreStats.cpu_percent}
|
||||
></ha-metric>
|
||||
<ha-metric
|
||||
.heading=${this.hass.localize(
|
||||
"ui.panel.config.system_health.ram_usage"
|
||||
)}
|
||||
.value=${this._coreStats.memory_percent}
|
||||
></ha-metric>
|
||||
`
|
||||
: ""}
|
||||
${this._supervisorStats
|
||||
? html`
|
||||
<h3>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.system_health.supervisor_stats"
|
||||
)}
|
||||
</h3>
|
||||
<ha-metric
|
||||
.heading=${this.hass.localize(
|
||||
"ui.panel.config.system_health.cpu_usage"
|
||||
)}
|
||||
.value=${this._supervisorStats.cpu_percent}
|
||||
></ha-metric>
|
||||
<ha-metric
|
||||
.heading=${this.hass.localize(
|
||||
"ui.panel.config.system_health.ram_usage"
|
||||
)}
|
||||
.value=${this._supervisorStats.memory_percent}
|
||||
></ha-metric>
|
||||
`
|
||||
: ""}
|
||||
</div>
|
||||
</ha-card>
|
||||
<div>
|
||||
${this._coreStats
|
||||
? html`
|
||||
<h3>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.system_health.core_stats"
|
||||
)}
|
||||
</h3>
|
||||
<ha-metric
|
||||
.heading=${this.hass.localize(
|
||||
"ui.panel.config.system_health.cpu_usage"
|
||||
)}
|
||||
.value=${this._coreStats.cpu_percent}
|
||||
></ha-metric>
|
||||
<ha-metric
|
||||
.heading=${this.hass.localize(
|
||||
"ui.panel.config.system_health.ram_usage"
|
||||
)}
|
||||
.value=${this._coreStats.memory_percent}
|
||||
></ha-metric>
|
||||
`
|
||||
: ""}
|
||||
${this._supervisorStats
|
||||
? html`
|
||||
<h3>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.system_health.supervisor_stats"
|
||||
)}
|
||||
</h3>
|
||||
<ha-metric
|
||||
.heading=${this.hass.localize(
|
||||
"ui.panel.config.system_health.cpu_usage"
|
||||
)}
|
||||
.value=${this._supervisorStats.cpu_percent}
|
||||
></ha-metric>
|
||||
<ha-metric
|
||||
.heading=${this.hass.localize(
|
||||
"ui.panel.config.system_health.ram_usage"
|
||||
)}
|
||||
.value=${this._supervisorStats.memory_percent}
|
||||
></ha-metric>
|
||||
`
|
||||
: ""}
|
||||
</div>
|
||||
`}
|
||||
|
||||
<integrations-card
|
||||
.hass=${this.hass}
|
||||
.narrow=${this.narrow}
|
||||
></integrations-card>
|
||||
</div>
|
||||
</hass-subpage>
|
||||
<mwc-button
|
||||
slot="primaryAction"
|
||||
.label=${this.hass.localize("ui.panel.config.repairs.copy")}
|
||||
@click=${this._copyInfo}
|
||||
></mwc-button>
|
||||
</ha-dialog>
|
||||
`;
|
||||
}
|
||||
|
||||
@ -386,17 +294,111 @@ class HaConfigSystemHealth extends SubscribeMixin(LitElement) {
|
||||
});
|
||||
}
|
||||
|
||||
private async _copyInfo(ev: CustomEvent<ActionDetail>): Promise<void> {
|
||||
const github = ev.detail.index === 1;
|
||||
private _getSections(): TemplateResult[] {
|
||||
const sections: TemplateResult[] = [];
|
||||
|
||||
if (!this._systemInfo) {
|
||||
sections.push(
|
||||
html`
|
||||
<div class="loading-container">
|
||||
<ha-circular-progress active></ha-circular-progress>
|
||||
</div>
|
||||
`
|
||||
);
|
||||
} else {
|
||||
const domains = Object.keys(this._systemInfo).sort(sortKeys);
|
||||
for (const domain of domains) {
|
||||
const domainInfo = this._systemInfo[domain];
|
||||
const keys: TemplateResult[] = [];
|
||||
|
||||
for (const key of Object.keys(domainInfo.info)) {
|
||||
let value: unknown;
|
||||
|
||||
if (
|
||||
domainInfo.info[key] &&
|
||||
typeof domainInfo.info[key] === "object"
|
||||
) {
|
||||
const info = domainInfo.info[key] as SystemCheckValueObject;
|
||||
|
||||
if (info.type === "pending") {
|
||||
value = html`
|
||||
<ha-circular-progress active size="tiny"></ha-circular-progress>
|
||||
`;
|
||||
} else if (info.type === "failed") {
|
||||
value = html`
|
||||
<span class="error">${info.error}</span>${!info.more_info
|
||||
? ""
|
||||
: html`
|
||||
–
|
||||
<a
|
||||
href=${info.more_info}
|
||||
target="_blank"
|
||||
rel="noreferrer noopener"
|
||||
>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.info.system_health.more_systemInfo"
|
||||
)}
|
||||
</a>
|
||||
`}
|
||||
`;
|
||||
} else if (info.type === "date") {
|
||||
value = formatDateTime(new Date(info.value), this.hass.locale);
|
||||
}
|
||||
} else {
|
||||
value = domainInfo.info[key];
|
||||
}
|
||||
|
||||
keys.push(html`
|
||||
<tr>
|
||||
<td>
|
||||
${this.hass.localize(
|
||||
`component.${domain}.system_health.info.${key}`
|
||||
) || key}
|
||||
</td>
|
||||
<td>${value}</td>
|
||||
</tr>
|
||||
`);
|
||||
}
|
||||
if (domain !== "homeassistant") {
|
||||
sections.push(
|
||||
html`
|
||||
<div class="card-header">
|
||||
<h3>${domainToName(this.hass.localize, domain)}</h3>
|
||||
${!domainInfo.manage_url
|
||||
? ""
|
||||
: html`
|
||||
<a class="manage" href=${domainInfo.manage_url}>
|
||||
<mwc-button>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.info.system_health.manage"
|
||||
)}
|
||||
</mwc-button>
|
||||
</a>
|
||||
`}
|
||||
</div>
|
||||
`
|
||||
);
|
||||
}
|
||||
sections.push(html`
|
||||
<table>
|
||||
${keys}
|
||||
</table>
|
||||
`);
|
||||
}
|
||||
}
|
||||
return sections;
|
||||
}
|
||||
|
||||
private async _copyInfo(): Promise<void> {
|
||||
let haContent: string | undefined;
|
||||
const domainParts: string[] = [];
|
||||
|
||||
for (const domain of Object.keys(this._info!).sort(sortKeys)) {
|
||||
const domainInfo = this._info![domain];
|
||||
for (const domain of Object.keys(this._systemInfo!).sort(sortKeys)) {
|
||||
const domainInfo = this._systemInfo![domain];
|
||||
let first = true;
|
||||
const parts = [
|
||||
`${
|
||||
github && domain !== "homeassistant"
|
||||
domain !== "homeassistant"
|
||||
? `<details><summary>${domainToName(
|
||||
this.hass.localize,
|
||||
domain
|
||||
@ -408,7 +410,7 @@ class HaConfigSystemHealth extends SubscribeMixin(LitElement) {
|
||||
for (const key of Object.keys(domainInfo.info)) {
|
||||
let value: unknown;
|
||||
|
||||
if (typeof domainInfo.info[key] === "object") {
|
||||
if (domainInfo.info[key] && typeof domainInfo.info[key] === "object") {
|
||||
const info = domainInfo.info[key] as SystemCheckValueObject;
|
||||
|
||||
if (info.type === "pending") {
|
||||
@ -421,11 +423,11 @@ class HaConfigSystemHealth extends SubscribeMixin(LitElement) {
|
||||
} else {
|
||||
value = domainInfo.info[key];
|
||||
}
|
||||
if (github && first) {
|
||||
if (first) {
|
||||
parts.push(`${key} | ${value}\n-- | --`);
|
||||
first = false;
|
||||
} else {
|
||||
parts.push(`${key}${github ? " | " : ": "}${value}`);
|
||||
parts.push(`${key} | ${value}`);
|
||||
}
|
||||
}
|
||||
|
||||
@ -433,16 +435,14 @@ class HaConfigSystemHealth extends SubscribeMixin(LitElement) {
|
||||
haContent = parts.join("\n");
|
||||
} else {
|
||||
domainParts.push(parts.join("\n"));
|
||||
if (github && domain !== "homeassistant") {
|
||||
if (domain !== "homeassistant") {
|
||||
domainParts.push("</details>");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
await copyToClipboard(
|
||||
`${github ? "## " : ""}System Health\n${haContent}\n\n${domainParts.join(
|
||||
"\n\n"
|
||||
)}`
|
||||
`${"## "}System Information\n${haContent}\n\n${domainParts.join("\n\n")}`
|
||||
);
|
||||
|
||||
showToast(this, {
|
||||
@ -450,73 +450,50 @@ class HaConfigSystemHealth extends SubscribeMixin(LitElement) {
|
||||
});
|
||||
}
|
||||
|
||||
static styles: CSSResultGroup = css`
|
||||
.content {
|
||||
padding: 28px 20px 0;
|
||||
max-width: 1040px;
|
||||
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 {
|
||||
display: block;
|
||||
max-width: 600px;
|
||||
margin: 0 auto;
|
||||
padding-bottom: 16px;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
ha-alert {
|
||||
display: block;
|
||||
max-width: 500px;
|
||||
margin: 0 auto;
|
||||
margin-bottom: max(24px, env(safe-area-inset-bottom));
|
||||
}
|
||||
table {
|
||||
width: 100%;
|
||||
}
|
||||
static styles: CSSResultGroup = [
|
||||
haStyleDialog,
|
||||
css`
|
||||
ha-alert {
|
||||
margin-bottom: 16px;
|
||||
display: block;
|
||||
}
|
||||
table {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
td:first-child {
|
||||
width: 45%;
|
||||
}
|
||||
td:first-child {
|
||||
width: 45%;
|
||||
}
|
||||
|
||||
td:last-child {
|
||||
direction: ltr;
|
||||
}
|
||||
td:last-child {
|
||||
direction: ltr;
|
||||
}
|
||||
|
||||
.loading-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
.loading-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.card-header {
|
||||
justify-content: space-between;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
.card-header {
|
||||
justify-content: space-between;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.error {
|
||||
color: var(--error-color);
|
||||
}
|
||||
.error {
|
||||
color: var(--error-color);
|
||||
}
|
||||
|
||||
a {
|
||||
color: var(--primary-color);
|
||||
}
|
||||
|
||||
a.manage {
|
||||
text-decoration: none;
|
||||
}
|
||||
`;
|
||||
a.manage {
|
||||
text-decoration: none;
|
||||
}
|
||||
`,
|
||||
];
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"ha-config-system-health": HaConfigSystemHealth;
|
||||
"dialog-system-information": DialogSystemInformation;
|
||||
}
|
||||
}
|
@ -1,8 +1,10 @@
|
||||
import type { ActionDetail } from "@material/mwc-list";
|
||||
import { RequestSelectedDetail } from "@material/mwc-list/mwc-list-item-base";
|
||||
import { mdiDotsVertical } from "@mdi/js";
|
||||
import { css, html, LitElement, PropertyValues, TemplateResult } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import memoizeOne from "memoize-one";
|
||||
import { isComponentLoaded } from "../../../common/config/is_component_loaded";
|
||||
import { shouldHandleRequestSelectedEvent } from "../../../common/mwc/handle-request-selected-event";
|
||||
import "../../../components/ha-card";
|
||||
import {
|
||||
fetchRepairsIssues,
|
||||
@ -10,11 +12,14 @@ import {
|
||||
severitySort,
|
||||
} from "../../../data/repairs";
|
||||
import "../../../layouts/hass-subpage";
|
||||
import { SubscribeMixin } from "../../../mixins/subscribe-mixin";
|
||||
import type { HomeAssistant } from "../../../types";
|
||||
import "./ha-config-repairs";
|
||||
import { showIntegrationStartupDialog } from "./show-integration-startup-dialog";
|
||||
import { showSystemInformationDialog } from "./show-system-information-dialog";
|
||||
|
||||
@customElement("ha-config-repairs-dashboard")
|
||||
class HaConfigRepairsDashboard extends LitElement {
|
||||
class HaConfigRepairsDashboard extends SubscribeMixin(LitElement) {
|
||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||
|
||||
@property({ type: Boolean }) public narrow!: boolean;
|
||||
@ -40,6 +45,7 @@ class HaConfigRepairsDashboard extends LitElement {
|
||||
this._showIgnored,
|
||||
this._repairsIssues
|
||||
);
|
||||
|
||||
return html`
|
||||
<hass-subpage
|
||||
back-path="/config/system"
|
||||
@ -48,13 +54,32 @@ class HaConfigRepairsDashboard extends LitElement {
|
||||
.header=${this.hass.localize("ui.panel.config.repairs.caption")}
|
||||
>
|
||||
<div slot="toolbar-icon">
|
||||
<ha-button-menu corner="BOTTOM_START" @action=${this._handleAction}>
|
||||
<ha-button-menu corner="BOTTOM_START">
|
||||
<ha-icon-button
|
||||
slot="trigger"
|
||||
.label=${this.hass.localize("ui.common.menu")}
|
||||
.path=${mdiDotsVertical}
|
||||
></ha-icon-button>
|
||||
<mwc-list-item id="skipped">
|
||||
${isComponentLoaded(this.hass, "system_health") ||
|
||||
isComponentLoaded(this.hass, "hassio")
|
||||
? html`
|
||||
<mwc-list-item
|
||||
@request-selected=${this._showSystemInformationDialog}
|
||||
>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.repairs.system_information"
|
||||
)}
|
||||
</mwc-list-item>
|
||||
`
|
||||
: ""}
|
||||
<mwc-list-item
|
||||
@request-selected=${this._showIntegrationStartupDialog}
|
||||
>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.repairs.integration_startup_time"
|
||||
)}
|
||||
</mwc-list-item>
|
||||
<mwc-list-item @request-selected=${this._toggleIgnored}>
|
||||
${this._showIgnored
|
||||
? this.hass.localize("ui.panel.config.repairs.hide_ignored")
|
||||
: this.hass.localize("ui.panel.config.repairs.show_ignored")}
|
||||
@ -98,12 +123,32 @@ class HaConfigRepairsDashboard extends LitElement {
|
||||
this.hass.loadBackendTranslation("issues", [...integrations]);
|
||||
}
|
||||
|
||||
private _handleAction(ev: CustomEvent<ActionDetail>) {
|
||||
switch (ev.detail.index) {
|
||||
case 0:
|
||||
this._showIgnored = !this._showIgnored;
|
||||
break;
|
||||
private _showSystemInformationDialog(
|
||||
ev: CustomEvent<RequestSelectedDetail>
|
||||
): void {
|
||||
if (!shouldHandleRequestSelectedEvent(ev)) {
|
||||
return;
|
||||
}
|
||||
|
||||
showSystemInformationDialog(this);
|
||||
}
|
||||
|
||||
private _showIntegrationStartupDialog(
|
||||
ev: CustomEvent<RequestSelectedDetail>
|
||||
): void {
|
||||
if (!shouldHandleRequestSelectedEvent(ev)) {
|
||||
return;
|
||||
}
|
||||
|
||||
showIntegrationStartupDialog(this);
|
||||
}
|
||||
|
||||
private _toggleIgnored(ev: CustomEvent<RequestSelectedDetail>): void {
|
||||
if (!shouldHandleRequestSelectedEvent(ev)) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._showIgnored = !this._showIgnored;
|
||||
}
|
||||
|
||||
static styles = css`
|
||||
|
@ -21,8 +21,8 @@ import type { HomeAssistant } from "../../../types";
|
||||
import { brandsUrl } from "../../../util/brands-url";
|
||||
import { documentationUrl } from "../../../util/documentation-url";
|
||||
|
||||
@customElement("integrations-card")
|
||||
class IntegrationsCard extends LitElement {
|
||||
@customElement("integrations-startup-time")
|
||||
class IntegrationsStartupTime extends LitElement {
|
||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||
|
||||
@property({ type: Boolean }) public narrow = false;
|
||||
@ -45,57 +45,47 @@ class IntegrationsCard extends LitElement {
|
||||
}
|
||||
|
||||
return html`
|
||||
<ha-card
|
||||
outlined
|
||||
.header=${this.hass.localize(
|
||||
"ui.panel.config.system_health.integration_start_time"
|
||||
)}
|
||||
>
|
||||
<mwc-list>
|
||||
${this._setups?.map((setup) => {
|
||||
const manifest = this._manifests && this._manifests[setup.domain];
|
||||
const docLink = manifest
|
||||
? manifest.is_built_in
|
||||
? documentationUrl(
|
||||
this.hass,
|
||||
`/integrations/${manifest.domain}`
|
||||
)
|
||||
: manifest.documentation
|
||||
: "";
|
||||
<mwc-list>
|
||||
${this._setups?.map((setup) => {
|
||||
const manifest = this._manifests && this._manifests[setup.domain];
|
||||
const docLink = manifest
|
||||
? manifest.is_built_in
|
||||
? documentationUrl(this.hass, `/integrations/${manifest.domain}`)
|
||||
: manifest.documentation
|
||||
: "";
|
||||
|
||||
const setupSeconds = setup.seconds?.toFixed(2);
|
||||
return html`
|
||||
<ha-clickable-list-item
|
||||
graphic="avatar"
|
||||
twoline
|
||||
hasMeta
|
||||
openNewTab
|
||||
@click=${this._entryClicked}
|
||||
href=${docLink}
|
||||
>
|
||||
<img
|
||||
loading="lazy"
|
||||
src=${brandsUrl({
|
||||
domain: setup.domain,
|
||||
type: "icon",
|
||||
useFallback: true,
|
||||
darkOptimized: this.hass.themes?.darkMode,
|
||||
})}
|
||||
referrerpolicy="no-referrer"
|
||||
slot="graphic"
|
||||
/>
|
||||
<span>
|
||||
${domainToName(this.hass.localize, setup.domain, manifest)}
|
||||
</span>
|
||||
<span slot="secondary">${setup.domain}</span>
|
||||
<div slot="meta">
|
||||
${setupSeconds ? html`${setupSeconds} s` : ""}
|
||||
</div>
|
||||
</ha-clickable-list-item>
|
||||
`;
|
||||
})}
|
||||
</mwc-list>
|
||||
</ha-card>
|
||||
const setupSeconds = setup.seconds?.toFixed(2);
|
||||
return html`
|
||||
<ha-clickable-list-item
|
||||
graphic="avatar"
|
||||
twoline
|
||||
hasMeta
|
||||
openNewTab
|
||||
@click=${this._entryClicked}
|
||||
href=${docLink}
|
||||
>
|
||||
<img
|
||||
loading="lazy"
|
||||
src=${brandsUrl({
|
||||
domain: setup.domain,
|
||||
type: "icon",
|
||||
useFallback: true,
|
||||
darkOptimized: this.hass.themes?.darkMode,
|
||||
})}
|
||||
referrerpolicy="no-referrer"
|
||||
slot="graphic"
|
||||
/>
|
||||
<span>
|
||||
${domainToName(this.hass.localize, setup.domain, manifest)}
|
||||
</span>
|
||||
<span slot="secondary">${setup.domain}</span>
|
||||
<div slot="meta">
|
||||
${setupSeconds ? html`${setupSeconds} s` : ""}
|
||||
</div>
|
||||
</ha-clickable-list-item>
|
||||
`;
|
||||
})}
|
||||
</mwc-list>
|
||||
`;
|
||||
}
|
||||
|
||||
@ -149,6 +139,6 @@ class IntegrationsCard extends LitElement {
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"integrations-card": IntegrationsCard;
|
||||
"integrations-startup-time": IntegrationsStartupTime;
|
||||
}
|
||||
}
|
12
src/panels/config/repairs/show-integration-startup-dialog.ts
Normal file
12
src/panels/config/repairs/show-integration-startup-dialog.ts
Normal file
@ -0,0 +1,12 @@
|
||||
import { fireEvent } from "../../../common/dom/fire_event";
|
||||
|
||||
export const loadIntegrationStartupDialog = () =>
|
||||
import("./dialog-integration-startup");
|
||||
|
||||
export const showIntegrationStartupDialog = (element: HTMLElement): void => {
|
||||
fireEvent(element, "show-dialog", {
|
||||
dialogTag: "dialog-integration-startup",
|
||||
dialogImport: loadIntegrationStartupDialog,
|
||||
dialogParams: {},
|
||||
});
|
||||
};
|
12
src/panels/config/repairs/show-system-information-dialog.ts
Normal file
12
src/panels/config/repairs/show-system-information-dialog.ts
Normal file
@ -0,0 +1,12 @@
|
||||
import { fireEvent } from "../../../common/dom/fire_event";
|
||||
|
||||
export const loadSystemInformationDialog = () =>
|
||||
import("./dialog-system-information");
|
||||
|
||||
export const showSystemInformationDialog = (element: HTMLElement): void => {
|
||||
fireEvent(element, "show-dialog", {
|
||||
dialogTag: "dialog-system-information",
|
||||
dialogImport: loadSystemInformationDialog,
|
||||
dialogParams: undefined,
|
||||
});
|
||||
};
|
@ -1237,6 +1237,9 @@
|
||||
"critical": "Critical",
|
||||
"error": "Error",
|
||||
"warning": "Warning",
|
||||
"system_information": "System information",
|
||||
"integration_startup_time": "Integration startup time",
|
||||
"copy": "Copy",
|
||||
"dialog": {
|
||||
"title": "Repair",
|
||||
"fix": "Repair",
|
||||
|
Loading…
x
Reference in New Issue
Block a user