mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-31 05:06:38 +00:00
Merge branch 'dev' of github.com:home-assistant/frontend into ha-button
This commit is contained in:
commit
542982f55d
@ -1,7 +1,30 @@
|
|||||||
import type { MockHomeAssistant } from "../../../src/fake_data/provide_hass";
|
import type { MockHomeAssistant } from "../../../src/fake_data/provide_hass";
|
||||||
|
|
||||||
|
let changeFunction;
|
||||||
|
|
||||||
export const mockFrontend = (hass: MockHomeAssistant) => {
|
export const mockFrontend = (hass: MockHomeAssistant) => {
|
||||||
hass.mockWS("frontend/get_user_data", () => ({
|
hass.mockWS("frontend/get_user_data", () => ({
|
||||||
value: null,
|
value: null,
|
||||||
}));
|
}));
|
||||||
|
hass.mockWS("frontend/set_user_data", ({ key, value }) => {
|
||||||
|
if (key === "sidebar") {
|
||||||
|
changeFunction?.({
|
||||||
|
value: {
|
||||||
|
panelOrder: value.panelOrder || [],
|
||||||
|
hiddenPanels: value.hiddenPanels || [],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
hass.mockWS("frontend/subscribe_user_data", (_msg, _hass, onChange) => {
|
||||||
|
changeFunction = onChange;
|
||||||
|
onChange?.({
|
||||||
|
value: {
|
||||||
|
panelOrder: [],
|
||||||
|
hiddenPanels: [],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
||||||
|
return () => {};
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
@ -262,7 +262,7 @@ export class HaItemDisplayEditor extends LitElement {
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
return items.sort((a, b) =>
|
return visibleItems.sort((a, b) =>
|
||||||
a.disableSorting && !b.disableSorting ? -1 : compare(a.value, b.value)
|
a.disableSorting && !b.disableSorting ? -1 : compare(a.value, b.value)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -368,7 +368,7 @@ class HaSidebar extends SubscribeMixin(LitElement) {
|
|||||||
if (!this._panelOrder || !this._hiddenPanels) {
|
if (!this._panelOrder || !this._hiddenPanels) {
|
||||||
return html`
|
return html`
|
||||||
<ha-fade-in .delay=${500}
|
<ha-fade-in .delay=${500}
|
||||||
><ha-spinner size="large"></ha-spinner
|
><ha-spinner size="small"></ha-spinner
|
||||||
></ha-fade-in>
|
></ha-fade-in>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
@ -2,12 +2,12 @@ import type { Connection } from "home-assistant-js-websocket";
|
|||||||
import { createCollection } from "home-assistant-js-websocket";
|
import { createCollection } from "home-assistant-js-websocket";
|
||||||
import type { Store } from "home-assistant-js-websocket/dist/store";
|
import type { Store } from "home-assistant-js-websocket/dist/store";
|
||||||
import memoizeOne from "memoize-one";
|
import memoizeOne from "memoize-one";
|
||||||
|
import { computeDomain } from "../common/entity/compute_domain";
|
||||||
import { computeStateName } from "../common/entity/compute_state_name";
|
import { computeStateName } from "../common/entity/compute_state_name";
|
||||||
import { caseInsensitiveStringCompare } from "../common/string/compare";
|
import { caseInsensitiveStringCompare } from "../common/string/compare";
|
||||||
import { debounce } from "../common/util/debounce";
|
import { debounce } from "../common/util/debounce";
|
||||||
import type { HomeAssistant } from "../types";
|
import type { HomeAssistant } from "../types";
|
||||||
import type { LightColor } from "./light";
|
import type { LightColor } from "./light";
|
||||||
import { computeDomain } from "../common/entity/compute_domain";
|
|
||||||
import type { RegistryEntry } from "./registry";
|
import type { RegistryEntry } from "./registry";
|
||||||
|
|
||||||
type EntityCategory = "config" | "diagnostic";
|
type EntityCategory = "config" | "diagnostic";
|
||||||
@ -315,3 +315,12 @@ export const getEntityPlatformLookup = (
|
|||||||
}
|
}
|
||||||
return entityLookup;
|
return entityLookup;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const getAutomaticEntityIds = (
|
||||||
|
hass: HomeAssistant,
|
||||||
|
entity_ids: string[]
|
||||||
|
) =>
|
||||||
|
hass.callWS<Record<string, string | null>>({
|
||||||
|
type: "config/entity_registry/get_automatic_entity_ids",
|
||||||
|
entity_ids,
|
||||||
|
});
|
||||||
|
@ -640,6 +640,12 @@ export const mergeHistoryResults = (
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (const item of ltsResult.line) {
|
for (const item of ltsResult.line) {
|
||||||
|
if (item.unit === BLANK_UNIT) {
|
||||||
|
// disabled entities have no unit, so we need to find the unit from the history result
|
||||||
|
item.unit =
|
||||||
|
historyResult.line.find((line) => line.identifier === item.identifier)
|
||||||
|
?.unit ?? BLANK_UNIT;
|
||||||
|
}
|
||||||
const key = computeGroupKey(
|
const key = computeGroupKey(
|
||||||
item.unit,
|
item.unit,
|
||||||
item.device_class,
|
item.device_class,
|
||||||
|
129
src/data/regenerate_entity_ids.ts
Normal file
129
src/data/regenerate_entity_ids.ts
Normal file
@ -0,0 +1,129 @@
|
|||||||
|
import { html, nothing } from "lit";
|
||||||
|
import {
|
||||||
|
showAlertDialog,
|
||||||
|
showConfirmationDialog,
|
||||||
|
} from "../dialogs/generic/show-dialog-box";
|
||||||
|
import type { HomeAssistant } from "../types";
|
||||||
|
import {
|
||||||
|
getAutomaticEntityIds,
|
||||||
|
updateEntityRegistryEntry,
|
||||||
|
} from "./entity_registry";
|
||||||
|
import "../components/ha-expansion-panel";
|
||||||
|
|
||||||
|
export const regenerateEntityIds = async (
|
||||||
|
element: HTMLElement,
|
||||||
|
hass: HomeAssistant,
|
||||||
|
entities: string[]
|
||||||
|
): Promise<void> => {
|
||||||
|
const entityIdsMapping = await getAutomaticEntityIds(hass, entities);
|
||||||
|
|
||||||
|
const entityIdsEntries = Object.entries(entityIdsMapping);
|
||||||
|
|
||||||
|
const dialogRename = entityIdsEntries
|
||||||
|
.filter(([oldId, newId]) => newId && oldId !== newId)
|
||||||
|
.map(
|
||||||
|
([oldId, newId]) =>
|
||||||
|
html`<tr>
|
||||||
|
<td>${oldId}</td>
|
||||||
|
<td>${newId}</td>
|
||||||
|
</tr>`
|
||||||
|
);
|
||||||
|
const dialogCantRename = entityIdsEntries
|
||||||
|
.filter(([_oldId, newId]) => newId === null)
|
||||||
|
.map(([oldId]) => html`<li>${oldId}</li>`);
|
||||||
|
const dialogNoRename = entityIdsEntries
|
||||||
|
.filter(([oldId, newId]) => oldId === newId)
|
||||||
|
.map(([oldId]) => html`<li>${oldId}</li>`);
|
||||||
|
if (dialogRename.length) {
|
||||||
|
showConfirmationDialog(element, {
|
||||||
|
title: hass.localize(
|
||||||
|
"ui.dialogs.recreate_entity_ids.confirm_rename_title"
|
||||||
|
),
|
||||||
|
text: html`${hass.localize(
|
||||||
|
"ui.dialogs.recreate_entity_ids.confirm_rename_warning"
|
||||||
|
)} <br /><br />
|
||||||
|
<ha-expansion-panel outlined>
|
||||||
|
<span slot="header"
|
||||||
|
>${hass.localize("ui.dialogs.recreate_entity_ids.will_rename", {
|
||||||
|
count: dialogRename.length,
|
||||||
|
})}</span
|
||||||
|
>
|
||||||
|
<div style="overflow: auto;">
|
||||||
|
<table style="width: 100%; text-align: var(--float-start);">
|
||||||
|
<tr>
|
||||||
|
<th>${hass.localize("ui.dialogs.recreate_entity_ids.old")}</th>
|
||||||
|
<th>${hass.localize("ui.dialogs.recreate_entity_ids.new")}</th>
|
||||||
|
</tr>
|
||||||
|
${dialogRename}
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</ha-expansion-panel>
|
||||||
|
${dialogCantRename.length
|
||||||
|
? html`<ha-expansion-panel outlined style="margin-top: 8px;">
|
||||||
|
<span slot="header"
|
||||||
|
>${hass.localize("ui.dialogs.recreate_entity_ids.cant_rename", {
|
||||||
|
count: dialogCantRename.length,
|
||||||
|
})}</span
|
||||||
|
>
|
||||||
|
${dialogCantRename}
|
||||||
|
</ha-expansion-panel>`
|
||||||
|
: nothing}
|
||||||
|
${dialogNoRename.length
|
||||||
|
? html`<ha-expansion-panel outlined style="margin-top: 8px;">
|
||||||
|
<span slot="header"
|
||||||
|
>${hass.localize("ui.dialogs.recreate_entity_ids.wont_change", {
|
||||||
|
count: dialogNoRename.length,
|
||||||
|
})}</span
|
||||||
|
>
|
||||||
|
${dialogNoRename}
|
||||||
|
</ha-expansion-panel>`
|
||||||
|
: nothing}`,
|
||||||
|
confirmText: hass.localize("ui.common.update"),
|
||||||
|
dismissText: hass.localize("ui.common.cancel"),
|
||||||
|
destructive: true,
|
||||||
|
confirm: () => {
|
||||||
|
entityIdsEntries
|
||||||
|
.filter(([oldId, newId]) => newId && oldId !== newId)
|
||||||
|
.forEach(([oldEntityId, newEntityId]) =>
|
||||||
|
updateEntityRegistryEntry(hass, oldEntityId, {
|
||||||
|
new_entity_id: newEntityId!,
|
||||||
|
}).catch((err: any) => {
|
||||||
|
showAlertDialog(element, {
|
||||||
|
title: hass.localize(
|
||||||
|
"ui.dialogs.recreate_entity_ids.update_entity_error",
|
||||||
|
{ entityId: oldEntityId }
|
||||||
|
),
|
||||||
|
text: err.message,
|
||||||
|
});
|
||||||
|
})
|
||||||
|
);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
showAlertDialog(element, {
|
||||||
|
title: hass.localize(
|
||||||
|
"ui.dialogs.recreate_entity_ids.confirm_no_renamable_entity_ids"
|
||||||
|
),
|
||||||
|
text: html`${dialogCantRename.length
|
||||||
|
? html`<ha-expansion-panel outlined style="margin-top: 8px;">
|
||||||
|
<span slot="header"
|
||||||
|
>${hass.localize("ui.dialogs.recreate_entity_ids.cant_rename", {
|
||||||
|
count: dialogCantRename.length,
|
||||||
|
})}</span
|
||||||
|
>
|
||||||
|
${dialogCantRename}
|
||||||
|
</ha-expansion-panel>`
|
||||||
|
: nothing}
|
||||||
|
${dialogNoRename.length
|
||||||
|
? html`<ha-expansion-panel outlined style="margin-top: 8px;">
|
||||||
|
<span slot="header"
|
||||||
|
>${hass.localize("ui.dialogs.recreate_entity_ids.wont_change", {
|
||||||
|
count: dialogNoRename.length,
|
||||||
|
})}</span
|
||||||
|
>
|
||||||
|
${dialogNoRename}
|
||||||
|
</ha-expansion-panel>`
|
||||||
|
: nothing}`,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
@ -9,7 +9,6 @@ import {
|
|||||||
} from "../../common/entity/compute_device_name";
|
} from "../../common/entity/compute_device_name";
|
||||||
import { computeDomain } from "../../common/entity/compute_domain";
|
import { computeDomain } from "../../common/entity/compute_domain";
|
||||||
import { navigate } from "../../common/navigate";
|
import { navigate } from "../../common/navigate";
|
||||||
import { slugify } from "../../common/string/slugify";
|
|
||||||
import "../../components/ha-area-picker";
|
import "../../components/ha-area-picker";
|
||||||
import "../../components/ha-button";
|
import "../../components/ha-button";
|
||||||
import { assistSatelliteSupportsSetupFlow } from "../../data/assist_satellite";
|
import { assistSatelliteSupportsSetupFlow } from "../../data/assist_satellite";
|
||||||
@ -17,6 +16,7 @@ import type { DataEntryFlowStepCreateEntry } from "../../data/data_entry_flow";
|
|||||||
import type { DeviceRegistryEntry } from "../../data/device_registry";
|
import type { DeviceRegistryEntry } from "../../data/device_registry";
|
||||||
import { updateDeviceRegistryEntry } from "../../data/device_registry";
|
import { updateDeviceRegistryEntry } from "../../data/device_registry";
|
||||||
import {
|
import {
|
||||||
|
getAutomaticEntityIds,
|
||||||
updateEntityRegistryEntry,
|
updateEntityRegistryEntry,
|
||||||
type EntityRegistryDisplayEntry,
|
type EntityRegistryDisplayEntry,
|
||||||
} from "../../data/entity_registry";
|
} from "../../data/entity_registry";
|
||||||
@ -182,19 +182,11 @@ class StepFlowCreateEntry extends LitElement {
|
|||||||
|
|
||||||
private async _flowDone(): Promise<void> {
|
private async _flowDone(): Promise<void> {
|
||||||
if (Object.keys(this._deviceUpdate).length) {
|
if (Object.keys(this._deviceUpdate).length) {
|
||||||
const renamedDevices: {
|
const renamedDevices: string[] = [];
|
||||||
deviceId: string;
|
|
||||||
oldDeviceName: string | null | undefined;
|
|
||||||
newDeviceName: string;
|
|
||||||
}[] = [];
|
|
||||||
const deviceUpdates = Object.entries(this._deviceUpdate).map(
|
const deviceUpdates = Object.entries(this._deviceUpdate).map(
|
||||||
([deviceId, update]) => {
|
([deviceId, update]) => {
|
||||||
if (update.name) {
|
if (update.name) {
|
||||||
renamedDevices.push({
|
renamedDevices.push(deviceId);
|
||||||
deviceId,
|
|
||||||
oldDeviceName: computeDeviceName(this.hass.devices[deviceId]),
|
|
||||||
newDeviceName: update.name,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
return updateDeviceRegistryEntry(this.hass, deviceId, {
|
return updateDeviceRegistryEntry(this.hass, deviceId, {
|
||||||
name_by_user: update.name,
|
name_by_user: update.name,
|
||||||
@ -209,38 +201,36 @@ class StepFlowCreateEntry extends LitElement {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
await Promise.allSettled(deviceUpdates);
|
||||||
const entityUpdates: Promise<any>[] = [];
|
const entityUpdates: Promise<any>[] = [];
|
||||||
renamedDevices.forEach(({ deviceId, oldDeviceName, newDeviceName }) => {
|
const entityIds: string[] = [];
|
||||||
if (!oldDeviceName) {
|
renamedDevices.forEach((deviceId) => {
|
||||||
return;
|
|
||||||
}
|
|
||||||
const entities = this._deviceEntities(
|
const entities = this._deviceEntities(
|
||||||
deviceId,
|
deviceId,
|
||||||
Object.values(this.hass.entities)
|
Object.values(this.hass.entities)
|
||||||
);
|
);
|
||||||
const oldDeviceSlug = slugify(oldDeviceName);
|
entityIds.push(...entities.map((entity) => entity.entity_id));
|
||||||
const newDeviceSlug = slugify(newDeviceName);
|
|
||||||
entities.forEach((entity) => {
|
|
||||||
const oldId = entity.entity_id;
|
|
||||||
|
|
||||||
if (oldId.includes(oldDeviceSlug)) {
|
|
||||||
const newEntityId = oldId.replace(oldDeviceSlug, newDeviceSlug);
|
|
||||||
entityUpdates.push(
|
|
||||||
updateEntityRegistryEntry(this.hass, entity.entity_id, {
|
|
||||||
new_entity_id: newEntityId,
|
|
||||||
}).catch((err) =>
|
|
||||||
showAlertDialog(this, {
|
|
||||||
text: this.hass.localize(
|
|
||||||
"ui.panel.config.integrations.config_flow.error_saving_entity",
|
|
||||||
{ error: err.message }
|
|
||||||
),
|
|
||||||
})
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
await Promise.allSettled([...deviceUpdates, ...entityUpdates]);
|
|
||||||
|
const entityIdsMapping = getAutomaticEntityIds(this.hass, entityIds);
|
||||||
|
|
||||||
|
Object.entries(entityIdsMapping).forEach(([oldEntityId, newEntityId]) => {
|
||||||
|
if (newEntityId) {
|
||||||
|
entityUpdates.push(
|
||||||
|
updateEntityRegistryEntry(this.hass, oldEntityId, {
|
||||||
|
new_entity_id: newEntityId,
|
||||||
|
}).catch((err) =>
|
||||||
|
showAlertDialog(this, {
|
||||||
|
text: this.hass.localize(
|
||||||
|
"ui.panel.config.integrations.config_flow.error_saving_entity",
|
||||||
|
{ error: err.message }
|
||||||
|
),
|
||||||
|
})
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
await Promise.allSettled(entityUpdates);
|
||||||
}
|
}
|
||||||
|
|
||||||
fireEvent(this, "flow-update", { step: undefined });
|
fireEvent(this, "flow-update", { step: undefined });
|
||||||
|
@ -222,7 +222,6 @@ export class DialogEnterCode
|
|||||||
grid-column-start: 6;
|
grid-column-start: 6;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ha-control-button {
|
ha-control-button {
|
||||||
width: 56px;
|
width: 56px;
|
||||||
height: 56px;
|
height: 56px;
|
||||||
@ -238,12 +237,6 @@ export class DialogEnterCode
|
|||||||
--control-button-background-color: var(--red-color);
|
--control-button-background-color: var(--red-color);
|
||||||
--control-button-icon-color: var(--red-color);
|
--control-button-icon-color: var(--red-color);
|
||||||
}
|
}
|
||||||
.hidden {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
.buttons {
|
|
||||||
margin-top: 12px;
|
|
||||||
}
|
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,6 +8,7 @@ import {
|
|||||||
mdiOpenInNew,
|
mdiOpenInNew,
|
||||||
mdiPencil,
|
mdiPencil,
|
||||||
mdiPlusCircle,
|
mdiPlusCircle,
|
||||||
|
mdiRestore,
|
||||||
} from "@mdi/js";
|
} from "@mdi/js";
|
||||||
import type { CSSResultGroup, TemplateResult } from "lit";
|
import type { CSSResultGroup, TemplateResult } from "lit";
|
||||||
import { LitElement, css, html, nothing } from "lit";
|
import { LitElement, css, html, nothing } from "lit";
|
||||||
@ -22,13 +23,11 @@ import { computeEntityEntryName } from "../../../common/entity/compute_entity_na
|
|||||||
import { computeStateDomain } from "../../../common/entity/compute_state_domain";
|
import { computeStateDomain } from "../../../common/entity/compute_state_domain";
|
||||||
import { computeStateName } from "../../../common/entity/compute_state_name";
|
import { computeStateName } from "../../../common/entity/compute_state_name";
|
||||||
import { stringCompare } from "../../../common/string/compare";
|
import { stringCompare } from "../../../common/string/compare";
|
||||||
import { slugify } from "../../../common/string/slugify";
|
|
||||||
import { groupBy } from "../../../common/util/group-by";
|
import { groupBy } from "../../../common/util/group-by";
|
||||||
import "../../../components/entity/ha-battery-icon";
|
import "../../../components/entity/ha-battery-icon";
|
||||||
import "../../../components/ha-alert";
|
import "../../../components/ha-alert";
|
||||||
import "../../../components/ha-button-menu";
|
|
||||||
import "../../../components/ha-button";
|
import "../../../components/ha-button";
|
||||||
import "../../../components/ha-expansion-panel";
|
import "../../../components/ha-button-menu";
|
||||||
import "../../../components/ha-icon-button";
|
import "../../../components/ha-icon-button";
|
||||||
import "../../../components/ha-icon-next";
|
import "../../../components/ha-icon-next";
|
||||||
import "../../../components/ha-list-item";
|
import "../../../components/ha-list-item";
|
||||||
@ -64,6 +63,7 @@ import {
|
|||||||
} from "../../../data/entity_registry";
|
} from "../../../data/entity_registry";
|
||||||
import type { IntegrationManifest } from "../../../data/integration";
|
import type { IntegrationManifest } from "../../../data/integration";
|
||||||
import { domainToName } from "../../../data/integration";
|
import { domainToName } from "../../../data/integration";
|
||||||
|
import { regenerateEntityIds } from "../../../data/regenerate_entity_ids";
|
||||||
import type { SceneEntities } from "../../../data/scene";
|
import type { SceneEntities } from "../../../data/scene";
|
||||||
import { showSceneEditor } from "../../../data/scene";
|
import { showSceneEditor } from "../../../data/scene";
|
||||||
import type { RelatedResult } from "../../../data/search";
|
import type { RelatedResult } from "../../../data/search";
|
||||||
@ -406,7 +406,11 @@ export class HaConfigDevicePage extends LitElement {
|
|||||||
${device.disabled_by === "user"
|
${device.disabled_by === "user"
|
||||||
? html`
|
? html`
|
||||||
<div class="card-actions" slot="actions">
|
<div class="card-actions" slot="actions">
|
||||||
<ha-button @click=${this._enableDevice}>
|
<ha-button
|
||||||
|
variant="warning"
|
||||||
|
size="small"
|
||||||
|
@click=${this._enableDevice}
|
||||||
|
>
|
||||||
${this.hass.localize("ui.common.enable")}
|
${this.hass.localize("ui.common.enable")}
|
||||||
</ha-button>
|
</ha-button>
|
||||||
</div>
|
</div>
|
||||||
@ -664,7 +668,7 @@ export class HaConfigDevicePage extends LitElement {
|
|||||||
`
|
`
|
||||||
: "";
|
: "";
|
||||||
|
|
||||||
return html` <hass-subpage
|
return html`<hass-subpage
|
||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
.narrow=${this.narrow}
|
.narrow=${this.narrow}
|
||||||
.header=${deviceName}
|
.header=${deviceName}
|
||||||
@ -675,6 +679,21 @@ export class HaConfigDevicePage extends LitElement {
|
|||||||
@click=${this._showSettings}
|
@click=${this._showSettings}
|
||||||
.label=${this.hass.localize("ui.panel.config.devices.edit_settings")}
|
.label=${this.hass.localize("ui.panel.config.devices.edit_settings")}
|
||||||
></ha-icon-button>
|
></ha-icon-button>
|
||||||
|
<ha-md-button-menu slot="toolbar-icon">
|
||||||
|
<ha-icon-button
|
||||||
|
slot="trigger"
|
||||||
|
.label=${this.hass.localize("ui.common.menu")}
|
||||||
|
.path=${mdiDotsVertical}
|
||||||
|
></ha-icon-button>
|
||||||
|
|
||||||
|
<ha-md-menu-item .clickAction=${this._resetEntityIds}>
|
||||||
|
<ha-svg-icon slot="start" .path=${mdiRestore}></ha-svg-icon>
|
||||||
|
<div slot="headline">
|
||||||
|
${this.hass.localize("ui.panel.config.devices.restore_entity_ids")}
|
||||||
|
</div>
|
||||||
|
</ha-md-menu-item>
|
||||||
|
</ha-md-button-menu>
|
||||||
|
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="header fullwidth">
|
<div class="header fullwidth">
|
||||||
${area
|
${area
|
||||||
@ -744,39 +763,35 @@ export class HaConfigDevicePage extends LitElement {
|
|||||||
? html`
|
? html`
|
||||||
<div class="card-actions" slot="actions">
|
<div class="card-actions" slot="actions">
|
||||||
<div>
|
<div>
|
||||||
<a
|
<ha-button
|
||||||
href=${ifDefined(firstDeviceAction!.href)}
|
href=${ifDefined(firstDeviceAction!.href)}
|
||||||
rel=${ifDefined(
|
rel=${ifDefined(
|
||||||
firstDeviceAction!.target ? "noreferrer" : undefined
|
firstDeviceAction!.target ? "noreferrer" : undefined
|
||||||
)}
|
)}
|
||||||
target=${ifDefined(firstDeviceAction!.target)}
|
target=${ifDefined(firstDeviceAction!.target)}
|
||||||
|
class=${ifDefined(firstDeviceAction!.classes)}
|
||||||
|
.action=${firstDeviceAction!.action}
|
||||||
|
@click=${this._deviceActionClicked}
|
||||||
>
|
>
|
||||||
<ha-button
|
${firstDeviceAction!.label}
|
||||||
class=${ifDefined(firstDeviceAction!.classes)}
|
${firstDeviceAction!.icon
|
||||||
.action=${firstDeviceAction!.action}
|
? html`
|
||||||
@click=${this._deviceActionClicked}
|
<ha-svg-icon
|
||||||
graphic="icon"
|
class=${ifDefined(firstDeviceAction!.classes)}
|
||||||
>
|
.path=${firstDeviceAction!.icon}
|
||||||
${firstDeviceAction!.label}
|
slot="prefix"
|
||||||
${firstDeviceAction!.icon
|
></ha-svg-icon>
|
||||||
? html`
|
`
|
||||||
<ha-svg-icon
|
: nothing}
|
||||||
class=${ifDefined(firstDeviceAction!.classes)}
|
${firstDeviceAction!.trailingIcon
|
||||||
.path=${firstDeviceAction!.icon}
|
? html`
|
||||||
slot="graphic"
|
<ha-svg-icon
|
||||||
></ha-svg-icon>
|
.path=${firstDeviceAction!.trailingIcon}
|
||||||
`
|
slot="suffix"
|
||||||
: ""}
|
></ha-svg-icon>
|
||||||
${firstDeviceAction!.trailingIcon
|
`
|
||||||
? html`
|
: nothing}
|
||||||
<ha-svg-icon
|
</ha-button>
|
||||||
.path=${firstDeviceAction!.trailingIcon}
|
|
||||||
slot="trailingIcon"
|
|
||||||
></ha-svg-icon>
|
|
||||||
`
|
|
||||||
: ""}
|
|
||||||
</ha-button>
|
|
||||||
</a>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
${actions.length
|
${actions.length
|
||||||
@ -1256,7 +1271,14 @@ export class HaConfigDevicePage extends LitElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async _showSettings() {
|
private _resetEntityIds = () => {
|
||||||
|
const entities = this._entities(this.deviceId, this._entityReg).map(
|
||||||
|
(e) => e.entity_id
|
||||||
|
);
|
||||||
|
regenerateEntityIds(this, this.hass, entities);
|
||||||
|
};
|
||||||
|
|
||||||
|
private _showSettings = async () => {
|
||||||
const device = this.hass.devices[this.deviceId];
|
const device = this.hass.devices[this.deviceId];
|
||||||
showDeviceRegistryDetailDialog(this, {
|
showDeviceRegistryDetailDialog(this, {
|
||||||
device,
|
device,
|
||||||
@ -1342,153 +1364,34 @@ export class HaConfigDevicePage extends LitElement {
|
|||||||
}
|
}
|
||||||
const entities = this._entities(this.deviceId, this._entityReg);
|
const entities = this._entities(this.deviceId, this._entityReg);
|
||||||
|
|
||||||
let renameEntityid = false;
|
|
||||||
let entityIdRenames: { oldId: string; newId?: string }[] = [];
|
|
||||||
|
|
||||||
if (this.showAdvanced) {
|
|
||||||
const oldDeviceSlug = slugify(oldDeviceName);
|
|
||||||
const newDeviceSlug = slugify(newDeviceName);
|
|
||||||
entityIdRenames = entities.map((entity) => {
|
|
||||||
const oldId = entity.entity_id;
|
|
||||||
if (oldId.includes(oldDeviceSlug)) {
|
|
||||||
const newId = oldId.replace(oldDeviceSlug, newDeviceSlug);
|
|
||||||
return { oldId, newId };
|
|
||||||
}
|
|
||||||
return { oldId };
|
|
||||||
});
|
|
||||||
|
|
||||||
const dialogRenames = entityIdRenames
|
|
||||||
.filter((entity) => entity.newId)
|
|
||||||
.map(
|
|
||||||
(entity) =>
|
|
||||||
html`<tr>
|
|
||||||
<td>${entity.oldId}</td>
|
|
||||||
<td>${entity.newId}</td>
|
|
||||||
</tr>`
|
|
||||||
);
|
|
||||||
const dialogNoRenames = entityIdRenames
|
|
||||||
.filter((entity) => !entity.newId)
|
|
||||||
.map((entity) => html`<li>${entity.oldId}</li>`);
|
|
||||||
|
|
||||||
if (dialogRenames.length) {
|
|
||||||
renameEntityid = await showConfirmationDialog(this, {
|
|
||||||
title: this.hass.localize(
|
|
||||||
"ui.panel.config.devices.confirm_rename_entity_ids"
|
|
||||||
),
|
|
||||||
text: html`${this.hass.localize(
|
|
||||||
"ui.panel.config.devices.confirm_rename_entity_ids_warning"
|
|
||||||
)} <br /><br />
|
|
||||||
<ha-expansion-panel outlined>
|
|
||||||
<span slot="header"
|
|
||||||
>${this.hass.localize(
|
|
||||||
"ui.panel.config.devices.confirm_rename_entity_will_rename",
|
|
||||||
{ count: dialogRenames.length }
|
|
||||||
)}</span
|
|
||||||
>
|
|
||||||
<div style="overflow: auto;">
|
|
||||||
<table style="width: 100%; text-align: var(--float-start);">
|
|
||||||
<tr>
|
|
||||||
<th>
|
|
||||||
${this.hass.localize(
|
|
||||||
"ui.panel.config.devices.confirm_rename_old"
|
|
||||||
)}
|
|
||||||
</th>
|
|
||||||
<th>
|
|
||||||
${this.hass.localize(
|
|
||||||
"ui.panel.config.devices.confirm_rename_new"
|
|
||||||
)}
|
|
||||||
</th>
|
|
||||||
</tr>
|
|
||||||
${dialogRenames}
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</ha-expansion-panel>
|
|
||||||
${dialogNoRenames.length
|
|
||||||
? html`<ha-expansion-panel outlined>
|
|
||||||
<span slot="header"
|
|
||||||
>${this.hass.localize(
|
|
||||||
"ui.panel.config.devices.confirm_rename_entity_wont_rename",
|
|
||||||
{
|
|
||||||
count: dialogNoRenames.length,
|
|
||||||
deviceSlug: oldDeviceSlug,
|
|
||||||
}
|
|
||||||
)}</span
|
|
||||||
>
|
|
||||||
${dialogNoRenames}</ha-expansion-panel
|
|
||||||
>`
|
|
||||||
: nothing} `,
|
|
||||||
confirmText: this.hass.localize("ui.common.rename"),
|
|
||||||
dismissText: this.hass.localize("ui.common.no"),
|
|
||||||
warning: true,
|
|
||||||
});
|
|
||||||
} else if (dialogNoRenames.length) {
|
|
||||||
await showAlertDialog(this, {
|
|
||||||
title: this.hass.localize(
|
|
||||||
"ui.panel.config.devices.confirm_rename_entity_no_renamable_entity_ids"
|
|
||||||
),
|
|
||||||
text: html`<ha-expansion-panel outlined>
|
|
||||||
<span slot="header"
|
|
||||||
>${this.hass.localize(
|
|
||||||
"ui.panel.config.devices.confirm_rename_entity_wont_rename",
|
|
||||||
{
|
|
||||||
deviceSlug: oldDeviceSlug,
|
|
||||||
count: dialogNoRenames.length,
|
|
||||||
}
|
|
||||||
)}</span
|
|
||||||
>
|
|
||||||
${dialogNoRenames}
|
|
||||||
</ha-expansion-panel>`,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const updateProms = entities.map((entity) => {
|
const updateProms = entities.map((entity) => {
|
||||||
const name = entity.name || entity.stateName;
|
const name = entity.name || entity.stateName;
|
||||||
let newEntityId: string | undefined;
|
|
||||||
let newName: string | null | undefined;
|
let newName: string | null | undefined;
|
||||||
|
|
||||||
let shouldUpdateName: boolean;
|
|
||||||
let shouldUpdateEntityId = false;
|
|
||||||
|
|
||||||
if (entity.has_entity_name && !entity.name) {
|
if (entity.has_entity_name && !entity.name) {
|
||||||
shouldUpdateName = false;
|
return undefined;
|
||||||
} else if (
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
entity.has_entity_name &&
|
entity.has_entity_name &&
|
||||||
(entity.name === oldDeviceName || entity.name === newDeviceName)
|
(entity.name === oldDeviceName || entity.name === newDeviceName)
|
||||||
) {
|
) {
|
||||||
shouldUpdateName = true;
|
|
||||||
// clear name if it matches the device name and it uses the device name (entity naming)
|
// clear name if it matches the device name and it uses the device name (entity naming)
|
||||||
newName = null;
|
newName = null;
|
||||||
} else if (name && name.includes(oldDeviceName)) {
|
} else if (name && name.includes(oldDeviceName)) {
|
||||||
shouldUpdateName = true;
|
|
||||||
newName = name.replace(oldDeviceName, newDeviceName);
|
newName = name.replace(oldDeviceName, newDeviceName);
|
||||||
} else {
|
} else {
|
||||||
shouldUpdateName = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (renameEntityid) {
|
|
||||||
const entityRename = entityIdRenames?.find(
|
|
||||||
(item) => item.oldId === entity.entity_id
|
|
||||||
);
|
|
||||||
if (entityRename?.newId) {
|
|
||||||
shouldUpdateEntityId = true;
|
|
||||||
newEntityId = entityRename.newId;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (newName === undefined && newEntityId === undefined) {
|
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
return updateEntityRegistryEntry(this.hass!, entity.entity_id, {
|
return updateEntityRegistryEntry(this.hass!, entity.entity_id, {
|
||||||
name: shouldUpdateName ? newName : undefined,
|
name: newName,
|
||||||
new_entity_id: shouldUpdateEntityId ? newEntityId : undefined,
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
await Promise.all(updateProms);
|
await Promise.all(updateProms);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
private async _enableDevice(): Promise<void> {
|
private async _enableDevice(): Promise<void> {
|
||||||
await updateDeviceRegistryEntry(this.hass, this.deviceId, {
|
await updateDeviceRegistryEntry(this.hass, this.deviceId, {
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { mdiContentCopy } from "@mdi/js";
|
import { mdiContentCopy, mdiRestore } from "@mdi/js";
|
||||||
import type { HassEntity } from "home-assistant-js-websocket";
|
import type { HassEntity } from "home-assistant-js-websocket";
|
||||||
import type { CSSResultGroup, PropertyValues } from "lit";
|
import type { CSSResultGroup, PropertyValues } from "lit";
|
||||||
import { css, html, LitElement, nothing } from "lit";
|
import { css, html, LitElement, nothing } from "lit";
|
||||||
@ -13,6 +13,7 @@ import { computeObjectId } from "../../../common/entity/compute_object_id";
|
|||||||
import { supportsFeature } from "../../../common/entity/supports-feature";
|
import { supportsFeature } from "../../../common/entity/supports-feature";
|
||||||
import { formatNumber } from "../../../common/number/format_number";
|
import { formatNumber } from "../../../common/number/format_number";
|
||||||
import { stringCompare } from "../../../common/string/compare";
|
import { stringCompare } from "../../../common/string/compare";
|
||||||
|
import { autoCaseNoun } from "../../../common/translations/auto_case_noun";
|
||||||
import type {
|
import type {
|
||||||
LocalizeFunc,
|
LocalizeFunc,
|
||||||
LocalizeKeys,
|
LocalizeKeys,
|
||||||
@ -23,13 +24,13 @@ import "../../../components/ha-area-picker";
|
|||||||
import "../../../components/ha-icon";
|
import "../../../components/ha-icon";
|
||||||
import "../../../components/ha-icon-button-next";
|
import "../../../components/ha-icon-button-next";
|
||||||
import "../../../components/ha-icon-picker";
|
import "../../../components/ha-icon-picker";
|
||||||
|
import "../../../components/ha-labels-picker";
|
||||||
import "../../../components/ha-list-item";
|
import "../../../components/ha-list-item";
|
||||||
import "../../../components/ha-radio";
|
import "../../../components/ha-radio";
|
||||||
import "../../../components/ha-select";
|
import "../../../components/ha-select";
|
||||||
import "../../../components/ha-settings-row";
|
import "../../../components/ha-settings-row";
|
||||||
import "../../../components/ha-state-icon";
|
import "../../../components/ha-state-icon";
|
||||||
import "../../../components/ha-switch";
|
import "../../../components/ha-switch";
|
||||||
import "../../../components/ha-labels-picker";
|
|
||||||
import type { HaSwitch } from "../../../components/ha-switch";
|
import type { HaSwitch } from "../../../components/ha-switch";
|
||||||
import "../../../components/ha-textfield";
|
import "../../../components/ha-textfield";
|
||||||
import {
|
import {
|
||||||
@ -59,6 +60,7 @@ import type {
|
|||||||
SensorEntityOptions,
|
SensorEntityOptions,
|
||||||
} from "../../../data/entity_registry";
|
} from "../../../data/entity_registry";
|
||||||
import {
|
import {
|
||||||
|
getAutomaticEntityIds,
|
||||||
subscribeEntityRegistry,
|
subscribeEntityRegistry,
|
||||||
updateEntityRegistryEntry,
|
updateEntityRegistryEntry,
|
||||||
} from "../../../data/entity_registry";
|
} from "../../../data/entity_registry";
|
||||||
@ -89,7 +91,6 @@ import { haStyle } from "../../../resources/styles";
|
|||||||
import type { HomeAssistant } from "../../../types";
|
import type { HomeAssistant } from "../../../types";
|
||||||
import { showToast } from "../../../util/toast";
|
import { showToast } from "../../../util/toast";
|
||||||
import { showDeviceRegistryDetailDialog } from "../devices/device-registry-detail/show-dialog-device-registry-detail";
|
import { showDeviceRegistryDetailDialog } from "../devices/device-registry-detail/show-dialog-device-registry-detail";
|
||||||
import { autoCaseNoun } from "../../../common/translations/auto_case_noun";
|
|
||||||
|
|
||||||
const OVERRIDE_DEVICE_CLASSES = {
|
const OVERRIDE_DEVICE_CLASSES = {
|
||||||
cover: [
|
cover: [
|
||||||
@ -757,11 +758,16 @@ export class EntityRegistrySettingsEditor extends LitElement {
|
|||||||
autocorrect="off"
|
autocorrect="off"
|
||||||
input-spellcheck="false"
|
input-spellcheck="false"
|
||||||
>
|
>
|
||||||
<ha-icon-button
|
<div class="layout horizontal" slot="trailingIcon">
|
||||||
@click=${this._copyEntityId}
|
<ha-icon-button
|
||||||
slot="trailingIcon"
|
@click=${this._restoreEntityId}
|
||||||
.path=${mdiContentCopy}
|
.path=${mdiRestore}
|
||||||
></ha-icon-button>
|
></ha-icon-button>
|
||||||
|
<ha-icon-button
|
||||||
|
@click=${this._copyEntityId}
|
||||||
|
.path=${mdiContentCopy}
|
||||||
|
></ha-icon-button>
|
||||||
|
</div>
|
||||||
</ha-textfield>
|
</ha-textfield>
|
||||||
${!this.entry.device_id
|
${!this.entry.device_id
|
||||||
? html`<ha-area-picker
|
? html`<ha-area-picker
|
||||||
@ -1285,6 +1291,13 @@ export class EntityRegistrySettingsEditor extends LitElement {
|
|||||||
this._icon = ev.detail.value;
|
this._icon = ev.detail.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async _restoreEntityId(): Promise<void> {
|
||||||
|
const entityIds = await getAutomaticEntityIds(this.hass, [
|
||||||
|
this._origEntityId,
|
||||||
|
]);
|
||||||
|
this._entityId = entityIds[this._origEntityId] || this._origEntityId;
|
||||||
|
}
|
||||||
|
|
||||||
private async _copyEntityId(): Promise<void> {
|
private async _copyEntityId(): Promise<void> {
|
||||||
await copyToClipboard(this._entityId);
|
await copyToClipboard(this._entityId);
|
||||||
showToast(this, {
|
showToast(this, {
|
||||||
@ -1507,7 +1520,7 @@ export class EntityRegistrySettingsEditor extends LitElement {
|
|||||||
--text-field-prefix-padding-right: 0;
|
--text-field-prefix-padding-right: 0;
|
||||||
--textfield-icon-trailing-padding: 0;
|
--textfield-icon-trailing-padding: 0;
|
||||||
}
|
}
|
||||||
ha-textfield.entityId > ha-icon-button {
|
ha-textfield.entityId ha-icon-button {
|
||||||
position: relative;
|
position: relative;
|
||||||
right: -8px;
|
right: -8px;
|
||||||
--mdc-icon-button-size: 36px;
|
--mdc-icon-button-size: 36px;
|
||||||
|
@ -10,6 +10,7 @@ import {
|
|||||||
mdiMenuDown,
|
mdiMenuDown,
|
||||||
mdiPencilOff,
|
mdiPencilOff,
|
||||||
mdiPlus,
|
mdiPlus,
|
||||||
|
mdiRestore,
|
||||||
mdiRestoreAlert,
|
mdiRestoreAlert,
|
||||||
mdiToggleSwitch,
|
mdiToggleSwitch,
|
||||||
mdiToggleSwitchOffOutline,
|
mdiToggleSwitchOffOutline,
|
||||||
@ -95,6 +96,7 @@ import {
|
|||||||
createLabelRegistryEntry,
|
createLabelRegistryEntry,
|
||||||
subscribeLabelRegistry,
|
subscribeLabelRegistry,
|
||||||
} from "../../../data/label_registry";
|
} from "../../../data/label_registry";
|
||||||
|
import { regenerateEntityIds } from "../../../data/regenerate_entity_ids";
|
||||||
import {
|
import {
|
||||||
showAlertDialog,
|
showAlertDialog,
|
||||||
showConfirmationDialog,
|
showConfirmationDialog,
|
||||||
@ -952,6 +954,21 @@ ${
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</ha-md-menu-item>
|
</ha-md-menu-item>
|
||||||
|
|
||||||
|
<ha-md-divider role="separator" tabindex="-1"></ha-md-divider>
|
||||||
|
|
||||||
|
<ha-md-menu-item .clickAction=${this._restoreEntityIdSelected}>
|
||||||
|
<ha-svg-icon
|
||||||
|
slot="start"
|
||||||
|
.path=${mdiRestore}
|
||||||
|
></ha-svg-icon>
|
||||||
|
<div slot="headline">
|
||||||
|
${this.hass.localize(
|
||||||
|
"ui.panel.config.entities.picker.restore_entity_id_selected.button"
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</ha-md-menu-item>
|
||||||
|
|
||||||
<ha-md-divider role="separator" tabindex="-1"></ha-md-divider>
|
<ha-md-divider role="separator" tabindex="-1"></ha-md-divider>
|
||||||
|
|
||||||
<ha-md-menu-item .clickAction=${this._removeSelected} class="warning">
|
<ha-md-menu-item .clickAction=${this._removeSelected} class="warning">
|
||||||
@ -1371,6 +1388,12 @@ ${rejected
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
private _restoreEntityIdSelected = () => {
|
||||||
|
regenerateEntityIds(this, this.hass, this._selected);
|
||||||
|
|
||||||
|
this._clearSelection();
|
||||||
|
};
|
||||||
|
|
||||||
private _removeSelected = async () => {
|
private _removeSelected = async () => {
|
||||||
if (!this._entities || !this.hass) {
|
if (!this._entities || !this.hass) {
|
||||||
return;
|
return;
|
||||||
|
@ -6,7 +6,6 @@ import memoizeOne from "memoize-one";
|
|||||||
import { fireEvent } from "../../../../../common/dom/fire_event";
|
import { fireEvent } from "../../../../../common/dom/fire_event";
|
||||||
import { computeStateName } from "../../../../../common/entity/compute_state_name";
|
import { computeStateName } from "../../../../../common/entity/compute_state_name";
|
||||||
import { stringCompare } from "../../../../../common/string/compare";
|
import { stringCompare } from "../../../../../common/string/compare";
|
||||||
import { slugify } from "../../../../../common/string/slugify";
|
|
||||||
import "../../../../../components/entity/state-badge";
|
import "../../../../../components/entity/state-badge";
|
||||||
import "../../../../../components/ha-area-picker";
|
import "../../../../../components/ha-area-picker";
|
||||||
import "../../../../../components/ha-card";
|
import "../../../../../components/ha-card";
|
||||||
@ -14,6 +13,7 @@ import "../../../../../components/ha-textfield";
|
|||||||
import { updateDeviceRegistryEntry } from "../../../../../data/device_registry";
|
import { updateDeviceRegistryEntry } from "../../../../../data/device_registry";
|
||||||
import type { EntityRegistryEntry } from "../../../../../data/entity_registry";
|
import type { EntityRegistryEntry } from "../../../../../data/entity_registry";
|
||||||
import {
|
import {
|
||||||
|
getAutomaticEntityIds,
|
||||||
subscribeEntityRegistry,
|
subscribeEntityRegistry,
|
||||||
updateEntityRegistryEntry,
|
updateEntityRegistryEntry,
|
||||||
} from "../../../../../data/entity_registry";
|
} from "../../../../../data/entity_registry";
|
||||||
@ -23,7 +23,6 @@ import { SubscribeMixin } from "../../../../../mixins/subscribe-mixin";
|
|||||||
import { haStyle } from "../../../../../resources/styles";
|
import { haStyle } from "../../../../../resources/styles";
|
||||||
import type { HomeAssistant } from "../../../../../types";
|
import type { HomeAssistant } from "../../../../../types";
|
||||||
import type { EntityRegistryStateEntry } from "../../../devices/ha-config-device-page";
|
import type { EntityRegistryStateEntry } from "../../../devices/ha-config-device-page";
|
||||||
import { getIeeeTail } from "./functions";
|
|
||||||
|
|
||||||
@customElement("zha-device-card")
|
@customElement("zha-device-card")
|
||||||
class ZHADeviceCard extends SubscribeMixin(LitElement) {
|
class ZHADeviceCard extends SubscribeMixin(LitElement) {
|
||||||
@ -135,30 +134,35 @@ class ZHADeviceCard extends SubscribeMixin(LitElement) {
|
|||||||
}
|
}
|
||||||
const entities = this._deviceEntities(device.device_reg_id, this._entities);
|
const entities = this._deviceEntities(device.device_reg_id, this._entities);
|
||||||
|
|
||||||
const oldDeviceEntityId = slugify(oldDeviceName);
|
const entityIdsMapping = getAutomaticEntityIds(
|
||||||
const newDeviceEntityId = slugify(newDeviceName);
|
this.hass,
|
||||||
const ieeeTail = getIeeeTail(device.ieee);
|
entities.map((entity) => entity.entity_id)
|
||||||
|
);
|
||||||
|
|
||||||
const updateProms = entities.map((entity) => {
|
const updateProms = entities.map((entity) => {
|
||||||
const name = entity.name || entity.stateName;
|
const name = entity.name;
|
||||||
let newEntityId: string | null = null;
|
const newEntityId = entityIdsMapping[entity.entity_id];
|
||||||
let newName: string | null = null;
|
let newName: string | null | undefined;
|
||||||
|
|
||||||
if (name && name.includes(oldDeviceName)) {
|
if (entity.has_entity_name && !entity.name) {
|
||||||
newName = name.replace(` ${ieeeTail}`, "");
|
newName = undefined;
|
||||||
newName = newName.replace(oldDeviceName, newDeviceName);
|
} else if (
|
||||||
newEntityId = entity.entity_id.replace(`_${ieeeTail}`, "");
|
entity.has_entity_name &&
|
||||||
newEntityId = newEntityId.replace(oldDeviceEntityId, newDeviceEntityId);
|
(entity.name === oldDeviceName || entity.name === newDeviceName)
|
||||||
|
) {
|
||||||
|
// clear name if it matches the device name and it uses the device name (entity naming)
|
||||||
|
newName = null;
|
||||||
|
} else if (name && name.includes(oldDeviceName)) {
|
||||||
|
newName = name.replace(oldDeviceName, newDeviceName);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!newName && !newEntityId) {
|
if (newName !== undefined && !newEntityId) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
return updateEntityRegistryEntry(this.hass!, entity.entity_id, {
|
return updateEntityRegistryEntry(this.hass!, entity.entity_id, {
|
||||||
name: newName || name,
|
name: newName,
|
||||||
disabled_by: entity.disabled_by,
|
new_entity_id: newEntityId || undefined,
|
||||||
new_entity_id: newEntityId || entity.entity_id,
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
await Promise.all(updateProms);
|
await Promise.all(updateProms);
|
||||||
|
@ -49,11 +49,10 @@ import "../../../../../../components/ha-fade-in";
|
|||||||
import "../../../../../../components/ha-icon-button";
|
import "../../../../../../components/ha-icon-button";
|
||||||
import "../../../../../../components/ha-qr-scanner";
|
import "../../../../../../components/ha-qr-scanner";
|
||||||
|
|
||||||
import { computeStateName } from "../../../../../../common/entity/compute_state_name";
|
|
||||||
import { navigate } from "../../../../../../common/navigate";
|
import { navigate } from "../../../../../../common/navigate";
|
||||||
import { slugify } from "../../../../../../common/string/slugify";
|
|
||||||
import type { EntityRegistryEntry } from "../../../../../../data/entity_registry";
|
import type { EntityRegistryEntry } from "../../../../../../data/entity_registry";
|
||||||
import {
|
import {
|
||||||
|
getAutomaticEntityIds,
|
||||||
subscribeEntityRegistry,
|
subscribeEntityRegistry,
|
||||||
updateEntityRegistryEntry,
|
updateEntityRegistryEntry,
|
||||||
} from "../../../../../../data/entity_registry";
|
} from "../../../../../../data/entity_registry";
|
||||||
@ -874,42 +873,47 @@ class DialogZWaveJSAddNode extends SubscribeMixin(LitElement) {
|
|||||||
|
|
||||||
if (nameChanged) {
|
if (nameChanged) {
|
||||||
// rename entities
|
// rename entities
|
||||||
const oldDeviceEntityId = slugify(oldDeviceName);
|
|
||||||
const newDeviceEntityId = slugify(newDeviceName);
|
const entities = this._entities.filter(
|
||||||
|
(entity) => entity.device_id === this._device!.id
|
||||||
|
);
|
||||||
|
|
||||||
|
const entityIdsMapping = getAutomaticEntityIds(
|
||||||
|
this.hass,
|
||||||
|
entities.map((entity) => entity.entity_id)
|
||||||
|
);
|
||||||
|
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
this._entities
|
entities.map((entity) => {
|
||||||
.filter((entity) => entity.device_id === this._device!.id)
|
const name = entity.name;
|
||||||
.map((entity) => {
|
let newName: string | null | undefined;
|
||||||
const entityState = this.hass.states[entity.entity_id];
|
const newEntityId = entityIdsMapping[entity.entity_id];
|
||||||
const name =
|
|
||||||
entity.name ||
|
|
||||||
(entityState && computeStateName(entityState));
|
|
||||||
let newEntityId: string | null = null;
|
|
||||||
let newName: string | null = null;
|
|
||||||
|
|
||||||
if (name && name.includes(oldDeviceName)) {
|
if (entity.has_entity_name && !entity.name) {
|
||||||
newName = name.replace(oldDeviceName, newDeviceName);
|
newName = undefined;
|
||||||
}
|
} else if (
|
||||||
|
entity.has_entity_name &&
|
||||||
|
(entity.name === oldDeviceName ||
|
||||||
|
entity.name === newDeviceName)
|
||||||
|
) {
|
||||||
|
// clear name if it matches the device name and it uses the device name (entity naming)
|
||||||
|
newName = null;
|
||||||
|
} else if (name && name.includes(oldDeviceName)) {
|
||||||
|
newName = name.replace(oldDeviceName, newDeviceName);
|
||||||
|
}
|
||||||
|
|
||||||
newEntityId = entity.entity_id.replace(
|
if (
|
||||||
oldDeviceEntityId,
|
(newName === undefined && !newEntityId) ||
|
||||||
newDeviceEntityId
|
newEntityId === entity.entity_id
|
||||||
);
|
) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
if (!newName && newEntityId === entity.entity_id) {
|
return updateEntityRegistryEntry(this.hass!, entity.entity_id, {
|
||||||
return undefined;
|
name: newName || name,
|
||||||
}
|
new_entity_id: newEntityId || undefined,
|
||||||
|
});
|
||||||
return updateEntityRegistryEntry(
|
})
|
||||||
this.hass!,
|
|
||||||
entity.entity_id,
|
|
||||||
{
|
|
||||||
name: newName || name,
|
|
||||||
new_entity_id: newEntityId || entity.entity_id,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
})
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} catch (_err: any) {
|
} catch (_err: any) {
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
|
import { mdiClose } from "@mdi/js";
|
||||||
import type { HassEntity, UnsubscribeFunc } from "home-assistant-js-websocket";
|
import type { HassEntity, UnsubscribeFunc } from "home-assistant-js-websocket";
|
||||||
import type { PropertyValues } from "lit";
|
import type { PropertyValues } from "lit";
|
||||||
import { LitElement, css, html, nothing } from "lit";
|
import { LitElement, css, html, nothing } from "lit";
|
||||||
import { customElement, property, query, state } from "lit/decorators";
|
import { customElement, property, state } from "lit/decorators";
|
||||||
import { classMap } from "lit/directives/class-map";
|
import { classMap } from "lit/directives/class-map";
|
||||||
import { styleMap } from "lit/directives/style-map";
|
import { styleMap } from "lit/directives/style-map";
|
||||||
import { applyThemesOnElement } from "../../../common/dom/apply_themes_on_element";
|
import { applyThemesOnElement } from "../../../common/dom/apply_themes_on_element";
|
||||||
@ -9,8 +10,8 @@ import { fireEvent } from "../../../common/dom/fire_event";
|
|||||||
import { stateColorCss } from "../../../common/entity/state_color";
|
import { stateColorCss } from "../../../common/entity/state_color";
|
||||||
import { supportsFeature } from "../../../common/entity/supports-feature";
|
import { supportsFeature } from "../../../common/entity/supports-feature";
|
||||||
import "../../../components/chips/ha-assist-chip";
|
import "../../../components/chips/ha-assist-chip";
|
||||||
import "../../../components/ha-card";
|
|
||||||
import "../../../components/ha-button";
|
import "../../../components/ha-button";
|
||||||
|
import "../../../components/ha-card";
|
||||||
import "../../../components/ha-state-icon";
|
import "../../../components/ha-state-icon";
|
||||||
import "../../../components/ha-textfield";
|
import "../../../components/ha-textfield";
|
||||||
import type { HaTextField } from "../../../components/ha-textfield";
|
import type { HaTextField } from "../../../components/ha-textfield";
|
||||||
@ -21,18 +22,18 @@ import {
|
|||||||
callAlarmAction,
|
callAlarmAction,
|
||||||
} from "../../../data/alarm_control_panel";
|
} from "../../../data/alarm_control_panel";
|
||||||
import { UNAVAILABLE } from "../../../data/entity";
|
import { UNAVAILABLE } from "../../../data/entity";
|
||||||
import type { HomeAssistant } from "../../../types";
|
|
||||||
import { findEntities } from "../common/find-entities";
|
|
||||||
import { createEntityNotFoundWarning } from "../components/hui-warning";
|
|
||||||
import type { LovelaceCard } from "../types";
|
|
||||||
import type { ExtEntityRegistryEntry } from "../../../data/entity_registry";
|
import type { ExtEntityRegistryEntry } from "../../../data/entity_registry";
|
||||||
import {
|
import {
|
||||||
getExtendedEntityRegistryEntry,
|
getExtendedEntityRegistryEntry,
|
||||||
subscribeEntityRegistry,
|
subscribeEntityRegistry,
|
||||||
} from "../../../data/entity_registry";
|
} from "../../../data/entity_registry";
|
||||||
|
import type { HomeAssistant } from "../../../types";
|
||||||
|
import { findEntities } from "../common/find-entities";
|
||||||
|
import { createEntityNotFoundWarning } from "../components/hui-warning";
|
||||||
|
import type { LovelaceCard } from "../types";
|
||||||
import type { AlarmPanelCardConfig, AlarmPanelCardConfigState } from "./types";
|
import type { AlarmPanelCardConfig, AlarmPanelCardConfigState } from "./types";
|
||||||
|
|
||||||
const BUTTONS = ["1", "2", "3", "4", "5", "6", "7", "8", "9", "", "0", "clear"];
|
const BUTTONS = ["1", "2", "3", "4", "5", "6", "7", "8", "9", "clear", "0", ""];
|
||||||
|
|
||||||
export const DEFAULT_STATES = [
|
export const DEFAULT_STATES = [
|
||||||
"arm_home",
|
"arm_home",
|
||||||
@ -101,7 +102,7 @@ class HuiAlarmPanelCard extends LitElement implements LovelaceCard {
|
|||||||
|
|
||||||
@state() private _entry?: ExtEntityRegistryEntry | null;
|
@state() private _entry?: ExtEntityRegistryEntry | null;
|
||||||
|
|
||||||
@query("#alarmCode") private _input?: HaTextField;
|
@state() private _value?: string;
|
||||||
|
|
||||||
private _unsubEntityRegistry?: UnsubscribeFunc;
|
private _unsubEntityRegistry?: UnsubscribeFunc;
|
||||||
|
|
||||||
@ -117,14 +118,14 @@ class HuiAlarmPanelCard extends LitElement implements LovelaceCard {
|
|||||||
|
|
||||||
public async getCardSize(): Promise<number> {
|
public async getCardSize(): Promise<number> {
|
||||||
if (!this._config || !this.hass) {
|
if (!this._config || !this.hass) {
|
||||||
return 9;
|
return 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
const stateObj = this.hass.states[this._config.entity];
|
const stateObj = this.hass.states[this._config.entity];
|
||||||
|
|
||||||
return !stateObj || stateObj.attributes.code_format !== FORMAT_NUMBER
|
return !stateObj || stateObj.attributes.code_format !== FORMAT_NUMBER
|
||||||
? 4
|
? 4
|
||||||
: 9;
|
: 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
public setConfig(config: AlarmPanelCardConfig): void {
|
public setConfig(config: AlarmPanelCardConfig): void {
|
||||||
@ -275,7 +276,8 @@ class HuiAlarmPanelCard extends LitElement implements LovelaceCard {
|
|||||||
? nothing
|
? nothing
|
||||||
: html`
|
: html`
|
||||||
<ha-textfield
|
<ha-textfield
|
||||||
id="alarmCode"
|
.value=${this._value || ""}
|
||||||
|
@input=${this._handleInput}
|
||||||
.label=${this.hass.localize("ui.card.alarm_control_panel.code")}
|
.label=${this.hass.localize("ui.card.alarm_control_panel.code")}
|
||||||
type="password"
|
type="password"
|
||||||
.inputMode=${stateObj.attributes.code_format === FORMAT_NUMBER
|
.inputMode=${stateObj.attributes.code_format === FORMAT_NUMBER
|
||||||
@ -286,26 +288,31 @@ class HuiAlarmPanelCard extends LitElement implements LovelaceCard {
|
|||||||
${stateObj.attributes.code_format !== FORMAT_NUMBER || defaultCode
|
${stateObj.attributes.code_format !== FORMAT_NUMBER || defaultCode
|
||||||
? nothing
|
? nothing
|
||||||
: html`
|
: html`
|
||||||
<div id="keypad">
|
<div class="keypad">
|
||||||
${BUTTONS.map((value) =>
|
${BUTTONS.map((value) =>
|
||||||
value === ""
|
value === ""
|
||||||
? html`<ha-button disabled></ha-button> `
|
? html`<span></span>`
|
||||||
: html`
|
: value === "clear"
|
||||||
<ha-button
|
? html`
|
||||||
.value=${value}
|
<ha-control-button
|
||||||
@click=${this._handlePadClick}
|
@click=${this._handlePadClick}
|
||||||
appearance="filled"
|
class="clear"
|
||||||
class=${classMap({
|
.value=${value}
|
||||||
numberkey: value !== "clear",
|
.disabled=${!this._value}
|
||||||
})}
|
.label=${this.hass!.localize("ui.common.clear")}
|
||||||
>
|
>
|
||||||
${value === "clear"
|
<ha-svg-icon path=${mdiClose}></ha-svg-icon>
|
||||||
? this.hass!.localize(
|
</ha-control-button>
|
||||||
`ui.card.alarm_control_panel.clear_code`
|
`
|
||||||
)
|
: html`
|
||||||
: value}
|
<ha-control-button
|
||||||
</ha-button>
|
.value=${value}
|
||||||
`
|
@click=${this._handlePadClick}
|
||||||
|
.label=${value}
|
||||||
|
>
|
||||||
|
${value}
|
||||||
|
</ha-control-button>
|
||||||
|
`
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
`}
|
`}
|
||||||
@ -327,22 +334,23 @@ class HuiAlarmPanelCard extends LitElement implements LovelaceCard {
|
|||||||
) || entityState;
|
) || entityState;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private _handleInput(e: Event): void {
|
||||||
|
this._value = (e.currentTarget as HaTextField).value;
|
||||||
|
}
|
||||||
|
|
||||||
private _handlePadClick(e: MouseEvent): void {
|
private _handlePadClick(e: MouseEvent): void {
|
||||||
const val = (e.currentTarget! as any).value;
|
const val = (e.currentTarget! as any).value;
|
||||||
this._input!.value = val === "clear" ? "" : this._input!.value + val;
|
this._value = val === "clear" ? "" : (this._value || "") + val;
|
||||||
}
|
}
|
||||||
|
|
||||||
private _handleActionClick(e: MouseEvent): void {
|
private _handleActionClick(e: MouseEvent): void {
|
||||||
const input = this._input;
|
|
||||||
callAlarmAction(
|
callAlarmAction(
|
||||||
this.hass!,
|
this.hass!,
|
||||||
this._config!.entity,
|
this._config!.entity,
|
||||||
(e.currentTarget! as any).action,
|
(e.currentTarget! as any).action,
|
||||||
input?.value || undefined
|
this._value || undefined
|
||||||
);
|
);
|
||||||
if (input) {
|
this._value = undefined;
|
||||||
input.value = "";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private _handleMoreInfo() {
|
private _handleMoreInfo() {
|
||||||
@ -411,20 +419,28 @@ class HuiAlarmPanelCard extends LitElement implements LovelaceCard {
|
|||||||
animation: none;
|
animation: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
#keypad {
|
.keypad {
|
||||||
display: flex;
|
--keypad-columns: 3;
|
||||||
justify-content: center;
|
margin-top: 12px;
|
||||||
flex-wrap: wrap;
|
padding: 12px;
|
||||||
margin: auto;
|
display: grid;
|
||||||
width: 100%;
|
grid-template-columns: repeat(var(--keypad-columns), auto);
|
||||||
max-width: 300px;
|
grid-auto-rows: auto;
|
||||||
direction: ltr;
|
grid-gap: 24px;
|
||||||
|
justify-items: center;
|
||||||
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
#keypad ha-button {
|
ha-control-button {
|
||||||
padding: 8px;
|
width: 56px;
|
||||||
width: 30%;
|
height: 56px;
|
||||||
box-sizing: border-box;
|
--control-button-border-radius: 28px;
|
||||||
|
--mdc-icon-size: 24px;
|
||||||
|
font-size: var(--ha-font-size-2xl);
|
||||||
|
}
|
||||||
|
.clear {
|
||||||
|
--control-button-background-color: var(--red-color);
|
||||||
|
--control-button-icon-color: var(--red-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
.actions {
|
.actions {
|
||||||
@ -437,10 +453,6 @@ class HuiAlarmPanelCard extends LitElement implements LovelaceCard {
|
|||||||
.actions ha-button {
|
.actions ha-button {
|
||||||
margin: 0 4px 4px;
|
margin: 0 4px 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
ha-button.numberkey {
|
|
||||||
--ha-button-font-size: var(--keypad-font-size, var(--ha-font-size-s));
|
|
||||||
}
|
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -224,19 +224,19 @@ export class HuiButtonCard extends LitElement implements LovelaceCard {
|
|||||||
filter: colored ? stateColorBrightness(stateObj) : undefined,
|
filter: colored ? stateColorBrightness(stateObj) : undefined,
|
||||||
height: this._config.icon_height
|
height: this._config.icon_height
|
||||||
? this._config.icon_height
|
? this._config.icon_height
|
||||||
: "",
|
: undefined,
|
||||||
})}
|
})}
|
||||||
></ha-state-icon>
|
></ha-state-icon>
|
||||||
`
|
`
|
||||||
: ""}
|
: nothing}
|
||||||
${this._config.show_name
|
${this._config.show_name
|
||||||
? html`<span tabindex="-1" .title=${name}>${name}</span>`
|
? html`<span tabindex="-1" .title=${name}>${name}</span>`
|
||||||
: ""}
|
: nothing}
|
||||||
${this._config.show_state && stateObj
|
${this._config.show_state && stateObj
|
||||||
? html`<span class="state">
|
? html`<span class="state">
|
||||||
${this.hass.formatEntityState(stateObj)}
|
${this.hass.formatEntityState(stateObj)}
|
||||||
</span>`
|
</span>`
|
||||||
: ""}
|
: nothing}
|
||||||
</ha-card>
|
</ha-card>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
@ -282,7 +282,8 @@ export class HuiButtonCard extends LitElement implements LovelaceCard {
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
padding: 4% 0;
|
padding: 4% 0;
|
||||||
font-size: 16.8px;
|
font-size: var(--ha-font-size-l);
|
||||||
|
line-height: var(--ha-line-height-condensed);
|
||||||
height: 100%;
|
height: 100%;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
@ -339,6 +339,7 @@
|
|||||||
"remove": "Remove",
|
"remove": "Remove",
|
||||||
"enable": "Enable",
|
"enable": "Enable",
|
||||||
"disable": "Disable",
|
"disable": "Disable",
|
||||||
|
"update": "Update",
|
||||||
"hide": "Hide",
|
"hide": "Hide",
|
||||||
"close": "Close",
|
"close": "Close",
|
||||||
"clear": "Clear",
|
"clear": "Clear",
|
||||||
@ -1535,6 +1536,17 @@
|
|||||||
"no_aliases": "Configure aliases and expose settings for voice assistants"
|
"no_aliases": "Configure aliases and expose settings for voice assistants"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"recreate_entity_ids": {
|
||||||
|
"confirm_rename_title": "Are you sure you want to recreate your entity IDs?",
|
||||||
|
"confirm_rename_warning": "This will not change any configuration (like automations, scripts, scenes, dashboards) that is currently using these entities! You will have to manually edit them yourself to use the new entity IDs!",
|
||||||
|
"will_rename": "{count} {count, plural,\n one {entity ID}\n other {entity IDs}\n} will be renamed",
|
||||||
|
"new": "New",
|
||||||
|
"old": "Old",
|
||||||
|
"cant_rename": "{count} {count, plural,\n one {entity ID}\n other {entity IDs}\n} can not be regenerated because they are not available",
|
||||||
|
"wont_change": "{count} {count, plural,\n one {entity ID}\n other {entity IDs}\n} will not change",
|
||||||
|
"update_entity_error": "Updating the entity ID of {entityId} failed",
|
||||||
|
"confirm_no_renamable_entity_ids": "No renamable entity IDs"
|
||||||
|
},
|
||||||
"device-registry-detail": {
|
"device-registry-detail": {
|
||||||
"name": "[%key:ui::panel::config::devices::name%]",
|
"name": "[%key:ui::panel::config::devices::name%]",
|
||||||
"enabled_label": "[%key:ui::panel::config::devices::enabled_label%]",
|
"enabled_label": "[%key:ui::panel::config::devices::enabled_label%]",
|
||||||
@ -4941,6 +4953,7 @@
|
|||||||
"filtering_by_config_entry": "[%key:ui::panel::config::entities::picker::filtering_by_config_entry%]",
|
"filtering_by_config_entry": "[%key:ui::panel::config::entities::picker::filtering_by_config_entry%]",
|
||||||
"device_info": "{type} info",
|
"device_info": "{type} info",
|
||||||
"edit_settings": "Edit settings",
|
"edit_settings": "Edit settings",
|
||||||
|
"restore_entity_ids": "Recreate entity IDs",
|
||||||
"unnamed_device": "Unnamed {type}",
|
"unnamed_device": "Unnamed {type}",
|
||||||
"unknown_error": "Unknown error",
|
"unknown_error": "Unknown error",
|
||||||
"name": "Name",
|
"name": "Name",
|
||||||
@ -5040,13 +5053,6 @@
|
|||||||
"disabled_entities": "+{count} disabled {count, plural,\n one {entity}\n other {entities}\n}",
|
"disabled_entities": "+{count} disabled {count, plural,\n one {entity}\n other {entities}\n}",
|
||||||
"hidden": "Hidden"
|
"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 manually edit them yourself to use the new entity IDs!",
|
|
||||||
"confirm_rename_entity_will_rename": "{count} {count, plural,\n one {entity ID}\n other {entity IDs}\n} will be renamed",
|
|
||||||
"confirm_rename_new": "New",
|
|
||||||
"confirm_rename_old": "Old",
|
|
||||||
"confirm_rename_entity_wont_rename": "{count} {count, plural,\n one {entity ID}\n other {entity IDs}\n} will not be renamed as they do not contain the current device name ({deviceSlug})",
|
|
||||||
"confirm_rename_entity_no_renamable_entity_ids": "No renamable entity IDs",
|
|
||||||
"confirm_disable_config_entry": "There are no more devices for the config entry {entry_name}, do you want to instead disable the config entry?",
|
"confirm_disable_config_entry": "There are no more devices for the config entry {entry_name}, do you want to instead disable the config entry?",
|
||||||
"update_device_error": "Updating the device failed",
|
"update_device_error": "Updating the device failed",
|
||||||
"disabled": "Disabled",
|
"disabled": "Disabled",
|
||||||
@ -5122,6 +5128,12 @@
|
|||||||
"confirm_title": "Do you want to disable {number} {number, plural,\n one {entity}\n other {entities}\n}?",
|
"confirm_title": "Do you want to disable {number} {number, plural,\n one {entity}\n other {entities}\n}?",
|
||||||
"confirm_text": "Disabled entities will not be added to Home Assistant."
|
"confirm_text": "Disabled entities will not be added to Home Assistant."
|
||||||
},
|
},
|
||||||
|
"restore_entity_id_selected": {
|
||||||
|
"button": "Recreate entity IDs of selected",
|
||||||
|
"confirm_title": "Recreate entity IDs?",
|
||||||
|
"confirm_text": "Are you sure you want to change the entity IDs of these entities? You will have to change you dashboards, automations and scripts to use the new entity IDs.",
|
||||||
|
"changes": "The following entity IDs will be updated:"
|
||||||
|
},
|
||||||
"delete_selected": {
|
"delete_selected": {
|
||||||
"button": "Delete selected",
|
"button": "Delete selected",
|
||||||
"confirm_title": "Delete selected entities?",
|
"confirm_title": "Delete selected entities?",
|
||||||
@ -9081,7 +9093,6 @@
|
|||||||
"yes": "[%key:ui::common::yes%]",
|
"yes": "[%key:ui::common::yes%]",
|
||||||
"no": "[%key:ui::common::no%]",
|
"no": "[%key:ui::common::no%]",
|
||||||
"add": "[%key:supervisor::dialog::repositories::add%]",
|
"add": "[%key:supervisor::dialog::repositories::add%]",
|
||||||
"description": "Description",
|
|
||||||
"failed_to_restart_name": "Failed to restart {name}",
|
"failed_to_restart_name": "Failed to restart {name}",
|
||||||
"failed_to_update_name": "Failed to update {name}",
|
"failed_to_update_name": "Failed to update {name}",
|
||||||
"learn_more": "Learn more",
|
"learn_more": "Learn more",
|
||||||
|
Loading…
x
Reference in New Issue
Block a user