mirror of
https://github.com/home-assistant/frontend.git
synced 2026-09-06 19:38:20 +00:00
Compare commits
26
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a6f8f0495c | ||
|
|
ba8b20d877 | ||
|
|
8de542388f | ||
|
|
e6c580aadc | ||
|
|
11696c566a | ||
|
|
edc15940a2 | ||
|
|
bf35ee549d | ||
|
|
4c3baa678c | ||
|
|
0bb2767696 | ||
|
|
80a4852325 | ||
|
|
9c3e0fc997 | ||
|
|
9e4bee123f | ||
|
|
c2c09b1284 | ||
|
|
f9ccfa00a2 | ||
|
|
070e11a2db | ||
|
|
fc1c6cea24 | ||
|
|
c6a103bd30 | ||
|
|
9d1618024e | ||
|
|
307aa161a6 | ||
|
|
affa6a92e7 | ||
|
|
1e5ec241d5 | ||
|
|
27a98a32fc | ||
|
|
2c8ac58f97 | ||
|
|
6b995969b1 | ||
|
|
72c107484a | ||
|
|
d1085b6657 |
@@ -31,7 +31,7 @@ export const mockHassioSupervisor = (hass: MockHomeAssistant) => {
|
||||
version_latest: "3.6.2",
|
||||
update_available: false,
|
||||
repository: "a0d7b954",
|
||||
icon: true,
|
||||
icon: false,
|
||||
logo: true,
|
||||
},
|
||||
{
|
||||
|
||||
Binary file not shown.
@@ -6,6 +6,7 @@ import {
|
||||
UPDATE_SUPPORT_PROGRESS,
|
||||
UPDATE_SUPPORT_INSTALL,
|
||||
UPDATE_SUPPORT_RELEASE_NOTES,
|
||||
UPDATE_SUPPORT_AUTO_UPDATE,
|
||||
} from "../../../../src/data/update";
|
||||
import "../../../../src/dialogs/more-info/more-info-content";
|
||||
import { getEntity } from "../../../../src/fake_data/entity";
|
||||
@@ -128,6 +129,12 @@ const ENTITIES = [
|
||||
supported_features:
|
||||
base_attributes.supported_features + UPDATE_SUPPORT_RELEASE_NOTES,
|
||||
}),
|
||||
getEntity("update", "update18", "on", {
|
||||
...base_attributes,
|
||||
friendly_name: "Update with auto update",
|
||||
supported_features:
|
||||
base_attributes.supported_features + UPDATE_SUPPORT_AUTO_UPDATE,
|
||||
}),
|
||||
];
|
||||
|
||||
@customElement("demo-more-info-update")
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[metadata]
|
||||
name = home-assistant-frontend
|
||||
version = 20220329.0
|
||||
version = 20220330.0
|
||||
author = The Home Assistant Authors
|
||||
author_email = [email protected]
|
||||
license = Apache-2.0
|
||||
|
||||
@@ -13,9 +13,12 @@ import { HaComboBox } from "./ha-combo-box";
|
||||
|
||||
const rowRenderer: ComboBoxLitRenderer<HassioAddonInfo> = (
|
||||
item
|
||||
) => html`<mwc-list-item twoline>
|
||||
) => html`<mwc-list-item twoline graphic="icon">
|
||||
<span>${item.name}</span>
|
||||
<span slot="secondary">${item.slug}</span>
|
||||
${item.icon
|
||||
? html`<img slot="graphic" .src="/api/hassio/addons/${item.slug}/icon" />`
|
||||
: ""}
|
||||
</mwc-list-item>`;
|
||||
|
||||
@customElement("ha-addon-picker")
|
||||
|
||||
+4
-3
@@ -2,6 +2,7 @@ import type {
|
||||
HassEntityAttributeBase,
|
||||
HassEntityBase,
|
||||
} from "home-assistant-js-websocket";
|
||||
import { BINARY_STATE_ON } from "../common/const";
|
||||
import { supportsFeature } from "../common/entity/supports-feature";
|
||||
import { HomeAssistant } from "../types";
|
||||
|
||||
@@ -10,6 +11,7 @@ export const UPDATE_SUPPORT_SPECIFIC_VERSION = 2;
|
||||
export const UPDATE_SUPPORT_PROGRESS = 4;
|
||||
export const UPDATE_SUPPORT_BACKUP = 8;
|
||||
export const UPDATE_SUPPORT_RELEASE_NOTES = 16;
|
||||
export const UPDATE_SUPPORT_AUTO_UPDATE = 32;
|
||||
|
||||
interface UpdateEntityAttributes extends HassEntityAttributeBase {
|
||||
current_version: string | null;
|
||||
@@ -30,9 +32,8 @@ export const updateUsesProgress = (entity: UpdateEntity): boolean =>
|
||||
typeof entity.attributes.in_progress === "number";
|
||||
|
||||
export const updateCanInstall = (entity: UpdateEntity): boolean =>
|
||||
supportsFeature(entity, UPDATE_SUPPORT_INSTALL) &&
|
||||
entity.attributes.latest_version !== entity.attributes.current_version &&
|
||||
entity.attributes.latest_version !== entity.attributes.skipped_version;
|
||||
entity.state === BINARY_STATE_ON &&
|
||||
supportsFeature(entity, UPDATE_SUPPORT_INSTALL);
|
||||
|
||||
export const updateIsInstalling = (entity: UpdateEntity): boolean =>
|
||||
updateUsesProgress(entity) || !!entity.attributes.in_progress;
|
||||
|
||||
@@ -167,12 +167,18 @@ export interface ZwaveJSNodeMetadata {
|
||||
wakeup: string;
|
||||
reset: string;
|
||||
device_database_url: string;
|
||||
comments: ZWaveJSNodeComment[];
|
||||
}
|
||||
|
||||
export interface ZWaveJSNodeConfigParams {
|
||||
[key: string]: ZWaveJSNodeConfigParam;
|
||||
}
|
||||
|
||||
export interface ZWaveJSNodeComment {
|
||||
level: "info" | "warning" | "error";
|
||||
text: string;
|
||||
}
|
||||
|
||||
export interface ZWaveJSNodeConfigParam {
|
||||
property: number;
|
||||
value: any;
|
||||
|
||||
@@ -96,6 +96,13 @@ class MoreInfoMediaPlayer extends LitElement {
|
||||
.path=${stateObj.attributes.is_volume_muted
|
||||
? mdiVolumeOff
|
||||
: mdiVolumeHigh}
|
||||
.label=${this.hass.localize(
|
||||
`ui.card.media_player.${
|
||||
stateObj.attributes.is_volume_muted
|
||||
? "media_volume_unmute"
|
||||
: "media_volume_mute"
|
||||
}`
|
||||
)}
|
||||
@click=${this._toggleMute}
|
||||
></ha-icon-button>
|
||||
`
|
||||
@@ -105,11 +112,17 @@ class MoreInfoMediaPlayer extends LitElement {
|
||||
<ha-icon-button
|
||||
action="volume_down"
|
||||
.path=${mdiVolumeMinus}
|
||||
.label=${this.hass.localize(
|
||||
"ui.card.media_player.media_volume_down"
|
||||
)}
|
||||
@click=${this._handleClick}
|
||||
></ha-icon-button>
|
||||
<ha-icon-button
|
||||
action="volume_up"
|
||||
.path=${mdiVolumePlus}
|
||||
.label=${this.hass.localize(
|
||||
"ui.card.media_player.media_volume_up"
|
||||
)}
|
||||
@click=${this._handleClick}
|
||||
></ha-icon-button>
|
||||
`
|
||||
|
||||
@@ -14,6 +14,7 @@ import {
|
||||
UpdateEntity,
|
||||
updateIsInstalling,
|
||||
updateReleaseNotes,
|
||||
UPDATE_SUPPORT_AUTO_UPDATE,
|
||||
UPDATE_SUPPORT_BACKUP,
|
||||
UPDATE_SUPPORT_INSTALL,
|
||||
UPDATE_SUPPORT_PROGRESS,
|
||||
@@ -130,14 +131,16 @@ class MoreInfoUpdate extends LitElement {
|
||||
: ""}
|
||||
<hr />
|
||||
<div class="actions">
|
||||
<mwc-button
|
||||
@click=${this._handleSkip}
|
||||
.disabled=${skippedVersion ||
|
||||
this.stateObj.state === "off" ||
|
||||
updateIsInstalling(this.stateObj)}
|
||||
>
|
||||
${this.hass.localize("ui.dialogs.more_info_control.update.skip")}
|
||||
</mwc-button>
|
||||
${supportsFeature(this.stateObj, UPDATE_SUPPORT_AUTO_UPDATE)
|
||||
? ""
|
||||
: html`<mwc-button
|
||||
@click=${this._handleSkip}
|
||||
.disabled=${skippedVersion ||
|
||||
this.stateObj.state === "off" ||
|
||||
updateIsInstalling(this.stateObj)}
|
||||
>
|
||||
${this.hass.localize("ui.dialogs.more_info_control.update.skip")}
|
||||
</mwc-button>`}
|
||||
${supportsFeature(this.stateObj, UPDATE_SUPPORT_INSTALL)
|
||||
? html`
|
||||
<mwc-button
|
||||
|
||||
@@ -246,8 +246,8 @@ class ConfigUrlForm extends LitElement {
|
||||
|
||||
if (isComponentLoaded(this.hass, "cloud")) {
|
||||
fetchCloudStatus(this.hass).then((cloudStatus) => {
|
||||
this._cloudStatus = cloudStatus;
|
||||
if (cloudStatus.logged_in) {
|
||||
this._cloudStatus = cloudStatus;
|
||||
this._showCustomExternalUrl = this._externalUrlValue !== null;
|
||||
}
|
||||
});
|
||||
|
||||
@@ -75,7 +75,7 @@ export class HaDeviceEntitiesCard extends LitElement {
|
||||
this._entityRows = [];
|
||||
|
||||
this.entities.forEach((entry) => {
|
||||
if (entry.disabled_by || entry.hidden_by) {
|
||||
if (entry.disabled_by) {
|
||||
if (this._extDisabledEntityEntries) {
|
||||
hiddenEntities.push(
|
||||
this._extDisabledEntityEntries[entry.entity_id] || entry
|
||||
@@ -167,7 +167,11 @@ export class HaDeviceEntitiesCard extends LitElement {
|
||||
computeStateName(stateObj),
|
||||
this.deviceName.toLowerCase()
|
||||
);
|
||||
if (name) {
|
||||
if (entry.hidden_by) {
|
||||
config.name = `${
|
||||
name || computeStateName(stateObj)
|
||||
} (${this.hass.localize("ui.panel.config.devices.entities.hidden")})`;
|
||||
} else if (name) {
|
||||
config.name = name;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,6 +28,11 @@ import {
|
||||
deleteConfigEntry,
|
||||
getConfigEntries,
|
||||
} from "../../../data/config_entries";
|
||||
import {
|
||||
createConfigFlow,
|
||||
handleConfigFlowStep,
|
||||
} from "../../../data/config_flow";
|
||||
import { DataEntryFlowStepCreateEntry } from "../../../data/data_entry_flow";
|
||||
import {
|
||||
DeviceRegistryEntry,
|
||||
subscribeDeviceRegistry,
|
||||
@@ -36,9 +41,11 @@ import {
|
||||
import {
|
||||
EntityRegistryEntryUpdateParams,
|
||||
ExtEntityRegistryEntry,
|
||||
fetchEntityRegistry,
|
||||
removeEntityRegistryEntry,
|
||||
updateEntityRegistryEntry,
|
||||
} from "../../../data/entity_registry";
|
||||
import { domainToName } from "../../../data/integration";
|
||||
import { showOptionsFlowDialog } from "../../../dialogs/config-flow/show-dialog-options-flow";
|
||||
import {
|
||||
showAlertDialog,
|
||||
@@ -48,6 +55,7 @@ import { SubscribeMixin } from "../../../mixins/subscribe-mixin";
|
||||
import { haStyle } from "../../../resources/styles";
|
||||
import type { HomeAssistant } from "../../../types";
|
||||
import { showDeviceRegistryDetailDialog } from "../devices/device-registry-detail/show-dialog-device-registry-detail";
|
||||
import { showEntityEditorDialog } from "./show-dialog-entity-editor";
|
||||
|
||||
const OVERRIDE_DEVICE_CLASSES = {
|
||||
cover: [
|
||||
@@ -88,6 +96,8 @@ const OVERRIDE_SENSOR_UNITS = {
|
||||
pressure: ["hPa", "Pa", "kPa", "bar", "cbar", "mbar", "mmHg", "inHg", "psi"],
|
||||
};
|
||||
|
||||
const SWITCH_AS_DOMAINS = ["light", "lock", "cover", "fan", "siren"];
|
||||
|
||||
@customElement("entity-registry-settings")
|
||||
export class EntityRegistrySettings extends SubscribeMixin(LitElement) {
|
||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||
@@ -102,6 +112,8 @@ export class EntityRegistrySettings extends SubscribeMixin(LitElement) {
|
||||
|
||||
@state() private _deviceClass?: string;
|
||||
|
||||
@state() private _switchAs = "switch";
|
||||
|
||||
@state() private _areaId?: string | null;
|
||||
|
||||
@state() private _disabledBy!: string | null;
|
||||
@@ -263,7 +275,7 @@ export class EntityRegistrySettings extends SubscribeMixin(LitElement) {
|
||||
>
|
||||
${this._deviceClassOptions[0].map(
|
||||
(deviceClass: string) => html`
|
||||
<mwc-list-item .value=${deviceClass} test=${deviceClass}>
|
||||
<mwc-list-item .value=${deviceClass}>
|
||||
${this.hass.localize(
|
||||
`ui.dialogs.entity_registry.editor.device_classes.${domain}.${deviceClass}`
|
||||
)}
|
||||
@@ -273,7 +285,7 @@ export class EntityRegistrySettings extends SubscribeMixin(LitElement) {
|
||||
<li divider role="separator"></li>
|
||||
${this._deviceClassOptions[1].map(
|
||||
(deviceClass: string) => html`
|
||||
<mwc-list-item .value=${deviceClass} test=${deviceClass}>
|
||||
<mwc-list-item .value=${deviceClass}>
|
||||
${this.hass.localize(
|
||||
`ui.dialogs.entity_registry.editor.device_classes.${domain}.${deviceClass}`
|
||||
)}
|
||||
@@ -307,6 +319,28 @@ export class EntityRegistrySettings extends SubscribeMixin(LitElement) {
|
||||
</ha-select>
|
||||
`
|
||||
: ""}
|
||||
${domain === "switch"
|
||||
? html`<ha-select
|
||||
.label=${this.hass.localize(
|
||||
"ui.dialogs.entity_registry.editor.device_class"
|
||||
)}
|
||||
naturalMenuWidth
|
||||
fixedMenuPosition
|
||||
@selected=${this._switchAsChanged}
|
||||
@closed=${stopPropagation}
|
||||
>
|
||||
<mwc-list-item value="switch" selected>
|
||||
${domainToName(this.hass.localize, "switch")}</mwc-list-item
|
||||
>
|
||||
${SWITCH_AS_DOMAINS.map(
|
||||
(as_domain) => html`
|
||||
<mwc-list-item .value=${as_domain}>
|
||||
${domainToName(this.hass.localize, as_domain)}
|
||||
</mwc-list-item>
|
||||
`
|
||||
)}
|
||||
</ha-select>`
|
||||
: ""}
|
||||
<ha-textfield
|
||||
error-message="Domain needs to stay the same"
|
||||
.value=${this._entityId}
|
||||
@@ -512,6 +546,13 @@ export class EntityRegistrySettings extends SubscribeMixin(LitElement) {
|
||||
this._unit_of_measurement = ev.target.value;
|
||||
}
|
||||
|
||||
private _switchAsChanged(ev): void {
|
||||
if (ev.target.value === "") {
|
||||
return;
|
||||
}
|
||||
this._switchAs = ev.target.value;
|
||||
}
|
||||
|
||||
private _areaPicked(ev: CustomEvent) {
|
||||
this._error = undefined;
|
||||
this._areaId = ev.detail.value;
|
||||
@@ -545,6 +586,9 @@ export class EntityRegistrySettings extends SubscribeMixin(LitElement) {
|
||||
|
||||
private async _updateEntry(): Promise<void> {
|
||||
this._submitting = true;
|
||||
|
||||
const parent = (this.getRootNode() as ShadowRoot).host as HTMLElement;
|
||||
|
||||
const params: Partial<EntityRegistryEntryUpdateParams> = {
|
||||
name: this._name.trim() || null,
|
||||
icon: this._icon.trim() || null,
|
||||
@@ -604,6 +648,46 @@ export class EntityRegistrySettings extends SubscribeMixin(LitElement) {
|
||||
} finally {
|
||||
this._submitting = false;
|
||||
}
|
||||
|
||||
if (this._switchAs !== "switch") {
|
||||
if (
|
||||
!(await showConfirmationDialog(this, {
|
||||
text: this.hass!.localize(
|
||||
"ui.dialogs.entity_registry.editor.switch_as_x_confirm",
|
||||
"domain",
|
||||
this._switchAs
|
||||
),
|
||||
}))
|
||||
) {
|
||||
return;
|
||||
}
|
||||
const configFlow = await createConfigFlow(this.hass, "switch_as_x");
|
||||
const result = (await handleConfigFlowStep(
|
||||
this.hass,
|
||||
configFlow.flow_id,
|
||||
{
|
||||
entity_id: this._entityId.trim(),
|
||||
target_domain: this._switchAs,
|
||||
}
|
||||
)) as DataEntryFlowStepCreateEntry;
|
||||
if (!result.result?.entry_id) {
|
||||
return;
|
||||
}
|
||||
const unsub = await this.hass.connection.subscribeEvents(() => {
|
||||
unsub();
|
||||
fetchEntityRegistry(this.hass.connection).then((entityRegistry) => {
|
||||
const entity = entityRegistry.find(
|
||||
(reg) => reg.config_entry_id === result.result!.entry_id
|
||||
);
|
||||
if (!entity) {
|
||||
return;
|
||||
}
|
||||
showEntityEditorDialog(parent, {
|
||||
entity_id: entity.entity_id,
|
||||
});
|
||||
});
|
||||
}, "entity_registry_updated");
|
||||
}
|
||||
}
|
||||
|
||||
private async _confirmDeleteEntry(): Promise<void> {
|
||||
|
||||
+22
-14
@@ -19,6 +19,7 @@ import { customElement, property, state } from "lit/decorators";
|
||||
import { classMap } from "lit/directives/class-map";
|
||||
import memoizeOne from "memoize-one";
|
||||
import { debounce } from "../../../../../common/util/debounce";
|
||||
import "../../../../../components/ha-alert";
|
||||
import "../../../../../components/ha-card";
|
||||
import "../../../../../components/ha-icon-next";
|
||||
import "../../../../../components/ha-select";
|
||||
@@ -130,7 +131,7 @@ class ZWaveJSNodeConfig extends SubscribeMixin(LitElement) {
|
||||
></hass-error-screen>`;
|
||||
}
|
||||
|
||||
if (!this._config) {
|
||||
if (!this._config || !this._nodeMetadata) {
|
||||
return html`<hass-loading-screen></hass-loading-screen>`;
|
||||
}
|
||||
|
||||
@@ -178,20 +179,27 @@ class ZWaveJSNodeConfig extends SubscribeMixin(LitElement) {
|
||||
</em>
|
||||
</p>
|
||||
</div>
|
||||
<ha-card>
|
||||
${this._config
|
||||
? html`
|
||||
${Object.entries(this._config).map(
|
||||
([id, item]) => html` <ha-settings-row
|
||||
class="config-item"
|
||||
.configId=${id}
|
||||
.narrow=${this.narrow}
|
||||
>
|
||||
${this._generateConfigBox(id, item)}
|
||||
</ha-settings-row>`
|
||||
${this._nodeMetadata.comments.length > 0
|
||||
? html`
|
||||
<div>
|
||||
${this._nodeMetadata.comments.map(
|
||||
(comment) => html`<ha-alert .alertType=${comment.level}>
|
||||
${comment.text}
|
||||
</ha-alert>`
|
||||
)}
|
||||
`
|
||||
: ``}
|
||||
</div>
|
||||
`
|
||||
: ``}
|
||||
<ha-card>
|
||||
${Object.entries(this._config).map(
|
||||
([id, item]) => html` <ha-settings-row
|
||||
class="config-item"
|
||||
.configId=${id}
|
||||
.narrow=${this.narrow}
|
||||
>
|
||||
${this._generateConfigBox(id, item)}
|
||||
</ha-settings-row>`
|
||||
)}
|
||||
</ha-card>
|
||||
</ha-config-section>
|
||||
</hass-tabs-subpage>
|
||||
|
||||
@@ -117,6 +117,10 @@ const REDIRECTS: Redirects = {
|
||||
component: "lovelace",
|
||||
redirect: "/config/lovelace/resources",
|
||||
},
|
||||
backup: {
|
||||
component: "backup",
|
||||
redirect: "/config/backup",
|
||||
},
|
||||
people: {
|
||||
component: "person",
|
||||
redirect: "/config/person",
|
||||
@@ -184,6 +188,13 @@ class HaPanelMy extends LitElement {
|
||||
super.connectedCallback();
|
||||
const path = this.route.path.substring(1);
|
||||
|
||||
if (path === "backup" && isComponentLoaded(this.hass, "hassio")) {
|
||||
navigate("/hassio/backups", {
|
||||
replace: true,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (path.startsWith("supervisor")) {
|
||||
if (!isComponentLoaded(this.hass, "hassio")) {
|
||||
this._error = "no_supervisor";
|
||||
|
||||
@@ -842,6 +842,7 @@
|
||||
"hidden_cause": "Hidden by {cause}.",
|
||||
"device_disabled": "The device of this entity is disabled.",
|
||||
"open_device_settings": "Open device settings",
|
||||
"switch_as_x_confirm": "This switch will be hidden and a new {domain} will be added. Your existing configurations using the switch will continue to work.",
|
||||
"enabled_description": "Disabled entities will not be added to Home Assistant.",
|
||||
"enabled_delay_confirm": "The enabled entities will be added to Home Assistant in {delay} seconds",
|
||||
"enabled_restart_confirm": "Restart Home Assistant to finish enabling the entities",
|
||||
@@ -2462,7 +2463,8 @@
|
||||
"add_entities_lovelace": "Add to dashboard",
|
||||
"none": "This device has no entities",
|
||||
"show_less": "Show less",
|
||||
"hidden_entities": "+{count} {count, plural,\n one {entity}\n other {entities}\n} not shown"
|
||||
"hidden_entities": "+{count} {count, plural,\n one {entity}\n other {entities}\n} not shown",
|
||||
"hidden": "Hidden"
|
||||
},
|
||||
"confirm_rename_entity_ids": "Do you also want to rename the entity IDs of your entities?",
|
||||
"confirm_rename_entity_ids_warning": "This will not change any configuration (like automations, scripts, scenes, dashboards) that is currently using these entities! You will have to update them yourself to use the new entity IDs!",
|
||||
@@ -4048,7 +4050,8 @@
|
||||
"update": "Update the historic statistic values from ''{metadata_unit}'' to ''{state_unit}''",
|
||||
"clear": "Delete all old statistic data for this entity"
|
||||
}
|
||||
}
|
||||
},
|
||||
"adjust_sum": "Adjust sum"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -5915,9 +5915,9 @@ __metadata:
|
||||
linkType: hard
|
||||
|
||||
"caniuse-lite@npm:^1.0.30001259":
|
||||
version: 1.0.30001261
|
||||
resolution: "caniuse-lite@npm:1.0.30001261"
|
||||
checksum: d894662312ecbdd772f0a258c4a45cac93605247b127b25649052353e0b981abfd0b445f469650943b612adc236fd510ae61c1293f3e77c68af7411d1b66574a
|
||||
version: 1.0.30001322
|
||||
resolution: "caniuse-lite@npm:1.0.30001322"
|
||||
checksum: 48609d1808c69034a74ab6df9db8cffd847e12da6979e150f364cc8e2a4310fce1f2811382ca57b3b4111c0182f7c67edfde3cd4159c29537fc232596aecf48b
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
|
||||
Reference in New Issue
Block a user