Template markdown card (#3451)

* Render templates in markdown card

* Add manual entity_id option

* Linting

* Address review comments

* Address review comments

* Address review comments

* Address review comments

* Tweak disconnect function

* Remove cardSize instance variable

* Fix demo
This commit is contained in:
Thomas Lovén 2019-08-10 21:55:32 +02:00 committed by Paulus Schoutsen
parent c15629b81b
commit 1f3a5b1396
4 changed files with 99 additions and 6 deletions

20
src/data/ws-templates.ts Normal file
View File

@ -0,0 +1,20 @@
import { Connection, UnsubscribeFunc } from "home-assistant-js-websocket";
interface RenderTemplateResult {
result: string;
}
export const subscribeRenderTemplate = (
conn: Connection,
onChange: (result: string) => void,
params: {
template: string;
entity_ids?: string | string[];
variables?: object;
}
): Promise<UnsubscribeFunc> => {
return conn.subscribeMessage(
(msg: RenderTemplateResult) => onChange(msg.result),
{ type: "render_template", ...params }
);
};

View File

@ -24,7 +24,10 @@ export interface MockHomeAssistant extends HomeAssistant {
updateHass(obj: Partial<MockHomeAssistant>);
updateStates(newStates: HassEntities);
addEntities(entites: Entity | Entity[], replace?: boolean);
mockWS(type: string, callback: (msg: any) => any);
mockWS(
type: string,
callback: (msg: any, onChange?: (response: any) => void) => any
);
mockAPI(path: string | RegExp, callback: MockRestCallback);
mockEvent(event);
mockTheme(theme: { [key: string]: string } | null);
@ -108,7 +111,7 @@ export const provideHass = (
console.error(`Unknown WS command: ${msg.type}`);
}
},
sendMessagePromise: (msg) => {
sendMessagePromise: async (msg) => {
const callback = wsCommands[msg.type];
return callback
? callback(msg)
@ -119,6 +122,17 @@ export const provideHass = (
} is not implemented in provide_hass.`,
});
},
subscribeMessage: async (onChange, msg) => {
const callback = wsCommands[msg.type];
return callback
? callback(msg, onChange)
: Promise.reject({
code: "command_not_mocked",
message: `WS Command ${
msg.type
} is not implemented in provide_hass.`,
});
},
subscribeEvents: async (
// @ts-ignore
callback,

View File

@ -8,12 +8,15 @@ import {
CSSResult,
} from "lit-element";
import { classMap } from "lit-html/directives/class-map";
import { UnsubscribeFunc } from "home-assistant-js-websocket";
import "../../../components/ha-card";
import "../../../components/ha-markdown";
import { HomeAssistant } from "../../../types";
import { LovelaceCard, LovelaceCardEditor } from "../types";
import { MarkdownCardConfig } from "./types";
import { subscribeRenderTemplate } from "../../../data/ws-templates";
@customElement("hui-markdown-card")
export class HuiMarkdownCard extends LitElement implements LovelaceCard {
@ -27,11 +30,16 @@ export class HuiMarkdownCard extends LitElement implements LovelaceCard {
}
@property() private _config?: MarkdownCardConfig;
@property() private _content?: string = "";
@property() private _unsubRenderTemplate?: Promise<UnsubscribeFunc>;
@property() private _hass?: HomeAssistant;
public getCardSize(): number {
return (
this._config!.content.split("\n").length + (this._config!.title ? 1 : 0)
);
return this._config === undefined
? 3
: this._config.card_size === undefined
? this._config.content.split("\n").length + (this._config.title ? 1 : 0)
: this._config.card_size;
}
public setConfig(config: MarkdownCardConfig): void {
@ -40,6 +48,20 @@ export class HuiMarkdownCard extends LitElement implements LovelaceCard {
}
this._config = config;
this._disconnect();
if (this._hass) {
this._connect();
}
}
public disconnectedCallback() {
this._disconnect();
}
public set hass(hass) {
this._hass = hass;
this._connect();
}
protected render(): TemplateResult | void {
@ -53,12 +75,47 @@ export class HuiMarkdownCard extends LitElement implements LovelaceCard {
class="markdown ${classMap({
"no-header": !this._config.title,
})}"
.content="${this._config.content}"
.content="${this._content}"
></ha-markdown>
</ha-card>
`;
}
private async _connect() {
if (!this._unsubRenderTemplate && this._hass && this._config) {
this._unsubRenderTemplate = subscribeRenderTemplate(
this._hass.connection,
(result) => {
this._content = result;
},
{
template: this._config.content,
entity_ids: this._config.entity_id,
}
);
this._unsubRenderTemplate.catch(() => {
this._content = this._config!.content;
this._unsubRenderTemplate = undefined;
});
}
}
private async _disconnect() {
if (this._unsubRenderTemplate) {
try {
const unsub = await this._unsubRenderTemplate;
this._unsubRenderTemplate = undefined;
await unsub();
} catch (e) {
if (e.code === "not_found") {
// If we get here, the connection was probably already closed. Ignore.
} else {
throw e;
}
}
}
}
static get styles(): CSSResult {
return css`
ha-markdown {

View File

@ -118,6 +118,8 @@ export interface MarkdownCardConfig extends LovelaceCardConfig {
type: "markdown";
content: string;
title?: string;
card_size?: number;
entity_ids?: string | string[];
}
export interface MediaControlCardConfig extends LovelaceCardConfig {