mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-27 11:16:35 +00:00
Add hardware dialog (#9348)
Co-authored-by: Bram Kragten <mail@bramkragten.nl>
This commit is contained in:
parent
342020b420
commit
c68b76e2da
194
hassio/src/dialogs/hardware/dialog-hassio-hardware.ts
Executable file
194
hassio/src/dialogs/hardware/dialog-hassio-hardware.ts
Executable file
@ -0,0 +1,194 @@
|
|||||||
|
import { mdiClose } from "@mdi/js";
|
||||||
|
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
||||||
|
import { customElement, property, state } from "lit/decorators";
|
||||||
|
import memoizeOne from "memoize-one";
|
||||||
|
import { fireEvent } from "../../../../src/common/dom/fire_event";
|
||||||
|
import "../../../../src/common/search/search-input";
|
||||||
|
import { compare } from "../../../../src/common/string/compare";
|
||||||
|
import "../../../../src/components/ha-dialog";
|
||||||
|
import "../../../../src/components/ha-expansion-panel";
|
||||||
|
import { HassioHardwareInfo } from "../../../../src/data/hassio/hardware";
|
||||||
|
import { dump } from "../../../../src/resources/js-yaml-dump";
|
||||||
|
import { haStyle, haStyleDialog } from "../../../../src/resources/styles";
|
||||||
|
import { HomeAssistant } from "../../../../src/types";
|
||||||
|
import { HassioHardwareDialogParams } from "./show-dialog-hassio-hardware";
|
||||||
|
|
||||||
|
const _filterDevices = memoizeOne(
|
||||||
|
(showAdvanced: boolean, hardware: HassioHardwareInfo, filter: string) =>
|
||||||
|
hardware.devices
|
||||||
|
.filter(
|
||||||
|
(device) =>
|
||||||
|
(showAdvanced ||
|
||||||
|
["tty", "gpio", "input"].includes(device.subsystem)) &&
|
||||||
|
(device.by_id?.toLowerCase().includes(filter) ||
|
||||||
|
device.name.toLowerCase().includes(filter) ||
|
||||||
|
device.dev_path.toLocaleLowerCase().includes(filter) ||
|
||||||
|
JSON.stringify(device.attributes)
|
||||||
|
.toLocaleLowerCase()
|
||||||
|
.includes(filter))
|
||||||
|
)
|
||||||
|
.sort((a, b) => compare(a.name, b.name))
|
||||||
|
);
|
||||||
|
|
||||||
|
@customElement("dialog-hassio-hardware")
|
||||||
|
class HassioHardwareDialog extends LitElement {
|
||||||
|
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||||
|
|
||||||
|
@state() private _dialogParams?: HassioHardwareDialogParams;
|
||||||
|
|
||||||
|
@state() private _filter?: string;
|
||||||
|
|
||||||
|
public showDialog(params: HassioHardwareDialogParams) {
|
||||||
|
this._dialogParams = params;
|
||||||
|
}
|
||||||
|
|
||||||
|
public closeDialog() {
|
||||||
|
this._dialogParams = undefined;
|
||||||
|
fireEvent(this, "dialog-closed", { dialog: this.localName });
|
||||||
|
}
|
||||||
|
|
||||||
|
protected render(): TemplateResult {
|
||||||
|
if (!this._dialogParams) {
|
||||||
|
return html``;
|
||||||
|
}
|
||||||
|
|
||||||
|
const devices = _filterDevices(
|
||||||
|
this.hass.userData?.showAdvanced || false,
|
||||||
|
this._dialogParams.hardware,
|
||||||
|
(this._filter || "").toLowerCase()
|
||||||
|
);
|
||||||
|
|
||||||
|
return html`
|
||||||
|
<ha-dialog
|
||||||
|
open
|
||||||
|
scrimClickAction
|
||||||
|
hideActions
|
||||||
|
@closed=${this.closeDialog}
|
||||||
|
.heading=${true}
|
||||||
|
>
|
||||||
|
<div class="header" slot="heading">
|
||||||
|
<h2>
|
||||||
|
${this._dialogParams.supervisor.localize("dialog.hardware.title")}
|
||||||
|
</h2>
|
||||||
|
<mwc-icon-button dialogAction="close">
|
||||||
|
<ha-svg-icon .path=${mdiClose}></ha-svg-icon>
|
||||||
|
</mwc-icon-button>
|
||||||
|
<search-input
|
||||||
|
autofocus
|
||||||
|
no-label-float
|
||||||
|
.filter=${this._filter}
|
||||||
|
@value-changed=${this._handleSearchChange}
|
||||||
|
.label=${this._dialogParams.supervisor.localize(
|
||||||
|
"dialog.hardware.search"
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
</search-input>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
${devices.map(
|
||||||
|
(device) =>
|
||||||
|
html`<ha-expansion-panel
|
||||||
|
.header=${device.name}
|
||||||
|
.secondary=${device.by_id || undefined}
|
||||||
|
outlined
|
||||||
|
>
|
||||||
|
<div class="device-property">
|
||||||
|
<span>
|
||||||
|
${this._dialogParams!.supervisor.localize(
|
||||||
|
"dialog.hardware.subsystem"
|
||||||
|
)}:
|
||||||
|
</span>
|
||||||
|
<span>${device.subsystem}</span>
|
||||||
|
</div>
|
||||||
|
<div class="device-property">
|
||||||
|
<span>
|
||||||
|
${this._dialogParams!.supervisor.localize(
|
||||||
|
"dialog.hardware.device_path"
|
||||||
|
)}:
|
||||||
|
</span>
|
||||||
|
<code>${device.dev_path}</code>
|
||||||
|
</div>
|
||||||
|
${device.by_id
|
||||||
|
? html` <div class="device-property">
|
||||||
|
<span>
|
||||||
|
${this._dialogParams!.supervisor.localize(
|
||||||
|
"dialog.hardware.id"
|
||||||
|
)}:
|
||||||
|
</span>
|
||||||
|
<code>${device.by_id}</code>
|
||||||
|
</div>`
|
||||||
|
: ""}
|
||||||
|
<div class="attributes">
|
||||||
|
<span>
|
||||||
|
${this._dialogParams!.supervisor.localize(
|
||||||
|
"dialog.hardware.attributes"
|
||||||
|
)}:
|
||||||
|
</span>
|
||||||
|
<pre>${dump(device.attributes, { indent: 2 })}</pre>
|
||||||
|
</div>
|
||||||
|
</ha-expansion-panel>`
|
||||||
|
)}
|
||||||
|
</ha-dialog>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
private _handleSearchChange(ev: CustomEvent) {
|
||||||
|
this._filter = ev.detail.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
static get styles(): CSSResultGroup {
|
||||||
|
return [
|
||||||
|
haStyle,
|
||||||
|
haStyleDialog,
|
||||||
|
css`
|
||||||
|
mwc-icon-button {
|
||||||
|
position: absolute;
|
||||||
|
right: 16px;
|
||||||
|
top: 10px;
|
||||||
|
text-decoration: none;
|
||||||
|
color: var(--primary-text-color);
|
||||||
|
}
|
||||||
|
h2 {
|
||||||
|
margin: 18px 42px 0 18px;
|
||||||
|
color: var(--primary-text-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
ha-expansion-panel {
|
||||||
|
margin: 4px 0;
|
||||||
|
}
|
||||||
|
pre,
|
||||||
|
code {
|
||||||
|
background-color: var(--markdown-code-background-color, none);
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
pre {
|
||||||
|
padding: 16px;
|
||||||
|
overflow: auto;
|
||||||
|
line-height: 1.45;
|
||||||
|
font-family: var(--code-font-family, monospace);
|
||||||
|
}
|
||||||
|
code {
|
||||||
|
font-size: 85%;
|
||||||
|
padding: 0.2em 0.4em;
|
||||||
|
}
|
||||||
|
search-input {
|
||||||
|
margin: 0 16px;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
.device-property {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
.attributes {
|
||||||
|
margin-top: 12px;
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
"dialog-hassio-hardware": HassioHardwareDialog;
|
||||||
|
}
|
||||||
|
}
|
19
hassio/src/dialogs/hardware/show-dialog-hassio-hardware.ts
Normal file
19
hassio/src/dialogs/hardware/show-dialog-hassio-hardware.ts
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
import { fireEvent } from "../../../../src/common/dom/fire_event";
|
||||||
|
import { HassioHardwareInfo } from "../../../../src/data/hassio/hardware";
|
||||||
|
import { Supervisor } from "../../../../src/data/supervisor/supervisor";
|
||||||
|
|
||||||
|
export interface HassioHardwareDialogParams {
|
||||||
|
supervisor: Supervisor;
|
||||||
|
hardware: HassioHardwareInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const showHassioHardwareDialog = (
|
||||||
|
element: HTMLElement,
|
||||||
|
dialogParams: HassioHardwareDialogParams
|
||||||
|
): void => {
|
||||||
|
fireEvent(element, "show-dialog", {
|
||||||
|
dialogTag: "dialog-hassio-hardware",
|
||||||
|
dialogImport: () => import("./dialog-hassio-hardware"),
|
||||||
|
dialogParams,
|
||||||
|
});
|
||||||
|
};
|
@ -2,7 +2,6 @@ import "@material/mwc-button";
|
|||||||
import { ActionDetail } from "@material/mwc-list/mwc-list-foundation";
|
import { ActionDetail } from "@material/mwc-list/mwc-list-foundation";
|
||||||
import "@material/mwc-list/mwc-list-item";
|
import "@material/mwc-list/mwc-list-item";
|
||||||
import { mdiDotsVertical } from "@mdi/js";
|
import { mdiDotsVertical } from "@mdi/js";
|
||||||
import { dump } from "js-yaml";
|
|
||||||
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
||||||
import { customElement, property } from "lit/decorators";
|
import { customElement, property } from "lit/decorators";
|
||||||
import memoizeOne from "memoize-one";
|
import memoizeOne from "memoize-one";
|
||||||
@ -41,8 +40,8 @@ import {
|
|||||||
roundWithOneDecimal,
|
roundWithOneDecimal,
|
||||||
} from "../../../src/util/calculate";
|
} from "../../../src/util/calculate";
|
||||||
import "../components/supervisor-metric";
|
import "../components/supervisor-metric";
|
||||||
import { showHassioMarkdownDialog } from "../dialogs/markdown/show-dialog-hassio-markdown";
|
|
||||||
import { showNetworkDialog } from "../dialogs/network/show-dialog-network";
|
import { showNetworkDialog } from "../dialogs/network/show-dialog-network";
|
||||||
|
import { showHassioHardwareDialog } from "../dialogs/hardware/show-dialog-hassio-hardware";
|
||||||
import { hassioStyle } from "../resources/hassio-style";
|
import { hassioStyle } from "../resources/hassio-style";
|
||||||
|
|
||||||
@customElement("hassio-host-info")
|
@customElement("hassio-host-info")
|
||||||
@ -229,20 +228,19 @@ class HassioHostInfo extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async _showHardware(): Promise<void> {
|
private async _showHardware(): Promise<void> {
|
||||||
|
let hardware;
|
||||||
try {
|
try {
|
||||||
const content = await fetchHassioHardwareInfo(this.hass);
|
hardware = await fetchHassioHardwareInfo(this.hass);
|
||||||
showHassioMarkdownDialog(this, {
|
|
||||||
title: this.supervisor.localize("system.host.hardware"),
|
|
||||||
content: `<pre>${dump(content, { indent: 2 })}</pre>`,
|
|
||||||
});
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
showAlertDialog(this, {
|
await showAlertDialog(this, {
|
||||||
title: this.supervisor.localize(
|
title: this.supervisor.localize(
|
||||||
"system.host.failed_to_get_hardware_list"
|
"system.host.failed_to_get_hardware_list"
|
||||||
),
|
),
|
||||||
text: extractApiErrorMessage(err),
|
text: extractApiErrorMessage(err),
|
||||||
});
|
});
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
showHassioHardwareDialog(this, { supervisor: this.supervisor, hardware });
|
||||||
}
|
}
|
||||||
|
|
||||||
private async _hostReboot(ev: CustomEvent): Promise<void> {
|
private async _hostReboot(ev: CustomEvent): Promise<void> {
|
||||||
|
@ -14,12 +14,17 @@ class HaExpansionPanel extends LitElement {
|
|||||||
|
|
||||||
@property() header?: string;
|
@property() header?: string;
|
||||||
|
|
||||||
|
@property() secondary?: string;
|
||||||
|
|
||||||
@query(".container") private _container!: HTMLDivElement;
|
@query(".container") private _container!: HTMLDivElement;
|
||||||
|
|
||||||
protected render(): TemplateResult {
|
protected render(): TemplateResult {
|
||||||
return html`
|
return html`
|
||||||
<div class="summary" @click=${this._toggleContainer}>
|
<div class="summary" @click=${this._toggleContainer}>
|
||||||
<slot name="header">${this.header}</slot>
|
<slot class="header" name="header">
|
||||||
|
${this.header}
|
||||||
|
<slot class="secondary" name="secondary">${this.secondary}</slot>
|
||||||
|
</slot>
|
||||||
<ha-svg-icon
|
<ha-svg-icon
|
||||||
.path=${mdiChevronDown}
|
.path=${mdiChevronDown}
|
||||||
class="summary-icon ${classMap({ expanded: this.expanded })}"
|
class="summary-icon ${classMap({ expanded: this.expanded })}"
|
||||||
@ -106,6 +111,16 @@ class HaExpansionPanel extends LitElement {
|
|||||||
.container.expanded {
|
.container.expanded {
|
||||||
height: auto;
|
height: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.header {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.secondary {
|
||||||
|
display: block;
|
||||||
|
color: var(--secondary-text-color);
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,12 +14,17 @@ interface HassioHardwareAudioList {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface HardwareDevice {
|
||||||
|
attributes: Record<string, string>;
|
||||||
|
by_id: null | string;
|
||||||
|
dev_path: string;
|
||||||
|
name: string;
|
||||||
|
subsystem: string;
|
||||||
|
sysfs: string;
|
||||||
|
}
|
||||||
|
|
||||||
export interface HassioHardwareInfo {
|
export interface HassioHardwareInfo {
|
||||||
serial: string[];
|
devices: HardwareDevice[];
|
||||||
input: string[];
|
|
||||||
disk: string[];
|
|
||||||
gpio: string[];
|
|
||||||
audio: Record<string, unknown>;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const fetchHassioHardwareAudio = async (
|
export const fetchHassioHardwareAudio = async (
|
||||||
|
@ -3980,6 +3980,14 @@
|
|||||||
"create_snapshot": "Create a snapshot of {name} before updating",
|
"create_snapshot": "Create a snapshot of {name} before updating",
|
||||||
"updating": "Updating {name} to version {version}",
|
"updating": "Updating {name} to version {version}",
|
||||||
"snapshotting": "Creating snapshot of {name}"
|
"snapshotting": "Creating snapshot of {name}"
|
||||||
|
},
|
||||||
|
"hardware": {
|
||||||
|
"title": "Hardware",
|
||||||
|
"search": "Search hardware",
|
||||||
|
"subsystem": "Subsystem",
|
||||||
|
"id": "ID",
|
||||||
|
"attributes": "Attributes",
|
||||||
|
"device_path": "Device path"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user