Compare commits

..

7 Commits

Author SHA1 Message Date
Joakim Sørensen
f69bce534a Update src/dialogs/analytics/dialog-analytics-optin.ts
Co-authored-by: Bram Kragten <mail@bramkragten.nl>
2021-04-27 16:30:52 +02:00
Joakim Sørensen
575f58bd88 Update src/dialogs/analytics/dialog-analytics-optin.ts
Co-authored-by: Charles Garwood <cgarwood@gmail.com>
2021-04-27 15:28:54 +02:00
Ludeeus
35535628fc reword 2021-04-27 11:33:39 +00:00
Ludeeus
8e018c9cfe add anonymized word 2021-04-27 11:23:53 +00:00
Ludeeus
5ae268b792 add analyticsLearnMore 2021-04-27 11:09:02 +00:00
Ludeeus
329732ac30 change button wording 2021-04-27 11:08:24 +00:00
Ludeeus
7f88bab552 Add analytics dialog 2021-04-27 11:06:25 +00:00
332 changed files with 4683 additions and 6286 deletions

View File

@@ -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"],

View File

@@ -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:

View File

@@ -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;

View File

@@ -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>

View File

@@ -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",

View File

@@ -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",
},

View File

@@ -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: {} };
}
);
};

View File

@@ -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) {

View File

@@ -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);

View File

@@ -75,8 +75,4 @@ class DemoConditional extends LitElement {
}
}
declare global {
interface HTMLElementTagNameMap {
"demo-hui-conditional-card": DemoConditional;
}
}
customElements.define("demo-hui-conditional-card", DemoConditional);

View File

@@ -239,8 +239,4 @@ class DemoEntities extends LitElement {
}
}
declare global {
interface HTMLElementTagNameMap {
"demo-hui-entities-card": DemoEntities;
}
}
customElements.define("demo-hui-entities-card", DemoEntities);

View File

@@ -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);

View File

@@ -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);

View File

@@ -129,8 +129,4 @@ class DemoGaugeEntity extends LitElement {
}
}
declare global {
interface HTMLElementTagNameMap {
"demo-hui-gauge-card": DemoGaugeEntity;
}
}
customElements.define("demo-hui-gauge-card", DemoGaugeEntity);

View File

@@ -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);

View File

@@ -42,8 +42,4 @@ class DemoIframe extends LitElement {
}
}
declare global {
interface HTMLElementTagNameMap {
"demo-hui-iframe-card": DemoIframe;
}
}
customElements.define("demo-hui-iframe-card", DemoIframe);

View File

@@ -85,8 +85,4 @@ class DemoLightEntity extends LitElement {
}
}
declare global {
interface HTMLElementTagNameMap {
"demo-hui-light-card": DemoLightEntity;
}
}
customElements.define("demo-hui-light-card", DemoLightEntity);

View File

@@ -183,8 +183,4 @@ class DemoMap extends LitElement {
}
}
declare global {
interface HTMLElementTagNameMap {
"demo-hui-map-card": DemoMap;
}
}
customElements.define("demo-hui-map-card", DemoMap);

View File

@@ -276,8 +276,4 @@ class DemoMarkdown extends LitElement {
}
}
declare global {
interface HTMLElementTagNameMap {
"demo-hui-markdown-card": DemoMarkdown;
}
}
customElements.define("demo-hui-markdown-card", DemoMarkdown);

View File

@@ -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);

View File

@@ -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);

View File

@@ -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);

View File

@@ -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);

View File

@@ -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);

View File

@@ -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);

View File

@@ -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);

View File

@@ -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);

View File

@@ -96,8 +96,4 @@ class DemoThermostatEntity extends LitElement {
}
}
declare global {
interface HTMLElementTagNameMap {
"demo-hui-thermostat-card": DemoThermostatEntity;
}
}
customElements.define("demo-hui-thermostat-card", DemoThermostatEntity);

View File

@@ -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,

View File

@@ -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"],
}),
];

View File

@@ -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`

View File

@@ -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>) {

View File

@@ -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>

View File

@@ -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 {

View File

@@ -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));
}

View File

@@ -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(),
});
}

View File

@@ -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

View File

@@ -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,

View File

@@ -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) {

View File

@@ -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;

View File

@@ -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

View File

@@ -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, {

View File

@@ -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>

View File

@@ -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>
`
: ""}

View File

@@ -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>

View File

@@ -178,7 +178,7 @@ class HassioCoreInfo extends LitElement {
folders: ["homeassistant"],
homeassistant: true,
},
updateHandler: async () => this._updateCore(),
updateHandler: async () => await this._updateCore(),
});
}

View File

@@ -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}

View File

@@ -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>

View File

@@ -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>
`

View File

@@ -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

View File

@@ -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": {

View File

@@ -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",

View File

@@ -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) {

View File

@@ -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];

View File

@@ -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);
};

View File

@@ -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);

View File

@@ -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,
});
}
},
};
};
};

View File

@@ -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];
}
};
},
});
};
},
});
};

View File

@@ -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);

View File

@@ -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,
}
);
};

View File

@@ -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("."));
};

View File

@@ -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);
};

View File

@@ -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);
};

View File

@@ -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 || "";
};

View File

@@ -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
);
};

View File

@@ -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;
};

View File

@@ -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! };
});

View File

@@ -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
);
};

View File

@@ -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);
});
};

View File

@@ -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 () {

View File

@@ -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) {

View File

@@ -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);
};

View File

@@ -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);

View File

@@ -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();

View File

@@ -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"

View File

@@ -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 [
{

View File

@@ -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 = {

View File

@@ -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;

View File

@@ -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
>`;

View File

@@ -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;

View File

@@ -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();

View File

@@ -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 {

View File

@@ -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}

View File

@@ -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,
});
}

View File

@@ -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 ");

View File

@@ -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();

View File

@@ -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>`

View File

@@ -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[] {

View File

@@ -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"

View File

@@ -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>
`;

View File

@@ -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>
`;

View File

@@ -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 {

View File

@@ -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>

View File

@@ -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,

View File

@@ -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;

View File

@@ -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;

View File

@@ -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"

View File

@@ -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({

View File

@@ -9,6 +9,7 @@ export interface AnalyticsPreferences {
export interface Analytics {
preferences: AnalyticsPreferences;
onboarded: boolean;
}
export const getAnalyticsDetails = (hass: HomeAssistant) =>

View File

@@ -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