diff --git a/src/editor/components/idSelector/IdSelector.ts b/src/editor/components/idSelector/IdSelector.ts index 5a3ef368ac..0c9ae9f9f3 100644 --- a/src/editor/components/idSelector/IdSelector.ts +++ b/src/editor/components/idSelector/IdSelector.ts @@ -12,6 +12,7 @@ import { import * as haServer from '../../haserver'; import { i18n } from '../../i18n'; import { createRow } from './elements'; +import { isFeatureSupported, pushIfNotExist } from './utils'; import { createSelectOptions } from './virtual-select'; interface EditableListButton { @@ -116,9 +117,10 @@ export default class IdSelector { if ( supportedFeatures !== undefined && state.attributes.supported_features !== undefined && - (state.attributes.supported_features & - supportedFeatures) === - 0 + !isFeatureSupported( + state.attributes.supported_features, + supportedFeatures, + ) ) { continue; } @@ -332,10 +334,3 @@ export function getSelectedIds(elementId: string): SelectedIds { [IdSelectorType.Regex]: Array.from(selectedIds[IdSelectorType.Regex]), }; } - -// Push an element to an array if it does not exist -function pushIfNotExist(array: T[], element: T) { - if (!array.includes(element)) { - array.push(element); - } -} diff --git a/src/editor/components/idSelector/utils.ts b/src/editor/components/idSelector/utils.ts new file mode 100644 index 0000000000..528c243560 --- /dev/null +++ b/src/editor/components/idSelector/utils.ts @@ -0,0 +1,29 @@ +// Push an element to an array if it does not exist +export function pushIfNotExist(array: T[], element: T) { + if (!array.includes(element)) { + array.push(element); + } +} + +function compareBitmask( + supported: number, + required: (number | number[])[], +): boolean { + return required.some((req) => { + if (Array.isArray(req)) { + return req.every((r) => (supported & r) !== 0); + } else { + return (supported & req) !== 0; + } + }); +} + +export function isFeatureSupported( + bitmask: number, + required: (number | number[])[], +): boolean { + if (required.length === 0) { + return true; + } + return compareBitmask(bitmask, required); +} diff --git a/src/nodes/action/editor/targets.ts b/src/nodes/action/editor/targets.ts index eb5043c349..32b37639ee 100644 --- a/src/nodes/action/editor/targets.ts +++ b/src/nodes/action/editor/targets.ts @@ -6,7 +6,7 @@ type ServiceEntityFilter = { integration?: string; domain?: string | string[]; device_class?: string | string[]; - supported_features?: number | [number]; + supported_features?: (number | number[])[]; }; type ServiceFilter = { @@ -17,7 +17,7 @@ export type ActionTargetFilter = { integration?: string; domain?: string[]; device_class?: string[]; - supported_features?: number; + supported_features?: (number | number[])[]; }; export enum ValidTarget { @@ -40,9 +40,7 @@ export function convertServiceEntityFilter( : filter.device_class ? [filter.device_class] : undefined, - supported_features: Array.isArray(filter.supported_features) - ? filter.supported_features[0] - : filter.supported_features, + supported_features: filter.supported_features, }; } diff --git a/test/editor/components/idSelector/utils.ts b/test/editor/components/idSelector/utils.ts new file mode 100644 index 0000000000..8a0f05ff95 --- /dev/null +++ b/test/editor/components/idSelector/utils.ts @@ -0,0 +1,45 @@ +import { expect } from 'chai'; + +import { + isFeatureSupported, + pushIfNotExist, +} from '../../../../src/editor/components/idSelector/utils'; + +describe('utils', function () { + describe('pushIfNotExist', function () { + it('should push element to array if it does not exist', function () { + const array = [1, 2, 3]; + pushIfNotExist(array, 4); + expect(array).to.include(4); + }); + + it('should not push element to array if it already exists', function () { + const array = [1, 2, 3]; + pushIfNotExist(array, 3); + expect(array).to.have.lengthOf(3); + }); + }); + + describe('isFeatureSupported', function () { + it('should return true if required array is empty', function () { + expect(isFeatureSupported(0b1010, [])).to.be.true; + }); + + it('should return true if bitmask supports all required features', function () { + expect(isFeatureSupported(0b1010, [0b0010, 0b1000])).to.be.true; + }); + + it('should return false if bitmask does not support any required features', function () { + expect(isFeatureSupported(0b1010, [0b0100, 0b0001])).to.be.false; + }); + + it('should return true if bitmask supports any features ', function () { + expect(isFeatureSupported(0b1111, [[0b1000, 0b0100], 0b1000])).to.be + .true; + }); + + it('should return false if bitmask does not support all features in nested arrays', function () { + expect(isFeatureSupported(0b1010, [[0b1000, 0b0100]])).to.be.false; + }); + }); +});