mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-23 09:16:38 +00:00
Updates to alarm panel card configuration (#17598)
* Updates to alarm panel card configuration * changes from feedback
This commit is contained in:
parent
ae9fcebfd5
commit
034ce56da5
@ -9,6 +9,7 @@ import {
|
|||||||
import { customElement, property, query, state } from "lit/decorators";
|
import { customElement, property, query, 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 { HassEntity } from "home-assistant-js-websocket";
|
||||||
import { applyThemesOnElement } from "../../../common/dom/apply_themes_on_element";
|
import { applyThemesOnElement } from "../../../common/dom/apply_themes_on_element";
|
||||||
import { fireEvent } from "../../../common/dom/fire_event";
|
import { fireEvent } from "../../../common/dom/fire_event";
|
||||||
import { alarmPanelIcon } from "../../../common/entity/alarm_panel_icon";
|
import { alarmPanelIcon } from "../../../common/entity/alarm_panel_icon";
|
||||||
@ -20,16 +21,48 @@ import type { HaTextField } from "../../../components/ha-textfield";
|
|||||||
import {
|
import {
|
||||||
callAlarmAction,
|
callAlarmAction,
|
||||||
FORMAT_NUMBER,
|
FORMAT_NUMBER,
|
||||||
|
ALARM_MODES,
|
||||||
|
AlarmMode,
|
||||||
} 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 type { HomeAssistant } from "../../../types";
|
||||||
import { findEntities } from "../common/find-entities";
|
import { findEntities } from "../common/find-entities";
|
||||||
import { createEntityNotFoundWarning } from "../components/hui-warning";
|
import { createEntityNotFoundWarning } from "../components/hui-warning";
|
||||||
import type { LovelaceCard } from "../types";
|
import type { LovelaceCard } from "../types";
|
||||||
import { AlarmPanelCardConfig } from "./types";
|
import { AlarmPanelCardConfig, AlarmPanelCardConfigState } from "./types";
|
||||||
|
import { supportsFeature } from "../../../common/entity/supports-feature";
|
||||||
|
|
||||||
const BUTTONS = ["1", "2", "3", "4", "5", "6", "7", "8", "9", "", "0", "clear"];
|
const BUTTONS = ["1", "2", "3", "4", "5", "6", "7", "8", "9", "", "0", "clear"];
|
||||||
|
|
||||||
|
export const DEFAULT_STATES = [
|
||||||
|
"arm_home",
|
||||||
|
"arm_away",
|
||||||
|
] as AlarmPanelCardConfigState[];
|
||||||
|
|
||||||
|
export const ALARM_MODE_STATE_MAP: Record<
|
||||||
|
AlarmPanelCardConfigState,
|
||||||
|
AlarmMode
|
||||||
|
> = {
|
||||||
|
arm_home: "armed_home",
|
||||||
|
arm_away: "armed_away",
|
||||||
|
arm_night: "armed_night",
|
||||||
|
arm_vacation: "armed_vacation",
|
||||||
|
arm_custom_bypass: "armed_custom_bypass",
|
||||||
|
};
|
||||||
|
|
||||||
|
export const filterSupportedAlarmStates = (
|
||||||
|
stateObj: HassEntity | undefined,
|
||||||
|
states: AlarmPanelCardConfigState[]
|
||||||
|
): AlarmPanelCardConfigState[] =>
|
||||||
|
states.filter(
|
||||||
|
(s) =>
|
||||||
|
stateObj &&
|
||||||
|
supportsFeature(
|
||||||
|
stateObj,
|
||||||
|
ALARM_MODES[ALARM_MODE_STATE_MAP[s]].feature || 0
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
@customElement("hui-alarm-panel-card")
|
@customElement("hui-alarm-panel-card")
|
||||||
class HuiAlarmPanelCard extends LitElement implements LovelaceCard {
|
class HuiAlarmPanelCard extends LitElement implements LovelaceCard {
|
||||||
public static async getConfigElement() {
|
public static async getConfigElement() {
|
||||||
@ -52,10 +85,13 @@ class HuiAlarmPanelCard extends LitElement implements LovelaceCard {
|
|||||||
includeDomains
|
includeDomains
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const entity = foundEntities[0] || "";
|
||||||
|
const stateObj = hass.states[entity];
|
||||||
|
|
||||||
return {
|
return {
|
||||||
type: "alarm-panel",
|
type: "alarm-panel",
|
||||||
states: ["arm_home", "arm_away"],
|
states: filterSupportedAlarmStates(stateObj, DEFAULT_STATES),
|
||||||
entity: foundEntities[0] || "",
|
entity,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -86,11 +122,7 @@ class HuiAlarmPanelCard extends LitElement implements LovelaceCard {
|
|||||||
throw new Error("Invalid configuration");
|
throw new Error("Invalid configuration");
|
||||||
}
|
}
|
||||||
|
|
||||||
const defaults = {
|
this._config = { ...config };
|
||||||
states: ["arm_away", "arm_home"] as const,
|
|
||||||
};
|
|
||||||
|
|
||||||
this._config = { ...defaults, ...config };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected updated(changedProps: PropertyValues): void {
|
protected updated(changedProps: PropertyValues): void {
|
||||||
@ -138,6 +170,9 @@ class HuiAlarmPanelCard extends LitElement implements LovelaceCard {
|
|||||||
return nothing;
|
return nothing;
|
||||||
}
|
}
|
||||||
const stateObj = this.hass.states[this._config.entity];
|
const stateObj = this.hass.states[this._config.entity];
|
||||||
|
const states =
|
||||||
|
this._config.states ||
|
||||||
|
filterSupportedAlarmStates(stateObj, DEFAULT_STATES);
|
||||||
|
|
||||||
if (!stateObj) {
|
if (!stateObj) {
|
||||||
return html`
|
return html`
|
||||||
@ -170,7 +205,7 @@ class HuiAlarmPanelCard extends LitElement implements LovelaceCard {
|
|||||||
</h1>
|
</h1>
|
||||||
<div id="armActions" class="actions">
|
<div id="armActions" class="actions">
|
||||||
${(stateObj.state === "disarmed"
|
${(stateObj.state === "disarmed"
|
||||||
? this._config.states!
|
? states
|
||||||
: (["disarm"] as const)
|
: (["disarm"] as const)
|
||||||
).map(
|
).map(
|
||||||
(stateAction) => html`
|
(stateAction) => html`
|
||||||
|
@ -14,10 +14,17 @@ import { HaDurationData } from "../../../components/ha-duration-input";
|
|||||||
import { LovelaceTileFeatureConfig } from "../tile-features/types";
|
import { LovelaceTileFeatureConfig } from "../tile-features/types";
|
||||||
import { ForecastType } from "../../../data/weather";
|
import { ForecastType } from "../../../data/weather";
|
||||||
|
|
||||||
|
export type AlarmPanelCardConfigState =
|
||||||
|
| "arm_away"
|
||||||
|
| "arm_home"
|
||||||
|
| "arm_night"
|
||||||
|
| "arm_vacation"
|
||||||
|
| "arm_custom_bypass";
|
||||||
|
|
||||||
export interface AlarmPanelCardConfig extends LovelaceCardConfig {
|
export interface AlarmPanelCardConfig extends LovelaceCardConfig {
|
||||||
entity: string;
|
entity: string;
|
||||||
name?: string;
|
name?: string;
|
||||||
states?: readonly (keyof TranslationDict["ui"]["card"]["alarm_control_panel"])[];
|
states?: AlarmPanelCardConfigState[];
|
||||||
theme?: string;
|
theme?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,14 +2,25 @@ import { html, LitElement, nothing } from "lit";
|
|||||||
import { customElement, property, state } from "lit/decorators";
|
import { customElement, property, state } from "lit/decorators";
|
||||||
import memoizeOne from "memoize-one";
|
import memoizeOne from "memoize-one";
|
||||||
import { array, assert, assign, object, optional, string } from "superstruct";
|
import { array, assert, assign, object, optional, string } from "superstruct";
|
||||||
|
import { HassEntity } from "home-assistant-js-websocket";
|
||||||
import { fireEvent } from "../../../../common/dom/fire_event";
|
import { fireEvent } from "../../../../common/dom/fire_event";
|
||||||
import type { LocalizeFunc } from "../../../../common/translations/localize";
|
import type { LocalizeFunc } from "../../../../common/translations/localize";
|
||||||
import "../../../../components/ha-form/ha-form";
|
import "../../../../components/ha-form/ha-form";
|
||||||
import type { SchemaUnion } from "../../../../components/ha-form/types";
|
import type { SchemaUnion } from "../../../../components/ha-form/types";
|
||||||
import type { HomeAssistant } from "../../../../types";
|
import type { HomeAssistant } from "../../../../types";
|
||||||
import type { AlarmPanelCardConfig } from "../../cards/types";
|
import type {
|
||||||
|
AlarmPanelCardConfig,
|
||||||
|
AlarmPanelCardConfigState,
|
||||||
|
} from "../../cards/types";
|
||||||
import type { LovelaceCardEditor } from "../../types";
|
import type { LovelaceCardEditor } from "../../types";
|
||||||
import { baseLovelaceCardConfig } from "../structs/base-card-struct";
|
import { baseLovelaceCardConfig } from "../structs/base-card-struct";
|
||||||
|
import {
|
||||||
|
DEFAULT_STATES,
|
||||||
|
ALARM_MODE_STATE_MAP,
|
||||||
|
filterSupportedAlarmStates,
|
||||||
|
} from "../../cards/hui-alarm-panel-card";
|
||||||
|
import { supportsFeature } from "../../../../common/entity/supports-feature";
|
||||||
|
import { ALARM_MODES } from "../../../../data/alarm_control_panel";
|
||||||
|
|
||||||
const cardConfigStruct = assign(
|
const cardConfigStruct = assign(
|
||||||
baseLovelaceCardConfig,
|
baseLovelaceCardConfig,
|
||||||
@ -21,13 +32,7 @@ const cardConfigStruct = assign(
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
const states = [
|
const states = Object.keys(ALARM_MODE_STATE_MAP) as AlarmPanelCardConfigState[];
|
||||||
"arm_home",
|
|
||||||
"arm_away",
|
|
||||||
"arm_night",
|
|
||||||
"arm_vacation",
|
|
||||||
"arm_custom_bypass",
|
|
||||||
] as const;
|
|
||||||
|
|
||||||
@customElement("hui-alarm-panel-card-editor")
|
@customElement("hui-alarm-panel-card-editor")
|
||||||
export class HuiAlarmPanelCardEditor
|
export class HuiAlarmPanelCardEditor
|
||||||
@ -44,7 +49,11 @@ export class HuiAlarmPanelCardEditor
|
|||||||
}
|
}
|
||||||
|
|
||||||
private _schema = memoizeOne(
|
private _schema = memoizeOne(
|
||||||
(localize: LocalizeFunc) =>
|
(
|
||||||
|
localize: LocalizeFunc,
|
||||||
|
stateObj: HassEntity | undefined,
|
||||||
|
config_states: AlarmPanelCardConfigState[]
|
||||||
|
) =>
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
name: "entity",
|
name: "entity",
|
||||||
@ -60,12 +69,24 @@ export class HuiAlarmPanelCardEditor
|
|||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: "multi_select",
|
|
||||||
name: "states",
|
name: "states",
|
||||||
options: states.map((s) => [
|
selector: {
|
||||||
s,
|
select: {
|
||||||
localize(`ui.card.alarm_control_panel.${s}`),
|
multiple: true,
|
||||||
]) as [string, string][],
|
mode: "list",
|
||||||
|
options: states.map((s) => ({
|
||||||
|
value: s,
|
||||||
|
label: localize(`ui.card.alarm_control_panel.${s}`),
|
||||||
|
disabled:
|
||||||
|
!config_states.includes(s) &&
|
||||||
|
(!stateObj ||
|
||||||
|
!supportsFeature(
|
||||||
|
stateObj,
|
||||||
|
ALARM_MODES[ALARM_MODE_STATE_MAP[s]].feature || 0
|
||||||
|
)),
|
||||||
|
})),
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
] as const
|
] as const
|
||||||
);
|
);
|
||||||
@ -75,11 +96,18 @@ export class HuiAlarmPanelCardEditor
|
|||||||
return nothing;
|
return nothing;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const stateObj = this.hass.states[this._config.entity];
|
||||||
|
const defaultFilteredStates = filterSupportedAlarmStates(
|
||||||
|
stateObj,
|
||||||
|
DEFAULT_STATES
|
||||||
|
);
|
||||||
|
const config = { states: defaultFilteredStates, ...this._config };
|
||||||
|
|
||||||
return html`
|
return html`
|
||||||
<ha-form
|
<ha-form
|
||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
.data=${this._config}
|
.data=${config}
|
||||||
.schema=${this._schema(this.hass.localize)}
|
.schema=${this._schema(this.hass.localize, stateObj, config.states)}
|
||||||
.computeLabel=${this._computeLabelCallback}
|
.computeLabel=${this._computeLabelCallback}
|
||||||
@value-changed=${this._valueChanged}
|
@value-changed=${this._valueChanged}
|
||||||
></ha-form>
|
></ha-form>
|
||||||
@ -87,7 +115,26 @@ export class HuiAlarmPanelCardEditor
|
|||||||
}
|
}
|
||||||
|
|
||||||
private _valueChanged(ev: CustomEvent): void {
|
private _valueChanged(ev: CustomEvent): void {
|
||||||
fireEvent(this, "config-changed", { config: ev.detail.value });
|
const newConfig = ev.detail.value;
|
||||||
|
|
||||||
|
// Sort states in a consistent order
|
||||||
|
if (newConfig.states) {
|
||||||
|
const sortStates = states.filter((s) => newConfig.states.includes(s));
|
||||||
|
newConfig.states = sortStates;
|
||||||
|
}
|
||||||
|
|
||||||
|
// When changing entities, clear any states that the new entity does not support
|
||||||
|
if (newConfig.states && newConfig.entity !== this._config?.entity) {
|
||||||
|
const newStateObj = this.hass?.states[newConfig.entity];
|
||||||
|
if (newStateObj) {
|
||||||
|
newConfig.states = filterSupportedAlarmStates(
|
||||||
|
newStateObj,
|
||||||
|
newConfig.states
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fireEvent(this, "config-changed", { config: newConfig });
|
||||||
}
|
}
|
||||||
|
|
||||||
private _computeLabelCallback = (
|
private _computeLabelCallback = (
|
||||||
|
Loading…
x
Reference in New Issue
Block a user