mirror of
https://github.com/home-assistant/frontend.git
synced 2025-11-24 18:27:19 +00:00
Compare commits
3 Commits
logbook-en
...
encryption
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
52ffc9c1e4 | ||
|
|
cbed509349 | ||
|
|
197eaa32a0 |
14
src/data/esphome.ts
Normal file
14
src/data/esphome.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import type { HomeAssistant } from "../types";
|
||||
|
||||
export interface ESPHomeEncryptionKey {
|
||||
encryption_key: string;
|
||||
}
|
||||
|
||||
export const fetchESPHomeEncryptionKey = (
|
||||
hass: HomeAssistant,
|
||||
entry_id: string
|
||||
): Promise<ESPHomeEncryptionKey> =>
|
||||
hass.callWS({
|
||||
type: "esphome/get_encryption_key",
|
||||
entry_id,
|
||||
});
|
||||
@@ -188,7 +188,6 @@ export default class HaAutomationSidebar extends LitElement {
|
||||
class="handle ${this._resizing ? "resizing" : ""}"
|
||||
@mousedown=${this._handleMouseDown}
|
||||
@touchstart=${this._handleMouseDown}
|
||||
@dblclick=${this._handleDoubleClick}
|
||||
@focus=${this._startKeyboardResizing}
|
||||
@blur=${this._stopKeyboardResizing}
|
||||
tabindex="0"
|
||||
@@ -259,17 +258,6 @@ export default class HaAutomationSidebar extends LitElement {
|
||||
);
|
||||
};
|
||||
|
||||
private _handleDoubleClick = (ev: MouseEvent) => {
|
||||
ev.preventDefault();
|
||||
ev.stopPropagation();
|
||||
this._unregisterResizeHandlers();
|
||||
this._tinykeysUnsub?.();
|
||||
this._tinykeysUnsub = undefined;
|
||||
this._resizing = false;
|
||||
document.body.style.removeProperty("cursor");
|
||||
fireEvent(this, "sidebar-reset-size");
|
||||
};
|
||||
|
||||
private _startResizing(clientX: number) {
|
||||
// register event listeners for drag handling
|
||||
document.addEventListener("mousemove", this._handleMouseMove);
|
||||
@@ -434,6 +422,5 @@ declare global {
|
||||
deltaInPx: number;
|
||||
};
|
||||
"sidebar-resizing-stopped": undefined;
|
||||
"sidebar-reset-size": undefined;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -317,7 +317,6 @@ export class HaManualAutomationEditor extends LitElement {
|
||||
@value-changed=${this._sidebarConfigChanged}
|
||||
@sidebar-resized=${this._resizeSidebar}
|
||||
@sidebar-resizing-stopped=${this._stopResizeSidebar}
|
||||
@sidebar-reset-size=${this._resetSidebarWidth}
|
||||
></ha-automation-sidebar>
|
||||
</div>
|
||||
</div>
|
||||
@@ -701,16 +700,6 @@ export class HaManualAutomationEditor extends LitElement {
|
||||
this._prevSidebarWidthPx = undefined;
|
||||
}
|
||||
|
||||
private _resetSidebarWidth(ev: Event) {
|
||||
ev.stopPropagation();
|
||||
this._prevSidebarWidthPx = undefined;
|
||||
this._sidebarWidthPx = SIDEBAR_DEFAULT_WIDTH;
|
||||
this.style.setProperty(
|
||||
"--sidebar-dynamic-width",
|
||||
`${this._sidebarWidthPx}px`
|
||||
);
|
||||
}
|
||||
|
||||
static get styles(): CSSResultGroup {
|
||||
return [
|
||||
saveFabStyles,
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
import { mdiKey } from "@mdi/js";
|
||||
import { getConfigEntries } from "../../../../../../data/config_entries";
|
||||
import type { DeviceRegistryEntry } from "../../../../../../data/device_registry";
|
||||
import { fetchESPHomeEncryptionKey } from "../../../../../../data/esphome";
|
||||
import type { HomeAssistant } from "../../../../../../types";
|
||||
import { showESPHomeEncryptionKeyDialog } from "../../../../integrations/integration-panels/esphome/show-dialog-esphome-encryption-key";
|
||||
import type { DeviceAction } from "../../../ha-config-device-page";
|
||||
|
||||
export const getESPHomeDeviceActions = async (
|
||||
el: HTMLElement,
|
||||
hass: HomeAssistant,
|
||||
device: DeviceRegistryEntry
|
||||
): Promise<DeviceAction[]> => {
|
||||
const actions: DeviceAction[] = [];
|
||||
|
||||
const configEntries = await getConfigEntries(hass, {
|
||||
domain: "esphome",
|
||||
});
|
||||
|
||||
const configEntry = configEntries.find((entry) =>
|
||||
device.config_entries.includes(entry.entry_id)
|
||||
);
|
||||
|
||||
if (!configEntry) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const entryId = configEntry.entry_id;
|
||||
|
||||
try {
|
||||
const encryptionKey = await fetchESPHomeEncryptionKey(hass, entryId);
|
||||
|
||||
if (encryptionKey.encryption_key) {
|
||||
actions.push({
|
||||
label: hass.localize(
|
||||
"ui.panel.config.devices.esphome.show_encryption_key"
|
||||
),
|
||||
icon: mdiKey,
|
||||
action: () =>
|
||||
showESPHomeEncryptionKeyDialog(el, {
|
||||
entry_id: entryId,
|
||||
encryption_key: encryptionKey.encryption_key,
|
||||
}),
|
||||
});
|
||||
}
|
||||
} catch (err) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.error("Failed to fetch ESPHome encryption key:", err);
|
||||
}
|
||||
|
||||
return actions;
|
||||
};
|
||||
@@ -1162,6 +1162,17 @@ export class HaConfigDevicePage extends LitElement {
|
||||
);
|
||||
deviceActions.push(...actions);
|
||||
}
|
||||
if (domains.includes("esphome")) {
|
||||
const esphome = await import(
|
||||
"./device-detail/integration-elements/esphome/device-actions"
|
||||
);
|
||||
const actions = await esphome.getESPHomeDeviceActions(
|
||||
this,
|
||||
this.hass,
|
||||
device
|
||||
);
|
||||
deviceActions.push(...actions);
|
||||
}
|
||||
if (domains.includes("matter")) {
|
||||
const matter = await import(
|
||||
"./device-detail/integration-elements/matter/device-actions"
|
||||
|
||||
@@ -0,0 +1,135 @@
|
||||
import { mdiClose, mdiContentCopy } from "@mdi/js";
|
||||
import type { CSSResultGroup } from "lit";
|
||||
import { css, html, LitElement, nothing } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { fireEvent } from "../../../../../common/dom/fire_event";
|
||||
import { copyToClipboard } from "../../../../../common/util/copy-clipboard";
|
||||
import "../../../../../components/ha-dialog-header";
|
||||
import "../../../../../components/ha-icon-button";
|
||||
import "../../../../../components/ha-wa-dialog";
|
||||
import { haStyleDialog } from "../../../../../resources/styles";
|
||||
import type { HomeAssistant } from "../../../../../types";
|
||||
import { showToast } from "../../../../../util/toast";
|
||||
import type { ESPHomeEncryptionKeyDialogParams } from "./show-dialog-esphome-encryption-key";
|
||||
|
||||
@customElement("dialog-esphome-encryption-key")
|
||||
class DialogESPHomeEncryptionKey extends LitElement {
|
||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||
|
||||
@state() private _params?: ESPHomeEncryptionKeyDialogParams;
|
||||
|
||||
public async showDialog(
|
||||
params: ESPHomeEncryptionKeyDialogParams
|
||||
): Promise<void> {
|
||||
this._params = params;
|
||||
}
|
||||
|
||||
public closeDialog(): void {
|
||||
this._params = undefined;
|
||||
fireEvent(this, "dialog-closed", { dialog: this.localName });
|
||||
}
|
||||
|
||||
protected render() {
|
||||
if (!this._params) {
|
||||
return nothing;
|
||||
}
|
||||
|
||||
return html`
|
||||
<ha-wa-dialog
|
||||
open
|
||||
@closed=${this.closeDialog}
|
||||
hideActions
|
||||
header-title=${this.hass.localize(
|
||||
"ui.panel.config.devices.esphome.encryption_key_title"
|
||||
)}
|
||||
>
|
||||
<ha-dialog-header slot="heading">
|
||||
<ha-icon-button
|
||||
slot="navigationIcon"
|
||||
dialogAction="cancel"
|
||||
.label=${this.hass.localize("ui.common.close")}
|
||||
.path=${mdiClose}
|
||||
></ha-icon-button>
|
||||
<span slot="title">
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.devices.esphome.encryption_key_title"
|
||||
)}
|
||||
</span>
|
||||
</ha-dialog-header>
|
||||
|
||||
<div class="content">
|
||||
<p>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.devices.esphome.encryption_key_description"
|
||||
)}
|
||||
</p>
|
||||
<div class="key-row">
|
||||
<div class="key-container">
|
||||
<code>${this._params.encryption_key}</code>
|
||||
</div>
|
||||
<ha-icon-button
|
||||
@click=${this._copyToClipboard}
|
||||
.label=${this.hass.localize("ui.common.copy")}
|
||||
.path=${mdiContentCopy}
|
||||
></ha-icon-button>
|
||||
</div>
|
||||
</div>
|
||||
</ha-wa-dialog>
|
||||
`;
|
||||
}
|
||||
|
||||
private async _copyToClipboard(): Promise<void> {
|
||||
if (!this._params?.encryption_key) {
|
||||
return;
|
||||
}
|
||||
|
||||
await copyToClipboard(this._params.encryption_key);
|
||||
showToast(this, {
|
||||
message: this.hass.localize("ui.common.copied_clipboard"),
|
||||
});
|
||||
}
|
||||
|
||||
static get styles(): CSSResultGroup {
|
||||
return [
|
||||
haStyleDialog,
|
||||
css`
|
||||
ha-dialog {
|
||||
--mdc-dialog-max-width: 500px;
|
||||
}
|
||||
|
||||
.content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--ha-space-6);
|
||||
}
|
||||
|
||||
.key-row {
|
||||
display: flex;
|
||||
gap: var(--ha-space-2);
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.key-container {
|
||||
flex: 1;
|
||||
border-radius: var(--ha-space-2);
|
||||
border: 1px solid var(--divider-color);
|
||||
background-color: var(--code-editor-background-color, #f8f8f8);
|
||||
padding: var(--ha-space-3);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
p {
|
||||
margin: 0;
|
||||
color: var(--secondary-text-color);
|
||||
line-height: var(--ha-line-height-condensed);
|
||||
}
|
||||
`,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"dialog-esphome-encryption-key": DialogESPHomeEncryptionKey;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
import { fireEvent } from "../../../../../common/dom/fire_event";
|
||||
|
||||
export interface ESPHomeEncryptionKeyDialogParams {
|
||||
entry_id: string;
|
||||
encryption_key: string;
|
||||
}
|
||||
|
||||
export const loadESPHomeEncryptionKeyDialog = () =>
|
||||
import("./dialog-esphome-encryption-key");
|
||||
|
||||
export const showESPHomeEncryptionKeyDialog = (
|
||||
element: HTMLElement,
|
||||
dialogParams: ESPHomeEncryptionKeyDialogParams
|
||||
): void => {
|
||||
fireEvent(element, "show-dialog", {
|
||||
dialogTag: "dialog-esphome-encryption-key",
|
||||
dialogImport: loadESPHomeEncryptionKeyDialog,
|
||||
dialogParams,
|
||||
});
|
||||
};
|
||||
@@ -270,7 +270,6 @@ export class HaManualScriptEditor extends LitElement {
|
||||
@value-changed=${this._sidebarConfigChanged}
|
||||
@sidebar-resized=${this._resizeSidebar}
|
||||
@sidebar-resizing-stopped=${this._stopResizeSidebar}
|
||||
@sidebar-reset-size=${this._resetSidebarWidth}
|
||||
></ha-automation-sidebar>
|
||||
</div>
|
||||
</div>
|
||||
@@ -619,16 +618,6 @@ export class HaManualScriptEditor extends LitElement {
|
||||
this._prevSidebarWidthPx = undefined;
|
||||
}
|
||||
|
||||
private _resetSidebarWidth(ev: Event) {
|
||||
ev.stopPropagation();
|
||||
this._prevSidebarWidthPx = undefined;
|
||||
this._sidebarWidthPx = SIDEBAR_DEFAULT_WIDTH;
|
||||
this.style.setProperty(
|
||||
"--sidebar-dynamic-width",
|
||||
`${this._sidebarWidthPx}px`
|
||||
);
|
||||
}
|
||||
|
||||
static get styles(): CSSResultGroup {
|
||||
return [
|
||||
saveFabStyles,
|
||||
|
||||
@@ -11,7 +11,6 @@ import { formatTimeWithSeconds } from "../../common/datetime/format_time";
|
||||
import { restoreScroll } from "../../common/decorators/restore-scroll";
|
||||
import { fireEvent } from "../../common/dom/fire_event";
|
||||
import { computeDomain } from "../../common/entity/compute_domain";
|
||||
import { DEFAULT_ENTITY_NAME } from "../../common/entity/compute_entity_name_display";
|
||||
import { navigate } from "../../common/navigate";
|
||||
import { computeTimelineColor } from "../../components/chart/timeline-color";
|
||||
import "../../components/entity/state-badge";
|
||||
@@ -464,24 +463,15 @@ class HaLogbookRenderer extends LitElement {
|
||||
entityName: string | undefined,
|
||||
noLink?: boolean
|
||||
) {
|
||||
if (!entityId) {
|
||||
return entityName || "";
|
||||
}
|
||||
|
||||
const stateObj = this.hass.states[entityId];
|
||||
const hasState = Boolean(stateObj);
|
||||
|
||||
const displayName = hasState
|
||||
? this.hass.formatEntityName(stateObj, DEFAULT_ENTITY_NAME) ||
|
||||
entityName ||
|
||||
stateObj.attributes.friendly_name ||
|
||||
entityId
|
||||
: entityName || entityId;
|
||||
|
||||
const hasState = entityId && entityId in this.hass.states;
|
||||
const displayName =
|
||||
entityName ||
|
||||
(hasState
|
||||
? this.hass.states[entityId].attributes.friendly_name || entityId
|
||||
: entityId);
|
||||
if (!hasState) {
|
||||
return displayName;
|
||||
}
|
||||
|
||||
return noLink
|
||||
? displayName
|
||||
: html`<button
|
||||
|
||||
@@ -5412,6 +5412,11 @@
|
||||
"partial_failure": "Some devices failed to delete successfully. Check system logs for more information."
|
||||
}
|
||||
}
|
||||
},
|
||||
"esphome": {
|
||||
"show_encryption_key": "Show encryption key",
|
||||
"encryption_key_title": "ESPHome Encryption Key",
|
||||
"encryption_key_description": "This is the encryption key for your ESPHome device. Keep it in a safe place, as you may need it when transferring devices between Home Assistant instances."
|
||||
}
|
||||
},
|
||||
"entities": {
|
||||
|
||||
Reference in New Issue
Block a user