mirror of
https://github.com/home-assistant/frontend.git
synced 2025-08-11 10:19:25 +00:00
Compare commits
37 Commits
Move-parti
...
20211229.0
Author | SHA1 | Date | |
---|---|---|---|
![]() |
0ab8f8fd7c | ||
![]() |
86b9eb0bd7 | ||
![]() |
011cbe7d22 | ||
![]() |
9b0b2c5b71 | ||
![]() |
be72bf7b3c | ||
![]() |
3e062ba673 | ||
![]() |
322d965539 | ||
![]() |
7b840527b5 | ||
![]() |
dced053ba2 | ||
![]() |
fe4322e64b | ||
![]() |
0800c702fb | ||
![]() |
b6d6e2fd4b | ||
![]() |
2bbb1bfa7e | ||
![]() |
e2af8ac3cc | ||
![]() |
25ff5fef14 | ||
![]() |
2f9c088091 | ||
![]() |
50c397901b | ||
![]() |
1f7d4c25d4 | ||
![]() |
29819fac23 | ||
![]() |
cc301df57d | ||
![]() |
7d5b566312 | ||
![]() |
07cd68f5d0 | ||
![]() |
99bf6fa781 | ||
![]() |
bfad1eb5ac | ||
![]() |
b7bd7c1065 | ||
![]() |
61bae5da64 | ||
![]() |
bdd13db8cf | ||
![]() |
cdc3d11181 | ||
![]() |
8f729e2a95 | ||
![]() |
bc9195f7d5 | ||
![]() |
7f1a321075 | ||
![]() |
72b9f8636d | ||
![]() |
c9cd316c0c | ||
![]() |
6cf3580fb4 | ||
![]() |
5d91aefb55 | ||
![]() |
e3c0530941 | ||
![]() |
2c9223ed80 |
@@ -133,6 +133,7 @@ class HassioAddonInfo extends LitElement {
|
||||
.narrow=${this.narrow}
|
||||
.supervisor=${this.supervisor}
|
||||
.addonSlug=${this.addon.slug}
|
||||
@update-complete=${this._updateComplete}
|
||||
></update-available-card>
|
||||
`
|
||||
: ""}
|
||||
@@ -865,6 +866,15 @@ class HassioAddonInfo extends LitElement {
|
||||
}
|
||||
}
|
||||
|
||||
private _updateComplete() {
|
||||
const eventdata = {
|
||||
success: true,
|
||||
response: undefined,
|
||||
path: "install",
|
||||
};
|
||||
fireEvent(this, "hass-api-called", eventdata);
|
||||
}
|
||||
|
||||
private async _installClicked(ev: CustomEvent): Promise<void> {
|
||||
const button = ev.currentTarget as any;
|
||||
button.progress = true;
|
||||
|
@@ -350,9 +350,7 @@ export class SupervisorBackupContent extends LitElement {
|
||||
if (folders?.length) {
|
||||
data.folders = folders;
|
||||
}
|
||||
if (this.homeAssistant) {
|
||||
data.homeassistant = this.homeAssistant;
|
||||
}
|
||||
data.homeassistant = this.homeAssistant;
|
||||
|
||||
return data;
|
||||
}
|
||||
|
@@ -1,5 +1,6 @@
|
||||
import "@polymer/paper-tooltip/paper-tooltip";
|
||||
import "@material/mwc-button/mwc-button";
|
||||
import { mdiDelete } from "@mdi/js";
|
||||
import { mdiDelete, mdiDeleteOff } from "@mdi/js";
|
||||
import "@polymer/paper-input/paper-input";
|
||||
import type { PaperInputElement } from "@polymer/paper-input/paper-input";
|
||||
import "@polymer/paper-item/paper-item";
|
||||
@@ -15,6 +16,7 @@ import { createCloseHeading } from "../../../../src/components/ha-dialog";
|
||||
import "../../../../src/components/ha-icon-button";
|
||||
import {
|
||||
fetchHassioAddonsInfo,
|
||||
HassioAddonInfo,
|
||||
HassioAddonRepository,
|
||||
} from "../../../../src/data/hassio/addon";
|
||||
import { extractApiErrorMessage } from "../../../../src/data/hassio/common";
|
||||
@@ -60,11 +62,24 @@ class HassioRepositoriesDialog extends LitElement {
|
||||
.sort((a, b) => caseInsensitiveStringCompare(a.name, b.name))
|
||||
);
|
||||
|
||||
private _filteredUsedRepositories = memoizeOne(
|
||||
(repos: HassioAddonRepository[], addons: HassioAddonInfo[]) =>
|
||||
repos
|
||||
.filter((repo) =>
|
||||
addons.some((addon) => addon.repository === repo.slug)
|
||||
)
|
||||
.map((repo) => repo.slug)
|
||||
);
|
||||
|
||||
protected render(): TemplateResult {
|
||||
if (!this._dialogParams?.supervisor || this._repositories === undefined) {
|
||||
return html``;
|
||||
}
|
||||
const repositories = this._filteredRepositories(this._repositories);
|
||||
const usedRepositories = this._filteredUsedRepositories(
|
||||
repositories,
|
||||
this._dialogParams.supervisor.supervisor.addons
|
||||
);
|
||||
return html`
|
||||
<ha-dialog
|
||||
.open=${this._opened}
|
||||
@@ -89,18 +104,32 @@ class HassioRepositoriesDialog extends LitElement {
|
||||
<div secondary>${repo.maintainer}</div>
|
||||
<div secondary>${repo.url}</div>
|
||||
</paper-item-body>
|
||||
<ha-icon-button
|
||||
.slug=${repo.slug}
|
||||
.label=${this._dialogParams!.supervisor.localize(
|
||||
"dialog.repositories.remove"
|
||||
)}
|
||||
.path=${mdiDelete}
|
||||
@click=${this._removeRepository}
|
||||
></ha-icon-button>
|
||||
<div class="delete">
|
||||
<ha-icon-button
|
||||
.disabled=${usedRepositories.includes(repo.slug)}
|
||||
.slug=${repo.slug}
|
||||
.path=${usedRepositories.includes(repo.slug)
|
||||
? mdiDeleteOff
|
||||
: mdiDelete}
|
||||
@click=${this._removeRepository}
|
||||
>
|
||||
</ha-icon-button>
|
||||
<paper-tooltip
|
||||
animation-delay="0"
|
||||
position="bottom"
|
||||
offset="1"
|
||||
>
|
||||
${this._dialogParams!.supervisor.localize(
|
||||
usedRepositories.includes(repo.slug)
|
||||
? "dialog.repositories.used"
|
||||
: "dialog.repositories.remove"
|
||||
)}
|
||||
</paper-tooltip>
|
||||
</div>
|
||||
</paper-item>
|
||||
`
|
||||
)
|
||||
: html` <paper-item> No repositories </paper-item> `}
|
||||
: html`<paper-item> No repositories </paper-item>`}
|
||||
<div class="layout horizontal bottom">
|
||||
<paper-input
|
||||
class="flex-auto"
|
||||
@@ -157,6 +186,9 @@ class HassioRepositoriesDialog extends LitElement {
|
||||
margin: 32px;
|
||||
text-align: center;
|
||||
}
|
||||
div.delete ha-icon-button {
|
||||
color: var(--error-color);
|
||||
}
|
||||
`,
|
||||
];
|
||||
}
|
||||
|
@@ -29,6 +29,10 @@ import {
|
||||
HassioAddonDetails,
|
||||
updateHassioAddon,
|
||||
} from "../../../src/data/hassio/addon";
|
||||
import {
|
||||
createHassioPartialBackup,
|
||||
HassioPartialBackupCreateParams,
|
||||
} from "../../../src/data/hassio/backup";
|
||||
import {
|
||||
extractApiErrorMessage,
|
||||
ignoreSupervisorError,
|
||||
@@ -99,7 +103,7 @@ class UpdateAvailableCard extends LitElement {
|
||||
|
||||
@state() private _addonInfo?: HassioAddonDetails;
|
||||
|
||||
@state() private _updating = false;
|
||||
@state() private _action: "backup" | "update" | null = null;
|
||||
|
||||
@state() private _error?: string;
|
||||
|
||||
@@ -134,7 +138,7 @@ class UpdateAvailableCard extends LitElement {
|
||||
name: this._name,
|
||||
})}
|
||||
</p>`
|
||||
: !this._updating
|
||||
: this._action === null
|
||||
? html`
|
||||
${this._changelogContent
|
||||
? html`
|
||||
@@ -168,13 +172,18 @@ class UpdateAvailableCard extends LitElement {
|
||||
: html`<ha-circular-progress alt="Updating" size="large" active>
|
||||
</ha-circular-progress>
|
||||
<p class="progress-text">
|
||||
${this.supervisor.localize("update_available.updating", {
|
||||
name: this._name,
|
||||
version: this._version_latest,
|
||||
})}
|
||||
${this._action === "update"
|
||||
? this.supervisor.localize("update_available.updating", {
|
||||
name: this._name,
|
||||
version: this._version_latest,
|
||||
})
|
||||
: this.supervisor.localize(
|
||||
"update_available.creating_backup",
|
||||
{ name: this._name }
|
||||
)}
|
||||
</p>`}
|
||||
</div>
|
||||
${this._version !== this._version_latest && !this._updating
|
||||
${this._version !== this._version_latest && this._action === null
|
||||
? html`
|
||||
<div class="card-actions">
|
||||
${changelog
|
||||
@@ -310,16 +319,37 @@ class UpdateAvailableCard extends LitElement {
|
||||
|
||||
private async _update() {
|
||||
this._error = undefined;
|
||||
this._updating = true;
|
||||
if (this._shouldCreateBackup) {
|
||||
let backupArgs: HassioPartialBackupCreateParams;
|
||||
if (this._updateType === "addon") {
|
||||
backupArgs = {
|
||||
name: `addon_${this.addonSlug}_${this._version}`,
|
||||
addons: [this.addonSlug!],
|
||||
homeassistant: false,
|
||||
};
|
||||
} else {
|
||||
backupArgs = {
|
||||
name: `${this._updateType}_${this._version}`,
|
||||
folders: ["homeassistant"],
|
||||
homeassistant: true,
|
||||
};
|
||||
}
|
||||
this._action = "backup";
|
||||
try {
|
||||
await createHassioPartialBackup(this.hass, backupArgs);
|
||||
} catch (err: any) {
|
||||
this._error = extractApiErrorMessage(err);
|
||||
this._action = null;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
this._action = "update";
|
||||
try {
|
||||
if (this._updateType === "addon") {
|
||||
await updateHassioAddon(
|
||||
this.hass,
|
||||
this.addonSlug!,
|
||||
this._shouldCreateBackup
|
||||
);
|
||||
await updateHassioAddon(this.hass, this.addonSlug!);
|
||||
} else if (this._updateType === "core") {
|
||||
await updateCore(this.hass, this._shouldCreateBackup);
|
||||
await updateCore(this.hass);
|
||||
} else if (this._updateType === "os") {
|
||||
await updateOS(this.hass);
|
||||
} else if (this._updateType === "supervisor") {
|
||||
@@ -328,7 +358,7 @@ class UpdateAvailableCard extends LitElement {
|
||||
} catch (err: any) {
|
||||
if (this.hass.connection.connected && !ignoreSupervisorError(err)) {
|
||||
this._error = extractApiErrorMessage(err);
|
||||
this._updating = false;
|
||||
this._action = null;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@@ -46,6 +46,7 @@ class UpdateAvailableDashboard extends LitElement {
|
||||
update-available-card {
|
||||
margin: auto;
|
||||
margin-top: 16px;
|
||||
margin-bottom: 24px;
|
||||
max-width: 600px;
|
||||
}
|
||||
`;
|
||||
|
@@ -102,7 +102,7 @@
|
||||
"fuse.js": "^6.0.0",
|
||||
"google-timezones-json": "^1.0.2",
|
||||
"hls.js": "^1.0.11",
|
||||
"home-assistant-js-websocket": "^5.11.3",
|
||||
"home-assistant-js-websocket": "^6.0.1",
|
||||
"idb-keyval": "^5.1.3",
|
||||
"intl-messageformat": "^9.9.1",
|
||||
"js-yaml": "^4.1.0",
|
||||
|
2
setup.py
2
setup.py
@@ -2,7 +2,7 @@ from setuptools import setup, find_packages
|
||||
|
||||
setup(
|
||||
name="home-assistant-frontend",
|
||||
version="20211215.0",
|
||||
version="20211229.0",
|
||||
description="The Home Assistant frontend",
|
||||
url="https://github.com/home-assistant/frontend",
|
||||
author="The Home Assistant Authors",
|
||||
|
@@ -199,13 +199,16 @@ export const DOMAINS_HIDE_DEFAULT_MORE_INFO = [
|
||||
"select",
|
||||
];
|
||||
|
||||
/** Domains that render an input element instead of a text value when rendered in a row.
|
||||
/** Domains that render an input element instead of a text value when displayed in a row.
|
||||
* Those rows should then not show a cursor pointer when hovered (which would normally
|
||||
* be the default) unless the element itself enforces it (e.g. a button). Also those elements
|
||||
* should not act as a click target to open the more info dialog (the row name and state icon
|
||||
* still do of course) as the click might instead e.g. activate the input field that this row shows.
|
||||
* still do of course) as the click should instead e.g. activate the input field or toggle
|
||||
* the button that this row shows.
|
||||
*/
|
||||
export const DOMAINS_INPUT_ROW = [
|
||||
"automation",
|
||||
"button",
|
||||
"cover",
|
||||
"fan",
|
||||
"group",
|
||||
@@ -223,6 +226,7 @@ export const DOMAINS_INPUT_ROW = [
|
||||
"script",
|
||||
"select",
|
||||
"switch",
|
||||
"vacuum",
|
||||
];
|
||||
|
||||
/** Domains that should have the history hidden in the more info dialog. */
|
||||
|
@@ -8,6 +8,10 @@ import { FrontendLocaleData } from "../data/translation";
|
||||
import { getValueInPercentage, normalize } from "../util/calculate";
|
||||
import { isSafari } from "../util/is_safari";
|
||||
|
||||
// Safari version 15.2 and up behaves differently than other Safari versions.
|
||||
// https://github.com/home-assistant/frontend/issues/10766
|
||||
const isSafari152 = isSafari && /Version\/15\.[^0-1]/.test(navigator.userAgent);
|
||||
|
||||
const getAngle = (value: number, min: number, max: number) => {
|
||||
const percentage = getValueInPercentage(normalize(value, min, max), min, max);
|
||||
return (percentage * 180) / 100;
|
||||
@@ -113,7 +117,9 @@ export class Gauge extends LitElement {
|
||||
: undefined
|
||||
)}
|
||||
transform=${ifDefined(
|
||||
isSafari ? `rotate(${this._angle} 50 50)` : undefined
|
||||
isSafari
|
||||
? `rotate(${this._angle}${isSafari152 ? "" : " 50 50"})`
|
||||
: undefined
|
||||
)}
|
||||
>
|
||||
`
|
||||
@@ -126,7 +132,9 @@ export class Gauge extends LitElement {
|
||||
: undefined
|
||||
)}
|
||||
transform=${ifDefined(
|
||||
isSafari ? `rotate(${this._angle} 50 50)` : undefined
|
||||
isSafari
|
||||
? `rotate(${this._angle}${isSafari152 ? "" : " 50 50"})`
|
||||
: undefined
|
||||
)}
|
||||
>`
|
||||
}
|
||||
|
@@ -302,8 +302,7 @@ export const installHassioAddon = async (
|
||||
|
||||
export const updateHassioAddon = async (
|
||||
hass: HomeAssistant,
|
||||
slug: string,
|
||||
backup: boolean
|
||||
slug: string
|
||||
): Promise<void> => {
|
||||
if (atLeastVersion(hass.config.version, 2021, 2, 4)) {
|
||||
await hass.callWS({
|
||||
@@ -311,13 +310,11 @@ export const updateHassioAddon = async (
|
||||
endpoint: `/store/addons/${slug}/update`,
|
||||
method: "post",
|
||||
timeout: null,
|
||||
data: { backup: backup },
|
||||
});
|
||||
} else {
|
||||
await hass.callApi<HassioResponse<void>>(
|
||||
"POST",
|
||||
`hassio/addons/${slug}/update`,
|
||||
{ backup: backup }
|
||||
`hassio/addons/${slug}/update`
|
||||
);
|
||||
}
|
||||
};
|
||||
|
@@ -6,18 +6,15 @@ export const restartCore = async (hass: HomeAssistant) => {
|
||||
await hass.callService("homeassistant", "restart");
|
||||
};
|
||||
|
||||
export const updateCore = async (hass: HomeAssistant, backup: boolean) => {
|
||||
export const updateCore = async (hass: HomeAssistant) => {
|
||||
if (atLeastVersion(hass.config.version, 2021, 2, 4)) {
|
||||
await hass.callWS({
|
||||
type: "supervisor/api",
|
||||
endpoint: "/core/update",
|
||||
method: "post",
|
||||
timeout: null,
|
||||
data: { backup: backup },
|
||||
});
|
||||
} else {
|
||||
await hass.callApi<HassioResponse<void>>("POST", `hassio/core/update`, {
|
||||
backup: backup,
|
||||
});
|
||||
await hass.callApi<HassioResponse<void>>("POST", `hassio/core/update`);
|
||||
}
|
||||
};
|
||||
|
@@ -110,7 +110,7 @@ export class ExternalMessaging {
|
||||
},
|
||||
});
|
||||
} else if (msg.command === "restart") {
|
||||
this.connection.socket.close();
|
||||
this.connection.reconnect(true);
|
||||
this.fireMessage({
|
||||
id: msg.id,
|
||||
type: "result",
|
||||
|
@@ -271,7 +271,10 @@ export const provideHass = (
|
||||
updateStates,
|
||||
updateTranslations,
|
||||
addTranslations,
|
||||
loadFragmentTranslation: async (_fragment: string) => hass().localize,
|
||||
loadFragmentTranslation: async (fragment: string) => {
|
||||
await updateTranslations(fragment);
|
||||
return hass().localize;
|
||||
},
|
||||
addEntities,
|
||||
mockWS(type, callback) {
|
||||
wsCommands[type] = callback;
|
||||
|
@@ -34,8 +34,6 @@ const panelUrl = (path: string) => {
|
||||
export class HomeAssistantAppEl extends QuickBarMixin(HassElement) {
|
||||
@state() private _route: Route;
|
||||
|
||||
@state() private _error = false;
|
||||
|
||||
private _panelUrl: string;
|
||||
|
||||
private _haVersion?: string;
|
||||
@@ -44,8 +42,6 @@ export class HomeAssistantAppEl extends QuickBarMixin(HassElement) {
|
||||
|
||||
private _visiblePromiseResolve?: () => void;
|
||||
|
||||
private _visibleLaunchScreen = true;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
const path = curPath();
|
||||
@@ -62,27 +58,22 @@ export class HomeAssistantAppEl extends QuickBarMixin(HassElement) {
|
||||
this._panelUrl = panelUrl(path);
|
||||
}
|
||||
|
||||
protected render() {
|
||||
if (this._isHassComplete() && this.hass) {
|
||||
return html`
|
||||
<home-assistant-main
|
||||
.hass=${this.hass}
|
||||
.route=${this._route}
|
||||
></home-assistant-main>
|
||||
`;
|
||||
}
|
||||
|
||||
return "";
|
||||
protected renderHass() {
|
||||
return html`
|
||||
<home-assistant-main
|
||||
.hass=${this.hass}
|
||||
.route=${this._route}
|
||||
></home-assistant-main>
|
||||
`;
|
||||
}
|
||||
|
||||
update(changedProps) {
|
||||
super.update(changedProps);
|
||||
|
||||
// Remove launch screen if main gui is loaded
|
||||
if (this._isHassComplete() && this._visibleLaunchScreen) {
|
||||
this._visibleLaunchScreen = false;
|
||||
if (this.hass?.states && this.hass.config && this.hass.services) {
|
||||
this.render = this.renderHass;
|
||||
this.update = super.update;
|
||||
removeLaunchScreen();
|
||||
}
|
||||
super.update(changedProps);
|
||||
}
|
||||
|
||||
protected firstUpdated(changedProps) {
|
||||
@@ -129,10 +120,9 @@ export class HomeAssistantAppEl extends QuickBarMixin(HassElement) {
|
||||
});
|
||||
|
||||
// Render launch screen info box (loading data / error message)
|
||||
if (!this._isHassComplete() && this._visibleLaunchScreen) {
|
||||
renderLaunchScreenInfoBox(
|
||||
html`<ha-init-page .error=${this._error}></ha-init-page>`
|
||||
);
|
||||
// if Home Assistant is not loaded yet.
|
||||
if (this.render !== this.renderHass) {
|
||||
this._renderInitInfo(false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -188,7 +178,7 @@ export class HomeAssistantAppEl extends QuickBarMixin(HassElement) {
|
||||
if (window.hassConnection) {
|
||||
result = await window.hassConnection;
|
||||
} else {
|
||||
// In the edge case that
|
||||
// In the edge case that core.ts loads before app.ts
|
||||
result = await new Promise((resolve) => {
|
||||
window.hassConnectionReady = resolve;
|
||||
});
|
||||
@@ -198,7 +188,7 @@ export class HomeAssistantAppEl extends QuickBarMixin(HassElement) {
|
||||
this._haVersion = conn.haVersion;
|
||||
this.initializeHass(auth, conn);
|
||||
} catch (err: any) {
|
||||
this._error = true;
|
||||
this._renderInitInfo(true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -255,12 +245,10 @@ export class HomeAssistantAppEl extends QuickBarMixin(HassElement) {
|
||||
}
|
||||
}
|
||||
|
||||
private _isHassComplete(): boolean {
|
||||
if (this.hass?.states && this.hass.config && this.hass.services) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
private _renderInitInfo(error: boolean) {
|
||||
renderLaunchScreenInfoBox(
|
||||
html`<ha-init-page .error=${error}></ha-init-page>`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -118,9 +118,9 @@ export class HaDeviceCard extends LitElement {
|
||||
word-wrap: break-word;
|
||||
}
|
||||
.manuf,
|
||||
.entity-id,
|
||||
.model {
|
||||
color: var(--secondary-text-color);
|
||||
word-wrap: break-word;
|
||||
}
|
||||
`;
|
||||
}
|
||||
|
@@ -218,9 +218,11 @@ class ZHADeviceCard extends SubscribeMixin(LitElement) {
|
||||
.device .manuf {
|
||||
color: var(--secondary-text-color);
|
||||
margin-bottom: 20px;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
.extra-info {
|
||||
margin-top: 8px;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
state-badge {
|
||||
cursor: pointer;
|
||||
|
@@ -5,7 +5,6 @@ import "@polymer/paper-input/paper-input";
|
||||
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { componentsWithService } from "../../../common/config/components_with_service";
|
||||
import { isComponentLoaded } from "../../../common/config/is_component_loaded";
|
||||
import "../../../components/buttons/ha-call-service-button";
|
||||
import "../../../components/ha-card";
|
||||
import { checkCoreConfig } from "../../../data/core";
|
||||
@@ -158,20 +157,6 @@ export class HaConfigServerControl extends LitElement {
|
||||
"ui.panel.config.server_control.section.server_management.restart"
|
||||
)}
|
||||
</ha-call-service-button>
|
||||
${!isComponentLoaded(this.hass, "hassio")
|
||||
? html`<ha-call-service-button
|
||||
class="warning"
|
||||
.hass=${this.hass}
|
||||
domain="homeassistant"
|
||||
service="stop"
|
||||
confirmation=${this.hass.localize(
|
||||
"ui.panel.config.server_control.section.server_management.confirm_stop"
|
||||
)}
|
||||
>${this.hass.localize(
|
||||
"ui.panel.config.server_control.section.server_management.stop"
|
||||
)}
|
||||
</ha-call-service-button>`
|
||||
: ""}
|
||||
</div>
|
||||
</ha-card>
|
||||
|
||||
|
@@ -163,16 +163,16 @@ class HuiEntitiesCard extends LitElement implements LovelaceCard {
|
||||
if (!this._config || !this._hass) {
|
||||
return;
|
||||
}
|
||||
const oldHass = changedProps.get("hass") as HomeAssistant | undefined;
|
||||
const oldHass = changedProps.get("_hass") as HomeAssistant | undefined;
|
||||
const oldConfig = changedProps.get("_config") as
|
||||
| EntitiesCardConfig
|
||||
| undefined;
|
||||
|
||||
if (
|
||||
!oldHass ||
|
||||
!oldConfig ||
|
||||
oldHass.themes !== this.hass.themes ||
|
||||
oldConfig.theme !== this._config.theme
|
||||
(changedProps.has("_hass") &&
|
||||
(!oldHass || oldHass.themes !== this._hass.themes)) ||
|
||||
(changedProps.has("_config") &&
|
||||
(!oldConfig || oldConfig.theme !== this._config.theme))
|
||||
) {
|
||||
applyThemesOnElement(this, this._hass.themes, this._config.theme);
|
||||
}
|
||||
|
@@ -33,6 +33,13 @@ class HuiGenericEntityRow extends LitElement {
|
||||
|
||||
@property({ type: Boolean }) public hideName = false;
|
||||
|
||||
// Allows to control if this row should capture the user interaction, e.g. with its
|
||||
// toggle switch, button or input field. Some domains dynamically decide what to show
|
||||
// => static determination will not work => the caller has to pass the desired value in.
|
||||
// Same applies for custom components that want to override the default behavior.
|
||||
// Default behavior is controlled by DOMAINS_INPUT_ROW.
|
||||
@property({ type: Boolean }) public catchInteraction?;
|
||||
|
||||
protected render(): TemplateResult {
|
||||
if (!this.hass || !this.config) {
|
||||
return html``;
|
||||
@@ -50,8 +57,11 @@ class HuiGenericEntityRow extends LitElement {
|
||||
}
|
||||
|
||||
const domain = computeDomain(this.config.entity);
|
||||
// By default, we always show a pointer, since if there is no explicit configuration provided,
|
||||
// the frontend always assumes "more-info" in the action handler. We only need to hide the pointer
|
||||
// if the tap action is explicitly set to "none".
|
||||
const pointer = !(
|
||||
this.config.tap_action && this.config.tap_action.action !== "none"
|
||||
this.config.tap_action && this.config.tap_action.action === "none"
|
||||
);
|
||||
|
||||
const hasSecondary = this.secondaryText || this.config.secondary_info;
|
||||
@@ -144,7 +154,7 @@ class HuiGenericEntityRow extends LitElement {
|
||||
: ""}
|
||||
</div>`
|
||||
: html``}
|
||||
${!DOMAINS_INPUT_ROW.includes(domain)
|
||||
${this.catchInteraction ?? !DOMAINS_INPUT_ROW.includes(domain)
|
||||
? html` <div
|
||||
class="text-content ${classMap({
|
||||
pointer,
|
||||
|
@@ -41,11 +41,18 @@ class HuiToggleEntityRow extends LitElement implements LovelaceRow {
|
||||
`;
|
||||
}
|
||||
|
||||
const showToggle =
|
||||
stateObj.state === "on" ||
|
||||
stateObj.state === "off" ||
|
||||
UNAVAILABLE_STATES.includes(stateObj.state);
|
||||
|
||||
return html`
|
||||
<hui-generic-entity-row .hass=${this.hass} .config=${this._config}>
|
||||
${stateObj.state === "on" ||
|
||||
stateObj.state === "off" ||
|
||||
UNAVAILABLE_STATES.includes(stateObj.state)
|
||||
<hui-generic-entity-row
|
||||
.hass=${this.hass}
|
||||
.config=${this._config}
|
||||
.catchInteraction=${!showToggle}
|
||||
>
|
||||
${showToggle
|
||||
? html`
|
||||
<ha-entity-toggle
|
||||
.hass=${this.hass}
|
||||
|
@@ -1419,7 +1419,7 @@
|
||||
},
|
||||
"server_control": {
|
||||
"caption": "Server Controls",
|
||||
"description": "Restart and stop the Home Assistant server",
|
||||
"description": "Validate and restart the Home Assistant server",
|
||||
"section": {
|
||||
"validation": {
|
||||
"heading": "Configuration validation",
|
||||
@@ -1461,7 +1461,8 @@
|
||||
"telegram": "Telegram notify services",
|
||||
"smtp": "SMTP notify services",
|
||||
"mqtt": "Manually configured MQTT entities",
|
||||
"rpi_gpio": "Raspberry Pi GPIO entities"
|
||||
"rpi_gpio": "Raspberry Pi GPIO entities",
|
||||
"timer": "Timers"
|
||||
},
|
||||
"server_management": {
|
||||
"heading": "Server management",
|
||||
@@ -4466,7 +4467,8 @@
|
||||
"repositories": {
|
||||
"title": "Manage add-on repositories",
|
||||
"add": "Add",
|
||||
"remove": "Remove"
|
||||
"remove": "Remove",
|
||||
"used": "Repository is in use for installed add-ons and can't be removed."
|
||||
},
|
||||
"restart_addon": {
|
||||
"confirm_text": "Restart add-on",
|
||||
|
@@ -7,9 +7,9 @@ export const removeLaunchScreen = () => {
|
||||
}
|
||||
};
|
||||
|
||||
export const renderLaunchScreenInfoBox = (element: TemplateResult) => {
|
||||
export const renderLaunchScreenInfoBox = (content: TemplateResult) => {
|
||||
const infoBoxElement = document.getElementById("ha-launch-screen-info-box");
|
||||
if (infoBoxElement) {
|
||||
render(element, infoBoxElement);
|
||||
render(content, infoBoxElement);
|
||||
}
|
||||
};
|
||||
|
10
yarn.lock
10
yarn.lock
@@ -9113,7 +9113,7 @@ fsevents@^1.2.7:
|
||||
gulp-rename: ^2.0.0
|
||||
gulp-zopfli-green: ^3.0.1
|
||||
hls.js: ^1.0.11
|
||||
home-assistant-js-websocket: ^5.11.3
|
||||
home-assistant-js-websocket: ^6.0.1
|
||||
html-minifier: ^4.0.0
|
||||
husky: ^1.3.1
|
||||
idb-keyval: ^5.1.3
|
||||
@@ -9184,10 +9184,10 @@ fsevents@^1.2.7:
|
||||
languageName: unknown
|
||||
linkType: soft
|
||||
|
||||
"home-assistant-js-websocket@npm:^5.11.3":
|
||||
version: 5.11.3
|
||||
resolution: "home-assistant-js-websocket@npm:5.11.3"
|
||||
checksum: 3ab90e5105c5f379d77fb23ab53eaec2789be7bf1fd507a7520d9cf329d36942b8e978a591b822cff96100630d43bd036a4e25e2f49c40d0c56a111808fb90a5
|
||||
"home-assistant-js-websocket@npm:^6.0.1":
|
||||
version: 6.0.1
|
||||
resolution: "home-assistant-js-websocket@npm:6.0.1"
|
||||
checksum: 566d6de6a4eb0e05ca434a45433cfe6fdd6b5cb2008e9a165709e08335df1c9b70903564c479ab8d48c6f5468a9784f47697192f9023170d2d86d43a461d6126
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
|
Reference in New Issue
Block a user