mirror of
https://github.com/home-assistant/frontend.git
synced 2025-08-01 13:37:47 +00:00
commit
181539baac
@ -172,10 +172,14 @@ const CONFIGS = [
|
||||
- type: glance
|
||||
entities:
|
||||
- entity: lock.kitchen_door
|
||||
tap_action: toggle
|
||||
tap_action:
|
||||
type: toggle
|
||||
- entity: light.ceiling_lights
|
||||
tap_action: call-service
|
||||
service: light.turn_on
|
||||
tap_action:
|
||||
action: call-service
|
||||
service: light.turn_on
|
||||
service_data:
|
||||
entity_id: light.ceiling_lights
|
||||
- device_tracker.demo_paulus
|
||||
- media_player.living_room
|
||||
- sun.sun
|
||||
|
@ -56,7 +56,8 @@ const CONFIGS = [
|
||||
--iron-icon-fill-color: rgba(50, 50, 50, .75)
|
||||
- type: image
|
||||
entity: light.bed_light
|
||||
tap_action: toggle
|
||||
tap_action:
|
||||
action: toggle
|
||||
image: /images/light_bulb_off.png
|
||||
state_image:
|
||||
'on': /images/light_bulb_on.png
|
||||
|
@ -83,6 +83,23 @@ const CONFIGS = [
|
||||
- binary_sensor.basement_floor_wet
|
||||
`,
|
||||
},
|
||||
{
|
||||
heading: "Custom tap action",
|
||||
config: `
|
||||
- type: picture-glance
|
||||
image: /images/living_room.png
|
||||
title: Living room
|
||||
entity: light.ceiling_lights
|
||||
tap_action:
|
||||
action: toggle
|
||||
entities:
|
||||
- entity: switch.decorative_lights
|
||||
icon: mdi:power
|
||||
tap_action:
|
||||
action: toggle
|
||||
- binary_sensor.basement_floor_wet
|
||||
`,
|
||||
},
|
||||
];
|
||||
|
||||
class DemoPicGlance extends PolymerElement {
|
||||
|
@ -4,6 +4,8 @@
|
||||
# Stop on errors
|
||||
set -e
|
||||
|
||||
cd "$(dirname "$0")/.."
|
||||
|
||||
BUILD_DIR=build
|
||||
OUTPUT_DIR=hass_frontend
|
||||
OUTPUT_DIR_ES5=hass_frontend_es5
|
||||
|
11
script/size_stats
Executable file
11
script/size_stats
Executable file
@ -0,0 +1,11 @@
|
||||
#!/bin/sh
|
||||
# Analyze stats
|
||||
|
||||
# Stop on errors
|
||||
set -e
|
||||
|
||||
cd "$(dirname "$0")/.."
|
||||
|
||||
STATS=1 NODE_ENV=production webpack --profile --json > compilation-stats.json
|
||||
npx webpack-bundle-analyzer compilation-stats.json hass_frontend
|
||||
rm compilation-stats.json
|
@ -1,7 +1,9 @@
|
||||
import Leaflet from "leaflet";
|
||||
|
||||
// Sets up a Leaflet map on the provided DOM element
|
||||
export default function setupLeafletMap(mapElement) {
|
||||
export const setupLeafletMap = async (mapElement) => {
|
||||
const Leaflet = (await import(/* webpackChunkName: "leaflet" */ "leaflet"))
|
||||
.default;
|
||||
Leaflet.Icon.Default.imagePath = "/static/images/leaflet";
|
||||
|
||||
const map = Leaflet.map(mapElement);
|
||||
const style = document.createElement("link");
|
||||
style.setAttribute("href", "/static/images/leaflet/leaflet.css");
|
||||
@ -21,5 +23,5 @@ export default function setupLeafletMap(mapElement) {
|
||||
}
|
||||
).addTo(map);
|
||||
|
||||
return map;
|
||||
}
|
||||
return [map, Leaflet];
|
||||
};
|
||||
|
@ -51,9 +51,13 @@ export type ActionConfig =
|
||||
| MoreInfoActionConfig
|
||||
| NoActionConfig;
|
||||
|
||||
export const fetchConfig = (hass: HomeAssistant): Promise<LovelaceConfig> =>
|
||||
export const fetchConfig = (
|
||||
hass: HomeAssistant,
|
||||
force: boolean
|
||||
): Promise<LovelaceConfig> =>
|
||||
hass.callWS({
|
||||
type: "lovelace/config",
|
||||
force,
|
||||
});
|
||||
|
||||
export const migrateConfig = (hass: HomeAssistant): Promise<void> =>
|
||||
|
@ -8,18 +8,18 @@ import { TemplateResult } from "lit-html";
|
||||
|
||||
import { fireEvent } from "../../../common/dom/fire_event";
|
||||
import { styleMap } from "lit-html/directives/styleMap";
|
||||
import { jQuery } from "../../../resources/jquery";
|
||||
import { roundSliderStyle } from "../../../resources/jquery.roundslider";
|
||||
import { HomeAssistant, LightEntity } from "../../../types";
|
||||
import { hassLocalizeLitMixin } from "../../../mixins/lit-localize-mixin";
|
||||
import { LovelaceCard } from "../types";
|
||||
import { LovelaceCardConfig } from "../../../data/lovelace";
|
||||
import { longPress } from "../common/directives/long-press-directive";
|
||||
import { hasConfigOrEntityChanged } from "../common/has-changed";
|
||||
import { loadRoundslider } from "../../../resources/jquery.roundslider.ondemand";
|
||||
import { toggleEntity } from "../common/entity/toggle-entity";
|
||||
|
||||
import stateIcon from "../../../common/entity/state_icon";
|
||||
import computeStateName from "../../../common/entity/compute_state_name";
|
||||
import applyThemesOnElement from "../../../common/dom/apply_themes_on_element";
|
||||
import { hasConfigOrEntityChanged } from "../common/has-changed";
|
||||
|
||||
import "../../../components/ha-card";
|
||||
import "../../../components/ha-icon";
|
||||
@ -49,11 +49,15 @@ export class HuiLightCard extends hassLocalizeLitMixin(LitElement)
|
||||
public hass?: HomeAssistant;
|
||||
private _config?: Config;
|
||||
private _brightnessTimout?: number;
|
||||
private _roundSliderStyle?: TemplateResult;
|
||||
private _jQuery?: any;
|
||||
|
||||
static get properties(): PropertyDeclarations {
|
||||
return {
|
||||
hass: {},
|
||||
_config: {},
|
||||
roundSliderStyle: {},
|
||||
_jQuery: {},
|
||||
};
|
||||
}
|
||||
|
||||
@ -99,14 +103,14 @@ export class HuiLightCard extends hassLocalizeLitMixin(LitElement)
|
||||
color: this._computeColor(stateObj),
|
||||
})
|
||||
}"
|
||||
@ha-click="${() => this._handleClick(false)}"
|
||||
@ha-hold="${() => this._handleClick(true)}"
|
||||
@ha-click="${this._handleTap}"
|
||||
@ha-hold="${this._handleHold}"
|
||||
.longPress="${longPress()}"
|
||||
></ha-icon>
|
||||
<div
|
||||
class="brightness"
|
||||
@ha-click="${() => this._handleClick(false)}"
|
||||
@ha-hold="${() => this._handleClick(true)}"
|
||||
@ha-click="${this._handleTap}"
|
||||
@ha-hold="${this._handleHold}"
|
||||
.longPress="${longPress()}"
|
||||
></div>
|
||||
<div class="name">
|
||||
@ -124,10 +128,15 @@ export class HuiLightCard extends hassLocalizeLitMixin(LitElement)
|
||||
return hasConfigOrEntityChanged(this, changedProps);
|
||||
}
|
||||
|
||||
protected firstUpdated(): void {
|
||||
protected async firstUpdated(): Promise<void> {
|
||||
const loaded = await loadRoundslider();
|
||||
|
||||
this._roundSliderStyle = loaded.roundSliderStyle;
|
||||
this._jQuery = loaded.jQuery;
|
||||
|
||||
const brightness = this.hass!.states[this._config!.entity].attributes
|
||||
.brightness;
|
||||
jQuery("#light", this.shadowRoot).roundSlider({
|
||||
this._jQuery("#light", this.shadowRoot).roundSlider({
|
||||
...lightConfig,
|
||||
change: (value) => this._setBrightness(value),
|
||||
drag: (value) => this._dragEvent(value),
|
||||
@ -139,13 +148,13 @@ export class HuiLightCard extends hassLocalizeLitMixin(LitElement)
|
||||
}
|
||||
|
||||
protected updated(changedProps: PropertyValues): void {
|
||||
if (!this._config || !this.hass) {
|
||||
if (!this._config || !this.hass || !this._jQuery) {
|
||||
return;
|
||||
}
|
||||
|
||||
const attrs = this.hass!.states[this._config!.entity].attributes;
|
||||
|
||||
jQuery("#light", this.shadowRoot).roundSlider({
|
||||
this._jQuery("#light", this.shadowRoot).roundSlider({
|
||||
value: Math.round((attrs.brightness / 254) * 100) || 0,
|
||||
});
|
||||
|
||||
@ -157,7 +166,7 @@ export class HuiLightCard extends hassLocalizeLitMixin(LitElement)
|
||||
|
||||
private renderStyle(): TemplateResult {
|
||||
return html`
|
||||
${roundSliderStyle}
|
||||
${this._roundSliderStyle}
|
||||
<style>
|
||||
:host {
|
||||
display: block;
|
||||
@ -311,18 +320,13 @@ export class HuiLightCard extends hassLocalizeLitMixin(LitElement)
|
||||
return `hsl(${hue}, 100%, ${100 - sat / 2}%)`;
|
||||
}
|
||||
|
||||
private _handleClick(hold: boolean): void {
|
||||
const entityId = this._config!.entity;
|
||||
private _handleTap() {
|
||||
toggleEntity(this.hass!, this._config!.entity!);
|
||||
}
|
||||
|
||||
if (hold) {
|
||||
fireEvent(this, "hass-more-info", {
|
||||
entityId,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
this.hass!.callService("light", "toggle", {
|
||||
entity_id: entityId,
|
||||
private _handleHold() {
|
||||
fireEvent(this, "hass-more-info", {
|
||||
entityId: this._config!.entity,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -1,19 +1,16 @@
|
||||
import { html } from "@polymer/polymer/lib/utils/html-tag";
|
||||
import { PolymerElement } from "@polymer/polymer/polymer-element";
|
||||
import "@polymer/paper-icon-button/paper-icon-button";
|
||||
import Leaflet from "leaflet";
|
||||
|
||||
import "../../map/ha-entity-marker";
|
||||
|
||||
import setupLeafletMap from "../../../common/dom/setup-leaflet-map";
|
||||
import { setupLeafletMap } from "../../../common/dom/setup-leaflet-map";
|
||||
import { processConfigEntities } from "../common/process-config-entities";
|
||||
import computeStateDomain from "../../../common/entity/compute_state_domain";
|
||||
import computeStateName from "../../../common/entity/compute_state_name";
|
||||
import debounce from "../../../common/util/debounce";
|
||||
import parseAspectRatio from "../../../common/util/parse-aspect-ratio";
|
||||
|
||||
Leaflet.Icon.Default.imagePath = "/static/images/leaflet";
|
||||
|
||||
class HuiMapCard extends PolymerElement {
|
||||
static get template() {
|
||||
return html`
|
||||
@ -143,13 +140,14 @@ class HuiMapCard extends PolymerElement {
|
||||
window.addEventListener("resize", this._debouncedResizeListener);
|
||||
}
|
||||
|
||||
this._map = setupLeafletMap(this.$.map);
|
||||
this._drawEntities(this.hass);
|
||||
this.loadMap();
|
||||
}
|
||||
|
||||
setTimeout(() => {
|
||||
this._resetMap();
|
||||
this._fitMap();
|
||||
}, 1);
|
||||
async loadMap() {
|
||||
[this._map, this.Leaflet] = await setupLeafletMap(this.$.map);
|
||||
this._drawEntities(this.hass);
|
||||
this._map.invalidateSize();
|
||||
this._fitMap();
|
||||
}
|
||||
|
||||
disconnectedCallback() {
|
||||
@ -177,7 +175,7 @@ class HuiMapCard extends PolymerElement {
|
||||
const zoom = this._config.default_zoom;
|
||||
if (this._mapItems.length === 0) {
|
||||
this._map.setView(
|
||||
new Leaflet.LatLng(
|
||||
new this.Leaflet.LatLng(
|
||||
this.hass.config.latitude,
|
||||
this.hass.config.longitude
|
||||
),
|
||||
@ -186,7 +184,7 @@ class HuiMapCard extends PolymerElement {
|
||||
return;
|
||||
}
|
||||
|
||||
const bounds = new Leaflet.latLngBounds(
|
||||
const bounds = new this.Leaflet.latLngBounds(
|
||||
this._mapItems.map((item) => item.getLatLng())
|
||||
);
|
||||
this._map.fitBounds(bounds.pad(0.5));
|
||||
@ -245,7 +243,7 @@ class HuiMapCard extends PolymerElement {
|
||||
iconHTML = title;
|
||||
}
|
||||
|
||||
markerIcon = Leaflet.divIcon({
|
||||
markerIcon = this.Leaflet.divIcon({
|
||||
html: iconHTML,
|
||||
iconSize: [24, 24],
|
||||
className: "",
|
||||
@ -253,7 +251,7 @@ class HuiMapCard extends PolymerElement {
|
||||
|
||||
// create market with the icon
|
||||
mapItems.push(
|
||||
Leaflet.marker([latitude, longitude], {
|
||||
this.Leaflet.marker([latitude, longitude], {
|
||||
icon: markerIcon,
|
||||
interactive: false,
|
||||
title: title,
|
||||
@ -262,7 +260,7 @@ class HuiMapCard extends PolymerElement {
|
||||
|
||||
// create circle around it
|
||||
mapItems.push(
|
||||
Leaflet.circle([latitude, longitude], {
|
||||
this.Leaflet.circle([latitude, longitude], {
|
||||
interactive: false,
|
||||
color: "#FF9800",
|
||||
radius: radius,
|
||||
@ -285,9 +283,9 @@ class HuiMapCard extends PolymerElement {
|
||||
el.setAttribute("entity-name", entityName);
|
||||
el.setAttribute("entity-picture", entityPicture || "");
|
||||
|
||||
/* Leaflet clones this element before adding it to the map. This messes up
|
||||
/* this.Leaflet clones this element before adding it to the map. This messes up
|
||||
our Polymer object and we can't pass data through. Thus we hack like this. */
|
||||
markerIcon = Leaflet.divIcon({
|
||||
markerIcon = this.Leaflet.divIcon({
|
||||
html: el.outerHTML,
|
||||
iconSize: [48, 48],
|
||||
className: "",
|
||||
@ -295,7 +293,7 @@ class HuiMapCard extends PolymerElement {
|
||||
|
||||
// create market with the icon
|
||||
mapItems.push(
|
||||
Leaflet.marker([latitude, longitude], {
|
||||
this.Leaflet.marker([latitude, longitude], {
|
||||
icon: markerIcon,
|
||||
title: computeStateName(stateObj),
|
||||
}).addTo(map)
|
||||
@ -304,7 +302,7 @@ class HuiMapCard extends PolymerElement {
|
||||
// create circle around if entity has accuracy
|
||||
if (gpsAccuracy) {
|
||||
mapItems.push(
|
||||
Leaflet.circle([latitude, longitude], {
|
||||
this.Leaflet.circle([latitude, longitude], {
|
||||
interactive: false,
|
||||
color: "#0288D1",
|
||||
radius: gpsAccuracy,
|
||||
|
@ -71,11 +71,13 @@ class HuiPictureElementsCard extends LitElement implements LovelaceCard {
|
||||
.entity="${this._config.entity}"
|
||||
.aspectRatio="${this._config.aspect_ratio}"
|
||||
></hui-image>
|
||||
${
|
||||
this._config.elements.map((elementConfig: LovelaceElementConfig) =>
|
||||
this._createHuiElement(elementConfig)
|
||||
)
|
||||
}
|
||||
<div id="root">
|
||||
${
|
||||
this._config.elements.map((elementConfig: LovelaceElementConfig) =>
|
||||
this._createHuiElement(elementConfig)
|
||||
)
|
||||
}
|
||||
</div>
|
||||
</ha-card>
|
||||
`;
|
||||
}
|
||||
|
@ -6,13 +6,11 @@ import {
|
||||
} from "@polymer/lit-element";
|
||||
import { classMap } from "lit-html/directives/classMap";
|
||||
import { TemplateResult } from "lit-html";
|
||||
import { jQuery } from "../../../resources/jquery";
|
||||
|
||||
import applyThemesOnElement from "../../../common/dom/apply_themes_on_element";
|
||||
import computeStateName from "../../../common/entity/compute_state_name";
|
||||
|
||||
import { hasConfigOrEntityChanged } from "../common/has-changed";
|
||||
import { roundSliderStyle } from "../../../resources/jquery.roundslider";
|
||||
import { HomeAssistant, ClimateEntity } from "../../../types";
|
||||
import { hassLocalizeLitMixin } from "../../../mixins/lit-localize-mixin";
|
||||
import { LovelaceCard } from "../types";
|
||||
@ -20,6 +18,7 @@ import { LovelaceCardConfig } from "../../../data/lovelace";
|
||||
|
||||
import "../../../components/ha-card";
|
||||
import "../../../components/ha-icon";
|
||||
import { loadRoundslider } from "../../../resources/jquery.roundslider.ondemand";
|
||||
|
||||
const thermostatConfig = {
|
||||
radius: 150,
|
||||
@ -58,11 +57,15 @@ export class HuiThermostatCard extends hassLocalizeLitMixin(LitElement)
|
||||
implements LovelaceCard {
|
||||
public hass?: HomeAssistant;
|
||||
private _config?: Config;
|
||||
private _roundSliderStyle?: TemplateResult;
|
||||
private _jQuery?: any;
|
||||
|
||||
static get properties(): PropertyDeclarations {
|
||||
return {
|
||||
hass: {},
|
||||
_config: {},
|
||||
roundSliderStyle: {},
|
||||
_jQuery: {},
|
||||
};
|
||||
}
|
||||
|
||||
@ -134,7 +137,12 @@ export class HuiThermostatCard extends hassLocalizeLitMixin(LitElement)
|
||||
return hasConfigOrEntityChanged(this, changedProps);
|
||||
}
|
||||
|
||||
protected firstUpdated(): void {
|
||||
protected async firstUpdated(): Promise<void> {
|
||||
const loaded = await loadRoundslider();
|
||||
|
||||
this._roundSliderStyle = loaded.roundSliderStyle;
|
||||
this._jQuery = loaded.jQuery;
|
||||
|
||||
const stateObj = this.hass!.states[this._config!.entity] as ClimateEntity;
|
||||
|
||||
const _sliderType =
|
||||
@ -143,7 +151,7 @@ export class HuiThermostatCard extends hassLocalizeLitMixin(LitElement)
|
||||
? "range"
|
||||
: "min-range";
|
||||
|
||||
jQuery("#thermostat", this.shadowRoot).roundSlider({
|
||||
this._jQuery("#thermostat", this.shadowRoot).roundSlider({
|
||||
...thermostatConfig,
|
||||
radius: this.clientWidth / 3,
|
||||
min: stateObj.attributes.min_temp,
|
||||
@ -155,7 +163,7 @@ export class HuiThermostatCard extends hassLocalizeLitMixin(LitElement)
|
||||
}
|
||||
|
||||
protected updated(changedProps: PropertyValues): void {
|
||||
if (!this._config || !this.hass) {
|
||||
if (!this._config || !this.hass || !this._jQuery) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -179,7 +187,7 @@ export class HuiThermostatCard extends hassLocalizeLitMixin(LitElement)
|
||||
sliderValue = uiValue = stateObj.attributes.temperature;
|
||||
}
|
||||
|
||||
jQuery("#thermostat", this.shadowRoot).roundSlider({
|
||||
this._jQuery("#thermostat", this.shadowRoot).roundSlider({
|
||||
value: sliderValue,
|
||||
});
|
||||
this.shadowRoot!.querySelector("#set-temperature")!.innerHTML = uiValue;
|
||||
@ -192,7 +200,7 @@ export class HuiThermostatCard extends hassLocalizeLitMixin(LitElement)
|
||||
|
||||
private renderStyle(): TemplateResult {
|
||||
return html`
|
||||
${roundSliderStyle}
|
||||
${this._roundSliderStyle}
|
||||
<style>
|
||||
:host {
|
||||
display: block;
|
||||
|
@ -1,4 +1,4 @@
|
||||
import "../../../cards/ha-camera-card";
|
||||
import "../../../cards/ha-weather-card";
|
||||
|
||||
import LegacyWrapperCard from "./hui-legacy-wrapper-card";
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
import computeStateName from "../../../common/entity/compute_state_name";
|
||||
import { HomeAssistant } from "../../../types";
|
||||
import { LovelaceElementConfig } from "../elements/types";
|
||||
import { ActionConfig } from "../../../data/lovelace";
|
||||
|
||||
export const computeTooltip = (
|
||||
hass: HomeAssistant,
|
||||
@ -11,7 +12,7 @@ export const computeTooltip = (
|
||||
}
|
||||
|
||||
let stateName = "";
|
||||
let tooltip: string;
|
||||
let tooltip = "";
|
||||
|
||||
if (config.entity) {
|
||||
stateName =
|
||||
@ -20,19 +21,45 @@ export const computeTooltip = (
|
||||
: config.entity;
|
||||
}
|
||||
|
||||
switch (config.tap_action && config.tap_action.action) {
|
||||
case "navigate":
|
||||
tooltip = `Navigate to ${config.navigation_path}`;
|
||||
break;
|
||||
case "toggle":
|
||||
tooltip = `Toggle ${stateName}`;
|
||||
break;
|
||||
case "call-service":
|
||||
tooltip = `Call service ${config.service}`;
|
||||
break;
|
||||
default:
|
||||
tooltip = `Show more-info: ${stateName}`;
|
||||
}
|
||||
const tapTooltip = config.tap_action
|
||||
? computeActionTooltip(stateName, config.tap_action, false)
|
||||
: "";
|
||||
const holdTooltip = config.hold_action
|
||||
? computeActionTooltip(stateName, config.hold_action, true)
|
||||
: "";
|
||||
|
||||
const newline = tapTooltip && holdTooltip ? "\n" : "";
|
||||
|
||||
tooltip = tapTooltip + newline + holdTooltip;
|
||||
|
||||
return tooltip;
|
||||
};
|
||||
|
||||
function computeActionTooltip(
|
||||
state: string,
|
||||
config: ActionConfig,
|
||||
isHold: boolean
|
||||
) {
|
||||
if (!config || !config.action || config.action === "none") {
|
||||
return "";
|
||||
}
|
||||
|
||||
let tooltip = isHold ? "Hold: " : "Tap: ";
|
||||
|
||||
switch (config.action) {
|
||||
case "navigate":
|
||||
tooltip += `Navigate to ${config.navigation_path}`;
|
||||
break;
|
||||
case "toggle":
|
||||
tooltip += `Toggle ${state}`;
|
||||
break;
|
||||
case "call-service":
|
||||
tooltip += `Call service ${config.service}`;
|
||||
break;
|
||||
case "more-info":
|
||||
tooltip += `Show more-info: ${state}`;
|
||||
break;
|
||||
}
|
||||
|
||||
return tooltip;
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { html, LitElement, PropertyDeclarations } from "@polymer/lit-element";
|
||||
import "@polymer/paper-button/paper-button";
|
||||
import { fireEvent } from "../../../common/dom/fire_event";
|
||||
import { showEditCardDialog } from "../editor/hui-dialog-edit-card";
|
||||
import { showEditCardDialog } from "../editor/show-edit-card-dialog";
|
||||
|
||||
import { hassLocalizeLitMixin } from "../../../mixins/lit-localize-mixin";
|
||||
import { confDeleteCard } from "../editor/delete-card";
|
||||
@ -50,14 +50,15 @@ export class HuiCardOptions extends hassLocalizeLitMixin(LitElement) {
|
||||
</style>
|
||||
<slot></slot>
|
||||
<div>
|
||||
<paper-button @click="${this._editCard}"
|
||||
>${
|
||||
this.localize("ui.panel.lovelace.editor.edit_card.edit")
|
||||
}</paper-button
|
||||
>
|
||||
<paper-button class="warning" @click="${this._deleteCard}"
|
||||
>${
|
||||
this.localize("ui.panel.lovelace.editor.edit_card.delete")
|
||||
}</paper-button
|
||||
><paper-button @click="${this._editCard}"
|
||||
>${
|
||||
this.localize("ui.panel.lovelace.editor.edit_card.edit")
|
||||
}</paper-button
|
||||
>
|
||||
</div>
|
||||
`;
|
||||
|
@ -1,5 +1,4 @@
|
||||
import { html, LitElement, PropertyDeclarations } from "@polymer/lit-element";
|
||||
import "@polymer/paper-button/paper-button";
|
||||
import { TemplateResult } from "lit-html";
|
||||
|
||||
import { HomeAssistant } from "../../../types";
|
||||
@ -84,9 +83,6 @@ export class HuiEntityEditor extends LitElement {
|
||||
.entities {
|
||||
padding-left: 20px;
|
||||
}
|
||||
paper-button {
|
||||
margin: 8px 0;
|
||||
}
|
||||
</style>
|
||||
`;
|
||||
}
|
||||
|
@ -28,7 +28,8 @@ export class HuiViewEditor extends hassLocalizeLitMixin(LitElement) {
|
||||
if (!this._config) {
|
||||
return "";
|
||||
}
|
||||
return this._config.id || "";
|
||||
|
||||
return "id" in this._config ? this._config.id! : "";
|
||||
}
|
||||
|
||||
get _title(): string {
|
||||
|
@ -2,7 +2,7 @@ import { html, LitElement, PropertyDeclarations } from "@polymer/lit-element";
|
||||
import { TemplateResult } from "lit-html";
|
||||
|
||||
import { HomeAssistant } from "../../../types";
|
||||
import { fireEvent, HASSDomEvent } from "../../../common/dom/fire_event";
|
||||
import { HASSDomEvent } from "../../../common/dom/fire_event";
|
||||
import { LovelaceCardConfig } from "../../../data/lovelace";
|
||||
import "./hui-edit-card";
|
||||
import "./hui-migrate-config";
|
||||
@ -11,7 +11,6 @@ declare global {
|
||||
// for fire event
|
||||
interface HASSDomEvents {
|
||||
"reload-lovelace": undefined;
|
||||
"show-edit-card": EditCardDialogParams;
|
||||
}
|
||||
// for add event listener
|
||||
interface HTMLElementEventMap {
|
||||
@ -19,10 +18,6 @@ declare global {
|
||||
}
|
||||
}
|
||||
|
||||
let registeredDialog = false;
|
||||
const dialogShowEvent = "show-edit-card";
|
||||
const dialogTag = "hui-dialog-edit-card";
|
||||
|
||||
export interface EditCardDialogParams {
|
||||
cardConfig?: LovelaceCardConfig;
|
||||
viewId?: string | number;
|
||||
@ -30,24 +25,6 @@ export interface EditCardDialogParams {
|
||||
reloadLovelace: () => void;
|
||||
}
|
||||
|
||||
const registerEditCardDialog = (element: HTMLElement) =>
|
||||
fireEvent(element, "register-dialog", {
|
||||
dialogShowEvent,
|
||||
dialogTag,
|
||||
dialogImport: () => import("./hui-dialog-edit-card"),
|
||||
});
|
||||
|
||||
export const showEditCardDialog = (
|
||||
element: HTMLElement,
|
||||
editCardDialogParams: EditCardDialogParams
|
||||
) => {
|
||||
if (!registeredDialog) {
|
||||
registeredDialog = true;
|
||||
registerEditCardDialog(element);
|
||||
}
|
||||
fireEvent(element, dialogShowEvent, editCardDialogParams);
|
||||
};
|
||||
|
||||
export class HuiDialogEditCard extends LitElement {
|
||||
protected hass?: HomeAssistant;
|
||||
private _params?: EditCardDialogParams;
|
||||
@ -110,4 +87,4 @@ declare global {
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define(dialogTag, HuiDialogEditCard);
|
||||
customElements.define("hui-dialog-edit-card", HuiDialogEditCard);
|
||||
|
@ -2,16 +2,15 @@ import { html, LitElement, PropertyDeclarations } from "@polymer/lit-element";
|
||||
import { TemplateResult } from "lit-html";
|
||||
|
||||
import { HomeAssistant } from "../../../types";
|
||||
import { fireEvent, HASSDomEvent } from "../../../common/dom/fire_event";
|
||||
import { LovelaceViewConfig } from "../../../data/lovelace";
|
||||
import { HASSDomEvent } from "../../../common/dom/fire_event";
|
||||
import "./hui-edit-view";
|
||||
import "./hui-migrate-config";
|
||||
import { EditViewDialogParams } from "./show-edit-view-dialog";
|
||||
|
||||
declare global {
|
||||
// for fire event
|
||||
interface HASSDomEvents {
|
||||
"reload-lovelace": undefined;
|
||||
"show-edit-view": EditViewDialogParams;
|
||||
}
|
||||
// for add event listener
|
||||
interface HTMLElementEventMap {
|
||||
@ -19,34 +18,6 @@ declare global {
|
||||
}
|
||||
}
|
||||
|
||||
let registeredDialog = false;
|
||||
const dialogShowEvent = "show-edit-view";
|
||||
const dialogTag = "hui-dialog-edit-view";
|
||||
|
||||
export interface EditViewDialogParams {
|
||||
viewConfig?: LovelaceViewConfig;
|
||||
add?: boolean;
|
||||
reloadLovelace: () => void;
|
||||
}
|
||||
|
||||
const registerEditViewDialog = (element: HTMLElement) =>
|
||||
fireEvent(element, "register-dialog", {
|
||||
dialogShowEvent,
|
||||
dialogTag,
|
||||
dialogImport: () => import("./hui-dialog-edit-view"),
|
||||
});
|
||||
|
||||
export const showEditViewDialog = (
|
||||
element: HTMLElement,
|
||||
editViewDialogParams: EditViewDialogParams
|
||||
) => {
|
||||
if (!registeredDialog) {
|
||||
registeredDialog = true;
|
||||
registerEditViewDialog(element);
|
||||
}
|
||||
fireEvent(element, dialogShowEvent, editViewDialogParams);
|
||||
};
|
||||
|
||||
export class HuiDialogEditView extends LitElement {
|
||||
protected hass?: HomeAssistant;
|
||||
private _params?: EditViewDialogParams;
|
||||
@ -71,7 +42,7 @@ export class HuiDialogEditView extends LitElement {
|
||||
if (
|
||||
!this._params.add &&
|
||||
this._params.viewConfig &&
|
||||
!this._params.viewConfig.id
|
||||
!("id" in this._params.viewConfig)
|
||||
) {
|
||||
return html`
|
||||
<hui-migrate-config
|
||||
@ -98,4 +69,4 @@ declare global {
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define(dialogTag, HuiDialogEditView);
|
||||
customElements.define("hui-dialog-edit-view", HuiDialogEditView);
|
||||
|
@ -10,6 +10,10 @@ import "@polymer/paper-spinner/paper-spinner";
|
||||
import "@polymer/paper-tabs/paper-tab";
|
||||
import "@polymer/paper-tabs/paper-tabs";
|
||||
import "@polymer/paper-dialog/paper-dialog";
|
||||
import "@polymer/paper-icon-button/paper-icon-button.js";
|
||||
import "@polymer/paper-item/paper-item.js";
|
||||
import "@polymer/paper-listbox/paper-listbox.js";
|
||||
import "@polymer/paper-menu-button/paper-menu-button.js";
|
||||
// This is not a duplicate import, one is for types, one is for element.
|
||||
// tslint:disable-next-line
|
||||
import { PaperDialogElement } from "@polymer/paper-dialog/paper-dialog";
|
||||
@ -28,6 +32,8 @@ import { hassLocalizeLitMixin } from "../../../mixins/lit-localize-mixin";
|
||||
import { EntitiesEditorEvent, ViewEditEvent } from "./types";
|
||||
import { processEditorEntities } from "./process-editor-entities";
|
||||
import { EntityConfig } from "../entity-rows/types";
|
||||
import { confDeleteView } from "./delete-view";
|
||||
import { navigate } from "../../../common/navigate";
|
||||
|
||||
export class HuiEditView extends hassLocalizeLitMixin(LitElement) {
|
||||
static get properties(): PropertyDeclarations {
|
||||
@ -79,7 +85,7 @@ export class HuiEditView extends hassLocalizeLitMixin(LitElement) {
|
||||
) {
|
||||
const { cards, badges, ...viewConfig } = this.viewConfig;
|
||||
this._config = viewConfig;
|
||||
this._badges = processEditorEntities(badges);
|
||||
this._badges = badges ? processEditorEntities(badges) : [];
|
||||
} else if (changedProperties.has("add")) {
|
||||
this._config = {};
|
||||
this._badges = [];
|
||||
@ -146,6 +152,15 @@ export class HuiEditView extends hassLocalizeLitMixin(LitElement) {
|
||||
></paper-spinner>
|
||||
${this.localize("ui.common.save")}</paper-button
|
||||
>
|
||||
<paper-menu-button no-animations>
|
||||
<paper-icon-button
|
||||
icon="hass:dots-vertical"
|
||||
slot="dropdown-trigger"
|
||||
></paper-icon-button>
|
||||
<paper-listbox slot="dropdown-content">
|
||||
<paper-item @click="${this._delete}">Delete</paper-item>
|
||||
</paper-listbox>
|
||||
</paper-menu-button>
|
||||
</div>
|
||||
</paper-dialog>
|
||||
`;
|
||||
@ -189,6 +204,20 @@ export class HuiEditView extends hassLocalizeLitMixin(LitElement) {
|
||||
this._updateConfigInBackend();
|
||||
}
|
||||
|
||||
private _delete() {
|
||||
if (this._config!.cards && this._config!.cards!.length > 0) {
|
||||
alert(
|
||||
"You can't delete a view that has card in them. Remove the cards first."
|
||||
);
|
||||
return;
|
||||
}
|
||||
confDeleteView(this.hass!, this._config!.id!, () => {
|
||||
this._closeDialog();
|
||||
this.reloadLovelace!();
|
||||
navigate(this, `/lovelace/0`);
|
||||
});
|
||||
}
|
||||
|
||||
private async _resizeDialog(): Promise<void> {
|
||||
await this.updateComplete;
|
||||
fireEvent(this._dialog, "iron-resize");
|
||||
@ -233,7 +262,7 @@ export class HuiEditView extends hassLocalizeLitMixin(LitElement) {
|
||||
} else {
|
||||
await updateViewConfig(
|
||||
this.hass!,
|
||||
this.viewConfig!.id!,
|
||||
String(this.viewConfig!.id!),
|
||||
this._config,
|
||||
"json"
|
||||
);
|
||||
|
38
src/panels/lovelace/editor/show-edit-card-dialog.ts
Normal file
38
src/panels/lovelace/editor/show-edit-card-dialog.ts
Normal file
@ -0,0 +1,38 @@
|
||||
import { LovelaceCardConfig } from "../../../data/lovelace";
|
||||
import { fireEvent } from "../../../common/dom/fire_event";
|
||||
|
||||
declare global {
|
||||
// for fire event
|
||||
interface HASSDomEvents {
|
||||
"show-edit-card": EditCardDialogParams;
|
||||
}
|
||||
}
|
||||
|
||||
let registeredDialog = false;
|
||||
const dialogShowEvent = "show-edit-card";
|
||||
const dialogTag = "hui-dialog-edit-card";
|
||||
|
||||
export interface EditCardDialogParams {
|
||||
cardConfig?: LovelaceCardConfig;
|
||||
viewId?: string | number;
|
||||
add: boolean;
|
||||
reloadLovelace: () => void;
|
||||
}
|
||||
|
||||
const registerEditCardDialog = (element: HTMLElement) =>
|
||||
fireEvent(element, "register-dialog", {
|
||||
dialogShowEvent,
|
||||
dialogTag,
|
||||
dialogImport: () => import("./hui-dialog-edit-card"),
|
||||
});
|
||||
|
||||
export const showEditCardDialog = (
|
||||
element: HTMLElement,
|
||||
editCardDialogParams: EditCardDialogParams
|
||||
) => {
|
||||
if (!registeredDialog) {
|
||||
registeredDialog = true;
|
||||
registerEditCardDialog(element);
|
||||
}
|
||||
fireEvent(element, dialogShowEvent, editCardDialogParams);
|
||||
};
|
42
src/panels/lovelace/editor/show-edit-view-dialog.ts
Normal file
42
src/panels/lovelace/editor/show-edit-view-dialog.ts
Normal file
@ -0,0 +1,42 @@
|
||||
import { HASSDomEvent, fireEvent } from "../../../common/dom/fire_event";
|
||||
import { LovelaceViewConfig } from "../../../data/lovelace";
|
||||
|
||||
declare global {
|
||||
// for fire event
|
||||
interface HASSDomEvents {
|
||||
"reload-lovelace": undefined;
|
||||
"show-edit-view": EditViewDialogParams;
|
||||
}
|
||||
// for add event listener
|
||||
interface HTMLElementEventMap {
|
||||
"reload-lovelace": HASSDomEvent<undefined>;
|
||||
}
|
||||
}
|
||||
|
||||
let registeredDialog = false;
|
||||
const dialogShowEvent = "show-edit-view";
|
||||
const dialogTag = "hui-dialog-edit-view";
|
||||
|
||||
export interface EditViewDialogParams {
|
||||
viewConfig?: LovelaceViewConfig;
|
||||
add?: boolean;
|
||||
reloadLovelace: () => void;
|
||||
}
|
||||
|
||||
const registerEditViewDialog = (element: HTMLElement) =>
|
||||
fireEvent(element, "register-dialog", {
|
||||
dialogShowEvent,
|
||||
dialogTag,
|
||||
dialogImport: () => import("./hui-dialog-edit-view"),
|
||||
});
|
||||
|
||||
export const showEditViewDialog = (
|
||||
element: HTMLElement,
|
||||
editViewDialogParams: EditViewDialogParams
|
||||
) => {
|
||||
if (!registeredDialog) {
|
||||
registeredDialog = true;
|
||||
registerEditViewDialog(element);
|
||||
}
|
||||
fireEvent(element, dialogShowEvent, editViewDialogParams);
|
||||
};
|
@ -8,7 +8,6 @@ export interface LovelaceElementConfig {
|
||||
hold_action?: ActionConfig;
|
||||
service?: string;
|
||||
service_data?: object;
|
||||
navigation_path?: string;
|
||||
tap_action?: ActionConfig;
|
||||
title?: string;
|
||||
}
|
||||
|
@ -8,11 +8,15 @@ import "./hui-error-entity-row";
|
||||
import { HomeAssistant } from "../../../types";
|
||||
import { EntityRow, EntityConfig } from "./types";
|
||||
|
||||
import computeStateDisplay from "../../../common/entity/compute_state_display";
|
||||
import { hassLocalizeLitMixin } from "../../../mixins/lit-localize-mixin";
|
||||
|
||||
interface SensorEntityConfig extends EntityConfig {
|
||||
format?: "relative" | "date" | "time" | "datetime";
|
||||
}
|
||||
|
||||
class HuiSensorEntityRow extends LitElement implements EntityRow {
|
||||
class HuiSensorEntityRow extends hassLocalizeLitMixin(LitElement)
|
||||
implements EntityRow {
|
||||
public hass?: HomeAssistant;
|
||||
private _config?: SensorEntityConfig;
|
||||
|
||||
@ -58,7 +62,7 @@ class HuiSensorEntityRow extends LitElement implements EntityRow {
|
||||
.format="${this._config.format}"
|
||||
></hui-timestamp-display>
|
||||
`
|
||||
: stateObj.state
|
||||
: computeStateDisplay(this.localize, stateObj, this.hass.language)
|
||||
}
|
||||
</div>
|
||||
</hui-generic-entity-row>
|
||||
|
@ -28,7 +28,7 @@ class Lovelace extends localizeMixin(PolymerElement) {
|
||||
route="[[route]]"
|
||||
config="[[_config]]"
|
||||
columns="[[_columns]]"
|
||||
on-config-refresh="_fetchConfig"
|
||||
on-config-refresh="_forceFetchConfig"
|
||||
></hui-root>
|
||||
</template>
|
||||
<template
|
||||
@ -48,7 +48,7 @@ class Lovelace extends localizeMixin(PolymerElement) {
|
||||
narrow="[[narrow]]"
|
||||
show-menu="[[showMenu]]"
|
||||
>
|
||||
<paper-button on-click="_fetchConfig"
|
||||
<paper-button on-click="_forceFetchConfig"
|
||||
>Reload ui-lovelace.yaml</paper-button
|
||||
>
|
||||
</hass-error-screen>
|
||||
@ -96,7 +96,7 @@ class Lovelace extends localizeMixin(PolymerElement) {
|
||||
}
|
||||
|
||||
ready() {
|
||||
this._fetchConfig();
|
||||
this._fetchConfig(false);
|
||||
this._updateColumns = this._updateColumns.bind(this);
|
||||
this.mqls = [300, 600, 900, 1200].map((width) => {
|
||||
const mql = matchMedia(`(min-width: ${width}px)`);
|
||||
@ -113,9 +113,13 @@ class Lovelace extends localizeMixin(PolymerElement) {
|
||||
this._columns = Math.max(1, matchColumns - (!this.narrow && this.showMenu));
|
||||
}
|
||||
|
||||
async _fetchConfig() {
|
||||
_forceFetchConfig() {
|
||||
this._fetchConfig(true);
|
||||
}
|
||||
|
||||
async _fetchConfig(force) {
|
||||
try {
|
||||
const conf = await fetchConfig(this.hass);
|
||||
const conf = await fetchConfig(this.hass, force);
|
||||
this.setProperties({
|
||||
_config: conf,
|
||||
_state: "loaded",
|
||||
|
@ -33,8 +33,7 @@ import "./hui-view";
|
||||
import debounce from "../../common/util/debounce";
|
||||
import createCardElement from "./common/create-card-element";
|
||||
import { showSaveDialog } from "./editor/hui-dialog-save-config";
|
||||
import { showEditViewDialog } from "./editor/hui-dialog-edit-view";
|
||||
import { confDeleteView } from "./editor/delete-view";
|
||||
import { showEditViewDialog } from "./editor/show-edit-view-dialog";
|
||||
|
||||
// CSS and JS should only be imported once. Modules and HTML are safe.
|
||||
const CSS_CACHE = {};
|
||||
@ -61,7 +60,6 @@ class HUIRoot extends NavigateMixin(
|
||||
text-transform: uppercase;
|
||||
}
|
||||
#add-view {
|
||||
background: var(--paper-fab-background, var(--accent-color));
|
||||
position: absolute;
|
||||
height: 44px;
|
||||
}
|
||||
@ -71,12 +69,9 @@ class HUIRoot extends NavigateMixin(
|
||||
paper-button.warning:not([disabled]) {
|
||||
color: var(--google-red-500);
|
||||
}
|
||||
app-toolbar.secondary {
|
||||
background-color: var(--light-primary-color);
|
||||
color: var(--primary-text-color, #333);
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
height: auto;
|
||||
#add-view ha-icon {
|
||||
background-color: var(--accent-color);
|
||||
border-radius: 5px;
|
||||
}
|
||||
#view {
|
||||
min-height: calc(100vh - 112px);
|
||||
@ -95,6 +90,9 @@ class HUIRoot extends NavigateMixin(
|
||||
paper-item {
|
||||
cursor: pointer;
|
||||
}
|
||||
.edit-view-icon {
|
||||
padding-left: 8px;
|
||||
}
|
||||
</style>
|
||||
<app-route route="[[route]]" pattern="/:view" data="{{routeData}}"></app-route>
|
||||
<hui-notification-drawer
|
||||
@ -140,7 +138,7 @@ class HUIRoot extends NavigateMixin(
|
||||
</app-toolbar>
|
||||
</template>
|
||||
|
||||
<div sticky hidden$="[[_computeTabsHidden(config.views)]]">
|
||||
<div sticky hidden$="[[_computeTabsHidden(config.views, _editMode)]]">
|
||||
<paper-tabs scrollable selected="[[_curView]]" on-iron-activate="_handleViewSelected">
|
||||
<template is="dom-repeat" items="[[config.views]]">
|
||||
<paper-tab>
|
||||
@ -150,6 +148,9 @@ class HUIRoot extends NavigateMixin(
|
||||
<template is="dom-if" if="[[!item.icon]]">
|
||||
[[_computeTabTitle(item.title)]]
|
||||
</template>
|
||||
<template is='dom-if' if="[[_computeEditVisible(_editMode, config.views)]]">
|
||||
<ha-icon class="edit-view-icon" on-click="_editView" icon="hass:pencil"></ha-icon>
|
||||
</template>
|
||||
</paper-tab>
|
||||
</template>
|
||||
<template is='dom-if' if="[[_editMode]]">
|
||||
@ -160,12 +161,6 @@ class HUIRoot extends NavigateMixin(
|
||||
</paper-tabs>
|
||||
</div>
|
||||
</app-header>
|
||||
<template is='dom-if' if="[[_editMode]]">
|
||||
<app-toolbar class="secondary">
|
||||
<paper-button on-click="_editView">[[localize("ui.panel.lovelace.editor.edit_view.edit")]]</paper-button>
|
||||
<paper-button class="warning" on-click="_deleteView">[[localize("ui.panel.lovelace.editor.edit_view.delete")]]</paper-button>
|
||||
</app-toolbar>
|
||||
</template>
|
||||
<div id='view' on-rebuild-view='_debouncedConfigChanged'></div>
|
||||
</app-header-layout>
|
||||
`;
|
||||
@ -280,8 +275,8 @@ class HUIRoot extends NavigateMixin(
|
||||
return config.title || "Home Assistant";
|
||||
}
|
||||
|
||||
_computeTabsHidden(views) {
|
||||
return views.length < 2;
|
||||
_computeTabsHidden(views, editMode) {
|
||||
return views.length < 2 && !editMode;
|
||||
}
|
||||
|
||||
_computeTabTitle(title) {
|
||||
@ -304,6 +299,10 @@ class HUIRoot extends NavigateMixin(
|
||||
window.open("https://www.home-assistant.io/lovelace/", "_blank");
|
||||
}
|
||||
|
||||
_computeEditVisible(editMode, views) {
|
||||
return editMode && views[this._curView];
|
||||
}
|
||||
|
||||
_editModeEnable() {
|
||||
if (this.config._frontendAuto) {
|
||||
showSaveDialog(this, {
|
||||
@ -316,10 +315,18 @@ class HUIRoot extends NavigateMixin(
|
||||
return;
|
||||
}
|
||||
this._editMode = true;
|
||||
if (this.config.views.length < 2) {
|
||||
this.$.view.classList.remove("tabs-hidden");
|
||||
this.fire("iron-resize");
|
||||
}
|
||||
}
|
||||
|
||||
_editModeDisable() {
|
||||
this._editMode = false;
|
||||
if (this.config.views.length < 2) {
|
||||
this.$.view.classList.add("tabs-hidden");
|
||||
this.fire("iron-resize");
|
||||
}
|
||||
}
|
||||
|
||||
_editModeChanged() {
|
||||
@ -345,24 +352,6 @@ class HUIRoot extends NavigateMixin(
|
||||
});
|
||||
}
|
||||
|
||||
_deleteView() {
|
||||
const viewConfig = this.config.views[this._curView];
|
||||
if (viewConfig.cards && viewConfig.cards.length > 0) {
|
||||
alert(
|
||||
"You can't delete a view that has card in them. Remove the cards first."
|
||||
);
|
||||
return;
|
||||
}
|
||||
if (!viewConfig.id) {
|
||||
this._editView();
|
||||
return;
|
||||
}
|
||||
confDeleteView(this.hass, viewConfig.id, () => {
|
||||
this.fire("config-refresh");
|
||||
this._navigateView(0);
|
||||
});
|
||||
}
|
||||
|
||||
_handleViewSelected(ev) {
|
||||
const index = ev.detail.selected;
|
||||
this._navigateView(index);
|
||||
@ -393,6 +382,10 @@ class HUIRoot extends NavigateMixin(
|
||||
view.setConfig(this.config);
|
||||
} else {
|
||||
const viewConfig = this.config.views[this._curView];
|
||||
if (!viewConfig) {
|
||||
this._editModeEnable();
|
||||
return;
|
||||
}
|
||||
if (viewConfig.panel) {
|
||||
view = createCardElement(viewConfig.cards[0]);
|
||||
view.isPanel = true;
|
||||
|
@ -11,7 +11,7 @@ import EventsMixin from "../../mixins/events-mixin";
|
||||
import localizeMixin from "../../mixins/localize-mixin";
|
||||
import createCardElement from "./common/create-card-element";
|
||||
import { computeCardSize } from "./common/compute-card-size";
|
||||
import { showEditCardDialog } from "./editor/hui-dialog-edit-card";
|
||||
import { showEditCardDialog } from "./editor/show-edit-card-dialog";
|
||||
|
||||
class HUIView extends localizeMixin(EventsMixin(PolymerElement)) {
|
||||
static get template() {
|
||||
@ -119,7 +119,7 @@ class HUIView extends localizeMixin(EventsMixin(PolymerElement)) {
|
||||
|
||||
_addCard() {
|
||||
showEditCardDialog(this, {
|
||||
viewId: this.config.id,
|
||||
viewId: "id" in this.config ? String(this.config.id) : undefined,
|
||||
add: true,
|
||||
reloadLovelace: () => {
|
||||
this.fire("config-refresh");
|
||||
|
@ -1,7 +1,6 @@
|
||||
import "@polymer/app-layout/app-toolbar/app-toolbar";
|
||||
import { html } from "@polymer/polymer/lib/utils/html-tag";
|
||||
import { PolymerElement } from "@polymer/polymer/polymer-element";
|
||||
import Leaflet from "leaflet";
|
||||
|
||||
import "../../components/ha-menu-button";
|
||||
import "../../components/ha-icon";
|
||||
@ -11,9 +10,7 @@ import "./ha-entity-marker";
|
||||
import computeStateDomain from "../../common/entity/compute_state_domain";
|
||||
import computeStateName from "../../common/entity/compute_state_name";
|
||||
import LocalizeMixin from "../../mixins/localize-mixin";
|
||||
import setupLeafletMap from "../../common/dom/setup-leaflet-map";
|
||||
|
||||
Leaflet.Icon.Default.imagePath = "/static/images/leaflet";
|
||||
import { setupLeafletMap } from "../../common/dom/setup-leaflet-map";
|
||||
|
||||
/*
|
||||
* @appliesMixin LocalizeMixin
|
||||
@ -61,14 +58,14 @@ class HaPanelMap extends LocalizeMixin(PolymerElement) {
|
||||
|
||||
connectedCallback() {
|
||||
super.connectedCallback();
|
||||
var map = (this._map = setupLeafletMap(this.$.map));
|
||||
this.loadMap();
|
||||
}
|
||||
|
||||
async loadMap() {
|
||||
[this._map, this.Leaflet] = await setupLeafletMap(this.$.map);
|
||||
this.drawEntities(this.hass);
|
||||
|
||||
setTimeout(() => {
|
||||
map.invalidateSize();
|
||||
this.fitMap();
|
||||
}, 1);
|
||||
this._map.invalidateSize();
|
||||
this.fitMap();
|
||||
}
|
||||
|
||||
disconnectedCallback() {
|
||||
@ -82,14 +79,14 @@ class HaPanelMap extends LocalizeMixin(PolymerElement) {
|
||||
|
||||
if (this._mapItems.length === 0) {
|
||||
this._map.setView(
|
||||
new Leaflet.LatLng(
|
||||
new this.Leaflet.LatLng(
|
||||
this.hass.config.latitude,
|
||||
this.hass.config.longitude
|
||||
),
|
||||
14
|
||||
);
|
||||
} else {
|
||||
bounds = new Leaflet.latLngBounds(
|
||||
bounds = new this.Leaflet.latLngBounds(
|
||||
this._mapItems.map((item) => item.getLatLng())
|
||||
);
|
||||
this._map.fitBounds(bounds.pad(0.5));
|
||||
@ -108,7 +105,7 @@ class HaPanelMap extends LocalizeMixin(PolymerElement) {
|
||||
}
|
||||
var mapItems = (this._mapItems = []);
|
||||
|
||||
Object.keys(hass.states).forEach(function(entityId) {
|
||||
Object.keys(hass.states).forEach((entityId) => {
|
||||
var entity = hass.states[entityId];
|
||||
var title = computeStateName(entity);
|
||||
|
||||
@ -137,7 +134,7 @@ class HaPanelMap extends LocalizeMixin(PolymerElement) {
|
||||
iconHTML = title;
|
||||
}
|
||||
|
||||
icon = Leaflet.divIcon({
|
||||
icon = this.Leaflet.divIcon({
|
||||
html: iconHTML,
|
||||
iconSize: [24, 24],
|
||||
className: "",
|
||||
@ -145,7 +142,7 @@ class HaPanelMap extends LocalizeMixin(PolymerElement) {
|
||||
|
||||
// create market with the icon
|
||||
mapItems.push(
|
||||
Leaflet.marker(
|
||||
this.Leaflet.marker(
|
||||
[entity.attributes.latitude, entity.attributes.longitude],
|
||||
{
|
||||
icon: icon,
|
||||
@ -157,7 +154,7 @@ class HaPanelMap extends LocalizeMixin(PolymerElement) {
|
||||
|
||||
// create circle around it
|
||||
mapItems.push(
|
||||
Leaflet.circle(
|
||||
this.Leaflet.circle(
|
||||
[entity.attributes.latitude, entity.attributes.longitude],
|
||||
{
|
||||
interactive: false,
|
||||
@ -181,7 +178,7 @@ class HaPanelMap extends LocalizeMixin(PolymerElement) {
|
||||
.join("");
|
||||
/* Leaflet clones this element before adding it to the map. This messes up
|
||||
our Polymer object and we can't pass data through. Thus we hack like this. */
|
||||
icon = Leaflet.divIcon({
|
||||
icon = this.Leaflet.divIcon({
|
||||
html:
|
||||
"<ha-entity-marker entity-id='" +
|
||||
entity.entity_id +
|
||||
@ -196,7 +193,7 @@ class HaPanelMap extends LocalizeMixin(PolymerElement) {
|
||||
|
||||
// create market with the icon
|
||||
mapItems.push(
|
||||
Leaflet.marker(
|
||||
this.Leaflet.marker(
|
||||
[entity.attributes.latitude, entity.attributes.longitude],
|
||||
{
|
||||
icon: icon,
|
||||
@ -208,7 +205,7 @@ class HaPanelMap extends LocalizeMixin(PolymerElement) {
|
||||
// create circle around if entity has accuracy
|
||||
if (entity.attributes.gps_accuracy) {
|
||||
mapItems.push(
|
||||
Leaflet.circle(
|
||||
this.Leaflet.circle(
|
||||
[entity.attributes.latitude, entity.attributes.longitude],
|
||||
{
|
||||
interactive: false,
|
||||
|
@ -1,8 +1,12 @@
|
||||
import { html } from "@polymer/lit-element";
|
||||
import "./jquery";
|
||||
// jQuery import should come before plugin import
|
||||
import { jQuery as jQuery_ } from "./jquery";
|
||||
import "round-slider";
|
||||
// eslint-disable-next-line
|
||||
import roundSliderCSS from "round-slider/dist/roundslider.min.css";
|
||||
|
||||
export const jQuery = jQuery_;
|
||||
|
||||
export const roundSliderStyle = html`
|
||||
<style>
|
||||
${roundSliderCSS}
|
||||
|
15
src/resources/jquery.roundslider.ondemand.ts
Normal file
15
src/resources/jquery.roundslider.ondemand.ts
Normal file
@ -0,0 +1,15 @@
|
||||
import { TemplateResult } from "lit-html";
|
||||
|
||||
type LoadedRoundSlider = Promise<{
|
||||
roundSliderStyle: TemplateResult;
|
||||
jQuery: any;
|
||||
}>;
|
||||
|
||||
let loaded: LoadedRoundSlider;
|
||||
|
||||
export const loadRoundslider = async (): LoadedRoundSlider => {
|
||||
if (!loaded) {
|
||||
loaded = import(/* webpackChunkName: "jquery-roundslider" */ "./jquery.roundslider");
|
||||
}
|
||||
return loaded;
|
||||
};
|
@ -16,6 +16,7 @@ if (!version) {
|
||||
}
|
||||
const VERSION = version[0];
|
||||
const isCI = process.env.CI === "true";
|
||||
const isStatsBuild = process.env.STATS === "1";
|
||||
|
||||
const generateJSPage = (entrypoint, latestBuild) => {
|
||||
return new HtmlWebpackPlugin({
|
||||
@ -51,10 +52,6 @@ function createConfig(isProdBuild, latestBuild) {
|
||||
entry["service-worker-hass"] = "./src/entrypoints/service-worker-hass.js";
|
||||
}
|
||||
|
||||
const chunkFilename = isProdBuild
|
||||
? "[chunkhash].chunk.js"
|
||||
: "[name].chunk.js";
|
||||
|
||||
return {
|
||||
mode: isProdBuild ? "production" : "development",
|
||||
devtool: isProdBuild
|
||||
@ -161,6 +158,7 @@ function createConfig(isProdBuild, latestBuild) {
|
||||
),
|
||||
isProdBuild &&
|
||||
!isCI &&
|
||||
!isStatsBuild &&
|
||||
new CompressionPlugin({
|
||||
cache: true,
|
||||
exclude: [/\.js\.map$/, /\.LICENSE$/, /\.py$/, /\.txt$/],
|
||||
@ -223,7 +221,10 @@ function createConfig(isProdBuild, latestBuild) {
|
||||
if (!isProdBuild || dontHash.has(chunk.name)) return `${chunk.name}.js`;
|
||||
return `${chunk.name}-${chunk.hash.substr(0, 8)}.js`;
|
||||
},
|
||||
chunkFilename: chunkFilename,
|
||||
chunkFilename:
|
||||
isProdBuild && !isStatsBuild
|
||||
? "[chunkhash].chunk.js"
|
||||
: "[name].chunk.js",
|
||||
path: path.resolve(__dirname, buildPath),
|
||||
publicPath,
|
||||
},
|
||||
@ -243,7 +244,7 @@ function createConfig(isProdBuild, latestBuild) {
|
||||
|
||||
const isProdBuild = process.env.NODE_ENV === "production";
|
||||
const configs = [createConfig(isProdBuild, /* latestBuild */ true)];
|
||||
if (isProdBuild) {
|
||||
if (isProdBuild && !isStatsBuild) {
|
||||
configs.push(createConfig(isProdBuild, /* latestBuild */ false));
|
||||
}
|
||||
module.exports = configs;
|
||||
|
Loading…
x
Reference in New Issue
Block a user