feat: Add support for templates in actions (#1891)

- Closes #1878
This commit is contained in:
Dermot Duffy
2025-02-14 07:23:19 -08:00
committed by GitHub
parent 8d3cf07b43
commit 7fb710d45d
18 changed files with 474 additions and 24 deletions
+80
View File
@@ -0,0 +1,80 @@
import { HomeAssistant } from '@dermotduffy/custom-card-helpers';
import { HASS, renderTemplate } from 'ha-nunjucks/dist';
import { ConditionsEvaluationData, ConditionState } from '../../conditions/types';
import { ActionType } from '../../config/types';
interface TemplateContextInternal {
camera?: string;
view?: string;
trigger?: ConditionsEvaluationData;
}
interface TemplateContext {
advanced_camera_card: TemplateContextInternal;
// Convenient alias.
acc: TemplateContextInternal;
}
export class TemplateRenderer {
public renderRecursively = (
hass: HomeAssistant,
data: unknown,
options?: {
conditionState?: ConditionState;
triggerData?: ConditionsEvaluationData;
},
): ActionType => {
return this._renderTemplateRecursively(
hass,
data,
this._conditionStateToTemplateContext(
options?.conditionState,
options?.triggerData,
),
);
};
protected _conditionStateToTemplateContext(
conditionState?: ConditionState,
triggerData?: ConditionsEvaluationData,
): TemplateContext | undefined {
if (!conditionState?.camera && !conditionState?.view && !triggerData) {
return;
}
const advancedCameraCardContext: TemplateContextInternal = {
...(conditionState?.camera && { camera: conditionState.camera }),
...(conditionState?.view && { view: conditionState.view }),
...(triggerData && { trigger: triggerData }),
};
return {
acc: advancedCameraCardContext,
advanced_camera_card: advancedCameraCardContext,
};
}
protected _renderTemplateRecursively(
hass: HomeAssistant,
data: unknown,
templateContext?: TemplateContext,
): ActionType {
if (typeof data === 'string') {
// ha-nunjucks has a more complete model of the Home Assistant object, but
// does not export it as a type.
return renderTemplate(hass as unknown as typeof HASS, data, templateContext);
} else if (Array.isArray(data)) {
return data.map((item) =>
this._renderTemplateRecursively(hass, item, templateContext),
);
} else if (typeof data === 'object' && data !== null) {
const result = {};
for (const key in data) {
result[key] = this._renderTemplateRecursively(hass, data[key], templateContext);
}
return result;
}
return data;
}
}