mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-19 23:36:36 +00:00
Merge pull request #10981 from home-assistant/dev
This commit is contained in:
commit
0800c702fb
@ -206,6 +206,7 @@ const createDeviceRegistryEntries = (
|
|||||||
model: "Mock Device",
|
model: "Mock Device",
|
||||||
name: "Tag Reader",
|
name: "Tag Reader",
|
||||||
sw_version: null,
|
sw_version: null,
|
||||||
|
hw_version: "1.0.0",
|
||||||
id: "mock-device-id",
|
id: "mock-device-id",
|
||||||
identifiers: [],
|
identifiers: [],
|
||||||
via_device_id: null,
|
via_device_id: null,
|
||||||
|
@ -133,6 +133,7 @@ class HassioAddonInfo extends LitElement {
|
|||||||
.narrow=${this.narrow}
|
.narrow=${this.narrow}
|
||||||
.supervisor=${this.supervisor}
|
.supervisor=${this.supervisor}
|
||||||
.addonSlug=${this.addon.slug}
|
.addonSlug=${this.addon.slug}
|
||||||
|
@update-complete=${this._updateComplete}
|
||||||
></update-available-card>
|
></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> {
|
private async _installClicked(ev: CustomEvent): Promise<void> {
|
||||||
const button = ev.currentTarget as any;
|
const button = ev.currentTarget as any;
|
||||||
button.progress = true;
|
button.progress = true;
|
||||||
|
@ -350,9 +350,7 @@ export class SupervisorBackupContent extends LitElement {
|
|||||||
if (folders?.length) {
|
if (folders?.length) {
|
||||||
data.folders = folders;
|
data.folders = folders;
|
||||||
}
|
}
|
||||||
if (this.homeAssistant) {
|
data.homeassistant = this.homeAssistant;
|
||||||
data.homeassistant = this.homeAssistant;
|
|
||||||
}
|
|
||||||
|
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
|
import "@polymer/paper-tooltip/paper-tooltip";
|
||||||
import "@material/mwc-button/mwc-button";
|
import "@material/mwc-button/mwc-button";
|
||||||
import { mdiDelete } from "@mdi/js";
|
import { mdiDelete, mdiDeleteOff } from "@mdi/js";
|
||||||
import "@polymer/paper-input/paper-input";
|
import "@polymer/paper-input/paper-input";
|
||||||
import type { PaperInputElement } from "@polymer/paper-input/paper-input";
|
import type { PaperInputElement } from "@polymer/paper-input/paper-input";
|
||||||
import "@polymer/paper-item/paper-item";
|
import "@polymer/paper-item/paper-item";
|
||||||
@ -15,6 +16,7 @@ import { createCloseHeading } from "../../../../src/components/ha-dialog";
|
|||||||
import "../../../../src/components/ha-icon-button";
|
import "../../../../src/components/ha-icon-button";
|
||||||
import {
|
import {
|
||||||
fetchHassioAddonsInfo,
|
fetchHassioAddonsInfo,
|
||||||
|
HassioAddonInfo,
|
||||||
HassioAddonRepository,
|
HassioAddonRepository,
|
||||||
} from "../../../../src/data/hassio/addon";
|
} from "../../../../src/data/hassio/addon";
|
||||||
import { extractApiErrorMessage } from "../../../../src/data/hassio/common";
|
import { extractApiErrorMessage } from "../../../../src/data/hassio/common";
|
||||||
@ -60,11 +62,24 @@ class HassioRepositoriesDialog extends LitElement {
|
|||||||
.sort((a, b) => caseInsensitiveStringCompare(a.name, b.name))
|
.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 {
|
protected render(): TemplateResult {
|
||||||
if (!this._dialogParams?.supervisor || this._repositories === undefined) {
|
if (!this._dialogParams?.supervisor || this._repositories === undefined) {
|
||||||
return html``;
|
return html``;
|
||||||
}
|
}
|
||||||
const repositories = this._filteredRepositories(this._repositories);
|
const repositories = this._filteredRepositories(this._repositories);
|
||||||
|
const usedRepositories = this._filteredUsedRepositories(
|
||||||
|
repositories,
|
||||||
|
this._dialogParams.supervisor.supervisor.addons
|
||||||
|
);
|
||||||
return html`
|
return html`
|
||||||
<ha-dialog
|
<ha-dialog
|
||||||
.open=${this._opened}
|
.open=${this._opened}
|
||||||
@ -89,18 +104,32 @@ class HassioRepositoriesDialog extends LitElement {
|
|||||||
<div secondary>${repo.maintainer}</div>
|
<div secondary>${repo.maintainer}</div>
|
||||||
<div secondary>${repo.url}</div>
|
<div secondary>${repo.url}</div>
|
||||||
</paper-item-body>
|
</paper-item-body>
|
||||||
<ha-icon-button
|
<div class="delete">
|
||||||
.slug=${repo.slug}
|
<ha-icon-button
|
||||||
.label=${this._dialogParams!.supervisor.localize(
|
.disabled=${usedRepositories.includes(repo.slug)}
|
||||||
"dialog.repositories.remove"
|
.slug=${repo.slug}
|
||||||
)}
|
.path=${usedRepositories.includes(repo.slug)
|
||||||
.path=${mdiDelete}
|
? mdiDeleteOff
|
||||||
@click=${this._removeRepository}
|
: mdiDelete}
|
||||||
></ha-icon-button>
|
@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>
|
</paper-item>
|
||||||
`
|
`
|
||||||
)
|
)
|
||||||
: html` <paper-item> No repositories </paper-item> `}
|
: html`<paper-item> No repositories </paper-item>`}
|
||||||
<div class="layout horizontal bottom">
|
<div class="layout horizontal bottom">
|
||||||
<paper-input
|
<paper-input
|
||||||
class="flex-auto"
|
class="flex-auto"
|
||||||
@ -157,6 +186,9 @@ class HassioRepositoriesDialog extends LitElement {
|
|||||||
margin: 32px;
|
margin: 32px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
div.delete ha-icon-button {
|
||||||
|
color: var(--error-color);
|
||||||
|
}
|
||||||
`,
|
`,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
@ -46,6 +46,7 @@ class UpdateAvailableDashboard extends LitElement {
|
|||||||
update-available-card {
|
update-available-card {
|
||||||
margin: auto;
|
margin: auto;
|
||||||
margin-top: 16px;
|
margin-top: 16px;
|
||||||
|
margin-bottom: 24px;
|
||||||
max-width: 600px;
|
max-width: 600px;
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
@ -102,7 +102,7 @@
|
|||||||
"fuse.js": "^6.0.0",
|
"fuse.js": "^6.0.0",
|
||||||
"google-timezones-json": "^1.0.2",
|
"google-timezones-json": "^1.0.2",
|
||||||
"hls.js": "^1.0.11",
|
"hls.js": "^1.0.11",
|
||||||
"home-assistant-js-websocket": "^5.11.3",
|
"home-assistant-js-websocket": "^5.12.0",
|
||||||
"idb-keyval": "^5.1.3",
|
"idb-keyval": "^5.1.3",
|
||||||
"intl-messageformat": "^9.9.1",
|
"intl-messageformat": "^9.9.1",
|
||||||
"js-yaml": "^4.1.0",
|
"js-yaml": "^4.1.0",
|
||||||
|
2
setup.py
2
setup.py
@ -2,7 +2,7 @@ from setuptools import setup, find_packages
|
|||||||
|
|
||||||
setup(
|
setup(
|
||||||
name="home-assistant-frontend",
|
name="home-assistant-frontend",
|
||||||
version="20211215.0",
|
version="20211220.0",
|
||||||
description="The Home Assistant frontend",
|
description="The Home Assistant frontend",
|
||||||
url="https://github.com/home-assistant/frontend",
|
url="https://github.com/home-assistant/frontend",
|
||||||
author="The Home Assistant Authors",
|
author="The Home Assistant Authors",
|
||||||
|
@ -199,13 +199,16 @@ export const DOMAINS_HIDE_DEFAULT_MORE_INFO = [
|
|||||||
"select",
|
"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
|
* 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
|
* 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
|
* 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 = [
|
export const DOMAINS_INPUT_ROW = [
|
||||||
|
"automation",
|
||||||
|
"button",
|
||||||
"cover",
|
"cover",
|
||||||
"fan",
|
"fan",
|
||||||
"group",
|
"group",
|
||||||
@ -223,6 +226,7 @@ export const DOMAINS_INPUT_ROW = [
|
|||||||
"script",
|
"script",
|
||||||
"select",
|
"select",
|
||||||
"switch",
|
"switch",
|
||||||
|
"vacuum",
|
||||||
];
|
];
|
||||||
|
|
||||||
/** Domains that should have the history hidden in the more info dialog. */
|
/** Domains that should have the history hidden in the more info dialog. */
|
||||||
|
@ -13,6 +13,7 @@ export interface DeviceRegistryEntry {
|
|||||||
model: string | null;
|
model: string | null;
|
||||||
name: string | null;
|
name: string | null;
|
||||||
sw_version: string | null;
|
sw_version: string | null;
|
||||||
|
hw_version: string | null;
|
||||||
via_device_id: string | null;
|
via_device_id: string | null;
|
||||||
area_id: string | null;
|
area_id: string | null;
|
||||||
name_by_user: string | null;
|
name_by_user: string | null;
|
||||||
|
@ -110,7 +110,7 @@ export class ExternalMessaging {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
} else if (msg.command === "restart") {
|
} else if (msg.command === "restart") {
|
||||||
this.connection.socket.close();
|
this.connection.reconnect(true);
|
||||||
this.fireMessage({
|
this.fireMessage({
|
||||||
id: msg.id,
|
id: msg.id,
|
||||||
type: "result",
|
type: "result",
|
||||||
|
@ -271,7 +271,10 @@ export const provideHass = (
|
|||||||
updateStates,
|
updateStates,
|
||||||
updateTranslations,
|
updateTranslations,
|
||||||
addTranslations,
|
addTranslations,
|
||||||
loadFragmentTranslation: async (_fragment: string) => hass().localize,
|
loadFragmentTranslation: async (fragment: string) => {
|
||||||
|
await updateTranslations(fragment);
|
||||||
|
return hass().localize;
|
||||||
|
},
|
||||||
addEntities,
|
addEntities,
|
||||||
mockWS(type, callback) {
|
mockWS(type, callback) {
|
||||||
wsCommands[type] = callback;
|
wsCommands[type] = callback;
|
||||||
|
@ -66,6 +66,17 @@ export class HaDeviceCard extends LitElement {
|
|||||||
</div>
|
</div>
|
||||||
`
|
`
|
||||||
: ""}
|
: ""}
|
||||||
|
${this.device.hw_version
|
||||||
|
? html`
|
||||||
|
<div class="extra-info">
|
||||||
|
${this.hass.localize(
|
||||||
|
"ui.panel.config.integrations.config_entry.hardware",
|
||||||
|
"version",
|
||||||
|
this.device.hw_version
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
`
|
||||||
|
: ""}
|
||||||
<slot></slot>
|
<slot></slot>
|
||||||
</div>
|
</div>
|
||||||
<slot name="actions"></slot>
|
<slot name="actions"></slot>
|
||||||
@ -107,9 +118,9 @@ export class HaDeviceCard extends LitElement {
|
|||||||
word-wrap: break-word;
|
word-wrap: break-word;
|
||||||
}
|
}
|
||||||
.manuf,
|
.manuf,
|
||||||
.entity-id,
|
|
||||||
.model {
|
.model {
|
||||||
color: var(--secondary-text-color);
|
color: var(--secondary-text-color);
|
||||||
|
word-wrap: break-word;
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
@ -218,9 +218,11 @@ class ZHADeviceCard extends SubscribeMixin(LitElement) {
|
|||||||
.device .manuf {
|
.device .manuf {
|
||||||
color: var(--secondary-text-color);
|
color: var(--secondary-text-color);
|
||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
||||||
|
word-wrap: break-word;
|
||||||
}
|
}
|
||||||
.extra-info {
|
.extra-info {
|
||||||
margin-top: 8px;
|
margin-top: 8px;
|
||||||
|
word-wrap: break-word;
|
||||||
}
|
}
|
||||||
state-badge {
|
state-badge {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
@ -163,16 +163,16 @@ class HuiEntitiesCard extends LitElement implements LovelaceCard {
|
|||||||
if (!this._config || !this._hass) {
|
if (!this._config || !this._hass) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const oldHass = changedProps.get("hass") as HomeAssistant | undefined;
|
const oldHass = changedProps.get("_hass") as HomeAssistant | undefined;
|
||||||
const oldConfig = changedProps.get("_config") as
|
const oldConfig = changedProps.get("_config") as
|
||||||
| EntitiesCardConfig
|
| EntitiesCardConfig
|
||||||
| undefined;
|
| undefined;
|
||||||
|
|
||||||
if (
|
if (
|
||||||
!oldHass ||
|
(changedProps.has("_hass") &&
|
||||||
!oldConfig ||
|
(!oldHass || oldHass.themes !== this._hass.themes)) ||
|
||||||
oldHass.themes !== this.hass.themes ||
|
(changedProps.has("_config") &&
|
||||||
oldConfig.theme !== this._config.theme
|
(!oldConfig || oldConfig.theme !== this._config.theme))
|
||||||
) {
|
) {
|
||||||
applyThemesOnElement(this, this._hass.themes, 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;
|
@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 {
|
protected render(): TemplateResult {
|
||||||
if (!this.hass || !this.config) {
|
if (!this.hass || !this.config) {
|
||||||
return html``;
|
return html``;
|
||||||
@ -50,8 +57,11 @@ class HuiGenericEntityRow extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const domain = computeDomain(this.config.entity);
|
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 = !(
|
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;
|
const hasSecondary = this.secondaryText || this.config.secondary_info;
|
||||||
@ -144,7 +154,7 @@ class HuiGenericEntityRow extends LitElement {
|
|||||||
: ""}
|
: ""}
|
||||||
</div>`
|
</div>`
|
||||||
: html``}
|
: html``}
|
||||||
${!DOMAINS_INPUT_ROW.includes(domain)
|
${this.catchInteraction ?? !DOMAINS_INPUT_ROW.includes(domain)
|
||||||
? html` <div
|
? html` <div
|
||||||
class="text-content ${classMap({
|
class="text-content ${classMap({
|
||||||
pointer,
|
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`
|
return html`
|
||||||
<hui-generic-entity-row .hass=${this.hass} .config=${this._config}>
|
<hui-generic-entity-row
|
||||||
${stateObj.state === "on" ||
|
.hass=${this.hass}
|
||||||
stateObj.state === "off" ||
|
.config=${this._config}
|
||||||
UNAVAILABLE_STATES.includes(stateObj.state)
|
.catchInteraction=${!showToggle}
|
||||||
|
>
|
||||||
|
${showToggle
|
||||||
? html`
|
? html`
|
||||||
<ha-entity-toggle
|
<ha-entity-toggle
|
||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
|
@ -1461,7 +1461,8 @@
|
|||||||
"telegram": "Telegram notify services",
|
"telegram": "Telegram notify services",
|
||||||
"smtp": "SMTP notify services",
|
"smtp": "SMTP notify services",
|
||||||
"mqtt": "Manually configured MQTT entities",
|
"mqtt": "Manually configured MQTT entities",
|
||||||
"rpi_gpio": "Raspberry Pi GPIO entities"
|
"rpi_gpio": "Raspberry Pi GPIO entities",
|
||||||
|
"timer": "Timers"
|
||||||
},
|
},
|
||||||
"server_management": {
|
"server_management": {
|
||||||
"heading": "Server management",
|
"heading": "Server management",
|
||||||
@ -2444,6 +2445,7 @@
|
|||||||
"manuf": "by {manufacturer}",
|
"manuf": "by {manufacturer}",
|
||||||
"via": "Connected via",
|
"via": "Connected via",
|
||||||
"firmware": "Firmware: {version}",
|
"firmware": "Firmware: {version}",
|
||||||
|
"hardware": "Hardware: {version}",
|
||||||
"unnamed_entry": "Unnamed entry",
|
"unnamed_entry": "Unnamed entry",
|
||||||
"unknown_via_device": "Unknown device",
|
"unknown_via_device": "Unknown device",
|
||||||
"area": "In {area}",
|
"area": "In {area}",
|
||||||
@ -4465,7 +4467,8 @@
|
|||||||
"repositories": {
|
"repositories": {
|
||||||
"title": "Manage add-on repositories",
|
"title": "Manage add-on repositories",
|
||||||
"add": "Add",
|
"add": "Add",
|
||||||
"remove": "Remove"
|
"remove": "Remove",
|
||||||
|
"used": "Repository is in use for installed add-ons and can't be removed."
|
||||||
},
|
},
|
||||||
"restart_addon": {
|
"restart_addon": {
|
||||||
"confirm_text": "Restart add-on",
|
"confirm_text": "Restart add-on",
|
||||||
|
10
yarn.lock
10
yarn.lock
@ -9113,7 +9113,7 @@ fsevents@^1.2.7:
|
|||||||
gulp-rename: ^2.0.0
|
gulp-rename: ^2.0.0
|
||||||
gulp-zopfli-green: ^3.0.1
|
gulp-zopfli-green: ^3.0.1
|
||||||
hls.js: ^1.0.11
|
hls.js: ^1.0.11
|
||||||
home-assistant-js-websocket: ^5.11.3
|
home-assistant-js-websocket: ^5.12.0
|
||||||
html-minifier: ^4.0.0
|
html-minifier: ^4.0.0
|
||||||
husky: ^1.3.1
|
husky: ^1.3.1
|
||||||
idb-keyval: ^5.1.3
|
idb-keyval: ^5.1.3
|
||||||
@ -9184,10 +9184,10 @@ fsevents@^1.2.7:
|
|||||||
languageName: unknown
|
languageName: unknown
|
||||||
linkType: soft
|
linkType: soft
|
||||||
|
|
||||||
"home-assistant-js-websocket@npm:^5.11.3":
|
"home-assistant-js-websocket@npm:^5.12.0":
|
||||||
version: 5.11.3
|
version: 5.12.0
|
||||||
resolution: "home-assistant-js-websocket@npm:5.11.3"
|
resolution: "home-assistant-js-websocket@npm:5.12.0"
|
||||||
checksum: 3ab90e5105c5f379d77fb23ab53eaec2789be7bf1fd507a7520d9cf329d36942b8e978a591b822cff96100630d43bd036a4e25e2f49c40d0c56a111808fb90a5
|
checksum: 62171c10e55e3245c9a4fc77dbd2641f234a66b4e3d0adaf8c4364c567473555dbf34f3d737bf3f31e92f2a198051b57f2782fd71f8406784693e64496809501
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user