mirror of
https://github.com/home-assistant/frontend.git
synced 2025-08-22 07:39:29 +00:00
Compare commits
7 Commits
expect-con
...
analytics-
Author | SHA1 | Date | |
---|---|---|---|
![]() |
f69bce534a | ||
![]() |
575f58bd88 | ||
![]() |
35535628fc | ||
![]() |
8e018c9cfe | ||
![]() |
5ae268b792 | ||
![]() |
329732ac30 | ||
![]() |
7f88bab552 |
@@ -4,7 +4,8 @@
|
||||
"plugin:@typescript-eslint/recommended",
|
||||
"plugin:wc/recommended",
|
||||
"plugin:lit/recommended",
|
||||
"prettier"
|
||||
"prettier",
|
||||
"prettier/@typescript-eslint"
|
||||
],
|
||||
"parser": "@typescript-eslint/parser",
|
||||
"parserOptions": {
|
||||
@@ -84,25 +85,6 @@
|
||||
"@typescript-eslint/explicit-function-return-type": 0,
|
||||
"@typescript-eslint/explicit-module-boundary-types": 0,
|
||||
"@typescript-eslint/no-shadow": ["error"],
|
||||
"@typescript-eslint/naming-convention": [
|
||||
0,
|
||||
{
|
||||
"selector": "default",
|
||||
"format": ["camelCase", "snake_case"],
|
||||
"leadingUnderscore": "allow",
|
||||
"trailingUnderscore": "allow"
|
||||
},
|
||||
{
|
||||
"selector": ["variable"],
|
||||
"format": ["camelCase", "snake_case", "UPPER_CASE"],
|
||||
"leadingUnderscore": "allow",
|
||||
"trailingUnderscore": "allow"
|
||||
},
|
||||
{
|
||||
"selector": "typeLike",
|
||||
"format": ["PascalCase"]
|
||||
}
|
||||
],
|
||||
"lit/attribute-value-entities": 0
|
||||
},
|
||||
"plugins": ["disable", "import", "lit", "prettier", "@typescript-eslint"],
|
||||
|
6
.github/workflows/ci.yaml
vendored
6
.github/workflows/ci.yaml
vendored
@@ -37,11 +37,9 @@ jobs:
|
||||
- name: Build resources
|
||||
run: ./node_modules/.bin/gulp gen-icons-json build-translations gather-gallery-demos
|
||||
- name: Run eslint
|
||||
run: yarn run lint:eslint
|
||||
run: ./node_modules/.bin/eslint '{**/src,src}/**/*.{js,ts,html}' --ignore-path .gitignore
|
||||
- name: Run tsc
|
||||
run: yarn run lint:types
|
||||
- name: Run prettier
|
||||
run: yarn run lint:prettier
|
||||
run: ./node_modules/.bin/tsc
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
|
@@ -54,7 +54,9 @@ class HcCast extends LitElement {
|
||||
const error =
|
||||
this.castManager.castState === "NO_DEVICES_AVAILABLE"
|
||||
? html`
|
||||
<p>There were no suitable Chromecast devices to cast to found.</p>
|
||||
<p>
|
||||
There were no suitable Chromecast devices to cast to found.
|
||||
</p>
|
||||
`
|
||||
: undefined;
|
||||
|
||||
|
@@ -86,7 +86,9 @@ export class HcConnect extends LitElement {
|
||||
</div>
|
||||
<div class="card-actions">
|
||||
<a href="/">
|
||||
<mwc-button> Retry </mwc-button>
|
||||
<mwc-button>
|
||||
Retry
|
||||
</mwc-button>
|
||||
</a>
|
||||
<div class="spacer"></div>
|
||||
<mwc-button @click=${this._handleLogout}>Log out</mwc-button>
|
||||
|
@@ -246,15 +246,11 @@ export const demoEntitiesArsaboo: DemoConfig["entities"] = (localize) =>
|
||||
|
||||
"light.living_room_lights": {
|
||||
entity_id: "light.living_room_lights",
|
||||
state: "on",
|
||||
state: "off",
|
||||
attributes: {
|
||||
min_mireds: 111,
|
||||
max_mireds: 400,
|
||||
brightness: 175,
|
||||
color_temp: 300,
|
||||
supported_color_modes: ["brightness", "color_temp"],
|
||||
friendly_name: "Living Room Lights",
|
||||
color_mode: "color_temp",
|
||||
supported_features: 55,
|
||||
},
|
||||
},
|
||||
@@ -267,27 +263,13 @@ export const demoEntitiesArsaboo: DemoConfig["entities"] = (localize) =>
|
||||
},
|
||||
"light.kitchen_lights": {
|
||||
entity_id: "light.kitchen_lights",
|
||||
state: "on",
|
||||
attributes: {
|
||||
min_mireds: 111,
|
||||
max_mireds: 400,
|
||||
brightness: 200,
|
||||
rgb_color: [255, 175, 96],
|
||||
supported_color_modes: ["brightness", "color_temp", "rgb"],
|
||||
color_mode: "rgb",
|
||||
friendly_name: "Kitchen Lights",
|
||||
supported_features: 55,
|
||||
},
|
||||
},
|
||||
"light.lifx5": {
|
||||
entity_id: "light.lifx5",
|
||||
state: "off",
|
||||
attributes: {
|
||||
supported_color_modes: ["brightness"],
|
||||
friendly_name: "Garage Lights",
|
||||
friendly_name: "Kitchen Lights",
|
||||
supported_features: 1,
|
||||
},
|
||||
},
|
||||
|
||||
"sensor.plexspy": {
|
||||
entity_id: "sensor.plexspy",
|
||||
state: "0",
|
||||
@@ -500,6 +482,16 @@ export const demoEntitiesArsaboo: DemoConfig["entities"] = (localize) =>
|
||||
icon: "hademo:history",
|
||||
},
|
||||
},
|
||||
"light.lifx5": {
|
||||
entity_id: "light.lifx5",
|
||||
state: "on",
|
||||
attributes: {
|
||||
min_mireds: 111,
|
||||
max_mireds: 400,
|
||||
friendly_name: "Garage Lights",
|
||||
supported_features: 55,
|
||||
},
|
||||
},
|
||||
"sensor.alok_to_home": {
|
||||
entity_id: "sensor.alok_to_home",
|
||||
state: "41",
|
||||
|
@@ -1114,9 +1114,6 @@ export const demoEntitiesTeachingbirds: DemoConfig["entities"] = () =>
|
||||
min_mireds: 153,
|
||||
max_mireds: 500,
|
||||
brightness: 63,
|
||||
color_temp: 200,
|
||||
supported_color_modes: ["brightness", "color_temp", "rgb"],
|
||||
color_mode: "color_temp",
|
||||
friendly_name: "Upstairs lights",
|
||||
supported_features: 63,
|
||||
custom_ui_state_card: "state-card-custom-ui",
|
||||
@@ -1128,7 +1125,6 @@ export const demoEntitiesTeachingbirds: DemoConfig["entities"] = () =>
|
||||
attributes: {
|
||||
friendly_name: "Walk in closet lights",
|
||||
supported_features: 41,
|
||||
supported_color_modes: ["brightness", "color_temp"],
|
||||
custom_ui_state_card: "state-card-custom-ui",
|
||||
icon: "mdi:wall-sconce",
|
||||
},
|
||||
@@ -1140,8 +1136,6 @@ export const demoEntitiesTeachingbirds: DemoConfig["entities"] = () =>
|
||||
brightness: 254,
|
||||
friendly_name: "Outdoor lights",
|
||||
supported_features: 41,
|
||||
supported_color_modes: ["brightness"],
|
||||
color_mode: "brightness",
|
||||
custom_ui_state_card: "state-card-custom-ui",
|
||||
icon: "mdi:wall-sconce",
|
||||
},
|
||||
@@ -1154,8 +1148,6 @@ export const demoEntitiesTeachingbirds: DemoConfig["entities"] = () =>
|
||||
max_mireds: 500,
|
||||
brightness: 128,
|
||||
color_temp: 366,
|
||||
supported_color_modes: ["brightness", "color_temp", "rgb"],
|
||||
color_mode: "color_temp",
|
||||
effect_list: ["colorloop"],
|
||||
friendly_name: "Downstairs lights",
|
||||
supported_features: 63,
|
||||
@@ -1315,7 +1307,6 @@ export const demoEntitiesTeachingbirds: DemoConfig["entities"] = () =>
|
||||
attributes: {
|
||||
min_mireds: 153,
|
||||
max_mireds: 500,
|
||||
supported_color_modes: ["brightness", "color_temp"],
|
||||
is_deconz_group: false,
|
||||
friendly_name: "Bedside Lamp",
|
||||
supported_features: 63,
|
||||
@@ -1329,7 +1320,6 @@ export const demoEntitiesTeachingbirds: DemoConfig["entities"] = () =>
|
||||
attributes: {
|
||||
min_mireds: 153,
|
||||
max_mireds: 500,
|
||||
supported_color_modes: ["brightness", "color_temp"],
|
||||
is_deconz_group: false,
|
||||
friendly_name: "Floorlamp Reading Light",
|
||||
supported_features: 43,
|
||||
@@ -1345,8 +1335,6 @@ export const demoEntitiesTeachingbirds: DemoConfig["entities"] = () =>
|
||||
max_mireds: 500,
|
||||
brightness: 128,
|
||||
color_temp: 366,
|
||||
supported_color_modes: ["brightness", "color_temp", "rgb"],
|
||||
color_mode: "color_temp",
|
||||
effect_list: ["colorloop"],
|
||||
is_deconz_group: false,
|
||||
friendly_name: "Hallway window light",
|
||||
@@ -1361,7 +1349,6 @@ export const demoEntitiesTeachingbirds: DemoConfig["entities"] = () =>
|
||||
attributes: {
|
||||
brightness: 77,
|
||||
is_deconz_group: false,
|
||||
supported_color_modes: ["brightness"],
|
||||
friendly_name: "Isa Ceiling Light",
|
||||
supported_features: 41,
|
||||
custom_ui_state_card: "state-card-custom-ui",
|
||||
@@ -1376,8 +1363,6 @@ export const demoEntitiesTeachingbirds: DemoConfig["entities"] = () =>
|
||||
max_mireds: 500,
|
||||
brightness: 150,
|
||||
color_temp: 366,
|
||||
supported_color_modes: ["brightness", "color_temp"],
|
||||
color_mode: "color_temp",
|
||||
effect_list: ["colorloop"],
|
||||
is_deconz_group: false,
|
||||
friendly_name: "Floorlamp",
|
||||
@@ -1392,7 +1377,6 @@ export const demoEntitiesTeachingbirds: DemoConfig["entities"] = () =>
|
||||
attributes: {
|
||||
friendly_name: "Bedroom Ceiling Light",
|
||||
supported_features: 41,
|
||||
supported_color_modes: ["brightness"],
|
||||
custom_ui_state_card: "state-card-custom-ui",
|
||||
icon: "mdi:ceiling-light",
|
||||
},
|
||||
@@ -1403,7 +1387,6 @@ export const demoEntitiesTeachingbirds: DemoConfig["entities"] = () =>
|
||||
attributes: {
|
||||
friendly_name: "Nightlight",
|
||||
supported_features: 17,
|
||||
supported_color_modes: ["brightness"],
|
||||
custom_ui_state_card: "state-card-custom-ui",
|
||||
icon: "mdi:lamp",
|
||||
},
|
||||
@@ -1770,7 +1753,6 @@ export const demoEntitiesTeachingbirds: DemoConfig["entities"] = () =>
|
||||
power_consumption: 2.2,
|
||||
friendly_name: "Upstairs Hallway Light",
|
||||
supported_features: 33,
|
||||
supported_color_modes: ["brightness"],
|
||||
custom_ui_state_card: "state-card-custom-ui",
|
||||
icon: "mdi:ceiling-light",
|
||||
},
|
||||
@@ -1786,7 +1768,6 @@ export const demoEntitiesTeachingbirds: DemoConfig["entities"] = () =>
|
||||
power_consumption: 0,
|
||||
friendly_name: "Dining Room Light",
|
||||
supported_features: 33,
|
||||
supported_color_modes: ["brightness"],
|
||||
custom_ui_state_card: "state-card-custom-ui",
|
||||
icon: "mdi:ceiling-light",
|
||||
},
|
||||
@@ -1802,7 +1783,6 @@ export const demoEntitiesTeachingbirds: DemoConfig["entities"] = () =>
|
||||
power_consumption: 0,
|
||||
friendly_name: "Living room Spotlights",
|
||||
supported_features: 33,
|
||||
supported_color_modes: ["brightness"],
|
||||
custom_ui_state_card: "state-card-custom-ui",
|
||||
icon: "mdi:track-light",
|
||||
},
|
||||
@@ -1819,7 +1799,6 @@ export const demoEntitiesTeachingbirds: DemoConfig["entities"] = () =>
|
||||
power_consumption: 2.5,
|
||||
friendly_name: "Passage Lights",
|
||||
supported_features: 33,
|
||||
supported_color_modes: ["brightness"],
|
||||
custom_ui_state_card: "state-card-custom-ui",
|
||||
icon: "mdi:track-light",
|
||||
},
|
||||
@@ -1864,7 +1843,6 @@ export const demoEntitiesTeachingbirds: DemoConfig["entities"] = () =>
|
||||
power_consumption: 37.4,
|
||||
friendly_name: "Kitchen Lights",
|
||||
supported_features: 33,
|
||||
supported_color_modes: ["brightness"],
|
||||
custom_ui_state_card: "state-card-custom-ui",
|
||||
icon: "mdi:track-light",
|
||||
},
|
||||
|
@@ -3,6 +3,8 @@ import { MockHomeAssistant } from "../../../src/fake_data/provide_hass";
|
||||
export const mockTranslations = (hass: MockHomeAssistant) => {
|
||||
hass.mockWS(
|
||||
"frontend/get_translations",
|
||||
(/* msg: {language: string, category: string} */) => ({ resources: {} })
|
||||
(/* msg: {language: string, category: string} */) => {
|
||||
return { resources: {} };
|
||||
}
|
||||
);
|
||||
};
|
||||
|
@@ -15,10 +15,6 @@ class DemoCard extends PolymerElement {
|
||||
margin: 0 0 20px;
|
||||
color: var(--primary-color);
|
||||
}
|
||||
h2 small {
|
||||
font-size: 0.5em;
|
||||
color: var(--primary-text-color);
|
||||
}
|
||||
#card {
|
||||
max-width: 400px;
|
||||
width: 100vw;
|
||||
@@ -38,12 +34,7 @@ class DemoCard extends PolymerElement {
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<h2>
|
||||
[[config.heading]]
|
||||
<template is="dom-if" if="[[_size]]">
|
||||
<small>(size [[_size]])</small>
|
||||
</template>
|
||||
</h2>
|
||||
<h2>[[config.heading]]</h2>
|
||||
<div class="root">
|
||||
<div id="card"></div>
|
||||
<template is="dom-if" if="[[showConfig]]">
|
||||
@@ -64,9 +55,6 @@ class DemoCard extends PolymerElement {
|
||||
observer: "_configChanged",
|
||||
},
|
||||
showConfig: Boolean,
|
||||
_size: {
|
||||
type: Number,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
@@ -82,17 +70,6 @@ class DemoCard extends PolymerElement {
|
||||
|
||||
const el = this._createCardElement(safeLoad(config.config)[0]);
|
||||
card.appendChild(el);
|
||||
this._getSize(el);
|
||||
}
|
||||
|
||||
async _getSize(el) {
|
||||
await customElements.whenDefined(el.localName);
|
||||
|
||||
if (!("getCardSize" in el)) {
|
||||
this._size = undefined;
|
||||
return;
|
||||
}
|
||||
this._size = await el.getCardSize();
|
||||
}
|
||||
|
||||
_createCardElement(cardConfig) {
|
||||
|
@@ -93,8 +93,4 @@ class DemoAlarmPanelEntity extends LitElement {
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"demo-hui-alarm-panel-card": DemoAlarmPanelEntity;
|
||||
}
|
||||
}
|
||||
customElements.define("demo-hui-alarm-panel-card", DemoAlarmPanelEntity);
|
||||
|
@@ -75,8 +75,4 @@ class DemoConditional extends LitElement {
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"demo-hui-conditional-card": DemoConditional;
|
||||
}
|
||||
}
|
||||
customElements.define("demo-hui-conditional-card", DemoConditional);
|
||||
|
@@ -239,8 +239,4 @@ class DemoEntities extends LitElement {
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"demo-hui-entities-card": DemoEntities;
|
||||
}
|
||||
}
|
||||
customElements.define("demo-hui-entities-card", DemoEntities);
|
||||
|
@@ -91,8 +91,4 @@ class DemoButtonEntity extends LitElement {
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"demo-hui-entity-button-card": DemoButtonEntity;
|
||||
}
|
||||
}
|
||||
customElements.define("demo-hui-entity-button-card", DemoButtonEntity);
|
||||
|
@@ -132,8 +132,4 @@ class DemoEntityFilter extends LitElement {
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"demo-hui-entity-filter-card": DemoEntityFilter;
|
||||
}
|
||||
}
|
||||
customElements.define("demo-hui-entity-filter-card", DemoEntityFilter);
|
||||
|
@@ -129,8 +129,4 @@ class DemoGaugeEntity extends LitElement {
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"demo-hui-gauge-card": DemoGaugeEntity;
|
||||
}
|
||||
}
|
||||
customElements.define("demo-hui-gauge-card", DemoGaugeEntity);
|
||||
|
@@ -186,7 +186,7 @@ const CONFIGS = [
|
||||
name:
|
||||
- light.kitchen_lights
|
||||
- entity: lock.kitchen_door
|
||||
name:
|
||||
name:
|
||||
- light.ceiling_lights
|
||||
`,
|
||||
},
|
||||
@@ -194,7 +194,7 @@ const CONFIGS = [
|
||||
heading: "Custom tap action",
|
||||
config: `
|
||||
- type: glance
|
||||
columns: 4
|
||||
columns: 4
|
||||
entities:
|
||||
- entity: lock.kitchen_door
|
||||
name: Custom
|
||||
@@ -232,8 +232,4 @@ class DemoGlanceEntity extends LitElement {
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"demo-hui-glance-card": DemoGlanceEntity;
|
||||
}
|
||||
}
|
||||
customElements.define("demo-hui-glance-card", DemoGlanceEntity);
|
||||
|
@@ -42,8 +42,4 @@ class DemoIframe extends LitElement {
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"demo-hui-iframe-card": DemoIframe;
|
||||
}
|
||||
}
|
||||
customElements.define("demo-hui-iframe-card", DemoIframe);
|
||||
|
@@ -85,8 +85,4 @@ class DemoLightEntity extends LitElement {
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"demo-hui-light-card": DemoLightEntity;
|
||||
}
|
||||
}
|
||||
customElements.define("demo-hui-light-card", DemoLightEntity);
|
||||
|
@@ -183,8 +183,4 @@ class DemoMap extends LitElement {
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"demo-hui-map-card": DemoMap;
|
||||
}
|
||||
}
|
||||
customElements.define("demo-hui-map-card", DemoMap);
|
||||
|
@@ -276,8 +276,4 @@ class DemoMarkdown extends LitElement {
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"demo-hui-markdown-card": DemoMarkdown;
|
||||
}
|
||||
}
|
||||
customElements.define("demo-hui-markdown-card", DemoMarkdown);
|
||||
|
@@ -180,8 +180,4 @@ class DemoHuiMediaControlCard extends LitElement {
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"demo-hui-media-control-card": DemoHuiMediaControlCard;
|
||||
}
|
||||
}
|
||||
customElements.define("demo-hui-media-control-card", DemoHuiMediaControlCard);
|
||||
|
@@ -77,8 +77,4 @@ class DemoHuiMediaPlayerRow extends LitElement {
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"demo-hui-media-player-row": DemoHuiMediaPlayerRow;
|
||||
}
|
||||
}
|
||||
customElements.define("demo-hui-media-player-row", DemoHuiMediaPlayerRow);
|
||||
|
@@ -147,8 +147,4 @@ class DemoPictureElements extends LitElement {
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"demo-hui-picture-elements-card": DemoPictureElements;
|
||||
}
|
||||
}
|
||||
customElements.define("demo-hui-picture-elements-card", DemoPictureElements);
|
||||
|
@@ -102,8 +102,4 @@ class DemoPictureEntity extends LitElement {
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"demo-hui-picture-entity-card": DemoPictureEntity;
|
||||
}
|
||||
}
|
||||
customElements.define("demo-hui-picture-entity-card", DemoPictureEntity);
|
||||
|
@@ -143,8 +143,4 @@ class DemoPictureGlance extends LitElement {
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"demo-hui-picture-glance-card": DemoPictureGlance;
|
||||
}
|
||||
}
|
||||
customElements.define("demo-hui-picture-glance-card", DemoPictureGlance);
|
||||
|
@@ -52,8 +52,4 @@ export class DemoPlantEntity extends LitElement {
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"demo-hui-plant-card": DemoPlantEntity;
|
||||
}
|
||||
}
|
||||
customElements.define("demo-hui-plant-card", DemoPlantEntity);
|
||||
|
@@ -48,8 +48,4 @@ class DemoShoppingListEntity extends LitElement {
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"demo-hui-shopping-list-card": DemoShoppingListEntity;
|
||||
}
|
||||
}
|
||||
customElements.define("demo-hui-shopping-list-card", DemoShoppingListEntity);
|
||||
|
@@ -49,110 +49,6 @@ const ENTITIES = [
|
||||
];
|
||||
|
||||
const CONFIGS = [
|
||||
{
|
||||
heading: "Default Grid",
|
||||
config: `
|
||||
- type: grid
|
||||
cards:
|
||||
- type: entity
|
||||
entity: light.kitchen_lights
|
||||
- type: entity
|
||||
entity: light.bed_light
|
||||
- type: entity
|
||||
entity: device_tracker.demo_paulus
|
||||
- type: sensor
|
||||
entity: sensor.illumination
|
||||
graph: line
|
||||
- type: entity
|
||||
entity: device_tracker.demo_anne_therese
|
||||
`,
|
||||
},
|
||||
{
|
||||
heading: "Non-square Grid with 2 columns",
|
||||
config: `
|
||||
- type: grid
|
||||
columns: 2
|
||||
square: false
|
||||
cards:
|
||||
- type: entity
|
||||
entity: light.kitchen_lights
|
||||
- type: entity
|
||||
entity: light.bed_light
|
||||
- type: entity
|
||||
entity: device_tracker.demo_paulus
|
||||
- type: sensor
|
||||
entity: sensor.illumination
|
||||
graph: line
|
||||
`,
|
||||
},
|
||||
{
|
||||
heading: "Default Grid with title",
|
||||
config: `
|
||||
- type: grid
|
||||
title: Kitchen
|
||||
cards:
|
||||
- type: entity
|
||||
entity: light.kitchen_lights
|
||||
- type: entity
|
||||
entity: light.bed_light
|
||||
- type: entity
|
||||
entity: device_tracker.demo_paulus
|
||||
- type: sensor
|
||||
entity: sensor.illumination
|
||||
graph: line
|
||||
- type: entity
|
||||
entity: device_tracker.demo_anne_therese
|
||||
`,
|
||||
},
|
||||
{
|
||||
heading: "Columns 4",
|
||||
config: `
|
||||
- type: grid
|
||||
columns: 4
|
||||
cards:
|
||||
- type: entity
|
||||
entity: light.kitchen_lights
|
||||
- type: entity
|
||||
entity: light.bed_light
|
||||
- type: entity
|
||||
entity: device_tracker.demo_paulus
|
||||
- type: sensor
|
||||
entity: sensor.illumination
|
||||
graph: line
|
||||
`,
|
||||
},
|
||||
{
|
||||
heading: "Columns 2",
|
||||
config: `
|
||||
- type: grid
|
||||
columns: 2
|
||||
cards:
|
||||
- type: entity
|
||||
entity: light.kitchen_lights
|
||||
- type: entity
|
||||
entity: light.bed_light
|
||||
`,
|
||||
},
|
||||
{
|
||||
heading: "Columns 1",
|
||||
config: `
|
||||
- type: grid
|
||||
columns: 1
|
||||
cards:
|
||||
- type: entity
|
||||
entity: light.kitchen_lights
|
||||
`,
|
||||
},
|
||||
{
|
||||
heading: "Size for single card",
|
||||
config: `
|
||||
- type: grid
|
||||
cards:
|
||||
- type: entity
|
||||
entity: light.kitchen_lights
|
||||
`,
|
||||
},
|
||||
|
||||
{
|
||||
heading: "Vertical Stack",
|
||||
config: `
|
||||
@@ -203,9 +99,45 @@ const CONFIGS = [
|
||||
entity: light.bed_light
|
||||
`,
|
||||
},
|
||||
{
|
||||
heading: "Default Grid",
|
||||
config: `
|
||||
- type: grid
|
||||
cards:
|
||||
- type: entity
|
||||
entity: light.kitchen_lights
|
||||
- type: entity
|
||||
entity: light.bed_light
|
||||
- type: entity
|
||||
entity: device_tracker.demo_paulus
|
||||
- type: sensor
|
||||
entity: sensor.illumination
|
||||
graph: line
|
||||
- type: entity
|
||||
entity: device_tracker.demo_anne_therese
|
||||
`,
|
||||
},
|
||||
{
|
||||
heading: "Non-square Grid with 2 columns",
|
||||
config: `
|
||||
- type: grid
|
||||
columns: 2
|
||||
square: false
|
||||
cards:
|
||||
- type: entity
|
||||
entity: light.kitchen_lights
|
||||
- type: entity
|
||||
entity: light.bed_light
|
||||
- type: entity
|
||||
entity: device_tracker.demo_paulus
|
||||
- type: sensor
|
||||
entity: sensor.illumination
|
||||
graph: line
|
||||
`,
|
||||
},
|
||||
];
|
||||
|
||||
@customElement("demo-hui-grid-and-stack-card")
|
||||
@customElement("demo-hui-stack-card")
|
||||
class DemoStack extends LitElement {
|
||||
@query("#demos") private _demoRoot!: HTMLElement;
|
||||
|
||||
@@ -223,8 +155,4 @@ class DemoStack extends LitElement {
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"demo-hui-grid-and-stack-card": DemoStack;
|
||||
}
|
||||
}
|
||||
customElements.define("demo-hui-stack-card", DemoStack);
|
@@ -96,8 +96,4 @@ class DemoThermostatEntity extends LitElement {
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"demo-hui-thermostat-card": DemoThermostatEntity;
|
||||
}
|
||||
}
|
||||
customElements.define("demo-hui-thermostat-card", DemoThermostatEntity);
|
||||
|
@@ -61,9 +61,6 @@ const nameAsDomainEntry = createConfigEntry("ESPHome");
|
||||
const longNameEntry = createConfigEntry(
|
||||
"Entry with a super long name that is going to the next line"
|
||||
);
|
||||
const longNonBreakingNameEntry = createConfigEntry(
|
||||
"EntryWithASuperLongNameThatDoesNotBreak"
|
||||
);
|
||||
const configPanelEntry = createConfigEntry("Config Panel", {
|
||||
domain: "mqtt",
|
||||
localized_domain_name: "MQTT",
|
||||
@@ -86,8 +83,7 @@ const setupRetryReasonEntry = createConfigEntry("Setup Retry", {
|
||||
});
|
||||
const setupRetryReasonMissingKeyEntry = createConfigEntry("Setup Retry", {
|
||||
state: "setup_retry",
|
||||
reason:
|
||||
"HTTPSConnectionpool: Max retries exceeded with NewConnectionError('<urllib3.connection.HTTPSConnection object at 0x9eedfc10>: Failed to establish a new connection: [Errno 113] Host is unreachable')",
|
||||
reason: "resolve_error",
|
||||
});
|
||||
const failedUnloadEntry = createConfigEntry("Failed Unload", {
|
||||
state: "failed_unload",
|
||||
@@ -145,7 +141,6 @@ const configEntries: Array<{
|
||||
{ items: [optionsFlowEntry] },
|
||||
{ items: [nameAsDomainEntry] },
|
||||
{ items: [longNameEntry] },
|
||||
{ items: [longNonBreakingNameEntry] },
|
||||
{ items: [setupErrorEntry] },
|
||||
{ items: [migrationErrorEntry] },
|
||||
{ items: [setupRetryEntry] },
|
||||
@@ -159,7 +154,6 @@ const configEntries: Array<{
|
||||
setupErrorEntry,
|
||||
migrationErrorEntry,
|
||||
longNameEntry,
|
||||
longNonBreakingNameEntry,
|
||||
setupRetryEntry,
|
||||
failedUnloadEntry,
|
||||
notLoadedEntry,
|
||||
|
@@ -9,10 +9,13 @@ import {
|
||||
} from "lit-element";
|
||||
import "../../../src/components/ha-card";
|
||||
import {
|
||||
LightColorModes,
|
||||
SUPPORT_BRIGHTNESS,
|
||||
SUPPORT_COLOR,
|
||||
SUPPORT_COLOR_TEMP,
|
||||
SUPPORT_EFFECT,
|
||||
SUPPORT_FLASH,
|
||||
SUPPORT_TRANSITION,
|
||||
SUPPORT_WHITE_VALUE,
|
||||
} from "../../../src/data/light";
|
||||
import "../../../src/dialogs/more-info/more-info-content";
|
||||
import { getEntity } from "../../../src/fake_data/entity";
|
||||
@@ -29,8 +32,7 @@ const ENTITIES = [
|
||||
getEntity("light", "kitchen_light", "on", {
|
||||
friendly_name: "Brightness Light",
|
||||
brightness: 200,
|
||||
supported_color_modes: [LightColorModes.BRIGHTNESS],
|
||||
color_mode: LightColorModes.BRIGHTNESS,
|
||||
supported_features: SUPPORT_BRIGHTNESS,
|
||||
}),
|
||||
getEntity("light", "color_temperature_light", "on", {
|
||||
friendly_name: "White Color Temperature Light",
|
||||
@@ -38,96 +40,20 @@ const ENTITIES = [
|
||||
color_temp: 75,
|
||||
min_mireds: 30,
|
||||
max_mireds: 150,
|
||||
supported_color_modes: [
|
||||
LightColorModes.BRIGHTNESS,
|
||||
LightColorModes.COLOR_TEMP,
|
||||
],
|
||||
color_mode: LightColorModes.COLOR_TEMP,
|
||||
supported_features: SUPPORT_BRIGHTNESS + SUPPORT_COLOR_TEMP,
|
||||
}),
|
||||
getEntity("light", "color_hs_light", "on", {
|
||||
friendly_name: "Color HS Light",
|
||||
brightness: 255,
|
||||
hs_color: [30, 100],
|
||||
rgb_color: [30, 100, 255],
|
||||
min_mireds: 30,
|
||||
max_mireds: 150,
|
||||
supported_features: SUPPORT_EFFECT + SUPPORT_FLASH + SUPPORT_TRANSITION,
|
||||
supported_color_modes: [
|
||||
LightColorModes.BRIGHTNESS,
|
||||
LightColorModes.COLOR_TEMP,
|
||||
LightColorModes.HS,
|
||||
],
|
||||
color_mode: LightColorModes.HS,
|
||||
effect_list: ["random", "colorloop"],
|
||||
}),
|
||||
getEntity("light", "color_rgb_ct_light", "on", {
|
||||
friendly_name: "Color RGB + CT Light",
|
||||
brightness: 255,
|
||||
color_temp: 75,
|
||||
min_mireds: 30,
|
||||
max_mireds: 150,
|
||||
supported_features: SUPPORT_EFFECT + SUPPORT_FLASH + SUPPORT_TRANSITION,
|
||||
supported_color_modes: [
|
||||
LightColorModes.BRIGHTNESS,
|
||||
LightColorModes.COLOR_TEMP,
|
||||
LightColorModes.RGB,
|
||||
],
|
||||
color_mode: LightColorModes.COLOR_TEMP,
|
||||
effect_list: ["random", "colorloop"],
|
||||
}),
|
||||
getEntity("light", "color_RGB_light", "on", {
|
||||
getEntity("light", "color_effectslight", "on", {
|
||||
friendly_name: "Color Effets Light",
|
||||
brightness: 255,
|
||||
rgb_color: [30, 100, 255],
|
||||
supported_features: SUPPORT_EFFECT + SUPPORT_FLASH + SUPPORT_TRANSITION,
|
||||
supported_color_modes: [LightColorModes.BRIGHTNESS, LightColorModes.RGB],
|
||||
color_mode: LightColorModes.RGB,
|
||||
effect_list: ["random", "colorloop"],
|
||||
}),
|
||||
getEntity("light", "color_rgbw_light", "on", {
|
||||
friendly_name: "Color RGBW Light",
|
||||
brightness: 255,
|
||||
rgbw_color: [30, 100, 255, 125],
|
||||
min_mireds: 30,
|
||||
max_mireds: 150,
|
||||
supported_features: SUPPORT_EFFECT + SUPPORT_FLASH + SUPPORT_TRANSITION,
|
||||
supported_color_modes: [
|
||||
LightColorModes.BRIGHTNESS,
|
||||
LightColorModes.COLOR_TEMP,
|
||||
LightColorModes.RGBW,
|
||||
],
|
||||
color_mode: LightColorModes.RGBW,
|
||||
effect_list: ["random", "colorloop"],
|
||||
}),
|
||||
getEntity("light", "color_rgbww_light", "on", {
|
||||
friendly_name: "Color RGBWW Light",
|
||||
brightness: 255,
|
||||
rgbww_color: [30, 100, 255, 125, 10],
|
||||
min_mireds: 30,
|
||||
max_mireds: 150,
|
||||
supported_features: SUPPORT_EFFECT + SUPPORT_FLASH + SUPPORT_TRANSITION,
|
||||
supported_color_modes: [
|
||||
LightColorModes.BRIGHTNESS,
|
||||
LightColorModes.COLOR_TEMP,
|
||||
LightColorModes.RGBWW,
|
||||
],
|
||||
color_mode: LightColorModes.RGBWW,
|
||||
effect_list: ["random", "colorloop"],
|
||||
}),
|
||||
getEntity("light", "color_xy_light", "on", {
|
||||
friendly_name: "Color XY Light",
|
||||
brightness: 255,
|
||||
xy_color: [30, 100],
|
||||
rgb_color: [30, 100, 255],
|
||||
min_mireds: 30,
|
||||
max_mireds: 150,
|
||||
supported_features: SUPPORT_EFFECT + SUPPORT_FLASH + SUPPORT_TRANSITION,
|
||||
supported_color_modes: [
|
||||
LightColorModes.BRIGHTNESS,
|
||||
LightColorModes.COLOR_TEMP,
|
||||
LightColorModes.XY,
|
||||
],
|
||||
color_mode: LightColorModes.XY,
|
||||
hs_color: [30, 100],
|
||||
white_value: 36,
|
||||
supported_features:
|
||||
SUPPORT_BRIGHTNESS +
|
||||
SUPPORT_EFFECT +
|
||||
SUPPORT_FLASH +
|
||||
SUPPORT_COLOR +
|
||||
SUPPORT_TRANSITION +
|
||||
SUPPORT_WHITE_VALUE,
|
||||
effect_list: ["random", "colorloop"],
|
||||
}),
|
||||
];
|
||||
|
@@ -47,7 +47,9 @@ class HassioAddonRepositoryEl extends LitElement {
|
||||
const repo = this.repo;
|
||||
let _addons = this.addons;
|
||||
if (!this.hass.userData?.showAdvanced) {
|
||||
_addons = _addons.filter((addon) => !addon.advanced);
|
||||
_addons = _addons.filter((addon) => {
|
||||
return !addon.advanced;
|
||||
});
|
||||
}
|
||||
const addons = this._getAddons(_addons, this.filter);
|
||||
|
||||
@@ -66,7 +68,9 @@ class HassioAddonRepositoryEl extends LitElement {
|
||||
}
|
||||
return html`
|
||||
<div class="content">
|
||||
<h1>${repo.name}</h1>
|
||||
<h1>
|
||||
${repo.name}
|
||||
</h1>
|
||||
<div class="card-group">
|
||||
${addons.map(
|
||||
(addon) => html`
|
||||
|
@@ -86,7 +86,9 @@ class HassioAddonStore extends LitElement {
|
||||
main-page
|
||||
supervisor
|
||||
>
|
||||
<span slot="header"> ${this.supervisor.localize("panel.store")} </span>
|
||||
<span slot="header">
|
||||
${this.supervisor.localize("panel.store")}
|
||||
</span>
|
||||
<ha-button-menu
|
||||
corner="BOTTOM_START"
|
||||
slot="toolbar-icon"
|
||||
@@ -152,8 +154,8 @@ class HassioAddonStore extends LitElement {
|
||||
repositories: HassioAddonRepository[],
|
||||
addons: HassioAddonInfo[],
|
||||
filter?: string
|
||||
) =>
|
||||
repositories.sort(sortRepos).map((repo) => {
|
||||
) => {
|
||||
return repositories.sort(sortRepos).map((repo) => {
|
||||
const filteredAddons = addons.filter(
|
||||
(addon) => addon.repository === repo.slug
|
||||
);
|
||||
@@ -169,7 +171,8 @@ class HassioAddonStore extends LitElement {
|
||||
></hassio-addon-repository>
|
||||
`
|
||||
: html``;
|
||||
})
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
private _handleAction(ev: CustomEvent<ActionDetail>) {
|
||||
|
@@ -69,13 +69,13 @@ class HassioAddonAudio extends LitElement {
|
||||
.selected=${this._selectedInput!}
|
||||
>
|
||||
${this._inputDevices &&
|
||||
this._inputDevices.map(
|
||||
(item) => html`
|
||||
this._inputDevices.map((item) => {
|
||||
return html`
|
||||
<paper-item device=${item.device || ""}>
|
||||
${item.name}
|
||||
</paper-item>
|
||||
`
|
||||
)}
|
||||
`;
|
||||
})}
|
||||
</paper-listbox>
|
||||
</paper-dropdown-menu>
|
||||
<paper-dropdown-menu
|
||||
@@ -90,13 +90,13 @@ class HassioAddonAudio extends LitElement {
|
||||
.selected=${this._selectedOutput!}
|
||||
>
|
||||
${this._outputDevices &&
|
||||
this._outputDevices.map(
|
||||
(item) => html`
|
||||
this._outputDevices.map((item) => {
|
||||
return html`
|
||||
<paper-item device=${item.device || ""}
|
||||
>${item.name}</paper-item
|
||||
>
|
||||
`
|
||||
)}
|
||||
`;
|
||||
})}
|
||||
</paper-listbox>
|
||||
</paper-dropdown-menu>
|
||||
</div>
|
||||
|
@@ -65,15 +65,19 @@ class HassioAddonConfig extends LitElement {
|
||||
|
||||
@query("ha-yaml-editor") private _editor?: HaYamlEditor;
|
||||
|
||||
public computeLabel = (entry: HaFormSchema): string =>
|
||||
this.addon.translations[this.hass.language]?.configuration?.[entry.name]
|
||||
?.name ||
|
||||
this.addon.translations.en?.configuration?.[entry.name].name ||
|
||||
entry.name;
|
||||
public computeLabel = (entry: HaFormSchema): string => {
|
||||
return (
|
||||
this.addon.translations[this.hass.language]?.configuration?.[entry.name]
|
||||
?.name ||
|
||||
this.addon.translations.en?.configuration?.[entry.name].name ||
|
||||
entry.name
|
||||
);
|
||||
};
|
||||
|
||||
private _filteredShchema = memoizeOne(
|
||||
(options: Record<string, unknown>, schema: HaFormSchema[]) =>
|
||||
schema.filter((entry) => entry.name in options || entry.required)
|
||||
(options: Record<string, unknown>, schema: HaFormSchema[]) => {
|
||||
return schema.filter((entry) => entry.name in options || entry.required);
|
||||
}
|
||||
);
|
||||
|
||||
protected render(): TemplateResult {
|
||||
|
@@ -79,10 +79,12 @@ class HassioAddonNetwork extends LitElement {
|
||||
"addon.configuration.network.host"
|
||||
)}
|
||||
</th>
|
||||
<th>${this.supervisor.localize("common.description")}</th>
|
||||
<th>
|
||||
${this.supervisor.localize("common.description")}
|
||||
</th>
|
||||
</tr>
|
||||
${this._config!.map(
|
||||
(item) => html`
|
||||
${this._config!.map((item) => {
|
||||
return html`
|
||||
<tr>
|
||||
<td>${item.container}</td>
|
||||
<td>
|
||||
@@ -98,8 +100,8 @@ class HassioAddonNetwork extends LitElement {
|
||||
</td>
|
||||
<td>${this._computeDescription(item)}</td>
|
||||
</tr>
|
||||
`
|
||||
)}
|
||||
`;
|
||||
})}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
@@ -122,20 +124,25 @@ class HassioAddonNetwork extends LitElement {
|
||||
}
|
||||
}
|
||||
|
||||
private _computeDescription = (item: NetworkItem): string =>
|
||||
this.addon.translations[this.hass.language]?.network?.[item.container]
|
||||
?.description ||
|
||||
this.addon.translations.en?.network?.[item.container]?.description ||
|
||||
item.description;
|
||||
private _computeDescription = (item: NetworkItem): string => {
|
||||
return (
|
||||
this.addon.translations[this.hass.language]?.network?.[item.container]
|
||||
?.description ||
|
||||
this.addon.translations.en?.network?.[item.container]?.description ||
|
||||
item.description
|
||||
);
|
||||
};
|
||||
|
||||
private _setNetworkConfig(): void {
|
||||
const network = this.addon.network || {};
|
||||
const description = this.addon.network_description || {};
|
||||
const items: NetworkItem[] = Object.keys(network).map((key) => ({
|
||||
container: key,
|
||||
host: network[key],
|
||||
description: description[key],
|
||||
}));
|
||||
const items: NetworkItem[] = Object.keys(network).map((key) => {
|
||||
return {
|
||||
container: key,
|
||||
host: network[key],
|
||||
description: description[key],
|
||||
};
|
||||
});
|
||||
this._config = items.sort((a, b) => (a.container > b.container ? 1 : -1));
|
||||
}
|
||||
|
||||
|
@@ -261,9 +261,13 @@ class HassioAddonInfo extends LitElement {
|
||||
${this.supervisor.localize(
|
||||
"addon.dashboard.visit_addon_page",
|
||||
"name",
|
||||
html`<a href="${this.addon.url!}" target="_blank" rel="noreferrer"
|
||||
>${this.addon.name}</a
|
||||
>`
|
||||
html`<a
|
||||
href="${this.addon.url!}"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
>
|
||||
${this.addon.name}
|
||||
</a>`
|
||||
)}
|
||||
</div>
|
||||
<div class="addon-container">
|
||||
@@ -562,7 +566,9 @@ class HassioAddonInfo extends LitElement {
|
||||
<span slot="heading">
|
||||
${this.supervisor.localize("addon.dashboard.hostname")}
|
||||
</span>
|
||||
<code slot="description"> ${this.addon.hostname} </code>
|
||||
<code slot="description">
|
||||
${this.addon.hostname}
|
||||
</code>
|
||||
</ha-settings-row>
|
||||
${metrics.map(
|
||||
(metric) =>
|
||||
@@ -991,7 +997,7 @@ class HassioAddonInfo extends LitElement {
|
||||
addons: [this.addon.slug],
|
||||
homeassistant: false,
|
||||
},
|
||||
updateHandler: async () => this._updateAddon(),
|
||||
updateHandler: async () => await this._updateAddon(),
|
||||
});
|
||||
}
|
||||
|
||||
|
@@ -56,13 +56,13 @@ class HassioCardContent extends LitElement {
|
||||
></ha-svg-icon>
|
||||
`}
|
||||
<div>
|
||||
<div class="title">${this.title}</div>
|
||||
<div class="title">
|
||||
${this.title}
|
||||
</div>
|
||||
<div class="addition">
|
||||
${this.description}
|
||||
${
|
||||
/* treat as available when undefined */
|
||||
this.available === false ? " (Not available)" : ""
|
||||
}
|
||||
${/* treat as available when undefined */
|
||||
this.available === false ? " (Not available)" : ""}
|
||||
${this.datetime
|
||||
? html`
|
||||
<ha-relative-time
|
||||
|
@@ -23,9 +23,13 @@ class SupervisorMetric extends LitElement {
|
||||
protected render(): TemplateResult {
|
||||
const roundedValue = roundWithOneDecimal(this.value);
|
||||
return html`<ha-settings-row>
|
||||
<span slot="heading"> ${this.description} </span>
|
||||
<span slot="heading">
|
||||
${this.description}
|
||||
</span>
|
||||
<div slot="description" .title=${this.tooltip ?? ""}>
|
||||
<span class="value"> ${roundedValue} % </span>
|
||||
<span class="value">
|
||||
${roundedValue} %
|
||||
</span>
|
||||
<ha-bar
|
||||
class="${classMap({
|
||||
"target-warning": roundedValue > 50,
|
||||
|
@@ -40,8 +40,9 @@ import { HomeAssistant } from "../../../src/types";
|
||||
import { showDialogSupervisorUpdate } from "../dialogs/update/show-dialog-update";
|
||||
import { hassioStyle } from "../resources/hassio-style";
|
||||
|
||||
const computeVersion = (key: string, version: string): string =>
|
||||
key === "os" ? version : `${key}-${version}`;
|
||||
const computeVersion = (key: string, version: string): string => {
|
||||
return key === "os" ? version : `${key}-${version}`;
|
||||
};
|
||||
|
||||
@customElement("hassio-update")
|
||||
export class HassioUpdate extends LitElement {
|
||||
@@ -49,12 +50,11 @@ export class HassioUpdate extends LitElement {
|
||||
|
||||
@property({ attribute: false }) public supervisor!: Supervisor;
|
||||
|
||||
private _pendingUpdates = memoizeOne(
|
||||
(supervisor: Supervisor): number =>
|
||||
Object.keys(supervisor).filter(
|
||||
(value) => supervisor[value].update_available
|
||||
).length
|
||||
);
|
||||
private _pendingUpdates = memoizeOne((supervisor: Supervisor): number => {
|
||||
return Object.keys(supervisor).filter(
|
||||
(value) => supervisor[value].update_available
|
||||
).length;
|
||||
});
|
||||
|
||||
protected render(): TemplateResult {
|
||||
if (!this.supervisor) {
|
||||
|
@@ -47,8 +47,7 @@ import { HassioNetworkDialogParams } from "./show-dialog-network";
|
||||
const IP_VERSIONS = ["ipv4", "ipv6"];
|
||||
|
||||
@customElement("dialog-hassio-network")
|
||||
export class DialogHassioNetwork
|
||||
extends LitElement
|
||||
export class DialogHassioNetwork extends LitElement
|
||||
implements HassDialog<HassioNetworkDialogParams> {
|
||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||
|
||||
@@ -77,9 +76,9 @@ export class DialogHassioNetwork
|
||||
this._dirty = false;
|
||||
this._curTabIndex = 0;
|
||||
this.supervisor = params.supervisor;
|
||||
this._interfaces = params.supervisor.network.interfaces.sort((a, b) =>
|
||||
a.primary > b.primary ? -1 : 1
|
||||
);
|
||||
this._interfaces = params.supervisor.network.interfaces.sort((a, b) => {
|
||||
return a.primary > b.primary ? -1 : 1;
|
||||
});
|
||||
this._interface = { ...this._interfaces[this._curTabIndex] };
|
||||
|
||||
await this.updateComplete;
|
||||
|
@@ -108,8 +108,8 @@ class HassioRegistriesDialog extends LitElement {
|
||||
</mwc-button>
|
||||
`
|
||||
: html`${this._registries?.length
|
||||
? this._registries.map(
|
||||
(entry) => html`
|
||||
? this._registries.map((entry) => {
|
||||
return html`
|
||||
<mwc-list-item class="option" hasMeta twoline>
|
||||
<span>${entry.registry}</span>
|
||||
<span slot="secondary"
|
||||
@@ -129,8 +129,8 @@ class HassioRegistriesDialog extends LitElement {
|
||||
<ha-svg-icon .path=${mdiDelete}></ha-svg-icon>
|
||||
</mwc-icon-button>
|
||||
</mwc-list-item>
|
||||
`
|
||||
)
|
||||
`;
|
||||
})
|
||||
: html`
|
||||
<mwc-list-item>
|
||||
<span
|
||||
|
@@ -43,7 +43,7 @@ class HassioRepositoriesDialog extends LitElement {
|
||||
|
||||
@internalProperty() private _opened = false;
|
||||
|
||||
@internalProperty() private _processing = false;
|
||||
@internalProperty() private _prosessing = false;
|
||||
|
||||
@internalProperty() private _error?: string;
|
||||
|
||||
@@ -87,8 +87,8 @@ class HassioRepositoriesDialog extends LitElement {
|
||||
${this._error ? html`<div class="error">${this._error}</div>` : ""}
|
||||
<div class="form">
|
||||
${repositories.length
|
||||
? repositories.map(
|
||||
(repo) => html`
|
||||
? repositories.map((repo) => {
|
||||
return html`
|
||||
<paper-item class="option">
|
||||
<paper-item-body three-line>
|
||||
<div>${repo.name}</div>
|
||||
@@ -105,9 +105,13 @@ class HassioRepositoriesDialog extends LitElement {
|
||||
<ha-svg-icon .path=${mdiDelete}></ha-svg-icon>
|
||||
</mwc-icon-button>
|
||||
</paper-item>
|
||||
`
|
||||
)
|
||||
: html` <paper-item> No repositories </paper-item> `}
|
||||
`;
|
||||
})
|
||||
: html`
|
||||
<paper-item>
|
||||
No repositories
|
||||
</paper-item>
|
||||
`}
|
||||
<div class="layout horizontal bottom">
|
||||
<paper-input
|
||||
class="flex-auto"
|
||||
@@ -119,11 +123,8 @@ class HassioRepositoriesDialog extends LitElement {
|
||||
@keydown=${this._handleKeyAdd}
|
||||
></paper-input>
|
||||
<mwc-button @click=${this._addRepository}>
|
||||
${this._processing
|
||||
? html`<ha-circular-progress
|
||||
active
|
||||
size="small"
|
||||
></ha-circular-progress>`
|
||||
${this._prosessing
|
||||
? html`<ha-circular-progress active></ha-circular-progress>`
|
||||
: this._dialogParams!.supervisor.localize(
|
||||
"dialog.repositories.add"
|
||||
)}
|
||||
@@ -204,9 +205,11 @@ class HassioRepositoriesDialog extends LitElement {
|
||||
if (!input || !input.value) {
|
||||
return;
|
||||
}
|
||||
this._processing = true;
|
||||
this._prosessing = true;
|
||||
const repositories = this._filteredRepositories(this._repositories!);
|
||||
const newRepositories = repositories.map((repo) => repo.source);
|
||||
const newRepositories = repositories.map((repo) => {
|
||||
return repo.source;
|
||||
});
|
||||
newRepositories.push(input.value);
|
||||
|
||||
try {
|
||||
@@ -219,19 +222,25 @@ class HassioRepositoriesDialog extends LitElement {
|
||||
} catch (err) {
|
||||
this._error = extractApiErrorMessage(err);
|
||||
}
|
||||
this._processing = false;
|
||||
this._prosessing = false;
|
||||
}
|
||||
|
||||
private async _removeRepository(ev: Event) {
|
||||
const slug = (ev.currentTarget as any).slug;
|
||||
const repositories = this._filteredRepositories(this._repositories!);
|
||||
const repository = repositories.find((repo) => repo.slug === slug);
|
||||
const repository = repositories.find((repo) => {
|
||||
return repo.slug === slug;
|
||||
});
|
||||
if (!repository) {
|
||||
return;
|
||||
}
|
||||
const newRepositories = repositories
|
||||
.map((repo) => repo.source)
|
||||
.filter((repo) => repo !== repository.source);
|
||||
.map((repo) => {
|
||||
return repo.source;
|
||||
})
|
||||
.filter((repo) => {
|
||||
return repo !== repository.source;
|
||||
});
|
||||
|
||||
try {
|
||||
await setSupervisorOption(this.hass, {
|
||||
|
@@ -18,8 +18,7 @@ import "../../components/hassio-upload-snapshot";
|
||||
import { HassioSnapshotUploadDialogParams } from "./show-dialog-snapshot-upload";
|
||||
|
||||
@customElement("dialog-hassio-snapshot-upload")
|
||||
export class DialogHassioSnapshotUpload
|
||||
extends LitElement
|
||||
export class DialogHassioSnapshotUpload extends LitElement
|
||||
implements HassDialog<HassioSnapshotUploadDialogParams> {
|
||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||
|
||||
@@ -58,7 +57,9 @@ export class DialogHassioSnapshotUpload
|
||||
>
|
||||
<div slot="heading">
|
||||
<ha-header-bar>
|
||||
<span slot="title"> Upload snapshot </span>
|
||||
<span slot="title">
|
||||
Upload snapshot
|
||||
</span>
|
||||
<mwc-icon-button slot="actionItems" dialogAction="cancel">
|
||||
<ha-svg-icon .path=${mdiClose}></ha-svg-icon>
|
||||
</mwc-icon-button>
|
||||
|
@@ -53,13 +53,14 @@ const _computeFolders = (folders) => {
|
||||
return list;
|
||||
};
|
||||
|
||||
const _computeAddons = (addons) =>
|
||||
addons.map((addon) => ({
|
||||
const _computeAddons = (addons) => {
|
||||
return addons.map((addon) => ({
|
||||
slug: addon.slug,
|
||||
name: addon.name,
|
||||
version: addon.version,
|
||||
checked: true,
|
||||
}));
|
||||
};
|
||||
|
||||
interface AddonItem {
|
||||
slug: string;
|
||||
@@ -121,7 +122,9 @@ class HassioSnapshotDialog extends LitElement {
|
||||
<ha-dialog open @closing=${this._closeDialog} .heading=${true}>
|
||||
<div slot="heading">
|
||||
<ha-header-bar>
|
||||
<span slot="title"> ${this._computeName} </span>
|
||||
<span slot="title">
|
||||
${this._computeName}
|
||||
</span>
|
||||
<mwc-icon-button slot="actionItems" dialogAction="cancel">
|
||||
<ha-svg-icon .path=${mdiClose}></ha-svg-icon>
|
||||
</mwc-icon-button>
|
||||
@@ -149,8 +152,8 @@ class HassioSnapshotDialog extends LitElement {
|
||||
? html`
|
||||
<div>Folders:</div>
|
||||
<paper-dialog-scrollable class="no-margin-top">
|
||||
${this._folders.map(
|
||||
(item) => html`
|
||||
${this._folders.map((item) => {
|
||||
return html`
|
||||
<paper-checkbox
|
||||
.checked=${item.checked}
|
||||
@change="${(ev: Event) =>
|
||||
@@ -161,8 +164,8 @@ class HassioSnapshotDialog extends LitElement {
|
||||
>
|
||||
${item.name}
|
||||
</paper-checkbox>
|
||||
`
|
||||
)}
|
||||
`;
|
||||
})}
|
||||
</paper-dialog-scrollable>
|
||||
`
|
||||
: ""}
|
||||
@@ -170,8 +173,8 @@ class HassioSnapshotDialog extends LitElement {
|
||||
? html`
|
||||
<div>Add-on:</div>
|
||||
<paper-dialog-scrollable class="no-margin-top">
|
||||
${this._addons.map(
|
||||
(item) => html`
|
||||
${this._addons.map((item) => {
|
||||
return html`
|
||||
<paper-checkbox
|
||||
.checked=${item.checked}
|
||||
@change="${(ev: Event) =>
|
||||
@@ -182,8 +185,8 @@ class HassioSnapshotDialog extends LitElement {
|
||||
>
|
||||
${item.name}
|
||||
</paper-checkbox>
|
||||
`
|
||||
)}
|
||||
`;
|
||||
})}
|
||||
</paper-dialog-scrollable>
|
||||
`
|
||||
: ""}
|
||||
|
@@ -132,7 +132,9 @@ class HassioSnapshots extends LitElement {
|
||||
</ha-button-menu>
|
||||
|
||||
<div class="content">
|
||||
<h1>${this.supervisor.localize("snapshot.create_snapshot")}</h1>
|
||||
<h1>
|
||||
${this.supervisor.localize("snapshot.create_snapshot")}
|
||||
</h1>
|
||||
<p class="description">
|
||||
${this.supervisor.localize("snapshot.description")}
|
||||
</p>
|
||||
|
@@ -178,7 +178,7 @@ class HassioCoreInfo extends LitElement {
|
||||
folders: ["homeassistant"],
|
||||
homeassistant: true,
|
||||
},
|
||||
updateHandler: async () => this._updateCore(),
|
||||
updateHandler: async () => await this._updateCore(),
|
||||
});
|
||||
}
|
||||
|
||||
|
@@ -97,7 +97,9 @@ class HassioHostInfo extends LitElement {
|
||||
<span slot="heading">
|
||||
${this.supervisor.localize("system.host.ip_address")}
|
||||
</span>
|
||||
<span slot="description"> ${primaryIpAddress} </span>
|
||||
<span slot="description">
|
||||
${primaryIpAddress}
|
||||
</span>
|
||||
<mwc-button
|
||||
.label=${this.supervisor.localize("system.host.change")}
|
||||
@click=${this._changeNetworkClicked}
|
||||
|
@@ -264,7 +264,9 @@ class HassioSupervisorInfo extends LitElement {
|
||||
title: this.supervisor.localize("system.supervisor.warning"),
|
||||
text: html`${this.supervisor.localize("system.supervisor.beta_warning")}
|
||||
<br />
|
||||
<b> ${this.supervisor.localize("system.supervisor.beta_backup")} </b>
|
||||
<b>
|
||||
${this.supervisor.localize("system.supervisor.beta_backup")}
|
||||
</b>
|
||||
<br /><br />
|
||||
${this.supervisor.localize("system.supervisor.beta_release_items")}
|
||||
<ul>
|
||||
|
@@ -87,13 +87,13 @@ class HassioSupervisorLog extends LitElement {
|
||||
attr-for-selected="provider"
|
||||
.selected=${this._selectedLogProvider}
|
||||
>
|
||||
${logProviders.map(
|
||||
(provider) => html`
|
||||
${logProviders.map((provider) => {
|
||||
return html`
|
||||
<paper-item provider=${provider.key}>
|
||||
${provider.name}
|
||||
</paper-item>
|
||||
`
|
||||
)}
|
||||
`;
|
||||
})}
|
||||
</paper-listbox>
|
||||
</paper-dropdown-menu>
|
||||
`
|
||||
|
@@ -39,7 +39,9 @@ class HassioSystem extends LitElement {
|
||||
main-page
|
||||
supervisor
|
||||
>
|
||||
<span slot="header"> ${this.supervisor.localize("panel.system")} </span>
|
||||
<span slot="header">
|
||||
${this.supervisor.localize("panel.system")}
|
||||
</span>
|
||||
<div class="content">
|
||||
<div class="card-group">
|
||||
<hassio-core-info
|
||||
|
63
package.json
63
package.json
@@ -14,10 +14,10 @@
|
||||
"format:prettier": "prettier \"**/src/**/*.{js,ts,json,css,md}\" --write",
|
||||
"lint:types": "tsc",
|
||||
"lint:lit": "lit-analyzer \"**/src/**/*.ts\" --format markdown --outFile result.md",
|
||||
"lint": "yarn run lint:eslint && yarn run lint:prettier && yarn run lint:types",
|
||||
"format": "yarn run format:eslint && yarn run format:prettier",
|
||||
"lint": "npm run lint:eslint && npm run lint:prettier && npm run lint:types",
|
||||
"format": "npm run format:eslint && npm run format:prettier",
|
||||
"mocha": "node_modules/.bin/ts-mocha -p test-mocha/tsconfig.test.json --opts test-mocha/mocha.opts",
|
||||
"test": "yarn run lint && yarn run mocha"
|
||||
"test": "npm run lint && npm run mocha"
|
||||
},
|
||||
"author": "Paulus Schoutsen <Paulus@PaulusSchoutsen.nl> (http://paulusschoutsen.nl)",
|
||||
"license": "Apache-2.0",
|
||||
@@ -115,8 +115,8 @@
|
||||
"js-yaml": "^3.13.1",
|
||||
"leaflet": "^1.4.0",
|
||||
"leaflet-draw": "^1.0.4",
|
||||
"lit-element": "^2.5.0",
|
||||
"lit-html": "^1.4.0",
|
||||
"lit-element": "^2.4.0",
|
||||
"lit-html": "^1.3.0",
|
||||
"lit-virtualizer": "^0.4.2",
|
||||
"marked": "2.0.0",
|
||||
"mdn-polyfills": "^5.16.0",
|
||||
@@ -138,26 +138,24 @@
|
||||
"vue": "^2.6.11",
|
||||
"vue2-daterange-picker": "^0.5.1",
|
||||
"web-animations-js": "^2.3.2",
|
||||
"workbox-cacheable-response": "^6.1.5",
|
||||
"workbox-core": "^6.1.5",
|
||||
"workbox-expiration": "^6.1.5",
|
||||
"workbox-precaching": "^6.1.5",
|
||||
"workbox-routing": "^6.1.5",
|
||||
"workbox-strategies": "^6.1.5",
|
||||
"workbox-core": "^5.1.3",
|
||||
"workbox-precaching": "^5.1.3",
|
||||
"workbox-routing": "^5.1.3",
|
||||
"workbox-strategies": "^5.1.3",
|
||||
"xss": "^1.0.6"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.14.0",
|
||||
"@babel/plugin-external-helpers": "^7.12.13",
|
||||
"@babel/plugin-proposal-class-properties": "^7.13.0",
|
||||
"@babel/plugin-proposal-decorators": "^7.13.15",
|
||||
"@babel/plugin-proposal-nullish-coalescing-operator": "^7.13.8",
|
||||
"@babel/plugin-proposal-object-rest-spread": "^7.13.8",
|
||||
"@babel/plugin-proposal-optional-chaining": "^7.13.12",
|
||||
"@babel/core": "^7.11.6",
|
||||
"@babel/plugin-external-helpers": "^7.10.4",
|
||||
"@babel/plugin-proposal-class-properties": "^7.10.4",
|
||||
"@babel/plugin-proposal-decorators": "^7.10.5",
|
||||
"@babel/plugin-proposal-nullish-coalescing-operator": "^7.10.4",
|
||||
"@babel/plugin-proposal-object-rest-spread": "^7.11.0",
|
||||
"@babel/plugin-proposal-optional-chaining": "^7.11.0",
|
||||
"@babel/plugin-syntax-dynamic-import": "^7.8.3",
|
||||
"@babel/plugin-syntax-import-meta": "^7.10.4",
|
||||
"@babel/preset-env": "^7.14.0",
|
||||
"@babel/preset-typescript": "^7.13.0",
|
||||
"@babel/preset-env": "^7.11.5",
|
||||
"@babel/preset-typescript": "^7.10.4",
|
||||
"@koa/cors": "^3.1.0",
|
||||
"@open-wc/dev-server-hmr": "^0.0.2",
|
||||
"@rollup/plugin-babel": "^5.2.1",
|
||||
@@ -168,6 +166,7 @@
|
||||
"@types/chai": "^4.1.7",
|
||||
"@types/chromecast-caf-receiver": "^5.0.11",
|
||||
"@types/chromecast-caf-sender": "^1.0.3",
|
||||
"@types/codemirror": "^0.0.97",
|
||||
"@types/js-yaml": "^3.12.1",
|
||||
"@types/leaflet": "^1.4.3",
|
||||
"@types/leaflet-draw": "^1.0.1",
|
||||
@@ -177,23 +176,23 @@
|
||||
"@types/resize-observer-browser": "^0.1.3",
|
||||
"@types/sortablejs": "^1.10.6",
|
||||
"@types/webspeechapi": "^0.0.29",
|
||||
"@typescript-eslint/eslint-plugin": "^4.22.0",
|
||||
"@typescript-eslint/parser": "^4.22.0",
|
||||
"@typescript-eslint/eslint-plugin": "^4.4.0",
|
||||
"@typescript-eslint/parser": "^4.4.0",
|
||||
"@web/dev-server": "^0.0.24",
|
||||
"@web/dev-server-rollup": "^0.2.11",
|
||||
"babel-loader": "^8.1.0",
|
||||
"chai": "^4.2.0",
|
||||
"cpx": "^1.5.0",
|
||||
"del": "^4.0.0",
|
||||
"eslint": "^7.25.0",
|
||||
"eslint-config-airbnb-typescript": "^12.3.1",
|
||||
"eslint-config-prettier": "^8.3.0",
|
||||
"eslint": "^6.8.0",
|
||||
"eslint-config-airbnb-typescript": "^7.2.1",
|
||||
"eslint-config-prettier": "^6.10.1",
|
||||
"eslint-import-resolver-webpack": "^0.13.0",
|
||||
"eslint-plugin-disable": "^2.0.1",
|
||||
"eslint-plugin-import": "^2.22.1",
|
||||
"eslint-plugin-lit": "^1.3.0",
|
||||
"eslint-plugin-prettier": "^3.4.0",
|
||||
"eslint-plugin-wc": "^1.3.0",
|
||||
"eslint-plugin-import": "^2.20.2",
|
||||
"eslint-plugin-lit": "^1.2.0",
|
||||
"eslint-plugin-prettier": "^3.1.3",
|
||||
"eslint-plugin-wc": "^1.2.0",
|
||||
"fancy-log": "^1.3.3",
|
||||
"fs-extra": "^7.0.1",
|
||||
"gulp": "^4.0.0",
|
||||
@@ -234,15 +233,15 @@
|
||||
"webpack-cli": "^4.5.0",
|
||||
"webpack-dev-server": "^3.11.2",
|
||||
"webpack-manifest-plugin": "^3.0.0",
|
||||
"workbox-build": "^6.1.5"
|
||||
"workbox-build": "^5.1.3"
|
||||
},
|
||||
"_comment": "Polymer fixed to 3.1 because 3.2 throws on logbook page",
|
||||
"_comment_2": "Fix in https://github.com/Polymer/polymer/pull/5569",
|
||||
"resolutions": {
|
||||
"@webcomponents/webcomponentsjs": "^2.2.10",
|
||||
"@polymer/polymer": "3.1.0",
|
||||
"lit-html": "1.4.0",
|
||||
"lit-element": "2.5.0"
|
||||
"lit-html": "1.3.0",
|
||||
"lit-element": "2.4.0"
|
||||
},
|
||||
"main": "src/home-assistant.js",
|
||||
"husky": {
|
||||
|
2
setup.py
2
setup.py
@@ -2,7 +2,7 @@ from setuptools import setup, find_packages
|
||||
|
||||
setup(
|
||||
name="home-assistant-frontend",
|
||||
version="20210503.0",
|
||||
version="20210423.0",
|
||||
description="The Home Assistant frontend",
|
||||
url="https://github.com/home-assistant/home-assistant-polymer",
|
||||
author="The Home Assistant Authors",
|
||||
|
@@ -38,7 +38,11 @@ class HaAuthFlow extends litLocalizeLiteMixin(LitElement) {
|
||||
@internalProperty() private _errorMessage?: string;
|
||||
|
||||
protected render() {
|
||||
return html` <form>${this._renderForm()}</form> `;
|
||||
return html`
|
||||
<form>
|
||||
${this._renderForm()}
|
||||
</form>
|
||||
`;
|
||||
}
|
||||
|
||||
protected firstUpdated(changedProps: PropertyValues) {
|
||||
|
@@ -17,8 +17,9 @@ export const hex2rgb = (hex: string): [number, number, number] => {
|
||||
];
|
||||
};
|
||||
|
||||
export const rgb2hex = (rgb: [number, number, number]): string =>
|
||||
`#${rgb_hex(rgb[0])}${rgb_hex(rgb[1])}${rgb_hex(rgb[2])}`;
|
||||
export const rgb2hex = (rgb: [number, number, number]): string => {
|
||||
return `#${rgb_hex(rgb[0])}${rgb_hex(rgb[1])}${rgb_hex(rgb[2])}`;
|
||||
};
|
||||
|
||||
// Conversion between LAB, XYZ and RGB from https://github.com/gka/chroma.js
|
||||
// Copyright (c) 2011-2019, Gregor Aisch
|
||||
@@ -48,10 +49,13 @@ const xyz_lab = (t: number) => {
|
||||
return t / t2 + t0;
|
||||
};
|
||||
|
||||
const xyz_rgb = (r: number) =>
|
||||
255 * (r <= 0.00304 ? 12.92 * r : 1.055 * r ** (1 / 2.4) - 0.055);
|
||||
const xyz_rgb = (r: number) => {
|
||||
return 255 * (r <= 0.00304 ? 12.92 * r : 1.055 * r ** (1 / 2.4) - 0.055);
|
||||
};
|
||||
|
||||
const lab_xyz = (t: number) => (t > t1 ? t * t * t : t2 * (t - t0));
|
||||
const lab_xyz = (t: number) => {
|
||||
return t > t1 ? t * t * t : t2 * (t - t0);
|
||||
};
|
||||
|
||||
// Conversions between RGB and LAB
|
||||
|
||||
@@ -98,17 +102,3 @@ export const lab2hex = (lab: [number, number, number]): string => {
|
||||
const rgb = lab2rgb(lab);
|
||||
return rgb2hex(rgb);
|
||||
};
|
||||
|
||||
export const rgb2hsv = (
|
||||
rgb: [number, number, number]
|
||||
): [number, number, number] => {
|
||||
const [r, g, b] = rgb;
|
||||
const v = Math.max(r, g, b);
|
||||
const c = v - Math.min(r, g, b);
|
||||
const h =
|
||||
c && (v === r ? (g - b) / c : v === g ? 2 + (b - r) / c : 4 + (r - g) / c);
|
||||
return [60 * (h < 0 ? h + 6 : h), v && c / v, v];
|
||||
};
|
||||
|
||||
export const rgb2hs = (rgb: [number, number, number]): [number, number] =>
|
||||
rgb2hsv(rgb).slice(0, 2) as [number, number];
|
||||
|
@@ -4,9 +4,13 @@
|
||||
export const labDarken = (
|
||||
lab: [number, number, number],
|
||||
amount = 1
|
||||
): [number, number, number] => [lab[0] - 18 * amount, lab[1], lab[2]];
|
||||
): [number, number, number] => {
|
||||
return [lab[0] - 18 * amount, lab[1], lab[2]];
|
||||
};
|
||||
|
||||
export const labBrighten = (
|
||||
lab: [number, number, number],
|
||||
amount = 1
|
||||
): [number, number, number] => labDarken(lab, -amount);
|
||||
): [number, number, number] => {
|
||||
return labDarken(lab, -amount);
|
||||
};
|
||||
|
@@ -2,9 +2,12 @@ import { PageNavigation } from "../../layouts/hass-tabs-subpage";
|
||||
import { HomeAssistant } from "../../types";
|
||||
import { isComponentLoaded } from "./is_component_loaded";
|
||||
|
||||
export const canShowPage = (hass: HomeAssistant, page: PageNavigation) =>
|
||||
(isCore(page) || isLoadedIntegration(hass, page)) &&
|
||||
!hideAdvancedPage(hass, page);
|
||||
export const canShowPage = (hass: HomeAssistant, page: PageNavigation) => {
|
||||
return (
|
||||
(isCore(page) || isLoadedIntegration(hass, page)) &&
|
||||
!hideAdvancedPage(hass, page)
|
||||
);
|
||||
};
|
||||
|
||||
const isLoadedIntegration = (hass: HomeAssistant, page: PageNavigation) =>
|
||||
!page.component || isComponentLoaded(hass, page.component);
|
||||
|
@@ -86,63 +86,70 @@ export const LocalStorage = (
|
||||
storageKey?: string,
|
||||
property?: boolean,
|
||||
propertyOptions?: PropertyDeclaration
|
||||
): any => (clsElement: ClassElement) => {
|
||||
const key = String(clsElement.key);
|
||||
storageKey = storageKey || String(clsElement.key);
|
||||
const initVal = clsElement.initializer ? clsElement.initializer() : undefined;
|
||||
): any => {
|
||||
return (clsElement: ClassElement) => {
|
||||
const key = String(clsElement.key);
|
||||
storageKey = storageKey || String(clsElement.key);
|
||||
const initVal = clsElement.initializer
|
||||
? clsElement.initializer()
|
||||
: undefined;
|
||||
|
||||
storage.addFromStorage(storageKey);
|
||||
storage.addFromStorage(storageKey);
|
||||
|
||||
const subscribe = (el: UpdatingElement): UnsubscribeFunc =>
|
||||
storage.subscribeChanges(storageKey!, (oldValue) => {
|
||||
el.requestUpdate(clsElement.key, oldValue);
|
||||
});
|
||||
const subscribe = (el: UpdatingElement): UnsubscribeFunc =>
|
||||
storage.subscribeChanges(storageKey!, (oldValue) => {
|
||||
el.requestUpdate(clsElement.key, oldValue);
|
||||
});
|
||||
|
||||
const getValue = (): any =>
|
||||
storage.hasKey(storageKey!) ? storage.getValue(storageKey!) : initVal;
|
||||
const getValue = (): any => {
|
||||
return storage.hasKey(storageKey!)
|
||||
? storage.getValue(storageKey!)
|
||||
: initVal;
|
||||
};
|
||||
|
||||
const setValue = (el: UpdatingElement, value: any) => {
|
||||
let oldValue: unknown | undefined;
|
||||
if (property) {
|
||||
oldValue = getValue();
|
||||
}
|
||||
storage.setValue(storageKey!, value);
|
||||
if (property) {
|
||||
el.requestUpdate(clsElement.key, oldValue);
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
kind: "method",
|
||||
placement: "prototype",
|
||||
key: clsElement.key,
|
||||
descriptor: {
|
||||
set(this: UpdatingElement, value: unknown) {
|
||||
setValue(this, value);
|
||||
},
|
||||
get() {
|
||||
return getValue();
|
||||
},
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
},
|
||||
finisher(cls: typeof UpdatingElement) {
|
||||
const setValue = (el: UpdatingElement, value: any) => {
|
||||
let oldValue: unknown | undefined;
|
||||
if (property) {
|
||||
const connectedCallback = cls.prototype.connectedCallback;
|
||||
const disconnectedCallback = cls.prototype.disconnectedCallback;
|
||||
cls.prototype.connectedCallback = function () {
|
||||
connectedCallback.call(this);
|
||||
this[`__unbsubLocalStorage${key}`] = subscribe(this);
|
||||
};
|
||||
cls.prototype.disconnectedCallback = function () {
|
||||
disconnectedCallback.call(this);
|
||||
this[`__unbsubLocalStorage${key}`]();
|
||||
};
|
||||
cls.createProperty(clsElement.key, {
|
||||
noAccessor: true,
|
||||
...propertyOptions,
|
||||
});
|
||||
oldValue = getValue();
|
||||
}
|
||||
},
|
||||
storage.setValue(storageKey!, value);
|
||||
if (property) {
|
||||
el.requestUpdate(clsElement.key, oldValue);
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
kind: "method",
|
||||
placement: "prototype",
|
||||
key: clsElement.key,
|
||||
descriptor: {
|
||||
set(this: UpdatingElement, value: unknown) {
|
||||
setValue(this, value);
|
||||
},
|
||||
get() {
|
||||
return getValue();
|
||||
},
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
},
|
||||
finisher(cls: typeof UpdatingElement) {
|
||||
if (property) {
|
||||
const connectedCallback = cls.prototype.connectedCallback;
|
||||
const disconnectedCallback = cls.prototype.disconnectedCallback;
|
||||
cls.prototype.connectedCallback = function () {
|
||||
connectedCallback.call(this);
|
||||
this[`__unbsubLocalStorage${key}`] = subscribe(this);
|
||||
};
|
||||
cls.prototype.disconnectedCallback = function () {
|
||||
disconnectedCallback.call(this);
|
||||
this[`__unbsubLocalStorage${key}`]();
|
||||
};
|
||||
cls.createProperty(clsElement.key, {
|
||||
noAccessor: true,
|
||||
...propertyOptions,
|
||||
});
|
||||
}
|
||||
},
|
||||
};
|
||||
};
|
||||
};
|
||||
|
@@ -1,33 +1,33 @@
|
||||
import type { LitElement } from "lit-element";
|
||||
import type { ClassElement } from "../../types";
|
||||
|
||||
export const restoreScroll = (selector: string): any => (
|
||||
element: ClassElement
|
||||
) => ({
|
||||
kind: "method",
|
||||
placement: "prototype",
|
||||
key: element.key,
|
||||
descriptor: {
|
||||
set(this: LitElement, value: number) {
|
||||
this[`__${String(element.key)}`] = value;
|
||||
export const restoreScroll = (selector: string): any => {
|
||||
return (element: ClassElement) => ({
|
||||
kind: "method",
|
||||
placement: "prototype",
|
||||
key: element.key,
|
||||
descriptor: {
|
||||
set(this: LitElement, value: number) {
|
||||
this[`__${String(element.key)}`] = value;
|
||||
},
|
||||
get(this: LitElement) {
|
||||
return this[`__${String(element.key)}`];
|
||||
},
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
},
|
||||
get(this: LitElement) {
|
||||
return this[`__${String(element.key)}`];
|
||||
},
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
},
|
||||
finisher(cls: typeof LitElement) {
|
||||
const connectedCallback = cls.prototype.connectedCallback;
|
||||
cls.prototype.connectedCallback = function () {
|
||||
connectedCallback.call(this);
|
||||
if (this[element.key]) {
|
||||
const target = this.renderRoot.querySelector(selector);
|
||||
if (!target) {
|
||||
return;
|
||||
finisher(cls: typeof LitElement) {
|
||||
const connectedCallback = cls.prototype.connectedCallback;
|
||||
cls.prototype.connectedCallback = function () {
|
||||
connectedCallback.call(this);
|
||||
if (this[element.key]) {
|
||||
const target = this.renderRoot.querySelector(selector);
|
||||
if (!target) {
|
||||
return;
|
||||
}
|
||||
target.scrollTop = this[element.key];
|
||||
}
|
||||
target.scrollTop = this[element.key];
|
||||
}
|
||||
};
|
||||
},
|
||||
});
|
||||
};
|
||||
},
|
||||
});
|
||||
};
|
||||
|
@@ -1,9 +1,13 @@
|
||||
// Load a resource and get a promise when loading done.
|
||||
// From: https://davidwalsh.name/javascript-loader
|
||||
|
||||
const _load = (tag: "link" | "script" | "img", url: string, type?: "module") =>
|
||||
const _load = (
|
||||
tag: "link" | "script" | "img",
|
||||
url: string,
|
||||
type?: "module"
|
||||
) => {
|
||||
// This promise will be used by Promise.all to determine success or failure
|
||||
new Promise((resolve, reject) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
const element = document.createElement(tag);
|
||||
let attr = "src";
|
||||
let parent = "body";
|
||||
@@ -31,6 +35,8 @@ const _load = (tag: "link" | "script" | "img", url: string, type?: "module") =>
|
||||
element[attr] = url;
|
||||
document[parent].appendChild(element);
|
||||
});
|
||||
};
|
||||
|
||||
export const loadCSS = (url: string) => _load("link", url);
|
||||
export const loadJS = (url: string) => _load("script", url);
|
||||
export const loadImg = (url: string) => _load("img", url);
|
||||
|
@@ -48,8 +48,8 @@ export const replaceTileLayer = (
|
||||
const createTileLayer = (
|
||||
leaflet: LeafletModuleType,
|
||||
darkMode: boolean
|
||||
): TileLayer =>
|
||||
leaflet.tileLayer(
|
||||
): TileLayer => {
|
||||
return leaflet.tileLayer(
|
||||
`https://{s}.basemaps.cartocdn.com/${
|
||||
darkMode ? "dark_all" : "light_all"
|
||||
}/{z}/{x}/{y}${leaflet.Browser.retina ? "@2x.png" : ".png"}`,
|
||||
@@ -61,3 +61,4 @@ const createTileLayer = (
|
||||
maxZoom: 20,
|
||||
}
|
||||
);
|
||||
};
|
||||
|
@@ -1,2 +1,3 @@
|
||||
export const computeDomain = (entityId: string): string =>
|
||||
entityId.substr(0, entityId.indexOf("."));
|
||||
export const computeDomain = (entityId: string): string => {
|
||||
return entityId.substr(0, entityId.indexOf("."));
|
||||
};
|
||||
|
@@ -1,3 +1,4 @@
|
||||
/** Compute the object ID of a state. */
|
||||
export const computeObjectId = (entityId: string): string =>
|
||||
entityId.substr(entityId.indexOf(".") + 1);
|
||||
export const computeObjectId = (entityId: string): string => {
|
||||
return entityId.substr(entityId.indexOf(".") + 1);
|
||||
};
|
||||
|
@@ -1,5 +1,6 @@
|
||||
import { HassEntity } from "home-assistant-js-websocket";
|
||||
import { computeDomain } from "./compute_domain";
|
||||
|
||||
export const computeStateDomain = (stateObj: HassEntity) =>
|
||||
computeDomain(stateObj.entity_id);
|
||||
export const computeStateDomain = (stateObj: HassEntity) => {
|
||||
return computeDomain(stateObj.entity_id);
|
||||
};
|
||||
|
@@ -1,7 +1,8 @@
|
||||
import { HassEntity } from "home-assistant-js-websocket";
|
||||
import { computeObjectId } from "./compute_object_id";
|
||||
|
||||
export const computeStateName = (stateObj: HassEntity): string =>
|
||||
stateObj.attributes.friendly_name === undefined
|
||||
export const computeStateName = (stateObj: HassEntity): string => {
|
||||
return stateObj.attributes.friendly_name === undefined
|
||||
? computeObjectId(stateObj.entity_id).replace(/_/g, " ")
|
||||
: stateObj.attributes.friendly_name || "";
|
||||
};
|
||||
|
@@ -1,4 +1,7 @@
|
||||
import { HassEntity } from "home-assistant-js-websocket";
|
||||
|
||||
export const hasLocation = (stateObj: HassEntity) =>
|
||||
"latitude" in stateObj.attributes && "longitude" in stateObj.attributes;
|
||||
export const hasLocation = (stateObj: HassEntity) => {
|
||||
return (
|
||||
"latitude" in stateObj.attributes && "longitude" in stateObj.attributes
|
||||
);
|
||||
};
|
||||
|
@@ -3,6 +3,7 @@ import { HassEntity } from "home-assistant-js-websocket";
|
||||
export const supportsFeature = (
|
||||
stateObj: HassEntity,
|
||||
feature: number
|
||||
): boolean =>
|
||||
): boolean => {
|
||||
// eslint-disable-next-line no-bitwise
|
||||
(stateObj.attributes.supported_features! & feature) !== 0;
|
||||
return (stateObj.attributes.supported_features! & feature) !== 0;
|
||||
};
|
||||
|
@@ -119,7 +119,6 @@ export const extractColors = (url: string, downsampleColors = 16) =>
|
||||
colorCount: downsampleColors,
|
||||
})
|
||||
.getPalette()
|
||||
.then(({ foreground, background }) => ({
|
||||
background: background!,
|
||||
foreground: foreground!,
|
||||
}));
|
||||
.then(({ foreground, background }) => {
|
||||
return { background: background!, foreground: foreground! };
|
||||
});
|
||||
|
@@ -71,8 +71,8 @@ type FuzzyFilterSort = <T extends ScorableTextItem>(
|
||||
items: T[]
|
||||
) => T[];
|
||||
|
||||
export const fuzzyFilterSort: FuzzyFilterSort = (filter, items) =>
|
||||
items
|
||||
export const fuzzyFilterSort: FuzzyFilterSort = (filter, items) => {
|
||||
return items
|
||||
.map((item) => {
|
||||
item.score = fuzzySequentialMatch(filter, item);
|
||||
return item;
|
||||
@@ -81,3 +81,4 @@ export const fuzzyFilterSort: FuzzyFilterSort = (filter, items) =>
|
||||
.sort(({ score: scoreA = 0 }, { score: scoreB = 0 }) =>
|
||||
scoreA > scoreB ? -1 : scoreA < scoreB ? 1 : 0
|
||||
);
|
||||
};
|
||||
|
@@ -2,7 +2,8 @@ export const afterNextRender = (cb: (value: unknown) => void): void => {
|
||||
requestAnimationFrame(() => setTimeout(cb, 0));
|
||||
};
|
||||
|
||||
export const nextRender = () =>
|
||||
new Promise((resolve) => {
|
||||
export const nextRender = () => {
|
||||
return new Promise((resolve) => {
|
||||
afterNextRender(resolve);
|
||||
});
|
||||
};
|
||||
|
@@ -69,21 +69,10 @@ class HaCallServiceButton extends EventsMixin(PolymerElement) {
|
||||
el.$.progress.actionSuccess();
|
||||
eventData.success = true;
|
||||
},
|
||||
function (err) {
|
||||
if (
|
||||
el.domain === "homeassistant" &&
|
||||
["restart", "stop"].includes(el.service) &&
|
||||
err?.error?.message &&
|
||||
err.error.message === "Connection lost"
|
||||
) {
|
||||
// We expect the service call to fail with 'Connection lost' when we restart or stop
|
||||
el.$.progress.actionSuccess();
|
||||
eventData.success = true;
|
||||
} else {
|
||||
el.$.progress.actionError();
|
||||
eventData.success = false;
|
||||
}
|
||||
function () {
|
||||
el.progress = false;
|
||||
el.$.progress.actionError();
|
||||
eventData.success = false;
|
||||
}
|
||||
)
|
||||
.then(function () {
|
||||
|
@@ -485,7 +485,9 @@ export class HaDataTable extends LitElement {
|
||||
data: DataTableRowData[],
|
||||
columns: SortableColumnContainer,
|
||||
filter: string
|
||||
): Promise<DataTableRowData[]> => filterData(data, columns, filter)
|
||||
): Promise<DataTableRowData[]> => {
|
||||
return filterData(data, columns, filter);
|
||||
}
|
||||
);
|
||||
|
||||
private _handleHeaderClick(ev: Event) {
|
||||
|
@@ -1,13 +1,13 @@
|
||||
import { Remote, wrap } from "comlink";
|
||||
import type { Api } from "./sort_filter_worker";
|
||||
import { wrap } from "comlink";
|
||||
import type { api } from "./sort_filter_worker";
|
||||
|
||||
type FilterDataType = Api["filterData"];
|
||||
type FilterDataType = api["filterData"];
|
||||
type FilterDataParamTypes = Parameters<FilterDataType>;
|
||||
|
||||
type SortDataType = Api["sortData"];
|
||||
type SortDataType = api["sortData"];
|
||||
type SortDataParamTypes = Parameters<SortDataType>;
|
||||
|
||||
let worker: Remote<Api> | undefined;
|
||||
let worker: any | undefined;
|
||||
|
||||
export const filterData = async (
|
||||
data: FilterDataParamTypes[0],
|
||||
@@ -18,7 +18,7 @@ export const filterData = async (
|
||||
worker = wrap(new Worker(new URL("./sort_filter_worker", import.meta.url)));
|
||||
}
|
||||
|
||||
return worker.filterData(data, columns, filter);
|
||||
return await worker.filterData(data, columns, filter);
|
||||
};
|
||||
|
||||
export const sortData = async (
|
||||
@@ -31,5 +31,5 @@ export const sortData = async (
|
||||
worker = wrap(new Worker(new URL("./sort_filter_worker", import.meta.url)));
|
||||
}
|
||||
|
||||
return worker.sortData(data, columns, direction, sortColumn);
|
||||
return await worker.sortData(data, columns, direction, sortColumn);
|
||||
};
|
||||
|
@@ -14,8 +14,8 @@ const filterData = (
|
||||
filter: string
|
||||
) => {
|
||||
filter = filter.toUpperCase();
|
||||
return data.filter((row) =>
|
||||
Object.entries(columns).some((columnEntry) => {
|
||||
return data.filter((row) => {
|
||||
return Object.entries(columns).some((columnEntry) => {
|
||||
const [key, column] = columnEntry;
|
||||
if (column.filterable) {
|
||||
if (
|
||||
@@ -27,8 +27,8 @@ const filterData = (
|
||||
}
|
||||
}
|
||||
return false;
|
||||
})
|
||||
);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
const sortData = (
|
||||
@@ -80,6 +80,6 @@ const api = {
|
||||
sortData,
|
||||
};
|
||||
|
||||
export type Api = typeof api;
|
||||
export type api = typeof api;
|
||||
|
||||
expose(api);
|
||||
|
@@ -64,8 +64,12 @@ export abstract class HaDeviceAutomationPicker<
|
||||
private _createNoAutomation: (deviceId?: string) => T;
|
||||
|
||||
constructor(
|
||||
localizeDeviceAutomation: HaDeviceAutomationPicker<T>["_localizeDeviceAutomation"],
|
||||
fetchDeviceAutomations: HaDeviceAutomationPicker<T>["_fetchDeviceAutomations"],
|
||||
localizeDeviceAutomation: HaDeviceAutomationPicker<
|
||||
T
|
||||
>["_localizeDeviceAutomation"],
|
||||
fetchDeviceAutomations: HaDeviceAutomationPicker<
|
||||
T
|
||||
>["_fetchDeviceAutomations"],
|
||||
createNoAutomation: HaDeviceAutomationPicker<T>["_createNoAutomation"]
|
||||
) {
|
||||
super();
|
||||
|
@@ -8,7 +8,9 @@ import "../ha-paper-dropdown-menu";
|
||||
import { HaDeviceAutomationPicker } from "./ha-device-automation-picker";
|
||||
|
||||
@customElement("ha-device-condition-picker")
|
||||
class HaDeviceConditionPicker extends HaDeviceAutomationPicker<DeviceCondition> {
|
||||
class HaDeviceConditionPicker extends HaDeviceAutomationPicker<
|
||||
DeviceCondition
|
||||
> {
|
||||
protected get NO_AUTOMATION_TEXT() {
|
||||
return this.hass.localize(
|
||||
"ui.panel.config.devices.automation.conditions.no_conditions"
|
||||
|
@@ -212,17 +212,19 @@ export class HaDevicePicker extends SubscribeMixin(LitElement) {
|
||||
);
|
||||
}
|
||||
|
||||
const outputDevices = inputDevices.map((device) => ({
|
||||
id: device.id,
|
||||
name: computeDeviceName(
|
||||
device,
|
||||
this.hass,
|
||||
deviceEntityLookup[device.id]
|
||||
),
|
||||
area: device.area_id
|
||||
? areaLookup[device.area_id].name
|
||||
: this.hass.localize("ui.components.device-picker.no_area"),
|
||||
}));
|
||||
const outputDevices = inputDevices.map((device) => {
|
||||
return {
|
||||
id: device.id,
|
||||
name: computeDeviceName(
|
||||
device,
|
||||
this.hass,
|
||||
deviceEntityLookup[device.id]
|
||||
),
|
||||
area: device.area_id
|
||||
? areaLookup[device.area_id].name
|
||||
: this.hass.localize("ui.components.device-picker.no_area"),
|
||||
};
|
||||
});
|
||||
if (!outputDevices.length) {
|
||||
return [
|
||||
{
|
||||
|
@@ -4,9 +4,9 @@ import { mixinBehaviors } from "@polymer/polymer/lib/legacy/class";
|
||||
import type { Constructor } from "../../types";
|
||||
import { HaIronFocusablesHelper } from "./ha-iron-focusables-helper";
|
||||
|
||||
const paperDialogClass = customElements.get(
|
||||
"paper-dialog"
|
||||
) as Constructor<PaperDialogElement>;
|
||||
const paperDialogClass = customElements.get("paper-dialog") as Constructor<
|
||||
PaperDialogElement
|
||||
>;
|
||||
|
||||
// behavior that will override existing iron-overlay-behavior and call the fixed implementation
|
||||
const haTabFixBehaviorImpl = {
|
||||
|
@@ -99,8 +99,12 @@ export class StateBadge extends LitElement {
|
||||
hostStyle.backgroundImage = `url(${imageUrl})`;
|
||||
this._showIcon = false;
|
||||
} else if (stateObj.state === "on") {
|
||||
if (this.stateColor !== false && stateObj.attributes.rgb_color) {
|
||||
iconStyle.color = `rgb(${stateObj.attributes.rgb_color.join(",")})`;
|
||||
if (stateObj.attributes.hs_color && this.stateColor !== false) {
|
||||
const hue = stateObj.attributes.hs_color[0];
|
||||
const sat = stateObj.attributes.hs_color[1];
|
||||
if (sat > 10) {
|
||||
iconStyle.color = `hsl(${hue}, 100%, ${100 - sat / 2}%)`;
|
||||
}
|
||||
}
|
||||
if (stateObj.attributes.brightness && this.stateColor !== false) {
|
||||
const brightness = stateObj.attributes.brightness;
|
||||
|
@@ -6,6 +6,5 @@ export const analyticsLearnMore = (hass: HomeAssistant) => html`<a
|
||||
.href=${documentationUrl(hass, "/integrations/analytics/")}
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
>
|
||||
How we process your data
|
||||
</a>`;
|
||||
>${hass.localize("ui.panel.config.core.section.core.analytics.learn_more")}</a
|
||||
>`;
|
||||
|
@@ -8,6 +8,7 @@ import {
|
||||
property,
|
||||
TemplateResult,
|
||||
} from "lit-element";
|
||||
import { isComponentLoaded } from "../common/config/is_component_loaded";
|
||||
import { fireEvent } from "../common/dom/fire_event";
|
||||
import { Analytics, AnalyticsPreferences } from "../data/analytics";
|
||||
import { haStyle } from "../resources/styles";
|
||||
@@ -16,18 +17,7 @@ import "./ha-checkbox";
|
||||
import type { HaCheckbox } from "./ha-checkbox";
|
||||
import "./ha-settings-row";
|
||||
|
||||
const ADDITIONAL_PREFERENCES = [
|
||||
{
|
||||
key: "usage",
|
||||
title: "Usage",
|
||||
description: "Details of what you use with Home Assistant",
|
||||
},
|
||||
{
|
||||
key: "statistics",
|
||||
title: "Statistical data",
|
||||
description: "Counts containing total number of datapoints",
|
||||
},
|
||||
];
|
||||
const ADDITIONAL_PREFERENCES = ["usage", "statistics"];
|
||||
|
||||
declare global {
|
||||
interface HASSDomEvents {
|
||||
@@ -57,9 +47,15 @@ export class HaAnalytics extends LitElement {
|
||||
>
|
||||
</ha-checkbox>
|
||||
</span>
|
||||
<span slot="heading" data-for="base"> Basic analytics </span>
|
||||
<span slot="heading" data-for="base">
|
||||
${this.hass.localize(
|
||||
`ui.panel.config.core.section.core.analytics.preference.base.title`
|
||||
)}
|
||||
</span>
|
||||
<span slot="description" data-for="base">
|
||||
This includes information about your system.
|
||||
${this.hass.localize(
|
||||
`ui.panel.config.core.section.core.analytics.preference.base.description`
|
||||
)}
|
||||
</span>
|
||||
</ha-settings-row>
|
||||
${ADDITIONAL_PREFERENCES.map(
|
||||
@@ -68,23 +64,44 @@ export class HaAnalytics extends LitElement {
|
||||
<span slot="prefix">
|
||||
<ha-checkbox
|
||||
@change=${this._handleRowCheckboxClick}
|
||||
.checked=${this.analytics?.preferences[preference.key]}
|
||||
.preference=${preference.key}
|
||||
name=${preference.key}
|
||||
.checked=${this.analytics?.preferences[preference]}
|
||||
.preference=${preference}
|
||||
name=${preference}
|
||||
>
|
||||
</ha-checkbox>
|
||||
${!baseEnabled
|
||||
? html`<paper-tooltip animation-delay="0" position="right">
|
||||
You need to enable basic analytics for this option to be
|
||||
available
|
||||
? html`<paper-tooltip animation-delay="0" position="right"
|
||||
>${this.hass.localize(
|
||||
"ui.panel.config.core.section.core.analytics.needs_base"
|
||||
)}
|
||||
</paper-tooltip>`
|
||||
: ""}
|
||||
</span>
|
||||
<span slot="heading" data-for=${preference.key}>
|
||||
${preference.title}
|
||||
<span slot="heading" data-for=${preference}>
|
||||
${preference === "usage"
|
||||
? isComponentLoaded(this.hass, "hassio")
|
||||
? this.hass.localize(
|
||||
`ui.panel.config.core.section.core.analytics.preference.usage_supervisor.title`
|
||||
)
|
||||
: this.hass.localize(
|
||||
`ui.panel.config.core.section.core.analytics.preference.usage.title`
|
||||
)
|
||||
: this.hass.localize(
|
||||
`ui.panel.config.core.section.core.analytics.preference.${preference}.title`
|
||||
)}
|
||||
</span>
|
||||
<span slot="description" data-for=${preference.key}>
|
||||
${preference.description}
|
||||
<span slot="description" data-for=${preference}>
|
||||
${preference !== "usage"
|
||||
? this.hass.localize(
|
||||
`ui.panel.config.core.section.core.analytics.preference.${preference}.description`
|
||||
)
|
||||
: isComponentLoaded(this.hass, "hassio")
|
||||
? this.hass.localize(
|
||||
`ui.panel.config.core.section.core.analytics.preference.usage_supervisor.description`
|
||||
)
|
||||
: this.hass.localize(
|
||||
`ui.panel.config.core.section.core.analytics.preference.usage.description`
|
||||
)}
|
||||
</span>
|
||||
</ha-settings-row>`
|
||||
)}
|
||||
@@ -99,9 +116,15 @@ export class HaAnalytics extends LitElement {
|
||||
>
|
||||
</ha-checkbox>
|
||||
</span>
|
||||
<span slot="heading" data-for="diagnostics"> Diagnostics </span>
|
||||
<span slot="heading" data-for="diagnostics">
|
||||
${this.hass.localize(
|
||||
`ui.panel.config.core.section.core.analytics.preference.diagnostics.title`
|
||||
)}
|
||||
</span>
|
||||
<span slot="description" data-for="diagnostics">
|
||||
Share crash reports when unexpected errors occur.
|
||||
${this.hass.localize(
|
||||
`ui.panel.config.core.section.core.analytics.preference.diagnostics.description`
|
||||
)}
|
||||
</span>
|
||||
</ha-settings-row>
|
||||
`;
|
||||
@@ -138,10 +161,7 @@ export class HaAnalytics extends LitElement {
|
||||
|
||||
preferences[preference] = checkbox.checked;
|
||||
|
||||
if (
|
||||
ADDITIONAL_PREFERENCES.some((entry) => entry.key === preference) &&
|
||||
checkbox.checked
|
||||
) {
|
||||
if (ADDITIONAL_PREFERENCES.includes(preference) && checkbox.checked) {
|
||||
preferences.base = true;
|
||||
} else if (preference === "base" && !checkbox.checked) {
|
||||
preferences.usage = false;
|
||||
|
@@ -391,9 +391,11 @@ export class HaAreaPicker extends SubscribeMixin(LitElement) {
|
||||
`;
|
||||
}
|
||||
|
||||
private _area = memoizeOne((areaId: string): AreaRegistryEntry | undefined =>
|
||||
this._areas?.find((area) => area.area_id === areaId)
|
||||
);
|
||||
private _area = memoizeOne((areaId: string):
|
||||
| AreaRegistryEntry
|
||||
| undefined => {
|
||||
return this._areas?.find((area) => area.area_id === areaId);
|
||||
});
|
||||
|
||||
private _clearValue(ev: Event) {
|
||||
ev.stopPropagation();
|
||||
|
@@ -36,8 +36,12 @@ class HaAttributes extends LitElement {
|
||||
).map(
|
||||
(attribute) => html`
|
||||
<div class="data-entry">
|
||||
<div class="key">${formatAttributeName(attribute)}</div>
|
||||
<div class="value">${this.formatAttribute(attribute)}</div>
|
||||
<div class="key">
|
||||
${formatAttributeName(attribute)}
|
||||
</div>
|
||||
<div class="value">
|
||||
${this.formatAttribute(attribute)}
|
||||
</div>
|
||||
</div>
|
||||
`
|
||||
)}
|
||||
@@ -88,9 +92,9 @@ class HaAttributes extends LitElement {
|
||||
if (!this.stateObj) {
|
||||
return [];
|
||||
}
|
||||
return Object.keys(this.stateObj.attributes).filter(
|
||||
(key) => filtersArray.indexOf(key) === -1
|
||||
);
|
||||
return Object.keys(this.stateObj.attributes).filter((key) => {
|
||||
return filtersArray.indexOf(key) === -1;
|
||||
});
|
||||
}
|
||||
|
||||
private formatAttribute(attribute: string): string | TemplateResult {
|
||||
|
@@ -9,7 +9,6 @@ import {
|
||||
property,
|
||||
TemplateResult,
|
||||
} from "lit-element";
|
||||
import { styleMap } from "lit-html/directives/style-map";
|
||||
import { fireEvent } from "../common/dom/fire_event";
|
||||
import type { ToggleButton } from "../types";
|
||||
import "./ha-svg-icon";
|
||||
@@ -20,8 +19,6 @@ export class HaButtonToggleGroup extends LitElement {
|
||||
|
||||
@property() public active?: string;
|
||||
|
||||
@property({ type: Boolean }) public fullWidth = false;
|
||||
|
||||
protected render(): TemplateResult {
|
||||
return html`
|
||||
<div>
|
||||
@@ -36,11 +33,6 @@ export class HaButtonToggleGroup extends LitElement {
|
||||
<ha-svg-icon .path=${button.iconPath}></ha-svg-icon>
|
||||
</mwc-icon-button>`
|
||||
: html`<mwc-button
|
||||
style=${styleMap({
|
||||
width: this.fullWidth
|
||||
? `${100 / this.buttons.length}%`
|
||||
: "initial",
|
||||
})}
|
||||
.value=${button.value}
|
||||
?active=${this.active === button.value}
|
||||
@click=${this._handleClick}
|
||||
|
@@ -124,6 +124,10 @@ export class HaCodeEditor extends UpdatingElement {
|
||||
}
|
||||
</style>`;
|
||||
|
||||
const container = document.createElement("span");
|
||||
|
||||
shadowRoot.appendChild(container);
|
||||
|
||||
this.codemirror = new this._loadedCodeMirror.EditorView({
|
||||
state: this._loadedCodeMirror.EditorState.create({
|
||||
doc: this._value,
|
||||
@@ -156,7 +160,7 @@ export class HaCodeEditor extends UpdatingElement {
|
||||
],
|
||||
}),
|
||||
root: shadowRoot,
|
||||
parent: shadowRoot,
|
||||
parent: container,
|
||||
});
|
||||
}
|
||||
|
||||
|
@@ -2,7 +2,7 @@ import { html } from "@polymer/polymer/lib/utils/html-tag";
|
||||
/* eslint-plugin-disable lit */
|
||||
import { PolymerElement } from "@polymer/polymer/polymer-element";
|
||||
import { EventsMixin } from "../mixins/events-mixin";
|
||||
import { rgb2hs } from "../common/color/convert-color";
|
||||
|
||||
/**
|
||||
* Color-picker custom element
|
||||
*
|
||||
@@ -114,12 +114,6 @@ class HaColorPicker extends EventsMixin(PolymerElement) {
|
||||
observer: "applyHsColor",
|
||||
},
|
||||
|
||||
// use these properties to update the state via attributes
|
||||
desiredRgbColor: {
|
||||
type: Object,
|
||||
observer: "applyRgbColor",
|
||||
},
|
||||
|
||||
// width, height and radius apply to the coordinates of
|
||||
// of the canvas.
|
||||
// border width are relative to these numbers
|
||||
@@ -183,11 +177,8 @@ class HaColorPicker extends EventsMixin(PolymerElement) {
|
||||
this.drawMarker();
|
||||
|
||||
if (this.desiredHsColor) {
|
||||
this.applyHsColor(this.desiredHsColor);
|
||||
}
|
||||
|
||||
if (this.desiredRgbColor) {
|
||||
this.applyRgbColor(this.desiredRgbColor);
|
||||
this.setMarkerOnColor(this.desiredHsColor);
|
||||
this.applyColorToCanvas(this.desiredHsColor);
|
||||
}
|
||||
|
||||
this.interactionLayer.addEventListener("mousedown", (ev) =>
|
||||
@@ -291,13 +282,12 @@ class HaColorPicker extends EventsMixin(PolymerElement) {
|
||||
processUserSelect(ev) {
|
||||
const canvasXY = this.convertToCanvasCoordinates(ev.clientX, ev.clientY);
|
||||
const hs = this.getColor(canvasXY.x, canvasXY.y);
|
||||
const rgb = this.getRgbColor(canvasXY.x, canvasXY.y);
|
||||
this.onColorSelect(hs, rgb);
|
||||
this.onColorSelect(hs);
|
||||
}
|
||||
|
||||
// apply color to marker position and canvas
|
||||
onColorSelect(hs, rgb) {
|
||||
this.setMarkerOnColor(hs); // marker always follows mouse 'raw' hs value (= mouse position)
|
||||
onColorSelect(hs) {
|
||||
this.setMarkerOnColor(hs); // marker always follows mounse 'raw' hs value (= mouse position)
|
||||
if (!this.ignoreSegments) {
|
||||
// apply segments if needed
|
||||
hs = this.applySegmentFilter(hs);
|
||||
@@ -311,11 +301,11 @@ class HaColorPicker extends EventsMixin(PolymerElement) {
|
||||
// eventually after throttle limit has passed
|
||||
clearTimeout(this.ensureFinalSelect);
|
||||
this.ensureFinalSelect = setTimeout(() => {
|
||||
this.fireColorSelected(hs, rgb); // do it for the final time
|
||||
this.fireColorSelected(hs); // do it for the final time
|
||||
}, this.throttle);
|
||||
return;
|
||||
}
|
||||
this.fireColorSelected(hs, rgb); // do it
|
||||
this.fireColorSelected(hs); // do it
|
||||
this.colorSelectIsThrottled = true;
|
||||
setTimeout(() => {
|
||||
this.colorSelectIsThrottled = false;
|
||||
@@ -323,9 +313,9 @@ class HaColorPicker extends EventsMixin(PolymerElement) {
|
||||
}
|
||||
|
||||
// set color values and fire colorselected event
|
||||
fireColorSelected(hs, rgb) {
|
||||
fireColorSelected(hs) {
|
||||
this.hsColor = hs;
|
||||
this.fire("colorselected", { hs, rgb });
|
||||
this.fire("colorselected", { hs: { h: hs.h, s: hs.s } });
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -373,11 +363,6 @@ class HaColorPicker extends EventsMixin(PolymerElement) {
|
||||
this.applyColorToCanvas(hs);
|
||||
}
|
||||
|
||||
applyRgbColor(rgb) {
|
||||
const [h, s] = rgb2hs(rgb);
|
||||
this.applyHsColor({ h, s });
|
||||
}
|
||||
|
||||
/*
|
||||
* input processing helpers
|
||||
*/
|
||||
@@ -410,15 +395,6 @@ class HaColorPicker extends EventsMixin(PolymerElement) {
|
||||
return { h: hue, s: sat };
|
||||
}
|
||||
|
||||
getRgbColor(x, y) {
|
||||
// get current pixel
|
||||
const imageData = this.backgroundLayer
|
||||
.getContext("2d")
|
||||
.getImageData(x + 250, y + 250, 1, 1);
|
||||
const pixel = imageData.data;
|
||||
return { r: pixel[0], g: pixel[1], b: pixel[2] };
|
||||
}
|
||||
|
||||
applySegmentFilter(hs) {
|
||||
// apply hue segment steps
|
||||
if (this.hueSegments) {
|
||||
@@ -492,7 +468,7 @@ class HaColorPicker extends EventsMixin(PolymerElement) {
|
||||
.getPropertyValue("--wheel-bordercolor")
|
||||
.trim();
|
||||
const wheelShadow = wheelStyle.getPropertyValue("--wheel-shadow").trim();
|
||||
// extract shadow properties from CSS variable
|
||||
// extract shadow properties from CCS variable
|
||||
// the shadow should be defined as: "10px 5px 5px 0px COLOR"
|
||||
if (wheelShadow !== "none") {
|
||||
const values = wheelShadow.split("px ");
|
||||
|
@@ -45,13 +45,16 @@ const i18n = {
|
||||
clear: "Clear",
|
||||
today: "Today",
|
||||
cancel: "Cancel",
|
||||
formatTitle: (monthName, fullYear) => monthName + " " + fullYear,
|
||||
formatDate: (d: { day: number; month: number; year: number }) =>
|
||||
[
|
||||
formatTitle: (monthName, fullYear) => {
|
||||
return monthName + " " + fullYear;
|
||||
},
|
||||
formatDate: (d: { day: number; month: number; year: number }) => {
|
||||
return [
|
||||
("0000" + String(d.year)).slice(-4),
|
||||
("0" + String(d.month + 1)).slice(-2),
|
||||
("0" + String(d.day)).slice(-2),
|
||||
].join("-"),
|
||||
].join("-");
|
||||
},
|
||||
parseDate: (text: string) => {
|
||||
const parts = text.split("-");
|
||||
const today = new Date();
|
||||
|
@@ -88,7 +88,9 @@ export class HaDateRangePicker extends LitElement {
|
||||
>
|
||||
<mwc-list @action=${this._setDateRange} activatable>
|
||||
${Object.keys(this.ranges).map(
|
||||
(name) => html`<mwc-list-item> ${name} </mwc-list-item>`
|
||||
(name) => html`<mwc-list-item>
|
||||
${name}
|
||||
</mwc-list-item>`
|
||||
)}
|
||||
</mwc-list>
|
||||
</div>`
|
||||
|
@@ -28,7 +28,9 @@ export class HaDialog extends MwcDialog {
|
||||
}
|
||||
|
||||
protected renderHeading() {
|
||||
return html`<slot name="heading"> ${super.renderHeading()} </slot>`;
|
||||
return html`<slot name="heading">
|
||||
${super.renderHeading()}
|
||||
</slot>`;
|
||||
}
|
||||
|
||||
protected static get styles(): CSSResult[] {
|
||||
|
@@ -79,7 +79,9 @@ export class HaFileUpload extends LitElement {
|
||||
dragged: this._drag,
|
||||
})}
|
||||
>
|
||||
<label for="input" slot="label"> ${this.label} </label>
|
||||
<label for="input" slot="label">
|
||||
${this.label}
|
||||
</label>
|
||||
<iron-input slot="input">
|
||||
<input
|
||||
id="input"
|
||||
|
@@ -80,22 +80,20 @@ export class HaFormMultiSelect extends LitElement implements HaFormElement {
|
||||
@selected-items-changed=${this._valueChanged}
|
||||
@iron-select=${this._onSelect}
|
||||
>
|
||||
${
|
||||
// TS doesn't work with union array types https://github.com/microsoft/TypeScript/issues/36390
|
||||
// @ts-ignore
|
||||
options.map((item: string | [string, string]) => {
|
||||
const value = this._optionValue(item);
|
||||
return html`
|
||||
<paper-icon-item .itemValue=${value}>
|
||||
<paper-checkbox
|
||||
.checked=${data.includes(value)}
|
||||
slot="item-icon"
|
||||
></paper-checkbox>
|
||||
${this._optionLabel(item)}
|
||||
</paper-icon-item>
|
||||
`;
|
||||
})
|
||||
}
|
||||
${// TS doesn't work with union array types https://github.com/microsoft/TypeScript/issues/36390
|
||||
// @ts-ignore
|
||||
options.map((item: string | [string, string]) => {
|
||||
const value = this._optionValue(item);
|
||||
return html`
|
||||
<paper-icon-item .itemValue=${value}>
|
||||
<paper-checkbox
|
||||
.checked=${data.includes(value)}
|
||||
slot="item-icon"
|
||||
></paper-checkbox>
|
||||
${this._optionLabel(item)}
|
||||
</paper-icon-item>
|
||||
`;
|
||||
})}
|
||||
</paper-listbox>
|
||||
</paper-menu-button>
|
||||
`;
|
||||
|
@@ -41,17 +41,15 @@ export class HaFormSelect extends LitElement implements HaFormElement {
|
||||
.selected=${this.data}
|
||||
@selected-item-changed=${this._valueChanged}
|
||||
>
|
||||
${
|
||||
// TS doesn't work with union array types https://github.com/microsoft/TypeScript/issues/36390
|
||||
// @ts-ignore
|
||||
this.schema.options!.map(
|
||||
(item: string | [string, string]) => html`
|
||||
<paper-item .itemValue=${this._optionValue(item)}>
|
||||
${this._optionLabel(item)}
|
||||
</paper-item>
|
||||
`
|
||||
)
|
||||
}
|
||||
${// TS doesn't work with union array types https://github.com/microsoft/TypeScript/issues/36390
|
||||
// @ts-ignore
|
||||
this.schema.options!.map(
|
||||
(item: string | [string, string]) => html`
|
||||
<paper-item .itemValue=${this._optionValue(item)}>
|
||||
${this._optionLabel(item)}
|
||||
</paper-item>
|
||||
`
|
||||
)}
|
||||
</paper-listbox>
|
||||
</ha-paper-dropdown-menu>
|
||||
`;
|
||||
|
@@ -4,9 +4,9 @@ import { style } from "@material/mwc-formfield/mwc-formfield-css";
|
||||
import { css, CSSResult, customElement } from "lit-element";
|
||||
import { Constructor } from "../types";
|
||||
|
||||
const MwcFormfield = customElements.get(
|
||||
"mwc-formfield"
|
||||
) as Constructor<Formfield>;
|
||||
const MwcFormfield = customElements.get("mwc-formfield") as Constructor<
|
||||
Formfield
|
||||
>;
|
||||
|
||||
@customElement("ha-formfield")
|
||||
export class HaFormfield extends MwcFormfield {
|
||||
|
@@ -36,7 +36,9 @@ export class HaSelectSelector extends LitElement {
|
||||
>
|
||||
${this.selector.select.options.map(
|
||||
(item: string) => html`
|
||||
<paper-item .itemValue=${item}> ${item} </paper-item>
|
||||
<paper-item .itemValue=${item}>
|
||||
${item}
|
||||
</paper-item>
|
||||
`
|
||||
)}
|
||||
</paper-listbox>
|
||||
|
@@ -140,11 +140,13 @@ export class HaServiceControl extends LitElement {
|
||||
|
||||
const fields = Object.entries(
|
||||
serviceDomains[domain][serviceName].fields
|
||||
).map(([key, value]) => ({
|
||||
key,
|
||||
...value,
|
||||
selector: value.selector as Selector | undefined,
|
||||
}));
|
||||
).map(([key, value]) => {
|
||||
return {
|
||||
key,
|
||||
...value,
|
||||
selector: value.selector as Selector | undefined,
|
||||
};
|
||||
});
|
||||
return {
|
||||
...serviceDomains[domain][serviceName],
|
||||
fields,
|
||||
|
@@ -5,9 +5,9 @@ import type { PaperTabsElement } from "@polymer/paper-tabs/paper-tabs";
|
||||
import { customElement } from "lit-element";
|
||||
import { Constructor } from "../types";
|
||||
|
||||
const PaperTabs = customElements.get(
|
||||
"paper-tabs"
|
||||
) as Constructor<PaperTabsElement>;
|
||||
const PaperTabs = customElements.get("paper-tabs") as Constructor<
|
||||
PaperTabsElement
|
||||
>;
|
||||
|
||||
let subTemplate: HTMLTemplateElement;
|
||||
|
||||
|
@@ -2,9 +2,9 @@ import "@polymer/paper-toast/paper-toast";
|
||||
import type { PaperToastElement } from "@polymer/paper-toast/paper-toast";
|
||||
import type { Constructor } from "../types";
|
||||
|
||||
const PaperToast = customElements.get(
|
||||
"paper-toast"
|
||||
) as Constructor<PaperToastElement>;
|
||||
const PaperToast = customElements.get("paper-toast") as Constructor<
|
||||
PaperToastElement
|
||||
>;
|
||||
|
||||
export class HaToast extends PaperToast {
|
||||
private _resizeListener?: (obj: { matches: boolean }) => unknown;
|
||||
|
@@ -122,7 +122,9 @@ export class HaMediaPlayerBrowse extends LitElement {
|
||||
});
|
||||
} else {
|
||||
return html`
|
||||
<div class="container">${this._renderError(this._error)}</div>
|
||||
<div class="container">
|
||||
${this._renderError(this._error)}
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
}
|
||||
@@ -200,7 +202,13 @@ export class HaMediaPlayerBrowse extends LitElement {
|
||||
`
|
||||
: ""}
|
||||
<h1 class="title">${currentItem.title}</h1>
|
||||
${subtitle ? html` <h2 class="subtitle">${subtitle}</h2> ` : ""}
|
||||
${subtitle
|
||||
? html`
|
||||
<h2 class="subtitle">
|
||||
${subtitle}
|
||||
</h2>
|
||||
`
|
||||
: ""}
|
||||
</div>
|
||||
${currentItem.can_play && (!currentItem.thumbnail || !this._narrow)
|
||||
? html`
|
||||
@@ -239,7 +247,9 @@ export class HaMediaPlayerBrowse extends LitElement {
|
||||
<div class="content" @scroll=${this._scroll} @touchmove=${this._scroll}>
|
||||
${this._error
|
||||
? html`
|
||||
<div class="container">${this._renderError(this._error)}</div>
|
||||
<div class="container">
|
||||
${this._renderError(this._error)}
|
||||
</div>
|
||||
`
|
||||
: currentItem.children?.length
|
||||
? childrenMediaClass.layout === "grid"
|
||||
|
@@ -143,7 +143,7 @@ class HatScriptGraph extends LitElement {
|
||||
const trace = this.trace.trace[path] as ChooseActionTraceStep[] | undefined;
|
||||
const trace_path = trace?.[0].result
|
||||
? trace[0].result.choice === "default"
|
||||
? [Array.isArray(config.choose) ? config.choose.length : 0]
|
||||
? [config.choose?.length || 0]
|
||||
: [trace[0].result.choice]
|
||||
: [];
|
||||
return html`
|
||||
@@ -167,33 +167,31 @@ class HatScriptGraph extends LitElement {
|
||||
nofocus
|
||||
></hat-graph-node>
|
||||
|
||||
${config.choose
|
||||
? ensureArray(config.choose)?.map((branch, i) => {
|
||||
const branch_path = `${path}/choose/${i}`;
|
||||
const track_this =
|
||||
trace !== undefined && trace[0].result?.choice === i;
|
||||
if (track_this) {
|
||||
this.trackedNodes[branch_path] = { config, path: branch_path };
|
||||
}
|
||||
return html`
|
||||
<hat-graph>
|
||||
<hat-graph-node
|
||||
.iconPath=${!trace || track_this
|
||||
? mdiCheckBoxOutline
|
||||
: mdiCheckboxBlankOutline}
|
||||
@focus=${this.selectNode(config, branch_path)}
|
||||
class=${classMap({
|
||||
active: this.selected === branch_path,
|
||||
track: track_this,
|
||||
})}
|
||||
></hat-graph-node>
|
||||
${ensureArray(branch.sequence).map((action, j) =>
|
||||
this.render_node(action, `${branch_path}/sequence/${j}`)
|
||||
)}
|
||||
</hat-graph>
|
||||
`;
|
||||
})
|
||||
: ""}
|
||||
${config.choose?.map((branch, i) => {
|
||||
const branch_path = `${path}/choose/${i}`;
|
||||
const track_this =
|
||||
trace !== undefined && trace[0].result?.choice === i;
|
||||
if (track_this) {
|
||||
this.trackedNodes[branch_path] = { config, path: branch_path };
|
||||
}
|
||||
return html`
|
||||
<hat-graph>
|
||||
<hat-graph-node
|
||||
.iconPath=${!trace || track_this
|
||||
? mdiCheckBoxOutline
|
||||
: mdiCheckboxBlankOutline}
|
||||
@focus=${this.selectNode(config, branch_path)}
|
||||
class=${classMap({
|
||||
active: this.selected === branch_path,
|
||||
track: track_this,
|
||||
})}
|
||||
></hat-graph-node>
|
||||
${ensureArray(branch.sequence).map((action, j) =>
|
||||
this.render_node(action, `${branch_path}/sequence/${j}`)
|
||||
)}
|
||||
</hat-graph>
|
||||
`;
|
||||
})}
|
||||
<hat-graph>
|
||||
<hat-graph-spacer
|
||||
class=${classMap({
|
||||
|
@@ -9,6 +9,7 @@ export interface AnalyticsPreferences {
|
||||
|
||||
export interface Analytics {
|
||||
preferences: AnalyticsPreferences;
|
||||
onboarded: boolean;
|
||||
}
|
||||
|
||||
export const getAnalyticsDetails = (hass: HomeAssistant) =>
|
||||
|
@@ -1,7 +1,8 @@
|
||||
import { Trigger, Condition } from "./automation";
|
||||
|
||||
export const describeTrigger = (trigger: Trigger) =>
|
||||
`${trigger.platform} trigger`;
|
||||
export const describeTrigger = (trigger: Trigger) => {
|
||||
return `${trigger.platform} trigger`;
|
||||
};
|
||||
|
||||
export const describeCondition = (condition: Condition) => {
|
||||
if (condition.alias) {
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user