mirror of
https://github.com/home-assistant/frontend.git
synced 2025-11-14 13:31:10 +00:00
Compare commits
16 Commits
copilot/fi
...
toggle_gro
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
134681b4c9 | ||
|
|
082f1ca55e | ||
|
|
341e63e878 | ||
|
|
5ed2d2fd2f | ||
|
|
c6f92d1375 | ||
|
|
e8201f7848 | ||
|
|
6d7df18e82 | ||
|
|
1471cfea66 | ||
|
|
9e4835107d | ||
|
|
3269fd3c5b | ||
|
|
17e63343c7 | ||
|
|
dc7ba0dac6 | ||
|
|
2ab4608884 | ||
|
|
de7f5c1bb7 | ||
|
|
7144b7802e | ||
|
|
ca315b88ce |
@@ -31,7 +31,8 @@ export type LocalizeKeys =
|
|||||||
| `ui.panel.lovelace.card.${string}`
|
| `ui.panel.lovelace.card.${string}`
|
||||||
| `ui.panel.lovelace.editor.${string}`
|
| `ui.panel.lovelace.editor.${string}`
|
||||||
| `ui.panel.page-authorize.form.${string}`
|
| `ui.panel.page-authorize.form.${string}`
|
||||||
| `component.${string}`;
|
| `component.${string}`
|
||||||
|
| `ui.entity.${string}`;
|
||||||
|
|
||||||
export type LandingPageKeys = FlattenObjectKeys<
|
export type LandingPageKeys = FlattenObjectKeys<
|
||||||
TranslationDict["landing-page"]
|
TranslationDict["landing-page"]
|
||||||
|
|||||||
@@ -72,6 +72,9 @@ export class HaControlButton extends LitElement {
|
|||||||
color 180ms ease-in-out;
|
color 180ms ease-in-out;
|
||||||
color: var(--control-button-icon-color);
|
color: var(--control-button-icon-color);
|
||||||
}
|
}
|
||||||
|
:host([vertical]) .button {
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
.button:focus-visible {
|
.button:focus-visible {
|
||||||
box-shadow: 0 0 0 2px var(--control-button-focus-color);
|
box-shadow: 0 0 0 2px var(--control-button-focus-color);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,272 @@
|
|||||||
|
import type { HassEntity } from "home-assistant-js-websocket";
|
||||||
|
import { css, html, LitElement, nothing } from "lit";
|
||||||
|
import { customElement, property } from "lit/decorators";
|
||||||
|
import memoizeOne from "memoize-one";
|
||||||
|
import { computeDomain } from "../../../../common/entity/compute_domain";
|
||||||
|
import { computeStateDomain } from "../../../../common/entity/compute_state_domain";
|
||||||
|
import { computeGroupEntitiesState } from "../../../../common/entity/group_entities";
|
||||||
|
import "../../../../components/ha-control-button";
|
||||||
|
import "../../../../components/ha-control-button-group";
|
||||||
|
import "../../../../components/ha-domain-icon";
|
||||||
|
import { isFullyClosed, isFullyOpen } from "../../../../data/cover";
|
||||||
|
import { OFF, ON, UNAVAILABLE } from "../../../../data/entity";
|
||||||
|
import { forwardHaptic } from "../../../../data/haptics";
|
||||||
|
import type { LovelaceSectionConfig } from "../../../../data/lovelace/config/section";
|
||||||
|
import type { TileCardConfig } from "../../../../panels/lovelace/cards/types";
|
||||||
|
import "../../../../panels/lovelace/sections/hui-section";
|
||||||
|
import type { HomeAssistant } from "../../../../types";
|
||||||
|
import "../ha-more-info-state-header";
|
||||||
|
|
||||||
|
export interface GroupToggleDialogParams {
|
||||||
|
entityIds: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
@customElement("ha-more-info-view-toggle-group")
|
||||||
|
class HaMoreInfoViewToggleGroup extends LitElement {
|
||||||
|
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||||
|
|
||||||
|
@property({ attribute: false }) public params?: GroupToggleDialogParams;
|
||||||
|
|
||||||
|
private _sectionConfig = memoizeOne(
|
||||||
|
(entities: string[]): LovelaceSectionConfig => ({
|
||||||
|
type: "grid",
|
||||||
|
cards: entities.map<TileCardConfig>((entity) => ({
|
||||||
|
type: "tile",
|
||||||
|
entity: entity,
|
||||||
|
icon_tap_action: {
|
||||||
|
action: "toggle",
|
||||||
|
},
|
||||||
|
tap_action: {
|
||||||
|
action: "more-info",
|
||||||
|
},
|
||||||
|
grid_options: {
|
||||||
|
columns: 12,
|
||||||
|
},
|
||||||
|
})),
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
private _combineEntities(entities: HassEntity[]): HassEntity {
|
||||||
|
const firstEntity = entities[0];
|
||||||
|
const domain = computeStateDomain(firstEntity);
|
||||||
|
|
||||||
|
const combined: HassEntity = {
|
||||||
|
entity_id: `${domain}.all_entities`,
|
||||||
|
state: computeGroupEntitiesState(entities),
|
||||||
|
attributes: {
|
||||||
|
device_class: firstEntity.attributes.device_class,
|
||||||
|
},
|
||||||
|
last_changed: new Date(
|
||||||
|
Math.max(...entities.map((e) => new Date(e.last_changed).getTime()))
|
||||||
|
).toISOString(),
|
||||||
|
last_updated: new Date(
|
||||||
|
Math.max(...entities.map((e) => new Date(e.last_updated).getTime()))
|
||||||
|
).toISOString(),
|
||||||
|
context: {
|
||||||
|
id: "",
|
||||||
|
parent_id: "",
|
||||||
|
user_id: "",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
return combined;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected render() {
|
||||||
|
if (!this.params) {
|
||||||
|
return nothing;
|
||||||
|
}
|
||||||
|
|
||||||
|
const sectionConfig = this._sectionConfig(this.params.entityIds);
|
||||||
|
|
||||||
|
const entities = this.params.entityIds
|
||||||
|
.map((entityId) => this.hass!.states[entityId] as HassEntity | undefined)
|
||||||
|
.filter((v): v is HassEntity => Boolean(v));
|
||||||
|
|
||||||
|
const groupStateObj = this._combineEntities(entities);
|
||||||
|
|
||||||
|
const formattedGroupState = this.hass.formatEntityState(groupStateObj);
|
||||||
|
|
||||||
|
const domain = computeStateDomain(groupStateObj);
|
||||||
|
|
||||||
|
const deviceClass = groupStateObj.attributes.device_class;
|
||||||
|
|
||||||
|
const availableEntities = entities.filter(
|
||||||
|
(entity) => entity.state !== UNAVAILABLE
|
||||||
|
);
|
||||||
|
|
||||||
|
const ON_STATE = domain === "cover" ? "open" : ON;
|
||||||
|
const OFF_STATE = domain === "cover" ? "closed" : OFF;
|
||||||
|
|
||||||
|
const isAllOn = availableEntities.every((entity) =>
|
||||||
|
computeDomain(entity.entity_id) === "cover"
|
||||||
|
? isFullyOpen(entity)
|
||||||
|
: entity.state === ON_STATE
|
||||||
|
);
|
||||||
|
const isAllOff = availableEntities.every((entity) =>
|
||||||
|
computeDomain(entity.entity_id) === "cover"
|
||||||
|
? isFullyClosed(entity)
|
||||||
|
: entity.state === OFF_STATE
|
||||||
|
);
|
||||||
|
|
||||||
|
const isMultiple = this.params.entityIds.length > 1;
|
||||||
|
|
||||||
|
return html`
|
||||||
|
<div class="content">
|
||||||
|
<ha-more-info-state-header
|
||||||
|
.hass=${this.hass}
|
||||||
|
.stateObj=${groupStateObj}
|
||||||
|
.stateOverride=${formattedGroupState}
|
||||||
|
></ha-more-info-state-header>
|
||||||
|
<div class="main">
|
||||||
|
<ha-control-button-group vertical>
|
||||||
|
<ha-control-button
|
||||||
|
vertical
|
||||||
|
@click=${this._turnAllOn}
|
||||||
|
.disabled=${isAllOn}
|
||||||
|
>
|
||||||
|
<ha-domain-icon
|
||||||
|
.hass=${this.hass}
|
||||||
|
.domain=${domain}
|
||||||
|
.state=${ON_STATE}
|
||||||
|
.deviceClass=${deviceClass}
|
||||||
|
></ha-domain-icon>
|
||||||
|
<p>
|
||||||
|
${domain === "cover"
|
||||||
|
? isMultiple
|
||||||
|
? this.hass.localize("ui.card.cover.open_all")
|
||||||
|
: this.hass.localize("ui.card.cover.open")
|
||||||
|
: isMultiple
|
||||||
|
? this.hass.localize("ui.card.common.turn_on_all")
|
||||||
|
: this.hass.localize("ui.card.common.turn_on")}
|
||||||
|
</p>
|
||||||
|
</ha-control-button>
|
||||||
|
<ha-control-button
|
||||||
|
vertical
|
||||||
|
@click=${this._turnAllOff}
|
||||||
|
.disabled=${isAllOff}
|
||||||
|
>
|
||||||
|
<ha-domain-icon
|
||||||
|
.hass=${this.hass}
|
||||||
|
.domain=${domain}
|
||||||
|
.state=${OFF_STATE}
|
||||||
|
.deviceClass=${deviceClass}
|
||||||
|
.icon=${domain === "light" ? "mdi:lightbulb-off" : undefined}
|
||||||
|
></ha-domain-icon>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
${domain === "cover"
|
||||||
|
? isMultiple
|
||||||
|
? this.hass.localize("ui.card.cover.close_all")
|
||||||
|
: this.hass.localize("ui.card.cover.close")
|
||||||
|
: isMultiple
|
||||||
|
? this.hass.localize("ui.card.common.turn_off_all")
|
||||||
|
: this.hass.localize("ui.card.common.turn_off")}
|
||||||
|
</p>
|
||||||
|
</ha-control-button>
|
||||||
|
</ha-control-button-group>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="entities">
|
||||||
|
<hui-section
|
||||||
|
.config=${sectionConfig}
|
||||||
|
.hass=${this.hass}
|
||||||
|
></hui-section>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
private _turnAllOff() {
|
||||||
|
if (!this.params) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
forwardHaptic("light");
|
||||||
|
const domain = computeDomain(this.params.entityIds[0]);
|
||||||
|
if (domain === "cover") {
|
||||||
|
this.hass.callService("cover", "close_cover", {
|
||||||
|
entity_id: this.params.entityIds,
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.hass.callService("homeassistant", "turn_off", {
|
||||||
|
entity_id: this.params.entityIds,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private _turnAllOn() {
|
||||||
|
if (!this.params) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
forwardHaptic("light");
|
||||||
|
const domain = computeDomain(this.params.entityIds[0]);
|
||||||
|
if (domain === "cover") {
|
||||||
|
this.hass.callService("cover", "open_cover", {
|
||||||
|
entity_id: this.params.entityIds,
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.hass.callService("homeassistant", "turn_on", {
|
||||||
|
entity_id: this.params.entityIds,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
static styles = [
|
||||||
|
css`
|
||||||
|
:host {
|
||||||
|
display: flex;
|
||||||
|
flex: 1;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
.content {
|
||||||
|
display: flex;
|
||||||
|
flex: 1;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
gap: 24px;
|
||||||
|
}
|
||||||
|
ha-more-info-state-header {
|
||||||
|
margin-top: 24px;
|
||||||
|
}
|
||||||
|
.main {
|
||||||
|
display: flex;
|
||||||
|
flex: 1;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
ha-control-button-group {
|
||||||
|
--control-button-group-spacing: 12px;
|
||||||
|
--control-button-group-thickness: 130px;
|
||||||
|
}
|
||||||
|
ha-control-button {
|
||||||
|
--control-button-border-radius: 16px;
|
||||||
|
--mdc-icon-size: 24px;
|
||||||
|
--control-button-padding: 16px 8px;
|
||||||
|
--control-button-background-opacity: 0.1;
|
||||||
|
}
|
||||||
|
ha-control-button p {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
.entities {
|
||||||
|
box-sizing: border-box;
|
||||||
|
width: 100%;
|
||||||
|
background-color: var(--primary-background-color);
|
||||||
|
padding: 12px;
|
||||||
|
padding-bottom: max(var(--safe-area-inset-bottom), 12px);
|
||||||
|
}
|
||||||
|
hui-section {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
"ha-more-info-view-toggle-group": HaMoreInfoViewToggleGroup;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -8,9 +8,9 @@ export const showVoiceAssistantsView = (
|
|||||||
title: string
|
title: string
|
||||||
): void => {
|
): void => {
|
||||||
fireEvent(element, "show-child-view", {
|
fireEvent(element, "show-child-view", {
|
||||||
viewTag: "ha-more-info-view-voice-assistants",
|
tag: "ha-more-info-view-voice-assistants",
|
||||||
viewImport: loadVoiceAssistantsView,
|
import: loadVoiceAssistantsView,
|
||||||
viewTitle: title,
|
title: title,
|
||||||
viewParams: {},
|
params: {},
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import {
|
|||||||
mdiPencilOutline,
|
mdiPencilOutline,
|
||||||
} from "@mdi/js";
|
} from "@mdi/js";
|
||||||
import type { HassEntity } from "home-assistant-js-websocket";
|
import type { HassEntity } from "home-assistant-js-websocket";
|
||||||
import type { PropertyValues } from "lit";
|
import type { PropertyValues, TemplateResult } from "lit";
|
||||||
import { LitElement, css, html, nothing } from "lit";
|
import { LitElement, css, html, nothing } from "lit";
|
||||||
import { customElement, property, state } from "lit/decorators";
|
import { customElement, property, state } from "lit/decorators";
|
||||||
import { cache } from "lit/directives/cache";
|
import { cache } from "lit/directives/cache";
|
||||||
@@ -68,15 +68,24 @@ export interface MoreInfoDialogParams {
|
|||||||
view?: View;
|
view?: View;
|
||||||
/** @deprecated Use `view` instead */
|
/** @deprecated Use `view` instead */
|
||||||
tab?: View;
|
tab?: View;
|
||||||
|
parentView?: ParentView;
|
||||||
}
|
}
|
||||||
|
|
||||||
type View = "info" | "history" | "settings" | "related";
|
type View = "info" | "history" | "settings" | "related" | "parent";
|
||||||
|
|
||||||
|
interface ParentView {
|
||||||
|
tag: string;
|
||||||
|
title?: string;
|
||||||
|
subtitle?: string;
|
||||||
|
import?: () => Promise<unknown>;
|
||||||
|
params?: any;
|
||||||
|
}
|
||||||
|
|
||||||
interface ChildView {
|
interface ChildView {
|
||||||
viewTag: string;
|
tag: string;
|
||||||
viewTitle?: string;
|
title?: string;
|
||||||
viewImport?: () => Promise<unknown>;
|
import?: () => Promise<unknown>;
|
||||||
viewParams?: any;
|
params?: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
@@ -88,7 +97,8 @@ declare global {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const DEFAULT_VIEW: View = "info";
|
const INFO_VIEW: View = "info";
|
||||||
|
const PARENT_VIEW: View = "parent";
|
||||||
|
|
||||||
@customElement("ha-more-info-dialog")
|
@customElement("ha-more-info-dialog")
|
||||||
export class MoreInfoDialog extends LitElement {
|
export class MoreInfoDialog extends LitElement {
|
||||||
@@ -98,9 +108,11 @@ export class MoreInfoDialog extends LitElement {
|
|||||||
|
|
||||||
@state() private _entityId?: string | null;
|
@state() private _entityId?: string | null;
|
||||||
|
|
||||||
@state() private _currView: View = DEFAULT_VIEW;
|
@state() private _currView: View = INFO_VIEW;
|
||||||
|
|
||||||
@state() private _initialView: View = DEFAULT_VIEW;
|
@state() private _initialView: View = INFO_VIEW;
|
||||||
|
|
||||||
|
@state() private _parentView?: ParentView;
|
||||||
|
|
||||||
@state() private _childView?: ChildView;
|
@state() private _childView?: ChildView;
|
||||||
|
|
||||||
@@ -114,17 +126,29 @@ export class MoreInfoDialog extends LitElement {
|
|||||||
|
|
||||||
public showDialog(params: MoreInfoDialogParams) {
|
public showDialog(params: MoreInfoDialogParams) {
|
||||||
this._entityId = params.entityId;
|
this._entityId = params.entityId;
|
||||||
if (!this._entityId) {
|
if (!this._entityId && !params.parentView) {
|
||||||
this.closeDialog();
|
this.closeDialog();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this._currView = params.view || DEFAULT_VIEW;
|
this._parentView = params.parentView;
|
||||||
this._initialView = params.view || DEFAULT_VIEW;
|
if (this._parentView?.import) {
|
||||||
|
this._parentView.import();
|
||||||
|
this._currView = PARENT_VIEW;
|
||||||
|
} else {
|
||||||
|
this._currView = params.view || INFO_VIEW;
|
||||||
|
}
|
||||||
|
this._initialView = params.view || INFO_VIEW;
|
||||||
this._childView = undefined;
|
this._childView = undefined;
|
||||||
this.large = false;
|
this.large = false;
|
||||||
this._loadEntityRegistryEntry();
|
this._loadEntityRegistryEntry();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public willUpdate(changedProps: PropertyValues): void {
|
||||||
|
if (changedProps.has("_entityId")) {
|
||||||
|
this._loadEntityRegistryEntry();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private async _loadEntityRegistryEntry() {
|
private async _loadEntityRegistryEntry() {
|
||||||
if (!this._entityId) {
|
if (!this._entityId) {
|
||||||
return;
|
return;
|
||||||
@@ -143,19 +167,18 @@ export class MoreInfoDialog extends LitElement {
|
|||||||
this._entityId = undefined;
|
this._entityId = undefined;
|
||||||
this._entry = undefined;
|
this._entry = undefined;
|
||||||
this._childView = undefined;
|
this._childView = undefined;
|
||||||
|
this._parentView = undefined;
|
||||||
|
this._currView = INFO_VIEW;
|
||||||
this._infoEditMode = false;
|
this._infoEditMode = false;
|
||||||
this._initialView = DEFAULT_VIEW;
|
this._initialView = INFO_VIEW;
|
||||||
this._isEscapeEnabled = true;
|
this._isEscapeEnabled = true;
|
||||||
window.removeEventListener("dialog-closed", this._enableEscapeKeyClose);
|
window.removeEventListener("dialog-closed", this._enableEscapeKeyClose);
|
||||||
window.removeEventListener("show-dialog", this._disableEscapeKeyClose);
|
window.removeEventListener("show-dialog", this._disableEscapeKeyClose);
|
||||||
fireEvent(this, "dialog-closed", { dialog: this.localName });
|
fireEvent(this, "dialog-closed", { dialog: this.localName });
|
||||||
}
|
}
|
||||||
|
|
||||||
private _shouldShowEditIcon(
|
private _shouldShowEditIcon(domain?: string, stateObj?: HassEntity): boolean {
|
||||||
domain: string,
|
if (__DEMO__ || !stateObj || !domain) {
|
||||||
stateObj: HassEntity | undefined
|
|
||||||
): boolean {
|
|
||||||
if (__DEMO__ || !stateObj) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (EDITABLE_DOMAINS_WITH_ID.includes(domain) && stateObj.attributes.id) {
|
if (EDITABLE_DOMAINS_WITH_ID.includes(domain) && stateObj.attributes.id) {
|
||||||
@@ -171,8 +194,9 @@ export class MoreInfoDialog extends LitElement {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private _shouldShowHistory(domain: string): boolean {
|
private _shouldShowHistory(domain?: string): boolean {
|
||||||
return (
|
return (
|
||||||
|
domain !== undefined &&
|
||||||
DOMAINS_WITH_MORE_INFO.includes(domain) &&
|
DOMAINS_WITH_MORE_INFO.includes(domain) &&
|
||||||
(computeShowHistoryComponent(this.hass, this._entityId!) ||
|
(computeShowHistoryComponent(this.hass, this._entityId!) ||
|
||||||
computeShowLogBookComponent(
|
computeShowLogBookComponent(
|
||||||
@@ -207,14 +231,30 @@ export class MoreInfoDialog extends LitElement {
|
|||||||
private _goBack() {
|
private _goBack() {
|
||||||
if (this._childView) {
|
if (this._childView) {
|
||||||
this._childView = undefined;
|
this._childView = undefined;
|
||||||
} else {
|
return;
|
||||||
this._setView(this._initialView);
|
}
|
||||||
|
const previousView = this._previousView();
|
||||||
|
if (previousView) {
|
||||||
|
this._setView(previousView);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private _previousView(): View | undefined {
|
||||||
|
if (this._currView === PARENT_VIEW) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
if (this._currView !== this._initialView) {
|
||||||
|
return this._initialView;
|
||||||
|
}
|
||||||
|
if (this._parentView) {
|
||||||
|
return PARENT_VIEW;
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
private _resetInitialView() {
|
private _resetInitialView() {
|
||||||
this._initialView = DEFAULT_VIEW;
|
this._initialView = INFO_VIEW;
|
||||||
this._setView(DEFAULT_VIEW);
|
this._setView(INFO_VIEW);
|
||||||
}
|
}
|
||||||
|
|
||||||
private _goToHistory() {
|
private _goToHistory() {
|
||||||
@@ -227,8 +267,8 @@ export class MoreInfoDialog extends LitElement {
|
|||||||
|
|
||||||
private _showChildView(ev: CustomEvent): void {
|
private _showChildView(ev: CustomEvent): void {
|
||||||
const view = ev.detail as ChildView;
|
const view = ev.detail as ChildView;
|
||||||
if (view.viewImport) {
|
if (view.import) {
|
||||||
view.viewImport();
|
view.import();
|
||||||
}
|
}
|
||||||
this._childView = view;
|
this._childView = view;
|
||||||
}
|
}
|
||||||
@@ -286,24 +326,31 @@ export class MoreInfoDialog extends LitElement {
|
|||||||
this._sensorNumericDeviceClasses = deviceClasses.numeric_device_classes;
|
this._sensorNumericDeviceClasses = deviceClasses.numeric_device_classes;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected render() {
|
private _handleMoreInfoEvent(ev: CustomEvent) {
|
||||||
if (!this._entityId) {
|
// If the parent view has a `show-dialog` event to open more info, we handle it here to set the entity ID and view.
|
||||||
return nothing;
|
const detail = ev.detail as MoreInfoDialogParams;
|
||||||
|
if (detail.entityId) {
|
||||||
|
this._entityId = detail.entityId;
|
||||||
|
this._setView(detail.view || INFO_VIEW);
|
||||||
|
ev.stopPropagation();
|
||||||
|
ev.preventDefault();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private _renderHeader = (): TemplateResult | typeof nothing => {
|
||||||
|
if (this._parentView && this._currView === PARENT_VIEW) {
|
||||||
|
return html`
|
||||||
|
${this._parentView
|
||||||
|
? html`<p class="breadcrumb">${this._parentView.subtitle}</p>`
|
||||||
|
: nothing}
|
||||||
|
<p class="main">${this._parentView.title}</p>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
const entityId = this._entityId;
|
const entityId = this._entityId;
|
||||||
|
|
||||||
|
if (entityId) {
|
||||||
const stateObj = this.hass.states[entityId] as HassEntity | undefined;
|
const stateObj = this.hass.states[entityId] as HassEntity | undefined;
|
||||||
|
|
||||||
const domain = computeDomain(entityId);
|
|
||||||
|
|
||||||
const isAdmin = this.hass.user!.is_admin;
|
|
||||||
|
|
||||||
const deviceId = this._getDeviceId();
|
|
||||||
|
|
||||||
const isDefaultView = this._currView === DEFAULT_VIEW && !this._childView;
|
|
||||||
const isSpecificInitialView =
|
|
||||||
this._initialView !== DEFAULT_VIEW && !this._childView;
|
|
||||||
const showCloseIcon = isDefaultView || isSpecificInitialView;
|
|
||||||
|
|
||||||
const context = stateObj
|
const context = stateObj
|
||||||
? getEntityContext(stateObj, this.hass)
|
? getEntityContext(stateObj, this.hass)
|
||||||
: this._entry
|
: this._entry
|
||||||
@@ -319,12 +366,59 @@ export class MoreInfoDialog extends LitElement {
|
|||||||
const deviceName = context?.device
|
const deviceName = context?.device
|
||||||
? computeDeviceName(context.device)
|
? computeDeviceName(context.device)
|
||||||
: undefined;
|
: undefined;
|
||||||
const areaName = context?.area ? computeAreaName(context.area) : undefined;
|
const areaName = context?.area
|
||||||
|
? computeAreaName(context.area)
|
||||||
|
: undefined;
|
||||||
|
|
||||||
const breadcrumb = [areaName, deviceName, entityName].filter(
|
const breadcrumb = [areaName, deviceName, entityName].filter(
|
||||||
(v): v is string => Boolean(v)
|
(v): v is string => Boolean(v)
|
||||||
);
|
);
|
||||||
const title = this._childView?.viewTitle || breadcrumb.pop() || entityId;
|
const title = this._childView?.title || breadcrumb.pop() || entityId;
|
||||||
|
const isAdmin = this.hass.user!.is_admin;
|
||||||
|
|
||||||
|
return html`
|
||||||
|
${breadcrumb.length > 0
|
||||||
|
? !__DEMO__ && isAdmin
|
||||||
|
? html`
|
||||||
|
<button
|
||||||
|
class="breadcrumb"
|
||||||
|
@click=${this._breadcrumbClick}
|
||||||
|
aria-label=${breadcrumb.join(" > ")}
|
||||||
|
>
|
||||||
|
${join(breadcrumb, html`<ha-icon-next></ha-icon-next>`)}
|
||||||
|
</button>
|
||||||
|
`
|
||||||
|
: html`
|
||||||
|
<p class="breadcrumb">
|
||||||
|
${join(breadcrumb, html`<ha-icon-next></ha-icon-next>`)}
|
||||||
|
</p>
|
||||||
|
`
|
||||||
|
: nothing}
|
||||||
|
<p class="main">${title}</p>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return nothing;
|
||||||
|
};
|
||||||
|
|
||||||
|
protected render() {
|
||||||
|
if (!this._entityId && !this._parentView) {
|
||||||
|
return nothing;
|
||||||
|
}
|
||||||
|
const entityId = this._entityId;
|
||||||
|
const stateObj = entityId ? this.hass.states[entityId] : undefined;
|
||||||
|
|
||||||
|
const domain = entityId ? computeDomain(entityId) : undefined;
|
||||||
|
|
||||||
|
const isAdmin = this.hass.user!.is_admin;
|
||||||
|
|
||||||
|
const deviceId = this._getDeviceId();
|
||||||
|
|
||||||
|
const previousView = this._previousView();
|
||||||
|
const isDefaultView = this._currView === INFO_VIEW && !this._childView;
|
||||||
|
const isSpecificInitialView =
|
||||||
|
this._initialView !== INFO_VIEW && !this._childView;
|
||||||
|
const showCloseIcon = !previousView && !this._childView;
|
||||||
|
|
||||||
return html`
|
return html`
|
||||||
<ha-dialog
|
<ha-dialog
|
||||||
@@ -332,7 +426,7 @@ export class MoreInfoDialog extends LitElement {
|
|||||||
@closed=${this.closeDialog}
|
@closed=${this.closeDialog}
|
||||||
@opened=${this._handleOpened}
|
@opened=${this._handleOpened}
|
||||||
.escapeKeyAction=${this._isEscapeEnabled ? undefined : ""}
|
.escapeKeyAction=${this._isEscapeEnabled ? undefined : ""}
|
||||||
.heading=${title}
|
.heading=${" "}
|
||||||
hideActions
|
hideActions
|
||||||
flexContent
|
flexContent
|
||||||
>
|
>
|
||||||
@@ -356,24 +450,7 @@ export class MoreInfoDialog extends LitElement {
|
|||||||
></ha-icon-button-prev>
|
></ha-icon-button-prev>
|
||||||
`}
|
`}
|
||||||
<span slot="title" @click=${this._enlarge} class="title">
|
<span slot="title" @click=${this._enlarge} class="title">
|
||||||
${breadcrumb.length > 0
|
${this._renderHeader()}
|
||||||
? !__DEMO__ && isAdmin
|
|
||||||
? html`
|
|
||||||
<button
|
|
||||||
class="breadcrumb"
|
|
||||||
@click=${this._breadcrumbClick}
|
|
||||||
aria-label=${breadcrumb.join(" > ")}
|
|
||||||
>
|
|
||||||
${join(breadcrumb, html`<ha-icon-next></ha-icon-next>`)}
|
|
||||||
</button>
|
|
||||||
`
|
|
||||||
: html`
|
|
||||||
<p class="breadcrumb">
|
|
||||||
${join(breadcrumb, html`<ha-icon-next></ha-icon-next>`)}
|
|
||||||
</p>
|
|
||||||
`
|
|
||||||
: nothing}
|
|
||||||
<p class="main">${title}</p>
|
|
||||||
</span>
|
</span>
|
||||||
${isDefaultView
|
${isDefaultView
|
||||||
? html`
|
? html`
|
||||||
@@ -521,18 +598,25 @@ export class MoreInfoDialog extends LitElement {
|
|||||||
@show-child-view=${this._showChildView}
|
@show-child-view=${this._showChildView}
|
||||||
@entity-entry-updated=${this._entryUpdated}
|
@entity-entry-updated=${this._entryUpdated}
|
||||||
@toggle-edit-mode=${this._handleToggleInfoEditModeEvent}
|
@toggle-edit-mode=${this._handleToggleInfoEditModeEvent}
|
||||||
|
@hass-more-info=${this._handleMoreInfoEvent}
|
||||||
>
|
>
|
||||||
${cache(
|
${cache(
|
||||||
this._childView
|
this._childView
|
||||||
? html`
|
? html`
|
||||||
<div class="child-view">
|
<div class="child-view">
|
||||||
${dynamicElement(this._childView.viewTag, {
|
${dynamicElement(this._childView.tag, {
|
||||||
hass: this.hass,
|
hass: this.hass,
|
||||||
entry: this._entry,
|
entry: this._entry,
|
||||||
params: this._childView.viewParams,
|
params: this._childView.params,
|
||||||
})}
|
})}
|
||||||
</div>
|
</div>
|
||||||
`
|
`
|
||||||
|
: this._currView === "parent"
|
||||||
|
? dynamicElement(this._parentView!.tag, {
|
||||||
|
hass: this.hass,
|
||||||
|
entry: this._entry,
|
||||||
|
params: this._parentView!.params,
|
||||||
|
})
|
||||||
: this._currView === "info"
|
: this._currView === "info"
|
||||||
? html`
|
? html`
|
||||||
<ha-more-info-info
|
<ha-more-info-info
|
||||||
@@ -563,7 +647,8 @@ export class MoreInfoDialog extends LitElement {
|
|||||||
<ha-related-items
|
<ha-related-items
|
||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
.itemId=${entityId}
|
.itemId=${entityId}
|
||||||
.itemType=${SearchableDomains.has(domain)
|
.itemType=${domain &&
|
||||||
|
SearchableDomains.has(domain)
|
||||||
? (domain as ItemType)
|
? (domain as ItemType)
|
||||||
: "entity"}
|
: "entity"}
|
||||||
></ha-related-items>
|
></ha-related-items>
|
||||||
|
|||||||
@@ -5,11 +5,9 @@ import { classMap } from "lit/directives/class-map";
|
|||||||
import { styleMap } from "lit/directives/style-map";
|
import { styleMap } from "lit/directives/style-map";
|
||||||
import memoizeOne from "memoize-one";
|
import memoizeOne from "memoize-one";
|
||||||
import { ensureArray } from "../../../common/array/ensure-array";
|
import { ensureArray } from "../../../common/array/ensure-array";
|
||||||
|
import { computeAreaName } from "../../../common/entity/compute_area_name";
|
||||||
import { generateEntityFilter } from "../../../common/entity/entity_filter";
|
import { generateEntityFilter } from "../../../common/entity/entity_filter";
|
||||||
import {
|
import { computeGroupEntitiesState } from "../../../common/entity/group_entities";
|
||||||
computeGroupEntitiesState,
|
|
||||||
toggleGroupEntities,
|
|
||||||
} from "../../../common/entity/group_entities";
|
|
||||||
import { stateActive } from "../../../common/entity/state_active";
|
import { stateActive } from "../../../common/entity/state_active";
|
||||||
import { domainColorProperties } from "../../../common/entity/state_color";
|
import { domainColorProperties } from "../../../common/entity/state_color";
|
||||||
import "../../../components/ha-control-button";
|
import "../../../components/ha-control-button";
|
||||||
@@ -17,7 +15,8 @@ import "../../../components/ha-control-button-group";
|
|||||||
import "../../../components/ha-domain-icon";
|
import "../../../components/ha-domain-icon";
|
||||||
import "../../../components/ha-svg-icon";
|
import "../../../components/ha-svg-icon";
|
||||||
import type { AreaRegistryEntry } from "../../../data/area_registry";
|
import type { AreaRegistryEntry } from "../../../data/area_registry";
|
||||||
import { forwardHaptic } from "../../../data/haptics";
|
import type { GroupToggleDialogParams } from "../../../dialogs/more-info/components/voice/ha-more-info-view-toggle-group";
|
||||||
|
import { showMoreInfoDialog } from "../../../dialogs/more-info/show-ha-more-info-dialog";
|
||||||
import { computeCssVariable } from "../../../resources/css-variables";
|
import { computeCssVariable } from "../../../resources/css-variables";
|
||||||
import type { HomeAssistant } from "../../../types";
|
import type { HomeAssistant } from "../../../types";
|
||||||
import type { AreaCardFeatureContext } from "../cards/hui-area-card";
|
import type { AreaCardFeatureContext } from "../cards/hui-area-card";
|
||||||
@@ -32,40 +31,25 @@ import type {
|
|||||||
import { AREA_CONTROLS } from "./types";
|
import { AREA_CONTROLS } from "./types";
|
||||||
|
|
||||||
interface AreaControlsButton {
|
interface AreaControlsButton {
|
||||||
offIcon?: string;
|
|
||||||
onIcon?: string;
|
|
||||||
filter: {
|
|
||||||
domain: string;
|
domain: string;
|
||||||
device_class?: string;
|
device_class?: string;
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const coverButton = (deviceClass: string) => ({
|
const coverButton = (deviceClass: string) => ({
|
||||||
filter: {
|
|
||||||
domain: "cover",
|
domain: "cover",
|
||||||
device_class: deviceClass,
|
device_class: deviceClass,
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
export const AREA_CONTROLS_BUTTONS: Record<AreaControl, AreaControlsButton> = {
|
export const AREA_CONTROLS_BUTTONS: Record<AreaControl, AreaControlsButton> = {
|
||||||
light: {
|
light: {
|
||||||
// Overrides the icons for lights
|
|
||||||
offIcon: "mdi:lightbulb-off",
|
|
||||||
onIcon: "mdi:lightbulb",
|
|
||||||
filter: {
|
|
||||||
domain: "light",
|
domain: "light",
|
||||||
},
|
},
|
||||||
},
|
|
||||||
fan: {
|
fan: {
|
||||||
filter: {
|
|
||||||
domain: "fan",
|
domain: "fan",
|
||||||
},
|
},
|
||||||
},
|
|
||||||
switch: {
|
switch: {
|
||||||
filter: {
|
|
||||||
domain: "switch",
|
domain: "switch",
|
||||||
},
|
},
|
||||||
},
|
|
||||||
"cover-blind": coverButton("blind"),
|
"cover-blind": coverButton("blind"),
|
||||||
"cover-curtain": coverButton("curtain"),
|
"cover-curtain": coverButton("curtain"),
|
||||||
"cover-damper": coverButton("damper"),
|
"cover-damper": coverButton("damper"),
|
||||||
@@ -98,7 +82,8 @@ export const getAreaControlEntities = (
|
|||||||
const filter = generateEntityFilter(hass, {
|
const filter = generateEntityFilter(hass, {
|
||||||
area: areaId,
|
area: areaId,
|
||||||
entity_category: "none",
|
entity_category: "none",
|
||||||
...controlButton.filter,
|
domain: controlButton.domain,
|
||||||
|
device_class: controlButton.device_class,
|
||||||
});
|
});
|
||||||
|
|
||||||
acc[control] = Object.keys(hass.entities).filter(
|
acc[control] = Object.keys(hass.entities).filter(
|
||||||
@@ -160,9 +145,7 @@ class HuiAreaControlsCardFeature
|
|||||||
this._config = config;
|
this._config = config;
|
||||||
}
|
}
|
||||||
|
|
||||||
private _handleButtonTap(ev: MouseEvent) {
|
private async _handleButtonTap(ev: MouseEvent) {
|
||||||
ev.stopPropagation();
|
|
||||||
|
|
||||||
if (!this.context?.area_id || !this.hass || !this._config) {
|
if (!this.context?.area_id || !this.hass || !this._config) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -178,12 +161,27 @@ class HuiAreaControlsCardFeature
|
|||||||
);
|
);
|
||||||
const entitiesIds = controlEntities[control];
|
const entitiesIds = controlEntities[control];
|
||||||
|
|
||||||
const entities = entitiesIds
|
const { domain, device_class: dc } = AREA_CONTROLS_BUTTONS[control];
|
||||||
.map((entityId) => this.hass!.states[entityId] as HassEntity | undefined)
|
|
||||||
.filter((v): v is HassEntity => Boolean(v));
|
|
||||||
|
|
||||||
forwardHaptic("light");
|
const domainName = this.hass.localize(
|
||||||
toggleGroupEntities(this.hass, entities);
|
`component.${domain}.entity_component.${dc ?? "_"}.name`
|
||||||
|
);
|
||||||
|
|
||||||
|
showMoreInfoDialog(this, {
|
||||||
|
entityId: null,
|
||||||
|
parentView: {
|
||||||
|
title: computeAreaName(this._area!) || "",
|
||||||
|
subtitle: domainName,
|
||||||
|
tag: "ha-more-info-view-toggle-group",
|
||||||
|
import: () =>
|
||||||
|
import(
|
||||||
|
"../../../dialogs/more-info/components/voice/ha-more-info-view-toggle-group"
|
||||||
|
),
|
||||||
|
params: {
|
||||||
|
entityIds: entitiesIds,
|
||||||
|
} as GroupToggleDialogParams,
|
||||||
|
},
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private _controlEntities = memoizeOne(
|
private _controlEntities = memoizeOne(
|
||||||
@@ -254,15 +252,22 @@ class HuiAreaControlsCardFeature
|
|||||||
? stateActive(entities[0], groupState)
|
? stateActive(entities[0], groupState)
|
||||||
: false;
|
: false;
|
||||||
|
|
||||||
const label = this.hass!.localize(
|
const domain = button.domain;
|
||||||
`ui.card_features.area_controls.${control}.${active ? "off" : "on"}`
|
const dc = button.device_class;
|
||||||
|
|
||||||
|
const domainName = this.hass!.localize(
|
||||||
|
`component.${domain}.entity_component.${dc ?? "_"}.name`
|
||||||
);
|
);
|
||||||
|
|
||||||
const icon = active ? button.onIcon : button.offIcon;
|
const label = `${domainName}: ${this.hass!.localize(
|
||||||
|
`ui.card_features.area_controls.open_more_info`
|
||||||
|
)}`;
|
||||||
|
|
||||||
const domain = button.filter.domain;
|
const icon =
|
||||||
const deviceClass = button.filter.device_class
|
domain === "light" && !active ? "mdi:lightbulb-off" : undefined;
|
||||||
? ensureArray(button.filter.device_class)[0]
|
|
||||||
|
const deviceClass = button.device_class
|
||||||
|
? ensureArray(button.device_class)[0]
|
||||||
: undefined;
|
: undefined;
|
||||||
|
|
||||||
const activeColor = computeCssVariable(
|
const activeColor = computeCssVariable(
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { ReactiveElement } from "lit";
|
import { ReactiveElement } from "lit";
|
||||||
import { customElement } from "lit/decorators";
|
import { customElement } from "lit/decorators";
|
||||||
|
import { computeDomain } from "../../../../common/entity/compute_domain";
|
||||||
import { clamp } from "../../../../common/number/clamp";
|
import { clamp } from "../../../../common/number/clamp";
|
||||||
import type { LovelaceBadgeConfig } from "../../../../data/lovelace/config/badge";
|
import type { LovelaceBadgeConfig } from "../../../../data/lovelace/config/badge";
|
||||||
import type { LovelaceCardConfig } from "../../../../data/lovelace/config/card";
|
import type { LovelaceCardConfig } from "../../../../data/lovelace/config/card";
|
||||||
@@ -148,7 +149,22 @@ export class AreaViewStrategy extends ReactiveElement {
|
|||||||
hass.localize("ui.panel.lovelace.strategy.areas.groups.security"),
|
hass.localize("ui.panel.lovelace.strategy.areas.groups.security"),
|
||||||
AREA_STRATEGY_GROUP_ICONS.security
|
AREA_STRATEGY_GROUP_ICONS.security
|
||||||
),
|
),
|
||||||
...security.map(computeTileCard),
|
...security.map((entityId) => {
|
||||||
|
const domain = computeDomain(entityId);
|
||||||
|
if (domain === "camera") {
|
||||||
|
return {
|
||||||
|
type: "picture-entity",
|
||||||
|
entity: entityId,
|
||||||
|
show_state: false,
|
||||||
|
show_name: false,
|
||||||
|
grid_options: {
|
||||||
|
columns: 6,
|
||||||
|
rows: 2,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return computeTileCard(entityId);
|
||||||
|
}),
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import { computeDomain } from "../../../../../common/entity/compute_domain";
|
|
||||||
import { computeStateName } from "../../../../../common/entity/compute_state_name";
|
import { computeStateName } from "../../../../../common/entity/compute_state_name";
|
||||||
import type { EntityFilterFunc } from "../../../../../common/entity/entity_filter";
|
import type { EntityFilterFunc } from "../../../../../common/entity/entity_filter";
|
||||||
import { generateEntityFilter } from "../../../../../common/entity/entity_filter";
|
import { generateEntityFilter } from "../../../../../common/entity/entity_filter";
|
||||||
@@ -10,7 +9,6 @@ import {
|
|||||||
import type { AreaRegistryEntry } from "../../../../../data/area_registry";
|
import type { AreaRegistryEntry } from "../../../../../data/area_registry";
|
||||||
import { areaCompare } from "../../../../../data/area_registry";
|
import { areaCompare } from "../../../../../data/area_registry";
|
||||||
import type { FloorRegistryEntry } from "../../../../../data/floor_registry";
|
import type { FloorRegistryEntry } from "../../../../../data/floor_registry";
|
||||||
import type { LovelaceCardConfig } from "../../../../../data/lovelace/config/card";
|
|
||||||
import type { HomeAssistant } from "../../../../../types";
|
import type { HomeAssistant } from "../../../../../types";
|
||||||
import { supportsAlarmModesCardFeature } from "../../../card-features/hui-alarm-modes-card-feature";
|
import { supportsAlarmModesCardFeature } from "../../../card-features/hui-alarm-modes-card-feature";
|
||||||
import { supportsCoverOpenCloseCardFeature } from "../../../card-features/hui-cover-open-close-card-feature";
|
import { supportsCoverOpenCloseCardFeature } from "../../../card-features/hui-cover-open-close-card-feature";
|
||||||
@@ -210,7 +208,7 @@ export const getAreaGroupedEntities = (
|
|||||||
|
|
||||||
export const computeAreaTileCardConfig =
|
export const computeAreaTileCardConfig =
|
||||||
(hass: HomeAssistant, prefix: string, includeFeature?: boolean) =>
|
(hass: HomeAssistant, prefix: string, includeFeature?: boolean) =>
|
||||||
(entity: string): LovelaceCardConfig => {
|
(entity: string): TileCardConfig => {
|
||||||
const stateObj = hass.states[entity];
|
const stateObj = hass.states[entity];
|
||||||
|
|
||||||
const context: LovelaceCardFeatureContext = {
|
const context: LovelaceCardFeatureContext = {
|
||||||
@@ -219,21 +217,6 @@ export const computeAreaTileCardConfig =
|
|||||||
|
|
||||||
const additionalCardConfig: Partial<TileCardConfig> = {};
|
const additionalCardConfig: Partial<TileCardConfig> = {};
|
||||||
|
|
||||||
const domain = computeDomain(entity);
|
|
||||||
|
|
||||||
if (domain === "camera") {
|
|
||||||
return {
|
|
||||||
type: "picture-entity",
|
|
||||||
entity: entity,
|
|
||||||
show_state: false,
|
|
||||||
show_name: false,
|
|
||||||
grid_options: {
|
|
||||||
columns: 6,
|
|
||||||
rows: 2,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
let feature: LovelaceCardFeatureConfig | undefined;
|
let feature: LovelaceCardFeatureConfig | undefined;
|
||||||
if (includeFeature) {
|
if (includeFeature) {
|
||||||
if (supportsLightBrightnessCardFeature(hass, context)) {
|
if (supportsLightBrightnessCardFeature(hass, context)) {
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ export default <T extends Constructor<HassBaseEl>>(superClass: T) =>
|
|||||||
{
|
{
|
||||||
entityId: ev.detail.entityId,
|
entityId: ev.detail.entityId,
|
||||||
view: ev.detail.view || ev.detail.tab,
|
view: ev.detail.view || ev.detail.tab,
|
||||||
|
parentView: ev.detail.parentView,
|
||||||
},
|
},
|
||||||
() => import("../dialogs/more-info/ha-more-info-dialog")
|
() => import("../dialogs/more-info/ha-more-info-dialog")
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -79,6 +79,8 @@
|
|||||||
"common": {
|
"common": {
|
||||||
"turn_on": "Turn on",
|
"turn_on": "Turn on",
|
||||||
"turn_off": "Turn off",
|
"turn_off": "Turn off",
|
||||||
|
"turn_on_all": "Turn on all",
|
||||||
|
"turn_off_all": "Turn off all",
|
||||||
"toggle": "Toggle",
|
"toggle": "Toggle",
|
||||||
"entity_not_found": "Entity not found"
|
"entity_not_found": "Entity not found"
|
||||||
},
|
},
|
||||||
@@ -145,7 +147,11 @@
|
|||||||
"close_cover": "Close cover",
|
"close_cover": "Close cover",
|
||||||
"open_tilt_cover": "Open cover tilt",
|
"open_tilt_cover": "Open cover tilt",
|
||||||
"close_tilt_cover": "Close cover tilt",
|
"close_tilt_cover": "Close cover tilt",
|
||||||
"stop_cover": "Stop cover"
|
"stop_cover": "Stop cover",
|
||||||
|
"open": "Open",
|
||||||
|
"open_all": "Open all",
|
||||||
|
"close": "Close",
|
||||||
|
"close_all": "Close all"
|
||||||
},
|
},
|
||||||
"fan": {
|
"fan": {
|
||||||
"preset_mode": "Preset mode",
|
"preset_mode": "Preset mode",
|
||||||
@@ -327,58 +333,7 @@
|
|||||||
},
|
},
|
||||||
"card_features": {
|
"card_features": {
|
||||||
"area_controls": {
|
"area_controls": {
|
||||||
"light": {
|
"open_more_info": "Open more info"
|
||||||
"on": "Turn on area lights",
|
|
||||||
"off": "Turn off area lights"
|
|
||||||
},
|
|
||||||
"fan": {
|
|
||||||
"on": "Turn on area fans",
|
|
||||||
"off": "Turn off area fans"
|
|
||||||
},
|
|
||||||
"switch": {
|
|
||||||
"on": "Turn on area switches",
|
|
||||||
"off": "Turn off area switches"
|
|
||||||
},
|
|
||||||
"cover-awning": {
|
|
||||||
"on": "Open area awnings",
|
|
||||||
"off": "Close area awnings"
|
|
||||||
},
|
|
||||||
"cover-blind": {
|
|
||||||
"on": "Open area blinds",
|
|
||||||
"off": "Close area blinds"
|
|
||||||
},
|
|
||||||
"cover-curtain": {
|
|
||||||
"on": "Open area curtains",
|
|
||||||
"off": "Close area curtains"
|
|
||||||
},
|
|
||||||
"cover-damper": {
|
|
||||||
"on": "Open area dampers",
|
|
||||||
"off": "Close area dampers"
|
|
||||||
},
|
|
||||||
"cover-door": {
|
|
||||||
"on": "Open area doors",
|
|
||||||
"off": "Close area doors"
|
|
||||||
},
|
|
||||||
"cover-garage": {
|
|
||||||
"on": "Open garage door",
|
|
||||||
"off": "Close garage door"
|
|
||||||
},
|
|
||||||
"cover-gate": {
|
|
||||||
"on": "Open area gates",
|
|
||||||
"off": "Close area gates"
|
|
||||||
},
|
|
||||||
"cover-shade": {
|
|
||||||
"on": "Open area shades",
|
|
||||||
"off": "Close area shades"
|
|
||||||
},
|
|
||||||
"cover-shutter": {
|
|
||||||
"on": "Open area shutters",
|
|
||||||
"off": "Close area shutters"
|
|
||||||
},
|
|
||||||
"cover-window": {
|
|
||||||
"on": "Open area windows",
|
|
||||||
"off": "Close area windows"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"common": {
|
"common": {
|
||||||
|
|||||||
Reference in New Issue
Block a user