diff --git a/build-scripts/gulp/demo.js b/build-scripts/gulp/demo.js index b2d40e17ae..2c8070962d 100644 --- a/build-scripts/gulp/demo.js +++ b/build-scripts/gulp/demo.js @@ -1,4 +1,4 @@ -// Run HA develop mode +// Run demo develop mode const gulp = require("gulp"); require("./clean.js"); diff --git a/build-scripts/gulp/webpack.js b/build-scripts/gulp/webpack.js index 2a21a14011..b1675ad076 100644 --- a/build-scripts/gulp/webpack.js +++ b/build-scripts/gulp/webpack.js @@ -84,12 +84,12 @@ gulp.task("webpack-dev-server-demo", () => { open: true, watchContentBase: true, contentBase: path.resolve(paths.demo_dir, "dist"), - }).listen(8080, "localhost", function(err) { + }).listen(8090, "localhost", function(err) { if (err) { throw err; } // Server listening - log("[webpack-dev-server]", "http://localhost:8080"); + log("[webpack-dev-server]", "http://localhost:8090"); }); }); diff --git a/build-scripts/webpack.js b/build-scripts/webpack.js index 031c72433d..7ee1a03714 100644 --- a/build-scripts/webpack.js +++ b/build-scripts/webpack.js @@ -96,7 +96,7 @@ const createAppConfig = ({ isProdBuild, latestBuild, isStatsBuild }) => { // Create an object mapping browser urls to their paths during build const translationMetadata = require("../build-translations/translationMetadata.json"); const workBoxTranslationsTemplatedURLs = {}; - const englishFP = translationMetadata["translations"]["en"]["fingerprints"]; + const englishFP = translationMetadata.translations.en.fingerprints; Object.keys(englishFP).forEach((key) => { workBoxTranslationsTemplatedURLs[ `/static/translations/${englishFP[key]}` @@ -192,7 +192,7 @@ const createDemoConfig = ({ isProdBuild, latestBuild, isStatsBuild }) => { new webpack.DefinePlugin({ __DEV__: !isProdBuild, __BUILD__: JSON.stringify(latestBuild ? "latest" : "es5"), - __VERSION__: JSON.stringify("DEMO"), + __VERSION__: JSON.stringify(`DEMO-${version}`), __DEMO__: true, __STATIC_PATH__: "/static/", "process.env.NODE_ENV": JSON.stringify( diff --git a/demo/src/configs/arsaboo/entities.ts b/demo/src/configs/arsaboo/entities.ts index 703b9751f0..9bbc753451 100644 --- a/demo/src/configs/arsaboo/entities.ts +++ b/demo/src/configs/arsaboo/entities.ts @@ -245,16 +245,7 @@ export const demoEntitiesArsaboo: DemoConfig["entities"] = (localize) => homebridge_cover_type: "garage_door", }, }, - "light.master_lights": { - entity_id: "light.master_lights", - state: "off", - attributes: { - min_mireds: 153, - max_mireds: 500, - friendly_name: "Master Lights", - supported_features: 63, - }, - }, + "light.living_room_lights": { entity_id: "light.living_room_lights", state: "off", @@ -280,40 +271,7 @@ export const demoEntitiesArsaboo: DemoConfig["entities"] = (localize) => supported_features: 1, }, }, - "light.hue_color_lamp_1": { - entity_id: "light.hue_color_lamp_1", - state: "on", - attributes: { - min_mireds: 153, - max_mireds: 500, - friendly_name: localize("ui.panel.page-demo.config.arsaboo.names.left"), - supported_features: 63, - }, - }, - "light.hue_color_lamp_2": { - entity_id: "light.hue_color_lamp_2", - state: "off", - attributes: { - min_mireds: 153, - max_mireds: 500, - friendly_name: localize( - "ui.panel.page-demo.config.arsaboo.names.right" - ), - supported_features: 63, - }, - }, - "light.hue_color_lamp_3": { - entity_id: "light.hue_color_lamp_3", - state: "on", - attributes: { - min_mireds: 153, - max_mireds: 500, - friendly_name: localize( - "ui.panel.page-demo.config.arsaboo.names.mirror" - ), - supported_features: 63, - }, - }, + "sensor.plexspy": { entity_id: "sensor.plexspy", state: "0", @@ -405,16 +363,6 @@ export const demoEntitiesArsaboo: DemoConfig["entities"] = (localize) => supported_features: 0, }, }, - "light.gateway_light_34ce00813670": { - entity_id: "light.gateway_light_34ce00813670", - state: "off", - attributes: { - friendly_name: localize( - "ui.panel.page-demo.config.arsaboo.names.hallway" - ), - supported_features: 17, - }, - }, "alarm_control_panel.abode_alarm": { entity_id: "alarm_control_panel.abode_alarm", state: "disarmed", @@ -472,35 +420,7 @@ export const demoEntitiesArsaboo: DemoConfig["entities"] = (localize) => device_class: "motion", }, }, - "binary_sensor.water_leak_sensor_158d0001d77800": { - entity_id: "binary_sensor.water_leak_sensor_158d0001d77800", - state: "off", - attributes: { - battery_level: 41, - friendly_name: "Laundry Water Leak", - device_class: "moisture", - }, - }, - "binary_sensor.motion_sensor_158d00016c53bf": { - entity_id: "binary_sensor.motion_sensor_158d00016c53bf", - state: "off", - attributes: { - "No motion since": 0, - battery_level: 43, - friendly_name: "Master Occupancy", - device_class: "motion", - }, - }, - "binary_sensor.motion_sensor_158d00016612af": { - entity_id: "binary_sensor.motion_sensor_158d00016612af", - state: "off", - attributes: { - "No motion since": 0, - battery_level: 41, - friendly_name: "Upstairs Occupancy", - device_class: "motion", - }, - }, + "binary_sensor.front_door": { entity_id: "binary_sensor.front_door", state: "off", @@ -587,16 +507,6 @@ export const demoEntitiesArsaboo: DemoConfig["entities"] = (localize) => icon: "hademo:history", }, }, - "light.lifxnrkitchen": { - entity_id: "light.lifxnrkitchen", - state: "off", - attributes: { - min_mireds: 111, - max_mireds: 400, - friendly_name: "LifxnrKitchen", - supported_features: 55, - }, - }, "light.lifx5": { entity_id: "light.lifx5", state: "on", @@ -607,41 +517,6 @@ export const demoEntitiesArsaboo: DemoConfig["entities"] = (localize) => supported_features: 55, }, }, - "light.lifxnrguest": { - entity_id: "light.lifxnrguest", - state: "off", - attributes: { - min_mireds: 111, - max_mireds: 400, - friendly_name: localize( - "ui.panel.page-demo.config.arsaboo.names.patio" - ), - supported_features: 55, - }, - }, - "light.lifx3": { - entity_id: "light.lifx3", - state: "off", - attributes: { - min_mireds: 111, - max_mireds: 400, - friendly_name: localize( - "ui.panel.page-demo.config.arsaboo.names.kitchen" - ), - supported_features: 55, - }, - }, - "sensor.illumination_158d00016c53bf": { - entity_id: "sensor.illumination_158d00016c53bf", - state: "10", - attributes: { - battery_level: 43, - unit_of_measurement: "lx", - friendly_name: "Master Brightness", - device_class: "illuminance", - icon: "hademo:brightness-7", - }, - }, "sensor.alok_to_home": { entity_id: "sensor.alok_to_home", state: "41", @@ -680,13 +555,6 @@ export const demoEntitiesArsaboo: DemoConfig["entities"] = (localize) => icon: "hademo:car", }, }, - "switch.wemoswitch": { - entity_id: "switch.wemoswitch", - state: "on", - attributes: { - friendly_name: localize("ui.panel.page-demo.config.arsaboo.labels.air"), - }, - }, "switch.driveway": { entity_id: "switch.driveway", state: "off", diff --git a/demo/src/configs/arsaboo/lovelace.ts b/demo/src/configs/arsaboo/lovelace.ts index 7039f4bdbb..752b665111 100644 --- a/demo/src/configs/arsaboo/lovelace.ts +++ b/demo/src/configs/arsaboo/lovelace.ts @@ -9,6 +9,27 @@ export const demoLovelaceArsaboo: DemoConfig["lovelace"] = (localize) => ({ title: "Home", cards: [ { type: "custom:ha-demo-card" }, + { + type: "entities", + title: localize("ui.panel.page-demo.config.arsaboo.labels.lights"), + entities: [ + { + entity: "light.kitchen_lights", + }, + { + entity: "light.living_room_lights", + }, + { + entity: "switch.wemoporch", + }, + "light.lifx5", + ], + }, + { + type: "thermostat", + entity: "climate.upstairs", + }, + { type: "picture-elements", image: "/assets/arsaboo/floorplans/main.png", @@ -381,104 +402,7 @@ export const demoLovelaceArsaboo: DemoConfig["lovelace"] = (localize) => ({ }, ], }, - { - type: "picture-elements", - image: "/assets/arsaboo/floorplans/second.png", - elements: [ - { - type: "state-icon", - entity: "binary_sensor.motion_sensor_158d00016612af", - style: { - top: "40%", - left: "35%", - }, - }, - // { - // type: "custom:thermostat-card", - // entity: "climate.bedroom", - // no_card: true, - // hvac: { - // attribute: "operation", - // }, - // style: { - // top: "79%", - // left: "92%", - // width: "50px", - // height: "50px", - // }, - // }, - { - type: "state-icon", - entity: "binary_sensor.motion_sensor_158d00016c53bf", - style: { - top: "55%", - left: "80%", - }, - }, - { - type: "state-label", - entity: "sensor.illumination_158d00016c53bf", - style: { - top: "78%", - left: "80%", - "text-align": "center", - "font-size": "12px", - color: "black", - }, - }, - { - type: "image", - entity: "light.master_lights", - tap_action: { - action: "toggle", - }, - hold_action: { - action: "more-info", - }, - image: "/assets/arsaboo/icons/light_bulb_off.png", - state_image: { - on: "/assets/arsaboo/icons/light_bulb_on.png", - }, - state_filter: { - on: - "brightness(130%) saturate(1.5) drop-shadow(0px 0px 10px gold)", - off: "brightness(80%) saturate(0.8)", - }, - style: { - top: "70%", - left: "80%", - width: "7%", - padding: "10px", - }, - }, - { - type: "state-icon", - entity: "binary_sensor.water_leak_sensor_158d0001d77800", - style: { - top: "25%", - left: "66%", - }, - }, - // { - // type: "custom:thermostat-card", - // entity: "climate.upstairs", - // no_card: true, - // hvac: { - // attribute: "operation", - // }, - // style: { - // top: "18%", - // left: "15%", - // width: "50px", - // height: "50px", - // }, - // }, - ], - }, - { - type: "thermostat", - entity: "climate.upstairs", - }, + { type: "media-control", entity: "media_player.family_room_2", @@ -496,44 +420,11 @@ export const demoLovelaceArsaboo: DemoConfig["lovelace"] = (localize) => ({ "sensor.usdinr", ], }, - { - type: "entities", - title: localize("ui.panel.page-demo.config.arsaboo.labels.lights"), - entities: [ - { - entity: "light.gateway_light_34ce00813670", - }, - { - entity: "light.lifx3", - }, - { - entity: "light.lifxnrguest", - }, - { - type: "section", - label: localize( - "ui.panel.page-demo.config.arsaboo.names.master_bedroom" - ), - }, - { - entity: "light.hue_color_lamp_1", - }, - { - entity: "light.hue_color_lamp_2", - }, - { - entity: "light.hue_color_lamp_3", - }, - { - entity: "switch.wemoswitch", - }, - ], - }, { type: "alarm-panel", entity: "alarm_control_panel.abode_alarm", - name: "Abode", + name: "Security", states: ["arm_home", "arm_away"], }, { @@ -554,7 +445,7 @@ export const demoLovelaceArsaboo: DemoConfig["lovelace"] = (localize) => ({ }, { type: "entities", - title: "Ring Doorbell", + title: "Doorbell", show_header_toggle: false, entities: [ "binary_sensor.ring_front_door_ding", diff --git a/demo/src/ha-demo.ts b/demo/src/ha-demo.ts index 0391b4df6d..6eb383eb22 100644 --- a/demo/src/ha-demo.ts +++ b/demo/src/ha-demo.ts @@ -16,6 +16,8 @@ import { mockEvents } from "./stubs/events"; import { mockMediaPlayer } from "./stubs/media_player"; import { HomeAssistant } from "../../src/types"; import { mockFrontend } from "./stubs/frontend"; +import { mockPersistentNotification } from "./stubs/persistent_notification"; +import { isNavigationClick } from "../../src/common/dom/is-navigation-click"; class HaDemo extends HomeAssistantAppEl { protected async _initialize() { @@ -43,6 +45,7 @@ class HaDemo extends HomeAssistantAppEl { mockEvents(hass); mockMediaPlayer(hass); mockFrontend(hass); + mockPersistentNotification(hass); // Once config is loaded AND localize, set entities and apply theme. Promise.all([selectedDemoConfig, localizePromise]).then( @@ -58,49 +61,14 @@ class HaDemo extends HomeAssistantAppEl { document.body.addEventListener( "click", (e) => { - if ( - e.defaultPrevented || - e.button !== 0 || - e.metaKey || - e.ctrlKey || - e.shiftKey - ) { - return; - } + const href = isNavigationClick(e); - const anchor = e - .composedPath() - .filter((n) => (n as HTMLElement).tagName === "A")[0] as - | HTMLAnchorElement - | undefined; - if ( - !anchor || - anchor.target || - anchor.hasAttribute("download") || - anchor.getAttribute("rel") === "external" - ) { - return; - } - - let href = anchor.href; - if (!href || href.indexOf("mailto:") !== -1) { - return; - } - - const location = window.location; - const origin = - location.origin || location.protocol + "//" + location.host; - if (href.indexOf(origin) !== 0) { - return; - } - href = href.substr(origin.length); - - if (href === "#") { + if (!href) { return; } e.preventDefault(); - navigate(this as any, href); + navigate(this, href); }, { capture: true } ); diff --git a/demo/src/stubs/persistent_notification.ts b/demo/src/stubs/persistent_notification.ts new file mode 100644 index 0000000000..2dcd4f61bd --- /dev/null +++ b/demo/src/stubs/persistent_notification.ts @@ -0,0 +1,16 @@ +import { MockHomeAssistant } from "../../../src/fake_data/provide_hass"; +import { PersistentNotification } from "../../../src/data/persistent_notification"; + +export const mockPersistentNotification = (hass: MockHomeAssistant) => { + hass.mockWS("persistent_notification/get", () => + Promise.resolve([ + { + created_at: new Date().toISOString(), + message: "There was motion detected in the backyard.", + notification_id: "demo-1", + title: "Motion Detected!", + status: "unread", + }, + ] as PersistentNotification[]) + ); +}; diff --git a/package.json b/package.json index 150504ac51..97757ab7f4 100644 --- a/package.json +++ b/package.json @@ -78,7 +78,7 @@ "fuse.js": "^3.4.4", "google-timezones-json": "^1.0.2", "hls.js": "^0.12.4", - "home-assistant-js-websocket": "^4.2.2", + "home-assistant-js-websocket": "4.3.1", "intl-messageformat": "^2.2.0", "jquery": "^3.3.1", "js-yaml": "^3.13.0", @@ -112,6 +112,8 @@ "@babel/preset-typescript": "^7.3.3", "@gfx/zopfli": "^1.0.11", "@types/chai": "^4.1.7", + "@types/chromecast-caf-receiver": "^3.0.12", + "@types/chromecast-caf-sender": "^1.0.1", "@types/hls.js": "^0.12.3", "@types/leaflet": "^1.4.3", "@types/memoize-one": "4.1.0", diff --git a/setup.py b/setup.py index af40db5999..5173765e0a 100644 --- a/setup.py +++ b/setup.py @@ -2,7 +2,7 @@ from setuptools import setup, find_packages setup( name="home-assistant-frontend", - version="20190721.1", + version="20190731.0", description="The Home Assistant frontend", url="https://github.com/home-assistant/home-assistant-polymer", author="The Home Assistant Authors", diff --git a/src/common/dom/is-navigation-click.ts b/src/common/dom/is-navigation-click.ts new file mode 100644 index 0000000000..3ab515b778 --- /dev/null +++ b/src/common/dom/is-navigation-click.ts @@ -0,0 +1,45 @@ +export const isNavigationClick = (e: MouseEvent) => { + // Taken from polymer/pwa-helpers. BSD-3 licensed + if ( + e.defaultPrevented || + e.button !== 0 || + e.metaKey || + e.ctrlKey || + e.shiftKey + ) { + return; + } + + const anchor = e + .composedPath() + .filter((n) => (n as HTMLElement).tagName === "A")[0] as + | HTMLAnchorElement + | undefined; + if ( + !anchor || + anchor.target || + anchor.hasAttribute("download") || + anchor.getAttribute("rel") === "external" + ) { + return; + } + + let href = anchor.href; + if (!href || href.indexOf("mailto:") !== -1) { + return; + } + + const location = window.location; + const origin = location.origin || location.protocol + "//" + location.host; + if (href.indexOf(origin) !== 0) { + return; + } + href = href.substr(origin.length); + + if (href === "#") { + return; + } + + e.preventDefault(); + return href; +}; diff --git a/src/components/entity/ha-entity-picker.ts b/src/components/entity/ha-entity-picker.ts index 53f0b74db2..cc6945be6d 100644 --- a/src/components/entity/ha-entity-picker.ts +++ b/src/components/entity/ha-entity-picker.ts @@ -139,6 +139,7 @@ class HaEntityPicker extends LitElement { ${this.value ? html` 0 ? html` [[_localizeState(localize, stateObj)]] -