Prettier 💎 (#1737)

* Add prettier

* Apply Prettier
This commit is contained in:
Paulus Schoutsen
2018-10-11 12:22:11 +02:00
committed by GitHub
parent 3b425c3e14
commit 34bfc12647
472 changed files with 12402 additions and 9875 deletions

View File

@@ -1,5 +1,5 @@
{ {
"extends": "airbnb-base", "extends": ["airbnb-base", "prettier"],
"parserOptions": { "parserOptions": {
"ecmaFeatures": { "ecmaFeatures": {
"jsx": true, "jsx": true,
@@ -67,13 +67,11 @@
"react/no-find-dom-node": 2, "react/no-find-dom-node": 2,
"react/no-is-mounted": 2, "react/no-is-mounted": 2,
"react/jsx-no-comment-textnodes": 2, "react/jsx-no-comment-textnodes": 2,
"react/jsx-curly-spacing": 2,
"react/jsx-no-undef": 2, "react/jsx-no-undef": 2,
"react/jsx-uses-react": 2, "react/jsx-uses-react": 2,
"react/jsx-uses-vars": 2, "react/jsx-uses-vars": 2,
"no-restricted-syntax": [0, "ForOfStatement"] "no-restricted-syntax": [0, "ForOfStatement"],
"prettier/prettier": "error"
}, },
"plugins": [ "plugins": ["react", "prettier"]
"react"
]
} }

View File

@@ -1,12 +1,12 @@
import { html } from '@polymer/polymer/lib/utils/html-tag.js'; import { html } from "@polymer/polymer/lib/utils/html-tag.js";
import { PolymerElement } from '@polymer/polymer/polymer-element.js'; import { PolymerElement } from "@polymer/polymer/polymer-element.js";
import JsYaml from 'js-yaml'; import JsYaml from "js-yaml";
import HomeAssistant from '../data/hass.js'; import HomeAssistant from "../data/hass.js";
import demoConfig from '../data/demo_config.js'; import demoConfig from "../data/demo_config.js";
import demoResources from '../data/demo_resources.js'; import demoResources from "../data/demo_resources.js";
import demoStates from '../data/demo_states.js'; import demoStates from "../data/demo_states.js";
import createCardElement from '../../../src/panels/lovelace/common/create-card-element.js'; import createCardElement from "../../../src/panels/lovelace/common/create-card-element.js";
class DemoCard extends PolymerElement { class DemoCard extends PolymerElement {
static get template() { static get template() {
@@ -50,11 +50,11 @@ class DemoCard extends PolymerElement {
return { return {
hass: { hass: {
type: Object, type: Object,
observer: '_hassChanged', observer: "_hassChanged",
}, },
config: { config: {
type: Object, type: Object,
observer: '_configChanged' observer: "_configChanged",
}, },
showConfig: Boolean, showConfig: Boolean,
}; };
@@ -74,7 +74,7 @@ class DemoCard extends PolymerElement {
const hass = new HomeAssistant(demoStates); const hass = new HomeAssistant(demoStates);
hass.config = demoConfig; hass.config = demoConfig;
hass.resources = demoResources; hass.resources = demoResources;
hass.language = 'en'; hass.language = "en";
hass.states = demoStates; hass.states = demoStates;
el.hass = hass; el.hass = hass;
} }
@@ -92,4 +92,4 @@ class DemoCard extends PolymerElement {
} }
} }
customElements.define('demo-card', DemoCard); customElements.define("demo-card", DemoCard);

View File

@@ -1,9 +1,9 @@
import { html } from '@polymer/polymer/lib/utils/html-tag.js'; import { html } from "@polymer/polymer/lib/utils/html-tag.js";
import { PolymerElement } from '@polymer/polymer/polymer-element.js'; import { PolymerElement } from "@polymer/polymer/polymer-element.js";
import '@polymer/app-layout/app-toolbar/app-toolbar.js'; import "@polymer/app-layout/app-toolbar/app-toolbar.js";
import '@polymer/paper-toggle-button/paper-toggle-button.js'; import "@polymer/paper-toggle-button/paper-toggle-button.js";
import './demo-card.js'; import "./demo-card.js";
class DemoCards extends PolymerElement { class DemoCards extends PolymerElement {
static get template() { static get template() {
@@ -50,9 +50,9 @@ class DemoCards extends PolymerElement {
_showConfig: { _showConfig: {
type: Boolean, type: Boolean,
value: false, value: false,
} },
}; };
} }
} }
customElements.define('demo-cards', DemoCards); customElements.define("demo-cards", DemoCards);

View File

@@ -1,10 +1,9 @@
import { html } from '@polymer/polymer/lib/utils/html-tag.js'; import { html } from "@polymer/polymer/lib/utils/html-tag.js";
import { PolymerElement } from '@polymer/polymer/polymer-element.js'; import { PolymerElement } from "@polymer/polymer/polymer-element.js";
import '../../../src/state-summary/state-card-content.js';
import '../../../src/dialogs/more-info/controls/more-info-content.js';
import '../../../src/components/ha-card.js';
import "../../../src/state-summary/state-card-content.js";
import "../../../src/dialogs/more-info/controls/more-info-content.js";
import "../../../src/components/ha-card.js";
class DemoMoreInfo extends PolymerElement { class DemoMoreInfo extends PolymerElement {
static get template() { static get template() {
@@ -68,8 +67,8 @@ class DemoMoreInfo extends PolymerElement {
showConfig: Boolean, showConfig: Boolean,
_stateObj: { _stateObj: {
type: Object, type: Object,
computed: '_getState(entityId, hass.states)' computed: "_getState(entityId, hass.states)",
} },
}; };
} }
@@ -82,7 +81,7 @@ class DemoMoreInfo extends PolymerElement {
// (it sucks, we will remove in the future) // (it sucks, we will remove in the future)
const tmp = {}; const tmp = {};
Object.keys(stateObj).forEach((key) => { Object.keys(stateObj).forEach((key) => {
if (key[0] !== '_') { if (key[0] !== "_") {
tmp[key] = stateObj[key]; tmp[key] = stateObj[key];
} }
}); });
@@ -90,4 +89,4 @@ class DemoMoreInfo extends PolymerElement {
} }
} }
customElements.define('demo-more-info', DemoMoreInfo); customElements.define("demo-more-info", DemoMoreInfo);

View File

@@ -1,9 +1,9 @@
import { html } from '@polymer/polymer/lib/utils/html-tag.js'; import { html } from "@polymer/polymer/lib/utils/html-tag.js";
import { PolymerElement } from '@polymer/polymer/polymer-element.js'; import { PolymerElement } from "@polymer/polymer/polymer-element.js";
import '@polymer/app-layout/app-toolbar/app-toolbar.js'; import "@polymer/app-layout/app-toolbar/app-toolbar.js";
import '@polymer/paper-toggle-button/paper-toggle-button.js'; import "@polymer/paper-toggle-button/paper-toggle-button.js";
import './demo-more-info.js'; import "./demo-more-info.js";
class DemoMoreInfos extends PolymerElement { class DemoMoreInfos extends PolymerElement {
static get template() { static get template() {
@@ -50,9 +50,9 @@ class DemoMoreInfos extends PolymerElement {
_showConfig: { _showConfig: {
type: Boolean, type: Boolean,
value: false, value: false,
} },
}; };
} }
} }
customElements.define('demo-more-infos', DemoMoreInfos); customElements.define("demo-more-infos", DemoMoreInfos);

View File

@@ -4,172 +4,106 @@ export default {
latitude: 51.5287352, latitude: 51.5287352,
longitude: -0.381773, longitude: -0.381773,
unit_system: { unit_system: {
length: 'km', length: "km",
mass: 'kg', mass: "kg",
temperature: '°C', temperature: "°C",
volume: 'L' volume: "L",
} },
}, },
services: { services: {
configurator: [ configurator: ["configure"],
'configure' tts: ["demo_say", "clear_cache"],
],
tts: [
'demo_say',
'clear_cache'
],
cover: [ cover: [
'open_cover', "open_cover",
'close_cover', "close_cover",
'open_cover_tilt', "open_cover_tilt",
'close_cover_tilt', "close_cover_tilt",
'set_cover_tilt_position', "set_cover_tilt_position",
'set_cover_position', "set_cover_position",
'stop_cover_tilt', "stop_cover_tilt",
'stop_cover' "stop_cover",
],
group: [
'set',
'reload',
'remove',
'set_visibility'
], ],
group: ["set", "reload", "remove", "set_visibility"],
alarm_control_panel: [ alarm_control_panel: [
'alarm_arm_night', "alarm_arm_night",
'alarm_disarm', "alarm_disarm",
'alarm_trigger', "alarm_trigger",
'alarm_arm_home', "alarm_arm_home",
'alarm_arm_away', "alarm_arm_away",
'alarm_arm_custom_bypass' "alarm_arm_custom_bypass",
],
conversation: [
'process'
],
notify: [
'demo_test_target_name',
'notify'
],
lock: [
'open',
'lock',
'unlock'
], ],
conversation: ["process"],
notify: ["demo_test_target_name", "notify"],
lock: ["open", "lock", "unlock"],
input_select: [ input_select: [
'select_previous', "select_previous",
'set_options', "set_options",
'select_next', "select_next",
'select_option' "select_option",
],
recorder: [
'purge'
],
persistent_notification: [
'create',
'dismiss'
],
timer: [
'pause',
'cancel',
'finish',
'start'
],
input_boolean: [
'turn_off',
'toggle',
'turn_on'
], ],
recorder: ["purge"],
persistent_notification: ["create", "dismiss"],
timer: ["pause", "cancel", "finish", "start"],
input_boolean: ["turn_off", "toggle", "turn_on"],
fan: [ fan: [
'set_speed', "set_speed",
'turn_on', "turn_on",
'turn_off', "turn_off",
'set_direction', "set_direction",
'oscillate', "oscillate",
'toggle' "toggle",
], ],
climate: [ climate: [
'set_humidity', "set_humidity",
'set_operation_mode', "set_operation_mode",
'set_aux_heat', "set_aux_heat",
'turn_on', "turn_on",
'set_hold_mode', "set_hold_mode",
'set_away_mode', "set_away_mode",
'turn_off', "turn_off",
'set_fan_mode', "set_fan_mode",
'set_temperature', "set_temperature",
'set_swing_mode' "set_swing_mode",
],
switch: [
'turn_off',
'toggle',
'turn_on'
],
script: [
'turn_off',
'demo',
'reload',
'toggle',
'turn_on'
],
scene: [
'turn_on'
],
system_log: [
'clear',
'write'
],
camera: [
'disable_motion_detection',
'enable_motion_detection',
'snapshot'
],
image_processing: [
'scan'
], ],
switch: ["turn_off", "toggle", "turn_on"],
script: ["turn_off", "demo", "reload", "toggle", "turn_on"],
scene: ["turn_on"],
system_log: ["clear", "write"],
camera: ["disable_motion_detection", "enable_motion_detection", "snapshot"],
image_processing: ["scan"],
media_player: [ media_player: [
'media_previous_track', "media_previous_track",
'clear_playlist', "clear_playlist",
'shuffle_set', "shuffle_set",
'media_seek', "media_seek",
'turn_on', "turn_on",
'media_play_pause', "media_play_pause",
'media_next_track', "media_next_track",
'media_pause', "media_pause",
'volume_down', "volume_down",
'volume_set', "volume_set",
'media_stop', "media_stop",
'toggle', "toggle",
'media_play', "media_play",
'play_media', "play_media",
'volume_mute', "volume_mute",
'turn_off', "turn_off",
'select_sound_mode', "select_sound_mode",
'select_source', "select_source",
'volume_up' "volume_up",
],
input_number: [
'set_value',
'increment',
'decrement'
],
device_tracker: [
'see'
], ],
input_number: ["set_value", "increment", "decrement"],
device_tracker: ["see"],
homeassistant: [ homeassistant: [
'stop', "stop",
'check_config', "check_config",
'reload_core_config', "reload_core_config",
'turn_on', "turn_on",
'turn_off', "turn_off",
'restart', "restart",
'toggle' "toggle",
], ],
light: [ light: ["turn_off", "toggle", "turn_on"],
'turn_off', input_text: ["set_value"],
'toggle', },
'turn_on'
],
input_text: [
'set_value'
]
}
}; };

View File

@@ -1,253 +1,264 @@
export default { export default {
en: { en: {
'state.default.off': 'Off', "state.default.off": "Off",
'state.default.on': 'On', "state.default.on": "On",
'state.default.unknown': 'Unknown', "state.default.unknown": "Unknown",
'state.default.unavailable': 'Unavailable', "state.default.unavailable": "Unavailable",
'state.alarm_control_panel.armed': 'Armed', "state.alarm_control_panel.armed": "Armed",
'state.alarm_control_panel.disarmed': 'Disarmed', "state.alarm_control_panel.disarmed": "Disarmed",
'state.alarm_control_panel.armed_home': 'Armed home', "state.alarm_control_panel.armed_home": "Armed home",
'state.alarm_control_panel.armed_away': 'Armed away', "state.alarm_control_panel.armed_away": "Armed away",
'state.alarm_control_panel.armed_night': 'Armed night', "state.alarm_control_panel.armed_night": "Armed night",
'state.alarm_control_panel.armed_custom_bypass': 'Armed custom bypass', "state.alarm_control_panel.armed_custom_bypass": "Armed custom bypass",
'state.alarm_control_panel.pending': 'Pending', "state.alarm_control_panel.pending": "Pending",
'state.alarm_control_panel.arming': 'Arming', "state.alarm_control_panel.arming": "Arming",
'state.alarm_control_panel.disarming': 'Disarming', "state.alarm_control_panel.disarming": "Disarming",
'state.alarm_control_panel.triggered': 'Triggered', "state.alarm_control_panel.triggered": "Triggered",
'state.automation.off': 'Off', "state.automation.off": "Off",
'state.automation.on': 'On', "state.automation.on": "On",
'state.binary_sensor.default.off': 'Off', "state.binary_sensor.default.off": "Off",
'state.binary_sensor.default.on': 'On', "state.binary_sensor.default.on": "On",
'state.binary_sensor.battery.off': 'Normal', "state.binary_sensor.battery.off": "Normal",
'state.binary_sensor.battery.on': 'Low', "state.binary_sensor.battery.on": "Low",
'state.binary_sensor.cold.off': 'Normal', "state.binary_sensor.cold.off": "Normal",
'state.binary_sensor.cold.on': 'Cold', "state.binary_sensor.cold.on": "Cold",
'state.binary_sensor.connectivity.off': 'Disconnected', "state.binary_sensor.connectivity.off": "Disconnected",
'state.binary_sensor.connectivity.on': 'Connected', "state.binary_sensor.connectivity.on": "Connected",
'state.binary_sensor.door.off': 'Closed', "state.binary_sensor.door.off": "Closed",
'state.binary_sensor.door.on': 'Open', "state.binary_sensor.door.on": "Open",
'state.binary_sensor.garage_door.off': 'Closed', "state.binary_sensor.garage_door.off": "Closed",
'state.binary_sensor.garage_door.on': 'Open', "state.binary_sensor.garage_door.on": "Open",
'state.binary_sensor.gas.off': 'Clear', "state.binary_sensor.gas.off": "Clear",
'state.binary_sensor.gas.on': 'Detected', "state.binary_sensor.gas.on": "Detected",
'state.binary_sensor.heat.off': 'Normal', "state.binary_sensor.heat.off": "Normal",
'state.binary_sensor.heat.on': 'Hot', "state.binary_sensor.heat.on": "Hot",
'state.binary_sensor.lock.off': 'Locked', "state.binary_sensor.lock.off": "Locked",
'state.binary_sensor.lock.on': 'Unlocked', "state.binary_sensor.lock.on": "Unlocked",
'state.binary_sensor.moisture.off': 'Dry', "state.binary_sensor.moisture.off": "Dry",
'state.binary_sensor.moisture.on': 'Wet', "state.binary_sensor.moisture.on": "Wet",
'state.binary_sensor.motion.off': 'Clear', "state.binary_sensor.motion.off": "Clear",
'state.binary_sensor.motion.on': 'Detected', "state.binary_sensor.motion.on": "Detected",
'state.binary_sensor.occupancy.off': 'Clear', "state.binary_sensor.occupancy.off": "Clear",
'state.binary_sensor.occupancy.on': 'Detected', "state.binary_sensor.occupancy.on": "Detected",
'state.binary_sensor.opening.off': 'Closed', "state.binary_sensor.opening.off": "Closed",
'state.binary_sensor.opening.on': 'Open', "state.binary_sensor.opening.on": "Open",
'state.binary_sensor.presence.off': 'Away', "state.binary_sensor.presence.off": "Away",
'state.binary_sensor.presence.on': 'Home', "state.binary_sensor.presence.on": "Home",
'state.binary_sensor.problem.off': 'OK', "state.binary_sensor.problem.off": "OK",
'state.binary_sensor.problem.on': 'Problem', "state.binary_sensor.problem.on": "Problem",
'state.binary_sensor.safety.off': 'Safe', "state.binary_sensor.safety.off": "Safe",
'state.binary_sensor.safety.on': 'Unsafe', "state.binary_sensor.safety.on": "Unsafe",
'state.binary_sensor.smoke.off': 'Clear', "state.binary_sensor.smoke.off": "Clear",
'state.binary_sensor.smoke.on': 'Detected', "state.binary_sensor.smoke.on": "Detected",
'state.binary_sensor.sound.off': 'Clear', "state.binary_sensor.sound.off": "Clear",
'state.binary_sensor.sound.on': 'Detected', "state.binary_sensor.sound.on": "Detected",
'state.binary_sensor.vibration.off': 'Clear', "state.binary_sensor.vibration.off": "Clear",
'state.binary_sensor.vibration.on': 'Detected', "state.binary_sensor.vibration.on": "Detected",
'state.binary_sensor.window.off': 'Closed', "state.binary_sensor.window.off": "Closed",
'state.binary_sensor.window.on': 'Open', "state.binary_sensor.window.on": "Open",
'state.calendar.off': 'Off', "state.calendar.off": "Off",
'state.calendar.on': 'On', "state.calendar.on": "On",
'state.camera.recording': 'Recording', "state.camera.recording": "Recording",
'state.camera.streaming': 'Streaming', "state.camera.streaming": "Streaming",
'state.camera.idle': 'Idle', "state.camera.idle": "Idle",
'state.climate.off': 'Off', "state.climate.off": "Off",
'state.climate.on': 'On', "state.climate.on": "On",
'state.climate.heat': 'Heat', "state.climate.heat": "Heat",
'state.climate.cool': 'Cool', "state.climate.cool": "Cool",
'state.climate.idle': 'Idle', "state.climate.idle": "Idle",
'state.climate.auto': 'Auto', "state.climate.auto": "Auto",
'state.climate.dry': 'Dry', "state.climate.dry": "Dry",
'state.climate.fan_only': 'Fan only', "state.climate.fan_only": "Fan only",
'state.climate.eco': 'Eco', "state.climate.eco": "Eco",
'state.climate.electric': 'Electric', "state.climate.electric": "Electric",
'state.climate.performance': 'Performance', "state.climate.performance": "Performance",
'state.climate.high_demand': 'High demand', "state.climate.high_demand": "High demand",
'state.climate.heat_pump': 'Heat pump', "state.climate.heat_pump": "Heat pump",
'state.climate.gas': 'Gas', "state.climate.gas": "Gas",
'state.configurator.configure': 'Configure', "state.configurator.configure": "Configure",
'state.configurator.configured': 'Configured', "state.configurator.configured": "Configured",
'state.cover.open': 'Open', "state.cover.open": "Open",
'state.cover.opening': 'Opening', "state.cover.opening": "Opening",
'state.cover.closed': 'Closed', "state.cover.closed": "Closed",
'state.cover.closing': 'Closing', "state.cover.closing": "Closing",
'state.cover.stopped': 'Stopped', "state.cover.stopped": "Stopped",
'state.device_tracker.home': 'Home', "state.device_tracker.home": "Home",
'state.device_tracker.not_home': 'Away', "state.device_tracker.not_home": "Away",
'state.fan.off': 'Off', "state.fan.off": "Off",
'state.fan.on': 'On', "state.fan.on": "On",
'state.group.off': 'Off', "state.group.off": "Off",
'state.group.on': 'On', "state.group.on": "On",
'state.group.home': 'Home', "state.group.home": "Home",
'state.group.not_home': 'Away', "state.group.not_home": "Away",
'state.group.open': 'Open', "state.group.open": "Open",
'state.group.opening': 'Opening', "state.group.opening": "Opening",
'state.group.closed': 'Closed', "state.group.closed": "Closed",
'state.group.closing': 'Closing', "state.group.closing": "Closing",
'state.group.stopped': 'Stopped', "state.group.stopped": "Stopped",
'state.group.locked': 'Locked', "state.group.locked": "Locked",
'state.group.unlocked': 'Unlocked', "state.group.unlocked": "Unlocked",
'state.group.ok': 'OK', "state.group.ok": "OK",
'state.group.problem': 'Problem', "state.group.problem": "Problem",
'state.input_boolean.off': 'Off', "state.input_boolean.off": "Off",
'state.input_boolean.on': 'On', "state.input_boolean.on": "On",
'state.light.off': 'Off', "state.light.off": "Off",
'state.light.on': 'On', "state.light.on": "On",
'state.lock.locked': 'Locked', "state.lock.locked": "Locked",
'state.lock.unlocked': 'Unlocked', "state.lock.unlocked": "Unlocked",
'state.media_player.off': 'Off', "state.media_player.off": "Off",
'state.media_player.on': 'On', "state.media_player.on": "On",
'state.media_player.playing': 'Playing', "state.media_player.playing": "Playing",
'state.media_player.paused': 'Paused', "state.media_player.paused": "Paused",
'state.media_player.idle': 'Idle', "state.media_player.idle": "Idle",
'state.media_player.standby': 'Standby', "state.media_player.standby": "Standby",
'state.plant.ok': 'OK', "state.plant.ok": "OK",
'state.plant.problem': 'Problem', "state.plant.problem": "Problem",
'state.remote.off': 'Off', "state.remote.off": "Off",
'state.remote.on': 'On', "state.remote.on": "On",
'state.scene.scening': 'Scening', "state.scene.scening": "Scening",
'state.script.off': 'Off', "state.script.off": "Off",
'state.script.on': 'On', "state.script.on": "On",
'state.sensor.off': 'Off', "state.sensor.off": "Off",
'state.sensor.on': 'On', "state.sensor.on": "On",
'state.sun.above_horizon': 'Above horizon', "state.sun.above_horizon": "Above horizon",
'state.sun.below_horizon': 'Below horizon', "state.sun.below_horizon": "Below horizon",
'state.switch.off': 'Off', "state.switch.off": "Off",
'state.switch.on': 'On', "state.switch.on": "On",
'state.weather.clear-night': 'Clear, night', "state.weather.clear-night": "Clear, night",
'state.weather.cloudy': 'Cloudy', "state.weather.cloudy": "Cloudy",
'state.weather.fog': 'Fog', "state.weather.fog": "Fog",
'state.weather.hail': 'Hail', "state.weather.hail": "Hail",
'state.weather.lightning': 'Lightning', "state.weather.lightning": "Lightning",
'state.weather.lightning-rainy': 'Lightning, rainy', "state.weather.lightning-rainy": "Lightning, rainy",
'state.weather.partlycloudy': 'Partly cloudy', "state.weather.partlycloudy": "Partly cloudy",
'state.weather.pouring': 'Pouring', "state.weather.pouring": "Pouring",
'state.weather.rainy': 'Rainy', "state.weather.rainy": "Rainy",
'state.weather.snowy': 'Snowy', "state.weather.snowy": "Snowy",
'state.weather.snowy-rainy': 'Snowy, rainy', "state.weather.snowy-rainy": "Snowy, rainy",
'state.weather.sunny': 'Sunny', "state.weather.sunny": "Sunny",
'state.weather.windy': 'Windy', "state.weather.windy": "Windy",
'state.weather.windy-variant': 'Windy', "state.weather.windy-variant": "Windy",
'state.zwave.default.initializing': 'Initializing', "state.zwave.default.initializing": "Initializing",
'state.zwave.default.dead': 'Dead', "state.zwave.default.dead": "Dead",
'state.zwave.default.sleeping': 'Sleeping', "state.zwave.default.sleeping": "Sleeping",
'state.zwave.default.ready': 'Ready', "state.zwave.default.ready": "Ready",
'state.zwave.query_stage.initializing': 'Initializing ({query_stage})', "state.zwave.query_stage.initializing": "Initializing ({query_stage})",
'state.zwave.query_stage.dead': 'Dead ({query_stage})', "state.zwave.query_stage.dead": "Dead ({query_stage})",
'state_badge.default.unknown': 'Unk', "state_badge.default.unknown": "Unk",
'state_badge.default.unavailable': 'Unavai', "state_badge.default.unavailable": "Unavai",
'state_badge.alarm_control_panel.armed': 'Armed', "state_badge.alarm_control_panel.armed": "Armed",
'state_badge.alarm_control_panel.disarmed': 'Disarm', "state_badge.alarm_control_panel.disarmed": "Disarm",
'state_badge.alarm_control_panel.armed_home': 'Armed', "state_badge.alarm_control_panel.armed_home": "Armed",
'state_badge.alarm_control_panel.armed_away': 'Armed', "state_badge.alarm_control_panel.armed_away": "Armed",
'state_badge.alarm_control_panel.armed_night': 'Armed', "state_badge.alarm_control_panel.armed_night": "Armed",
'state_badge.alarm_control_panel.armed_custom_bypass': 'Armed', "state_badge.alarm_control_panel.armed_custom_bypass": "Armed",
'state_badge.alarm_control_panel.pending': 'Pend', "state_badge.alarm_control_panel.pending": "Pend",
'state_badge.alarm_control_panel.arming': 'Arming', "state_badge.alarm_control_panel.arming": "Arming",
'state_badge.alarm_control_panel.disarming': 'Disarm', "state_badge.alarm_control_panel.disarming": "Disarm",
'state_badge.alarm_control_panel.triggered': 'Trig', "state_badge.alarm_control_panel.triggered": "Trig",
'state_badge.device_tracker.home': 'Home', "state_badge.device_tracker.home": "Home",
'state_badge.device_tracker.not_home': 'Away', "state_badge.device_tracker.not_home": "Away",
'ui.card.alarm_control_panel.code': 'Code', "ui.card.alarm_control_panel.code": "Code",
'ui.card.alarm_control_panel.clear_code': 'Clear', "ui.card.alarm_control_panel.clear_code": "Clear",
'ui.card.alarm_control_panel.disarm': 'Disarm', "ui.card.alarm_control_panel.disarm": "Disarm",
'ui.card.alarm_control_panel.arm_home': 'Arm home', "ui.card.alarm_control_panel.arm_home": "Arm home",
'ui.card.alarm_control_panel.arm_away': 'Arm away', "ui.card.alarm_control_panel.arm_away": "Arm away",
'ui.card.automation.last_triggered': 'Last triggered', "ui.card.automation.last_triggered": "Last triggered",
'ui.card.automation.trigger': 'Trigger', "ui.card.automation.trigger": "Trigger",
'ui.card.camera.not_available': 'Image not available', "ui.card.camera.not_available": "Image not available",
'ui.card.climate.currently': 'Currently', "ui.card.climate.currently": "Currently",
'ui.card.climate.on_off': 'On / off', "ui.card.climate.on_off": "On / off",
'ui.card.climate.target_temperature': 'Target temperature', "ui.card.climate.target_temperature": "Target temperature",
'ui.card.climate.target_humidity': 'Target humidity', "ui.card.climate.target_humidity": "Target humidity",
'ui.card.climate.operation': 'Operation', "ui.card.climate.operation": "Operation",
'ui.card.climate.fan_mode': 'Fan mode', "ui.card.climate.fan_mode": "Fan mode",
'ui.card.climate.swing_mode': 'Swing mode', "ui.card.climate.swing_mode": "Swing mode",
'ui.card.climate.away_mode': 'Away mode', "ui.card.climate.away_mode": "Away mode",
'ui.card.climate.aux_heat': 'Aux heat', "ui.card.climate.aux_heat": "Aux heat",
'ui.card.cover.position': 'Position', "ui.card.cover.position": "Position",
'ui.card.cover.tilt_position': 'Tilt position', "ui.card.cover.tilt_position": "Tilt position",
'ui.card.fan.speed': 'Speed', "ui.card.fan.speed": "Speed",
'ui.card.fan.oscillate': 'Oscillate', "ui.card.fan.oscillate": "Oscillate",
'ui.card.fan.direction': 'Direction', "ui.card.fan.direction": "Direction",
'ui.card.light.brightness': 'Brightness', "ui.card.light.brightness": "Brightness",
'ui.card.light.color_temperature': 'Color temperature', "ui.card.light.color_temperature": "Color temperature",
'ui.card.light.white_value': 'White value', "ui.card.light.white_value": "White value",
'ui.card.light.effect': 'Effect', "ui.card.light.effect": "Effect",
'ui.card.lock.code': 'Code', "ui.card.lock.code": "Code",
'ui.card.lock.lock': 'Lock', "ui.card.lock.lock": "Lock",
'ui.card.lock.unlock': 'Unlock', "ui.card.lock.unlock": "Unlock",
'ui.card.media_player.source': 'Source', "ui.card.media_player.source": "Source",
'ui.card.media_player.sound_mode': 'Sound mode', "ui.card.media_player.sound_mode": "Sound mode",
'ui.card.media_player.text_to_speak': 'Text to speak', "ui.card.media_player.text_to_speak": "Text to speak",
'ui.card.persistent_notification.dismiss': 'Dismiss', "ui.card.persistent_notification.dismiss": "Dismiss",
'ui.card.scene.activate': 'Activate', "ui.card.scene.activate": "Activate",
'ui.card.script.execute': 'Execute', "ui.card.script.execute": "Execute",
'ui.card.weather.attributes.air_pressure': 'Air pressure', "ui.card.weather.attributes.air_pressure": "Air pressure",
'ui.card.weather.attributes.humidity': 'Humidity', "ui.card.weather.attributes.humidity": "Humidity",
'ui.card.weather.attributes.temperature': 'Temperature', "ui.card.weather.attributes.temperature": "Temperature",
'ui.card.weather.attributes.visibility': 'Visibility', "ui.card.weather.attributes.visibility": "Visibility",
'ui.card.weather.attributes.wind_speed': 'Wind speed', "ui.card.weather.attributes.wind_speed": "Wind speed",
'ui.card.weather.cardinal_direction.e': 'E', "ui.card.weather.cardinal_direction.e": "E",
'ui.card.weather.cardinal_direction.ene': 'ENE', "ui.card.weather.cardinal_direction.ene": "ENE",
'ui.card.weather.cardinal_direction.ese': 'ESE', "ui.card.weather.cardinal_direction.ese": "ESE",
'ui.card.weather.cardinal_direction.n': 'N', "ui.card.weather.cardinal_direction.n": "N",
'ui.card.weather.cardinal_direction.ne': 'NE', "ui.card.weather.cardinal_direction.ne": "NE",
'ui.card.weather.cardinal_direction.nne': 'NNE', "ui.card.weather.cardinal_direction.nne": "NNE",
'ui.card.weather.cardinal_direction.nw': 'NW', "ui.card.weather.cardinal_direction.nw": "NW",
'ui.card.weather.cardinal_direction.nnw': 'NNW', "ui.card.weather.cardinal_direction.nnw": "NNW",
'ui.card.weather.cardinal_direction.s': 'S', "ui.card.weather.cardinal_direction.s": "S",
'ui.card.weather.cardinal_direction.se': 'SE', "ui.card.weather.cardinal_direction.se": "SE",
'ui.card.weather.cardinal_direction.sse': 'SSE', "ui.card.weather.cardinal_direction.sse": "SSE",
'ui.card.weather.cardinal_direction.ssw': 'SSW', "ui.card.weather.cardinal_direction.ssw": "SSW",
'ui.card.weather.cardinal_direction.sw': 'SW', "ui.card.weather.cardinal_direction.sw": "SW",
'ui.card.weather.cardinal_direction.w': 'W', "ui.card.weather.cardinal_direction.w": "W",
'ui.card.weather.cardinal_direction.wnw': 'WNW', "ui.card.weather.cardinal_direction.wnw": "WNW",
'ui.card.weather.cardinal_direction.wsw': 'WSW', "ui.card.weather.cardinal_direction.wsw": "WSW",
'ui.card.weather.forecast': 'Forecast', "ui.card.weather.forecast": "Forecast",
'ui.common.loading': 'Loading', "ui.common.loading": "Loading",
'ui.common.cancel': 'Cancel', "ui.common.cancel": "Cancel",
'ui.components.entity.entity-picker.entity': 'Entity', "ui.components.entity.entity-picker.entity": "Entity",
'ui.components.relative_time.past': '{time} ago', "ui.components.relative_time.past": "{time} ago",
'ui.components.relative_time.future': 'In {time}', "ui.components.relative_time.future": "In {time}",
'ui.components.relative_time.never': 'Never', "ui.components.relative_time.never": "Never",
'ui.components.relative_time.duration.second': '{count} {count, plural,\n one {second}\n other {seconds}\n}', "ui.components.relative_time.duration.second":
'ui.components.relative_time.duration.minute': '{count} {count, plural,\n one {minute}\n other {minutes}\n}', "{count} {count, plural,\n one {second}\n other {seconds}\n}",
'ui.components.relative_time.duration.hour': '{count} {count, plural,\n one {hour}\n other {hours}\n}', "ui.components.relative_time.duration.minute":
'ui.components.relative_time.duration.day': '{count} {count, plural,\n one {day}\n other {days}\n}', "{count} {count, plural,\n one {minute}\n other {minutes}\n}",
'ui.components.relative_time.duration.week': '{count} {count, plural,\n one {week}\n other {weeks}\n}', "ui.components.relative_time.duration.hour":
'ui.components.history_charts.loading_history': 'Loading state history...', "{count} {count, plural,\n one {hour}\n other {hours}\n}",
'ui.components.history_charts.no_history_found': 'No state history found.', "ui.components.relative_time.duration.day":
'ui.components.service-picker.service': 'Service', "{count} {count, plural,\n one {day}\n other {days}\n}",
'ui.dialogs.more_info_settings.save': 'Save', "ui.components.relative_time.duration.week":
'ui.dialogs.more_info_settings.name': 'Name', "{count} {count, plural,\n one {week}\n other {weeks}\n}",
'ui.duration.second': '{count} {count, plural,\n one {second}\n other {seconds}\n}', "ui.components.history_charts.loading_history": "Loading state history...",
'ui.duration.minute': '{count} {count, plural,\n one {minute}\n other {minutes}\n}', "ui.components.history_charts.no_history_found": "No state history found.",
'ui.duration.hour': '{count} {count, plural,\n one {hour}\n other {hours}\n}', "ui.components.service-picker.service": "Service",
'ui.duration.day': '{count} {count, plural,\n one {day}\n other {days}\n}', "ui.dialogs.more_info_settings.save": "Save",
'ui.duration.week': '{count} {count, plural,\n one {week}\n other {weeks}\n}', "ui.dialogs.more_info_settings.name": "Name",
'ui.login-form.password': 'Password', "ui.duration.second":
'ui.login-form.remember': 'Remember', "{count} {count, plural,\n one {second}\n other {seconds}\n}",
'ui.login-form.log_in': 'Log in', "ui.duration.minute":
'ui.notification_toast.entity_turned_on': 'Turned on {entity}.', "{count} {count, plural,\n one {minute}\n other {minutes}\n}",
'ui.notification_toast.entity_turned_off': 'Turned off {entity}.', "ui.duration.hour":
'ui.notification_toast.service_called': 'Service {service} called.', "{count} {count, plural,\n one {hour}\n other {hours}\n}",
'ui.notification_toast.service_call_failed': 'Failed to call service {service}.', "ui.duration.day":
'ui.notification_toast.connection_lost': 'Connection lost. Reconnecting…', "{count} {count, plural,\n one {day}\n other {days}\n}",
'ui.sidebar.developer_tools': 'Developer tools', "ui.duration.week":
'ui.sidebar.log_out': 'Log out', "{count} {count, plural,\n one {week}\n other {weeks}\n}",
'attribute.weather.humidity': 'Humidity', "ui.login-form.password": "Password",
'attribute.weather.visibility': 'Visibility', "ui.login-form.remember": "Remember",
'attribute.weather.wind_speed': 'Wind speed', "ui.login-form.log_in": "Log in",
} "ui.notification_toast.entity_turned_on": "Turned on {entity}.",
"ui.notification_toast.entity_turned_off": "Turned off {entity}.",
"ui.notification_toast.service_called": "Service {service} called.",
"ui.notification_toast.service_call_failed":
"Failed to call service {service}.",
"ui.notification_toast.connection_lost": "Connection lost. Reconnecting…",
"ui.sidebar.developer_tools": "Developer tools",
"ui.sidebar.log_out": "Log out",
"attribute.weather.humidity": "Humidity",
"attribute.weather.visibility": "Visibility",
"attribute.weather.wind_speed": "Wind speed",
},
}; };

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
const now = () => new Date().toISOString(); const now = () => new Date().toISOString();
const randomTime = () => const randomTime = () =>
new Date(new Date().getTime() - (Math.random() * 80 * 60 * 1000)).toISOString(); new Date(new Date().getTime() - Math.random() * 80 * 60 * 1000).toISOString();
/* eslint-disable no-unused-vars */ /* eslint-disable no-unused-vars */
@@ -18,19 +18,23 @@ export class Entity {
} }
async handleService(domain, service, data) { async handleService(domain, service, data) {
console.log(`Unmocked service for ${this.entityId}: ${domain}/${service}`, data); console.log(
`Unmocked service for ${this.entityId}: ${domain}/${service}`,
data
);
} }
update(state, attributes = {}) { update(state, attributes = {}) {
this.state = state; this.state = state;
this.lastUpdated = now(); this.lastUpdated = now();
this.lastChanged = state === this.state ? this.lastChanged : this.lastUpdated; this.lastChanged =
state === this.state ? this.lastChanged : this.lastUpdated;
this.attributes = Object.assign({}, this.baseAttributes, attributes); this.attributes = Object.assign({}, this.baseAttributes, attributes);
console.log('update', this.entityId, this); console.log("update", this.entityId, this);
this.hass.updateStates({ this.hass.updateStates({
[this.entityId]: this.toState() [this.entityId]: this.toState(),
}); });
} }
@@ -47,22 +51,25 @@ export class Entity {
export class LightEntity extends Entity { export class LightEntity extends Entity {
async handleService(domain, service, data) { async handleService(domain, service, data) {
if (!['homeassistant', this.domain].includes(domain)) return; if (!["homeassistant", this.domain].includes(domain)) return;
if (service === 'turn_on') { if (service === "turn_on") {
// eslint-disable-next-line // eslint-disable-next-line
const { brightness, hs_color } = data; const { brightness, hs_color } = data;
this.update('on', Object.assign(this.attributes, { this.update(
"on",
Object.assign(this.attributes, {
brightness, brightness,
hs_color, hs_color,
})); })
} else if (service === 'turn_off') { );
this.update('off'); } else if (service === "turn_off") {
} else if (service === 'toggle') { this.update("off");
if (this.state === 'on') { } else if (service === "toggle") {
this.handleService(domain, 'turn_off', data); if (this.state === "on") {
this.handleService(domain, "turn_off", data);
} else { } else {
this.handleService(domain, 'turn_on', data); this.handleService(domain, "turn_on", data);
} }
} }
} }
@@ -72,10 +79,10 @@ export class LockEntity extends Entity {
async handleService(domain, service, data) { async handleService(domain, service, data) {
if (domain !== this.domain) return; if (domain !== this.domain) return;
if (service === 'lock') { if (service === "lock") {
this.update('locked'); this.update("locked");
} else if (service === 'unlock') { } else if (service === "unlock") {
this.update('unlocked'); this.update("unlocked");
} }
} }
} }
@@ -84,24 +91,26 @@ export class CoverEntity extends Entity {
async handleService(domain, service, data) { async handleService(domain, service, data) {
if (domain !== this.domain) return; if (domain !== this.domain) return;
if (service === 'open_cover') { if (service === "open_cover") {
this.update('open'); this.update("open");
} else if (service === 'close_cover') { } else if (service === "close_cover") {
this.update('closing'); this.update("closing");
} }
} }
} }
export class GroupEntity extends Entity { export class GroupEntity extends Entity {
async handleService(domain, service, data) { async handleService(domain, service, data) {
if (!['homeassistant', this.domain].includes(domain)) return; if (!["homeassistant", this.domain].includes(domain)) return;
await Promise.all(this.attributes.entity_id.map((ent) => { await Promise.all(
this.attributes.entity_id.map((ent) => {
const entity = this.hass.mockEntities[ent]; const entity = this.hass.mockEntities[ent];
return entity.handleService(entity.domain, service, data); return entity.handleService(entity.domain, service, data);
})); })
);
this.update(service === 'turn_on' ? 'on' : 'off'); this.update(service === "turn_on" ? "on" : "off");
} }
} }

View File

@@ -9,15 +9,17 @@ export default class FakeHass {
} }
async callService(domain, service, serviceData) { async callService(domain, service, serviceData) {
console.log('callService', { domain, service, serviceData }); console.log("callService", { domain, service, serviceData });
return Promise.resolve(); return Promise.resolve();
} }
async callWS(msg) { async callWS(msg) {
const callback = this._wsCommands[msg.type]; const callback = this._wsCommands[msg.type];
return callback ? callback(msg) : Promise.reject({ return callback
code: 'command_not_mocked', ? callback(msg)
message: 'This command is not implemented in the gallery.', : Promise.reject({
code: "command_not_mocked",
message: "This command is not implemented in the gallery.",
}); });
} }
@@ -29,6 +31,6 @@ export default class FakeHass {
} else { } else {
console.error(`Unknown command: ${msg.type}`); console.error(`Unknown command: ${msg.type}`);
} }
console.log('sendWS', msg); console.log("sendWS", msg);
} }
} }

View File

@@ -1,9 +1,9 @@
import fireEvent from '../../../src/common/dom/fire_event.js'; import fireEvent from "../../../src/common/dom/fire_event.js";
import demoConfig from './demo_config.js'; import demoConfig from "./demo_config.js";
import demoResources from './demo_resources.js'; import demoResources from "./demo_resources.js";
const ensureArray = val => (Array.isArray(val) ? val : [val]); const ensureArray = (val) => (Array.isArray(val) ? val : [val]);
export default (elements, { initialStates = {} } = {}) => { export default (elements, { initialStates = {} } = {}) => {
elements = ensureArray(elements); elements = ensureArray(elements);
@@ -14,13 +14,15 @@ export default (elements, { initialStates = {} } = {}) => {
function updateHass(obj) { function updateHass(obj) {
hass = Object.assign({}, hass, obj); hass = Object.assign({}, hass, obj);
elements.forEach((el) => { el.hass = hass; }); elements.forEach((el) => {
el.hass = hass;
});
} }
updateHass({ updateHass({
// Home Assistant properties // Home Assistant properties
config: demoConfig, config: demoConfig,
language: 'en', language: "en",
resources: demoResources, resources: demoResources,
states: initialStates, states: initialStates,
@@ -29,20 +31,27 @@ export default (elements, { initialStates = {} } = {}) => {
// Home Assistant functions // Home Assistant functions
async callService(domain, service, data) { async callService(domain, service, data) {
fireEvent(elements[0], 'show-notification', { message: `Called service ${domain}/${service}` }); fireEvent(elements[0], "show-notification", {
message: `Called service ${domain}/${service}`,
});
if (data.entity_id) { if (data.entity_id) {
await Promise.all(ensureArray(data.entity_id).map(ent => await Promise.all(
entities[ent].handleService(domain, service, data))); ensureArray(data.entity_id).map((ent) =>
entities[ent].handleService(domain, service, data)
)
);
} else { } else {
console.log('unmocked callService', domain, service, data); console.log("unmocked callService", domain, service, data);
} }
}, },
async callWS(msg) { async callWS(msg) {
const callback = wsCommands[msg.type]; const callback = wsCommands[msg.type];
return callback ? callback(msg) : Promise.reject({ return callback
code: 'command_not_mocked', ? callback(msg)
message: 'This command is not implemented in the gallery.', : Promise.reject({
code: "command_not_mocked",
message: "This command is not implemented in the gallery.",
}); });
}, },
@@ -54,7 +63,7 @@ export default (elements, { initialStates = {} } = {}) => {
} else { } else {
console.error(`Unknown command: ${msg.type}`); console.error(`Unknown command: ${msg.type}`);
} }
console.log('sendWS', msg); console.log("sendWS", msg);
}, },
// Mock functions // Mock functions
@@ -72,7 +81,7 @@ export default (elements, { initialStates = {} } = {}) => {
states[ent.entityId] = ent.toState(); states[ent.entityId] = ent.toState();
}); });
this.updateStates(states); this.updateStates(states);
} },
}); });
return hass; return hass;

View File

@@ -1,28 +1,28 @@
import { html } from '@polymer/polymer/lib/utils/html-tag.js'; import { html } from "@polymer/polymer/lib/utils/html-tag.js";
import { PolymerElement } from '@polymer/polymer/polymer-element.js'; import { PolymerElement } from "@polymer/polymer/polymer-element.js";
import getEntity from '../data/entity.js'; import getEntity from "../data/entity.js";
import provideHass from '../data/provide_hass.js'; import provideHass from "../data/provide_hass.js";
import '../components/demo-cards.js'; import "../components/demo-cards.js";
const ENTITIES = [ const ENTITIES = [
getEntity('light', 'controller_1', 'on', { getEntity("light", "controller_1", "on", {
friendly_name: 'Controller 1' friendly_name: "Controller 1",
}), }),
getEntity('light', 'controller_2', 'on', { getEntity("light", "controller_2", "on", {
friendly_name: 'Controller 2' friendly_name: "Controller 2",
}), }),
getEntity('light', 'floor', 'off', { getEntity("light", "floor", "off", {
friendly_name: 'Floor light' friendly_name: "Floor light",
}), }),
getEntity('light', 'kitchen', 'on', { getEntity("light", "kitchen", "on", {
friendly_name: 'Kitchen light' friendly_name: "Kitchen light",
}), }),
]; ];
const CONFIGS = [ const CONFIGS = [
{ {
heading: 'Controller', heading: "Controller",
config: ` config: `
- type: entities - type: entities
entities: entities:
@@ -31,10 +31,10 @@ const CONFIGS = [
- type: divider - type: divider
- light.floor - light.floor
- light.kitchen - light.kitchen
` `,
}, },
{ {
heading: 'Demo', heading: "Demo",
config: ` config: `
- type: conditional - type: conditional
conditions: conditions:
@@ -49,7 +49,7 @@ const CONFIGS = [
- light.controller_2 - light.controller_2
- light.floor - light.floor
- light.kitchen - light.kitchen
` `,
}, },
]; ];
@@ -68,7 +68,7 @@ class DemoConditional extends PolymerElement {
return { return {
_configs: { _configs: {
type: Object, type: Object,
value: CONFIGS value: CONFIGS,
}, },
hass: Object, hass: Object,
}; };
@@ -81,4 +81,4 @@ class DemoConditional extends PolymerElement {
} }
} }
customElements.define('demo-hui-conditional-card', DemoConditional); customElements.define("demo-hui-conditional-card", DemoConditional);

View File

@@ -1,75 +1,70 @@
import { html } from '@polymer/polymer/lib/utils/html-tag.js'; import { html } from "@polymer/polymer/lib/utils/html-tag.js";
import { PolymerElement } from '@polymer/polymer/polymer-element.js'; import { PolymerElement } from "@polymer/polymer/polymer-element.js";
import getEntity from '../data/entity.js'; import getEntity from "../data/entity.js";
import provideHass from '../data/provide_hass.js'; import provideHass from "../data/provide_hass.js";
import '../components/demo-cards.js'; import "../components/demo-cards.js";
const ENTITIES = [ const ENTITIES = [
getEntity('light', 'bed_light', 'on', { getEntity("light", "bed_light", "on", {
friendly_name: 'Bed Light' friendly_name: "Bed Light",
}), }),
getEntity('group', 'kitchen', 'on', { getEntity("group", "kitchen", "on", {
entity_id: [ entity_id: ["light.bed_light"],
'light.bed_light',
],
order: 8, order: 8,
friendly_name: 'Kitchen' friendly_name: "Kitchen",
}), }),
getEntity('lock', 'kitchen_door', 'locked', { getEntity("lock", "kitchen_door", "locked", {
friendly_name: 'Kitchen Door' friendly_name: "Kitchen Door",
}), }),
getEntity('cover', 'kitchen_window', 'open', { getEntity("cover", "kitchen_window", "open", {
friendly_name: 'Kitchen Window', friendly_name: "Kitchen Window",
supported_features: 11 supported_features: 11,
}), }),
getEntity('scene', 'romantic_lights', 'scening', { getEntity("scene", "romantic_lights", "scening", {
entity_id: [ entity_id: ["light.bed_light", "light.ceiling_lights"],
'light.bed_light', friendly_name: "Romantic lights",
'light.ceiling_lights'
],
friendly_name: 'Romantic lights'
}), }),
getEntity('device_tracker', 'demo_paulus', 'home', { getEntity("device_tracker", "demo_paulus", "home", {
source_type: 'gps', source_type: "gps",
latitude: 32.877105, latitude: 32.877105,
longitude: 117.232185, longitude: 117.232185,
gps_accuracy: 91, gps_accuracy: 91,
battery: 71, battery: 71,
friendly_name: 'Paulus' friendly_name: "Paulus",
}), }),
getEntity('climate', 'ecobee', 'auto', { getEntity("climate", "ecobee", "auto", {
current_temperature: 73, current_temperature: 73,
min_temp: 45, min_temp: 45,
max_temp: 95, max_temp: 95,
temperature: null, temperature: null,
target_temp_high: 75, target_temp_high: 75,
target_temp_low: 70, target_temp_low: 70,
fan_mode: 'Auto Low', fan_mode: "Auto Low",
fan_list: ['On Low', 'On High', 'Auto Low', 'Auto High', 'Off'], fan_list: ["On Low", "On High", "Auto Low", "Auto High", "Off"],
operation_mode: 'auto', operation_mode: "auto",
operation_list: ['heat', 'cool', 'auto', 'off'], operation_list: ["heat", "cool", "auto", "off"],
hold_mode: 'home', hold_mode: "home",
swing_mode: 'Auto', swing_mode: "Auto",
swing_list: ['Auto', '1', '2', '3', 'Off'], swing_list: ["Auto", "1", "2", "3", "Off"],
unit_of_measurement: '°F', unit_of_measurement: "°F",
friendly_name: 'Ecobee', friendly_name: "Ecobee",
supported_features: 1014 supported_features: 1014,
}), }),
getEntity('input_number', 'noise_allowance', 5, { getEntity("input_number", "noise_allowance", 5, {
min: 0, min: 0,
max: 10, max: 10,
step: 1, step: 1,
mode: 'slider', mode: "slider",
unit_of_measurement: 'dB', unit_of_measurement: "dB",
friendly_name: 'Allowed Noise', friendly_name: "Allowed Noise",
icon: 'mdi:bell-ring' icon: "mdi:bell-ring",
}) }),
]; ];
const CONFIGS = [ const CONFIGS = [
{ {
heading: 'Basic', heading: "Basic",
config: ` config: `
- type: entities - type: entities
entities: entities:
@@ -82,10 +77,10 @@ const CONFIGS = [
- light.non_existing - light.non_existing
- climate.ecobee - climate.ecobee
- input_number.noise_allowance - input_number.noise_allowance
` `,
}, },
{ {
heading: 'With title, toggle-able', heading: "With title, toggle-able",
config: ` config: `
- type: entities - type: entities
entities: entities:
@@ -98,10 +93,10 @@ const CONFIGS = [
- climate.ecobee - climate.ecobee
- input_number.noise_allowance - input_number.noise_allowance
title: Random group title: Random group
` `,
}, },
{ {
heading: 'With title, toggle = false', heading: "With title, toggle = false",
config: ` config: `
- type: entities - type: entities
entities: entities:
@@ -115,19 +110,19 @@ const CONFIGS = [
- input_number.noise_allowance - input_number.noise_allowance
title: Random group title: Random group
show_header_toggle: false show_header_toggle: false
` `,
}, },
{ {
heading: 'With title, can\'t toggle', heading: "With title, can't toggle",
config: ` config: `
- type: entities - type: entities
entities: entities:
- device_tracker.demo_paulus - device_tracker.demo_paulus
title: Random group title: Random group
` `,
}, },
{ {
heading: 'Custom name, secondary info, custom icon', heading: "Custom name, secondary info, custom icon",
config: ` config: `
- type: entities - type: entities
entities: entities:
@@ -147,10 +142,10 @@ const CONFIGS = [
- input_number.noise_allowance - input_number.noise_allowance
title: Random group title: Random group
show_header_toggle: false show_header_toggle: false
` `,
}, },
{ {
heading: 'Special rows', heading: "Special rows",
config: ` config: `
- type: entities - type: entities
entities: entities:
@@ -171,7 +166,7 @@ const CONFIGS = [
height: 30px height: 30px
margin: 4px 0 margin: 4px 0
background: center / contain url("/images/divider.png") no-repeat background: center / contain url("/images/divider.png") no-repeat
` `,
}, },
]; ];
@@ -190,7 +185,7 @@ class DemoEntities extends PolymerElement {
return { return {
_configs: { _configs: {
type: Object, type: Object,
value: CONFIGS value: CONFIGS,
}, },
hass: Object, hass: Object,
}; };
@@ -203,4 +198,4 @@ class DemoEntities extends PolymerElement {
} }
} }
customElements.define('demo-hui-entities-card', DemoEntities); customElements.define("demo-hui-entities-card", DemoEntities);

View File

@@ -1,11 +1,11 @@
import { html } from '@polymer/polymer/lib/utils/html-tag.js'; import { html } from "@polymer/polymer/lib/utils/html-tag.js";
import { PolymerElement } from '@polymer/polymer/polymer-element.js'; import { PolymerElement } from "@polymer/polymer/polymer-element.js";
import '../components/demo-cards.js'; import "../components/demo-cards.js";
const CONFIGS = [ const CONFIGS = [
{ {
heading: 'Basic', heading: "Basic",
config: ` config: `
- type: entity-filter - type: entity-filter
entities: entities:
@@ -18,10 +18,10 @@ const CONFIGS = [
state_filter: state_filter:
- "on" - "on"
- not_home - not_home
` `,
}, },
{ {
heading: 'With card config', heading: "With card config",
config: ` config: `
- type: entity-filter - type: entity-filter
entities: entities:
@@ -37,10 +37,10 @@ const CONFIGS = [
card: card:
type: glance type: glance
show_state: false show_state: false
` `,
}, },
{ {
heading: 'Showing single entity conditionally', heading: "Showing single entity conditionally",
config: ` config: `
- type: entity-filter - type: entity-filter
entities: entities:
@@ -50,8 +50,8 @@ const CONFIGS = [
card: card:
type: media-control type: media-control
entity: media_player.lounge_room entity: media_player.lounge_room
` `,
} },
]; ];
class DemoFilter extends PolymerElement { class DemoFilter extends PolymerElement {
@@ -65,10 +65,10 @@ class DemoFilter extends PolymerElement {
return { return {
_configs: { _configs: {
type: Object, type: Object,
value: CONFIGS value: CONFIGS,
} },
}; };
} }
} }
customElements.define('demo-hui-entity-filter-card', DemoFilter); customElements.define("demo-hui-entity-filter-card", DemoFilter);

View File

@@ -1,34 +1,34 @@
import { html } from '@polymer/polymer/lib/utils/html-tag.js'; import { html } from "@polymer/polymer/lib/utils/html-tag.js";
import { PolymerElement } from '@polymer/polymer/polymer-element.js'; import { PolymerElement } from "@polymer/polymer/polymer-element.js";
import '../components/demo-cards.js'; import "../components/demo-cards.js";
const CONFIGS = [ const CONFIGS = [
{ {
heading: 'Basic example', heading: "Basic example",
config: ` config: `
- type: gauge - type: gauge
entity: sensor.brightness entity: sensor.brightness
` `,
}, },
{ {
heading: 'With title', heading: "With title",
config: ` config: `
- type: gauge - type: gauge
title: Humidity title: Humidity
entity: sensor.outside_humidity entity: sensor.outside_humidity
` `,
}, },
{ {
heading: 'Custom Unit of Measurement', heading: "Custom Unit of Measurement",
config: ` config: `
- type: gauge - type: gauge
entity: sensor.outside_temperature entity: sensor.outside_temperature
unit_of_measurement: C unit_of_measurement: C
` `,
}, },
{ {
heading: 'Setting Severity Levels', heading: "Setting Severity Levels",
config: ` config: `
- type: gauge - type: gauge
entity: sensor.brightness entity: sensor.brightness
@@ -36,30 +36,30 @@ const CONFIGS = [
red: 32 red: 32
green: 0 green: 0
yellow: 23 yellow: 23
` `,
}, },
{ {
heading: 'Setting Min and Max Values', heading: "Setting Min and Max Values",
config: ` config: `
- type: gauge - type: gauge
entity: sensor.brightness entity: sensor.brightness
min: 0 min: 0
max: 38 max: 38
` `,
}, },
{ {
heading: 'Invalid Entity', heading: "Invalid Entity",
config: ` config: `
- type: gauge - type: gauge
entity: sensor.invalid_entity entity: sensor.invalid_entity
` `,
}, },
{ {
heading: 'Non-Numeric Value', heading: "Non-Numeric Value",
config: ` config: `
- type: gauge - type: gauge
entity: plant.bonsai entity: plant.bonsai
` `,
}, },
]; ];
@@ -74,10 +74,10 @@ class DemoGaugeEntity extends PolymerElement {
return { return {
_configs: { _configs: {
type: Object, type: Object,
value: CONFIGS value: CONFIGS,
} },
}; };
} }
} }
customElements.define('demo-hui-gauge-card', DemoGaugeEntity); customElements.define("demo-hui-gauge-card", DemoGaugeEntity);

View File

@@ -1,11 +1,11 @@
import { html } from '@polymer/polymer/lib/utils/html-tag.js'; import { html } from "@polymer/polymer/lib/utils/html-tag.js";
import { PolymerElement } from '@polymer/polymer/polymer-element.js'; import { PolymerElement } from "@polymer/polymer/polymer-element.js";
import '../components/demo-cards.js'; import "../components/demo-cards.js";
const CONFIGS = [ const CONFIGS = [
{ {
heading: 'Basic example', heading: "Basic example",
config: ` config: `
- type: glance - type: glance
entities: entities:
@@ -16,10 +16,10 @@ const CONFIGS = [
- light.kitchen_lights - light.kitchen_lights
- lock.kitchen_door - lock.kitchen_door
- light.ceiling_lights - light.ceiling_lights
` `,
}, },
{ {
heading: 'With title', heading: "With title",
config: ` config: `
- type: glance - type: glance
title: This is glance title: This is glance
@@ -31,10 +31,10 @@ const CONFIGS = [
- light.kitchen_lights - light.kitchen_lights
- lock.kitchen_door - lock.kitchen_door
- light.ceiling_lights - light.ceiling_lights
` `,
}, },
{ {
heading: 'Custom column width', heading: "Custom column width",
config: ` config: `
- type: glance - type: glance
column_width: calc(100% / 7) column_width: calc(100% / 7)
@@ -46,10 +46,10 @@ const CONFIGS = [
- light.kitchen_lights - light.kitchen_lights
- lock.kitchen_door - lock.kitchen_door
- light.ceiling_lights - light.ceiling_lights
` `,
}, },
{ {
heading: 'No name', heading: "No name",
config: ` config: `
- type: glance - type: glance
show_name: false show_name: false
@@ -61,10 +61,10 @@ const CONFIGS = [
- light.kitchen_lights - light.kitchen_lights
- lock.kitchen_door - lock.kitchen_door
- light.ceiling_lights - light.ceiling_lights
` `,
}, },
{ {
heading: 'No state', heading: "No state",
config: ` config: `
- type: glance - type: glance
show_state: false show_state: false
@@ -76,10 +76,10 @@ const CONFIGS = [
- light.kitchen_lights - light.kitchen_lights
- lock.kitchen_door - lock.kitchen_door
- light.ceiling_lights - light.ceiling_lights
` `,
}, },
{ {
heading: 'No name and no state', heading: "No name and no state",
config: ` config: `
- type: glance - type: glance
show_name: false show_name: false
@@ -92,10 +92,10 @@ const CONFIGS = [
- light.kitchen_lights - light.kitchen_lights
- lock.kitchen_door - lock.kitchen_door
- light.ceiling_lights - light.ceiling_lights
` `,
}, },
{ {
heading: 'Custom name, custom icon', heading: "Custom name, custom icon",
config: ` config: `
- type: glance - type: glance
entities: entities:
@@ -109,10 +109,10 @@ const CONFIGS = [
icon: mdi:alarm-light icon: mdi:alarm-light
- lock.kitchen_door - lock.kitchen_door
- light.ceiling_lights - light.ceiling_lights
` `,
}, },
{ {
heading: 'Custom tap action', heading: "Custom tap action",
config: ` config: `
- type: glance - type: glance
entities: entities:
@@ -126,10 +126,10 @@ const CONFIGS = [
- sun.sun - sun.sun
- cover.kitchen_window - cover.kitchen_window
- light.kitchen_lights - light.kitchen_lights
` `,
}, },
{ {
heading: 'Selectively hidden name', heading: "Selectively hidden name",
config: ` config: `
- type: glance - type: glance
entities: entities:
@@ -140,10 +140,10 @@ const CONFIGS = [
- entity: cover.kitchen_window - entity: cover.kitchen_window
name: name:
- light.kitchen_lights - light.kitchen_lights
` `,
}, },
{ {
heading: 'Primary theme', heading: "Primary theme",
config: ` config: `
- type: glance - type: glance
theming: primary theming: primary
@@ -155,7 +155,7 @@ const CONFIGS = [
- light.kitchen_lights - light.kitchen_lights
- lock.kitchen_door - lock.kitchen_door
- light.ceiling_lights - light.ceiling_lights
` `,
}, },
]; ];
@@ -170,10 +170,10 @@ class DemoPicEntity extends PolymerElement {
return { return {
_configs: { _configs: {
type: Object, type: Object,
value: CONFIGS value: CONFIGS,
} },
}; };
} }
} }
customElements.define('demo-hui-glance-card', DemoPicEntity); customElements.define("demo-hui-glance-card", DemoPicEntity);

View File

@@ -1,39 +1,39 @@
import { html } from '@polymer/polymer/lib/utils/html-tag.js'; import { html } from "@polymer/polymer/lib/utils/html-tag.js";
import { PolymerElement } from '@polymer/polymer/polymer-element.js'; import { PolymerElement } from "@polymer/polymer/polymer-element.js";
import '../components/demo-cards.js'; import "../components/demo-cards.js";
const CONFIGS = [ const CONFIGS = [
{ {
heading: 'Without title', heading: "Without title",
config: ` config: `
- type: iframe - type: iframe
url: https://embed.windy.com/embed2.html url: https://embed.windy.com/embed2.html
` `,
}, },
{ {
heading: 'With title', heading: "With title",
config: ` config: `
- type: iframe - type: iframe
url: https://embed.windy.com/embed2.html url: https://embed.windy.com/embed2.html
title: Weather radar title: Weather radar
` `,
}, },
{ {
heading: 'Height-Width 3:4', heading: "Height-Width 3:4",
config: ` config: `
- type: iframe - type: iframe
url: https://embed.windy.com/embed2.html url: https://embed.windy.com/embed2.html
aspect_ratio: 75% aspect_ratio: 75%
` `,
}, },
{ {
heading: 'Height-Width 1:1', heading: "Height-Width 1:1",
config: ` config: `
- type: iframe - type: iframe
url: https://embed.windy.com/embed2.html url: https://embed.windy.com/embed2.html
aspect_ratio: 100% aspect_ratio: 100%
` `,
}, },
]; ];
@@ -48,10 +48,10 @@ class DemoIframe extends PolymerElement {
return { return {
_configs: { _configs: {
type: Object, type: Object,
value: CONFIGS value: CONFIGS,
} },
}; };
} }
} }
customElements.define('demo-hui-iframe-card', DemoIframe); customElements.define("demo-hui-iframe-card", DemoIframe);

View File

@@ -1,120 +1,120 @@
import { html } from '@polymer/polymer/lib/utils/html-tag.js'; import { html } from "@polymer/polymer/lib/utils/html-tag.js";
import { PolymerElement } from '@polymer/polymer/polymer-element.js'; import { PolymerElement } from "@polymer/polymer/polymer-element.js";
import getEntity from '../data/entity.js'; import getEntity from "../data/entity.js";
import provideHass from '../data/provide_hass.js'; import provideHass from "../data/provide_hass.js";
import '../components/demo-cards.js'; import "../components/demo-cards.js";
const ENTITIES = [ const ENTITIES = [
getEntity('device_tracker', 'demo_paulus', 'not_home', { getEntity("device_tracker", "demo_paulus", "not_home", {
source_type: 'gps', source_type: "gps",
latitude: 32.877105, latitude: 32.877105,
longitude: 117.232185, longitude: 117.232185,
gps_accuracy: 91, gps_accuracy: 91,
battery: 71, battery: 71,
friendly_name: 'Paulus' friendly_name: "Paulus",
}), }),
getEntity('device_tracker', 'demo_home_boy', 'home', { getEntity("device_tracker", "demo_home_boy", "home", {
source_type: 'gps', source_type: "gps",
latitude: 32.87334, latitude: 32.87334,
longitude: 117.22745, longitude: 117.22745,
gps_accuracy: 20, gps_accuracy: 20,
battery: 53, battery: 53,
friendly_name: 'Home Boy' friendly_name: "Home Boy",
}), }),
getEntity('zone', 'home', 'zoning', { getEntity("zone", "home", "zoning", {
latitude: 32.87354, latitude: 32.87354,
longitude: 117.22765, longitude: 117.22765,
radius: 100, radius: 100,
friendly_name: 'Home', friendly_name: "Home",
icon: 'mdi:home' icon: "mdi:home",
}) }),
]; ];
const CONFIGS = [ const CONFIGS = [
{ {
heading: 'Without title', heading: "Without title",
config: ` config: `
- type: map - type: map
entities: entities:
- entity: device_tracker.demo_paulus - entity: device_tracker.demo_paulus
- device_tracker.demo_home_boy - device_tracker.demo_home_boy
- zone.home - zone.home
` `,
}, },
{ {
heading: 'With title', heading: "With title",
config: ` config: `
- type: map - type: map
entities: entities:
- entity: device_tracker.demo_paulus - entity: device_tracker.demo_paulus
- zone.home - zone.home
title: Where is Paulus? title: Where is Paulus?
` `,
}, },
{ {
heading: 'Height-Width 1:2', heading: "Height-Width 1:2",
config: ` config: `
- type: map - type: map
entities: entities:
- entity: device_tracker.demo_paulus - entity: device_tracker.demo_paulus
- zone.home - zone.home
aspect_ratio: 50% aspect_ratio: 50%
` `,
}, },
{ {
heading: 'Default Zoom', heading: "Default Zoom",
config: ` config: `
- type: map - type: map
default_zoom: 12 default_zoom: 12
entities: entities:
- entity: device_tracker.demo_paulus - entity: device_tracker.demo_paulus
- zone.home - zone.home
` `,
}, },
{ {
heading: 'Default Zoom too High', heading: "Default Zoom too High",
config: ` config: `
- type: map - type: map
default_zoom: 20 default_zoom: 20
entities: entities:
- entity: device_tracker.demo_paulus - entity: device_tracker.demo_paulus
- zone.home - zone.home
` `,
}, },
{ {
heading: 'Single Marker', heading: "Single Marker",
config: ` config: `
- type: map - type: map
entities: entities:
- device_tracker.demo_paulus - device_tracker.demo_paulus
` `,
}, },
{ {
heading: 'Single Marker Default Zoom', heading: "Single Marker Default Zoom",
config: ` config: `
- type: map - type: map
default_zoom: 8 default_zoom: 8
entities: entities:
- device_tracker.demo_paulus - device_tracker.demo_paulus
` `,
}, },
{ {
heading: 'No Entities', heading: "No Entities",
config: ` config: `
- type: map - type: map
entities: entities:
- light.bed_light - light.bed_light
` `,
}, },
{ {
heading: 'No Entities, Default Zoom', heading: "No Entities, Default Zoom",
config: ` config: `
- type: map - type: map
default_zoom: 8 default_zoom: 8
entities: entities:
- light.bed_light - light.bed_light
` `,
}, },
]; ];
@@ -133,9 +133,9 @@ class DemoMap extends PolymerElement {
return { return {
_configs: { _configs: {
type: Object, type: Object,
value: CONFIGS value: CONFIGS,
}, },
hass: Object hass: Object,
}; };
} }
@@ -146,4 +146,4 @@ class DemoMap extends PolymerElement {
} }
} }
customElements.define('demo-hui-map-card', DemoMap); customElements.define("demo-hui-map-card", DemoMap);

View File

@@ -1,11 +1,11 @@
import { html } from '@polymer/polymer/lib/utils/html-tag.js'; import { html } from "@polymer/polymer/lib/utils/html-tag.js";
import { PolymerElement } from '@polymer/polymer/polymer-element.js'; import { PolymerElement } from "@polymer/polymer/polymer-element.js";
import '../components/demo-cards.js'; import "../components/demo-cards.js";
const CONFIGS = [ const CONFIGS = [
{ {
heading: 'markdown-it demo', heading: "markdown-it demo",
config: ` config: `
- type: markdown - type: markdown
content: > content: >
@@ -248,7 +248,7 @@ const CONFIGS = [
::: warning ::: warning
*here be dragons* *here be dragons*
::: :::
` `,
}, },
]; ];
@@ -263,10 +263,10 @@ class DemoMarkdown extends PolymerElement {
return { return {
_configs: { _configs: {
type: Object, type: Object,
value: CONFIGS value: CONFIGS,
} },
}; };
} }
} }
customElements.define('demo-hui-markdown-card', DemoMarkdown); customElements.define("demo-hui-markdown-card", DemoMarkdown);

View File

@@ -1,58 +1,58 @@
import { html } from '@polymer/polymer/lib/utils/html-tag.js'; import { html } from "@polymer/polymer/lib/utils/html-tag.js";
import { PolymerElement } from '@polymer/polymer/polymer-element.js'; import { PolymerElement } from "@polymer/polymer/polymer-element.js";
import getEntity from '../data/entity.js'; import getEntity from "../data/entity.js";
import provideHass from '../data/provide_hass.js'; import provideHass from "../data/provide_hass.js";
import '../components/demo-cards.js'; import "../components/demo-cards.js";
const ENTITIES = [ const ENTITIES = [
getEntity('media_player', 'bedroom', 'playing', { getEntity("media_player", "bedroom", "playing", {
media_content_type: 'movie', media_content_type: "movie",
media_title: 'Epic sax guy 10 hours', media_title: "Epic sax guy 10 hours",
app_name: 'YouTube', app_name: "YouTube",
supported_features: 32 supported_features: 32,
}), }),
getEntity('media_player', 'family_room', 'paused', { getEntity("media_player", "family_room", "paused", {
media_content_type: 'music', media_content_type: "music",
media_title: 'I Wanna Be A Hippy (Flamman & Abraxas Radio Mix)', media_title: "I Wanna Be A Hippy (Flamman & Abraxas Radio Mix)",
media_artist: 'Technohead', media_artist: "Technohead",
supported_features: 16417 supported_features: 16417,
}), }),
getEntity('media_player', 'family_room_no_play', 'paused', { getEntity("media_player", "family_room_no_play", "paused", {
media_content_type: 'movie', media_content_type: "movie",
media_title: 'Epic sax guy 10 hours', media_title: "Epic sax guy 10 hours",
app_name: 'YouTube', app_name: "YouTube",
supported_features: 33 supported_features: 33,
}), }),
getEntity('media_player', 'living_room', 'playing', { getEntity("media_player", "living_room", "playing", {
media_content_type: 'tvshow', media_content_type: "tvshow",
media_title: 'Chapter 1', media_title: "Chapter 1",
media_series_title: 'House of Cards', media_series_title: "House of Cards",
app_name: 'Netflix', app_name: "Netflix",
supported_features: 1
}),
getEntity('media_player', 'lounge_room', 'idle', {
media_content_type: 'music',
media_title: 'I Wanna Be A Hippy (Flamman & Abraxas Radio Mix)',
media_artist: 'Technohead',
supported_features: 1, supported_features: 1,
}), }),
getEntity('media_player', 'theater', 'off', { getEntity("media_player", "lounge_room", "idle", {
media_content_type: 'movie', media_content_type: "music",
media_title: 'Epic sax guy 10 hours', media_title: "I Wanna Be A Hippy (Flamman & Abraxas Radio Mix)",
app_name: 'YouTube', media_artist: "Technohead",
supported_features: 33 supported_features: 1,
}), }),
getEntity('media_player', 'android_cast', 'playing', { getEntity("media_player", "theater", "off", {
media_title: 'Android Screen Casting', media_content_type: "movie",
app_name: 'Screen Mirroring', media_title: "Epic sax guy 10 hours",
supported_features: 21437 app_name: "YouTube",
supported_features: 33,
}),
getEntity("media_player", "android_cast", "playing", {
media_title: "Android Screen Casting",
app_name: "Screen Mirroring",
supported_features: 21437,
}), }),
]; ];
const CONFIGS = [ const CONFIGS = [
{ {
heading: 'Media Players', heading: "Media Players",
config: ` config: `
- type: entities - type: entities
entities: entities:
@@ -70,8 +70,8 @@ const CONFIGS = [
name: Chromcast Idle name: Chromcast Idle
- entity: media_player.theater - entity: media_player.theater
name: 'Player Off' name: 'Player Off'
` `,
} },
]; ];
class DemoHuiMediaPlayerRows extends PolymerElement { class DemoHuiMediaPlayerRows extends PolymerElement {
@@ -89,7 +89,7 @@ class DemoHuiMediaPlayerRows extends PolymerElement {
return { return {
_configs: { _configs: {
type: Object, type: Object,
value: CONFIGS value: CONFIGS,
}, },
hass: Object, hass: Object,
}; };
@@ -102,4 +102,4 @@ class DemoHuiMediaPlayerRows extends PolymerElement {
} }
} }
customElements.define('demo-hui-media-player-rows', DemoHuiMediaPlayerRows); customElements.define("demo-hui-media-player-rows", DemoHuiMediaPlayerRows);

View File

@@ -1,11 +1,11 @@
import { html } from '@polymer/polymer/lib/utils/html-tag.js'; import { html } from "@polymer/polymer/lib/utils/html-tag.js";
import { PolymerElement } from '@polymer/polymer/polymer-element.js'; import { PolymerElement } from "@polymer/polymer/polymer-element.js";
import '../components/demo-cards.js'; import "../components/demo-cards.js";
const CONFIGS = [ const CONFIGS = [
{ {
heading: 'Card with few elements', heading: "Card with few elements",
config: ` config: `
- type: picture-elements - type: picture-elements
image: /images/floorplan.png image: /images/floorplan.png
@@ -49,7 +49,7 @@ const CONFIGS = [
style: style:
top: 8% top: 8%
left: 35% left: 35%
` `,
}, },
]; ];
@@ -64,10 +64,10 @@ class DemoPicElements extends PolymerElement {
return { return {
_configs: { _configs: {
type: Object, type: Object,
value: CONFIGS value: CONFIGS,
} },
}; };
} }
} }
customElements.define('demo-hui-picture-elements-card', DemoPicElements); customElements.define("demo-hui-picture-elements-card", DemoPicElements);

View File

@@ -1,67 +1,67 @@
import { html } from '@polymer/polymer/lib/utils/html-tag.js'; import { html } from "@polymer/polymer/lib/utils/html-tag.js";
import { PolymerElement } from '@polymer/polymer/polymer-element.js'; import { PolymerElement } from "@polymer/polymer/polymer-element.js";
import '../components/demo-cards.js'; import "../components/demo-cards.js";
const CONFIGS = [ const CONFIGS = [
{ {
heading: 'State on', heading: "State on",
config: ` config: `
- type: picture-entity - type: picture-entity
image: /images/kitchen.png image: /images/kitchen.png
entity: light.kitchen_lights entity: light.kitchen_lights
` `,
}, },
{ {
heading: 'State off', heading: "State off",
config: ` config: `
- type: picture-entity - type: picture-entity
image: /images/bed.png image: /images/bed.png
entity: light.bed_light entity: light.bed_light
` `,
}, },
{ {
heading: 'Entity unavailable', heading: "Entity unavailable",
config: ` config: `
- type: picture-entity - type: picture-entity
image: /images/living_room.png image: /images/living_room.png
entity: light.non_existing entity: light.non_existing
` `,
}, },
{ {
heading: 'Camera entity', heading: "Camera entity",
config: ` config: `
- type: picture-entity - type: picture-entity
entity: camera.demo_camera entity: camera.demo_camera
` `,
}, },
{ {
heading: 'Hidden name', heading: "Hidden name",
config: ` config: `
- type: picture-entity - type: picture-entity
image: /images/kitchen.png image: /images/kitchen.png
entity: light.kitchen_lights entity: light.kitchen_lights
show_name: false show_name: false
` `,
}, },
{ {
heading: 'Hidden state', heading: "Hidden state",
config: ` config: `
- type: picture-entity - type: picture-entity
image: /images/kitchen.png image: /images/kitchen.png
entity: light.kitchen_lights entity: light.kitchen_lights
show_state: false show_state: false
` `,
}, },
{ {
heading: 'Both hidden', heading: "Both hidden",
config: ` config: `
- type: picture-entity - type: picture-entity
image: /images/kitchen.png image: /images/kitchen.png
entity: light.kitchen_lights entity: light.kitchen_lights
show_name: false show_name: false
show_state: false show_state: false
` `,
}, },
]; ];
@@ -76,10 +76,10 @@ class DemoPicEntity extends PolymerElement {
return { return {
_configs: { _configs: {
type: Object, type: Object,
value: CONFIGS value: CONFIGS,
} },
}; };
} }
} }
customElements.define('demo-hui-picture-entity-card', DemoPicEntity); customElements.define("demo-hui-picture-entity-card", DemoPicEntity);

View File

@@ -1,11 +1,11 @@
import { html } from '@polymer/polymer/lib/utils/html-tag.js'; import { html } from "@polymer/polymer/lib/utils/html-tag.js";
import { PolymerElement } from '@polymer/polymer/polymer-element.js'; import { PolymerElement } from "@polymer/polymer/polymer-element.js";
import '../components/demo-cards.js'; import "../components/demo-cards.js";
const CONFIGS = [ const CONFIGS = [
{ {
heading: 'Title, dialog, toggle', heading: "Title, dialog, toggle",
config: ` config: `
- type: picture-glance - type: picture-glance
image: /images/living_room.png image: /images/living_room.png
@@ -15,10 +15,10 @@ const CONFIGS = [
- light.ceiling_lights - light.ceiling_lights
- binary_sensor.movement_backyard - binary_sensor.movement_backyard
- binary_sensor.basement_floor_wet - binary_sensor.basement_floor_wet
` `,
}, },
{ {
heading: 'Title, dialog, no toggle', heading: "Title, dialog, no toggle",
config: ` config: `
- type: picture-glance - type: picture-glance
image: /images/living_room.png image: /images/living_room.png
@@ -26,10 +26,10 @@ const CONFIGS = [
entities: entities:
- binary_sensor.movement_backyard - binary_sensor.movement_backyard
- binary_sensor.basement_floor_wet - binary_sensor.basement_floor_wet
` `,
}, },
{ {
heading: 'Title, no dialog, toggle', heading: "Title, no dialog, toggle",
config: ` config: `
- type: picture-glance - type: picture-glance
image: /images/living_room.png image: /images/living_room.png
@@ -37,10 +37,10 @@ const CONFIGS = [
entities: entities:
- switch.decorative_lights - switch.decorative_lights
- light.ceiling_lights - light.ceiling_lights
` `,
}, },
{ {
heading: 'No title, dialog, toggle', heading: "No title, dialog, toggle",
config: ` config: `
- type: picture-glance - type: picture-glance
image: /images/living_room.png image: /images/living_room.png
@@ -49,30 +49,30 @@ const CONFIGS = [
- light.ceiling_lights - light.ceiling_lights
- binary_sensor.movement_backyard - binary_sensor.movement_backyard
- binary_sensor.basement_floor_wet - binary_sensor.basement_floor_wet
` `,
}, },
{ {
heading: 'No title, dialog, no toggle', heading: "No title, dialog, no toggle",
config: ` config: `
- type: picture-glance - type: picture-glance
image: /images/living_room.png image: /images/living_room.png
entities: entities:
- binary_sensor.movement_backyard - binary_sensor.movement_backyard
- binary_sensor.basement_floor_wet - binary_sensor.basement_floor_wet
` `,
}, },
{ {
heading: 'No title, no dialog, toggle', heading: "No title, no dialog, toggle",
config: ` config: `
- type: picture-glance - type: picture-glance
image: /images/living_room.png image: /images/living_room.png
entities: entities:
- switch.decorative_lights - switch.decorative_lights
- light.ceiling_lights - light.ceiling_lights
` `,
}, },
{ {
heading: 'Custom icon', heading: "Custom icon",
config: ` config: `
- type: picture-glance - type: picture-glance
image: /images/living_room.png image: /images/living_room.png
@@ -81,7 +81,7 @@ const CONFIGS = [
- entity: switch.decorative_lights - entity: switch.decorative_lights
icon: mdi:power icon: mdi:power
- binary_sensor.basement_floor_wet - binary_sensor.basement_floor_wet
` `,
}, },
]; ];
@@ -96,10 +96,10 @@ class DemoPicGlance extends PolymerElement {
return { return {
_configs: { _configs: {
type: Object, type: Object,
value: CONFIGS value: CONFIGS,
} },
}; };
} }
} }
customElements.define('demo-hui-picture-glance-card', DemoPicGlance); customElements.define("demo-hui-picture-glance-card", DemoPicGlance);

View File

@@ -1,11 +1,11 @@
import { html } from '@polymer/polymer/lib/utils/html-tag.js'; import { html } from "@polymer/polymer/lib/utils/html-tag.js";
import { PolymerElement } from '@polymer/polymer/polymer-element.js'; import { PolymerElement } from "@polymer/polymer/polymer-element.js";
import '../components/demo-cards.js'; import "../components/demo-cards.js";
const CONFIGS = [ const CONFIGS = [
{ {
heading: 'Vertical Stack', heading: "Vertical Stack",
config: ` config: `
- type: vertical-stack - type: vertical-stack
cards: cards:
@@ -17,10 +17,10 @@ const CONFIGS = [
- device_tracker.demo_anne_therese - device_tracker.demo_anne_therese
- device_tracker.demo_home_boy - device_tracker.demo_home_boy
- device_tracker.demo_paulus - device_tracker.demo_paulus
` `,
}, },
{ {
heading: 'Horizontal Stack', heading: "Horizontal Stack",
config: ` config: `
- type: horizontal-stack - type: horizontal-stack
cards: cards:
@@ -32,10 +32,10 @@ const CONFIGS = [
- device_tracker.demo_anne_therese - device_tracker.demo_anne_therese
- device_tracker.demo_home_boy - device_tracker.demo_home_boy
- device_tracker.demo_paulus - device_tracker.demo_paulus
` `,
}, },
{ {
heading: 'Combination of both', heading: "Combination of both",
config: ` config: `
- type: vertical-stack - type: vertical-stack
cards: cards:
@@ -52,7 +52,7 @@ const CONFIGS = [
- type: picture-entity - type: picture-entity
image: /images/bed.png image: /images/bed.png
entity: light.bed_light entity: light.bed_light
` `,
}, },
]; ];
@@ -67,10 +67,10 @@ class DemoStack extends PolymerElement {
return { return {
_configs: { _configs: {
type: Object, type: Object,
value: CONFIGS value: CONFIGS,
} },
}; };
} }
} }
customElements.define('demo-hui-stack-card', DemoStack); customElements.define("demo-hui-stack-card", DemoStack);

View File

@@ -1,13 +1,13 @@
import { html } from '@polymer/polymer/lib/utils/html-tag.js'; import { html } from "@polymer/polymer/lib/utils/html-tag.js";
import { PolymerElement } from '@polymer/polymer/polymer-element.js'; import { PolymerElement } from "@polymer/polymer/polymer-element.js";
import '../../../src/dialogs/more-info/controls/more-info-content.js'; import "../../../src/dialogs/more-info/controls/more-info-content.js";
import '../../../src/components/ha-card.js'; import "../../../src/components/ha-card.js";
import getEntity from '../data/entity.js'; import getEntity from "../data/entity.js";
import provideHass from '../data/provide_hass.js'; import provideHass from "../data/provide_hass.js";
import '../components/demo-more-infos.js'; import "../components/demo-more-infos.js";
/* eslint-disable no-unused-vars */ /* eslint-disable no-unused-vars */
@@ -20,17 +20,16 @@ const SUPPORT_TRANSITION = 32;
const SUPPORT_WHITE_VALUE = 128; const SUPPORT_WHITE_VALUE = 128;
const ENTITIES = [ const ENTITIES = [
getEntity('light', 'bed_light', 'on', { getEntity("light", "bed_light", "on", {
friendly_name: 'Basic Light' friendly_name: "Basic Light",
}), }),
getEntity('light', 'kitchen_light', 'on', { getEntity("light", "kitchen_light", "on", {
friendly_name: 'Brightness Light', friendly_name: "Brightness Light",
brightness: 80, brightness: 80,
supported_features: SUPPORT_BRIGHTNESS, supported_features: SUPPORT_BRIGHTNESS,
}), }),
]; ];
class DemoMoreInfoLight extends PolymerElement { class DemoMoreInfoLight extends PolymerElement {
static get template() { static get template() {
return html` return html`
@@ -45,7 +44,7 @@ class DemoMoreInfoLight extends PolymerElement {
return { return {
_entities: { _entities: {
type: Array, type: Array,
value: ENTITIES.map(ent => ent.entityId), value: ENTITIES.map((ent) => ent.entityId),
}, },
}; };
} }
@@ -57,4 +56,4 @@ class DemoMoreInfoLight extends PolymerElement {
} }
} }
customElements.define('demo-more-info-light', DemoMoreInfoLight); customElements.define("demo-more-info-light", DemoMoreInfoLight);

View File

@@ -1,12 +1,12 @@
import '@polymer/paper-styles/typography.js'; import "@polymer/paper-styles/typography.js";
import '@polymer/polymer/lib/elements/dom-if.js'; import "@polymer/polymer/lib/elements/dom-if.js";
import '@polymer/polymer/lib/elements/dom-repeat.js'; import "@polymer/polymer/lib/elements/dom-repeat.js";
import '../../src/resources/hass-icons.js'; import "../../src/resources/hass-icons.js";
import '../../src/resources/ha-style.js'; import "../../src/resources/ha-style.js";
import '../../src/resources/roboto.js'; import "../../src/resources/roboto.js";
import '../../src/components/ha-iconset-svg.js'; import "../../src/components/ha-iconset-svg.js";
import './ha-gallery.js'; import "./ha-gallery.js";
document.body.appendChild(document.createElement('ha-gallery')); document.body.appendChild(document.createElement("ha-gallery"));

View File

@@ -1,19 +1,19 @@
import '@polymer/app-layout/app-header-layout/app-header-layout.js'; import "@polymer/app-layout/app-header-layout/app-header-layout.js";
import '@polymer/app-layout/app-header/app-header.js'; import "@polymer/app-layout/app-header/app-header.js";
import '@polymer/app-layout/app-toolbar/app-toolbar.js'; import "@polymer/app-layout/app-toolbar/app-toolbar.js";
import '@polymer/iron-icon/iron-icon.js'; import "@polymer/iron-icon/iron-icon.js";
import '@polymer/paper-card/paper-card.js'; import "@polymer/paper-card/paper-card.js";
import '@polymer/paper-item/paper-item.js'; import "@polymer/paper-item/paper-item.js";
import '@polymer/paper-item/paper-item-body.js'; import "@polymer/paper-item/paper-item-body.js";
import '@polymer/paper-icon-button/paper-icon-button.js'; import "@polymer/paper-icon-button/paper-icon-button.js";
import { html } from '@polymer/polymer/lib/utils/html-tag.js'; import { html } from "@polymer/polymer/lib/utils/html-tag.js";
import { PolymerElement } from '@polymer/polymer/polymer-element.js'; import { PolymerElement } from "@polymer/polymer/polymer-element.js";
import '../../src/managers/notification-manager.js'; import "../../src/managers/notification-manager.js";
const DEMOS = require.context('./demos', true, /^(.*\.(js$))[^.]*$/im); const DEMOS = require.context("./demos", true, /^(.*\.(js$))[^.]*$/im);
const fixPath = path => path.substr(2, path.length - 5); const fixPath = (path) => path.substr(2, path.length - 5);
class HaGallery extends PolymerElement { class HaGallery extends PolymerElement {
static get template() { static get template() {
@@ -131,19 +131,19 @@ class HaGallery extends PolymerElement {
_demo: { _demo: {
type: String, type: String,
value: document.location.hash.substr(1), value: document.location.hash.substr(1),
observer: '_demoChanged', observer: "_demoChanged",
}, },
_demos: { _demos: {
type: Array, type: Array,
value: DEMOS.keys().map(fixPath) value: DEMOS.keys().map(fixPath),
}, },
_lovelaceDemos: { _lovelaceDemos: {
type: Array, type: Array,
computed: '_computeLovelace(_demos)', computed: "_computeLovelace(_demos)",
}, },
_moreInfoDemos: { _moreInfoDemos: {
type: Array, type: Array,
computed: '_computeMoreInfos(_demos)', computed: "_computeMoreInfos(_demos)",
}, },
}; };
} }
@@ -151,18 +151,21 @@ class HaGallery extends PolymerElement {
ready() { ready() {
super.ready(); super.ready();
this.addEventListener( this.addEventListener("show-notification", (ev) =>
'show-notification', this.$.notifications.showNotification(ev.detail.message)
ev => this.$.notifications.showNotification(ev.detail.message)
); );
this.addEventListener('hass-more-info', (ev) => { this.addEventListener("hass-more-info", (ev) => {
if (ev.detail.entityId) { if (ev.detail.entityId) {
this.$.notifications.showNotification(`Showing more info for ${ev.detail.entityId}`); this.$.notifications.showNotification(
`Showing more info for ${ev.detail.entityId}`
);
} }
}); });
window.addEventListener('hashchange', () => { this._demo = document.location.hash.substr(1); }); window.addEventListener("hashchange", () => {
this._demo = document.location.hash.substr(1);
});
} }
_withDefault(value, def) { _withDefault(value, def) {
@@ -182,20 +185,20 @@ class HaGallery extends PolymerElement {
} }
_computeHeaderButtonClass(demo) { _computeHeaderButtonClass(demo) {
return demo ? '' : 'invisible'; return demo ? "" : "invisible";
} }
_backTapped() { _backTapped() {
document.location.hash = ''; document.location.hash = "";
} }
_computeLovelace(demos) { _computeLovelace(demos) {
return demos.filter(demo => demo.includes('hui')); return demos.filter((demo) => demo.includes("hui"));
} }
_computeMoreInfos(demos) { _computeMoreInfos(demos) {
return demos.filter(demo => demo.includes('more-info')); return demos.filter((demo) => demo.includes("more-info"));
} }
} }
customElements.define('ha-gallery', HaGallery); customElements.define("ha-gallery", HaGallery);

View File

@@ -1,36 +1,34 @@
const path = require('path'); const path = require("path");
const UglifyJsPlugin = require('uglifyjs-webpack-plugin'); const UglifyJsPlugin = require("uglifyjs-webpack-plugin");
const CopyWebpackPlugin = require('copy-webpack-plugin'); const CopyWebpackPlugin = require("copy-webpack-plugin");
const isProd = process.env.NODE_ENV === 'production'; const isProd = process.env.NODE_ENV === "production";
const chunkFilename = isProd ? const chunkFilename = isProd ? "chunk.[chunkhash].js" : "[name].chunk.js";
'chunk.[chunkhash].js' : '[name].chunk.js'; const buildPath = path.resolve(__dirname, "dist");
const buildPath = path.resolve(__dirname, 'dist'); const publicPath = isProd ? "./" : "http://localhost:8080/";
const publicPath = isProd ? './' : 'http://localhost:8080/';
module.exports = { module.exports = {
mode: isProd ? 'production' : 'development', mode: isProd ? "production" : "development",
// Disabled in prod while we make Home Assistant able to serve the right files. // Disabled in prod while we make Home Assistant able to serve the right files.
// Was source-map // Was source-map
devtool: isProd ? 'none' : 'inline-source-map', devtool: isProd ? "none" : "inline-source-map",
entry: './src/entrypoint.js', entry: "./src/entrypoint.js",
module: { module: {
rules: [ rules: [
{ {
test: /\.js$/, test: /\.js$/,
use: { use: {
loader: 'babel-loader', loader: "babel-loader",
options: { options: {
plugins: [ plugins: [
// Only support the syntax, Webpack will handle it. // Only support the syntax, Webpack will handle it.
'syntax-dynamic-import', "syntax-dynamic-import",
[ [
'transform-react-jsx', "transform-react-jsx",
{ {
pragma: 'h' pragma: "h",
} },
], ],
], ],
}, },
}, },
@@ -38,39 +36,49 @@ module.exports = {
{ {
test: /\.(html)$/, test: /\.(html)$/,
use: { use: {
loader: 'html-loader', loader: "html-loader",
options: { options: {
exportAsEs6Default: true, exportAsEs6Default: true,
}
}
}, },
] },
},
],
}, },
plugins: [ plugins: [
new CopyWebpackPlugin([ new CopyWebpackPlugin([
'public', "public",
{ from: '../public', to: 'static' }, { from: "../public", to: "static" },
{ from: '../build-translations/output', to: 'static/translations' }, { from: "../build-translations/output", to: "static/translations" },
{ from: '../node_modules/leaflet/dist/leaflet.css', to: 'static/images/leaflet/' }, {
{ from: '../node_modules/@polymer/font-roboto-local/fonts', to: 'static/fonts' }, from: "../node_modules/leaflet/dist/leaflet.css",
{ from: '../node_modules/leaflet/dist/images', to: 'static/images/leaflet/' }, to: "static/images/leaflet/",
},
{
from: "../node_modules/@polymer/font-roboto-local/fonts",
to: "static/fonts",
},
{
from: "../node_modules/leaflet/dist/images",
to: "static/images/leaflet/",
},
]), ]),
isProd && new UglifyJsPlugin({ isProd &&
new UglifyJsPlugin({
extractComments: true, extractComments: true,
sourceMap: true, sourceMap: true,
uglifyOptions: { uglifyOptions: {
// Disabling because it broke output // Disabling because it broke output
mangle: false, mangle: false,
} },
}), }),
].filter(Boolean), ].filter(Boolean),
output: { output: {
filename: '[name].js', filename: "[name].js",
chunkFilename: chunkFilename, chunkFilename: chunkFilename,
path: buildPath, path: buildPath,
publicPath, publicPath,
}, },
devServer: { devServer: {
contentBase: './public', contentBase: "./public",
} },
}; };

View File

@@ -1,8 +1,8 @@
var path = require('path'); var path = require("path");
module.exports = { module.exports = {
polymer_dir: path.resolve(__dirname, '..'), polymer_dir: path.resolve(__dirname, ".."),
build_dir: path.resolve(__dirname, '../build'), build_dir: path.resolve(__dirname, "../build"),
output: path.resolve(__dirname, '../hass_frontend'), output: path.resolve(__dirname, "../hass_frontend"),
output_es5: path.resolve(__dirname, '../hass_frontend_es5'), output_es5: path.resolve(__dirname, "../hass_frontend_es5"),
}; };

View File

@@ -1,31 +1,34 @@
const gulp = require('gulp'); const gulp = require("gulp");
const path = require('path'); const path = require("path");
const fs = require('fs'); const fs = require("fs");
const config = require('../config'); const config = require("../config");
const ICON_PACKAGE_PATH = path.resolve(__dirname, '../../node_modules/@mdi/svg/'); const ICON_PACKAGE_PATH = path.resolve(
const META_PATH = path.resolve(ICON_PACKAGE_PATH, 'meta.json'); __dirname,
const ICON_PATH = path.resolve(ICON_PACKAGE_PATH, 'svg'); "../../node_modules/@mdi/svg/"
const OUTPUT_DIR = path.resolve(__dirname, '../../build'); );
const MDI_OUTPUT_PATH = path.resolve(OUTPUT_DIR, 'mdi.html'); const META_PATH = path.resolve(ICON_PACKAGE_PATH, "meta.json");
const HASS_OUTPUT_PATH = path.resolve(OUTPUT_DIR, 'hass-icons.html'); const ICON_PATH = path.resolve(ICON_PACKAGE_PATH, "svg");
const OUTPUT_DIR = path.resolve(__dirname, "../../build");
const MDI_OUTPUT_PATH = path.resolve(OUTPUT_DIR, "mdi.html");
const HASS_OUTPUT_PATH = path.resolve(OUTPUT_DIR, "hass-icons.html");
const BUILT_IN_PANEL_ICONS = [ const BUILT_IN_PANEL_ICONS = [
'calendar', // Calendar "calendar", // Calendar
'settings', // Config "settings", // Config
'home-assistant', // Hass.io "home-assistant", // Hass.io
'poll-box', // History panel "poll-box", // History panel
'format-list-bulleted-type', // Logbook "format-list-bulleted-type", // Logbook
'mailbox', // Mailbox "mailbox", // Mailbox
'account-location', // Map "account-location", // Map
'cart', // Shopping List "cart", // Shopping List
]; ];
// Given an icon name, load the SVG file // Given an icon name, load the SVG file
function loadIcon(name) { function loadIcon(name) {
const iconPath = path.resolve(ICON_PATH, `${name}.svg`); const iconPath = path.resolve(ICON_PATH, `${name}.svg`);
try { try {
return fs.readFileSync(iconPath, 'utf-8'); return fs.readFileSync(iconPath, "utf-8");
} catch (err) { } catch (err) {
return null; return null;
} }
@@ -33,7 +36,7 @@ function loadIcon(name) {
// Given an SVG file, convert it to an iron-iconset-svg definition // Given an SVG file, convert it to an iron-iconset-svg definition
function transformXMLtoPolymer(name, xml) { function transformXMLtoPolymer(name, xml) {
const start = xml.indexOf('><path') + 1; const start = xml.indexOf("><path") + 1;
const end = xml.length - start - 6; const end = xml.length - start - 6;
const path = xml.substr(start, end); const path = xml.substr(start, end);
return `<g id="${name}">${path}</g>`; return `<g id="${name}">${path}</g>`;
@@ -41,22 +44,26 @@ function transformXMLtoPolymer(name, xml) {
// Given an iconset name and icon names, generate a polymer iconset // Given an iconset name and icon names, generate a polymer iconset
function generateIconset(name, iconNames) { function generateIconset(name, iconNames) {
const iconDefs = iconNames.map(name => { const iconDefs = iconNames
.map((name) => {
const iconDef = loadIcon(name); const iconDef = loadIcon(name);
if (!iconDef) { if (!iconDef) {
throw new Error(`Unknown icon referenced: ${name}`); throw new Error(`Unknown icon referenced: ${name}`);
} }
return transformXMLtoPolymer(name, iconDef) return transformXMLtoPolymer(name, iconDef);
}).join(''); })
.join("");
return `<ha-iconset-svg name="${name}" size="24"><svg><defs>${iconDefs}</defs></svg></ha-iconset-svg>`; return `<ha-iconset-svg name="${name}" size="24"><svg><defs>${iconDefs}</defs></svg></ha-iconset-svg>`;
} }
// Generate the full MDI iconset // Generate the full MDI iconset
function genMDIIcons() { function genMDIIcons() {
const meta = JSON.parse(fs.readFileSync(path.resolve(ICON_PACKAGE_PATH, META_PATH), 'UTF-8')); const meta = JSON.parse(
const iconNames = meta.map(iconInfo => iconInfo.name); fs.readFileSync(path.resolve(ICON_PACKAGE_PATH, META_PATH), "UTF-8")
);
const iconNames = meta.map((iconInfo) => iconInfo.name);
fs.existsSync(OUTPUT_DIR) || fs.mkdirSync(OUTPUT_DIR); fs.existsSync(OUTPUT_DIR) || fs.mkdirSync(OUTPUT_DIR);
fs.writeFileSync(MDI_OUTPUT_PATH, generateIconset('mdi', iconNames)); fs.writeFileSync(MDI_OUTPUT_PATH, generateIconset("mdi", iconNames));
} }
// Helper function to map recursively over files in a folder and it's subfolders // Helper function to map recursively over files in a folder and it's subfolders
@@ -75,30 +82,30 @@ function mapFiles(startPath, filter, mapFunc) {
// Find all icons used by the project. // Find all icons used by the project.
function findIcons(path, iconsetName) { function findIcons(path, iconsetName) {
const iconRegex = new RegExp(`${iconsetName}:[\\w-]+`, 'g'); const iconRegex = new RegExp(`${iconsetName}:[\\w-]+`, "g");
const icons = new Set(); const icons = new Set();
function processFile(filename) { function processFile(filename) {
const content = fs.readFileSync(filename); const content = fs.readFileSync(filename);
let match; let match;
// eslint-disable-next-line // eslint-disable-next-line
while (match = iconRegex.exec(content)) { while ((match = iconRegex.exec(content))) {
// strip off "hass:" and add to set // strip off "hass:" and add to set
icons.add(match[0].substr(iconsetName.length + 1)); icons.add(match[0].substr(iconsetName.length + 1));
} }
} }
mapFiles(path, '.js', processFile); mapFiles(path, ".js", processFile);
return Array.from(icons); return Array.from(icons);
} }
function genHassIcons() { function genHassIcons() {
const iconNames = findIcons('./src', 'hass').concat(BUILT_IN_PANEL_ICONS); const iconNames = findIcons("./src", "hass").concat(BUILT_IN_PANEL_ICONS);
fs.existsSync(OUTPUT_DIR) || fs.mkdirSync(OUTPUT_DIR); fs.existsSync(OUTPUT_DIR) || fs.mkdirSync(OUTPUT_DIR);
fs.writeFileSync(HASS_OUTPUT_PATH, generateIconset('hass', iconNames)); fs.writeFileSync(HASS_OUTPUT_PATH, generateIconset("hass", iconNames));
} }
gulp.task('gen-icons-mdi', () => genMDIIcons()); gulp.task("gen-icons-mdi", () => genMDIIcons());
gulp.task('gen-icons-hass', () => genHassIcons()); gulp.task("gen-icons-hass", () => genHassIcons());
gulp.task('gen-icons', ['gen-icons-hass', 'gen-icons-mdi'], () => {}); gulp.task("gen-icons", ["gen-icons-hass", "gen-icons-mdi"], () => {});
module.exports = { module.exports = {
findIcons, findIcons,

View File

@@ -1,40 +1,44 @@
const path = require('path'); const path = require("path");
const gulp = require('gulp'); const gulp = require("gulp");
const foreach = require('gulp-foreach'); const foreach = require("gulp-foreach");
const hash = require('gulp-hash'); const hash = require("gulp-hash");
const insert = require('gulp-insert'); const insert = require("gulp-insert");
const merge = require('gulp-merge-json'); const merge = require("gulp-merge-json");
const minify = require('gulp-jsonminify'); const minify = require("gulp-jsonminify");
const rename = require('gulp-rename'); const rename = require("gulp-rename");
const transform = require('gulp-json-transform'); const transform = require("gulp-json-transform");
const inDir = 'translations'; const inDir = "translations";
const workDir = 'build-translations'; const workDir = "build-translations";
const fullDir = workDir + '/full'; const fullDir = workDir + "/full";
const coreDir = workDir + '/core'; const coreDir = workDir + "/core";
const outDir = workDir + '/output'; const outDir = workDir + "/output";
// Panel translations which should be split from the core translations. These // Panel translations which should be split from the core translations. These
// should mirror the fragment definitions in polymer.json, so that we load // should mirror the fragment definitions in polymer.json, so that we load
// additional resources at equivalent points. // additional resources at equivalent points.
const TRANSLATION_FRAGMENTS = [ const TRANSLATION_FRAGMENTS = [
'config', "config",
'history', "history",
'logbook', "logbook",
'mailbox', "mailbox",
'profile', "profile",
'shopping-list', "shopping-list",
'page-authorize', "page-authorize",
'page-onboarding', "page-onboarding",
]; ];
const tasks = []; const tasks = [];
function recursiveFlatten(prefix, data) { function recursiveFlatten(prefix, data) {
let output = {}; let output = {};
Object.keys(data).forEach(function (key) { Object.keys(data).forEach(function(key) {
if (typeof (data[key]) === 'object') { if (typeof data[key] === "object") {
output = Object.assign({}, output, recursiveFlatten(prefix + key + '.', data[key])); output = Object.assign(
{},
output,
recursiveFlatten(prefix + key + ".", data[key])
);
} else { } else {
output[prefix + key] = data[key]; output[prefix + key] = data[key];
} }
@@ -43,14 +47,14 @@ function recursiveFlatten(prefix, data) {
} }
function flatten(data) { function flatten(data) {
return recursiveFlatten('', data); return recursiveFlatten("", data);
} }
function emptyFilter(data) { function emptyFilter(data) {
const newData = {}; const newData = {};
Object.keys(data).forEach((key) => { Object.keys(data).forEach((key) => {
if (data[key]) { if (data[key]) {
if (typeof (data[key]) === 'object') { if (typeof data[key] === "object") {
newData[key] = emptyFilter(data[key]); newData[key] = emptyFilter(data[key]);
} else { } else {
newData[key] = data[key]; newData[key] = data[key];
@@ -70,16 +74,18 @@ function emptyFilter(data) {
* @link https://docs.lokalise.co/article/KO5SZWLLsy-key-referencing * @link https://docs.lokalise.co/article/KO5SZWLLsy-key-referencing
*/ */
const re_key_reference = /\[%key:([^%]+)%\]/; const re_key_reference = /\[%key:([^%]+)%\]/;
function lokalise_transform (data, original) { function lokalise_transform(data, original) {
const output = {}; const output = {};
Object.entries(data).forEach(([key, value]) => { Object.entries(data).forEach(([key, value]) => {
if (value instanceof Object) { if (value instanceof Object) {
output[key] = lokalise_transform(value, original); output[key] = lokalise_transform(value, original);
} else { } else {
output[key] = value.replace(re_key_reference, (match, key) => { output[key] = value.replace(re_key_reference, (match, key) => {
const replace = key.split('::').reduce((tr, k) => tr[k], original); const replace = key.split("::").reduce((tr, k) => tr[k], original);
if (typeof replace !== 'string') { if (typeof replace !== "string") {
throw Error(`Invalid key placeholder ${key} in src/translations/en.json`); throw Error(
`Invalid key placeholder ${key} in src/translations/en.json`
);
} }
return replace; return replace;
}); });
@@ -97,21 +103,24 @@ function lokalise_transform (data, original) {
* project is buildable immediately after merging new translation keys, since * project is buildable immediately after merging new translation keys, since
* the Lokalise update to translations/en.json will not happen immediately. * the Lokalise update to translations/en.json will not happen immediately.
*/ */
let taskName = 'build-master-translation'; let taskName = "build-master-translation";
gulp.task(taskName, function () { gulp.task(taskName, function() {
return gulp.src('src/translations/en.json') return gulp
.pipe(transform(function(data, file) { .src("src/translations/en.json")
.pipe(
transform(function(data, file) {
return lokalise_transform(data, data); return lokalise_transform(data, data);
})) })
.pipe(rename('translationMaster.json')) )
.pipe(rename("translationMaster.json"))
.pipe(gulp.dest(workDir)); .pipe(gulp.dest(workDir));
}); });
tasks.push(taskName); tasks.push(taskName);
taskName = 'build-merged-translations'; taskName = "build-merged-translations";
gulp.task(taskName, ['build-master-translation'], function () { gulp.task(taskName, ["build-master-translation"], function() {
return gulp.src(inDir + '/*.json') return gulp.src(inDir + "/*.json").pipe(
.pipe(foreach(function(stream, file) { foreach(function(stream, file) {
// For each language generate a merged json file. It begins with the master // For each language generate a merged json file. It begins with the master
// translation as a failsafe for untranslated strings, and merges all parent // translation as a failsafe for untranslated strings, and merges all parent
// tags into one file for each specific subtag // tags into one file for each specific subtag
@@ -119,97 +128,119 @@ gulp.task(taskName, ['build-master-translation'], function () {
// TODO: This is a naive interpretation of BCP47 that should be improved. // TODO: This is a naive interpretation of BCP47 that should be improved.
// Will be OK for now as long as we don't have anything more complicated // Will be OK for now as long as we don't have anything more complicated
// than a base translation + region. // than a base translation + region.
const tr = path.basename(file.history[0], '.json'); const tr = path.basename(file.history[0], ".json");
const subtags = tr.split('-'); const subtags = tr.split("-");
const src = [workDir + '/translationMaster.json']; const src = [workDir + "/translationMaster.json"];
for (let i = 1; i <= subtags.length; i++) { for (let i = 1; i <= subtags.length; i++) {
const lang = subtags.slice(0, i).join('-'); const lang = subtags.slice(0, i).join("-");
src.push(inDir + '/' + lang + '.json'); src.push(inDir + "/" + lang + ".json");
} }
return gulp.src(src) return gulp
.pipe(transform(data => emptyFilter(data))) .src(src)
.pipe(merge({ .pipe(transform((data) => emptyFilter(data)))
fileName: tr + '.json', .pipe(
})) merge({
fileName: tr + ".json",
})
)
.pipe(gulp.dest(fullDir)); .pipe(gulp.dest(fullDir));
})); })
);
}); });
tasks.push(taskName); tasks.push(taskName);
const splitTasks = []; const splitTasks = [];
TRANSLATION_FRAGMENTS.forEach((fragment) => { TRANSLATION_FRAGMENTS.forEach((fragment) => {
taskName = 'build-translation-fragment-' + fragment; taskName = "build-translation-fragment-" + fragment;
gulp.task(taskName, ['build-merged-translations'], function () { gulp.task(taskName, ["build-merged-translations"], function() {
// Return only the translations for this fragment. // Return only the translations for this fragment.
return gulp.src(fullDir + '/*.json') return gulp
.pipe(transform(data => ({ .src(fullDir + "/*.json")
.pipe(
transform((data) => ({
ui: { ui: {
panel: { panel: {
[fragment]: data.ui.panel[fragment], [fragment]: data.ui.panel[fragment],
}, },
}, },
}))) }))
.pipe(gulp.dest(workDir + '/' + fragment)); )
.pipe(gulp.dest(workDir + "/" + fragment));
}); });
tasks.push(taskName); tasks.push(taskName);
splitTasks.push(taskName); splitTasks.push(taskName);
}); });
taskName = 'build-translation-core'; taskName = "build-translation-core";
gulp.task(taskName, ['build-merged-translations'], function () { gulp.task(taskName, ["build-merged-translations"], function() {
// Remove the fragment translations from the core translation. // Remove the fragment translations from the core translation.
return gulp.src(fullDir + '/*.json') return gulp
.pipe(transform((data) => { .src(fullDir + "/*.json")
.pipe(
transform((data) => {
TRANSLATION_FRAGMENTS.forEach((fragment) => { TRANSLATION_FRAGMENTS.forEach((fragment) => {
delete data.ui.panel[fragment]; delete data.ui.panel[fragment];
}); });
return data; return data;
})) })
)
.pipe(gulp.dest(coreDir)); .pipe(gulp.dest(coreDir));
}); });
tasks.push(taskName); tasks.push(taskName);
splitTasks.push(taskName); splitTasks.push(taskName);
taskName = 'build-flattened-translations'; taskName = "build-flattened-translations";
gulp.task(taskName, splitTasks, function () { gulp.task(taskName, splitTasks, function() {
// Flatten the split versions of our translations, and move them into outDir // Flatten the split versions of our translations, and move them into outDir
return gulp.src( return gulp
TRANSLATION_FRAGMENTS.map(fragment => workDir + '/' + fragment + '/*.json') .src(
.concat(coreDir + '/*.json'), TRANSLATION_FRAGMENTS.map(
{ base: workDir }, (fragment) => workDir + "/" + fragment + "/*.json"
).concat(coreDir + "/*.json"),
{ base: workDir }
) )
.pipe(transform(function (data) { .pipe(
transform(function(data) {
// Polymer.AppLocalizeBehavior requires flattened json // Polymer.AppLocalizeBehavior requires flattened json
return flatten(data); return flatten(data);
})) })
)
.pipe(minify()) .pipe(minify())
.pipe(rename((filePath) => { .pipe(
if (filePath.dirname === 'core') { rename((filePath) => {
filePath.dirname = ''; if (filePath.dirname === "core") {
filePath.dirname = "";
} }
})) })
)
.pipe(gulp.dest(outDir)); .pipe(gulp.dest(outDir));
}); });
tasks.push(taskName); tasks.push(taskName);
taskName = 'build-translation-fingerprints'; taskName = "build-translation-fingerprints";
gulp.task(taskName, ['build-flattened-translations'], function () { gulp.task(taskName, ["build-flattened-translations"], function() {
return gulp.src(outDir + '/**/*.json') return gulp
.pipe(rename({ .src(outDir + "/**/*.json")
extname: '', .pipe(
})) rename({
.pipe(hash({ extname: "",
algorithm: 'md5', })
)
.pipe(
hash({
algorithm: "md5",
hashLength: 32, hashLength: 32,
template: '<%= name %>-<%= hash %>.json', template: "<%= name %>-<%= hash %>.json",
})) })
.pipe(hash.manifest('translationFingerprints.json')) )
.pipe(transform(function (data) { .pipe(hash.manifest("translationFingerprints.json"))
.pipe(
transform(function(data) {
// After generating fingerprints of our translation files, consolidate // After generating fingerprints of our translation files, consolidate
// all translation fragment fingerprints under the translation name key // all translation fragment fingerprints under the translation name key
const newData = {}; const newData = {};
Object.entries(data).forEach(([key, value]) => { Object.entries(data).forEach(([key, value]) => {
const parts = key.split('/'); const parts = key.split("/");
let translation = key; let translation = key;
if (parts.length === 2) { if (parts.length === 2) {
translation = parts[1]; translation = parts[1];
@@ -222,36 +253,44 @@ gulp.task(taskName, ['build-flattened-translations'], function () {
newData[translation].fingerprints[key] = value; newData[translation].fingerprints[key] = value;
}); });
return newData; return newData;
})) })
)
.pipe(gulp.dest(workDir)); .pipe(gulp.dest(workDir));
}); });
tasks.push(taskName); tasks.push(taskName);
taskName = 'build-translations'; taskName = "build-translations";
gulp.task(taskName, ['build-translation-fingerprints'], function () { gulp.task(taskName, ["build-translation-fingerprints"], function() {
return gulp.src([ return gulp
'src/translations/translationMetadata.json', .src([
workDir + '/translationFingerprints.json', "src/translations/translationMetadata.json",
workDir + "/translationFingerprints.json",
]) ])
.pipe(merge({})) .pipe(merge({}))
.pipe(transform(function (data) { .pipe(
transform(function(data) {
const newData = {}; const newData = {};
Object.entries(data).forEach(([key, value]) => { Object.entries(data).forEach(([key, value]) => {
// Filter out translations without native name. // Filter out translations without native name.
if (data[key].nativeName) { if (data[key].nativeName) {
newData[key] = data[key]; newData[key] = data[key];
} else { } else {
console.warn(`Skipping language ${key}. Native name was not translated.`); console.warn(
`Skipping language ${key}. Native name was not translated.`
);
} }
if (data[key]) newData[key] = value; if (data[key]) newData[key] = value;
}); });
return newData; return newData;
})) })
.pipe(transform(data => ({ )
.pipe(
transform((data) => ({
fragments: TRANSLATION_FRAGMENTS, fragments: TRANSLATION_FRAGMENTS,
translations: data, translations: data,
}))) }))
.pipe(rename('translationMetadata.json')) )
.pipe(rename("translationMetadata.json"))
.pipe(gulp.dest(workDir)); .pipe(gulp.dest(workDir));
}); });
tasks.push(taskName); tasks.push(taskName);

View File

@@ -1,8 +1,8 @@
const path = require('path'); const path = require("path");
module.exports = { module.exports = {
// Target directory for the build. // Target directory for the build.
buildDir: path.resolve(__dirname, 'build'), buildDir: path.resolve(__dirname, "build"),
// Path where the Hass.io frontend will be publicly available. // Path where the Hass.io frontend will be publicly available.
publicPath: '/api/hassio/app', publicPath: "/api/hassio/app",
} };

View File

@@ -1,15 +1,12 @@
#!/usr/bin/env node #!/usr/bin/env node
const fs = require('fs'); const fs = require("fs");
const { const { findIcons, generateIconset } = require("../../gulp/tasks/gen-icons.js");
findIcons,
generateIconset,
} = require('../../gulp/tasks/gen-icons.js');
const MENU_BUTTON_ICON = 'menu'; const MENU_BUTTON_ICON = "menu";
function genHassioIcons() { function genHassioIcons() {
const iconNames = findIcons('./src', 'hassio').concat(MENU_BUTTON_ICON); const iconNames = findIcons("./src", "hassio").concat(MENU_BUTTON_ICON);
fs.writeFileSync('./hassio-icons.html', generateIconset('hassio', iconNames)); fs.writeFileSync("./hassio-icons.html", generateIconset("hassio", iconNames));
} }
genHassioIcons(); genHassioIcons();

View File

@@ -1,10 +1,10 @@
import '@polymer/paper-card/paper-card.js'; import "@polymer/paper-card/paper-card.js";
import { html } from '@polymer/polymer/lib/utils/html-tag.js'; import { html } from "@polymer/polymer/lib/utils/html-tag.js";
import { PolymerElement } from '@polymer/polymer/polymer-element.js'; import { PolymerElement } from "@polymer/polymer/polymer-element.js";
import '../components/hassio-card-content.js'; import "../components/hassio-card-content.js";
import '../resources/hassio-style.js'; import "../resources/hassio-style.js";
import NavigateMixin from '../../../src/mixins/navigate-mixin.js'; import NavigateMixin from "../../../src/mixins/navigate-mixin.js";
class HassioAddonRepository extends NavigateMixin(PolymerElement) { class HassioAddonRepository extends NavigateMixin(PolymerElement) {
static get template() { static get template() {
@@ -52,17 +52,23 @@ class HassioAddonRepository extends NavigateMixin(PolymerElement) {
} }
computeIcon(addon) { computeIcon(addon) {
return addon.installed && addon.installed !== addon.version ? 'hassio:arrow-up-bold-circle' : 'hassio:puzzle'; return addon.installed && addon.installed !== addon.version
? "hassio:arrow-up-bold-circle"
: "hassio:puzzle";
} }
computeIconTitle(addon) { computeIconTitle(addon) {
if (addon.installed) return addon.installed !== addon.version ? 'New version available' : 'Add-on is installed'; if (addon.installed)
return 'Add-on is not installed'; return addon.installed !== addon.version
? "New version available"
: "Add-on is installed";
return "Add-on is not installed";
} }
computeIconClass(addon) { computeIconClass(addon) {
if (addon.installed) return addon.installed !== addon.version ? 'update' : 'installed'; if (addon.installed)
return ''; return addon.installed !== addon.version ? "update" : "installed";
return "";
} }
addonTapped(ev) { addonTapped(ev) {
@@ -70,4 +76,4 @@ class HassioAddonRepository extends NavigateMixin(PolymerElement) {
} }
} }
customElements.define('hassio-addon-repository', HassioAddonRepository); customElements.define("hassio-addon-repository", HassioAddonRepository);

View File

@@ -1,8 +1,8 @@
import { html } from '@polymer/polymer/lib/utils/html-tag.js'; import { html } from "@polymer/polymer/lib/utils/html-tag.js";
import { PolymerElement } from '@polymer/polymer/polymer-element.js'; import { PolymerElement } from "@polymer/polymer/polymer-element.js";
import './hassio-addon-repository.js'; import "./hassio-addon-repository.js";
import './hassio-repositories-editor.js'; import "./hassio-repositories-editor.js";
class HassioAddonStore extends PolymerElement { class HassioAddonStore extends PolymerElement {
static get template() { static get template() {
@@ -30,7 +30,7 @@ class HassioAddonStore extends PolymerElement {
ready() { ready() {
super.ready(); super.ready();
this.addEventListener('hass-api-called', ev => this.apiCalled(ev)); this.addEventListener("hass-api-called", (ev) => this.apiCalled(ev));
this.loadData(); this.loadData();
} }
@@ -41,42 +41,45 @@ class HassioAddonStore extends PolymerElement {
} }
sortRepos(a, b) { sortRepos(a, b) {
if (a.slug === 'local') { if (a.slug === "local") {
return -1; return -1;
} if (b.slug === 'local') { }
if (b.slug === "local") {
return 1; return 1;
} if (a.slug === 'core') { }
if (a.slug === "core") {
return -1; return -1;
} if (b.slug === 'core') { }
if (b.slug === "core") {
return 1; return 1;
} }
return a.name < b.name ? -1 : 1; return a.name < b.name ? -1 : 1;
} }
computeAddons(repo) { computeAddons(repo) {
return this.addons.filter(function (addon) { return this.addons.filter(function(addon) {
return addon.repository === repo; return addon.repository === repo;
}); });
} }
loadData() { loadData() {
this.hass.callApi('get', 'hassio/addons') this.hass.callApi("get", "hassio/addons").then(
.then((info) => { (info) => {
this.addons = info.data.addons; this.addons = info.data.addons;
this.repos = info.data.repositories; this.repos = info.data.repositories;
}, () => { },
() => {
this.addons = []; this.addons = [];
this.repos = []; this.repos = [];
}); }
);
} }
refreshData() { refreshData() {
this.hass.callApi('post', 'hassio/addons/reload') this.hass.callApi("post", "hassio/addons/reload").then(() => {
.then(() => {
this.loadData(); this.loadData();
}); });
} }
} }
customElements.define('hassio-addon-store', HassioAddonStore); customElements.define("hassio-addon-store", HassioAddonStore);

View File

@@ -1,12 +1,12 @@
import '@polymer/iron-icon/iron-icon.js'; import "@polymer/iron-icon/iron-icon.js";
import '@polymer/paper-card/paper-card.js'; import "@polymer/paper-card/paper-card.js";
import '@polymer/paper-input/paper-input.js'; import "@polymer/paper-input/paper-input.js";
import { html } from '@polymer/polymer/lib/utils/html-tag.js'; import { html } from "@polymer/polymer/lib/utils/html-tag.js";
import { PolymerElement } from '@polymer/polymer/polymer-element.js'; import { PolymerElement } from "@polymer/polymer/polymer-element.js";
import '../../../src/components/buttons/ha-call-api-button.js'; import "../../../src/components/buttons/ha-call-api-button.js";
import '../components/hassio-card-content.js'; import "../components/hassio-card-content.js";
import '../resources/hassio-style.js'; import "../resources/hassio-style.js";
class HassioRepositoriesEditor extends PolymerElement { class HassioRepositoriesEditor extends PolymerElement {
static get template() { static get template() {
@@ -60,7 +60,7 @@ class HassioRepositoriesEditor extends PolymerElement {
hass: Object, hass: Object,
repos: { repos: {
type: Array, type: Array,
observer: 'reposChanged', observer: "reposChanged",
}, },
repoList: Array, repoList: Array,
repoUrl: String, repoUrl: String,
@@ -68,8 +68,10 @@ class HassioRepositoriesEditor extends PolymerElement {
} }
reposChanged(repos) { reposChanged(repos) {
this.repoList = repos.filter(repo => repo.slug !== 'core' && repo.slug !== 'local'); this.repoList = repos.filter(
this.repoUrl = ''; (repo) => repo.slug !== "core" && repo.slug !== "local"
);
this.repoUrl = "";
} }
sortRepos(a, b) { sortRepos(a, b) {
@@ -77,15 +79,17 @@ class HassioRepositoriesEditor extends PolymerElement {
} }
computeRemoveRepoData(repoList, url) { computeRemoveRepoData(repoList, url) {
const list = repoList.filter(repo => repo.url !== url).map(repo => repo.url); const list = repoList
.filter((repo) => repo.url !== url)
.map((repo) => repo.url);
return { addons_repositories: list }; return { addons_repositories: list };
} }
computeAddRepoData(repoList, url) { computeAddRepoData(repoList, url) {
const list = repoList ? repoList.map(repo => repo.url) : []; const list = repoList ? repoList.map((repo) => repo.url) : [];
list.push(url); list.push(url);
return { addons_repositories: list }; return { addons_repositories: list };
} }
} }
customElements.define('hassio-repositories-editor', HassioRepositoriesEditor); customElements.define("hassio-repositories-editor", HassioRepositoriesEditor);

View File

@@ -1,15 +1,15 @@
import 'web-animations-js/web-animations-next-lite.min.js'; import "web-animations-js/web-animations-next-lite.min.js";
import '@polymer/paper-button/paper-button.js'; import "@polymer/paper-button/paper-button.js";
import '@polymer/paper-card/paper-card.js'; import "@polymer/paper-card/paper-card.js";
import '@polymer/paper-dropdown-menu/paper-dropdown-menu.js'; import "@polymer/paper-dropdown-menu/paper-dropdown-menu.js";
import '@polymer/paper-item/paper-item.js'; import "@polymer/paper-item/paper-item.js";
import '@polymer/paper-listbox/paper-listbox.js'; import "@polymer/paper-listbox/paper-listbox.js";
import { html } from '@polymer/polymer/lib/utils/html-tag.js'; import { html } from "@polymer/polymer/lib/utils/html-tag.js";
import { PolymerElement } from '@polymer/polymer/polymer-element.js'; import { PolymerElement } from "@polymer/polymer/polymer-element.js";
import '../../../src/resources/ha-style.js'; import "../../../src/resources/ha-style.js";
import EventsMixin from '../../../src/mixins/events-mixin.js'; import EventsMixin from "../../../src/mixins/events-mixin.js";
class HassioAddonAudio extends EventsMixin(PolymerElement) { class HassioAddonAudio extends EventsMixin(PolymerElement) {
static get template() { static get template() {
@@ -64,7 +64,7 @@ class HassioAddonAudio extends EventsMixin(PolymerElement) {
hass: Object, hass: Object,
addon: { addon: {
type: Object, type: Object,
observer: 'addonChanged' observer: "addonChanged",
}, },
inputDevices: Array, inputDevices: Array,
outputDevices: Array, outputDevices: Array,
@@ -76,40 +76,55 @@ class HassioAddonAudio extends EventsMixin(PolymerElement) {
addonChanged(addon) { addonChanged(addon) {
this.setProperties({ this.setProperties({
selectedInput: addon.audio_input || 'null', selectedInput: addon.audio_input || "null",
selectedOutput: addon.audio_output || 'null' selectedOutput: addon.audio_output || "null",
}); });
if (this.outputDevices) return; if (this.outputDevices) return;
const noDevice = [{ device: 'null', name: '-' }]; const noDevice = [{ device: "null", name: "-" }];
this.hass.callApi('get', 'hassio/hardware/audio').then((resp) => { this.hass.callApi("get", "hassio/hardware/audio").then(
(resp) => {
const dev = resp.data.audio; const dev = resp.data.audio;
const input = Object.keys(dev.input).map(key => ({ device: key, name: dev.input[key] })); const input = Object.keys(dev.input).map((key) => ({
const output = Object.keys(dev.output).map(key => ({ device: key, name: dev.output[key] })); device: key,
name: dev.input[key],
}));
const output = Object.keys(dev.output).map((key) => ({
device: key,
name: dev.output[key],
}));
this.setProperties({ this.setProperties({
inputDevices: noDevice.concat(input), inputDevices: noDevice.concat(input),
outputDevices: noDevice.concat(output) outputDevices: noDevice.concat(output),
}); });
}, () => { },
() => {
this.setProperties({ this.setProperties({
inputDevices: noDevice, inputDevices: noDevice,
outputDevices: noDevice outputDevices: noDevice,
});
}); });
} }
);
}
_saveSettings() { _saveSettings() {
this.error = null; this.error = null;
const path = `hassio/addons/${this.addon.slug}/options`; const path = `hassio/addons/${this.addon.slug}/options`;
this.hass.callApi('post', path, { this.hass
audio_input: this.selectedInput === 'null' ? null : this.selectedInput, .callApi("post", path, {
audio_output: this.selectedOutput === 'null' ? null : this.selectedOutput audio_input: this.selectedInput === "null" ? null : this.selectedInput,
}).then(() => { audio_output:
this.fire('hass-api-called', { success: true, path: path }); this.selectedOutput === "null" ? null : this.selectedOutput,
}, (resp) => { })
.then(
() => {
this.fire("hass-api-called", { success: true, path: path });
},
(resp) => {
this.error = resp.body.message; this.error = resp.body.message;
}); }
);
} }
} }
customElements.define('hassio-addon-audio', HassioAddonAudio); customElements.define("hassio-addon-audio", HassioAddonAudio);

View File

@@ -1,10 +1,10 @@
import '@polymer/iron-autogrow-textarea/iron-autogrow-textarea.js'; import "@polymer/iron-autogrow-textarea/iron-autogrow-textarea.js";
import '@polymer/paper-button/paper-button.js'; import "@polymer/paper-button/paper-button.js";
import '@polymer/paper-card/paper-card.js'; import "@polymer/paper-card/paper-card.js";
import { html } from '@polymer/polymer/lib/utils/html-tag.js'; import { html } from "@polymer/polymer/lib/utils/html-tag.js";
import { PolymerElement } from '@polymer/polymer/polymer-element.js'; import { PolymerElement } from "@polymer/polymer/polymer-element.js";
import '../../../src/components/buttons/ha-call-api-button.js'; import "../../../src/components/buttons/ha-call-api-button.js";
class HassioAddonConfig extends PolymerElement { class HassioAddonConfig extends PolymerElement {
static get template() { static get template() {
@@ -52,12 +52,12 @@ class HassioAddonConfig extends PolymerElement {
hass: Object, hass: Object,
addon: { addon: {
type: Object, type: Object,
observer: 'addonChanged', observer: "addonChanged",
}, },
addonSlug: String, addonSlug: String,
config: { config: {
type: String, type: String,
observer: 'configChanged', observer: "configChanged",
}, },
configParsed: Object, configParsed: Object,
error: String, error: String,
@@ -71,15 +71,15 @@ class HassioAddonConfig extends PolymerElement {
} }
addonChanged(addon) { addonChanged(addon) {
this.config = addon ? JSON.stringify(addon.options, null, 2) : ''; this.config = addon ? JSON.stringify(addon.options, null, 2) : "";
} }
configChanged(config) { configChanged(config) {
try { try {
this.$.config.classList.remove('syntaxerror'); this.$.config.classList.remove("syntaxerror");
this.configParsed = JSON.parse(config); this.configParsed = JSON.parse(config);
} catch (err) { } catch (err) {
this.$.config.classList.add('syntaxerror'); this.$.config.classList.add("syntaxerror");
this.configParsed = null; this.configParsed = null;
} }
} }
@@ -87,12 +87,14 @@ class HassioAddonConfig extends PolymerElement {
saveTapped() { saveTapped() {
this.error = null; this.error = null;
this.hass.callApi('post', `hassio/addons/${this.addonSlug}/options`, { this.hass
options: this.configParsed .callApi("post", `hassio/addons/${this.addonSlug}/options`, {
}).catch((resp) => { options: this.configParsed,
})
.catch((resp) => {
this.error = resp.body.message; this.error = resp.body.message;
}); });
} }
} }
customElements.define('hassio-addon-config', HassioAddonConfig); customElements.define("hassio-addon-config", HassioAddonConfig);

View File

@@ -1,16 +1,16 @@
import '@polymer/iron-icon/iron-icon.js'; import "@polymer/iron-icon/iron-icon.js";
import '@polymer/paper-button/paper-button.js'; import "@polymer/paper-button/paper-button.js";
import '@polymer/paper-card/paper-card.js'; import "@polymer/paper-card/paper-card.js";
import '@polymer/paper-toggle-button/paper-toggle-button.js'; import "@polymer/paper-toggle-button/paper-toggle-button.js";
import { html } from '@polymer/polymer/lib/utils/html-tag.js'; import { html } from "@polymer/polymer/lib/utils/html-tag.js";
import { PolymerElement } from '@polymer/polymer/polymer-element.js'; import { PolymerElement } from "@polymer/polymer/polymer-element.js";
import '../../../src/components/buttons/ha-call-api-button.js'; import "../../../src/components/buttons/ha-call-api-button.js";
import '../../../src/components/ha-markdown.js'; import "../../../src/components/ha-markdown.js";
import '../../../src/resources/ha-style.js'; import "../../../src/resources/ha-style.js";
import EventsMixin from '../../../src/mixins/events-mixin.js'; import EventsMixin from "../../../src/mixins/events-mixin.js";
import '../components/hassio-card-content.js'; import "../components/hassio-card-content.js";
class HassioAddonInfo extends EventsMixin(PolymerElement) { class HassioAddonInfo extends EventsMixin(PolymerElement) {
static get template() { static get template() {
@@ -157,21 +157,26 @@ class HassioAddonInfo extends EventsMixin(PolymerElement) {
addonSlug: String, addonSlug: String,
isRunning: { isRunning: {
type: Boolean, type: Boolean,
computed: 'computeIsRunning(addon)', computed: "computeIsRunning(addon)",
}, },
}; };
} }
computeIsRunning(addon) { computeIsRunning(addon) {
return addon && addon.state === 'started'; return addon && addon.state === "started";
} }
computeUpdateAvailable(addon) { computeUpdateAvailable(addon) {
return addon && !addon.detached && addon.version && addon.version !== addon.last_version; return (
addon &&
!addon.detached &&
addon.version &&
addon.version !== addon.last_version
);
} }
pathWebui(webui) { pathWebui(webui) {
return webui && webui.replace('[HOST]', document.location.hostname); return webui && webui.replace("[HOST]", document.location.hostname);
} }
computeShowWebUI(webui, isRunning) { computeShowWebUI(webui, isRunning) {
@@ -179,49 +184,54 @@ class HassioAddonInfo extends EventsMixin(PolymerElement) {
} }
computeStartOnBoot(state) { computeStartOnBoot(state) {
return state === 'auto'; return state === "auto";
} }
startOnBootToggled() { startOnBootToggled() {
const data = { boot: this.addon.boot === 'auto' ? 'manual' : 'auto' }; const data = { boot: this.addon.boot === "auto" ? "manual" : "auto" };
this.hass.callApi('POST', `hassio/addons/${this.addonSlug}/options`, data); this.hass.callApi("POST", `hassio/addons/${this.addonSlug}/options`, data);
} }
autoUpdateToggled() { autoUpdateToggled() {
const data = { auto_update: !this.addon.auto_update }; const data = { auto_update: !this.addon.auto_update };
this.hass.callApi('POST', `hassio/addons/${this.addonSlug}/options`, data); this.hass.callApi("POST", `hassio/addons/${this.addonSlug}/options`, data);
} }
openChangelog() { openChangelog() {
this.hass.callApi('get', `hassio/addons/${this.addonSlug}/changelog`) this.hass
.then( .callApi("get", `hassio/addons/${this.addonSlug}/changelog`)
resp => resp, .then((resp) => resp, () => "Error getting changelog")
() => 'Error getting changelog' .then((content) => {
).then((content) => { this.fire("hassio-markdown-dialog", {
this.fire('hassio-markdown-dialog', { title: "Changelog",
title: 'Changelog',
content: content, content: content,
}); });
}); });
} }
_unistallClicked() { _unistallClicked() {
if (!confirm('Are you sure you want to uninstall this add-on?')) { if (!confirm("Are you sure you want to uninstall this add-on?")) {
return; return;
} }
const path = `hassio/addons/${this.addonSlug}/uninstall`; const path = `hassio/addons/${this.addonSlug}/uninstall`;
const eventData = { const eventData = {
path: path, path: path,
}; };
this.hass.callApi('post', path).then((resp) => { this.hass
.callApi("post", path)
.then(
(resp) => {
eventData.success = true; eventData.success = true;
eventData.response = resp; eventData.response = resp;
}, (resp) => { },
(resp) => {
eventData.success = false; eventData.success = false;
eventData.response = resp; eventData.response = resp;
}).then(() => { }
this.fire('hass-api-called', eventData); )
.then(() => {
this.fire("hass-api-called", eventData);
}); });
} }
} }
customElements.define('hassio-addon-info', HassioAddonInfo); customElements.define("hassio-addon-info", HassioAddonInfo);

View File

@@ -1,9 +1,9 @@
import '@polymer/paper-button/paper-button.js'; import "@polymer/paper-button/paper-button.js";
import '@polymer/paper-card/paper-card.js'; import "@polymer/paper-card/paper-card.js";
import { html } from '@polymer/polymer/lib/utils/html-tag.js'; import { html } from "@polymer/polymer/lib/utils/html-tag.js";
import { PolymerElement } from '@polymer/polymer/polymer-element.js'; import { PolymerElement } from "@polymer/polymer/polymer-element.js";
import '../../../src/resources/ha-style.js'; import "../../../src/resources/ha-style.js";
class HassioAddonLogs extends PolymerElement { class HassioAddonLogs extends PolymerElement {
static get template() { static get template() {
@@ -33,7 +33,7 @@ class HassioAddonLogs extends PolymerElement {
hass: Object, hass: Object,
addonSlug: { addonSlug: {
type: String, type: String,
observer: 'addonSlugChanged', observer: "addonSlugChanged",
}, },
log: String, log: String,
}; };
@@ -41,7 +41,9 @@ class HassioAddonLogs extends PolymerElement {
addonSlugChanged(slug) { addonSlugChanged(slug) {
if (!this.hass) { if (!this.hass) {
setTimeout(() => { this.addonChanged(slug); }, 0); setTimeout(() => {
this.addonChanged(slug);
}, 0);
return; return;
} }
@@ -49,11 +51,12 @@ class HassioAddonLogs extends PolymerElement {
} }
refresh() { refresh() {
this.hass.callApi('get', `hassio/addons/${this.addonSlug}/logs`) this.hass
.callApi("get", `hassio/addons/${this.addonSlug}/logs`)
.then((info) => { .then((info) => {
this.log = info; this.log = info;
}); });
} }
} }
customElements.define('hassio-addon-logs', HassioAddonLogs); customElements.define("hassio-addon-logs", HassioAddonLogs);

View File

@@ -1,11 +1,11 @@
import '@polymer/paper-card/paper-card.js'; import "@polymer/paper-card/paper-card.js";
import '@polymer/paper-input/paper-input.js'; import "@polymer/paper-input/paper-input.js";
import { html } from '@polymer/polymer/lib/utils/html-tag.js'; import { html } from "@polymer/polymer/lib/utils/html-tag.js";
import { PolymerElement } from '@polymer/polymer/polymer-element.js'; import { PolymerElement } from "@polymer/polymer/polymer-element.js";
import '../../../src/components/buttons/ha-call-api-button.js'; import "../../../src/components/buttons/ha-call-api-button.js";
import '../../../src/resources/ha-style.js'; import "../../../src/resources/ha-style.js";
import EventsMixin from '../../../src/mixins/events-mixin.js'; import EventsMixin from "../../../src/mixins/events-mixin.js";
class HassioAddonNetwork extends EventsMixin(PolymerElement) { class HassioAddonNetwork extends EventsMixin(PolymerElement) {
static get template() { static get template() {
@@ -64,7 +64,7 @@ class HassioAddonNetwork extends EventsMixin(PolymerElement) {
config: Object, config: Object,
addon: { addon: {
type: Object, type: Object,
observer: 'addonChanged', observer: "addonChanged",
}, },
error: String, error: String,
resetData: { resetData: {
@@ -80,29 +80,36 @@ class HassioAddonNetwork extends EventsMixin(PolymerElement) {
if (!addon) return; if (!addon) return;
const network = addon.network || {}; const network = addon.network || {};
const items = Object.keys(network).map(key => ({ const items = Object.keys(network).map((key) => ({
container: key, container: key,
host: network[key] host: network[key],
})); }));
this.config = items.sort(function (el1, el2) { return el1.host - el2.host; }); this.config = items.sort(function(el1, el2) {
return el1.host - el2.host;
});
} }
saveTapped() { saveTapped() {
this.error = null; this.error = null;
const data = {}; const data = {};
this.config.forEach(function (item) { this.config.forEach(function(item) {
data[item.container] = parseInt(item.host); data[item.container] = parseInt(item.host);
}); });
const path = `hassio/addons/${this.addonSlug}/options`; const path = `hassio/addons/${this.addonSlug}/options`;
this.hass.callApi('post', path, { this.hass
network: data .callApi("post", path, {
}).then(() => { network: data,
this.fire('hass-api-called', { success: true, path: path }); })
}, (resp) => { .then(
() => {
this.fire("hass-api-called", { success: true, path: path });
},
(resp) => {
this.error = resp.body.message; this.error = resp.body.message;
}); }
);
} }
} }
customElements.define('hassio-addon-network', HassioAddonNetwork); customElements.define("hassio-addon-network", HassioAddonNetwork);

View File

@@ -1,19 +1,19 @@
import '@polymer/app-layout/app-header-layout/app-header-layout.js'; import "@polymer/app-layout/app-header-layout/app-header-layout.js";
import '@polymer/app-layout/app-header/app-header.js'; import "@polymer/app-layout/app-header/app-header.js";
import '@polymer/app-layout/app-toolbar/app-toolbar.js'; import "@polymer/app-layout/app-toolbar/app-toolbar.js";
import '@polymer/app-route/app-route.js'; import "@polymer/app-route/app-route.js";
import '@polymer/paper-icon-button/paper-icon-button.js'; import "@polymer/paper-icon-button/paper-icon-button.js";
import { html } from '@polymer/polymer/lib/utils/html-tag.js'; import { html } from "@polymer/polymer/lib/utils/html-tag.js";
import { PolymerElement } from '@polymer/polymer/polymer-element.js'; import { PolymerElement } from "@polymer/polymer/polymer-element.js";
import '../../../src/components/ha-menu-button.js'; import "../../../src/components/ha-menu-button.js";
import '../../../src/resources/ha-style.js'; import "../../../src/resources/ha-style.js";
import '../hassio-markdown-dialog.js'; import "../hassio-markdown-dialog.js";
import './hassio-addon-audio.js'; import "./hassio-addon-audio.js";
import './hassio-addon-config.js'; import "./hassio-addon-config.js";
import './hassio-addon-info.js'; import "./hassio-addon-info.js";
import './hassio-addon-logs.js'; import "./hassio-addon-logs.js";
import './hassio-addon-network.js'; import "./hassio-addon-network.js";
class HassioAddonView extends PolymerElement { class HassioAddonView extends PolymerElement {
static get template() { static get template() {
@@ -91,7 +91,7 @@ class HassioAddonView extends PolymerElement {
route: Object, route: Object,
routeData: { routeData: {
type: Object, type: Object,
observer: 'routeDataChanged', observer: "routeDataChanged",
}, },
routeMatches: Boolean, routeMatches: Boolean,
addon: Object, addon: Object,
@@ -99,15 +99,17 @@ class HassioAddonView extends PolymerElement {
markdownTitle: String, markdownTitle: String,
markdownContent: { markdownContent: {
type: String, type: String,
value: '', value: "",
}, },
}; };
} }
ready() { ready() {
super.ready(); super.ready();
this.addEventListener('hass-api-called', ev => this.apiCalled(ev)); this.addEventListener("hass-api-called", (ev) => this.apiCalled(ev));
this.addEventListener('hassio-markdown-dialog', ev => this.openMarkdown(ev)); this.addEventListener("hassio-markdown-dialog", (ev) =>
this.openMarkdown(ev)
);
} }
apiCalled(ev) { apiCalled(ev) {
@@ -115,7 +117,7 @@ class HassioAddonView extends PolymerElement {
if (!path) return; if (!path) return;
if (path.substr(path.lastIndexOf('/') + 1) === 'uninstall') { if (path.substr(path.lastIndexOf("/") + 1) === "uninstall") {
this.backTapped(); this.backTapped();
} else { } else {
this.routeDataChanged(this.routeData); this.routeDataChanged(this.routeData);
@@ -124,12 +126,14 @@ class HassioAddonView extends PolymerElement {
routeDataChanged(routeData) { routeDataChanged(routeData) {
if (!this.routeMatches || !routeData || !routeData.slug) return; if (!this.routeMatches || !routeData || !routeData.slug) return;
this.hass.callApi('get', `hassio/addons/${routeData.slug}/info`) this.hass.callApi("get", `hassio/addons/${routeData.slug}/info`).then(
.then((info) => { (info) => {
this.addon = info.data; this.addon = info.data;
}, () => { },
() => {
this.addon = null; this.addon = null;
}); }
);
} }
backTapped() { backTapped() {
@@ -141,8 +145,8 @@ class HassioAddonView extends PolymerElement {
markdownTitle: ev.detail.title, markdownTitle: ev.detail.title,
markdownContent: ev.detail.content, markdownContent: ev.detail.content,
}); });
this.shadowRoot.querySelector('hassio-markdown-dialog').openDialog(); this.shadowRoot.querySelector("hassio-markdown-dialog").openDialog();
} }
} }
customElements.define('hassio-addon-view', HassioAddonView); customElements.define("hassio-addon-view", HassioAddonView);

View File

@@ -1,8 +1,8 @@
import '@polymer/iron-icon/iron-icon.js'; import "@polymer/iron-icon/iron-icon.js";
import { html } from '@polymer/polymer/lib/utils/html-tag.js'; import { html } from "@polymer/polymer/lib/utils/html-tag.js";
import { PolymerElement } from '@polymer/polymer/polymer-element.js'; import { PolymerElement } from "@polymer/polymer/polymer-element.js";
import '../../../src/components/ha-relative-time.js'; import "../../../src/components/ha-relative-time.js";
class HassioCardContent extends PolymerElement { class HassioCardContent extends PolymerElement {
static get template() { static get template() {
@@ -65,11 +65,11 @@ class HassioCardContent extends PolymerElement {
datetime: String, datetime: String,
icon: { icon: {
type: String, type: String,
value: 'hass:help-circle' value: "hass:help-circle",
}, },
iconTitle: String, iconTitle: String,
iconClass: String, iconClass: String,
}; };
} }
} }
customElements.define('hassio-card-content', HassioCardContent); customElements.define("hassio-card-content", HassioCardContent);

View File

@@ -1,10 +1,10 @@
import '@polymer/paper-card/paper-card.js'; import "@polymer/paper-card/paper-card.js";
import { html } from '@polymer/polymer/lib/utils/html-tag.js'; import { html } from "@polymer/polymer/lib/utils/html-tag.js";
import { PolymerElement } from '@polymer/polymer/polymer-element.js'; import { PolymerElement } from "@polymer/polymer/polymer-element.js";
import '../components/hassio-card-content.js'; import "../components/hassio-card-content.js";
import '../resources/hassio-style.js'; import "../resources/hassio-style.js";
import NavigateMixin from '../../../src/mixins/navigate-mixin.js'; import NavigateMixin from "../../../src/mixins/navigate-mixin.js";
class HassioAddons extends NavigateMixin(PolymerElement) { class HassioAddons extends NavigateMixin(PolymerElement) {
static get template() { static get template() {
@@ -46,28 +46,32 @@ class HassioAddons extends NavigateMixin(PolymerElement) {
} }
computeIcon(addon) { computeIcon(addon) {
return addon.installed !== addon.version ? 'hassio:arrow-up-bold-circle' : 'hassio:puzzle'; return addon.installed !== addon.version
? "hassio:arrow-up-bold-circle"
: "hassio:puzzle";
} }
computeIconTitle(addon) { computeIconTitle(addon) {
if (addon.installed !== addon.version) return 'New version available'; if (addon.installed !== addon.version) return "New version available";
return addon.state === 'started' ? 'Add-on is running' : 'Add-on is stopped'; return addon.state === "started"
? "Add-on is running"
: "Add-on is stopped";
} }
computeIconClass(addon) { computeIconClass(addon) {
if (addon.installed !== addon.version) return 'update'; if (addon.installed !== addon.version) return "update";
return addon.state === 'started' ? 'running' : ''; return addon.state === "started" ? "running" : "";
} }
addonTapped(ev) { addonTapped(ev) {
this.navigate('/hassio/addon/' + ev.model.addon.slug); this.navigate("/hassio/addon/" + ev.model.addon.slug);
ev.target.blur(); ev.target.blur();
} }
openStore(ev) { openStore(ev) {
this.navigate('/hassio/store'); this.navigate("/hassio/store");
ev.target.blur(); ev.target.blur();
} }
} }
customElements.define('hassio-addons', HassioAddons); customElements.define("hassio-addons", HassioAddons);

View File

@@ -1,9 +1,9 @@
import { html } from '@polymer/polymer/lib/utils/html-tag.js'; import { html } from "@polymer/polymer/lib/utils/html-tag.js";
import { PolymerElement } from '@polymer/polymer/polymer-element.js'; import { PolymerElement } from "@polymer/polymer/polymer-element.js";
import './hassio-addons.js'; import "./hassio-addons.js";
import './hassio-hass-update.js'; import "./hassio-hass-update.js";
import EventsMixin from '../../../src/mixins/events-mixin.js'; import EventsMixin from "../../../src/mixins/events-mixin.js";
class HassioDashboard extends EventsMixin(PolymerElement) { class HassioDashboard extends EventsMixin(PolymerElement) {
static get template() { static get template() {
@@ -29,4 +29,4 @@ class HassioDashboard extends EventsMixin(PolymerElement) {
} }
} }
customElements.define('hassio-dashboard', HassioDashboard); customElements.define("hassio-dashboard", HassioDashboard);

View File

@@ -1,11 +1,11 @@
import '@polymer/paper-button/paper-button.js'; import "@polymer/paper-button/paper-button.js";
import '@polymer/paper-card/paper-card.js'; import "@polymer/paper-card/paper-card.js";
import { html } from '@polymer/polymer/lib/utils/html-tag.js'; import { html } from "@polymer/polymer/lib/utils/html-tag.js";
import { PolymerElement } from '@polymer/polymer/polymer-element.js'; import { PolymerElement } from "@polymer/polymer/polymer-element.js";
import '../../../src/components/buttons/ha-call-api-button.js'; import "../../../src/components/buttons/ha-call-api-button.js";
import '../components/hassio-card-content.js'; import "../components/hassio-card-content.js";
import '../resources/hassio-style.js'; import "../resources/hassio-style.js";
class HassioHassUpdate extends PolymerElement { class HassioHassUpdate extends PolymerElement {
static get template() { static get template() {
@@ -56,7 +56,7 @@ class HassioHassUpdate extends PolymerElement {
ready() { ready() {
super.ready(); super.ready();
this.addEventListener('hass-api-called', ev => this.apiCalled(ev)); this.addEventListener("hass-api-called", (ev) => this.apiCalled(ev));
} }
apiCalled(ev) { apiCalled(ev) {
@@ -67,8 +67,8 @@ class HassioHassUpdate extends PolymerElement {
const response = ev.detail.response; const response = ev.detail.response;
if (typeof response.body === 'object') { if (typeof response.body === "object") {
this.errors = response.body.message || 'Unknown error'; this.errors = response.body.message || "Unknown error";
} else { } else {
this.errors = response.body; this.errors = response.body;
} }
@@ -79,4 +79,4 @@ class HassioHassUpdate extends PolymerElement {
} }
} }
customElements.define('hassio-hass-update', HassioHassUpdate); customElements.define("hassio-hass-update", HassioHassUpdate);

View File

@@ -1,4 +1,4 @@
window.loadES5Adapter().then(() => { window.loadES5Adapter().then(() => {
import(/* webpackChunkName: "hassio-icons" */ './resources/hassio-icons.js'); import(/* webpackChunkName: "hassio-icons" */ "./resources/hassio-icons.js");
import(/* webpackChunkName: "hassio-main" */ './hassio-main.js'); import(/* webpackChunkName: "hassio-main" */ "./hassio-main.js");
}); });

View File

@@ -1,8 +1,8 @@
import { html } from '@polymer/polymer/lib/utils/html-tag.js'; import { html } from "@polymer/polymer/lib/utils/html-tag.js";
import { PolymerElement } from '@polymer/polymer/polymer-element.js'; import { PolymerElement } from "@polymer/polymer/polymer-element.js";
import './hassio-main.js'; import "./hassio-main.js";
import './resources/hassio-icons.js'; import "./resources/hassio-icons.js";
class HassioApp extends PolymerElement { class HassioApp extends PolymerElement {
static get template() { static get template() {
@@ -29,13 +29,13 @@ class HassioApp extends PolymerElement {
ready() { ready() {
super.ready(); super.ready();
window.setProperties = this.setProperties.bind(this); window.setProperties = this.setProperties.bind(this);
this.addEventListener('location-changed', () => this._locationChanged()); this.addEventListener("location-changed", () => this._locationChanged());
this.addEventListener('hass-open-menu', () => this._menuEvent(true)); this.addEventListener("hass-open-menu", () => this._menuEvent(true));
this.addEventListener('hass-close-menu', () => this._menuEvent(false)); this.addEventListener("hass-close-menu", () => this._menuEvent(false));
} }
_menuEvent(shouldOpen) { _menuEvent(shouldOpen) {
this.hassioPanel.fire(shouldOpen ? 'hass-open-menu' : 'hass-close-menu'); this.hassioPanel.fire(shouldOpen ? "hass-open-menu" : "hass-close-menu");
} }
_locationChanged() { _locationChanged() {
@@ -43,4 +43,4 @@ class HassioApp extends PolymerElement {
} }
} }
customElements.define('hassio-app', HassioApp); customElements.define("hassio-app", HassioApp);

View File

@@ -1,4 +1,4 @@
import { PolymerElement } from '@polymer/polymer/polymer-element.js'; import { PolymerElement } from "@polymer/polymer/polymer-element.js";
class HassioData extends PolymerElement { class HassioData extends PolymerElement {
static get properties() { static get properties() {
@@ -36,25 +36,24 @@ class HassioData extends PolymerElement {
} }
fetchSupervisorInfo() { fetchSupervisorInfo() {
return this.hass.callApi('get', 'hassio/supervisor/info') return this.hass.callApi("get", "hassio/supervisor/info").then((info) => {
.then((info) => {
this.supervisor = info.data; this.supervisor = info.data;
}); });
} }
fetchHostInfo() { fetchHostInfo() {
return this.hass.callApi('get', 'hassio/host/info') return this.hass.callApi("get", "hassio/host/info").then((info) => {
.then((info) => {
this.host = info.data; this.host = info.data;
}); });
} }
fetchHassInfo() { fetchHassInfo() {
return this.hass.callApi('get', 'hassio/homeassistant/info') return this.hass
.callApi("get", "hassio/homeassistant/info")
.then((info) => { .then((info) => {
this.homeassistant = info.data; this.homeassistant = info.data;
}); });
} }
} }
customElements.define('hassio-data', HassioData); customElements.define("hassio-data", HassioData);

View File

@@ -1,15 +1,15 @@
import '@polymer/app-route/app-route.js'; import "@polymer/app-route/app-route.js";
import { html } from '@polymer/polymer/lib/utils/html-tag.js'; import { html } from "@polymer/polymer/lib/utils/html-tag.js";
import { PolymerElement } from '@polymer/polymer/polymer-element.js'; import { PolymerElement } from "@polymer/polymer/polymer-element.js";
import '../../src/layouts/hass-loading-screen.js'; import "../../src/layouts/hass-loading-screen.js";
import './addon-view/hassio-addon-view.js'; import "./addon-view/hassio-addon-view.js";
import './hassio-data.js'; import "./hassio-data.js";
import './hassio-pages-with-tabs.js'; import "./hassio-pages-with-tabs.js";
import applyThemesOnElement from '../../src/common/dom/apply_themes_on_element.js'; import applyThemesOnElement from "../../src/common/dom/apply_themes_on_element.js";
import EventsMixin from '../../src/mixins/events-mixin.js'; import EventsMixin from "../../src/mixins/events-mixin.js";
import NavigateMixin from '../../src/mixins/navigate-mixin.js'; import NavigateMixin from "../../src/mixins/navigate-mixin.js";
class HassioMain extends EventsMixin(NavigateMixin(PolymerElement)) { class HassioMain extends EventsMixin(NavigateMixin(PolymerElement)) {
static get template() { static get template() {
@@ -41,11 +41,11 @@ class HassioMain extends EventsMixin(NavigateMixin(PolymerElement)) {
type: Object, type: Object,
// Fake route object // Fake route object
value: { value: {
prefix: '/hassio', prefix: "/hassio",
path: '/dashboard', path: "/dashboard",
__queryParams: {} __queryParams: {},
}, },
observer: 'routeChanged', observer: "routeChanged",
}, },
routeData: Object, routeData: Object,
supervisorInfo: Object, supervisorInfo: Object,
@@ -53,7 +53,7 @@ class HassioMain extends EventsMixin(NavigateMixin(PolymerElement)) {
hassInfo: Object, hassInfo: Object,
loaded: { loaded: {
type: Boolean, type: Boolean,
computed: 'computeIsLoaded(supervisorInfo, hostInfo, hassInfo)', computed: "computeIsLoaded(supervisorInfo, hostInfo, hassInfo)",
}, },
}; };
} }
@@ -61,7 +61,7 @@ class HassioMain extends EventsMixin(NavigateMixin(PolymerElement)) {
ready() { ready() {
super.ready(); super.ready();
applyThemesOnElement(this, this.hass.themes, this.hass.selectedTheme, true); applyThemesOnElement(this, this.hass.themes, this.hass.selectedTheme, true);
this.addEventListener('hass-api-called', ev => this.apiCalled(ev)); this.addEventListener("hass-api-called", (ev) => this.apiCalled(ev));
} }
connectedCallback() { connectedCallback() {
@@ -74,7 +74,7 @@ class HassioMain extends EventsMixin(NavigateMixin(PolymerElement)) {
let tries = 1; let tries = 1;
const tryUpdate = () => { const tryUpdate = () => {
this.$.data.refresh().catch(function () { this.$.data.refresh().catch(function() {
tries += 1; tries += 1;
setTimeout(tryUpdate, Math.min(tries, 5) * 1000); setTimeout(tryUpdate, Math.min(tries, 5) * 1000);
}); });
@@ -85,21 +85,19 @@ class HassioMain extends EventsMixin(NavigateMixin(PolymerElement)) {
} }
computeIsLoaded(supervisorInfo, hostInfo, hassInfo) { computeIsLoaded(supervisorInfo, hostInfo, hassInfo) {
return (supervisorInfo !== null return supervisorInfo !== null && hostInfo !== null && hassInfo !== null;
&& hostInfo !== null
&& hassInfo !== null);
} }
routeChanged(route) { routeChanged(route) {
if (route.path === '' && route.prefix === '/hassio') { if (route.path === "" && route.prefix === "/hassio") {
this.navigate('/hassio/dashboard', true); this.navigate("/hassio/dashboard", true);
} }
this.fire('iron-resize'); this.fire("iron-resize");
} }
equalsAddon(page) { equalsAddon(page) {
return page && page === 'addon'; return page && page === "addon";
} }
} }
customElements.define('hassio-main', HassioMain); customElements.define("hassio-main", HassioMain);

View File

@@ -1,12 +1,12 @@
import '@polymer/app-layout/app-toolbar/app-toolbar.js'; import "@polymer/app-layout/app-toolbar/app-toolbar.js";
import '@polymer/paper-dialog-scrollable/paper-dialog-scrollable.js'; import "@polymer/paper-dialog-scrollable/paper-dialog-scrollable.js";
import '@polymer/paper-dialog/paper-dialog.js'; import "@polymer/paper-dialog/paper-dialog.js";
import '@polymer/paper-icon-button/paper-icon-button.js'; import "@polymer/paper-icon-button/paper-icon-button.js";
import { html } from '@polymer/polymer/lib/utils/html-tag.js'; import { html } from "@polymer/polymer/lib/utils/html-tag.js";
import { PolymerElement } from '@polymer/polymer/polymer-element.js'; import { PolymerElement } from "@polymer/polymer/polymer-element.js";
import '../../src/components/ha-markdown.js'; import "../../src/components/ha-markdown.js";
import '../../src/resources/ha-style.js'; import "../../src/resources/ha-style.js";
class HassioMarkdownDialog extends PolymerElement { class HassioMarkdownDialog extends PolymerElement {
static get template() { static get template() {
@@ -73,4 +73,4 @@ class HassioMarkdownDialog extends PolymerElement {
this.$.dialog.open(); this.$.dialog.open();
} }
} }
customElements.define('hassio-markdown-dialog', HassioMarkdownDialog); customElements.define("hassio-markdown-dialog", HassioMarkdownDialog);

View File

@@ -1,24 +1,24 @@
import '@polymer/app-layout/app-header-layout/app-header-layout.js'; import "@polymer/app-layout/app-header-layout/app-header-layout.js";
import '@polymer/app-layout/app-header/app-header.js'; import "@polymer/app-layout/app-header/app-header.js";
import '@polymer/app-layout/app-toolbar/app-toolbar.js'; import "@polymer/app-layout/app-toolbar/app-toolbar.js";
import '@polymer/paper-icon-button/paper-icon-button.js'; import "@polymer/paper-icon-button/paper-icon-button.js";
import '@polymer/paper-tabs/paper-tab.js'; import "@polymer/paper-tabs/paper-tab.js";
import '@polymer/paper-tabs/paper-tabs.js'; import "@polymer/paper-tabs/paper-tabs.js";
import { html } from '@polymer/polymer/lib/utils/html-tag.js'; import { html } from "@polymer/polymer/lib/utils/html-tag.js";
import { PolymerElement } from '@polymer/polymer/polymer-element.js'; import { PolymerElement } from "@polymer/polymer/polymer-element.js";
import '../../src/components/ha-menu-button.js'; import "../../src/components/ha-menu-button.js";
import '../../src/resources/ha-style.js'; import "../../src/resources/ha-style.js";
import './addon-store/hassio-addon-store.js'; import "./addon-store/hassio-addon-store.js";
import './dashboard/hassio-dashboard.js'; import "./dashboard/hassio-dashboard.js";
import './hassio-markdown-dialog.js'; import "./hassio-markdown-dialog.js";
import './snapshots/hassio-snapshot.js'; import "./snapshots/hassio-snapshot.js";
import './snapshots/hassio-snapshots.js'; import "./snapshots/hassio-snapshots.js";
import './system/hassio-system.js'; import "./system/hassio-system.js";
import scrollToTarget from '../../src/common/dom/scroll-to-target.js'; import scrollToTarget from "../../src/common/dom/scroll-to-target.js";
import NavigateMixin from '../../src/mixins/navigate-mixin.js'; import NavigateMixin from "../../src/mixins/navigate-mixin.js";
class HassioPagesWithTabs extends NavigateMixin(PolymerElement) { class HassioPagesWithTabs extends NavigateMixin(PolymerElement) {
static get template() { static get template() {
@@ -87,18 +87,20 @@ class HassioPagesWithTabs extends NavigateMixin(PolymerElement) {
markdownTitle: String, markdownTitle: String,
markdownContent: { markdownContent: {
type: String, type: String,
value: '', value: "",
}, },
}; };
} }
ready() { ready() {
super.ready(); super.ready();
this.addEventListener('hassio-markdown-dialog', ev => this.openMarkdown(ev)); this.addEventListener("hassio-markdown-dialog", (ev) =>
this.openMarkdown(ev)
);
} }
handlePageSelected(ev) { handlePageSelected(ev) {
const newPage = ev.detail.item.getAttribute('page-name'); const newPage = ev.detail.item.getAttribute("page-name");
if (newPage !== this.page) { if (newPage !== this.page) {
this.navigate(`/hassio/${newPage}`); this.navigate(`/hassio/${newPage}`);
} }
@@ -110,14 +112,14 @@ class HassioPagesWithTabs extends NavigateMixin(PolymerElement) {
} }
showRefreshButton(page) { showRefreshButton(page) {
return page === 'store' || page === 'snapshots'; return page === "store" || page === "snapshots";
} }
refreshClicked() { refreshClicked() {
if (this.page === 'snapshots') { if (this.page === "snapshots") {
this.shadowRoot.querySelector('hassio-snapshots').refreshData(); this.shadowRoot.querySelector("hassio-snapshots").refreshData();
} else { } else {
this.shadowRoot.querySelector('hassio-addon-store').refreshData(); this.shadowRoot.querySelector("hassio-addon-store").refreshData();
} }
} }
@@ -126,8 +128,8 @@ class HassioPagesWithTabs extends NavigateMixin(PolymerElement) {
markdownTitle: ev.detail.title, markdownTitle: ev.detail.title,
markdownContent: ev.detail.content, markdownContent: ev.detail.content,
}); });
this.shadowRoot.querySelector('hassio-markdown-dialog').openDialog(); this.shadowRoot.querySelector("hassio-markdown-dialog").openDialog();
} }
} }
customElements.define('hassio-pages-with-tabs', HassioPagesWithTabs); customElements.define("hassio-pages-with-tabs", HassioPagesWithTabs);

View File

@@ -1,7 +1,7 @@
import '../../../src/components/ha-iconset-svg.js'; import "../../../src/components/ha-iconset-svg.js";
import iconSetContent from '../../hassio-icons.html'; import iconSetContent from "../../hassio-icons.html";
const documentContainer = document.createElement('template'); const documentContainer = document.createElement("template");
documentContainer.setAttribute('style', 'display: none;'); documentContainer.setAttribute("style", "display: none;");
documentContainer.innerHTML = iconSetContent; documentContainer.innerHTML = iconSetContent;
document.head.appendChild(documentContainer.content); document.head.appendChild(documentContainer.content);

View File

@@ -1,5 +1,5 @@
const documentContainer = document.createElement('template'); const documentContainer = document.createElement("template");
documentContainer.setAttribute('style', 'display: none;'); documentContainer.setAttribute("style", "display: none;");
documentContainer.innerHTML = `<dom-module id="hassio-style"> documentContainer.innerHTML = `<dom-module id="hassio-style">
<template> <template>

View File

@@ -1,14 +1,14 @@
import '@polymer/app-layout/app-toolbar/app-toolbar.js'; import "@polymer/app-layout/app-toolbar/app-toolbar.js";
import '@polymer/paper-button/paper-button.js'; import "@polymer/paper-button/paper-button.js";
import '@polymer/paper-checkbox/paper-checkbox.js'; import "@polymer/paper-checkbox/paper-checkbox.js";
import '@polymer/paper-dialog-scrollable/paper-dialog-scrollable.js'; import "@polymer/paper-dialog-scrollable/paper-dialog-scrollable.js";
import '@polymer/paper-dialog/paper-dialog.js'; import "@polymer/paper-dialog/paper-dialog.js";
import '@polymer/paper-icon-button/paper-icon-button.js'; import "@polymer/paper-icon-button/paper-icon-button.js";
import '@polymer/paper-input/paper-input.js'; import "@polymer/paper-input/paper-input.js";
import { html } from '@polymer/polymer/lib/utils/html-tag.js'; import { html } from "@polymer/polymer/lib/utils/html-tag.js";
import { PolymerElement } from '@polymer/polymer/polymer-element.js'; import { PolymerElement } from "@polymer/polymer/polymer-element.js";
import '../../../src/resources/ha-style.js'; import "../../../src/resources/ha-style.js";
class HassioSnapshot extends PolymerElement { class HassioSnapshot extends PolymerElement {
static get template() { static get template() {
@@ -114,7 +114,7 @@ class HassioSnapshot extends PolymerElement {
snapshotSlug: { snapshotSlug: {
type: String, type: String,
notify: true, notify: true,
observer: '_snapshotSlugChanged', observer: "_snapshotSlugChanged",
}, },
snapshotDeleted: { snapshotDeleted: {
type: Boolean, type: Boolean,
@@ -131,85 +131,124 @@ class HassioSnapshot extends PolymerElement {
} }
_snapshotSlugChanged(snapshotSlug) { _snapshotSlugChanged(snapshotSlug) {
if (!snapshotSlug || snapshotSlug === 'update') return; if (!snapshotSlug || snapshotSlug === "update") return;
this.hass.callApi('get', `hassio/snapshots/${snapshotSlug}/info`) this.hass.callApi("get", `hassio/snapshots/${snapshotSlug}/info`).then(
.then((info) => { (info) => {
info.data.folders = this._computeFolders(info.data.folders); info.data.folders = this._computeFolders(info.data.folders);
info.data.addons = this._computeAddons(info.data.addons); info.data.addons = this._computeAddons(info.data.addons);
this.snapshot = info.data; this.snapshot = info.data;
this.$.dialog.open(); this.$.dialog.open();
}, () => { },
() => {
this.snapshot = null; this.snapshot = null;
}); }
);
} }
_computeFolders(folders) { _computeFolders(folders) {
const list = []; const list = [];
if (folders.includes('homeassistant')) list.push({ slug: 'homeassistant', name: 'Home Assistant configuration', checked: true }); if (folders.includes("homeassistant"))
if (folders.includes('ssl')) list.push({ slug: 'ssl', name: 'SSL', checked: true }); list.push({
if (folders.includes('share')) list.push({ slug: 'share', name: 'Share', checked: true }); slug: "homeassistant",
if (folders.includes('addons/local')) list.push({ slug: 'addons/local', name: 'Local add-ons', checked: true }); name: "Home Assistant configuration",
checked: true,
});
if (folders.includes("ssl"))
list.push({ slug: "ssl", name: "SSL", checked: true });
if (folders.includes("share"))
list.push({ slug: "share", name: "Share", checked: true });
if (folders.includes("addons/local"))
list.push({ slug: "addons/local", name: "Local add-ons", checked: true });
return list; return list;
} }
_computeAddons(addons) { _computeAddons(addons) {
return addons.map(addon => ( return addons.map((addon) => ({
{ slug: addon.slug, name: addon.name, version: addon.version, checked: true })); slug: addon.slug,
name: addon.name,
version: addon.version,
checked: true,
}));
} }
_isFullSnapshot(type) { _isFullSnapshot(type) {
return type === 'full'; return type === "full";
} }
_partialRestoreClicked() { _partialRestoreClicked() {
if (!confirm('Are you sure you want to restore this snapshot?')) { if (!confirm("Are you sure you want to restore this snapshot?")) {
return; return;
} }
const addons = this.snapshot.addons.filter(addon => addon.checked).map(addon => addon.slug); const addons = this.snapshot.addons
const folders = this.snapshot.folders.filter( .filter((addon) => addon.checked)
folder => folder.checked .map((addon) => addon.slug);
).map(folder => folder.slug); const folders = this.snapshot.folders
.filter((folder) => folder.checked)
.map((folder) => folder.slug);
const data = { const data = {
homeassistant: this.restoreHass, homeassistant: this.restoreHass,
addons: addons, addons: addons,
folders: folders folders: folders,
}; };
if (this.snapshot.protected) data.password = this.snapshotPassword; if (this.snapshot.protected) data.password = this.snapshotPassword;
this.hass.callApi('post', `hassio/snapshots/${this.snapshotSlug}/restore/partial`, data).then(() => { this.hass
alert('Snapshot restored!'); .callApi(
"post",
`hassio/snapshots/${this.snapshotSlug}/restore/partial`,
data
)
.then(
() => {
alert("Snapshot restored!");
this.$.dialog.close(); this.$.dialog.close();
}, (error) => { },
(error) => {
this.error = error.body.message; this.error = error.body.message;
}); }
);
} }
_fullRestoreClicked() { _fullRestoreClicked() {
if (!confirm('Are you sure you want to restore this snapshot?')) { if (!confirm("Are you sure you want to restore this snapshot?")) {
return; return;
} }
const data = this.snapshot.protected ? { password: this.snapshotPassword } : null; const data = this.snapshot.protected
this.hass.callApi('post', `hassio/snapshots/${this.snapshotSlug}/restore/full`, data) ? { password: this.snapshotPassword }
.then(() => { : null;
alert('Snapshot restored!'); this.hass
.callApi(
"post",
`hassio/snapshots/${this.snapshotSlug}/restore/full`,
data
)
.then(
() => {
alert("Snapshot restored!");
this.$.dialog.close(); this.$.dialog.close();
}, (error) => { },
(error) => {
this.error = error.body.message; this.error = error.body.message;
}); }
);
} }
_deleteClicked() { _deleteClicked() {
if (!confirm('Are you sure you want to delete this snapshot?')) { if (!confirm("Are you sure you want to delete this snapshot?")) {
return; return;
} }
this.hass.callApi('post', `hassio/snapshots/${this.snapshotSlug}/remove`) this.hass
.then(() => { .callApi("post", `hassio/snapshots/${this.snapshotSlug}/remove`)
.then(
() => {
this.$.dialog.close(); this.$.dialog.close();
this.snapshotDeleted = true; this.snapshotDeleted = true;
}, (error) => { },
(error) => {
this.error = error.body.message; this.error = error.body.message;
}); }
);
} }
_computeDownloadUrl(snapshotSlug) { _computeDownloadUrl(snapshotSlug) {
@@ -218,7 +257,7 @@ class HassioSnapshot extends PolymerElement {
} }
_computeDownloadName(snapshot) { _computeDownloadName(snapshot) {
const name = this._computeName(snapshot).replace(/[^a-z0-9]+/gi, '_'); const name = this._computeName(snapshot).replace(/[^a-z0-9]+/gi, "_");
return `Hass_io_${name}.tar`; return `Hass_io_${name}.tar`;
} }
@@ -227,11 +266,11 @@ class HassioSnapshot extends PolymerElement {
} }
_computeType(type) { _computeType(type) {
return type === 'full' ? 'Full snapshot' : 'Partial snapshot'; return type === "full" ? "Full snapshot" : "Partial snapshot";
} }
_computeSize(size) { _computeSize(size) {
return (Math.ceil(size * 10) / 10) + ' MB'; return Math.ceil(size * 10) / 10 + " MB";
} }
_sortAddons(a, b) { _sortAddons(a, b) {
@@ -240,12 +279,12 @@ class HassioSnapshot extends PolymerElement {
_formatDatetime(datetime) { _formatDatetime(datetime) {
return new Date(datetime).toLocaleDateString(navigator.language, { return new Date(datetime).toLocaleDateString(navigator.language, {
weekday: 'long', weekday: "long",
year: 'numeric', year: "numeric",
month: 'short', month: "short",
day: 'numeric', day: "numeric",
hour: 'numeric', hour: "numeric",
minute: '2-digit' minute: "2-digit",
}); });
} }
@@ -253,4 +292,4 @@ class HassioSnapshot extends PolymerElement {
this.snapshotSlug = null; this.snapshotSlug = null;
} }
} }
customElements.define('hassio-snapshot', HassioSnapshot); customElements.define("hassio-snapshot", HassioSnapshot);

View File

@@ -1,15 +1,15 @@
import '@polymer/paper-button/paper-button.js'; import "@polymer/paper-button/paper-button.js";
import '@polymer/paper-card/paper-card.js'; import "@polymer/paper-card/paper-card.js";
import '@polymer/paper-checkbox/paper-checkbox.js'; import "@polymer/paper-checkbox/paper-checkbox.js";
import '@polymer/paper-input/paper-input.js'; import "@polymer/paper-input/paper-input.js";
import '@polymer/paper-radio-button/paper-radio-button.js'; import "@polymer/paper-radio-button/paper-radio-button.js";
import '@polymer/paper-radio-group/paper-radio-group.js'; import "@polymer/paper-radio-group/paper-radio-group.js";
import { html } from '@polymer/polymer/lib/utils/html-tag.js'; import { html } from "@polymer/polymer/lib/utils/html-tag.js";
import { PolymerElement } from '@polymer/polymer/polymer-element.js'; import { PolymerElement } from "@polymer/polymer/polymer-element.js";
import '../components/hassio-card-content.js'; import "../components/hassio-card-content.js";
import '../resources/hassio-style.js'; import "../resources/hassio-style.js";
import EventsMixin from '../../../src/mixins/events-mixin.js'; import EventsMixin from "../../../src/mixins/events-mixin.js";
class HassioSnapshots extends EventsMixin(PolymerElement) { class HassioSnapshots extends EventsMixin(PolymerElement) {
static get template() { static get template() {
@@ -105,16 +105,16 @@ class HassioSnapshots extends EventsMixin(PolymerElement) {
hass: Object, hass: Object,
snapshotName: { snapshotName: {
type: String, type: String,
value: '', value: "",
}, },
snapshotPassword: { snapshotPassword: {
type: String, type: String,
value: '', value: "",
}, },
snapshotHasPassword: Boolean, snapshotHasPassword: Boolean,
snapshotType: { snapshotType: {
type: String, type: String,
value: 'full', value: "full",
}, },
snapshots: { snapshots: {
type: Array, type: Array,
@@ -122,16 +122,20 @@ class HassioSnapshots extends EventsMixin(PolymerElement) {
}, },
installedAddons: { installedAddons: {
type: Array, type: Array,
observer: '_installedAddonsChanged', observer: "_installedAddonsChanged",
}, },
addonList: Array, addonList: Array,
folderList: { folderList: {
type: Array, type: Array,
value: [ value: [
{ slug: 'homeassistant', name: 'Home Assistant configuration', checked: true }, {
{ slug: 'ssl', name: 'SSL', checked: true }, slug: "homeassistant",
{ slug: 'share', name: 'Share', checked: true }, name: "Home Assistant configuration",
{ slug: 'addons/local', name: 'Local add-ons', checked: true }, checked: true,
},
{ slug: "ssl", name: "SSL", checked: true },
{ slug: "share", name: "Share", checked: true },
{ slug: "addons/local", name: "Local add-ons", checked: true },
], ],
}, },
snapshotSlug: { snapshotSlug: {
@@ -141,7 +145,7 @@ class HassioSnapshots extends EventsMixin(PolymerElement) {
snapshotDeleted: { snapshotDeleted: {
type: Boolean, type: Boolean,
notify: true, notify: true,
observer: '_snapshotDeletedChanged', observer: "_snapshotDeletedChanged",
}, },
creatingSnapshot: Boolean, creatingSnapshot: Boolean,
dialogOpened: Boolean, dialogOpened: Boolean,
@@ -151,7 +155,7 @@ class HassioSnapshots extends EventsMixin(PolymerElement) {
ready() { ready() {
super.ready(); super.ready();
this.addEventListener('hass-api-called', ev => this._apiCalled(ev)); this.addEventListener("hass-api-called", (ev) => this._apiCalled(ev));
this._updateSnapshots(); this._updateSnapshots();
} }
@@ -162,57 +166,70 @@ class HassioSnapshots extends EventsMixin(PolymerElement) {
} }
_updateSnapshots() { _updateSnapshots() {
this.hass.callApi('get', 'hassio/snapshots') this.hass.callApi("get", "hassio/snapshots").then(
.then((result) => { (result) => {
this.snapshots = result.data.snapshots; this.snapshots = result.data.snapshots;
}, (error) => { },
(error) => {
this.error = error.message; this.error = error.message;
}); }
);
} }
_createSnapshot() { _createSnapshot() {
this.error = ''; this.error = "";
if (this.snapshotHasPassword && !this.snapshotPassword.length) { if (this.snapshotHasPassword && !this.snapshotPassword.length) {
this.error = 'Please enter a password.'; this.error = "Please enter a password.";
return; return;
} }
this.creatingSnapshot = true; this.creatingSnapshot = true;
let name = this.snapshotName; let name = this.snapshotName;
if (!name.length) { if (!name.length) {
name = new Date().toLocaleDateString(navigator.language, { name = new Date().toLocaleDateString(navigator.language, {
weekday: 'long', weekday: "long",
year: 'numeric', year: "numeric",
month: 'short', month: "short",
day: 'numeric' }); day: "numeric",
});
} }
let data; let data;
let path; let path;
if (this.snapshotType === 'full') { if (this.snapshotType === "full") {
data = { name: name }; data = { name: name };
path = 'hassio/snapshots/new/full'; path = "hassio/snapshots/new/full";
} else { } else {
const addons = this.addonList.filter(addon => addon.checked).map(addon => addon.slug); const addons = this.addonList
const folders = this.folderList.filter(folder => folder.checked).map(folder => folder.slug); .filter((addon) => addon.checked)
.map((addon) => addon.slug);
const folders = this.folderList
.filter((folder) => folder.checked)
.map((folder) => folder.slug);
data = { name: name, folders: folders, addons: addons }; data = { name: name, folders: folders, addons: addons };
path = 'hassio/snapshots/new/partial'; path = "hassio/snapshots/new/partial";
} }
if (this.snapshotHasPassword) { if (this.snapshotHasPassword) {
data.password = this.snapshotPassword; data.password = this.snapshotPassword;
} }
this.hass.callApi('post', path, data) this.hass.callApi("post", path, data).then(
.then(() => { () => {
this.creatingSnapshot = false; this.creatingSnapshot = false;
this.fire('hass-api-called', { success: true }); this.fire("hass-api-called", { success: true });
}, (error) => { },
(error) => {
this.creatingSnapshot = false; this.creatingSnapshot = false;
this.error = error.message; this.error = error.message;
}); }
);
} }
_installedAddonsChanged(addons) { _installedAddonsChanged(addons) {
this.addonList = addons.map(addon => ({ slug: addon.slug, name: addon.name, checked: true })); this.addonList = addons.map((addon) => ({
slug: addon.slug,
name: addon.name,
checked: true,
}));
} }
_sortAddons(a, b) { _sortAddons(a, b) {
@@ -228,12 +245,15 @@ class HassioSnapshots extends EventsMixin(PolymerElement) {
} }
_computeDetails(snapshot) { _computeDetails(snapshot) {
const type = snapshot.type === 'full' ? 'Full snapshot' : 'Partial snapshot'; const type =
snapshot.type === "full" ? "Full snapshot" : "Partial snapshot";
return snapshot.protected ? `${type}, password protected` : type; return snapshot.protected ? `${type}, password protected` : type;
} }
_computeIcon(type) { _computeIcon(type) {
return type === 'full' ? 'hassio:package-variant-closed' : 'hassio:package-variant'; return type === "full"
? "hassio:package-variant-closed"
: "hassio:package-variant";
} }
_snapshotClicked(ev) { _snapshotClicked(ev) {
@@ -241,7 +261,7 @@ class HassioSnapshots extends EventsMixin(PolymerElement) {
} }
_fullSelected(type) { _fullSelected(type) {
return type === 'full'; return type === "full";
} }
_snapshotDeletedChanged(snapshotDeleted) { _snapshotDeletedChanged(snapshotDeleted) {
@@ -252,11 +272,10 @@ class HassioSnapshots extends EventsMixin(PolymerElement) {
} }
refreshData() { refreshData() {
this.hass.callApi('post', 'hassio/snapshots/reload') this.hass.callApi("post", "hassio/snapshots/reload").then(() => {
.then(() => {
this._updateSnapshots(); this._updateSnapshots();
}); });
} }
} }
customElements.define('hassio-snapshots', HassioSnapshots); customElements.define("hassio-snapshots", HassioSnapshots);

View File

@@ -1,10 +1,10 @@
import '@polymer/paper-button/paper-button.js'; import "@polymer/paper-button/paper-button.js";
import '@polymer/paper-card/paper-card.js'; import "@polymer/paper-card/paper-card.js";
import { html } from '@polymer/polymer/lib/utils/html-tag.js'; import { html } from "@polymer/polymer/lib/utils/html-tag.js";
import { PolymerElement } from '@polymer/polymer/polymer-element.js'; import { PolymerElement } from "@polymer/polymer/polymer-element.js";
import '../../../src/components/buttons/ha-call-api-button.js'; import "../../../src/components/buttons/ha-call-api-button.js";
import EventsMixin from '../../../src/mixins/events-mixin.js'; import EventsMixin from "../../../src/mixins/events-mixin.js";
class HassioHostInfo extends EventsMixin(PolymerElement) { class HassioHostInfo extends EventsMixin(PolymerElement) {
static get template() { static get template() {
@@ -97,16 +97,16 @@ class HassioHostInfo extends EventsMixin(PolymerElement) {
hass: Object, hass: Object,
data: { data: {
type: Object, type: Object,
observer: '_dataChanged' observer: "_dataChanged",
}, },
errors: String, errors: String,
_hassOs: Object _hassOs: Object,
}; };
} }
ready() { ready() {
super.ready(); super.ready();
this.addEventListener('hass-api-called', ev => this.apiCalled(ev)); this.addEventListener("hass-api-called", (ev) => this.apiCalled(ev));
} }
apiCalled(ev) { apiCalled(ev) {
@@ -117,17 +117,16 @@ class HassioHostInfo extends EventsMixin(PolymerElement) {
var response = ev.detail.response; var response = ev.detail.response;
if (typeof response.body === 'object') { if (typeof response.body === "object") {
this.errors = response.body.message || 'Unknown error'; this.errors = response.body.message || "Unknown error";
} else { } else {
this.errors = response.body; this.errors = response.body;
} }
} }
_dataChanged(data) { _dataChanged(data) {
if (data.features && data.features.includes('hassos')) { if (data.features && data.features.includes("hassos")) {
this.hass.callApi('get', 'hassio/hassos/info') this.hass.callApi("get", "hassio/hassos/info").then((resp) => {
.then((resp) => {
this._hassOs = resp.data; this._hassOs = resp.data;
}); });
} else { } else {
@@ -144,28 +143,31 @@ class HassioHostInfo extends EventsMixin(PolymerElement) {
} }
_showHardware() { _showHardware() {
this.hass.callApi('get', 'hassio/hardware/info') this.hass
.callApi("get", "hassio/hardware/info")
.then( .then(
resp => this._objectToMarkdown(resp.data), (resp) => this._objectToMarkdown(resp.data),
() => 'Error getting hardware info' () => "Error getting hardware info"
).then((content) => { )
this.fire('hassio-markdown-dialog', { .then((content) => {
title: 'Hardware', this.fire("hassio-markdown-dialog", {
title: "Hardware",
content: content, content: content,
}); });
}); });
} }
_objectToMarkdown(obj, indent = '') { _objectToMarkdown(obj, indent = "") {
let data = ''; let data = "";
Object.keys(obj).forEach((key) => { Object.keys(obj).forEach((key) => {
if (typeof obj[key] !== 'object') { if (typeof obj[key] !== "object") {
data += `${indent}- ${key}: ${obj[key]}\n`; data += `${indent}- ${key}: ${obj[key]}\n`;
} else { } else {
data += `${indent}- ${key}:\n`; data += `${indent}- ${key}:\n`;
if (Array.isArray(obj[key])) { if (Array.isArray(obj[key])) {
if (obj[key].length) { if (obj[key].length) {
data += `${indent} - ` + obj[key].join(`\n${indent} - `) + '\n'; data +=
`${indent} - ` + obj[key].join(`\n${indent} - `) + "\n";
} }
} else { } else {
data += this._objectToMarkdown(obj[key], ` ${indent}`); data += this._objectToMarkdown(obj[key], ` ${indent}`);
@@ -177,11 +179,11 @@ class HassioHostInfo extends EventsMixin(PolymerElement) {
_changeHostnameClicked() { _changeHostnameClicked() {
const curHostname = this.data.hostname; const curHostname = this.data.hostname;
const hostname = prompt('Please enter a new hostname:', curHostname); const hostname = prompt("Please enter a new hostname:", curHostname);
if (hostname && hostname !== curHostname) { if (hostname && hostname !== curHostname) {
this.hass.callApi('post', 'hassio/host/options', { hostname }); this.hass.callApi("post", "hassio/host/options", { hostname });
} }
} }
} }
customElements.define('hassio-host-info', HassioHostInfo); customElements.define("hassio-host-info", HassioHostInfo);

View File

@@ -1,10 +1,10 @@
import '@polymer/paper-button/paper-button.js'; import "@polymer/paper-button/paper-button.js";
import '@polymer/paper-card/paper-card.js'; import "@polymer/paper-card/paper-card.js";
import { html } from '@polymer/polymer/lib/utils/html-tag.js'; import { html } from "@polymer/polymer/lib/utils/html-tag.js";
import { PolymerElement } from '@polymer/polymer/polymer-element.js'; import { PolymerElement } from "@polymer/polymer/polymer-element.js";
import '../../../src/components/buttons/ha-call-api-button.js'; import "../../../src/components/buttons/ha-call-api-button.js";
import EventsMixin from '../../../src/mixins/events-mixin.js'; import EventsMixin from "../../../src/mixins/events-mixin.js";
class HassioSupervisorInfo extends EventsMixin(PolymerElement) { class HassioSupervisorInfo extends EventsMixin(PolymerElement) {
static get template() { static get template() {
@@ -85,14 +85,14 @@ class HassioSupervisorInfo extends EventsMixin(PolymerElement) {
errors: String, errors: String,
leaveBeta: { leaveBeta: {
type: Object, type: Object,
value: { channel: 'stable' }, value: { channel: "stable" },
}, },
}; };
} }
ready() { ready() {
super.ready(); super.ready();
this.addEventListener('hass-api-called', ev => this.apiCalled(ev)); this.addEventListener("hass-api-called", (ev) => this.apiCalled(ev));
} }
apiCalled(ev) { apiCalled(ev) {
@@ -103,8 +103,8 @@ class HassioSupervisorInfo extends EventsMixin(PolymerElement) {
var response = ev.detail.response; var response = ev.detail.response;
if (typeof response.body === 'object') { if (typeof response.body === "object") {
this.errors = response.body.message || 'Unknown error'; this.errors = response.body.message || "Unknown error";
} else { } else {
this.errors = response.body; this.errors = response.body;
} }
@@ -119,18 +119,20 @@ class HassioSupervisorInfo extends EventsMixin(PolymerElement) {
} }
_joinBeta() { _joinBeta() {
if (!confirm(`WARNING: if (
!confirm(`WARNING:
Beta releases are for testers and early adopters and can contain unstable code changes. Make sure you have backups of your data before you activate this feature. Beta releases are for testers and early adopters and can contain unstable code changes. Make sure you have backups of your data before you activate this feature.
This inludes beta releases for: This inludes beta releases for:
- Home Assistant (Release Candidates) - Home Assistant (Release Candidates)
- Hass.io supervisor - Hass.io supervisor
- Host system`)) { - Host system`)
) {
return; return;
} }
const method = 'post'; const method = "post";
const path = 'hassio/supervisor/options'; const path = "hassio/supervisor/options";
const data = { channel: 'beta' }; const data = { channel: "beta" };
const eventData = { const eventData = {
method: method, method: method,
@@ -138,17 +140,22 @@ This inludes beta releases for:
data: data, data: data,
}; };
this.hass.callApi(method, path, data) this.hass
.then((resp) => { .callApi(method, path, data)
.then(
(resp) => {
eventData.success = true; eventData.success = true;
eventData.response = resp; eventData.response = resp;
}, (resp) => { },
(resp) => {
eventData.success = false; eventData.success = false;
eventData.response = resp; eventData.response = resp;
}).then(() => { }
this.fire('hass-api-called', eventData); )
.then(() => {
this.fire("hass-api-called", eventData);
}); });
} }
} }
customElements.define('hassio-supervisor-info', HassioSupervisorInfo); customElements.define("hassio-supervisor-info", HassioSupervisorInfo);

View File

@@ -1,7 +1,7 @@
import '@polymer/paper-button/paper-button.js'; import "@polymer/paper-button/paper-button.js";
import '@polymer/paper-card/paper-card.js'; import "@polymer/paper-card/paper-card.js";
import { html } from '@polymer/polymer/lib/utils/html-tag.js'; import { html } from "@polymer/polymer/lib/utils/html-tag.js";
import { PolymerElement } from '@polymer/polymer/polymer-element.js'; import { PolymerElement } from "@polymer/polymer/polymer-element.js";
class HassioSupervisorLog extends PolymerElement { class HassioSupervisorLog extends PolymerElement {
static get template() { static get template() {
@@ -38,12 +38,14 @@ class HassioSupervisorLog extends PolymerElement {
} }
loadData() { loadData() {
this.hass.callApi('get', 'hassio/supervisor/logs') this.hass.callApi("get", "hassio/supervisor/logs").then(
.then((info) => { (info) => {
this.log = info; this.log = info;
}, () => { },
this.log = 'Error fetching logs'; () => {
}); this.log = "Error fetching logs";
}
);
} }
refreshTapped() { refreshTapped() {
@@ -51,4 +53,4 @@ class HassioSupervisorLog extends PolymerElement {
} }
} }
customElements.define('hassio-supervisor-log', HassioSupervisorLog); customElements.define("hassio-supervisor-log", HassioSupervisorLog);

View File

@@ -1,10 +1,10 @@
import '@polymer/iron-flex-layout/iron-flex-layout-classes.js'; import "@polymer/iron-flex-layout/iron-flex-layout-classes.js";
import { html } from '@polymer/polymer/lib/utils/html-tag.js'; import { html } from "@polymer/polymer/lib/utils/html-tag.js";
import { PolymerElement } from '@polymer/polymer/polymer-element.js'; import { PolymerElement } from "@polymer/polymer/polymer-element.js";
import './hassio-host-info.js'; import "./hassio-host-info.js";
import './hassio-supervisor-info.js'; import "./hassio-supervisor-info.js";
import './hassio-supervisor-log.js'; import "./hassio-supervisor-log.js";
class HassioSystem extends PolymerElement { class HassioSystem extends PolymerElement {
static get template() { static get template() {
@@ -40,4 +40,4 @@ class HassioSystem extends PolymerElement {
} }
} }
customElements.define('hassio-system', HassioSystem); customElements.define("hassio-system", HassioSystem);

View File

@@ -1,26 +1,25 @@
const UglifyJsPlugin = require('uglifyjs-webpack-plugin'); const UglifyJsPlugin = require("uglifyjs-webpack-plugin");
const CompressionPlugin = require("compression-webpack-plugin"); const CompressionPlugin = require("compression-webpack-plugin");
const config = require('./config.js'); const config = require("./config.js");
const isProdBuild = process.env.NODE_ENV === 'production' const isProdBuild = process.env.NODE_ENV === "production";
const chunkFilename = isProdBuild ? const chunkFilename = isProdBuild ? "chunk.[chunkhash].js" : "[name].chunk.js";
'chunk.[chunkhash].js' : '[name].chunk.js';
module.exports = { module.exports = {
mode: isProdBuild ? 'production' : 'development', mode: isProdBuild ? "production" : "development",
devtool: isProdBuild ? 'source-map' : 'inline-source-map', devtool: isProdBuild ? "source-map" : "inline-source-map",
entry: { entry: {
entrypoint: './src/entrypoint.js', entrypoint: "./src/entrypoint.js",
}, },
module: { module: {
rules: [ rules: [
{ {
test: /\.m?js$/, test: /\.m?js$/,
use: { use: {
loader: 'babel-loader', loader: "babel-loader",
options: { options: {
presets: [ presets: [
[require('babel-preset-env').default, { modules: false }] [require("babel-preset-env").default, { modules: false }],
], ],
plugins: [ plugins: [
// Only support the syntax, Webpack will handle it. // Only support the syntax, Webpack will handle it.
@@ -32,38 +31,34 @@ module.exports = {
{ {
test: /\.(html)$/, test: /\.(html)$/,
use: { use: {
loader: 'html-loader', loader: "html-loader",
options: { options: {
exportAsEs6Default: true, exportAsEs6Default: true,
} },
} },
} },
],
]
}, },
plugins: [ plugins: [
isProdBuild && new UglifyJsPlugin({ isProdBuild &&
new UglifyJsPlugin({
extractComments: true, extractComments: true,
sourceMap: true, sourceMap: true,
uglifyOptions: { uglifyOptions: {
// Disabling because it broke output // Disabling because it broke output
mangle: false, mangle: false,
} },
}), }),
isProdBuild && new CompressionPlugin({ isProdBuild &&
new CompressionPlugin({
cache: true, cache: true,
exclude: [ exclude: [/\.js\.map$/, /\.LICENSE$/, /\.py$/, /\.txt$/],
/\.js\.map$/,
/\.LICENSE$/,
/\.py$/,
/\.txt$/,
]
}), }),
].filter(Boolean), ].filter(Boolean),
output: { output: {
filename: '[name].js', filename: "[name].js",
chunkFilename, chunkFilename,
path: config.buildDir, path: config.buildDir,
publicPath: `${config.publicPath}/`, publicPath: `${config.publicPath}/`,
} },
}; };

View File

@@ -104,7 +104,9 @@
"del": "^3.0.0", "del": "^3.0.0",
"eslint": "^5.6.0", "eslint": "^5.6.0",
"eslint-config-airbnb-base": "^13.1.0", "eslint-config-airbnb-base": "^13.1.0",
"eslint-config-prettier": "^3.1.0",
"eslint-plugin-import": "^2.14.0", "eslint-plugin-import": "^2.14.0",
"eslint-plugin-prettier": "^3.0.0",
"eslint-plugin-react": "^7.11.1", "eslint-plugin-react": "^7.11.1",
"gulp": "^3.9.1", "gulp": "^3.9.1",
"gulp-foreach": "^0.1.0", "gulp-foreach": "^0.1.0",
@@ -117,12 +119,15 @@
"html-loader": "^0.5.5", "html-loader": "^0.5.5",
"html-minifier": "^3.5.20", "html-minifier": "^3.5.20",
"html-webpack-plugin": "^3.2.0", "html-webpack-plugin": "^3.2.0",
"husky": "^1.1.0",
"lint-staged": "^7.3.0",
"merge-stream": "^1.0.1", "merge-stream": "^1.0.1",
"mocha": "^5.2.0", "mocha": "^5.2.0",
"parse5": "^5.1.0", "parse5": "^5.1.0",
"polymer-analyzer": "^3.1.2", "polymer-analyzer": "^3.1.2",
"polymer-bundler": "^4.0.2", "polymer-bundler": "^4.0.2",
"polymer-cli": "^1.8.0", "polymer-cli": "^1.8.0",
"prettier": "^1.14.3",
"raw-loader": "^0.5.1", "raw-loader": "^0.5.1",
"reify": "^0.17.3", "reify": "^0.17.3",
"require-dir": "^1.0.0", "require-dir": "^1.0.0",
@@ -146,5 +151,20 @@
"@vaadin/vaadin-lumo-styles": "1.2.0", "@vaadin/vaadin-lumo-styles": "1.2.0",
"fecha": "https://github.com/balloob/fecha/archive/51d14fd0eb4781e2ecf265d1c3080706259133b5.tar.gz" "fecha": "https://github.com/balloob/fecha/archive/51d14fd0eb4781e2ecf265d1c3080706259133b5.tar.gz"
}, },
"main": "src/home-assistant.js" "main": "src/home-assistant.js",
"husky": {
"hooks": {
"pre-commit": "lint-staged"
}
},
"lint-staged": {
"*.{js,json,css,md}": [
"prettier --write",
"git add"
]
},
"prettier": {
"trailingComma": "es5",
"arrowParens": "always"
}
} }

View File

@@ -1,8 +1,8 @@
import { PolymerElement } from '@polymer/polymer/polymer-element.js'; import { PolymerElement } from "@polymer/polymer/polymer-element.js";
import '@polymer/paper-button/paper-button.js'; import "@polymer/paper-button/paper-button.js";
import { html } from '@polymer/polymer/lib/utils/html-tag.js'; import { html } from "@polymer/polymer/lib/utils/html-tag.js";
import '../components/ha-form.js'; import "../components/ha-form.js";
import LocalizeLiteMixin from '../mixins/localize-lite-mixin.js'; import LocalizeLiteMixin from "../mixins/localize-lite-mixin.js";
class HaAuthFlow extends LocalizeLiteMixin(PolymerElement) { class HaAuthFlow extends LocalizeLiteMixin(PolymerElement) {
static get template() { static get template() {
@@ -61,14 +61,14 @@ class HaAuthFlow extends LocalizeLiteMixin(PolymerElement) {
return { return {
authProvider: { authProvider: {
type: Object, type: Object,
observer: '_providerChanged', observer: "_providerChanged",
}, },
clientId: String, clientId: String,
redirectUri: String, redirectUri: String,
oauth2State: String, oauth2State: String,
_state: { _state: {
type: String, type: String,
value: 'loading' value: "loading",
}, },
_stepData: { _stepData: {
type: Object, type: Object,
@@ -85,7 +85,7 @@ class HaAuthFlow extends LocalizeLiteMixin(PolymerElement) {
ready() { ready() {
super.ready(); super.ready();
this.addEventListener('keypress', (ev) => { this.addEventListener("keypress", (ev) => {
if (ev.keyCode === 13) { if (ev.keyCode === 13) {
this._handleSubmit(); this._handleSubmit();
} }
@@ -93,22 +93,22 @@ class HaAuthFlow extends LocalizeLiteMixin(PolymerElement) {
} }
async _providerChanged(newProvider, oldProvider) { async _providerChanged(newProvider, oldProvider) {
if (oldProvider && this._step && this._step.type === 'form') { if (oldProvider && this._step && this._step.type === "form") {
fetch(`/auth/login_flow/${this._step.flow_id}`, { fetch(`/auth/login_flow/${this._step.flow_id}`, {
method: 'DELETE', method: "DELETE",
credentials: 'same-origin', credentials: "same-origin",
}).catch(() => {}); }).catch(() => {});
} }
try { try {
const response = await fetch('/auth/login_flow', { const response = await fetch("/auth/login_flow", {
method: 'POST', method: "POST",
credentials: 'same-origin', credentials: "same-origin",
body: JSON.stringify({ body: JSON.stringify({
client_id: this.clientId, client_id: this.clientId,
handler: [newProvider.type, newProvider.id], handler: [newProvider.type, newProvider.id],
redirect_uri: this.redirectUri, redirect_uri: this.redirectUri,
}) }),
}); });
const data = await response.json(); const data = await response.json();
@@ -117,16 +117,16 @@ class HaAuthFlow extends LocalizeLiteMixin(PolymerElement) {
this._updateStep(data); this._updateStep(data);
} else { } else {
this.setProperties({ this.setProperties({
_state: 'error', _state: "error",
_errorMsg: data.message, _errorMsg: data.message,
}); });
} }
} catch (err) { } catch (err) {
// eslint-disable-next-line // eslint-disable-next-line
console.error('Error starting auth flow', err); console.error("Error starting auth flow", err);
this.setProperties({ this.setProperties({
_state: 'error', _state: "error",
_errorMsg: this.localize('ui.panel.page-authorize.form.unknown_error'), _errorMsg: this.localize("ui.panel.page-authorize.form.unknown_error"),
}); });
} }
} }
@@ -134,11 +134,14 @@ class HaAuthFlow extends LocalizeLiteMixin(PolymerElement) {
_updateStep(step) { _updateStep(step) {
const props = { const props = {
_step: step, _step: step,
_state: 'step', _state: "step",
}; };
if (this._step if (
&& (step.flow_id !== this._step.flow_id || step.step_id !== this._step.step_id)) { this._step &&
(step.flow_id !== this._step.flow_id ||
step.step_id !== this._step.step_id)
) {
props._stepData = {}; props._stepData = {};
} }
@@ -150,15 +153,23 @@ class HaAuthFlow extends LocalizeLiteMixin(PolymerElement) {
} }
_computeSubmitCaption(stepType) { _computeSubmitCaption(stepType) {
return stepType === 'form' ? 'Next' : 'Start over'; return stepType === "form" ? "Next" : "Start over";
} }
_computeStepAbortedReason(localize, step) { _computeStepAbortedReason(localize, step) {
return localize(`ui.panel.page-authorize.form.providers.${step.handler[0]}.abort.${step.reason}`); return localize(
`ui.panel.page-authorize.form.providers.${step.handler[0]}.abort.${
step.reason
}`
);
} }
_computeStepDescription(localize, step) { _computeStepDescription(localize, step) {
const args = [`ui.panel.page-authorize.form.providers.${step.handler[0]}.step.${step.step_id}.description`]; const args = [
`ui.panel.page-authorize.form.providers.${step.handler[0]}.step.${
step.step_id
}.description`,
];
const placeholders = step.description_placeholders || {}; const placeholders = step.description_placeholders || {};
Object.keys(placeholders).forEach((key) => { Object.keys(placeholders).forEach((key) => {
args.push(key); args.push(key);
@@ -169,22 +180,32 @@ class HaAuthFlow extends LocalizeLiteMixin(PolymerElement) {
_computeLabelCallback(localize, step) { _computeLabelCallback(localize, step) {
// Returns a callback for ha-form to calculate labels per schema object // Returns a callback for ha-form to calculate labels per schema object
return schema => localize(`ui.panel.page-authorize.form.providers.${step.handler[0]}.step.${step.step_id}.data.${schema.name}`); return (schema) =>
localize(
`ui.panel.page-authorize.form.providers.${step.handler[0]}.step.${
step.step_id
}.data.${schema.name}`
);
} }
_computeErrorCallback(localize, step) { _computeErrorCallback(localize, step) {
// Returns a callback for ha-form to calculate error messages // Returns a callback for ha-form to calculate error messages
return error => localize(`ui.panel.page-authorize.form.providers.${step.handler[0]}.error.${error}`); return (error) =>
localize(
`ui.panel.page-authorize.form.providers.${
step.handler[0]
}.error.${error}`
);
} }
async _handleSubmit() { async _handleSubmit() {
if (this._step.type !== 'form') { if (this._step.type !== "form") {
this._providerChanged(this.authProvider, null); this._providerChanged(this.authProvider, null);
return; return;
} }
this._state = 'loading'; this._state = "loading";
// To avoid a jumping UI. // To avoid a jumping UI.
this.style.setProperty('min-height', `${this.offsetHeight}px`); this.style.setProperty("min-height", `${this.offsetHeight}px`);
const postData = Object.assign({}, this._stepData, { const postData = Object.assign({}, this._stepData, {
client_id: this.clientId, client_id: this.clientId,
@@ -192,20 +213,20 @@ class HaAuthFlow extends LocalizeLiteMixin(PolymerElement) {
try { try {
const response = await fetch(`/auth/login_flow/${this._step.flow_id}`, { const response = await fetch(`/auth/login_flow/${this._step.flow_id}`, {
method: 'POST', method: "POST",
credentials: 'same-origin', credentials: "same-origin",
body: JSON.stringify(postData) body: JSON.stringify(postData),
}); });
const newStep = await response.json(); const newStep = await response.json();
if (newStep.type === 'create_entry') { if (newStep.type === "create_entry") {
// OAuth 2: 3.1.2 we need to retain query component of a redirect URI // OAuth 2: 3.1.2 we need to retain query component of a redirect URI
let url = this.redirectUri; let url = this.redirectUri;
if (!url.includes('?')) { if (!url.includes("?")) {
url += '?'; url += "?";
} else if (!url.endsWith('&')) { } else if (!url.endsWith("&")) {
url += '&'; url += "&";
} }
url += `code=${encodeURIComponent(newStep.result)}`; url += `code=${encodeURIComponent(newStep.result)}`;
@@ -220,11 +241,11 @@ class HaAuthFlow extends LocalizeLiteMixin(PolymerElement) {
this._updateStep(newStep); this._updateStep(newStep);
} catch (err) { } catch (err) {
// eslint-disable-next-line // eslint-disable-next-line
console.error('Error submitting step', err); console.error("Error submitting step", err);
this._state = 'error-loading'; this._state = "error-loading";
} finally { } finally {
this.style.setProperty('min-height', ''); this.style.setProperty("min-height", "");
} }
} }
} }
customElements.define('ha-auth-flow', HaAuthFlow); customElements.define("ha-auth-flow", HaAuthFlow);

View File

@@ -1,13 +1,13 @@
import '@polymer/polymer/lib/elements/dom-if.js'; import "@polymer/polymer/lib/elements/dom-if.js";
import '@polymer/polymer/lib/elements/dom-repeat.js'; import "@polymer/polymer/lib/elements/dom-repeat.js";
import { html } from '@polymer/polymer/lib/utils/html-tag.js'; import { html } from "@polymer/polymer/lib/utils/html-tag.js";
import { PolymerElement } from '@polymer/polymer/polymer-element.js'; import { PolymerElement } from "@polymer/polymer/polymer-element.js";
import '../components/ha-markdown.js'; import "../components/ha-markdown.js";
import LocalizeLiteMixin from '../mixins/localize-lite-mixin.js'; import LocalizeLiteMixin from "../mixins/localize-lite-mixin.js";
import './ha-auth-flow.js'; import "./ha-auth-flow.js";
class HaAuthorize extends LocalizeLiteMixin(PolymerElement) { class HaAuthorize extends LocalizeLiteMixin(PolymerElement) {
static get template() { static get template() {
@@ -66,17 +66,17 @@ class HaAuthorize extends LocalizeLiteMixin(PolymerElement) {
oauth2State: String, oauth2State: String,
translationFragment: { translationFragment: {
type: String, type: String,
value: 'page-authorize', value: "page-authorize",
} },
}; };
} }
async ready() { async ready() {
super.ready(); super.ready();
const query = {}; const query = {};
const values = location.search.substr(1).split('&'); const values = location.search.substr(1).split("&");
for (let i = 0; i < values.length; i++) { for (let i = 0; i < values.length; i++) {
const value = values[i].split('='); const value = values[i].split("=");
if (value.length > 1) { if (value.length > 1) {
query[decodeURIComponent(value[0])] = decodeURIComponent(value[1]); query[decodeURIComponent(value[0])] = decodeURIComponent(value[1]);
} }
@@ -87,7 +87,7 @@ class HaAuthorize extends LocalizeLiteMixin(PolymerElement) {
if (query.state) props.oauth2State = query.state; if (query.state) props.oauth2State = query.state;
this.setProperties(props); this.setProperties(props);
import(/* webpackChunkName: "pick-auth-provider" */ '../auth/ha-pick-auth-provider.js'); import(/* webpackChunkName: "pick-auth-provider" */ "../auth/ha-pick-auth-provider.js");
// Fetch auth providers // Fetch auth providers
try { try {
@@ -95,13 +95,16 @@ class HaAuthorize extends LocalizeLiteMixin(PolymerElement) {
const authProviders = await response.json(); const authProviders = await response.json();
// Forward to main screen which will redirect to right onboarding page. // Forward to main screen which will redirect to right onboarding page.
if (response.status === 400 && authProviders.code === 'onboarding_required') { if (
location.href = '/'; response.status === 400 &&
authProviders.code === "onboarding_required"
) {
location.href = "/";
return; return;
} }
if (authProviders.length === 0) { if (authProviders.length === 0) {
alert('No auth providers returned. Unable to finish login.'); alert("No auth providers returned. Unable to finish login.");
return; return;
} }
@@ -111,8 +114,8 @@ class HaAuthorize extends LocalizeLiteMixin(PolymerElement) {
}); });
} catch (err) { } catch (err) {
// eslint-disable-next-line // eslint-disable-next-line
console.error('Error loading auth providers', err); console.error("Error loading auth providers", err);
this._state = 'error-loading'; this._state = "error-loading";
} }
} }
@@ -125,15 +128,25 @@ class HaAuthorize extends LocalizeLiteMixin(PolymerElement) {
} }
_computeInactiveProvders(curProvider, providers) { _computeInactiveProvders(curProvider, providers) {
return providers.filter(prv => prv.type !== curProvider.type || prv.id !== curProvider.id); return providers.filter(
(prv) => prv.type !== curProvider.type || prv.id !== curProvider.id
);
} }
_computeIntro(localize, clientId, authProvider) { _computeIntro(localize, clientId, authProvider) {
return ( return (
localize('ui.panel.page-authorize.authorizing_client', 'clientId', clientId) localize(
+ '\n\n' "ui.panel.page-authorize.authorizing_client",
+ localize('ui.panel.page-authorize.logging_in_with', 'authProviderName', authProvider.name) "clientId",
clientId
) +
"\n\n" +
localize(
"ui.panel.page-authorize.logging_in_with",
"authProviderName",
authProvider.name
)
); );
} }
} }
customElements.define('ha-authorize', HaAuthorize); customElements.define("ha-authorize", HaAuthorize);

View File

@@ -1,15 +1,17 @@
import '@polymer/paper-item/paper-item.js'; import "@polymer/paper-item/paper-item.js";
import '@polymer/paper-item/paper-item-body.js'; import "@polymer/paper-item/paper-item-body.js";
import { html } from '@polymer/polymer/lib/utils/html-tag.js'; import { html } from "@polymer/polymer/lib/utils/html-tag.js";
import { PolymerElement } from '@polymer/polymer/polymer-element.js'; import { PolymerElement } from "@polymer/polymer/polymer-element.js";
import EventsMixin from '../mixins/events-mixin.js'; import EventsMixin from "../mixins/events-mixin.js";
import LocalizeLiteMixin from '../mixins/localize-lite-mixin.js'; import LocalizeLiteMixin from "../mixins/localize-lite-mixin.js";
/* /*
* @appliesMixin EventsMixin * @appliesMixin EventsMixin
*/ */
class HaPickAuthProvider extends EventsMixin(LocalizeLiteMixin(PolymerElement)) { class HaPickAuthProvider extends EventsMixin(
LocalizeLiteMixin(PolymerElement)
) {
static get template() { static get template() {
return html` return html`
<style> <style>
@@ -34,18 +36,18 @@ class HaPickAuthProvider extends EventsMixin(LocalizeLiteMixin(PolymerElement))
return { return {
_state: { _state: {
type: String, type: String,
value: 'loading' value: "loading",
}, },
authProviders: Array, authProviders: Array,
}; };
} }
_handlePick(ev) { _handlePick(ev) {
this.fire('pick', ev.model.item); this.fire("pick", ev.model.item);
} }
_equal(a, b) { _equal(a, b) {
return a === b; return a === b;
} }
} }
customElements.define('ha-pick-auth-provider', HaPickAuthProvider); customElements.define("ha-pick-auth-provider", HaPickAuthProvider);

View File

@@ -1,7 +1,7 @@
import { html } from '@polymer/polymer/lib/utils/html-tag.js'; import { html } from "@polymer/polymer/lib/utils/html-tag.js";
import { PolymerElement } from '@polymer/polymer/polymer-element.js'; import { PolymerElement } from "@polymer/polymer/polymer-element.js";
import '../components/entity/ha-state-label-badge.js'; import "../components/entity/ha-state-label-badge.js";
class HaBadgesCard extends PolymerElement { class HaBadgesCard extends PolymerElement {
static get template() { static get template() {
@@ -25,4 +25,4 @@ class HaBadgesCard extends PolymerElement {
}; };
} }
} }
customElements.define('ha-badges-card', HaBadgesCard); customElements.define("ha-badges-card", HaBadgesCard);

View File

@@ -1,11 +1,10 @@
import '@polymer/paper-styles/element-styles/paper-material-styles.js'; import "@polymer/paper-styles/element-styles/paper-material-styles.js";
import { html } from '@polymer/polymer/lib/utils/html-tag.js'; import { html } from "@polymer/polymer/lib/utils/html-tag.js";
import { PolymerElement } from '@polymer/polymer/polymer-element.js'; import { PolymerElement } from "@polymer/polymer/polymer-element.js";
import computeStateName from "../common/entity/compute_state_name.js";
import computeStateName from '../common/entity/compute_state_name.js'; import EventsMixin from "../mixins/events-mixin.js";
import EventsMixin from '../mixins/events-mixin.js'; import LocalizeMixin from "../mixins/localize-mixin.js";
import LocalizeMixin from '../mixins/localize-mixin.js';
const UPDATE_INTERVAL = 10000; // ms const UPDATE_INTERVAL = 10000; // ms
/* /*
@@ -67,11 +66,11 @@ class HaCameraCard extends LocalizeMixin(EventsMixin(PolymerElement)) {
hass: Object, hass: Object,
stateObj: { stateObj: {
type: Object, type: Object,
observer: 'updateCameraFeedSrc', observer: "updateCameraFeedSrc",
}, },
cameraFeedSrc: { cameraFeedSrc: {
type: String, type: String,
value: '', value: "",
}, },
imageLoaded: { imageLoaded: {
type: Boolean, type: Boolean,
@@ -82,7 +81,7 @@ class HaCameraCard extends LocalizeMixin(EventsMixin(PolymerElement)) {
ready() { ready() {
super.ready(); super.ready();
this.addEventListener('click', () => this.cardTapped()); this.addEventListener("click", () => this.cardTapped());
} }
connectedCallback() { connectedCallback() {
@@ -96,13 +95,13 @@ class HaCameraCard extends LocalizeMixin(EventsMixin(PolymerElement)) {
} }
cardTapped() { cardTapped() {
this.fire('hass-more-info', { entityId: this.stateObj.entity_id }); this.fire("hass-more-info", { entityId: this.stateObj.entity_id });
} }
async updateCameraFeedSrc() { async updateCameraFeedSrc() {
try { try {
const { content_type: contentType, content } = await this.hass.callWS({ const { content_type: contentType, content } = await this.hass.callWS({
type: 'camera_thumbnail', type: "camera_thumbnail",
entity_id: this.stateObj.entity_id, entity_id: this.stateObj.entity_id,
}); });
this.setProperties({ this.setProperties({
@@ -118,4 +117,4 @@ class HaCameraCard extends LocalizeMixin(EventsMixin(PolymerElement)) {
return computeStateName(stateObj); return computeStateName(stateObj);
} }
} }
customElements.define('ha-camera-card', HaCameraCard); customElements.define("ha-camera-card", HaCameraCard);

View File

@@ -1,28 +1,29 @@
import { PolymerElement } from '@polymer/polymer/polymer-element.js'; import { PolymerElement } from "@polymer/polymer/polymer-element.js";
import './ha-camera-card.js'; import "./ha-camera-card.js";
import './ha-entities-card.js'; import "./ha-entities-card.js";
import './ha-history_graph-card.js'; import "./ha-history_graph-card.js";
import './ha-media_player-card.js'; import "./ha-media_player-card.js";
import './ha-persistent_notification-card.js'; import "./ha-persistent_notification-card.js";
import './ha-plant-card.js'; import "./ha-plant-card.js";
import './ha-weather-card.js'; import "./ha-weather-card.js";
import dynamicContentUpdater from '../common/dom/dynamic_content_updater.js'; import dynamicContentUpdater from "../common/dom/dynamic_content_updater.js";
class HaCardChooser extends PolymerElement { class HaCardChooser extends PolymerElement {
static get properties() { static get properties() {
return { return {
cardData: { cardData: {
type: Object, type: Object,
observer: 'cardDataChanged', observer: "cardDataChanged",
}, },
}; };
} }
_updateCard(newData) { _updateCard(newData) {
dynamicContentUpdater( dynamicContentUpdater(
this, 'HA-' + newData.cardType.toUpperCase() + '-CARD', this,
"HA-" + newData.cardType.toUpperCase() + "-CARD",
newData newData
); );
} }
@@ -32,7 +33,7 @@ class HaCardChooser extends PolymerElement {
this.observer = new IntersectionObserver((entries) => { this.observer = new IntersectionObserver((entries) => {
if (!entries.length) return; if (!entries.length) return;
if (entries[0].isIntersecting) { if (entries[0].isIntersecting) {
this.style.height = ''; this.style.height = "";
if (this._detachedChild) { if (this._detachedChild) {
this.appendChild(this._detachedChild); this.appendChild(this._detachedChild);
this._detachedChild = null; this._detachedChild = null;
@@ -58,13 +59,14 @@ class HaCardChooser extends PolymerElement {
if (!newData) return; if (!newData) return;
// ha-entities-card is exempt from observer as it doesn't load heavy resources. // ha-entities-card is exempt from observer as it doesn't load heavy resources.
// and usually doesn't load external resources (except for entity_picture). // and usually doesn't load external resources (except for entity_picture).
const eligibleToObserver = (window.IntersectionObserver && newData.cardType !== 'entities'); const eligibleToObserver =
window.IntersectionObserver && newData.cardType !== "entities";
if (!eligibleToObserver) { if (!eligibleToObserver) {
if (this.observer) { if (this.observer) {
this.observer.unobserve(this); this.observer.unobserve(this);
this.observer = null; this.observer = null;
} }
this.style.height = ''; this.style.height = "";
this._updateCard(newData); this._updateCard(newData);
return; return;
} }
@@ -76,4 +78,4 @@ class HaCardChooser extends PolymerElement {
} }
} }
} }
customElements.define('ha-card-chooser', HaCardChooser); customElements.define("ha-card-chooser", HaCardChooser);

View File

@@ -1,18 +1,17 @@
import '@polymer/iron-flex-layout/iron-flex-layout-classes.js'; import "@polymer/iron-flex-layout/iron-flex-layout-classes.js";
import { html } from '@polymer/polymer/lib/utils/html-tag.js'; import { html } from "@polymer/polymer/lib/utils/html-tag.js";
import { PolymerElement } from '@polymer/polymer/polymer-element.js'; import { PolymerElement } from "@polymer/polymer/polymer-element.js";
import '../components/entity/ha-entity-toggle.js'; import "../components/entity/ha-entity-toggle.js";
import '../components/ha-card.js'; import "../components/ha-card.js";
import '../state-summary/state-card-content.js'; import "../state-summary/state-card-content.js";
import computeStateDomain from "../common/entity/compute_state_domain.js";
import computeStateDomain from '../common/entity/compute_state_domain.js'; import computeStateName from "../common/entity/compute_state_name.js";
import computeStateName from '../common/entity/compute_state_name.js'; import stateMoreInfoType from "../common/entity/state_more_info_type.js";
import stateMoreInfoType from '../common/entity/state_more_info_type.js'; import canToggleState from "../common/entity/can_toggle_state.js";
import canToggleState from '../common/entity/can_toggle_state.js'; import EventsMixin from "../mixins/events-mixin.js";
import EventsMixin from '../mixins/events-mixin.js'; import LocalizeMixin from "../mixins/localize-mixin.js";
import LocalizeMixin from '../mixins/localize-mixin.js';
class HaEntitiesCard extends LocalizeMixin(EventsMixin(PolymerElement)) { class HaEntitiesCard extends LocalizeMixin(EventsMixin(PolymerElement)) {
static get template() { static get template() {
@@ -74,7 +73,7 @@ class HaEntitiesCard extends LocalizeMixin(EventsMixin(PolymerElement)) {
groupEntity: Object, groupEntity: Object,
title: { title: {
type: String, type: String,
computed: 'computeTitle(states, groupEntity, localize)', computed: "computeTitle(states, groupEntity, localize)",
}, },
}; };
} }
@@ -91,34 +90,40 @@ class HaEntitiesCard extends LocalizeMixin(EventsMixin(PolymerElement)) {
return computeStateName(groupEntity).trim(); return computeStateName(groupEntity).trim();
} }
const domain = computeStateDomain(states[0]); const domain = computeStateDomain(states[0]);
return (localize && localize(`domain.${domain}`)) || domain.replace(/_/g, ' '); return (
(localize && localize(`domain.${domain}`)) || domain.replace(/_/g, " ")
);
} }
computeTitleClass(groupEntity) { computeTitleClass(groupEntity) {
let classes = 'header horizontal layout center '; let classes = "header horizontal layout center ";
if (groupEntity) { if (groupEntity) {
classes += 'more-info'; classes += "more-info";
} }
return classes; return classes;
} }
computeStateClass(stateObj) { computeStateClass(stateObj) {
return stateMoreInfoType(stateObj) !== 'hidden' ? 'state more-info' : 'state'; return stateMoreInfoType(stateObj) !== "hidden"
? "state more-info"
: "state";
} }
addTapEvents() { addTapEvents() {
const cards = this.root.querySelectorAll('.state'); const cards = this.root.querySelectorAll(".state");
cards.forEach((card) => { cards.forEach((card) => {
if (card.classList.contains('more-info')) { if (card.classList.contains("more-info")) {
card.addEventListener('click', this.entityTapped); card.addEventListener("click", this.entityTapped);
} else { } else {
card.removeEventListener('click', this.entityTapped); card.removeEventListener("click", this.entityTapped);
} }
}); });
} }
entityTapped(ev) { entityTapped(ev) {
const item = this.root.querySelector('dom-repeat').itemForElement(ev.target); const item = this.root
.querySelector("dom-repeat")
.itemForElement(ev.target);
let entityId; let entityId;
if (!item && !this.groupEntity) { if (!item && !this.groupEntity) {
return; return;
@@ -130,12 +135,16 @@ class HaEntitiesCard extends LocalizeMixin(EventsMixin(PolymerElement)) {
} else { } else {
entityId = this.groupEntity.entity_id; entityId = this.groupEntity.entity_id;
} }
this.fire('hass-more-info', { entityId: entityId }); this.fire("hass-more-info", { entityId: entityId });
} }
showGroupToggle(groupEntity, states) { showGroupToggle(groupEntity, states) {
if (!groupEntity || !states || groupEntity.attributes.control === 'hidden' if (
|| (groupEntity.state !== 'on' && groupEntity.state !== 'off')) { !groupEntity ||
!states ||
groupEntity.attributes.control === "hidden" ||
(groupEntity.state !== "on" && groupEntity.state !== "off")
) {
return false; return false;
} }
@@ -156,4 +165,4 @@ class HaEntitiesCard extends LocalizeMixin(EventsMixin(PolymerElement)) {
return canToggleCount > 1; return canToggleCount > 1;
} }
} }
customElements.define('ha-entities-card', HaEntitiesCard); customElements.define("ha-entities-card", HaEntitiesCard);

View File

@@ -1,13 +1,12 @@
import '@polymer/paper-card/paper-card.js'; import "@polymer/paper-card/paper-card.js";
import { html } from '@polymer/polymer/lib/utils/html-tag.js'; import { html } from "@polymer/polymer/lib/utils/html-tag.js";
import { PolymerElement } from '@polymer/polymer/polymer-element.js'; import { PolymerElement } from "@polymer/polymer/polymer-element.js";
import '../components/state-history-charts.js'; import "../components/state-history-charts.js";
import '../data/ha-state-history-data.js'; import "../data/ha-state-history-data.js";
import computeStateName from "../common/entity/compute_state_name.js";
import computeStateName from '../common/entity/compute_state_name.js'; import EventsMixin from "../mixins/events-mixin.js";
import EventsMixin from '../mixins/events-mixin.js';
/* /*
* @appliesMixin EventsMixin * @appliesMixin EventsMixin
@@ -55,7 +54,7 @@ class HaHistoryGraphCard extends EventsMixin(PolymerElement) {
hass: Object, hass: Object,
stateObj: { stateObj: {
type: Object, type: Object,
observer: 'stateObjObserver', observer: "stateObjObserver",
}, },
inDialog: { inDialog: {
type: Boolean, type: Boolean,
@@ -76,14 +75,19 @@ class HaHistoryGraphCard extends EventsMixin(PolymerElement) {
stateObjObserver(stateObj) { stateObjObserver(stateObj) {
if (!stateObj) return; if (!stateObj) return;
if (this.cacheConfig.cacheKey !== stateObj.entity_id if (
|| this.cacheConfig.refresh !== (stateObj.attributes.refresh || 0) this.cacheConfig.cacheKey !== stateObj.entity_id ||
|| this.cacheConfig.hoursToShow !== (stateObj.attributes.hours_to_show || 24)) { this.cacheConfig.refresh !== (stateObj.attributes.refresh || 0) ||
this.cacheConfig = Object.assign({}, { this.cacheConfig.hoursToShow !== (stateObj.attributes.hours_to_show || 24)
) {
this.cacheConfig = Object.assign(
{},
{
refresh: stateObj.attributes.refresh || 0, refresh: stateObj.attributes.refresh || 0,
cacheKey: stateObj.entity_id, cacheKey: stateObj.entity_id,
hoursToShow: stateObj.attributes.hours_to_show || 24 hoursToShow: stateObj.attributes.hours_to_show || 24,
}); }
);
} }
} }
@@ -92,7 +96,7 @@ class HaHistoryGraphCard extends EventsMixin(PolymerElement) {
} }
computeContentClass(inDialog) { computeContentClass(inDialog) {
return inDialog ? '' : 'content'; return inDialog ? "" : "content";
} }
computeHistoryEntities(stateObj) { computeHistoryEntities(stateObj) {
@@ -104,11 +108,11 @@ class HaHistoryGraphCard extends EventsMixin(PolymerElement) {
} }
cardTapped(ev) { cardTapped(ev) {
const mq = window.matchMedia('(min-width: 610px) and (min-height: 550px)'); const mq = window.matchMedia("(min-width: 610px) and (min-height: 550px)");
if (mq.matches) { if (mq.matches) {
ev.stopPropagation(); ev.stopPropagation();
this.fire('hass-more-info', { entityId: this.stateObj.entity_id }); this.fire("hass-more-info", { entityId: this.stateObj.entity_id });
} }
} }
} }
customElements.define('ha-history_graph-card', HaHistoryGraphCard); customElements.define("ha-history_graph-card", HaHistoryGraphCard);

View File

@@ -1,15 +1,15 @@
import '@polymer/iron-flex-layout/iron-flex-layout-classes.js'; import "@polymer/iron-flex-layout/iron-flex-layout-classes.js";
import '@polymer/paper-icon-button/paper-icon-button.js'; import "@polymer/paper-icon-button/paper-icon-button.js";
import '@polymer/paper-progress/paper-progress.js'; import "@polymer/paper-progress/paper-progress.js";
import '@polymer/paper-styles/element-styles/paper-material-styles.js'; import "@polymer/paper-styles/element-styles/paper-material-styles.js";
import { html } from '@polymer/polymer/lib/utils/html-tag.js'; import { html } from "@polymer/polymer/lib/utils/html-tag.js";
import { PolymerElement } from '@polymer/polymer/polymer-element.js'; import { PolymerElement } from "@polymer/polymer/polymer-element.js";
import HassMediaPlayerEntity from '../util/hass-media-player-model.js'; import HassMediaPlayerEntity from "../util/hass-media-player-model.js";
import computeStateName from '../common/entity/compute_state_name.js'; import computeStateName from "../common/entity/compute_state_name.js";
import EventsMixin from '../mixins/events-mixin.js'; import EventsMixin from "../mixins/events-mixin.js";
import LocalizeMixin from '../mixins/localize-mixin.js'; import LocalizeMixin from "../mixins/localize-mixin.js";
/* /*
* @appliesMixin LocalizeMixin * @appliesMixin LocalizeMixin
@@ -189,12 +189,12 @@ class HaMediaPlayerCard extends LocalizeMixin(EventsMixin(PolymerElement)) {
stateObj: Object, stateObj: Object,
playerObj: { playerObj: {
type: Object, type: Object,
computed: 'computePlayerObj(hass, stateObj)', computed: "computePlayerObj(hass, stateObj)",
observer: 'playerObjChanged', observer: "playerObjChanged",
}, },
playbackControlIcon: { playbackControlIcon: {
type: String, type: String,
computed: 'computePlaybackControlIcon(playerObj)', computed: "computePlaybackControlIcon(playerObj)",
}, },
playbackPosition: Number, playbackPosition: Number,
}; };
@@ -203,7 +203,10 @@ class HaMediaPlayerCard extends LocalizeMixin(EventsMixin(PolymerElement)) {
async playerObjChanged(playerObj, oldPlayerObj) { async playerObjChanged(playerObj, oldPlayerObj) {
if (playerObj.isPlaying && playerObj.showProgress) { if (playerObj.isPlaying && playerObj.showProgress) {
if (!this._positionTracking) { if (!this._positionTracking) {
this._positionTracking = setInterval(() => this.updatePlaybackPosition(), 1000); this._positionTracking = setInterval(
() => this.updatePlaybackPosition(),
1000
);
} }
} else if (this._positionTracking) { } else if (this._positionTracking) {
clearInterval(this._positionTracking); clearInterval(this._positionTracking);
@@ -214,25 +217,27 @@ class HaMediaPlayerCard extends LocalizeMixin(EventsMixin(PolymerElement)) {
} }
const picture = playerObj.stateObj.attributes.entity_picture; const picture = playerObj.stateObj.attributes.entity_picture;
const oldPicture = oldPlayerObj && oldPlayerObj.stateObj.attributes.entity_picture; const oldPicture =
oldPlayerObj && oldPlayerObj.stateObj.attributes.entity_picture;
if (picture !== oldPicture && !picture) { if (picture !== oldPicture && !picture) {
this.$.cover.style.backgroundImage = ''; this.$.cover.style.backgroundImage = "";
return; return;
} if (picture === oldPicture) { }
if (picture === oldPicture) {
return; return;
} }
// We have a new picture url // We have a new picture url
try { try {
const { content_type: contentType, content } = await this.hass.callWS({ const { content_type: contentType, content } = await this.hass.callWS({
type: 'media_player_thumbnail', type: "media_player_thumbnail",
entity_id: playerObj.stateObj.entity_id, entity_id: playerObj.stateObj.entity_id,
}); });
this.$.cover.style.backgroundImage = `url(data:${contentType};base64,${content})`; this.$.cover.style.backgroundImage = `url(data:${contentType};base64,${content})`;
} catch (err) { } catch (err) {
this.$.cover.style.backgroundImage = ''; this.$.cover.style.backgroundImage = "";
this.$.cover.parentElement.classList.add('no-cover'); this.$.cover.parentElement.classList.add("no-cover");
} }
} }
@@ -241,14 +246,14 @@ class HaMediaPlayerCard extends LocalizeMixin(EventsMixin(PolymerElement)) {
} }
computeBannerClasses(playerObj) { computeBannerClasses(playerObj) {
var cls = 'banner'; var cls = "banner";
if (playerObj.isOff || playerObj.isIdle) { if (playerObj.isOff || playerObj.isIdle) {
cls += ' is-off no-cover'; cls += " is-off no-cover";
} else if (!playerObj.stateObj.attributes.entity_picture) { } else if (!playerObj.stateObj.attributes.entity_picture) {
cls += ' no-cover'; cls += " no-cover";
} else if (playerObj.stateObj.attributes.media_content_type === 'music') { } else if (playerObj.stateObj.attributes.media_content_type === "music") {
cls += ' content-type-music'; cls += " content-type-music";
} }
return cls; return cls;
@@ -259,7 +264,9 @@ class HaMediaPlayerCard extends LocalizeMixin(EventsMixin(PolymerElement)) {
} }
computeHidePowerButton(playerObj) { computeHidePowerButton(playerObj) {
return playerObj.isOff ? !playerObj.supportsTurnOn : !playerObj.supportsTurnOff; return playerObj.isOff
? !playerObj.supportsTurnOn
: !playerObj.supportsTurnOff;
} }
computePlayerObj(hass, stateObj) { computePlayerObj(hass, stateObj) {
@@ -267,21 +274,29 @@ class HaMediaPlayerCard extends LocalizeMixin(EventsMixin(PolymerElement)) {
} }
computePrimaryText(localize, playerObj) { computePrimaryText(localize, playerObj) {
return playerObj.primaryTitle return (
|| localize(`state.media_player.${playerObj.stateObj.state}`) playerObj.primaryTitle ||
|| localize(`state.default.${playerObj.stateObj.state}`) || playerObj.stateObj.state; localize(`state.media_player.${playerObj.stateObj.state}`) ||
localize(`state.default.${playerObj.stateObj.state}`) ||
playerObj.stateObj.state
);
} }
computePlaybackControlIcon(playerObj) { computePlaybackControlIcon(playerObj) {
if (playerObj.isPlaying) { if (playerObj.isPlaying) {
return playerObj.supportsPause ? 'hass:pause' : 'hass:stop'; return playerObj.supportsPause ? "hass:pause" : "hass:stop";
} if (playerObj.hasMediaControl || playerObj.isOff || playerObj.isIdle) {
if (playerObj.hasMediaControl && playerObj.supportsPause && !playerObj.isPaused) {
return 'hass:play-pause';
} }
return playerObj.supportsPlay ? 'hass:play' : null; if (playerObj.hasMediaControl || playerObj.isOff || playerObj.isIdle) {
if (
playerObj.hasMediaControl &&
playerObj.supportsPause &&
!playerObj.isPaused
) {
return "hass:play-pause";
} }
return ''; return playerObj.supportsPlay ? "hass:play" : null;
}
return "";
} }
_computeStateName(stateObj) { _computeStateName(stateObj) {
@@ -295,7 +310,7 @@ class HaMediaPlayerCard extends LocalizeMixin(EventsMixin(PolymerElement)) {
handleOpenMoreInfo(ev) { handleOpenMoreInfo(ev) {
ev.stopPropagation(); ev.stopPropagation();
this.fire('hass-more-info', { entityId: this.stateObj.entity_id }); this.fire("hass-more-info", { entityId: this.stateObj.entity_id });
} }
handlePlaybackControl(ev) { handlePlaybackControl(ev) {
@@ -313,4 +328,4 @@ class HaMediaPlayerCard extends LocalizeMixin(EventsMixin(PolymerElement)) {
this.playerObj.togglePower(); this.playerObj.togglePower();
} }
} }
customElements.define('ha-media_player-card', HaMediaPlayerCard); customElements.define("ha-media_player-card", HaMediaPlayerCard);

View File

@@ -1,14 +1,13 @@
import '@polymer/paper-button/paper-button.js'; import "@polymer/paper-button/paper-button.js";
import { html } from '@polymer/polymer/lib/utils/html-tag.js'; import { html } from "@polymer/polymer/lib/utils/html-tag.js";
import { PolymerElement } from '@polymer/polymer/polymer-element.js'; import { PolymerElement } from "@polymer/polymer/polymer-element.js";
import '../components/ha-card.js'; import "../components/ha-card.js";
import '../components/ha-markdown.js'; import "../components/ha-markdown.js";
import computeStateName from "../common/entity/compute_state_name.js";
import computeStateName from '../common/entity/compute_state_name.js'; import LocalizeMixin from "../mixins/localize-mixin.js";
import LocalizeMixin from '../mixins/localize-mixin.js'; import computeObjectId from "../common/entity/compute_object_id";
import computeObjectId from '../common/entity/compute_object_id';
/* /*
* @appliesMixin LocalizeMixin * @appliesMixin LocalizeMixin
@@ -60,15 +59,17 @@ class HaPersistentNotificationCard extends LocalizeMixin(PolymerElement) {
} }
computeTitle(stateObj) { computeTitle(stateObj) {
return (stateObj.attributes.title return stateObj.attributes.title || computeStateName(stateObj);
|| computeStateName(stateObj));
} }
dismissTap(ev) { dismissTap(ev) {
ev.preventDefault(); ev.preventDefault();
this.hass.callService('persistent_notification', 'dismiss', { this.hass.callService("persistent_notification", "dismiss", {
notification_id: computeObjectId(this.stateObj.entity_id) notification_id: computeObjectId(this.stateObj.entity_id),
}); });
} }
} }
customElements.define('ha-persistent_notification-card', HaPersistentNotificationCard); customElements.define(
"ha-persistent_notification-card",
HaPersistentNotificationCard
);

View File

@@ -1,11 +1,11 @@
import { html } from '@polymer/polymer/lib/utils/html-tag.js'; import { html } from "@polymer/polymer/lib/utils/html-tag.js";
import { PolymerElement } from '@polymer/polymer/polymer-element.js'; import { PolymerElement } from "@polymer/polymer/polymer-element.js";
import '../components/ha-card.js'; import "../components/ha-card.js";
import '../components/ha-icon.js'; import "../components/ha-icon.js";
import computeStateName from '../common/entity/compute_state_name.js'; import computeStateName from "../common/entity/compute_state_name.js";
import EventsMixin from '../mixins/events-mixin.js'; import EventsMixin from "../mixins/events-mixin.js";
class HaPlantCard extends EventsMixin(PolymerElement) { class HaPlantCard extends EventsMixin(PolymerElement) {
static get template() { static get template() {
@@ -85,18 +85,18 @@ class HaPlantCard extends EventsMixin(PolymerElement) {
static get properties() { static get properties() {
return { return {
hass: Object, hass: Object,
stateObj: Object stateObj: Object,
}; };
} }
constructor() { constructor() {
super(); super();
this.sensors = { this.sensors = {
moisture: 'hass:water', moisture: "hass:water",
temperature: 'hass:thermometer', temperature: "hass:thermometer",
brightness: 'hass:white-balance-sunny', brightness: "hass:white-balance-sunny",
conductivity: 'hass:emoticon-poop', conductivity: "hass:emoticon-poop",
battery: 'hass:battery' battery: "hass:battery",
}; };
} }
@@ -105,16 +105,17 @@ class HaPlantCard extends EventsMixin(PolymerElement) {
} }
computeAttributes(data) { computeAttributes(data) {
return Object.keys(this.sensors).filter(key => key in data); return Object.keys(this.sensors).filter((key) => key in data);
} }
computeIcon(attr, batLvl) { computeIcon(attr, batLvl) {
const icon = this.sensors[attr]; const icon = this.sensors[attr];
if (attr === 'battery') { if (attr === "battery") {
if (batLvl <= 5) { if (batLvl <= 5) {
return `${icon}-alert`; return `${icon}-alert`;
} if (batLvl < 95) { }
return `${icon}-${Math.round((batLvl / 10) - 0.01) * 10}`; if (batLvl < 95) {
return `${icon}-${Math.round(batLvl / 10 - 0.01) * 10}`;
} }
} }
return icon; return icon;
@@ -125,20 +126,22 @@ class HaPlantCard extends EventsMixin(PolymerElement) {
} }
computeUom(dict, attr) { computeUom(dict, attr) {
return dict[attr] || ''; return dict[attr] || "";
} }
computeAttributeClass(problem, attr) { computeAttributeClass(problem, attr) {
return problem.indexOf(attr) === -1 ? '' : 'problem'; return problem.indexOf(attr) === -1 ? "" : "problem";
} }
computeImageClass(entityPicture) { computeImageClass(entityPicture) {
return entityPicture ? 'has-plant-image' : ''; return entityPicture ? "has-plant-image" : "";
} }
attributeClicked(ev) { attributeClicked(ev) {
this.fire('hass-more-info', { entityId: this.stateObj.attributes.sensors[ev.model.item] }); this.fire("hass-more-info", {
entityId: this.stateObj.attributes.sensors[ev.model.item],
});
} }
} }
customElements.define('ha-plant-card', HaPlantCard); customElements.define("ha-plant-card", HaPlantCard);

View File

@@ -1,17 +1,16 @@
import { html } from '@polymer/polymer/lib/utils/html-tag.js'; import { html } from "@polymer/polymer/lib/utils/html-tag.js";
import { PolymerElement } from '@polymer/polymer/polymer-element.js'; import { PolymerElement } from "@polymer/polymer/polymer-element.js";
import '../components/ha-card.js'; import "../components/ha-card.js";
import '../components/ha-icon.js'; import "../components/ha-icon.js";
import EventsMixin from '../mixins/events-mixin.js'; import EventsMixin from "../mixins/events-mixin.js";
import LocalizeMixin from '../mixins/localize-mixin.js'; import LocalizeMixin from "../mixins/localize-mixin.js";
/* /*
* @appliesMixin LocalizeMixin * @appliesMixin LocalizeMixin
*/ */
class HaWeatherCard extends class HaWeatherCard extends LocalizeMixin(EventsMixin(PolymerElement)) {
LocalizeMixin(EventsMixin(PolymerElement)) {
static get template() { static get template() {
return html` return html`
<style> <style>
@@ -160,42 +159,57 @@ class HaWeatherCard extends
stateObj: Object, stateObj: Object,
forecast: { forecast: {
type: Array, type: Array,
computed: 'computeForecast(stateObj.attributes.forecast)' computed: "computeForecast(stateObj.attributes.forecast)",
} },
}; };
} }
constructor() { constructor() {
super(); super();
this.cardinalDirections = [ this.cardinalDirections = [
'N', 'NNE', 'NE', 'ENE', 'E', 'ESE', 'SE', 'SSE', "N",
'S', 'SSW', 'SW', 'WSW', 'W', 'WNW', 'NW', 'NNW', 'N' "NNE",
"NE",
"ENE",
"E",
"ESE",
"SE",
"SSE",
"S",
"SSW",
"SW",
"WSW",
"W",
"WNW",
"NW",
"NNW",
"N",
]; ];
this.weatherIcons = { this.weatherIcons = {
'clear-night': 'hass:weather-night', "clear-night": "hass:weather-night",
cloudy: 'hass:weather-cloudy', cloudy: "hass:weather-cloudy",
fog: 'hass:weather-fog', fog: "hass:weather-fog",
hail: 'hass:weather-hail', hail: "hass:weather-hail",
lightning: 'hass:weather-lightning', lightning: "hass:weather-lightning",
'lightning-rainy': 'hass:weather-lightning-rainy', "lightning-rainy": "hass:weather-lightning-rainy",
partlycloudy: 'hass:weather-partlycloudy', partlycloudy: "hass:weather-partlycloudy",
pouring: 'hass:weather-pouring', pouring: "hass:weather-pouring",
rainy: 'hass:weather-rainy', rainy: "hass:weather-rainy",
snowy: 'hass:weather-snowy', snowy: "hass:weather-snowy",
'snowy-rainy': 'hass:weather-snowy-rainy', "snowy-rainy": "hass:weather-snowy-rainy",
sunny: 'hass:weather-sunny', sunny: "hass:weather-sunny",
windy: 'hass:weather-windy', windy: "hass:weather-windy",
'windy-variant': 'hass:weather-windy-variant' "windy-variant": "hass:weather-windy-variant",
}; };
} }
ready() { ready() {
this.addEventListener('click', this._onClick); this.addEventListener("click", this._onClick);
super.ready(); super.ready();
} }
_onClick() { _onClick() {
this.fire('hass-more-info', { entityId: this.stateObj.entity_id }); this.fire("hass-more-info", { entityId: this.stateObj.entity_id });
} }
computeForecast(forecast) { computeForecast(forecast) {
@@ -203,16 +217,16 @@ class HaWeatherCard extends
} }
getUnit(measure) { getUnit(measure) {
const lengthUnit = this.hass.config.unit_system.length || ''; const lengthUnit = this.hass.config.unit_system.length || "";
switch (measure) { switch (measure) {
case 'air_pressure': case "air_pressure":
return lengthUnit === 'km' ? 'hPa' : 'inHg'; return lengthUnit === "km" ? "hPa" : "inHg";
case 'length': case "length":
return lengthUnit; return lengthUnit;
case 'precipitation': case "precipitation":
return lengthUnit === 'km' ? 'mm' : 'in'; return lengthUnit === "km" ? "mm" : "in";
default: default:
return this.hass.config.unit_system[measure] || ''; return this.hass.config.unit_system[measure] || "";
} }
} }
@@ -239,20 +253,22 @@ class HaWeatherCard extends
getWind(speed, bearing, localize) { getWind(speed, bearing, localize) {
if (bearing != null) { if (bearing != null) {
const cardinalDirection = this.windBearingToText(bearing); const cardinalDirection = this.windBearingToText(bearing);
return `${speed} ${this.getUnit('length')}/h (${localize(`ui.card.weather.cardinal_direction.${cardinalDirection.toLowerCase()}`) || cardinalDirection})`; return `${speed} ${this.getUnit("length")}/h (${localize(
`ui.card.weather.cardinal_direction.${cardinalDirection.toLowerCase()}`
) || cardinalDirection})`;
} }
return `${speed} ${this.getUnit('length')}/h`; return `${speed} ${this.getUnit("length")}/h`;
} }
_showValue(item) { _showValue(item) {
return typeof item !== 'undefined' && item !== null; return typeof item !== "undefined" && item !== null;
} }
computeDate(data) { computeDate(data) {
const date = new Date(data); const date = new Date(data);
return date.toLocaleDateString( return date.toLocaleDateString(
this.hass.selectedLanguage || this.hass.language, this.hass.selectedLanguage || this.hass.language,
{ weekday: 'short' } { weekday: "short" }
); );
} }
@@ -260,8 +276,8 @@ class HaWeatherCard extends
const date = new Date(data); const date = new Date(data);
return date.toLocaleTimeString( return date.toLocaleTimeString(
this.hass.selectedLanguage || this.hass.language, this.hass.selectedLanguage || this.hass.language,
{ hour: 'numeric' } { hour: "numeric" }
); );
} }
} }
customElements.define('ha-weather-card', HaWeatherCard); customElements.define("ha-weather-card", HaWeatherCard);

View File

@@ -1,13 +1,15 @@
/** /**
* Auth class that connects to a native app for authentication. * Auth class that connects to a native app for authentication.
*/ */
import { Auth } from 'home-assistant-js-websocket'; import { Auth } from "home-assistant-js-websocket";
const CALLBACK_SET_TOKEN = 'externalAuthSetToken'; const CALLBACK_SET_TOKEN = "externalAuthSetToken";
const CALLBACK_REVOKE_TOKEN = 'externalAuthRevokeToken'; const CALLBACK_REVOKE_TOKEN = "externalAuthRevokeToken";
if (!window.externalApp && !window.webkit) { if (!window.externalApp && !window.webkit) {
throw new Error('External auth requires either externalApp or webkit defined on Window object.'); throw new Error(
"External auth requires either externalApp or webkit defined on Window object."
);
} }
export default class ExternalAuth extends Auth { export default class ExternalAuth extends Auth {
@@ -16,7 +18,7 @@ export default class ExternalAuth extends Auth {
this.data = { this.data = {
hassUrl, hassUrl,
access_token: '', access_token: "",
// This will trigger connection to do a refresh right away // This will trigger connection to do a refresh right away
expires: 0, expires: 0,
}; };
@@ -24,7 +26,8 @@ export default class ExternalAuth extends Auth {
async refreshAccessToken() { async refreshAccessToken() {
const responseProm = new Promise((resolve, reject) => { const responseProm = new Promise((resolve, reject) => {
window[CALLBACK_SET_TOKEN] = (success, data) => (success ? resolve(data) : reject(data)); window[CALLBACK_SET_TOKEN] = (success, data) =>
success ? resolve(data) : reject(data);
}); });
// Allow promise to set resolve on window object. // Allow promise to set resolve on window object.
@@ -35,7 +38,9 @@ export default class ExternalAuth extends Auth {
if (window.externalApp) { if (window.externalApp) {
window.externalApp.getExternalAuth(callbackPayload); window.externalApp.getExternalAuth(callbackPayload);
} else { } else {
window.webkit.messageHandlers.getExternalAuth.postMessage(callbackPayload); window.webkit.messageHandlers.getExternalAuth.postMessage(
callbackPayload
);
} }
// Response we expect back: // Response we expect back:
@@ -46,12 +51,13 @@ export default class ExternalAuth extends Auth {
const tokens = await responseProm; const tokens = await responseProm;
this.data.access_token = tokens.access_token; this.data.access_token = tokens.access_token;
this.data.expires = (tokens.expires_in * 1000) + Date.now(); this.data.expires = tokens.expires_in * 1000 + Date.now();
} }
async revoke() { async revoke() {
const responseProm = new Promise((resolve, reject) => { const responseProm = new Promise((resolve, reject) => {
window[CALLBACK_REVOKE_TOKEN] = (success, data) => (success ? resolve(data) : reject(data)); window[CALLBACK_REVOKE_TOKEN] = (success, data) =>
success ? resolve(data) : reject(data);
}); });
// Allow promise to set resolve on window object. // Allow promise to set resolve on window object.
@@ -62,7 +68,9 @@ export default class ExternalAuth extends Auth {
if (window.externalApp) { if (window.externalApp) {
window.externalApp.revokeExternalAuth(callbackPayload); window.externalApp.revokeExternalAuth(callbackPayload);
} else { } else {
window.webkit.messageHandlers.revokeExternalAuth.postMessage(callbackPayload); window.webkit.messageHandlers.revokeExternalAuth.postMessage(
callbackPayload
);
} }
await responseProm; await responseProm;

View File

@@ -10,7 +10,9 @@ if (!tokenCache) {
} }
export function askWrite() { export function askWrite() {
return tokenCache.tokens !== undefined && tokenCache.writeEnabled === undefined; return (
tokenCache.tokens !== undefined && tokenCache.writeEnabled === undefined
);
} }
export function saveTokens(tokens) { export function saveTokens(tokens) {

View File

@@ -1,4 +1,4 @@
/** Return if the displaymode is in standalone mode (PWA). */ /** Return if the displaymode is in standalone mode (PWA). */
export default function isPwa() { export default function isPwa() {
return (window.matchMedia('(display-mode: standalone)').matches); return window.matchMedia("(display-mode: standalone)").matches;
} }

View File

@@ -5,84 +5,80 @@
// Each constant should have a description what it is supposed to be used for. // Each constant should have a description what it is supposed to be used for.
/** Icon to use when no icon specified for domain. */ /** Icon to use when no icon specified for domain. */
export const DEFAULT_DOMAIN_ICON = 'hass:bookmark'; export const DEFAULT_DOMAIN_ICON = "hass:bookmark";
/** Domains that have a state card. */ /** Domains that have a state card. */
export const DOMAINS_WITH_CARD = [ export const DOMAINS_WITH_CARD = [
'climate', "climate",
'cover', "cover",
'configurator', "configurator",
'input_select', "input_select",
'input_number', "input_number",
'input_text', "input_text",
'lock', "lock",
'media_player', "media_player",
'scene', "scene",
'script', "script",
'timer', "timer",
'vacuum', "vacuum",
'water_heater', "water_heater",
'weblink', "weblink",
]; ];
/** Domains with separate more info dialog. */ /** Domains with separate more info dialog. */
export const DOMAINS_WITH_MORE_INFO = [ export const DOMAINS_WITH_MORE_INFO = [
'alarm_control_panel', "alarm_control_panel",
'automation', "automation",
'camera', "camera",
'climate', "climate",
'configurator', "configurator",
'cover', "cover",
'fan', "fan",
'group', "group",
'history_graph', "history_graph",
'input_datetime', "input_datetime",
'light', "light",
'lock', "lock",
'media_player', "media_player",
'script', "script",
'sun', "sun",
'updater', "updater",
'vacuum', "vacuum",
'water_heater', "water_heater",
'weather' "weather",
]; ];
/** Domains that show no more info dialog. */ /** Domains that show no more info dialog. */
export const DOMAINS_HIDE_MORE_INFO = [ export const DOMAINS_HIDE_MORE_INFO = [
'input_number', "input_number",
'input_select', "input_select",
'input_text', "input_text",
'scene', "scene",
'weblink' "weblink",
]; ];
/** Domains that should have the history hidden in the more info dialog. */ /** Domains that should have the history hidden in the more info dialog. */
export const DOMAINS_MORE_INFO_NO_HISTORY = [ export const DOMAINS_MORE_INFO_NO_HISTORY = [
'camera', "camera",
'configurator', "configurator",
'history_graph', "history_graph",
'scene', "scene",
]; ];
/** States that we consider "off". */ /** States that we consider "off". */
export const STATES_OFF = [ export const STATES_OFF = ["closed", "locked", "off"];
'closed',
'locked',
'off'
];
/** Domains where we allow toggle in Lovelace. */ /** Domains where we allow toggle in Lovelace. */
export const DOMAINS_TOGGLE = new Set([ export const DOMAINS_TOGGLE = new Set([
'fan', "fan",
'input_boolean', "input_boolean",
'light', "light",
'switch' "switch",
]); ]);
/** Temperature units. */ /** Temperature units. */
export const UNIT_C = '°C'; export const UNIT_C = "°C";
export const UNIT_F = '°F'; export const UNIT_F = "°F";
/** Entity ID of the default view. */ /** Entity ID of the default view. */
export const DEFAULT_VIEW_ENTITY_ID = 'group.default_view'; export const DEFAULT_VIEW_ENTITY_ID = "group.default_view";

View File

@@ -1,4 +1,4 @@
export default function durationToSeconds(duration) { export default function durationToSeconds(duration) {
const parts = duration.split(':').map(Number); const parts = duration.split(":").map(Number);
return (parts[0] * 3600) + (parts[1] * 60) + parts[2]; return parts[0] * 3600 + parts[1] * 60 + parts[2];
} }

View File

@@ -1,21 +1,21 @@
import fecha from 'fecha'; import fecha from "fecha";
// Check for support of native locale string options // Check for support of native locale string options
function toLocaleDateStringSupportsOptions() { function toLocaleDateStringSupportsOptions() {
try { try {
new Date().toLocaleDateString('i'); new Date().toLocaleDateString("i");
} catch (e) { } catch (e) {
return e.name === 'RangeError'; return e.name === "RangeError";
} }
return false; return false;
} }
export default (toLocaleDateStringSupportsOptions() export default (toLocaleDateStringSupportsOptions()
? function (dateObj, locales) { ? (dateObj, locales) =>
return dateObj.toLocaleDateString( dateObj.toLocaleDateString(locales, {
locales, year: "numeric",
{ year: 'numeric', month: 'long', day: 'numeric' }, month: "long",
); day: "numeric",
} : function (dateObj, locales) { // eslint-disable-line no-unused-vars })
return fecha.format(dateObj, 'mediumDate'); : // eslint-disable-next-line no-unused-vars
}); (dateObj, locales) => fecha.format(dateObj, "mediumDate"));

View File

@@ -1,24 +1,23 @@
import fecha from 'fecha'; import fecha from "fecha";
// Check for support of native locale string options // Check for support of native locale string options
function toLocaleStringSupportsOptions() { function toLocaleStringSupportsOptions() {
try { try {
new Date().toLocaleString('i'); new Date().toLocaleString("i");
} catch (e) { } catch (e) {
return e.name === 'RangeError'; return e.name === "RangeError";
} }
return false; return false;
} }
export default (toLocaleStringSupportsOptions() export default (toLocaleStringSupportsOptions()
? function (dateObj, locales) { ? (dateObj, locales) =>
return dateObj.toLocaleString(locales, { dateObj.toLocaleString(locales, {
year: 'numeric', year: "numeric",
month: 'long', month: "long",
day: 'numeric', day: "numeric",
hour: 'numeric', hour: "numeric",
minute: '2-digit', minute: "2-digit",
}); })
} : function (dateObj, locales) { // eslint-disable-line no-unused-vars : // eslint-disable-next-line no-unused-vars
return fecha.format(dateObj, 'haDateTime'); (dateObj, locales) => fecha.format(dateObj, "haDateTime"));
});

View File

@@ -1,21 +1,20 @@
import fecha from 'fecha'; import fecha from "fecha";
// Check for support of native locale string options // Check for support of native locale string options
function toLocaleTimeStringSupportsOptions() { function toLocaleTimeStringSupportsOptions() {
try { try {
new Date().toLocaleTimeString('i'); new Date().toLocaleTimeString("i");
} catch (e) { } catch (e) {
return e.name === 'RangeError'; return e.name === "RangeError";
} }
return false; return false;
} }
export default (toLocaleTimeStringSupportsOptions() export default (toLocaleTimeStringSupportsOptions()
? function (dateObj, locales) { ? (dateObj, locales) =>
return dateObj.toLocaleTimeString( dateObj.toLocaleTimeString(locales, {
locales, hour: "numeric",
{ hour: 'numeric', minute: '2-digit' } minute: "2-digit",
); })
} : function (dateObj, locales) { // eslint-disable-line no-unused-vars : // eslint-disable-next-line no-unused-vars
return fecha.format(dateObj, 'shortTime'); (dateObj, locales) => fecha.format(dateObj, "shortTime"));
});

View File

@@ -1,30 +1,33 @@
/** Calculate a string representing a date object as relative time from now. /** Calculate a string representing a date object as relative time from now.
* *
* Example output: 5 minutes ago, in 3 days. * Example output: 5 minutes ago, in 3 days.
*/ */
const tests = [ const tests = [60, "second", 60, "minute", 24, "hour", 7, "day"];
60, 'second',
60, 'minute',
24, 'hour',
7, 'day',
];
export default function relativeTime(dateObj, localize) { export default function relativeTime(dateObj, localize) {
let delta = (new Date() - dateObj) / 1000; let delta = (new Date() - dateObj) / 1000;
const tense = delta >= 0 ? 'past' : 'future'; const tense = delta >= 0 ? "past" : "future";
delta = Math.abs(delta); delta = Math.abs(delta);
for (let i = 0; i < tests.length; i += 2) { for (let i = 0; i < tests.length; i += 2) {
if (delta < tests[i]) { if (delta < tests[i]) {
delta = Math.floor(delta); delta = Math.floor(delta);
const time = localize(`ui.components.relative_time.duration.${tests[i + 1]}`, 'count', delta); const time = localize(
return localize(`ui.components.relative_time.${tense}`, 'time', time); `ui.components.relative_time.duration.${tests[i + 1]}`,
"count",
delta
);
return localize(`ui.components.relative_time.${tense}`, "time", time);
} }
delta /= tests[i]; delta /= tests[i];
} }
delta = Math.floor(delta); delta = Math.floor(delta);
const time = localize('ui.components.relative_time.duration.week', 'count', delta); const time = localize(
return localize(`ui.components.relative_time.${tense}`, 'time', time); "ui.components.relative_time.duration.week",
"count",
delta
);
return localize(`ui.components.relative_time.${tense}`, "time", time);
} }

View File

@@ -1,16 +1,18 @@
const leftPad = number => (number < 10 ? `0${number}` : number); const leftPad = (number) => (number < 10 ? `0${number}` : number);
export default function secondsToDuration(d) { export default function secondsToDuration(d) {
const h = Math.floor(d / 3600); const h = Math.floor(d / 3600);
const m = Math.floor((d % 3600) / 60); const m = Math.floor((d % 3600) / 60);
const s = Math.floor(d % 3600 % 60); const s = Math.floor((d % 3600) % 60);
if (h > 0) { if (h > 0) {
return `${h}:${leftPad(m)}:${leftPad(s)}`; return `${h}:${leftPad(m)}:${leftPad(s)}`;
} if (m > 0) { }
if (m > 0) {
return `${m}:${leftPad(s)}`; return `${m}:${leftPad(s)}`;
} if (s > 0) { }
return '' + s; if (s > 0) {
return "" + s;
} }
return null; return null;
} }

View File

@@ -5,21 +5,26 @@
* themes: HASS Theme information * themes: HASS Theme information
* localTheme: selected theme. * localTheme: selected theme.
* updateMeta: boolean if we should update the theme-color meta element. * updateMeta: boolean if we should update the theme-color meta element.
*/ */
export default function applyThemesOnElement(element, themes, localTheme, updateMeta = false) { export default function applyThemesOnElement(
element,
themes,
localTheme,
updateMeta = false
) {
if (!element._themes) { if (!element._themes) {
element._themes = {}; element._themes = {};
} }
let themeName = themes.default_theme; let themeName = themes.default_theme;
if (localTheme === 'default' || (localTheme && themes.themes[localTheme])) { if (localTheme === "default" || (localTheme && themes.themes[localTheme])) {
themeName = localTheme; themeName = localTheme;
} }
const styles = Object.assign({}, element._themes); const styles = Object.assign({}, element._themes);
if (themeName !== 'default') { if (themeName !== "default") {
var theme = themes.themes[themeName]; var theme = themes.themes[themeName];
Object.keys(theme).forEach((key) => { Object.keys(theme).forEach((key) => {
var prefixedKey = '--' + key; var prefixedKey = "--" + key;
element._themes[prefixedKey] = ''; element._themes[prefixedKey] = "";
styles[prefixedKey] = theme[key]; styles[prefixedKey] = theme[key];
}); });
} }
@@ -27,17 +32,18 @@ export default function applyThemesOnElement(element, themes, localTheme, update
element.updateStyles(styles); element.updateStyles(styles);
} else if (window.ShadyCSS) { } else if (window.ShadyCSS) {
// implement updateStyles() method of Polemer elements // implement updateStyles() method of Polemer elements
window.ShadyCSS.styleSubtree(/** @type {!HTMLElement} */(element), styles); window.ShadyCSS.styleSubtree(/** @type {!HTMLElement} */ (element), styles);
} }
if (!updateMeta) return; if (!updateMeta) return;
const meta = document.querySelector('meta[name=theme-color]'); const meta = document.querySelector("meta[name=theme-color]");
if (meta) { if (meta) {
if (!meta.hasAttribute('default-content')) { if (!meta.hasAttribute("default-content")) {
meta.setAttribute('default-content', meta.getAttribute('content')); meta.setAttribute("default-content", meta.getAttribute("content"));
} }
const themeColor = styles['--primary-color'] || meta.getAttribute('default-content'); const themeColor =
meta.setAttribute('content', themeColor); styles["--primary-color"] || meta.getAttribute("default-content");
meta.setAttribute("content", themeColor);
} }
} }

View File

@@ -45,11 +45,11 @@
*/ */
export default function fire(node, type, detail, options) { export default function fire(node, type, detail, options) {
options = options || {}; options = options || {};
detail = (detail === null || detail === undefined) ? {} : detail; detail = detail === null || detail === undefined ? {} : detail;
const event = new Event(type, { const event = new Event(type, {
bubbles: options.bubbles === undefined ? true : options.bubbles, bubbles: options.bubbles === undefined ? true : options.bubbles,
cancelable: Boolean(options.cancelable), cancelable: Boolean(options.cancelable),
composed: options.composed === undefined ? true : options.composed composed: options.composed === undefined ? true : options.composed,
}); });
event.detail = detail; event.detail = detail;
node.dispatchEvent(event); node.dispatchEvent(event);

View File

@@ -3,10 +3,10 @@
function _load(tag, url, type) { function _load(tag, url, type) {
// This promise will be used by Promise.all to determine success or failure // This promise will be used by Promise.all to determine success or failure
return new Promise(function (resolve, reject) { return new Promise(function(resolve, reject) {
const element = document.createElement(tag); const element = document.createElement(tag);
let attr = 'src'; let attr = "src";
let parent = 'body'; let parent = "body";
// Important success and error for the promise // Important success and error for the promise
element.onload = () => resolve(url); element.onload = () => resolve(url);
@@ -14,17 +14,17 @@ function _load(tag, url, type) {
// Need to set different attributes depending on tag type // Need to set different attributes depending on tag type
switch (tag) { switch (tag) {
case 'script': case "script":
element.async = true; element.async = true;
if (type) { if (type) {
element.type = type; element.type = type;
} }
break; break;
case 'link': case "link":
element.type = 'text/css'; element.type = "text/css";
element.rel = 'stylesheet'; element.rel = "stylesheet";
attr = 'href'; attr = "href";
parent = 'head'; parent = "head";
} }
// Inject into document to kick off loading // Inject into document to kick off loading
@@ -33,7 +33,7 @@ function _load(tag, url, type) {
}); });
} }
export const loadCSS = url => _load('link', url); export const loadCSS = (url) => _load("link", url);
export const loadJS = url => _load('script', url); export const loadJS = (url) => _load("script", url);
export const loadImg = url => _load('img', url); export const loadImg = (url) => _load("img", url);
export const loadModule = url => _load('script', url, 'module'); export const loadModule = (url) => _load("script", url, "module");

View File

@@ -16,7 +16,7 @@ export default function scrollToTarget(element, target) {
var easingFn = function easeOutQuad(t, b, c, d) { var easingFn = function easeOutQuad(t, b, c, d) {
/* eslint-disable no-param-reassign, space-infix-ops, no-mixed-operators */ /* eslint-disable no-param-reassign, space-infix-ops, no-mixed-operators */
t /= d; t /= d;
return -c * t*(t-2) + b; return -c * t * (t - 2) + b;
/* eslint-enable no-param-reassign, space-infix-ops, no-mixed-operators */ /* eslint-enable no-param-reassign, space-infix-ops, no-mixed-operators */
}; };
var animationId = Math.random(); var animationId = Math.random();
@@ -31,8 +31,13 @@ export default function scrollToTarget(element, target) {
if (elapsedTime > duration) { if (elapsedTime > duration) {
scroller.scrollTop = top; scroller.scrollTop = top;
} else if (element._currentAnimationId === animationId) { } else if (element._currentAnimationId === animationId) {
scroller.scrollTop = easingFn(elapsedTime, currentScrollTop, deltaScrollTop, duration); scroller.scrollTop = easingFn(
elapsedTime,
currentScrollTop,
deltaScrollTop,
duration
);
requestAnimationFrame(updateFrame.bind(element)); requestAnimationFrame(updateFrame.bind(element));
} }
}).call(element); }.call(element));
} }

View File

@@ -1,18 +1,21 @@
import Leaflet from 'leaflet'; import Leaflet from "leaflet";
// Sets up a Leaflet map on the provided DOM element // Sets up a Leaflet map on the provided DOM element
export default function setupLeafletMap(mapElement) { export default function setupLeafletMap(mapElement) {
const map = Leaflet.map(mapElement); const map = Leaflet.map(mapElement);
const style = document.createElement('link'); const style = document.createElement("link");
style.setAttribute('href', '/static/images/leaflet/leaflet.css'); style.setAttribute("href", "/static/images/leaflet/leaflet.css");
style.setAttribute('rel', 'stylesheet'); style.setAttribute("rel", "stylesheet");
mapElement.parentNode.appendChild(style); mapElement.parentNode.appendChild(style);
map.setView([51.505, -0.09], 13); map.setView([51.505, -0.09], 13);
Leaflet.tileLayer( Leaflet.tileLayer(
`https://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}${Leaflet.Browser.retina ? '@2x.png' : '.png'}`, `https://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}${
Leaflet.Browser.retina ? "@2x.png" : ".png"
}`,
{ {
attribution: '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a>, &copy; <a href="https://carto.com/attributions">CARTO</a>', attribution:
subdomains: 'abcd', '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a>, &copy; <a href="https://carto.com/attributions">CARTO</a>',
subdomains: "abcd",
minZoom: 0, minZoom: 0,
maxZoom: 20, maxZoom: 20,
} }

View File

@@ -1,2 +1,2 @@
/** An empty image which can be set as src of an img element. */ /** An empty image which can be set as src of an img element. */
export default 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7'; export default "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7";

View File

@@ -1,6 +1,9 @@
export default function attributeClassNames(stateObj, attributes) { export default function attributeClassNames(stateObj, attributes) {
if (!stateObj) return ''; if (!stateObj) return "";
return attributes.map(function (attribute) { return attributes
return attribute in stateObj.attributes ? 'has-' + attribute : ''; .map(function(attribute) {
}).filter(attr => attr !== '').join(' '); return attribute in stateObj.attributes ? "has-" + attribute : "";
})
.filter((attr) => attr !== "")
.join(" ");
} }

View File

@@ -1,49 +1,49 @@
/** Return an icon representing a binary sensor state. */ /** Return an icon representing a binary sensor state. */
export default function binarySensorIcon(state) { export default function binarySensorIcon(state) {
var activated = state.state && state.state === 'off'; var activated = state.state && state.state === "off";
switch (state.attributes.device_class) { switch (state.attributes.device_class) {
case 'battery': case "battery":
return activated ? 'hass:battery' : 'hass:battery-outline'; return activated ? "hass:battery" : "hass:battery-outline";
case 'cold': case "cold":
return activated ? 'hass:thermometer' : 'hass:snowflake'; return activated ? "hass:thermometer" : "hass:snowflake";
case 'connectivity': case "connectivity":
return activated ? 'hass:server-network-off' : 'hass:server-network'; return activated ? "hass:server-network-off" : "hass:server-network";
case 'door': case "door":
return activated ? 'hass:door-closed' : 'hass:door-open'; return activated ? "hass:door-closed" : "hass:door-open";
case 'garage_door': case "garage_door":
return activated ? 'hass:garage' : 'hass:garage-open'; return activated ? "hass:garage" : "hass:garage-open";
case 'gas': case "gas":
case 'power': case "power":
case 'problem': case "problem":
case 'safety': case "safety":
case 'smoke': case "smoke":
return activated ? 'hass:verified' : 'hass:alert'; return activated ? "hass:verified" : "hass:alert";
case 'heat': case "heat":
return activated ? 'hass:thermometer' : 'hass:fire'; return activated ? "hass:thermometer" : "hass:fire";
case 'light': case "light":
return activated ? 'hass:brightness-5' : 'hass:brightness-7'; return activated ? "hass:brightness-5" : "hass:brightness-7";
case 'lock': case "lock":
return activated ? 'hass:lock' : 'hass:lock-open'; return activated ? "hass:lock" : "hass:lock-open";
case 'moisture': case "moisture":
return activated ? 'hass:water-off' : 'hass:water'; return activated ? "hass:water-off" : "hass:water";
case 'motion': case "motion":
return activated ? 'hass:walk' : 'hass:run'; return activated ? "hass:walk" : "hass:run";
case 'occupancy': case "occupancy":
return activated ? 'hass:home-outline' : 'hass:home'; return activated ? "hass:home-outline" : "hass:home";
case 'opening': case "opening":
return activated ? 'hass:square' : 'hass:square-outline'; return activated ? "hass:square" : "hass:square-outline";
case 'plug': case "plug":
return activated ? 'hass:power-plug-off' : 'hass:power-plug'; return activated ? "hass:power-plug-off" : "hass:power-plug";
case 'presence': case "presence":
return activated ? 'hass:home-outline' : 'hass:home'; return activated ? "hass:home-outline" : "hass:home";
case 'sound': case "sound":
return activated ? 'hass:music-note-off' : 'hass:music-note'; return activated ? "hass:music-note-off" : "hass:music-note";
case 'vibration': case "vibration":
return activated ? 'hass:crop-portrait' : 'hass:vibrate'; return activated ? "hass:crop-portrait" : "hass:vibrate";
case 'window': case "window":
return activated ? 'hass:window-closed' : 'hass:window-open'; return activated ? "hass:window-closed" : "hass:window-open";
default: default:
return activated ? 'hass:radiobox-blank' : 'hass:checkbox-marked-circle'; return activated ? "hass:radiobox-blank" : "hass:checkbox-marked-circle";
} }
} }

View File

@@ -1,11 +1,14 @@
export default function canToggleDomain(hass, domain) { export default function canToggleDomain(hass, domain) {
const services = hass.services[domain]; const services = hass.services[domain];
if (!services) { return false; } if (!services) {
return false;
if (domain === 'lock') {
return 'lock' in services;
} if (domain === 'cover') {
return 'open_cover' in services;
} }
return 'turn_on' in services;
if (domain === "lock") {
return "lock" in services;
}
if (domain === "cover") {
return "open_cover" in services;
}
return "turn_on" in services;
} }

View File

@@ -1,12 +1,12 @@
import canToggleDomain from './can_toggle_domain.js'; import canToggleDomain from "./can_toggle_domain.js";
import computeStateDomain from './compute_state_domain.js'; import computeStateDomain from "./compute_state_domain.js";
export default function canToggleState(hass, stateObj) { export default function canToggleState(hass, stateObj) {
const domain = computeStateDomain(stateObj); const domain = computeStateDomain(stateObj);
if (domain === 'group') { if (domain === "group") {
return stateObj.state === 'on' || stateObj.state === 'off'; return stateObj.state === "on" || stateObj.state === "off";
} }
if (domain === 'climate') { if (domain === "climate") {
return !!((stateObj.attributes || {}).supported_features & 4096); return !!((stateObj.attributes || {}).supported_features & 4096);
} }

View File

@@ -1,3 +1,3 @@
export default function computeDomain(entityId) { export default function computeDomain(entityId) {
return entityId.substr(0, entityId.indexOf('.')); return entityId.substr(0, entityId.indexOf("."));
} }

View File

@@ -1,4 +1,4 @@
/** Compute the object ID of a state. */ /** Compute the object ID of a state. */
export default function computeObjectId(entityId) { export default function computeObjectId(entityId) {
return entityId.substr(entityId.indexOf('.') + 1); return entityId.substr(entityId.indexOf(".") + 1);
} }

View File

@@ -1,22 +1,32 @@
import computeStateDomain from './compute_state_domain.js'; import computeStateDomain from "./compute_state_domain.js";
import formatDateTime from '../datetime/format_date_time.js'; import formatDateTime from "../datetime/format_date_time.js";
import formatDate from '../datetime/format_date.js'; import formatDate from "../datetime/format_date.js";
import formatTime from '../datetime/format_time.js'; import formatTime from "../datetime/format_time.js";
export default function computeStateDisplay(localize, stateObj, language) { export default function computeStateDisplay(localize, stateObj, language) {
if (!stateObj._stateDisplay) { if (!stateObj._stateDisplay) {
const domain = computeStateDomain(stateObj); const domain = computeStateDomain(stateObj);
if (domain === 'binary_sensor') { if (domain === "binary_sensor") {
// Try device class translation, then default binary sensor translation // Try device class translation, then default binary sensor translation
if (stateObj.attributes.device_class) { if (stateObj.attributes.device_class) {
stateObj._stateDisplay = localize(`state.${domain}.${stateObj.attributes.device_class}.${stateObj.state}`); stateObj._stateDisplay = localize(
`state.${domain}.${stateObj.attributes.device_class}.${
stateObj.state
}`
);
} }
if (!stateObj._stateDisplay) { if (!stateObj._stateDisplay) {
stateObj._stateDisplay = localize(`state.${domain}.default.${stateObj.state}`); stateObj._stateDisplay = localize(
`state.${domain}.default.${stateObj.state}`
);
} }
} else if (stateObj.attributes.unit_of_measurement && !['unknown', 'unavailable'].includes(stateObj.state)) { } else if (
stateObj._stateDisplay = stateObj.state + ' ' + stateObj.attributes.unit_of_measurement; stateObj.attributes.unit_of_measurement &&
} else if (domain === 'input_datetime') { !["unknown", "unavailable"].includes(stateObj.state)
) {
stateObj._stateDisplay =
stateObj.state + " " + stateObj.attributes.unit_of_measurement;
} else if (domain === "input_datetime") {
let date; let date;
if (!stateObj.attributes.has_time) { if (!stateObj.attributes.has_time) {
date = new Date( date = new Date(
@@ -30,33 +40,44 @@ export default function computeStateDisplay(localize, stateObj, language) {
date = new Date( date = new Date(
// Due to bugs.chromium.org/p/chromium/issues/detail?id=797548 // Due to bugs.chromium.org/p/chromium/issues/detail?id=797548
// don't use artificial 1970 year. // don't use artificial 1970 year.
now.getFullYear(), now.getMonth(), now.getDay(), now.getFullYear(),
now.getMonth(),
now.getDay(),
stateObj.attributes.hour, stateObj.attributes.hour,
stateObj.attributes.minute stateObj.attributes.minute
); );
stateObj._stateDisplay = formatTime(date, language); stateObj._stateDisplay = formatTime(date, language);
} else { } else {
date = new Date( date = new Date(
stateObj.attributes.year, stateObj.attributes.month - 1, stateObj.attributes.year,
stateObj.attributes.day, stateObj.attributes.hour, stateObj.attributes.month - 1,
stateObj.attributes.day,
stateObj.attributes.hour,
stateObj.attributes.minute stateObj.attributes.minute
); );
stateObj._stateDisplay = formatDateTime(date, language); stateObj._stateDisplay = formatDateTime(date, language);
} }
} else if (domain === 'zwave') { } else if (domain === "zwave") {
if (['initializing', 'dead'].includes(stateObj.state)) { if (["initializing", "dead"].includes(stateObj.state)) {
stateObj._stateDisplay = localize(`state.zwave.query_stage.${stateObj.state}`, 'query_stage', stateObj.attributes.query_stage); stateObj._stateDisplay = localize(
`state.zwave.query_stage.${stateObj.state}`,
"query_stage",
stateObj.attributes.query_stage
);
} else { } else {
stateObj._stateDisplay = localize(`state.zwave.default.${stateObj.state}`); stateObj._stateDisplay = localize(
`state.zwave.default.${stateObj.state}`
);
} }
} else { } else {
stateObj._stateDisplay = localize(`state.${domain}.${stateObj.state}`); stateObj._stateDisplay = localize(`state.${domain}.${stateObj.state}`);
} }
// Fall back to default, component backend translation, or raw state if nothing else matches. // Fall back to default, component backend translation, or raw state if nothing else matches.
stateObj._stateDisplay = stateObj._stateDisplay stateObj._stateDisplay =
|| localize(`state.default.${stateObj.state}`) stateObj._stateDisplay ||
|| localize(`component.${domain}.state.${stateObj.state}`) localize(`state.default.${stateObj.state}`) ||
|| stateObj.state; localize(`component.${domain}.state.${stateObj.state}`) ||
stateObj.state;
} }
return stateObj._stateDisplay; return stateObj._stateDisplay;

View File

@@ -1,4 +1,4 @@
import computeDomain from './compute_domain.js'; import computeDomain from "./compute_domain.js";
export default function computeStateDomain(stateObj) { export default function computeStateDomain(stateObj) {
return computeDomain(stateObj.entity_id); return computeDomain(stateObj.entity_id);

View File

@@ -1,10 +1,10 @@
import computeObjectId from './compute_object_id'; import computeObjectId from "./compute_object_id";
export default function computeStateName(stateObj) { export default function computeStateName(stateObj) {
if (stateObj._entityDisplay === undefined) { if (stateObj._entityDisplay === undefined) {
stateObj._entityDisplay = ( stateObj._entityDisplay =
stateObj.attributes.friendly_name stateObj.attributes.friendly_name ||
|| computeObjectId(stateObj.entity_id).replace(/_/g, ' ')); computeObjectId(stateObj.entity_id).replace(/_/g, " ");
} }
return stateObj._entityDisplay; return stateObj._entityDisplay;

View File

@@ -1,12 +1,12 @@
/** Return an icon representing a cover state. */ /** Return an icon representing a cover state. */
import domainIcon from './domain_icon.js'; import domainIcon from "./domain_icon.js";
export default function coverIcon(state) { export default function coverIcon(state) {
var open = state.state && state.state !== 'closed'; var open = state.state && state.state !== "closed";
switch (state.attributes.device_class) { switch (state.attributes.device_class) {
case 'garage': case "garage":
return open ? 'hass:garage-open' : 'hass:garage'; return open ? "hass:garage-open" : "hass:garage";
default: default:
return domainIcon('cover', state.state); return domainIcon("cover", state.state);
} }
} }

Some files were not shown because too many files have changed in this diff Show More