Merge pull request #10981 from home-assistant/dev

This commit is contained in:
Bram Kragten 2021-12-20 14:01:20 +01:00 committed by GitHub
commit 0800c702fb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 121 additions and 38 deletions

View File

@ -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,

View File

@ -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;

View File

@ -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;
} }

View File

@ -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);
}
`, `,
]; ];
} }

View File

@ -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;
} }
`; `;

View File

@ -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",

View File

@ -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",

View File

@ -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. */

View File

@ -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;

View File

@ -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",

View File

@ -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;

View File

@ -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;
} }
`; `;
} }

View File

@ -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;

View File

@ -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);
} }

View File

@ -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,

View File

@ -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}

View File

@ -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",

View File

@ -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