Fix card-wide actions.
This commit is contained in:
@@ -1,3 +1,4 @@
|
|||||||
|
import { z } from 'zod';
|
||||||
import {
|
import {
|
||||||
Actions,
|
Actions,
|
||||||
ActionsConfig,
|
ActionsConfig,
|
||||||
@@ -13,6 +14,15 @@ import {
|
|||||||
import { getStreamCameraID } from '../utils/substream.js';
|
import { getStreamCameraID } from '../utils/substream.js';
|
||||||
import { CardActionsManagerAPI } from './types.js';
|
import { CardActionsManagerAPI } from './types.js';
|
||||||
|
|
||||||
|
const interactionSchema = z.object({
|
||||||
|
action: z.enum(['tap', 'double_tap', 'hold', 'start_tap', 'end_tap']),
|
||||||
|
});
|
||||||
|
export type Interaction = z.infer<typeof interactionSchema>;
|
||||||
|
|
||||||
|
const interactionEventSchema = z.object({
|
||||||
|
detail: interactionSchema,
|
||||||
|
});
|
||||||
|
|
||||||
export class ActionsManager {
|
export class ActionsManager {
|
||||||
protected _api: CardActionsManagerAPI;
|
protected _api: CardActionsManagerAPI;
|
||||||
|
|
||||||
@@ -49,7 +59,14 @@ export class ActionsManager {
|
|||||||
/**
|
/**
|
||||||
* Handle an human interaction called on an element (e.g. 'tap').
|
* Handle an human interaction called on an element (e.g. 'tap').
|
||||||
*/
|
*/
|
||||||
public handleInteraction(interaction: string): void {
|
public handleInteractionEvent = (ev: Event): void => {
|
||||||
|
const result = interactionEventSchema.safeParse(ev);
|
||||||
|
if (!result.success) {
|
||||||
|
// The event may not be a CustomEvent object, see:
|
||||||
|
// https://github.com/custom-cards/custom-card-helpers/blob/master/src/fire-event.ts#L70
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const interaction = result.data.detail.action;
|
||||||
const hass = this._api.getHASSManager().getHASS();
|
const hass = this._api.getHASSManager().getHASS();
|
||||||
const config = this.getMergedActions();
|
const config = this.getMergedActions();
|
||||||
const actionConfig = getActionConfigGivenAction(interaction, config);
|
const actionConfig = getActionConfigGivenAction(interaction, config);
|
||||||
@@ -70,12 +87,11 @@ export class ActionsManager {
|
|||||||
actionConfig,
|
actionConfig,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
public handleActionEvent = (ev: Event): void => {
|
public handleActionEvent = (ev: Event): void => {
|
||||||
if (!('detail' in ev)) {
|
if (!('detail' in ev)) {
|
||||||
// The event may not actually be a CustomEvent object, but may still have a
|
// The event may not be a CustomEvent object, see:
|
||||||
// detail field. See:
|
|
||||||
// https://github.com/custom-cards/custom-card-helpers/blob/master/src/fire-event.ts#L70
|
// https://github.com/custom-cards/custom-card-helpers/blob/master/src/fire-event.ts#L70
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -77,7 +77,11 @@ export class CardElementManager {
|
|||||||
this._api.getActionsManager().handleActionEvent,
|
this._api.getActionsManager().handleActionEvent,
|
||||||
);
|
);
|
||||||
this._element.addEventListener(
|
this._element.addEventListener(
|
||||||
'@action',
|
'action',
|
||||||
|
this._api.getActionsManager().handleInteractionEvent,
|
||||||
|
);
|
||||||
|
this._element.addEventListener(
|
||||||
|
'action',
|
||||||
this._api.getInteractionManager().reportInteraction,
|
this._api.getInteractionManager().reportInteraction,
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -123,7 +127,11 @@ export class CardElementManager {
|
|||||||
this._api.getActionsManager().handleActionEvent,
|
this._api.getActionsManager().handleActionEvent,
|
||||||
);
|
);
|
||||||
this._element.removeEventListener(
|
this._element.removeEventListener(
|
||||||
'@action',
|
'action',
|
||||||
|
this._api.getActionsManager().handleInteractionEvent,
|
||||||
|
);
|
||||||
|
this._element.removeEventListener(
|
||||||
|
'action',
|
||||||
this._api.getInteractionManager().reportInteraction,
|
this._api.getInteractionManager().reportInteraction,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ import {
|
|||||||
frigateCardHandleActionConfig,
|
frigateCardHandleActionConfig,
|
||||||
getActionConfigGivenAction,
|
getActionConfigGivenAction,
|
||||||
} from '../../src/utils/action.js';
|
} from '../../src/utils/action.js';
|
||||||
import { ActionsManager } from '../../src/card-controller/actions-manager';
|
import { ActionsManager, Interaction } from '../../src/card-controller/actions-manager';
|
||||||
import {
|
import {
|
||||||
createCardAPI,
|
createCardAPI,
|
||||||
createConfig,
|
createConfig,
|
||||||
@@ -165,7 +165,9 @@ describe('ActionsManager.handleInteraction', () => {
|
|||||||
};
|
};
|
||||||
vi.mocked(getActionConfigGivenAction).mockReturnValue(actionForThisInteraction);
|
vi.mocked(getActionConfigGivenAction).mockReturnValue(actionForThisInteraction);
|
||||||
|
|
||||||
manager.handleInteraction('tap');
|
manager.handleInteractionEvent(
|
||||||
|
new CustomEvent<Interaction>('event', { detail: { action: 'tap' } }),
|
||||||
|
);
|
||||||
|
|
||||||
expect(frigateCardHandleActionConfig).toBeCalledWith(
|
expect(frigateCardHandleActionConfig).toBeCalledWith(
|
||||||
element,
|
element,
|
||||||
@@ -176,13 +178,29 @@ describe('ActionsManager.handleInteraction', () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should not handle interaction', () => {
|
it('should not handle interaction without hass', () => {
|
||||||
const api = createCardAPI();
|
const api = createCardAPI();
|
||||||
const manager = new ActionsManager(api);
|
const manager = new ActionsManager(api);
|
||||||
vi.mocked(api.getHASSManager().getHASS).mockReturnValue(null);
|
vi.mocked(api.getHASSManager().getHASS).mockReturnValue(null);
|
||||||
|
|
||||||
// No values of hass.
|
// No values of hass.
|
||||||
manager.handleInteraction('tap');
|
manager.handleInteractionEvent(
|
||||||
|
new CustomEvent<Interaction>('event', { detail: { action: 'tap' } }),
|
||||||
|
);
|
||||||
|
expect(frigateCardHandleActionConfig).not.toBeCalledWith();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not handle malformed interaction', () => {
|
||||||
|
const api = createCardAPI();
|
||||||
|
const manager = new ActionsManager(api);
|
||||||
|
|
||||||
|
manager.handleInteractionEvent(
|
||||||
|
new CustomEvent<Interaction>('event', {
|
||||||
|
|
||||||
|
// Malformed interaction type.
|
||||||
|
detail: { action: 'double_finger_snap' } as unknown as Interaction,
|
||||||
|
}),
|
||||||
|
);
|
||||||
expect(frigateCardHandleActionConfig).not.toBeCalledWith();
|
expect(frigateCardHandleActionConfig).not.toBeCalledWith();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user