Compare commits

..
Author SHA1 Message Date
Ludeeus d1605ba196 Add move data disk 2021-09-16 15:15:57 +00:00
21 changed files with 202 additions and 423 deletions
@@ -1,191 +0,0 @@
import "@polymer/paper-dropdown-menu/paper-dropdown-menu";
import "@polymer/paper-item/paper-item";
import "@polymer/paper-listbox/paper-listbox";
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/components/ha-circular-progress";
import "../../../../src/components/ha-markdown";
import {
extractApiErrorMessage,
ignoreSupervisorError,
} from "../../../../src/data/hassio/common";
import {
DatadiskList,
listDatadisks,
moveDatadisk,
} from "../../../../src/data/hassio/host";
import { Supervisor } from "../../../../src/data/supervisor/supervisor";
import { showAlertDialog } from "../../../../src/dialogs/generic/show-dialog-box";
import { haStyle, haStyleDialog } from "../../../../src/resources/styles";
import { HomeAssistant } from "../../../../src/types";
import { HassioDatatiskDialogParams } from "./show-dialog-hassio-datadisk";
const calculateMoveTime = memoizeOne((supervisor: Supervisor): number => {
const speed = supervisor.host.disk_life_time !== "" ? 30 : 10;
const moveTime = (supervisor.host.disk_used * 1000) / 60 / speed;
const rebootTime = (supervisor.host.startup_time * 4) / 60;
return Math.ceil((moveTime + rebootTime) / 10) * 10;
});
@customElement("dialog-hassio-datadisk")
class HassioDatadiskDialog extends LitElement {
@property({ attribute: false }) public hass!: HomeAssistant;
@state() private dialogParams?: HassioDatatiskDialogParams;
@state() private selectedDevice?: string;
@state() private devices?: DatadiskList["devices"];
@state() private moving = false;
public showDialog(params: HassioDatatiskDialogParams) {
this.dialogParams = params;
listDatadisks(this.hass).then((data) => {
this.devices = data.devices;
});
}
public closeDialog(): void {
this.dialogParams = undefined;
this.selectedDevice = undefined;
this.devices = undefined;
this.moving = false;
fireEvent(this, "dialog-closed", { dialog: this.localName });
}
protected render(): TemplateResult {
if (!this.dialogParams) {
return html``;
}
return html`
<ha-dialog
open
scrimClickAction
escapeKeyAction
@closed=${this.closeDialog}
?hideActions=${this.moving}
>
${this.moving
? html`<slot name="heading">
<h2 id="title" class="header_title">
${this.dialogParams.supervisor.localize(
"dialog.datadisk_move.moving"
)}
</h2>
</slot>
<ha-circular-progress alt="Moving" size="large" active>
</ha-circular-progress>
<p class="progress-text">
${this.dialogParams.supervisor.localize(
"dialog.datadisk_move.moving_desc"
)}
</p>`
: html`<slot name="heading">
<h2 id="title" class="header_title">
${this.dialogParams.supervisor.localize(
"dialog.datadisk_move.title"
)}
</h2>
</slot>
${this.devices?.length
? html`
${this.dialogParams.supervisor.localize(
"dialog.datadisk_move.description",
{
current_path: this.dialogParams.supervisor.os.data_disk,
time: calculateMoveTime(this.dialogParams.supervisor),
}
)}
<br /><br />
<paper-dropdown-menu
.label=${this.dialogParams.supervisor.localize(
"dialog.datadisk_move.select_device"
)}
@value-changed=${this._select_device}
>
<paper-listbox slot="dropdown-content">
${this.devices.map(
(device) => html`<paper-item>${device}</paper-item>`
)}
</paper-listbox>
</paper-dropdown-menu>
`
: this.devices === undefined
? this.dialogParams.supervisor.localize(
"dialog.datadisk_move.loading_devices"
)
: this.dialogParams.supervisor.localize(
"dialog.datadisk_move.no_devices"
)}
<mwc-button slot="secondaryAction" @click=${this.closeDialog}>
${this.dialogParams.supervisor.localize(
"dialog.datadisk_move.cancel"
)}
</mwc-button>
<mwc-button
.disabled=${!this.selectedDevice}
slot="primaryAction"
@click=${this._moveDatadisk}
>
${this.dialogParams.supervisor.localize(
"dialog.datadisk_move.move"
)}
</mwc-button>`}
</ha-dialog>
`;
}
private _select_device(event) {
this.selectedDevice = event.detail.value;
}
private async _moveDatadisk() {
this.moving = true;
try {
await moveDatadisk(this.hass, this.selectedDevice!);
} catch (err) {
if (this.hass.connection.connected && !ignoreSupervisorError(err)) {
showAlertDialog(this, {
title: this.dialogParams!.supervisor.localize(
"system.host.failed_to_move"
),
text: extractApiErrorMessage(err),
});
this.closeDialog();
}
}
}
static get styles(): CSSResultGroup {
return [
haStyle,
haStyleDialog,
css`
paper-dropdown-menu {
width: 100%;
}
ha-circular-progress {
display: block;
margin: 32px;
text-align: center;
}
.progress-text {
text-align: center;
}
`,
];
}
}
declare global {
interface HTMLElementTagNameMap {
"dialog-hassio-datadisk": HassioDatadiskDialog;
}
}
@@ -1,17 +0,0 @@
import { fireEvent } from "../../../../src/common/dom/fire_event";
import { Supervisor } from "../../../../src/data/supervisor/supervisor";
export interface HassioDatatiskDialogParams {
supervisor: Supervisor;
}
export const showHassioDatadiskDialog = (
element: HTMLElement,
dialogParams: HassioDatatiskDialogParams
): void => {
fireEvent(element, "show-dialog", {
dialogTag: "dialog-hassio-datadisk",
dialogImport: () => import("./dialog-hassio-datadisk"),
dialogParams,
});
};
+43 -22
View File
@@ -18,6 +18,7 @@ import { fetchHassioHardwareInfo } from "../../../src/data/hassio/hardware";
import {
changeHostOptions,
configSyncOS,
dataDiskMove,
rebootHost,
shutdownHost,
updateOS,
@@ -39,9 +40,8 @@ import {
roundWithOneDecimal,
} from "../../../src/util/calculate";
import "../components/supervisor-metric";
import { showHassioDatadiskDialog } from "../dialogs/datadisk/show-dialog-hassio-datadisk";
import { showHassioHardwareDialog } from "../dialogs/hardware/show-dialog-hassio-hardware";
import { showNetworkDialog } from "../dialogs/network/show-dialog-network";
import { showHassioHardwareDialog } from "../dialogs/hardware/show-dialog-hassio-hardware";
import { hassioStyle } from "../resources/hassio-style";
@customElement("hassio-host-info")
@@ -189,18 +189,17 @@ class HassioHostInfo extends LitElement {
</mwc-list-item>
${this.supervisor.host.features.includes("haos")
? html`<mwc-list-item
@click=${() => this._handleMenuAction("import_from_usb")}
>
${this.supervisor.localize("system.host.import_from_usb")}
</mwc-list-item>
${this.supervisor.host.features.includes("os_agent") &&
atLeastVersion(this.supervisor.host.agent_version, 1, 2, 0)
? html`<mwc-list-item
@click=${() => this._handleMenuAction("move_datadisk")}
>
${this.supervisor.localize("system.host.move_datadisk")}
</mwc-list-item>`
: ""} `
@click=${() => this._handleMenuAction("import_from_usb")}
>
${this.supervisor.localize("system.host.import_from_usb")}
</mwc-list-item>`
: ""}
${this.supervisor.host.features.includes("agent")
? html`<mwc-list-item
@click=${() => this._handleMenuAction("data_disk_move")}
>
${this.supervisor.localize("system.host.data_disk_move")}
</mwc-list-item>`
: ""}
</ha-button-menu>
</div>
@@ -231,18 +230,12 @@ class HassioHostInfo extends LitElement {
case "import_from_usb":
await this._importFromUSB();
break;
case "move_datadisk":
await this._moveDatadisk();
case "data_disk_move":
await this._dataDiskMove();
break;
}
}
private _moveDatadisk(): void {
showHassioDatadiskDialog(this, {
supervisor: this.supervisor,
});
}
private async _showHardware(): Promise<void> {
let hardware;
try {
@@ -411,6 +404,34 @@ class HassioHostInfo extends LitElement {
}
}
private async _dataDiskMove(): Promise<void> {
const confirmed = await showConfirmationDialog(this, {
title: this.supervisor.localize("system.host.data_disk_move"),
text: html`${this.supervisor.localize(
"dialog.data_disk_move.description",
{ current_path: this.supervisor.os.data_disk }
)} <br /><br />${this.supervisor.localize(
"dialog.data_disk_move.confirm_text"
)}`,
confirmText: this.supervisor.localize("dialog.data_disk_move.move"),
dismissText: this.supervisor.localize("dialog.data_disk_move.cancel"),
});
if (!confirmed) {
return;
}
try {
await dataDiskMove(this.hass);
} catch (err) {
if (this.hass.connection.connected && !ignoreSupervisorError(err)) {
showAlertDialog(this, {
title: this.supervisor.localize("system.host.failed_to_move"),
text: extractApiErrorMessage(err),
});
}
}
}
private async _loadData(): Promise<void> {
if (atLeastVersion(this.hass.config.version, 2021, 2, 4)) {
fireEvent(this, "supervisor-collection-refresh", {
+1 -1
View File
@@ -2,7 +2,7 @@ from setuptools import setup, find_packages
setup(
name="home-assistant-frontend",
version="20210922.0",
version="20210911.0",
description="The Home Assistant frontend",
url="https://github.com/home-assistant/frontend",
author="The Home Assistant Authors",
-24
View File
@@ -1,24 +0,0 @@
/** Return an icon representing a alarm panel state. */
export const alarmPanelIcon = (state?: string) => {
switch (state) {
case "armed_away":
return "hass:shield-lock";
case "armed_vacation":
return "hass:shield-airplane";
case "armed_home":
return "hass:shield-home";
case "armed_night":
return "hass:shield-moon";
case "armed_custom_bypass":
return "hass:security";
case "pending":
return "hass:shield-outline";
case "triggered":
return "hass:bell-ring";
case "disarmed":
return "hass:shield-off";
default:
return "hass:shield";
}
};
+12 -2
View File
@@ -5,7 +5,6 @@ import { HassEntity } from "home-assistant-js-websocket";
* Optionally pass in a state to influence the domain icon.
*/
import { DEFAULT_DOMAIN_ICON, FIXED_DOMAIN_ICONS } from "../const";
import { alarmPanelIcon } from "./alarm_panel_icon";
import { binarySensorIcon } from "./binary_sensor_icon";
import { coverIcon } from "./cover_icon";
import { sensorIcon } from "./sensor_icon";
@@ -19,7 +18,18 @@ export const domainIcon = (
switch (domain) {
case "alarm_control_panel":
return alarmPanelIcon(compareState);
switch (compareState) {
case "armed_home":
return "hass:bell-plus";
case "armed_night":
return "hass:bell-sleep";
case "disarmed":
return "hass:bell-outline";
case "triggered":
return "hass:bell-ring";
default:
return "hass:bell";
}
case "binary_sensor":
return binarySensorIcon(compareState, stateObj);
+1 -1
View File
@@ -15,7 +15,7 @@ const haTabFixBehaviorImpl = {
},
};
// paper-dialog that uses the haTabFixBehaviorImpl behavior
// paper-dialog that uses the haTabFixBehaviorImpl behvaior
// export class HaPaperDialog extends paperDialogClass {}
// @ts-ignore
export class HaPaperDialog
@@ -13,6 +13,7 @@ import secondsToDuration from "../../common/datetime/seconds_to_duration";
import { computeStateDisplay } from "../../common/entity/compute_state_display";
import { computeStateDomain } from "../../common/entity/compute_state_domain";
import { computeStateName } from "../../common/entity/compute_state_name";
import { domainIcon } from "../../common/entity/domain_icon";
import { stateIcon } from "../../common/entity/state_icon";
import { timerTimeRemaining } from "../../data/timer";
import { formatNumber } from "../../common/string/format_number";
@@ -140,6 +141,26 @@ export class HaStateLabelBadge extends LitElement {
}
switch (domain) {
case "alarm_control_panel":
if (entityState.state === "pending") {
return "hass:clock-fast";
}
if (entityState.state === "armed_away") {
return "hass:nature";
}
if (entityState.state === "armed_home") {
return "hass:home-variant";
}
if (entityState.state === "armed_night") {
return "hass:weather-night";
}
if (entityState.state === "armed_custom_bypass") {
return "hass:shield-home";
}
if (entityState.state === "triggered") {
return "hass:alert-circle";
}
// state == 'disarmed'
return domainIcon(domain, entityState);
case "binary_sensor":
case "device_tracker":
case "updater":
@@ -82,7 +82,7 @@ export class HaTracePathDetails extends LitElement {
] as ChooseActionTraceStep[];
if (parentTraceInfo && parentTraceInfo[0]?.result?.choice === "default") {
return "The default action was executed because no options matched.";
return "The default node was executed because no choices matched.";
}
}
+3 -5
View File
@@ -325,15 +325,13 @@ class ActionRenderer {
if (defaultExecuted) {
this._renderEntry(choosePath, `${name}: Default action executed`);
} else if (chooseTrace.result) {
const choiceNumeric =
chooseTrace.result.choice !== "default"
? chooseTrace.result.choice + 1
: undefined;
const choiceConfig = this._getDataFromPath(
`${this.keys[index]}/choose/${chooseTrace.result.choice}`
) as ChooseActionChoice | undefined;
const choiceName = choiceConfig
? `${choiceConfig.alias || `Option ${choiceNumeric}`} executed`
? `${
choiceConfig.alias || `Choice ${chooseTrace.result.choice}`
} executed`
: `Error: ${chooseTrace.error}`;
this._renderEntry(choosePath, `${name}: ${choiceName}`);
} else {
+13 -38
View File
@@ -3,7 +3,6 @@ import { HomeAssistant } from "../../types";
import { hassioApiResultExtractor, HassioResponse } from "./common";
export type HassioHostInfo = {
agent_version: string;
chassis: string;
cpe: string;
deployment: string;
@@ -15,8 +14,6 @@ export type HassioHostInfo = {
hostname: string;
kernel: string;
operating_system: string;
boot_timestamp: number;
startup_time: number;
};
export interface HassioHassOSInfo {
@@ -28,10 +25,6 @@ export interface HassioHassOSInfo {
data_disk: string;
}
export interface DatadiskList {
devices: string[];
}
export const fetchHassioHostInfo = async (
hass: HomeAssistant
): Promise<HassioHostInfo> => {
@@ -121,6 +114,19 @@ export const configSyncOS = async (hass: HomeAssistant) => {
return hass.callApi<HassioResponse<void>>("POST", "hassio/os/config/sync");
};
export const dataDiskMove = async (hass: HomeAssistant) => {
if (atLeastVersion(hass.config.version, 2021, 2, 4)) {
return hass.callWS({
type: "supervisor/api",
endpoint: "/os/datadisk/move",
method: "post",
timeout: null,
});
}
return hass.callApi<HassioResponse<void>>("POST", "hassio/os/datadisk/move");
};
export const changeHostOptions = async (hass: HomeAssistant, options: any) => {
if (atLeastVersion(hass.config.version, 2021, 2, 4)) {
return hass.callWS({
@@ -137,34 +143,3 @@ export const changeHostOptions = async (hass: HomeAssistant, options: any) => {
options
);
};
export const moveDatadisk = async (hass: HomeAssistant, device: string) => {
if (atLeastVersion(hass.config.version, 2021, 2, 4)) {
return hass.callWS({
type: "supervisor/api",
endpoint: "/os/datadisk/move",
method: "post",
timeout: null,
data: { device },
});
}
return hass.callApi<HassioResponse<void>>("POST", "hassio/os/datadisk/move");
};
export const listDatadisks = async (
hass: HomeAssistant
): Promise<DatadiskList> => {
if (atLeastVersion(hass.config.version, 2021, 2, 4)) {
return hass.callWS<DatadiskList>({
type: "supervisor/api",
endpoint: "/os/datadisk/list",
method: "get",
timeout: null,
});
}
return hassioApiResultExtractor(
await hass.callApi<HassioResponse<DatadiskList>>("GET", "/os/datadisk/list")
);
};
@@ -279,14 +279,9 @@ export class HaConfigLovelaceDashboards extends LitElement {
removeDashboard: async () => {
if (
!(await showConfirmationDialog(this, {
title: this.hass!.localize(
"ui.panel.config.lovelace.dashboards.confirm_delete_title",
{ dashboard_title: dashboard!.title }
),
text: this.hass!.localize(
"ui.panel.config.lovelace.dashboards.confirm_delete_text"
"ui.panel.config.lovelace.dashboards.confirm_delete"
),
confirmText: this.hass!.localize("ui.common.delete"),
}))
) {
return false;
@@ -129,9 +129,9 @@ class HuiEnergyCarbonGaugeCard
<ha-svg-icon id="info" .path=${mdiInformation}></ha-svg-icon>
<paper-tooltip animation-delay="0" for="info" position="left">
<span>
This card indicates how much of the energy consumed by your
This card represents how much of the energy consumed by your
home was generated using non-fossil fuels like solar, wind and
nuclear. The higher, the better!
nuclear.
</span>
</paper-tooltip>
<ha-gauge
@@ -77,11 +77,11 @@ class HuiEnergySolarGaugeCard
let value: number | undefined;
if (productionReturnedToGrid !== null && totalSolarProduction) {
const consumedSolar = Math.max(
const cosumedSolar = Math.max(
0,
totalSolarProduction - productionReturnedToGrid
);
value = (consumedSolar / totalSolarProduction) * 100;
value = (cosumedSolar / totalSolarProduction) * 100;
}
return html`
@@ -91,13 +91,12 @@ class HuiEnergySolarGaugeCard
<ha-svg-icon id="info" .path=${mdiInformation}></ha-svg-icon>
<paper-tooltip animation-delay="0" for="info" position="left">
<span>
This card indicates how much of the solar energy you produced
was used by your home instead of being returned to the grid.
This card represents how much of the solar energy was used by
your home and was not returned to the grid.
<br /><br />
If this number is typically very low, indicating excess solar
production, you might want to consider charging a home battery
or electric car from your solar panels at times of high solar
production.
If you frequently produce more than you consume, try to
conserve this energy by installing a battery or buying an
electric car to charge.
</span>
</paper-tooltip>
<ha-gauge
@@ -110,11 +109,11 @@ class HuiEnergySolarGaugeCard
"--gauge-color": this._computeSeverity(value),
})}
></ha-gauge>
<div class="name">Self-consumed solar energy</div>
<div class="name">Self consumed solar energy</div>
`
: totalSolarProduction === 0
? "You have not produced any solar energy"
: "Self-consumed solar energy couldn't be calculated"}
: "Self consumed solar energy couldn't be calculated"}
</ha-card>
`;
}
@@ -12,7 +12,6 @@ import { customElement, property, state, query } from "lit/decorators";
import { classMap } from "lit/directives/class-map";
import { applyThemesOnElement } from "../../../common/dom/apply_themes_on_element";
import { fireEvent } from "../../../common/dom/fire_event";
import { alarmPanelIcon } from "../../../common/entity/alarm_panel_icon";
import "../../../components/ha-card";
import "../../../components/ha-label-badge";
import {
@@ -25,6 +24,17 @@ import { createEntityNotFoundWarning } from "../components/hui-warning";
import type { LovelaceCard } from "../types";
import { AlarmPanelCardConfig } from "./types";
const ICONS = {
armed_away: "hass:shield-lock",
armed_custom_bypass: "hass:security",
armed_home: "hass:shield-home",
armed_night: "hass:shield-moon",
armed_vacation: "hass:shield-lock",
disarmed: "hass:shield-check",
pending: "hass:shield-outline",
triggered: "hass:bell-ring",
};
const BUTTONS = ["1", "2", "3", "4", "5", "6", "7", "8", "9", "", "0", "clear"];
@customElement("hui-alarm-panel-card")
@@ -152,7 +162,7 @@ class HuiAlarmPanelCard extends LitElement implements LovelaceCard {
>
<ha-label-badge
class="${classMap({ [stateObj.state]: true })}"
.icon="${alarmPanelIcon(stateObj.state)}"
.icon="${ICONS[stateObj.state] || "hass:shield-outline"}"
.label="${this._stateIconLabel(stateObj.state)}"
@click=${this._handleMoreInfo}
></ha-label-badge>
@@ -55,7 +55,6 @@ export class HuiCreateDialogCard
public closeDialog(): boolean {
this._params = undefined;
this._currTabIndex = 0;
this._selectedEntities = [];
fireEvent(this, "dialog-closed", { dialog: this.localName });
return true;
}
@@ -1,9 +1,10 @@
import "@polymer/paper-dialog-scrollable/paper-dialog-scrollable";
import deepFreeze from "deep-freeze";
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
import { customElement, property, state } from "lit/decorators";
import { customElement, property, state, query } from "lit/decorators";
import { fireEvent } from "../../../../common/dom/fire_event";
import "../../../../components/dialog/ha-paper-dialog";
import type { HaPaperDialog } from "../../../../components/dialog/ha-paper-dialog";
import type { LovelaceCardConfig } from "../../../../data/lovelace";
import { haStyleDialog } from "../../../../resources/styles";
import type { HomeAssistant } from "../../../../types";
@@ -18,18 +19,16 @@ export class HuiDialogDeleteCard extends LitElement {
@state() private _cardConfig?: LovelaceCardConfig;
@query("ha-paper-dialog", true) private _dialog!: HaPaperDialog;
public async showDialog(params: DeleteCardDialogParams): Promise<void> {
this._params = params;
this._cardConfig = params.cardConfig;
if (!Object.isFrozen(this._cardConfig)) {
this._cardConfig = deepFreeze(this._cardConfig);
}
}
public closeDialog(): void {
this._params = undefined;
this._cardConfig = undefined;
fireEvent(this, "dialog-closed", { dialog: this.localName });
await this.updateComplete;
fireEvent(this._dialog as HTMLElement, "iron-resize");
}
protected render(): TemplateResult {
@@ -38,12 +37,9 @@ export class HuiDialogDeleteCard extends LitElement {
}
return html`
<ha-dialog
open
@closed=${this.closeDialog}
.heading=${this.hass.localize("ui.panel.lovelace.cards.confirm_delete")}
>
<div>
<ha-paper-dialog with-backdrop opened modal>
<h2>${this.hass.localize("ui.panel.lovelace.cards.confirm_delete")}</h2>
<paper-dialog-scrollable>
${this._cardConfig
? html`
<div class="element-preview">
@@ -54,18 +50,16 @@ export class HuiDialogDeleteCard extends LitElement {
</div>
`
: ""}
</paper-dialog-scrollable>
<div class="paper-dialog-buttons">
<mwc-button @click="${this._close}">
${this.hass!.localize("ui.common.cancel")}
</mwc-button>
<mwc-button class="warning" @click="${this._delete}">
${this.hass!.localize("ui.common.delete")}
</mwc-button>
</div>
<mwc-button slot="secondaryAction" @click="${this.closeDialog}">
${this.hass!.localize("ui.common.cancel")}
</mwc-button>
<mwc-button
slot="primaryAction"
class="warning"
@click="${this._delete}"
>
${this.hass!.localize("ui.common.delete")}
</mwc-button>
</ha-dialog>
</ha-paper-dialog>
`;
}
@@ -86,12 +80,17 @@ export class HuiDialogDeleteCard extends LitElement {
];
}
private _close(): void {
this._params = undefined;
this._cardConfig = undefined;
}
private _delete(): void {
if (!this._params?.deleteCard) {
return;
}
this._params.deleteCard();
this.closeDialog();
this._close();
}
}
@@ -1,8 +1,7 @@
import "@polymer/paper-dialog-scrollable/paper-dialog-scrollable";
import deepFreeze from "deep-freeze";
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
import { customElement, property, query, state } from "lit/decorators";
import { fireEvent } from "../../../../common/dom/fire_event";
import { customElement, property, state, query } from "lit/decorators";
import "../../../../components/dialog/ha-paper-dialog";
import "../../../../components/ha-yaml-editor";
import type { HaYamlEditor } from "../../../../components/ha-yaml-editor";
@@ -48,26 +47,16 @@ export class HuiDialogSuggestCard extends LitElement {
}
}
public closeDialog(): void {
this._params = undefined;
this._cardConfig = undefined;
fireEvent(this, "dialog-closed", { dialog: this.localName });
}
protected render(): TemplateResult {
if (!this._params) {
return html``;
}
return html`
<ha-dialog
open
scrimClickAction
@closed=${this.closeDialog}
.heading=${this.hass!.localize(
"ui.panel.lovelace.editor.suggest_card.header"
)}
>
<div>
<ha-paper-dialog with-backdrop opened>
<h2>
${this.hass!.localize("ui.panel.lovelace.editor.suggest_card.header")}
</h2>
<paper-dialog-scrollable>
${this._cardConfig
? html`
<div class="element-preview">
@@ -91,39 +80,37 @@ export class HuiDialogSuggestCard extends LitElement {
</div>
`
: ""}
</paper-dialog-scrollable>
<div class="paper-dialog-buttons">
<mwc-button @click="${this._close}">
${this._params.yaml
? this.hass!.localize("ui.common.close")
: this.hass!.localize("ui.common.cancel")}
</mwc-button>
${!this._params.yaml
? html`
<mwc-button @click="${this._pickCard}"
>${this.hass!.localize(
"ui.panel.lovelace.editor.suggest_card.create_own"
)}</mwc-button
>
<mwc-button ?disabled="${this._saving}" @click="${this._save}">
${this._saving
? html`
<ha-circular-progress
active
title="Saving"
size="small"
></ha-circular-progress>
`
: this.hass!.localize(
"ui.panel.lovelace.editor.suggest_card.add"
)}
</mwc-button>
`
: ""}
</div>
<mwc-button slot="secondaryAction" @click="${this.closeDialog}">
${this._params.yaml
? this.hass!.localize("ui.common.close")
: this.hass!.localize("ui.common.cancel")}
</mwc-button>
${!this._params.yaml
? html`
<mwc-button slot="primaryAction" @click="${this._pickCard}"
>${this.hass!.localize(
"ui.panel.lovelace.editor.suggest_card.create_own"
)}</mwc-button
>
<mwc-button
slot="primaryAction"
.disabled="${this._saving}"
@click="${this._save}"
>
${this._saving
? html`
<ha-circular-progress
active
title="Saving"
size="small"
></ha-circular-progress>
`
: this.hass!.localize(
"ui.panel.lovelace.editor.suggest_card.add"
)}
</mwc-button>
`
: ""}
</ha-dialog>
</ha-paper-dialog>
`;
}
@@ -133,17 +120,17 @@ export class HuiDialogSuggestCard extends LitElement {
css`
@media all and (max-width: 450px), all and (max-height: 500px) {
/* overrule the ha-style-dialog max-height on small screens */
ha-dialog {
ha-paper-dialog {
max-height: 100%;
height: 100%;
}
}
@media all and (min-width: 850px) {
ha-dialog {
ha-paper-dialog {
width: 845px;
}
}
ha-dialog {
ha-paper-dialog {
max-width: 845px;
--dialog-z-index: 5;
}
@@ -167,6 +154,11 @@ export class HuiDialogSuggestCard extends LitElement {
];
}
private _close(): void {
this._params = undefined;
this._cardConfig = undefined;
}
private _pickCard(): void {
if (
!this._params?.lovelaceConfig ||
@@ -182,7 +174,7 @@ export class HuiDialogSuggestCard extends LitElement {
path: this._params!.path,
entities: this._params!.entities,
});
this.closeDialog();
this._close();
}
private async _save(): Promise<void> {
@@ -204,7 +196,7 @@ export class HuiDialogSuggestCard extends LitElement {
);
this._saving = false;
showSaveSuccessToast(this, this.hass);
this.closeDialog();
this._close();
}
}
@@ -68,7 +68,9 @@ export class HuiEntityPickerTable extends LitElement {
<div @click=${this._handleEntityClicked} style="cursor: pointer;">
${name}
${narrow
? html` <div class="secondary">${entity.entity_id}</div> `
? html`
<div class="secondary">${entity.stateObj.entity_id}</div>
`
: ""}
</div>
`,
@@ -89,9 +89,9 @@ export class HuiUnusedEntities extends LitElement {
icon: "",
entity_id: entity,
stateObj,
name: stateObj ? computeStateName(stateObj) : "Unavailable",
name: computeStateName(stateObj),
domain: computeDomain(entity),
last_changed: stateObj?.last_changed,
last_changed: stateObj!.last_changed,
};
}) as DataTableRowData[]}
@selected-changed=${this._handleSelectedChanged}
+8 -18
View File
@@ -1117,13 +1117,9 @@
"title": "Unexpected unit of measurement",
"description": "The following entities do not have the expected units of measurement ''{currency}/kWh'' or ''{currency}/Wh'':"
},
"entity_unexpected_state_class": {
"entity_unexpected_state_class_total_increasing": {
"title": "Unexpected state class",
"description": "The following entities do not have the expected state class:"
},
"entity_state_class_measurement_no_last_reset": {
"title": "Last reset missing",
"description": "The following entities have state class 'measurement' but 'last_reset' is missing:"
"description": "The following entities do not have the expected state class 'total_increasing'"
}
}
}
@@ -1254,8 +1250,7 @@
"open": "Open",
"add_dashboard": "Add dashboard"
},
"confirm_delete_title": "Delete {dashboard_title}?",
"confirm_delete_text": "Your dashboard will be permanently deleted.",
"confirm_delete": "Are you sure you want to delete this dashboard?",
"cant_edit_yaml": "Dashboards defined in YAML cannot be edited from the UI. Change them in configuration.yaml.",
"cant_edit_default": "The standard Lovelace dashboard cannot be edited from the UI. You can hide it by setting another dashboard as default.",
"detail": {
@@ -4104,7 +4099,7 @@
"failed_to_shutdown": "Failed to shutdown the host",
"failed_to_set_hostname": "Setting hostname failed",
"failed_to_import_from_usb": "Failed to import from USB",
"failed_to_move": "Failed to move datadisk",
"failed_to_move": "Failed to move data disk",
"used_space": "Used space",
"hostname": "Hostname",
"change_hostname": "Change Hostname",
@@ -4121,7 +4116,7 @@
"shutdown_host": "Shutdown host",
"hardware": "Hardware",
"import_from_usb": "Import from USB",
"move_datadisk": "Move datadisk"
"data_disk_move": "Move to data disk"
},
"core": {
"cpu_usage": "Core CPU Usage",
@@ -4209,14 +4204,9 @@
"attributes": "Attributes",
"device_path": "Device path"
},
"datadisk_move": {
"title": "[%key:supervisor::system::host::move_datadisk%]",
"description": "You are currently using ''{current_path}'' as datadisk. Moving data disks will reboot your device and it's estimated to take {time} minutes. Your Home Assistant installation will not be accessible during this period. Do not disconnect the power during the move!",
"select_device": "Select new datadisk",
"no_devices": "No suitable attached devices found",
"moving_desc": "Rebooting and moving datadisk. Please have patience",
"moving": "Moving datadisk",
"loading_devices": "Loading devices",
"data_disk_move": {
"description": "The current path to the data disk is ''{current_path}'', moving the disk will require a reboot of the host which will be done automatically.",
"confirm_text": "Do you want to move now?",
"cancel": "[%key:ui::common::cancel%]",
"move": "Move"
}