mirror of
https://github.com/home-assistant/frontend.git
synced 2025-08-02 05:57:54 +00:00
commit
16c9303ae9
BIN
demo/public/assets/teachingbirds/plants.png
Normal file
BIN
demo/public/assets/teachingbirds/plants.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 46 KiB |
@ -7,6 +7,32 @@
|
|||||||
content="width=device-width, initial-scale=1, shrink-to-fit=no"
|
content="width=device-width, initial-scale=1, shrink-to-fit=no"
|
||||||
/>
|
/>
|
||||||
<meta name="theme-color" content="#2157BC" />
|
<meta name="theme-color" content="#2157BC" />
|
||||||
|
<meta property="fb:app_id" content="338291289691179" />
|
||||||
|
<meta property="og:title" content="Home Assistant Demo" />
|
||||||
|
<meta property="og:site_name" content="Home Assistant" />
|
||||||
|
<meta property="og:url" content="https://demo.home-assistant.io/" />
|
||||||
|
<meta property="og:type" content="website" />
|
||||||
|
<meta
|
||||||
|
property="og:description"
|
||||||
|
content="Open source home automation that puts local control and privacy first."
|
||||||
|
/>
|
||||||
|
<meta
|
||||||
|
property="og:image"
|
||||||
|
content="https://www.home-assistant.io/images/default-social.png"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<meta name="twitter:card" content="summary_large_image" />
|
||||||
|
<meta name="twitter:site" content="@home_assistant" />
|
||||||
|
|
||||||
|
<meta name="twitter:title" content="Home Assistant" />
|
||||||
|
<meta
|
||||||
|
name="twitter:description"
|
||||||
|
content="Open source home automation that puts local control and privacy first."
|
||||||
|
/>
|
||||||
|
<meta
|
||||||
|
name="twitter:image"
|
||||||
|
content="https://www.home-assistant.io/images/default-social.png"
|
||||||
|
/>
|
||||||
<title>Home Assistant Demo</title>
|
<title>Home Assistant Demo</title>
|
||||||
<script src="./custom-elements-es5-adapter.js"></script>
|
<script src="./custom-elements-es5-adapter.js"></script>
|
||||||
<script src="./compatibility.js"></script>
|
<script src="./compatibility.js"></script>
|
||||||
|
@ -18,9 +18,12 @@ export const setDemoConfig = async (
|
|||||||
lovelace: Lovelace,
|
lovelace: Lovelace,
|
||||||
index: number
|
index: number
|
||||||
) => {
|
) => {
|
||||||
|
const confProm = demoConfigs[index]();
|
||||||
|
const config = await confProm;
|
||||||
|
|
||||||
selectedDemoConfigIndex = index;
|
selectedDemoConfigIndex = index;
|
||||||
selectedDemoConfig = demoConfigs[index]();
|
selectedDemoConfig = confProm;
|
||||||
const config = await selectedDemoConfig;
|
|
||||||
hass.addEntities(config.entities(), true);
|
hass.addEntities(config.entities(), true);
|
||||||
lovelace.saveConfig(config.lovelace());
|
lovelace.saveConfig(config.lovelace());
|
||||||
hass.mockTheme(config.theme());
|
hass.mockTheme(config.theme());
|
||||||
|
@ -352,9 +352,18 @@ export const demoLovelaceKernehed: () => LovelaceConfig = () => ({
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
entities: [
|
entities: [
|
||||||
"sensor.pi_hole_dns_queries_today",
|
{
|
||||||
"sensor.pi_hole_ads_blocked_today",
|
entity: "sensor.pi_hole_dns_queries_today",
|
||||||
"sensor.pi_hole_dns_unique_clients",
|
name: "DNS Queries Today",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
entity: "sensor.pi_hole_ads_blocked_today",
|
||||||
|
name: "Ads Blocked Today",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
entity: "sensor.pi_hole_dns_unique_clients",
|
||||||
|
name: "DNS Unique Clients",
|
||||||
|
},
|
||||||
],
|
],
|
||||||
show_header_toggle: false,
|
show_header_toggle: false,
|
||||||
type: "entities",
|
type: "entities",
|
||||||
@ -369,16 +378,16 @@ export const demoLovelaceKernehed: () => LovelaceConfig = () => ({
|
|||||||
"binary_sensor.windows_server",
|
"binary_sensor.windows_server",
|
||||||
"binary_sensor.teamspeak",
|
"binary_sensor.teamspeak",
|
||||||
"binary_sensor.harmony_hub",
|
"binary_sensor.harmony_hub",
|
||||||
{
|
// {
|
||||||
style: {
|
// style: {
|
||||||
height: "1px",
|
// height: "1px",
|
||||||
width: "85%",
|
// width: "85%",
|
||||||
"margin-left": "auto",
|
// "margin-left": "auto",
|
||||||
background: "#62717b",
|
// background: "#62717b",
|
||||||
"margin-right": "auto",
|
// "margin-right": "auto",
|
||||||
},
|
// },
|
||||||
type: "divider",
|
// type: "divider",
|
||||||
},
|
// },
|
||||||
// {
|
// {
|
||||||
// items: ["sensor.uptime_router", "sensor.installerad_routeros"],
|
// items: ["sensor.uptime_router", "sensor.installerad_routeros"],
|
||||||
// head: {
|
// head: {
|
||||||
|
@ -1239,7 +1239,7 @@ export const demoEntitiesTeachingbirds: () => Entity[] = () =>
|
|||||||
},
|
},
|
||||||
"sensor.herbs_moisture": {
|
"sensor.herbs_moisture": {
|
||||||
entity_id: "sensor.herbs_moisture",
|
entity_id: "sensor.herbs_moisture",
|
||||||
state: "unknown",
|
state: "39",
|
||||||
attributes: {
|
attributes: {
|
||||||
unit_of_measurement: "%",
|
unit_of_measurement: "%",
|
||||||
friendly_name: "Herbs moisture",
|
friendly_name: "Herbs moisture",
|
||||||
@ -1448,7 +1448,7 @@ export const demoEntitiesTeachingbirds: () => Entity[] = () =>
|
|||||||
},
|
},
|
||||||
"sensor.big_chili_moisture": {
|
"sensor.big_chili_moisture": {
|
||||||
entity_id: "sensor.big_chili_moisture",
|
entity_id: "sensor.big_chili_moisture",
|
||||||
state: "0",
|
state: "36",
|
||||||
attributes: {
|
attributes: {
|
||||||
unit_of_measurement: "%",
|
unit_of_measurement: "%",
|
||||||
friendly_name: "Big chili moisture",
|
friendly_name: "Big chili moisture",
|
||||||
@ -1497,7 +1497,7 @@ export const demoEntitiesTeachingbirds: () => Entity[] = () =>
|
|||||||
},
|
},
|
||||||
"sensor.small_chili_moisture": {
|
"sensor.small_chili_moisture": {
|
||||||
entity_id: "sensor.small_chili_moisture",
|
entity_id: "sensor.small_chili_moisture",
|
||||||
state: "unknown",
|
state: "34",
|
||||||
attributes: {
|
attributes: {
|
||||||
unit_of_measurement: "%",
|
unit_of_measurement: "%",
|
||||||
friendly_name: "Small chili moisture",
|
friendly_name: "Small chili moisture",
|
||||||
|
@ -231,62 +231,62 @@ export const demoLovelaceTeachingbirds: () => LovelaceConfig = () => ({
|
|||||||
cards: [
|
cards: [
|
||||||
{
|
{
|
||||||
cards: [
|
cards: [
|
||||||
{
|
// {
|
||||||
entities: [
|
// entities: [
|
||||||
{
|
// {
|
||||||
name: "Front door lock",
|
// name: "Front door lock",
|
||||||
entity: "sensor.front_door_lock",
|
// entity: "sensor.front_door_lock",
|
||||||
},
|
// },
|
||||||
{
|
// {
|
||||||
name: "Yard door lock",
|
// name: "Yard door lock",
|
||||||
entity: "sensor.yard_door_lock",
|
// entity: "sensor.yard_door_lock",
|
||||||
},
|
// },
|
||||||
"sensor.front_door",
|
// "sensor.front_door",
|
||||||
"sensor.back_door",
|
// "sensor.back_door",
|
||||||
"sensor.backyard_door",
|
// "sensor.backyard_door",
|
||||||
"sensor.balcony_door",
|
// "sensor.balcony_door",
|
||||||
"sensor.yard_door",
|
// "sensor.yard_door",
|
||||||
{
|
// {
|
||||||
name: "Dining area",
|
// name: "Dining area",
|
||||||
entity: "sensor.dining_area_window",
|
// entity: "sensor.dining_area_window",
|
||||||
},
|
// },
|
||||||
{
|
// {
|
||||||
name: "Bedroom",
|
// name: "Bedroom",
|
||||||
entity: "sensor.bedroom_window",
|
// entity: "sensor.bedroom_window",
|
||||||
},
|
// },
|
||||||
{
|
// {
|
||||||
name: "Ring motion",
|
// name: "Ring motion",
|
||||||
entity: "sensor.front_door_outdoor_movement",
|
// entity: "sensor.front_door_outdoor_movement",
|
||||||
},
|
// },
|
||||||
"sensor.hallway_movement",
|
// "sensor.hallway_movement",
|
||||||
"sensor.passage_movement",
|
// "sensor.passage_movement",
|
||||||
"sensor.upstairs_hallway_movement",
|
// "sensor.upstairs_hallway_movement",
|
||||||
"sensor.living_room_movement",
|
// "sensor.living_room_movement",
|
||||||
"sensor.back_door_camera_movement",
|
// "sensor.back_door_camera_movement",
|
||||||
{
|
// {
|
||||||
name: "Storage door",
|
// name: "Storage door",
|
||||||
entity: "sensor.yard_storage_door",
|
// entity: "sensor.yard_storage_door",
|
||||||
},
|
// },
|
||||||
"sensor.water_heater",
|
// "sensor.water_heater",
|
||||||
"sensor.kitchen_sink",
|
// "sensor.kitchen_sink",
|
||||||
"binary_sensor.smoke_sensor_158d0001d37bdd",
|
// "binary_sensor.smoke_sensor_158d0001d37bdd",
|
||||||
"binary_sensor.smoke_sensor_158d0001d37be5",
|
// "binary_sensor.smoke_sensor_158d0001d37be5",
|
||||||
"binary_sensor.smoke_sensor_158d0001d37c82",
|
// "binary_sensor.smoke_sensor_158d0001d37c82",
|
||||||
],
|
// ],
|
||||||
show_empty: false,
|
// show_empty: false,
|
||||||
type: "entity-filter",
|
// type: "entity-filter",
|
||||||
card: {
|
// card: {
|
||||||
type: "glance",
|
// type: "glance",
|
||||||
show_state: false,
|
// show_state: false,
|
||||||
},
|
// },
|
||||||
state_filter: [
|
// state_filter: [
|
||||||
"Open",
|
// "Open",
|
||||||
"Movement detected",
|
// "Movement detected",
|
||||||
"Leaking",
|
// "Leaking",
|
||||||
"Unlocked",
|
// "Unlocked",
|
||||||
"on",
|
// "on",
|
||||||
],
|
// ],
|
||||||
},
|
// },
|
||||||
{
|
{
|
||||||
entities: [
|
entities: [
|
||||||
"light.outdoor_lights",
|
"light.outdoor_lights",
|
||||||
@ -384,6 +384,48 @@ export const demoLovelaceTeachingbirds: () => LovelaceConfig = () => ({
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
cards: [
|
cards: [
|
||||||
|
{
|
||||||
|
image: "/assets/teachingbirds/plants.png",
|
||||||
|
elements: [
|
||||||
|
{
|
||||||
|
style: {
|
||||||
|
top: "30%",
|
||||||
|
"--ha-label-badge-font-size": "1em",
|
||||||
|
left: "10%",
|
||||||
|
},
|
||||||
|
type: "state-badge",
|
||||||
|
entity: "sensor.small_chili_moisture",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
style: {
|
||||||
|
top: "30%",
|
||||||
|
"--ha-label-badge-font-size": "1em",
|
||||||
|
left: "25%",
|
||||||
|
},
|
||||||
|
type: "state-badge",
|
||||||
|
entity: "sensor.big_chili_moisture",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
style: {
|
||||||
|
top: "30%",
|
||||||
|
"--ha-label-badge-font-size": "1em",
|
||||||
|
left: "40%",
|
||||||
|
},
|
||||||
|
type: "state-badge",
|
||||||
|
entity: "sensor.herbs_moisture",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
style: {
|
||||||
|
top: "12%",
|
||||||
|
"--ha-label-badge-font-size": "1em",
|
||||||
|
left: "92%",
|
||||||
|
},
|
||||||
|
type: "state-label",
|
||||||
|
entity: "sensor.greenhouse_temperature",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
type: "picture-elements",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
// show_name: false,
|
// show_name: false,
|
||||||
// entity: "camera.stockholm_meteogram",
|
// entity: "camera.stockholm_meteogram",
|
||||||
@ -676,6 +718,7 @@ export const demoLovelaceTeachingbirds: () => LovelaceConfig = () => ({
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
title: "Home info",
|
title: "Home info",
|
||||||
|
path: "home_info",
|
||||||
icon: "mdi:home-heart",
|
icon: "mdi:home-heart",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -6,6 +6,7 @@ export const demoThemeTeachingbirds = () => ({
|
|||||||
"paper-item-icon-color": "#d3d3d3",
|
"paper-item-icon-color": "#d3d3d3",
|
||||||
"divider-color": "rgba(255, 255, 255, 0.12)",
|
"divider-color": "rgba(255, 255, 255, 0.12)",
|
||||||
"primary-color": "#389638",
|
"primary-color": "#389638",
|
||||||
|
"light-primary-color": "#6f956f",
|
||||||
"label-badge-red": "var(--primary-color)",
|
"label-badge-red": "var(--primary-color)",
|
||||||
"paper-slider-secondary-color": "var(--light-primary-color)",
|
"paper-slider-secondary-color": "var(--light-primary-color)",
|
||||||
"paper-slider-knob-color": "var(--primary-color)",
|
"paper-slider-knob-color": "var(--primary-color)",
|
||||||
|
@ -1,6 +1,14 @@
|
|||||||
import { LitElement, html, CSSResult, css } from "lit-element";
|
import {
|
||||||
|
LitElement,
|
||||||
|
html,
|
||||||
|
CSSResult,
|
||||||
|
css,
|
||||||
|
PropertyDeclarations,
|
||||||
|
} from "lit-element";
|
||||||
import { until } from "lit-html/directives/until";
|
import { until } from "lit-html/directives/until";
|
||||||
import "@polymer/paper-icon-button";
|
import "@polymer/paper-icon-button";
|
||||||
|
import "@polymer/paper-button";
|
||||||
|
import "@polymer/paper-spinner/paper-spinner-lite";
|
||||||
import "../../../src/components/ha-card";
|
import "../../../src/components/ha-card";
|
||||||
import { LovelaceCard, Lovelace } from "../../../src/panels/lovelace/types";
|
import { LovelaceCard, Lovelace } from "../../../src/panels/lovelace/types";
|
||||||
import { LovelaceCardConfig } from "../../../src/data/lovelace";
|
import { LovelaceCardConfig } from "../../../src/data/lovelace";
|
||||||
@ -15,6 +23,15 @@ import {
|
|||||||
export class HADemoCard extends LitElement implements LovelaceCard {
|
export class HADemoCard extends LitElement implements LovelaceCard {
|
||||||
public lovelace?: Lovelace;
|
public lovelace?: Lovelace;
|
||||||
public hass?: MockHomeAssistant;
|
public hass?: MockHomeAssistant;
|
||||||
|
private _switching?: boolean;
|
||||||
|
|
||||||
|
static get properties(): PropertyDeclarations {
|
||||||
|
return {
|
||||||
|
lovelace: {},
|
||||||
|
hass: {},
|
||||||
|
_switching: {},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
public getCardSize() {
|
public getCardSize() {
|
||||||
return 2;
|
return 2;
|
||||||
@ -28,36 +45,51 @@ export class HADemoCard extends LitElement implements LovelaceCard {
|
|||||||
|
|
||||||
protected render() {
|
protected render() {
|
||||||
return html`
|
return html`
|
||||||
<ha-card header="Home Assistant Demo Switcher">
|
<ha-card>
|
||||||
<div class="picker">
|
<div class="picker">
|
||||||
<paper-icon-button
|
<paper-icon-button
|
||||||
@click=${this._prevConfig}
|
@click=${this._prevConfig}
|
||||||
icon="hass:chevron-right"
|
icon="hass:chevron-right"
|
||||||
style="transform: rotate(180deg)"
|
style="transform: rotate(180deg)"
|
||||||
|
.disabled=${this._switching}
|
||||||
></paper-icon-button>
|
></paper-icon-button>
|
||||||
<div>
|
<div>
|
||||||
${
|
${
|
||||||
until(
|
this._switching
|
||||||
selectedDemoConfig.then(
|
? html`
|
||||||
(conf) => html`
|
<paper-spinner-lite active></paper-spinner-lite>
|
||||||
${conf.name}
|
|
||||||
<small>
|
|
||||||
by
|
|
||||||
<a target="_blank" href="${conf.authorUrl}">
|
|
||||||
${conf.authorName}
|
|
||||||
</a>
|
|
||||||
</small>
|
|
||||||
`
|
`
|
||||||
),
|
: until(
|
||||||
""
|
selectedDemoConfig.then(
|
||||||
)
|
(conf) => html`
|
||||||
|
${conf.name}
|
||||||
|
<small>
|
||||||
|
by
|
||||||
|
<a target="_blank" href="${conf.authorUrl}">
|
||||||
|
${conf.authorName}
|
||||||
|
</a>
|
||||||
|
</small>
|
||||||
|
`
|
||||||
|
),
|
||||||
|
""
|
||||||
|
)
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
<paper-icon-button
|
<paper-icon-button
|
||||||
@click=${this._nextConfig}
|
@click=${this._nextConfig}
|
||||||
icon="hass:chevron-right"
|
icon="hass:chevron-right"
|
||||||
|
.disabled=${this._switching}
|
||||||
></paper-icon-button>
|
></paper-icon-button>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="content">
|
||||||
|
Welcome home! You've reached the Home Assistant demo where we showcase
|
||||||
|
the best UIs created by our community.
|
||||||
|
</div>
|
||||||
|
<div class="actions">
|
||||||
|
<a href="https://www.home-assistant.io" target="_blank">
|
||||||
|
<paper-button>Learn more about Home Assistant</paper-button>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
</ha-card>
|
</ha-card>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
@ -78,39 +110,28 @@ export class HADemoCard extends LitElement implements LovelaceCard {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private _updateConfig(index: number) {
|
private async _updateConfig(index: number) {
|
||||||
setDemoConfig(this.hass!, this.lovelace!, index);
|
this._switching = true;
|
||||||
|
try {
|
||||||
|
await setDemoConfig(this.hass!, this.lovelace!, index);
|
||||||
|
} catch (err) {
|
||||||
|
alert("Failed to switch config :-(");
|
||||||
|
} finally {
|
||||||
|
this._switching = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static get styles(): CSSResult[] {
|
static get styles(): CSSResult[] {
|
||||||
return [
|
return [
|
||||||
css`
|
css`
|
||||||
.content {
|
|
||||||
padding: 0 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
ul {
|
|
||||||
margin-top: 0;
|
|
||||||
margin-bottom: 0;
|
|
||||||
padding: 16px 16px 16px 38px;
|
|
||||||
}
|
|
||||||
|
|
||||||
li {
|
|
||||||
padding: 8px 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
li:first-child {
|
|
||||||
margin-top: -8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
li:last-child {
|
|
||||||
margin-bottom: -8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
a {
|
a {
|
||||||
color: var(--primary-color);
|
color: var(--primary-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.content {
|
||||||
|
padding: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
.picker {
|
.picker {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
@ -125,6 +146,15 @@ export class HADemoCard extends LitElement implements LovelaceCard {
|
|||||||
.picker small {
|
.picker small {
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.actions {
|
||||||
|
padding-left: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.actions paper-button {
|
||||||
|
color: var(--primary-color);
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
`,
|
`,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,10 @@ class HaDemo extends HomeAssistant {
|
|||||||
protected async _handleConnProm() {
|
protected async _handleConnProm() {
|
||||||
const initial: Partial<HomeAssistant> = {
|
const initial: Partial<HomeAssistant> = {
|
||||||
panelUrl: (this as any).panelUrl,
|
panelUrl: (this as any).panelUrl,
|
||||||
|
// Override updateHass so that the correct hass lifecycle methods are called
|
||||||
|
updateHass: (hassUpdate) =>
|
||||||
|
// @ts-ignore
|
||||||
|
this._updateHass(hassUpdate),
|
||||||
};
|
};
|
||||||
|
|
||||||
const hass = provideHass(this, initial);
|
const hass = provideHass(this, initial);
|
||||||
|
2
setup.py
2
setup.py
@ -2,7 +2,7 @@ from setuptools import setup, find_packages
|
|||||||
|
|
||||||
setup(
|
setup(
|
||||||
name="home-assistant-frontend",
|
name="home-assistant-frontend",
|
||||||
version="20190120.0",
|
version="20190121.0",
|
||||||
description="The Home Assistant frontend",
|
description="The Home Assistant frontend",
|
||||||
url="https://github.com/home-assistant/home-assistant-polymer",
|
url="https://github.com/home-assistant/home-assistant-polymer",
|
||||||
author="The Home Assistant Authors",
|
author="The Home Assistant Authors",
|
||||||
|
@ -45,15 +45,8 @@ export const provideHass = (
|
|||||||
} = {};
|
} = {};
|
||||||
const entities = {};
|
const entities = {};
|
||||||
|
|
||||||
function updateHass(obj: Partial<MockHomeAssistant>) {
|
|
||||||
const newHass = { ...hass(), ...obj };
|
|
||||||
elements.forEach((el) => {
|
|
||||||
el.hass = newHass;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateStates(newStates: HassEntities) {
|
function updateStates(newStates: HassEntities) {
|
||||||
updateHass({
|
hass().updateHass({
|
||||||
states: { ...hass().states, ...newStates },
|
states: { ...hass().states, ...newStates },
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -66,7 +59,7 @@ export const provideHass = (
|
|||||||
states[ent.entityId] = ent.toState();
|
states[ent.entityId] = ent.toState();
|
||||||
});
|
});
|
||||||
if (replace) {
|
if (replace) {
|
||||||
updateHass({
|
hass().updateHass({
|
||||||
states,
|
states,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
@ -93,7 +86,7 @@ export const provideHass = (
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
updateHass({
|
const hassObj: MockHomeAssistant = {
|
||||||
// Home Assistant properties
|
// Home Assistant properties
|
||||||
auth: {} as any,
|
auth: {} as any,
|
||||||
connection: {
|
connection: {
|
||||||
@ -141,11 +134,11 @@ export const provideHass = (
|
|||||||
panelUrl: "lovelace",
|
panelUrl: "lovelace",
|
||||||
|
|
||||||
language: getActiveTranslation(),
|
language: getActiveTranslation(),
|
||||||
resources: null,
|
resources: null as any,
|
||||||
|
|
||||||
translationMetadata,
|
translationMetadata: translationMetadata as any,
|
||||||
dockedSidebar: false,
|
dockedSidebar: false,
|
||||||
moreInfoEntityId: null,
|
moreInfoEntityId: null as any,
|
||||||
async callService(domain, service, data) {
|
async callService(domain, service, data) {
|
||||||
fireEvent(elements[0], "hass-notification", {
|
fireEvent(elements[0], "hass-notification", {
|
||||||
message: `Called service ${domain}/${service}`,
|
message: `Called service ${domain}/${service}`,
|
||||||
@ -197,7 +190,12 @@ export const provideHass = (
|
|||||||
|
|
||||||
// Mock stuff
|
// Mock stuff
|
||||||
mockEntities: entities,
|
mockEntities: entities,
|
||||||
updateHass,
|
updateHass(obj: Partial<MockHomeAssistant>) {
|
||||||
|
const newHass = { ...hass(), ...obj };
|
||||||
|
elements.forEach((el) => {
|
||||||
|
el.hass = newHass;
|
||||||
|
});
|
||||||
|
},
|
||||||
updateStates,
|
updateStates,
|
||||||
addEntities,
|
addEntities,
|
||||||
mockWS(type, callback) {
|
mockWS(type, callback) {
|
||||||
@ -208,7 +206,7 @@ export const provideHass = (
|
|||||||
(eventListeners[event] || []).forEach((fn) => fn(event));
|
(eventListeners[event] || []).forEach((fn) => fn(event));
|
||||||
},
|
},
|
||||||
mockTheme(theme) {
|
mockTheme(theme) {
|
||||||
updateHass({
|
hass().updateHass({
|
||||||
selectedTheme: theme ? "mock" : "default",
|
selectedTheme: theme ? "mock" : "default",
|
||||||
themes: {
|
themes: {
|
||||||
...hass().themes,
|
...hass().themes,
|
||||||
@ -217,15 +215,22 @@ export const provideHass = (
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
const hassObj = hass();
|
const { themes, selectedTheme } = hass();
|
||||||
elements.forEach((el) => {
|
applyThemesOnElement(
|
||||||
applyThemesOnElement(el, hassObj.themes, hassObj.selectedTheme, true);
|
document.documentElement,
|
||||||
});
|
themes,
|
||||||
|
selectedTheme,
|
||||||
|
true
|
||||||
|
);
|
||||||
},
|
},
|
||||||
|
|
||||||
...overrideData,
|
...overrideData,
|
||||||
} as MockHomeAssistant);
|
};
|
||||||
|
|
||||||
|
// Update the elements. Note, we call it on hassObj so that if it was
|
||||||
|
// overridden (like in the demo), it will still work.
|
||||||
|
hassObj.updateHass(hassObj);
|
||||||
|
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
return hass();
|
return hassObj;
|
||||||
};
|
};
|
||||||
|
@ -47,14 +47,16 @@ export class HomeAssistant extends ext(PolymerElement, [
|
|||||||
use-hash-as-path="[[_useHashAsPath]]"
|
use-hash-as-path="[[_useHashAsPath]]"
|
||||||
></app-location>
|
></app-location>
|
||||||
<app-route
|
<app-route
|
||||||
route="{{route}}"
|
route="[[route]]"
|
||||||
pattern="/:panel"
|
pattern="/:panel"
|
||||||
data="{{routeData}}"
|
data="{{routeData}}"
|
||||||
|
tail="{{subroute}}"
|
||||||
></app-route>
|
></app-route>
|
||||||
<template is="dom-if" if="[[showMain]]" restamp>
|
<template is="dom-if" if="[[showMain]]" restamp>
|
||||||
<home-assistant-main
|
<home-assistant-main
|
||||||
hass="[[hass]]"
|
hass="[[hass]]"
|
||||||
route="{{route}}"
|
route="[[route]]"
|
||||||
|
tail="[[subroute]]"
|
||||||
></home-assistant-main>
|
></home-assistant-main>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -81,6 +81,9 @@ class HomeAssistantMain extends NavigateMixin(EventsMixin(PolymerElement)) {
|
|||||||
return {
|
return {
|
||||||
hass: Object,
|
hass: Object,
|
||||||
narrow: Boolean,
|
narrow: Boolean,
|
||||||
|
tail: {
|
||||||
|
type: Object,
|
||||||
|
},
|
||||||
route: {
|
route: {
|
||||||
type: Object,
|
type: Object,
|
||||||
observer: "_routeChanged",
|
observer: "_routeChanged",
|
||||||
@ -135,7 +138,7 @@ class HomeAssistantMain extends NavigateMixin(EventsMixin(PolymerElement)) {
|
|||||||
|
|
||||||
connectedCallback() {
|
connectedCallback() {
|
||||||
super.connectedCallback();
|
super.connectedCallback();
|
||||||
if (this.route.prefix === "") {
|
if (this.tail.prefix === "") {
|
||||||
this.navigate(`/${localStorage.defaultPage || DEFAULT_PANEL}`, true);
|
this.navigate(`/${localStorage.defaultPage || DEFAULT_PANEL}`, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,246 +0,0 @@
|
|||||||
import "@polymer/app-route/app-route";
|
|
||||||
import { dom } from "@polymer/polymer/lib/legacy/polymer.dom";
|
|
||||||
import { html } from "@polymer/polymer/lib/utils/html-tag";
|
|
||||||
import { PolymerElement } from "@polymer/polymer/polymer-element";
|
|
||||||
|
|
||||||
import "./hass-loading-screen";
|
|
||||||
import "./hass-error-screen";
|
|
||||||
import { importHref } from "../resources/html-import/import-href";
|
|
||||||
|
|
||||||
import dynamicContentUpdater from "../common/dom/dynamic_content_updater";
|
|
||||||
import NavigateMixin from "../mixins/navigate-mixin";
|
|
||||||
|
|
||||||
const loaded = {};
|
|
||||||
|
|
||||||
function ensureLoaded(panel) {
|
|
||||||
if (panel in loaded) return loaded[panel];
|
|
||||||
|
|
||||||
let imported;
|
|
||||||
// Name each panel we support here, that way Webpack knows about it.
|
|
||||||
switch (panel) {
|
|
||||||
case "config":
|
|
||||||
imported = import(/* webpackChunkName: "panel-config" */ "../panels/config/ha-panel-config");
|
|
||||||
break;
|
|
||||||
|
|
||||||
case "custom":
|
|
||||||
imported = import(/* webpackChunkName: "panel-custom" */ "../panels/custom/ha-panel-custom");
|
|
||||||
break;
|
|
||||||
|
|
||||||
case "dev-event":
|
|
||||||
imported = import(/* webpackChunkName: "panel-dev-event" */ "../panels/dev-event/ha-panel-dev-event");
|
|
||||||
break;
|
|
||||||
|
|
||||||
case "dev-info":
|
|
||||||
imported = import(/* webpackChunkName: "panel-dev-info" */ "../panels/dev-info/ha-panel-dev-info");
|
|
||||||
break;
|
|
||||||
|
|
||||||
case "dev-mqtt":
|
|
||||||
imported = import(/* webpackChunkName: "panel-dev-mqtt" */ "../panels/dev-mqtt/ha-panel-dev-mqtt");
|
|
||||||
break;
|
|
||||||
|
|
||||||
case "dev-service":
|
|
||||||
imported = import(/* webpackChunkName: "panel-dev-service" */ "../panels/dev-service/ha-panel-dev-service");
|
|
||||||
break;
|
|
||||||
|
|
||||||
case "dev-state":
|
|
||||||
imported = import(/* webpackChunkName: "panel-dev-state" */ "../panels/dev-state/ha-panel-dev-state");
|
|
||||||
break;
|
|
||||||
|
|
||||||
case "dev-template":
|
|
||||||
imported = import(/* webpackChunkName: "panel-dev-template" */ "../panels/dev-template/ha-panel-dev-template");
|
|
||||||
break;
|
|
||||||
|
|
||||||
case "lovelace":
|
|
||||||
imported = import(/* webpackChunkName: "panel-lovelace" */ "../panels/lovelace/ha-panel-lovelace");
|
|
||||||
break;
|
|
||||||
|
|
||||||
case "states":
|
|
||||||
imported = import(/* webpackChunkName: "panel-states" */ "../panels/states/ha-panel-states");
|
|
||||||
break;
|
|
||||||
|
|
||||||
case "history":
|
|
||||||
imported = import(/* webpackChunkName: "panel-history" */ "../panels/history/ha-panel-history");
|
|
||||||
break;
|
|
||||||
|
|
||||||
case "iframe":
|
|
||||||
imported = import(/* webpackChunkName: "panel-iframe" */ "../panels/iframe/ha-panel-iframe");
|
|
||||||
break;
|
|
||||||
|
|
||||||
case "kiosk":
|
|
||||||
imported = import(/* webpackChunkName: "panel-kiosk" */ "../panels/kiosk/ha-panel-kiosk");
|
|
||||||
break;
|
|
||||||
|
|
||||||
case "logbook":
|
|
||||||
imported = import(/* webpackChunkName: "panel-logbook" */ "../panels/logbook/ha-panel-logbook");
|
|
||||||
break;
|
|
||||||
|
|
||||||
case "mailbox":
|
|
||||||
imported = import(/* webpackChunkName: "panel-mailbox" */ "../panels/mailbox/ha-panel-mailbox");
|
|
||||||
break;
|
|
||||||
|
|
||||||
case "map":
|
|
||||||
imported = import(/* webpackChunkName: "panel-map" */ "../panels/map/ha-panel-map");
|
|
||||||
break;
|
|
||||||
|
|
||||||
case "profile":
|
|
||||||
imported = import(/* webpackChunkName: "panel-profile" */ "../panels/profile/ha-panel-profile");
|
|
||||||
break;
|
|
||||||
|
|
||||||
case "shopping-list":
|
|
||||||
imported = import(/* webpackChunkName: "panel-shopping-list" */ "../panels/shopping-list/ha-panel-shopping-list");
|
|
||||||
break;
|
|
||||||
|
|
||||||
case "calendar":
|
|
||||||
imported = import(/* webpackChunkName: "panel-calendar" */ "../panels/calendar/ha-panel-calendar");
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
imported = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (imported != null) {
|
|
||||||
loaded[panel] = imported;
|
|
||||||
}
|
|
||||||
|
|
||||||
return imported;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* @appliesMixin NavigateMixin
|
|
||||||
*/
|
|
||||||
class PartialPanelResolver extends NavigateMixin(PolymerElement) {
|
|
||||||
static get template() {
|
|
||||||
return html`
|
|
||||||
<style>
|
|
||||||
[hidden] {
|
|
||||||
display: none !important;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
<app-route
|
|
||||||
route="{{route}}"
|
|
||||||
pattern="/:panel"
|
|
||||||
data="{{routeData}}"
|
|
||||||
tail="{{routeTail}}"
|
|
||||||
></app-route>
|
|
||||||
|
|
||||||
<template is="dom-if" if="[[_equal(_state, 'loading')]]">
|
|
||||||
<hass-loading-screen
|
|
||||||
narrow="[[narrow]]"
|
|
||||||
show-menu="[[showMenu]]"
|
|
||||||
></hass-loading-screen>
|
|
||||||
</template>
|
|
||||||
<template is="dom-if" if="[[_equal(_state, 'error')]]">
|
|
||||||
<hass-error-screen
|
|
||||||
title=""
|
|
||||||
error="Error while loading this panel."
|
|
||||||
narrow="[[narrow]]"
|
|
||||||
show-menu="[[showMenu]]"
|
|
||||||
></hass-error-screen>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<span id="panel" hidden$="[[!_equal(_state, 'loaded')]]"></span>
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
|
|
||||||
static get properties() {
|
|
||||||
return {
|
|
||||||
hass: {
|
|
||||||
type: Object,
|
|
||||||
observer: "updateAttributes",
|
|
||||||
},
|
|
||||||
|
|
||||||
narrow: {
|
|
||||||
type: Boolean,
|
|
||||||
value: false,
|
|
||||||
observer: "updateAttributes",
|
|
||||||
},
|
|
||||||
|
|
||||||
showMenu: {
|
|
||||||
type: Boolean,
|
|
||||||
value: false,
|
|
||||||
observer: "updateAttributes",
|
|
||||||
},
|
|
||||||
route: Object,
|
|
||||||
routeData: Object,
|
|
||||||
routeTail: {
|
|
||||||
type: Object,
|
|
||||||
observer: "updateAttributes",
|
|
||||||
},
|
|
||||||
_state: {
|
|
||||||
type: String,
|
|
||||||
value: "loading",
|
|
||||||
},
|
|
||||||
panel: {
|
|
||||||
type: Object,
|
|
||||||
computed: "computeCurrentPanel(hass)",
|
|
||||||
observer: "panelChanged",
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
panelChanged(panel) {
|
|
||||||
if (!panel) {
|
|
||||||
if (this.$.panel.lastChild) {
|
|
||||||
this.$.panel.removeChild(this.$.panel.lastChild);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this._state = "loading";
|
|
||||||
|
|
||||||
let loadingProm;
|
|
||||||
if (panel.url) {
|
|
||||||
loadingProm = new Promise((resolve, reject) =>
|
|
||||||
importHref(panel.url, resolve, reject)
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
loadingProm = ensureLoaded(panel.component_name);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (loadingProm === null) {
|
|
||||||
this._state = "error";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
loadingProm.then(
|
|
||||||
() => {
|
|
||||||
dynamicContentUpdater(
|
|
||||||
this.$.panel,
|
|
||||||
"ha-panel-" + panel.component_name,
|
|
||||||
{
|
|
||||||
hass: this.hass,
|
|
||||||
narrow: this.narrow,
|
|
||||||
showMenu: this.showMenu,
|
|
||||||
route: this.routeTail,
|
|
||||||
panel: panel,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
this._state = "loaded";
|
|
||||||
},
|
|
||||||
(err) => {
|
|
||||||
// eslint-disable-next-line
|
|
||||||
console.error("Error loading panel", err);
|
|
||||||
this._state = "error";
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
updateAttributes() {
|
|
||||||
var customEl = dom(this.$.panel).lastChild;
|
|
||||||
if (!customEl) return;
|
|
||||||
customEl.hass = this.hass;
|
|
||||||
customEl.narrow = this.narrow;
|
|
||||||
customEl.showMenu = this.showMenu;
|
|
||||||
customEl.route = this.routeTail;
|
|
||||||
}
|
|
||||||
|
|
||||||
computeCurrentPanel(hass) {
|
|
||||||
return hass.panels[hass.panelUrl];
|
|
||||||
}
|
|
||||||
|
|
||||||
_equal(a, b) {
|
|
||||||
return a === b;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
customElements.define("partial-panel-resolver", PartialPanelResolver);
|
|
268
src/layouts/partial-panel-resolver.ts
Normal file
268
src/layouts/partial-panel-resolver.ts
Normal file
@ -0,0 +1,268 @@
|
|||||||
|
import {
|
||||||
|
LitElement,
|
||||||
|
html,
|
||||||
|
PropertyDeclarations,
|
||||||
|
PropertyValues,
|
||||||
|
} from "lit-element";
|
||||||
|
|
||||||
|
import "./hass-loading-screen";
|
||||||
|
import "./hass-error-screen";
|
||||||
|
import { HomeAssistant, Panel, PanelElement, Route } from "../types";
|
||||||
|
|
||||||
|
// Cache of panel loading promises.
|
||||||
|
const LOADED: { [panel: string]: Promise<void> } = {};
|
||||||
|
|
||||||
|
// Which panel elements we will cache.
|
||||||
|
// Maybe we can cache them all eventually, but not sure yet about
|
||||||
|
// unknown side effects (like history taking a lot of memory, reset needed)
|
||||||
|
const CACHED_EL = ["lovelace", "states"];
|
||||||
|
|
||||||
|
function ensureLoaded(panel): Promise<void> | null {
|
||||||
|
if (panel in LOADED) {
|
||||||
|
return LOADED[panel];
|
||||||
|
}
|
||||||
|
|
||||||
|
let imported;
|
||||||
|
// Name each panel we support here, that way Webpack knows about it.
|
||||||
|
switch (panel) {
|
||||||
|
case "config":
|
||||||
|
imported = import(/* webpackChunkName: "panel-config" */ "../panels/config/ha-panel-config");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "custom":
|
||||||
|
imported = import(/* webpackChunkName: "panel-custom" */ "../panels/custom/ha-panel-custom");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "dev-event":
|
||||||
|
imported = import(/* webpackChunkName: "panel-dev-event" */ "../panels/dev-event/ha-panel-dev-event");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "dev-info":
|
||||||
|
imported = import(/* webpackChunkName: "panel-dev-info" */ "../panels/dev-info/ha-panel-dev-info");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "dev-mqtt":
|
||||||
|
imported = import(/* webpackChunkName: "panel-dev-mqtt" */ "../panels/dev-mqtt/ha-panel-dev-mqtt");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "dev-service":
|
||||||
|
imported = import(/* webpackChunkName: "panel-dev-service" */ "../panels/dev-service/ha-panel-dev-service");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "dev-state":
|
||||||
|
imported = import(/* webpackChunkName: "panel-dev-state" */ "../panels/dev-state/ha-panel-dev-state");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "dev-template":
|
||||||
|
imported = import(/* webpackChunkName: "panel-dev-template" */ "../panels/dev-template/ha-panel-dev-template");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "lovelace":
|
||||||
|
imported = import(/* webpackChunkName: "panel-lovelace" */ "../panels/lovelace/ha-panel-lovelace");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "states":
|
||||||
|
imported = import(/* webpackChunkName: "panel-states" */ "../panels/states/ha-panel-states");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "history":
|
||||||
|
imported = import(/* webpackChunkName: "panel-history" */ "../panels/history/ha-panel-history");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "iframe":
|
||||||
|
imported = import(/* webpackChunkName: "panel-iframe" */ "../panels/iframe/ha-panel-iframe");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "kiosk":
|
||||||
|
imported = import(/* webpackChunkName: "panel-kiosk" */ "../panels/kiosk/ha-panel-kiosk");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "logbook":
|
||||||
|
imported = import(/* webpackChunkName: "panel-logbook" */ "../panels/logbook/ha-panel-logbook");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "mailbox":
|
||||||
|
imported = import(/* webpackChunkName: "panel-mailbox" */ "../panels/mailbox/ha-panel-mailbox");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "map":
|
||||||
|
imported = import(/* webpackChunkName: "panel-map" */ "../panels/map/ha-panel-map");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "profile":
|
||||||
|
imported = import(/* webpackChunkName: "panel-profile" */ "../panels/profile/ha-panel-profile");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "shopping-list":
|
||||||
|
imported = import(/* webpackChunkName: "panel-shopping-list" */ "../panels/shopping-list/ha-panel-shopping-list");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "calendar":
|
||||||
|
imported = import(/* webpackChunkName: "panel-calendar" */ "../panels/calendar/ha-panel-calendar");
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
imported = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (imported != null) {
|
||||||
|
LOADED[panel] = imported;
|
||||||
|
}
|
||||||
|
|
||||||
|
return imported;
|
||||||
|
}
|
||||||
|
|
||||||
|
class PartialPanelResolver extends LitElement {
|
||||||
|
public hass?: HomeAssistant;
|
||||||
|
public narrow?: boolean;
|
||||||
|
public showMenu?: boolean;
|
||||||
|
public route?: Route | null;
|
||||||
|
|
||||||
|
private _routeTail?: Route | null;
|
||||||
|
private _panel?: Panel;
|
||||||
|
private _panelEl?: PanelElement;
|
||||||
|
private _error?: boolean;
|
||||||
|
private _cache: { [name: string]: PanelElement };
|
||||||
|
|
||||||
|
static get properties(): PropertyDeclarations {
|
||||||
|
return {
|
||||||
|
hass: {},
|
||||||
|
narrow: {},
|
||||||
|
showMenu: {},
|
||||||
|
route: {},
|
||||||
|
|
||||||
|
_routeTail: {},
|
||||||
|
_error: {},
|
||||||
|
_panelEl: {},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
this._cache = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
protected render() {
|
||||||
|
if (this._error) {
|
||||||
|
return html`
|
||||||
|
<hass-error-screen
|
||||||
|
title=""
|
||||||
|
error="Error while loading this panel."
|
||||||
|
.narrow=${this.narrow}
|
||||||
|
.showMenu=${this.showMenu}
|
||||||
|
/>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this._panelEl) {
|
||||||
|
return html`
|
||||||
|
<hass-loading-screen
|
||||||
|
.narrow=${this.narrow}
|
||||||
|
.showMenu=${this.showMenu}
|
||||||
|
></hass-loading-screen>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return html`
|
||||||
|
${this._panelEl}
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected updated(changedProps: PropertyValues) {
|
||||||
|
if (!this.hass) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (changedProps.has("route")) {
|
||||||
|
// Manual splitting
|
||||||
|
const route = this.route!;
|
||||||
|
const dividerPos = route.path.indexOf("/", 1);
|
||||||
|
this._routeTail = {
|
||||||
|
prefix: route.path.substr(0, dividerPos),
|
||||||
|
path: route.path.substr(dividerPos),
|
||||||
|
};
|
||||||
|
|
||||||
|
// If just route changed, no need to process further.
|
||||||
|
if (changedProps.size === 1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (changedProps.has("hass")) {
|
||||||
|
const panel = this.hass.panels[this.hass.panelUrl];
|
||||||
|
|
||||||
|
if (panel !== this._panel) {
|
||||||
|
this._panel = panel;
|
||||||
|
this._panelEl = undefined;
|
||||||
|
|
||||||
|
// Found cached one, use that
|
||||||
|
if (panel.component_name in this._cache) {
|
||||||
|
this._panelEl = this._cache[panel.component_name];
|
||||||
|
this._updatePanel();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const loadingProm = ensureLoaded(panel.component_name);
|
||||||
|
|
||||||
|
if (loadingProm === null) {
|
||||||
|
this._error = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
loadingProm.then(
|
||||||
|
() => {
|
||||||
|
// If panel changed while loading.
|
||||||
|
if (this._panel !== panel) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this._panelEl = (this._panelEl = document.createElement(
|
||||||
|
`ha-panel-${panel.component_name}`
|
||||||
|
)) as PanelElement;
|
||||||
|
|
||||||
|
if (CACHED_EL.includes(panel.component_name)) {
|
||||||
|
this._cache[panel.component_name] = this._panelEl;
|
||||||
|
}
|
||||||
|
|
||||||
|
this._updatePanel();
|
||||||
|
},
|
||||||
|
(err) => {
|
||||||
|
// tslint:disable-next-line
|
||||||
|
console.error("Error loading panel", err);
|
||||||
|
this._error = true;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this._updatePanel();
|
||||||
|
}
|
||||||
|
|
||||||
|
private _updatePanel() {
|
||||||
|
const el = this._panelEl;
|
||||||
|
|
||||||
|
if (!el) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ("setProperties" in el) {
|
||||||
|
// As long as we have Polymer panels
|
||||||
|
(el as any).setProperties({
|
||||||
|
hass: this.hass,
|
||||||
|
narrow: this.narrow,
|
||||||
|
showMenu: this.showMenu,
|
||||||
|
route: this._routeTail,
|
||||||
|
panel: this._panel,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
el.hass = this.hass;
|
||||||
|
el.narrow = this.narrow;
|
||||||
|
el.showMenu = this.showMenu;
|
||||||
|
el.route = this._routeTail;
|
||||||
|
el.panel = this._panel;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
customElements.define("partial-panel-resolver", PartialPanelResolver);
|
@ -4,7 +4,7 @@ import { fetchConfig, LovelaceConfig, saveConfig } from "../../data/lovelace";
|
|||||||
import "../../layouts/hass-loading-screen";
|
import "../../layouts/hass-loading-screen";
|
||||||
import "../../layouts/hass-error-screen";
|
import "../../layouts/hass-error-screen";
|
||||||
import "./hui-root";
|
import "./hui-root";
|
||||||
import { HomeAssistant, PanelInfo } from "../../types";
|
import { HomeAssistant, PanelInfo, Route } from "../../types";
|
||||||
import { Lovelace } from "./types";
|
import { Lovelace } from "./types";
|
||||||
import { LitElement, html, PropertyValues, TemplateResult } from "lit-element";
|
import { LitElement, html, PropertyValues, TemplateResult } from "lit-element";
|
||||||
import { hassLocalizeLitMixin } from "../../mixins/lit-localize-mixin";
|
import { hassLocalizeLitMixin } from "../../mixins/lit-localize-mixin";
|
||||||
@ -22,7 +22,7 @@ class LovelacePanel extends hassLocalizeLitMixin(LitElement) {
|
|||||||
public hass?: HomeAssistant;
|
public hass?: HomeAssistant;
|
||||||
public narrow?: boolean;
|
public narrow?: boolean;
|
||||||
public showMenu?: boolean;
|
public showMenu?: boolean;
|
||||||
public route?: object;
|
public route?: Route;
|
||||||
private _columns?: number;
|
private _columns?: number;
|
||||||
private _state?: "loading" | "loaded" | "error" | "yaml-editor";
|
private _state?: "loading" | "loaded" | "error" | "yaml-editor";
|
||||||
private _errorMsg?: string;
|
private _errorMsg?: string;
|
||||||
|
15
src/types.ts
15
src/types.ts
@ -86,7 +86,7 @@ export interface HomeAssistant {
|
|||||||
services: HassServices;
|
services: HassServices;
|
||||||
config: HassConfig;
|
config: HassConfig;
|
||||||
themes: Themes;
|
themes: Themes;
|
||||||
selectedTheme: string | null;
|
selectedTheme?: string | null;
|
||||||
panels: Panels;
|
panels: Panels;
|
||||||
panelUrl: string;
|
panelUrl: string;
|
||||||
language: string;
|
language: string;
|
||||||
@ -169,3 +169,16 @@ export interface PanelInfo<T = unknown> {
|
|||||||
url_path: string;
|
url_path: string;
|
||||||
config: T;
|
config: T;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface Route {
|
||||||
|
prefix: string;
|
||||||
|
path: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface PanelElement extends HTMLElement {
|
||||||
|
hass?: HomeAssistant;
|
||||||
|
narrow?: boolean;
|
||||||
|
showMenu?: boolean;
|
||||||
|
route?: Route | null;
|
||||||
|
panel?: Panel;
|
||||||
|
}
|
||||||
|
@ -393,6 +393,12 @@
|
|||||||
},
|
},
|
||||||
"state": {
|
"state": {
|
||||||
"for": "Протягом"
|
"for": "Протягом"
|
||||||
|
},
|
||||||
|
"time_pattern": {
|
||||||
|
"label": "Шаблон часу",
|
||||||
|
"hours": "Годин",
|
||||||
|
"minutes": "Хвилин",
|
||||||
|
"seconds": "Секунд"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -832,6 +838,7 @@
|
|||||||
},
|
},
|
||||||
"sun": {
|
"sun": {
|
||||||
"elevation": "Висота",
|
"elevation": "Висота",
|
||||||
|
"rising": "Схід сонця",
|
||||||
"setting": "Налаштування"
|
"setting": "Налаштування"
|
||||||
},
|
},
|
||||||
"updater": {
|
"updater": {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user