fix: Confirmations should apply to all actions (#1959)
This also refactors how generic HA actions are handled, and improves typing of actions. [skip ci]
This commit is contained in:
@@ -1,90 +0,0 @@
|
||||
import { fireHASSEvent } from './fire-hass-event.js';
|
||||
import { forwardHaptic } from './haptic.js';
|
||||
import { navigate } from './navigate.js';
|
||||
import { toggleEntity } from './toggle-entity.js';
|
||||
import { ActionConfig, HomeAssistant } from './types.js';
|
||||
|
||||
export const handleActionConfig = (
|
||||
node: HTMLElement,
|
||||
hass: HomeAssistant,
|
||||
config: {
|
||||
entity?: string;
|
||||
camera_image?: string;
|
||||
hold_action?: ActionConfig;
|
||||
tap_action?: ActionConfig;
|
||||
double_tap_action?: ActionConfig;
|
||||
},
|
||||
actionConfig: ActionConfig | undefined,
|
||||
): void => {
|
||||
if (!actionConfig) {
|
||||
actionConfig = {
|
||||
action: 'more-info',
|
||||
};
|
||||
}
|
||||
|
||||
if (
|
||||
actionConfig.confirmation &&
|
||||
(!actionConfig.confirmation.exemptions ||
|
||||
!actionConfig.confirmation.exemptions.some((e) => e.user === hass!.user!.id))
|
||||
) {
|
||||
forwardHaptic('warning');
|
||||
|
||||
if (
|
||||
!confirm(
|
||||
actionConfig.confirmation.text ||
|
||||
`Are you sure you want to ${actionConfig.action}?`,
|
||||
)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
switch (actionConfig.action) {
|
||||
case 'more-info':
|
||||
if (config.entity || config.camera_image) {
|
||||
fireHASSEvent(node, 'hass-more-info', {
|
||||
entityId: config.entity ? config.entity : config.camera_image!,
|
||||
});
|
||||
}
|
||||
break;
|
||||
case 'navigate':
|
||||
if (actionConfig.navigation_path) {
|
||||
navigate(node, actionConfig.navigation_path);
|
||||
}
|
||||
break;
|
||||
case 'url':
|
||||
if (actionConfig.url_path) {
|
||||
window.open(actionConfig.url_path);
|
||||
}
|
||||
break;
|
||||
case 'toggle':
|
||||
if (config.entity) {
|
||||
toggleEntity(hass, config.entity!);
|
||||
forwardHaptic('success');
|
||||
}
|
||||
break;
|
||||
case 'perform-action': {
|
||||
if (!actionConfig.perform_action) {
|
||||
forwardHaptic('failure');
|
||||
return;
|
||||
}
|
||||
const [domain, service] = actionConfig.perform_action.split('.', 2);
|
||||
hass.callService(domain, service, actionConfig.data, actionConfig.target);
|
||||
forwardHaptic('success');
|
||||
break;
|
||||
}
|
||||
case 'call-service': {
|
||||
if (!actionConfig.service) {
|
||||
forwardHaptic('failure');
|
||||
return;
|
||||
}
|
||||
const [domain, service] = actionConfig.service.split('.', 2);
|
||||
hass.callService(domain, service, actionConfig.data, actionConfig.target);
|
||||
forwardHaptic('success');
|
||||
break;
|
||||
}
|
||||
case 'fire-dom-event': {
|
||||
fireHASSEvent(node, 'll-custom', actionConfig);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -1,5 +0,0 @@
|
||||
import { ActionConfig } from './types.js';
|
||||
|
||||
export function hasAction(config?: ActionConfig): boolean {
|
||||
return config !== undefined && config.action !== 'none';
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
import { fireHASSEvent } from './fire-hass-event.js';
|
||||
|
||||
declare global {
|
||||
interface HASSDomEvents {
|
||||
'location-changed': {
|
||||
replace: boolean;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export const navigate = (_node: unknown, path: string, replace: boolean = false) => {
|
||||
if (replace) {
|
||||
history.replaceState(null, '', path);
|
||||
} else {
|
||||
history.pushState(null, '', path);
|
||||
}
|
||||
fireHASSEvent(window, 'location-changed', {
|
||||
replace,
|
||||
});
|
||||
};
|
||||
@@ -1,8 +0,0 @@
|
||||
import { STATES_OFF } from './const.js';
|
||||
import { turnOnOffEntity } from './turn-on-off-entity.js';
|
||||
import { HomeAssistant } from './types.js';
|
||||
|
||||
export const toggleEntity = (hass: HomeAssistant, entityId: string): Promise<void> => {
|
||||
const turnOn = STATES_OFF.includes(hass.states[entityId].state);
|
||||
return turnOnOffEntity(hass, entityId, turnOn);
|
||||
};
|
||||
@@ -1,25 +0,0 @@
|
||||
import { HomeAssistant } from './types.js';
|
||||
import { computeDomain } from './compute-domain.js';
|
||||
|
||||
export const turnOnOffEntity = (
|
||||
hass: HomeAssistant,
|
||||
entityId: string,
|
||||
turnOn = true,
|
||||
): Promise<void> => {
|
||||
const stateDomain = computeDomain(entityId);
|
||||
const serviceDomain = stateDomain === 'group' ? 'homeassistant' : stateDomain;
|
||||
|
||||
let service;
|
||||
switch (stateDomain) {
|
||||
case 'lock':
|
||||
service = turnOn ? 'unlock' : 'lock';
|
||||
break;
|
||||
case 'cover':
|
||||
service = turnOn ? 'open_cover' : 'close_cover';
|
||||
break;
|
||||
default:
|
||||
service = turnOn ? 'turn_on' : 'turn_off';
|
||||
}
|
||||
|
||||
return hass.callService(serviceDomain, service, { entity_id: entityId });
|
||||
};
|
||||
@@ -7,87 +7,6 @@ import {
|
||||
HassServiceTarget,
|
||||
MessageBase,
|
||||
} from 'home-assistant-js-websocket';
|
||||
import { HapticType } from './haptic.js';
|
||||
|
||||
interface ToggleMenuActionConfig extends BaseActionConfig {
|
||||
action: 'toggle-menu';
|
||||
}
|
||||
|
||||
export interface ToggleActionConfig extends BaseActionConfig {
|
||||
action: 'toggle';
|
||||
}
|
||||
|
||||
export interface CallServiceActionConfig extends BaseActionConfig {
|
||||
action: 'call-service';
|
||||
service: string;
|
||||
data?: {
|
||||
entity_id?: string | [string];
|
||||
[key: string]: unknown;
|
||||
};
|
||||
target?: HassServiceTarget;
|
||||
repeat?: number;
|
||||
haptic?: HapticType;
|
||||
}
|
||||
|
||||
export interface PerformActionActionConfig extends BaseActionConfig {
|
||||
action: 'perform-action';
|
||||
perform_action: string;
|
||||
data?: {
|
||||
entity_id?: string | [string];
|
||||
[key: string]: unknown;
|
||||
};
|
||||
target?: HassServiceTarget;
|
||||
repeat?: number;
|
||||
haptic?: HapticType;
|
||||
}
|
||||
|
||||
export interface NavigateActionConfig extends BaseActionConfig {
|
||||
action: 'navigate';
|
||||
navigation_path: string;
|
||||
}
|
||||
|
||||
export interface UrlActionConfig extends BaseActionConfig {
|
||||
action: 'url';
|
||||
url_path: string;
|
||||
}
|
||||
export interface MoreInfoActionConfig extends BaseActionConfig {
|
||||
action: 'more-info';
|
||||
entity?: string;
|
||||
}
|
||||
export interface NoActionConfig extends BaseActionConfig {
|
||||
action: 'none';
|
||||
}
|
||||
interface CustomActionConfig extends BaseActionConfig {
|
||||
action: 'fire-dom-event';
|
||||
}
|
||||
/**
|
||||
* `repeat` and `haptic` are specifically for use in custom cards like the Button-Card
|
||||
*/
|
||||
interface BaseActionConfig {
|
||||
confirmation?: ConfirmationRestrictionConfig;
|
||||
repeat?: number;
|
||||
haptic?: HapticType;
|
||||
}
|
||||
|
||||
export interface ConfirmationRestrictionConfig {
|
||||
text?: string;
|
||||
exemptions?: RestrictionConfig[];
|
||||
}
|
||||
|
||||
interface RestrictionConfig {
|
||||
user: string;
|
||||
}
|
||||
|
||||
export declare type ActionConfig =
|
||||
| ToggleActionConfig
|
||||
| CallServiceActionConfig
|
||||
| PerformActionActionConfig
|
||||
| NavigateActionConfig
|
||||
| UrlActionConfig
|
||||
| MoreInfoActionConfig
|
||||
| NoActionConfig
|
||||
| CustomActionConfig
|
||||
| ToggleMenuActionConfig;
|
||||
|
||||
declare global {
|
||||
interface HASSDomEvents {
|
||||
|
||||
Reference in New Issue
Block a user