mirror of
https://github.com/home-assistant/frontend.git
synced 2026-05-14 21:27:01 +00:00
Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 8e1474d717 | |||
| 6172c9db23 | |||
| ad36772c74 | |||
| f732de574b |
@@ -1,3 +1,4 @@
|
||||
import "@home-assistant/webawesome/dist/components/popup/popup";
|
||||
import { mdiLightbulbOutline } from "@mdi/js";
|
||||
import { css, html, LitElement, nothing } from "lit";
|
||||
import { customElement, property } from "lit/decorators";
|
||||
@@ -9,18 +10,41 @@ import "./ha-svg-icon";
|
||||
class HaTip extends LitElement {
|
||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||
|
||||
/**
|
||||
* When set, renders the tip inside a popup anchored to the given element
|
||||
* instead of inline. Does not steal focus.
|
||||
*/
|
||||
@property({ attribute: false }) public popoverAnchor?: Element;
|
||||
|
||||
public render() {
|
||||
if (!this.hass) {
|
||||
return nothing;
|
||||
}
|
||||
|
||||
return html`
|
||||
const content = html`
|
||||
<ha-svg-icon .path=${mdiLightbulbOutline}></ha-svg-icon>
|
||||
<span class="prefix"
|
||||
>${this.hass.localize("ui.panel.config.tips.tip")}</span
|
||||
>
|
||||
<span class="text"><slot></slot></span>
|
||||
`;
|
||||
|
||||
if (this.popoverAnchor) {
|
||||
return html`
|
||||
<wa-popup
|
||||
active
|
||||
.anchor=${this.popoverAnchor}
|
||||
placement="top-start"
|
||||
distance="4"
|
||||
flip
|
||||
shift
|
||||
>
|
||||
<div class="popup-content">${content}</div>
|
||||
</wa-popup>
|
||||
`;
|
||||
}
|
||||
|
||||
return content;
|
||||
}
|
||||
|
||||
static styles = css`
|
||||
@@ -40,6 +64,14 @@ class HaTip extends LitElement {
|
||||
.prefix {
|
||||
font-weight: var(--ha-font-weight-medium);
|
||||
}
|
||||
|
||||
.popup-content {
|
||||
padding: var(--ha-space-2) var(--ha-space-3);
|
||||
background: var(--card-background-color);
|
||||
border-radius: var(--ha-border-radius-xl);
|
||||
box-shadow: var(--wa-shadow-m);
|
||||
color: var(--primary-text-color);
|
||||
}
|
||||
`;
|
||||
}
|
||||
|
||||
|
||||
@@ -39,11 +39,15 @@ export class EntitySettingsHelperTab extends LitElement {
|
||||
|
||||
@state() private _submitting = false;
|
||||
|
||||
@state() private _dirty = false;
|
||||
|
||||
@state() private _componentLoaded?: boolean;
|
||||
|
||||
@query("entity-registry-settings-editor")
|
||||
private _registryEditor?: EntityRegistrySettingsEditor;
|
||||
|
||||
private _originalItemJson?: string;
|
||||
|
||||
protected firstUpdated(changedProperties: PropertyValues<this>) {
|
||||
super.firstUpdated(changedProperties);
|
||||
this._componentLoaded = isComponentLoaded(
|
||||
@@ -120,7 +124,9 @@ export class EntitySettingsHelperTab extends LitElement {
|
||||
</ha-button>
|
||||
<ha-button
|
||||
@click=${this._updateItem}
|
||||
.disabled=${!!this._submitting || !!(this._item && !this._item.name)}
|
||||
.disabled=${!this._dirty ||
|
||||
!!this._submitting ||
|
||||
!!(this._item && !this._item.name)}
|
||||
>
|
||||
${this.hass.localize("ui.dialogs.entity_registry.editor.update")}
|
||||
</ha-button>
|
||||
@@ -128,8 +134,18 @@ export class EntitySettingsHelperTab extends LitElement {
|
||||
`;
|
||||
}
|
||||
|
||||
private get _isHelperDirty(): boolean {
|
||||
if (!this._item || !this._originalItemJson) return false;
|
||||
return JSON.stringify(this._item) !== this._originalItemJson;
|
||||
}
|
||||
|
||||
private _updateDirty() {
|
||||
this._dirty = (this._registryEditor?.dirty ?? false) || this._isHelperDirty;
|
||||
}
|
||||
|
||||
private _entityRegistryChanged() {
|
||||
this._error = undefined;
|
||||
this._updateDirty();
|
||||
}
|
||||
|
||||
private _valueChanged(ev: CustomEvent): void {
|
||||
@@ -138,11 +154,15 @@ export class EntitySettingsHelperTab extends LitElement {
|
||||
}
|
||||
this._error = undefined;
|
||||
this._item = ev.detail.value;
|
||||
this._updateDirty();
|
||||
}
|
||||
|
||||
private async _getItem() {
|
||||
const items = await HELPERS_CRUD[this.entry.platform].fetch(this.hass!);
|
||||
this._item = items.find((item) => item.id === this.entry.unique_id) || null;
|
||||
this._originalItemJson = this._item
|
||||
? JSON.stringify(this._item)
|
||||
: undefined;
|
||||
}
|
||||
|
||||
private async _updateItem(): Promise<void> {
|
||||
|
||||
@@ -208,6 +208,34 @@ export class EntityRegistrySettingsEditor extends LitElement {
|
||||
|
||||
private _deviceClassOptions?: string[][];
|
||||
|
||||
private _initialStateJson!: string;
|
||||
|
||||
private _lastDirty = false;
|
||||
|
||||
private _currentState() {
|
||||
return {
|
||||
name: this._name.trim() || null,
|
||||
icon: this._icon.trim() || null,
|
||||
entityId: this._entityId.trim(),
|
||||
areaId: this._areaId ?? null,
|
||||
labels: this._labels ?? [],
|
||||
deviceClass: this._deviceClass,
|
||||
disabledBy: this._disabledBy,
|
||||
hiddenBy: this._hiddenBy,
|
||||
unitOfMeasurement: this._unit_of_measurement,
|
||||
precision: this._precision,
|
||||
defaultCode: this._defaultCode,
|
||||
calendarColor: this._calendarColor ?? null,
|
||||
precipitationUnit: this._precipitation_unit,
|
||||
pressureUnit: this._pressure_unit,
|
||||
temperatureUnit: this._temperature_unit,
|
||||
visibilityUnit: this._visibility_unit,
|
||||
windSpeedUnit: this._wind_speed_unit,
|
||||
switchAsDomain: this._switchAsDomain,
|
||||
switchAsInvert: this._switchAsInvert,
|
||||
};
|
||||
}
|
||||
|
||||
protected willUpdate(changedProperties: PropertyValues<this>) {
|
||||
super.willUpdate(changedProperties);
|
||||
if (
|
||||
@@ -274,6 +302,9 @@ export class EntityRegistrySettingsEditor extends LitElement {
|
||||
this._wind_speed_unit = stateObj?.attributes?.wind_speed_unit;
|
||||
}
|
||||
|
||||
this._initialStateJson = JSON.stringify(this._currentState());
|
||||
this._lastDirty = false;
|
||||
|
||||
const deviceClasses: string[][] = OVERRIDE_DEVICE_CLASSES[domain];
|
||||
|
||||
if (!deviceClasses || this._hideDeviceClassOverride(domain)) {
|
||||
@@ -372,6 +403,16 @@ export class EntityRegistrySettingsEditor extends LitElement {
|
||||
this._switchAsDomain = "switch";
|
||||
this._switchAsInvert = false;
|
||||
}
|
||||
this._initialStateJson = JSON.stringify(this._currentState());
|
||||
this._lastDirty = false;
|
||||
}
|
||||
|
||||
if (this._initialStateJson) {
|
||||
const dirty = this.dirty;
|
||||
if (dirty !== this._lastDirty) {
|
||||
this._lastDirty = dirty;
|
||||
fireEvent(this, "change");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -407,6 +448,23 @@ export class EntityRegistrySettingsEditor extends LitElement {
|
||||
.disabled=${this.disabled}
|
||||
@input=${this._nameChanged}
|
||||
>
|
||||
${this._device
|
||||
? html`<span slot="hint"
|
||||
>${this.hass.localize(
|
||||
"ui.dialogs.entity_registry.editor.device_name_tip",
|
||||
{
|
||||
link: html`<button
|
||||
class="link"
|
||||
@click=${this._resetNameAndOpenDeviceSettings}
|
||||
>
|
||||
${this.hass.localize(
|
||||
"ui.dialogs.entity_registry.editor.open_device_settings"
|
||||
)}
|
||||
</button>`,
|
||||
}
|
||||
)}</span
|
||||
>`
|
||||
: nothing}
|
||||
</ha-input>`}
|
||||
${this.hideIcon
|
||||
? nothing
|
||||
@@ -1060,6 +1118,10 @@ export class EntityRegistrySettingsEditor extends LitElement {
|
||||
`;
|
||||
}
|
||||
|
||||
public get dirty(): boolean {
|
||||
return JSON.stringify(this._currentState()) !== this._initialStateJson;
|
||||
}
|
||||
|
||||
public async updateEntry(): Promise<{
|
||||
close: boolean;
|
||||
entry: ExtEntityRegistryEntry;
|
||||
@@ -1518,6 +1580,13 @@ export class EntityRegistrySettingsEditor extends LitElement {
|
||||
}
|
||||
}
|
||||
|
||||
private _resetNameAndOpenDeviceSettings() {
|
||||
this._name = this.entry.name || "";
|
||||
fireEvent(this, "change");
|
||||
|
||||
this._openDeviceSettings();
|
||||
}
|
||||
|
||||
private _openDeviceSettings() {
|
||||
showDeviceRegistryDetailDialog(this, {
|
||||
device: this._device!,
|
||||
|
||||
@@ -44,6 +44,8 @@ export class EntityRegistrySettings extends SubscribeMixin(LitElement) {
|
||||
|
||||
@state() private _submitting?: boolean;
|
||||
|
||||
@state() private _dirty = false;
|
||||
|
||||
@query("entity-registry-settings-editor")
|
||||
private _registryEditor?: EntityRegistrySettingsEditor;
|
||||
|
||||
@@ -144,7 +146,11 @@ export class EntityRegistrySettings extends SubscribeMixin(LitElement) {
|
||||
>
|
||||
${this.hass.localize("ui.dialogs.entity_registry.editor.delete")}
|
||||
</ha-button>
|
||||
<ha-button @click=${this._updateEntry} .loading=${!!this._submitting}>
|
||||
<ha-button
|
||||
@click=${this._updateEntry}
|
||||
.disabled=${!this._dirty || !!this._submitting}
|
||||
.loading=${!!this._submitting}
|
||||
>
|
||||
${this.hass.localize("ui.dialogs.entity_registry.editor.update")}
|
||||
</ha-button>
|
||||
</div>
|
||||
@@ -153,6 +159,7 @@ export class EntityRegistrySettings extends SubscribeMixin(LitElement) {
|
||||
|
||||
private _entityRegistryChanged() {
|
||||
this._error = undefined;
|
||||
this._dirty = this._registryEditor?.dirty ?? false;
|
||||
}
|
||||
|
||||
private _openDeviceSettings() {
|
||||
|
||||
@@ -1958,6 +1958,7 @@
|
||||
"entity_disabled": "This entity is disabled.",
|
||||
"enable_entity": "Enable",
|
||||
"open_device_settings": "Open device settings",
|
||||
"device_name_tip": "Consider renaming the device instead to update all its entities at once. {link}",
|
||||
"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.",
|
||||
"switch_as_x_remove_confirm": "This {domain} will be removed and the original switch will be visible again. Your existing configurations using the {domain} will no longer work!",
|
||||
"switch_as_x_change_confirm": "This {domain_1} will be removed and will be replaced by a new {domain_2}. Your existing configurations using the {domain_1} will no longer work!",
|
||||
|
||||
Reference in New Issue
Block a user