Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions src/common/util/uid.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
function s4() {
return Math.floor((1 + Math.random()) * 0x10000)
.toString(16)
.substring(1);
}

export function uid() {
return s4() + s4() + s4() + s4() + s4();
}
21 changes: 17 additions & 4 deletions src/data/lovelace.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,12 @@ export const migrateConfig = (hass: HomeAssistant): Promise<void> =>
export const saveConfig = (
hass: HomeAssistant,
config: LovelaceConfig | string,
configFormat: "json" | "yaml"
format: "json" | "yaml"
): Promise<void> =>
hass.callWS({
type: "lovelace/config/save",
config,
format: configFormat,
format,
});

export const getCardConfig = (
Expand All @@ -54,13 +54,13 @@ export const updateCardConfig = (
hass: HomeAssistant,
cardId: string,
config: LovelaceCardConfig | string,
configFormat: "json" | "yaml"
format: "json" | "yaml"
): Promise<void> =>
hass.callWS({
type: "lovelace/config/card/update",
card_id: cardId,
card_config: config,
format: configFormat,
format,
});

export const deleteCard = (
Expand All @@ -71,3 +71,16 @@ export const deleteCard = (
type: "lovelace/config/card/delete",
card_id: cardId,
});

export const addCard = (
hass: HomeAssistant,
viewId: string,
config: LovelaceCardConfig | string,
format: "json" | "yaml"
): Promise<void> =>
hass.callWS({
type: "lovelace/config/card/add",
view_id: viewId,
card_config: config,
format,
});
5 changes: 5 additions & 0 deletions src/panels/lovelace/cards/hui-entities-card.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,11 @@ class HuiEntitiesCard extends hassLocalizeLitMixin(LitElement)
await import("../editor/config-elements/hui-entities-card-editor");
return document.createElement("hui-entities-card-editor");
}

public static getStubConfig(): object {
return { entities: [] };
}

protected _hass?: HomeAssistant;
protected _config?: Config;
protected _configEntities?: ConfigEntity[];
Expand Down
3 changes: 3 additions & 0 deletions src/panels/lovelace/cards/hui-glance-card.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@ export class HuiGlanceCard extends hassLocalizeLitMixin(LitElement)
await import("../editor/config-elements/hui-glance-card-editor");
return document.createElement("hui-glance-card-editor");
}
public static getStubConfig(): object {
return { entities: [] };
}

public hass?: HomeAssistant;
private _config?: Config;
Expand Down
7 changes: 7 additions & 0 deletions src/panels/lovelace/common/get-card-element-tag.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
const CUSTOM_TYPE_PREFIX = "custom:";

export function getCardElementTag(type: string): string {
return type.startsWith(CUSTOM_TYPE_PREFIX)
? type.substr(CUSTOM_TYPE_PREFIX.length)
: `hui-${type}-card`;
}
22 changes: 6 additions & 16 deletions src/panels/lovelace/components/hui-card-options.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
import "@polymer/paper-button/paper-button";
import { html, LitElement, PropertyDeclarations } from "@polymer/lit-element";
import "@polymer/paper-button/paper-button";
import { fireEvent } from "../../../common/dom/fire_event";
import {
showEditCardDialog,
registerEditCardDialog,
} from "../editor/hui-dialog-edit-card";
import { showEditCardDialog } from "../editor/hui-dialog-edit-card";

import { confDeleteCard } from "../editor/delete-card";
import { HomeAssistant } from "../../../types";
Expand All @@ -14,14 +11,14 @@ declare global {
// for fire event
interface HASSDomEvents {
"show-edit-card": {
cardConfig: LovelaceCardConfig;
cardConfig?: LovelaceCardConfig;
viewId?: string | number;
add: boolean;
reloadLovelace: () => void;
};
}
}

let registeredDialog = false;

export class HuiCardOptions extends LitElement {
public cardConfig?: LovelaceCardConfig;
protected hass?: HomeAssistant;
Expand All @@ -30,14 +27,6 @@ export class HuiCardOptions extends LitElement {
return { hass: {} };
}

public connectedCallback() {
super.connectedCallback();
if (!registeredDialog) {
registeredDialog = true;
registerEditCardDialog(this);
}
}

protected render() {
return html`
<style>
Expand Down Expand Up @@ -72,6 +61,7 @@ export class HuiCardOptions extends LitElement {
}
showEditCardDialog(this, {
cardConfig: this.cardConfig,
add: false,
reloadLovelace: () => fireEvent(this, "config-refresh"),
});
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,6 @@ const cardConfigStruct = struct({

export class HuiEntitiesCardEditor extends hassLocalizeLitMixin(LitElement)
implements LovelaceCardEditor {
public hass?: HomeAssistant;
private _config?: Config;
private _configEntities?: ConfigEntity[];

static get properties(): PropertyDeclarations {
return { hass: {}, _config: {}, _configEntities: {} };
}
Expand All @@ -58,6 +54,10 @@ export class HuiEntitiesCardEditor extends hassLocalizeLitMixin(LitElement)
return this._config!.theme || "Backend-selected";
}

public hass?: HomeAssistant;
private _config?: Config;
private _configEntities?: ConfigEntity[];

public setConfig(config: Config): void {
config = cardConfigStruct(config);

Expand Down
110 changes: 110 additions & 0 deletions src/panels/lovelace/editor/hui-card-picker.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
import { html, LitElement } from "@polymer/lit-element";
import { TemplateResult } from "lit-html";
import "@polymer/paper-button/paper-button";

import { HomeAssistant } from "../../../types";
import { fireEvent } from "../../../common/dom/fire_event";
import { LovelaceCardConfig } from "../../../data/lovelace";
import { getCardElementTag } from "../common/get-card-element-tag";
import { CardPickTarget } from "./types";
import { uid } from "../../../common/util/uid";

declare global {
interface HASSDomEvents {
"card-picked": {
config: LovelaceCardConfig;
};
}
}

const cards = [
{ name: "Alarm panel", type: "alarm-panel" },
{ name: "Conditional", type: "conditional" },
{ name: "Entities", type: "entities" },
{ name: "Entity Button", type: "entity-button" },
{ name: "Entity Filter", type: "entity-filter" },
{ name: "Gauge", type: "gauge" },
{ name: "Glance", type: "glance" },
{ name: "History Graph", type: "history-graph" },
{ name: "Horizontal Stack", type: "horizontal-graph" },
{ name: "iFrame", type: "iframe" },
{ name: "Light", type: "light" },
{ name: "Map", type: "map" },
{ name: "Markdown", type: "markdown" },
{ name: "Media Control", type: "media-control" },
{ name: "Picture", type: "picture" },
{ name: "Picture Elements", type: "picture-elements" },
{ name: "Picture Entity", type: "picture-entity" },
{ name: "Picture Glance", type: "picture-glance" },
{ name: "Plant Status", type: "plant-status" },
{ name: "Sensor", type: "sensor" },
{ name: "Shopping List", type: "shopping-list" },
{ name: "Thermostat", type: "thermostat" },
{ name: "Vertical Stack", type: "vertical-stack" },
{ name: "Weather Forecast", type: "weather-forecast" },
];

export class HuiCardPicker extends LitElement {
protected hass?: HomeAssistant;

protected render(): TemplateResult {
return html`
${this.renderStyle()}
<h3>Pick the card you want to add:</h3>
<div class="cards-container">
${
cards.map((card) => {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Idea: In the future we can add a global window object where custom cards can register so they can be shown in this list too.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah! I had that in mind!

return html`
<paper-button
raised
@click="${this._cardPicked}"
.type="${card.type}"
>${card.name}</paper-button
>
`;
})
}
</div>
`;
}

private renderStyle(): TemplateResult {
return html`
<style>
.cards-container {
display: flex;
flex-wrap: wrap;
margin-bottom: 10px;
}
.cards-container paper-button {
flex: 1 0 25%;
}
</style>
`;
}

private _cardPicked(ev: Event): void {
const type = (ev.currentTarget! as CardPickTarget).type;
const tag = getCardElementTag(type);

const elClass = customElements.get(tag);
let config: LovelaceCardConfig = { type, id: uid() };

if (elClass && elClass.getStubConfig) {
const cardConfig = elClass.getStubConfig(this.hass);
config = { ...config, ...cardConfig };
}

fireEvent(this, "card-picked", {
config,
});
}
}

declare global {
interface HTMLElementTagNameMap {
"hui-card-picker": HuiCardPicker;
}
}

customElements.define("hui-card-picker", HuiCardPicker);
7 changes: 2 additions & 5 deletions src/panels/lovelace/editor/hui-card-preview.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,7 @@ import { HomeAssistant } from "../../../types";
import { LovelaceCardConfig } from "../../../data/lovelace";
import { LovelaceCard } from "../types";
import { ConfigError } from "./types";

const CUSTOM_TYPE_PREFIX = "custom:";
import { getCardElementTag } from "../common/get-card-element-tag";

export class HuiCardPreview extends HTMLElement {
private _hass?: HomeAssistant;
Expand Down Expand Up @@ -39,9 +38,7 @@ export class HuiCardPreview extends HTMLElement {
return;
}

const tag = configValue.type.startsWith(CUSTOM_TYPE_PREFIX)
? configValue.type.substr(CUSTOM_TYPE_PREFIX.length)
: `hui-${configValue.type}-card`;
const tag = getCardElementTag(configValue.type);

if (tag.toUpperCase() === this._element.tagName) {
this._element.setConfig(configValue);
Expand Down
35 changes: 30 additions & 5 deletions src/panels/lovelace/editor/hui-dialog-edit-card.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,18 @@ declare global {
}
}

let registeredDialog = false;
const dialogShowEvent = "show-edit-card";
const dialogTag = "hui-dialog-edit-card";

export interface EditCardDialogParams {
cardConfig: LovelaceCardConfig;
cardConfig?: LovelaceCardConfig;
viewId?: string | number;
add: boolean;
reloadLovelace: () => void;
}

export const registerEditCardDialog = (element: HTMLElement) =>
const registerEditCardDialog = (element: HTMLElement) =>
fireEvent(element, "register-dialog", {
dialogShowEvent,
dialogTag,
Expand All @@ -37,7 +40,13 @@ export const registerEditCardDialog = (element: HTMLElement) =>
export const showEditCardDialog = (
element: HTMLElement,
editCardDialogParams: EditCardDialogParams
) => fireEvent(element, dialogShowEvent, editCardDialogParams);
) => {
if (!registeredDialog) {
registeredDialog = true;
registerEditCardDialog(element);
}
fireEvent(element, dialogShowEvent, editCardDialogParams);
};

export class HuiDialogEditCard extends LitElement {
protected hass?: HomeAssistant;
Expand All @@ -60,7 +69,12 @@ export class HuiDialogEditCard extends LitElement {
if (!this._params) {
return html``;
}
if (!this._params.cardConfig.id) {
if (
(!this._params.add &&
this._params.cardConfig &&
!this._params.cardConfig.id) ||
(this._params.add && !this._params.viewId)
) {
return html`
<hui-migrate-config
.hass="${this.hass}"
Expand All @@ -70,13 +84,24 @@ export class HuiDialogEditCard extends LitElement {
}
return html`
<hui-edit-card
.cardConfig="${this._params.cardConfig}"
.hass="${this.hass}"
.viewId="${this._params.viewId}"
.cardConfig="${this._params.cardConfig}"
@reload-lovelace="${this._params.reloadLovelace}"
@cancel-edit-card="${this._cancel}"
>
</hui-edit-card>
`;
}

private _cancel() {
this._params = {
add: false,
reloadLovelace: () => {
return;
},
};
}
}

declare global {
Expand Down
Loading