diff --git a/demo/src/ha-demo.ts b/demo/src/ha-demo.ts index 0066940028..d80eae6fad 100644 --- a/demo/src/ha-demo.ts +++ b/demo/src/ha-demo.ts @@ -1,4 +1,4 @@ -import { HomeAssistantAppEl } from "../../src/layouts/app/home-assistant"; +import { HomeAssistantAppEl } from "../../src/layouts/home-assistant"; import { provideHass, MockHomeAssistant, @@ -18,7 +18,7 @@ import { HomeAssistant } from "../../src/types"; import { mockFrontend } from "./stubs/frontend"; class HaDemo extends HomeAssistantAppEl { - protected async _handleConnProm() { + protected async _initialize() { const initial: Partial = { panelUrl: (this as any).panelUrl, // Override updateHass so that the correct hass lifecycle methods are called diff --git a/src/components/entity/ha-entity-toggle.ts b/src/components/entity/ha-entity-toggle.ts index 2818cb5ac0..d6b1aea809 100644 --- a/src/components/entity/ha-entity-toggle.ts +++ b/src/components/entity/ha-entity-toggle.ts @@ -14,7 +14,7 @@ import { } from "lit-element"; import { HomeAssistant } from "../../types"; import { HassEntity } from "home-assistant-js-websocket"; -import { forwardHaptic } from "../../util/haptics"; +import { forwardHaptic } from "../../data/haptics"; const isOn = (stateObj?: HassEntity) => stateObj !== undefined && !STATES_OFF.includes(stateObj.state); @@ -90,7 +90,7 @@ class HaEntityToggle extends LitElement { if (!this.hass || !this.stateObj) { return; } - forwardHaptic(this, "light"); + forwardHaptic("light"); const stateDomain = computeStateDomain(this.stateObj); let serviceDomain; let service; diff --git a/src/data/connection-status.ts b/src/data/connection-status.ts new file mode 100644 index 0000000000..c801ad4208 --- /dev/null +++ b/src/data/connection-status.ts @@ -0,0 +1,22 @@ +/** + * Broadcast connection status updates + */ + +import { fireEvent, HASSDomEvent } from "../common/dom/fire_event"; + +export type ConnectionStatus = "connected" | "auth-invalid" | "disconnected"; + +declare global { + // for fire event + interface HASSDomEvents { + "connection-status": ConnectionStatus; + } + + interface GlobalEventHandlersEventMap { + "connection-status": HASSDomEvent; + } +} + +export const broadcastConnectionStatus = (status: ConnectionStatus) => { + fireEvent(window, "connection-status", status); +}; diff --git a/src/util/haptics.ts b/src/data/haptics.ts similarity index 79% rename from src/util/haptics.ts rename to src/data/haptics.ts index 2cd6cf000c..d492fb5b3a 100644 --- a/src/util/haptics.ts +++ b/src/data/haptics.ts @@ -1,5 +1,5 @@ /** - * Utility function that enables haptic feedback + * Broadcast haptic feedback requests */ import { fireEvent, HASSDomEvent } from "../common/dom/fire_event"; @@ -27,6 +27,6 @@ declare global { } } -export const forwardHaptic = (el: HTMLElement, hapticType: HapticType) => { - fireEvent(el, "haptic", hapticType); +export const forwardHaptic = (hapticType: HapticType) => { + fireEvent(window, "haptic", hapticType); }; diff --git a/src/entrypoints/app.ts b/src/entrypoints/app.ts index b53f611074..c73fc24187 100644 --- a/src/entrypoints/app.ts +++ b/src/entrypoints/app.ts @@ -11,7 +11,7 @@ import "../resources/roboto"; // properly into iron-meta, which is used to transfer iconsets to iron-icon. import "../components/ha-iconset-svg"; -import "../layouts/app/home-assistant"; +import "../layouts/home-assistant"; setPassiveTouchGestures(true); /* LastPass createElement workaround. See #428 */ diff --git a/src/external_app/external_events_forwarder.ts b/src/external_app/external_events_forwarder.ts index 9f146cfebc..4ac2258105 100644 --- a/src/external_app/external_events_forwarder.ts +++ b/src/external_app/external_events_forwarder.ts @@ -1,7 +1,7 @@ import { ExternalMessaging } from "./external_messaging"; export const externalForwardConnectionEvents = (bus: ExternalMessaging) => { - document.addEventListener("connection-status", (ev) => + window.addEventListener("connection-status", (ev) => bus.fireMessage({ type: "connection-status", payload: { event: ev.detail }, @@ -10,6 +10,6 @@ export const externalForwardConnectionEvents = (bus: ExternalMessaging) => { }; export const externalForwardHaptics = (bus: ExternalMessaging) => - document.addEventListener("haptic", (ev) => + window.addEventListener("haptic", (ev) => bus.fireMessage({ type: "haptic", payload: { hapticType: ev.detail } }) ); diff --git a/src/layouts/app/connection-mixin.js b/src/layouts/app/connection-mixin.js deleted file mode 100644 index a3f5fbe993..0000000000 --- a/src/layouts/app/connection-mixin.js +++ /dev/null @@ -1,161 +0,0 @@ -import { - ERR_INVALID_AUTH, - subscribeEntities, - subscribeConfig, - subscribeServices, - callService, -} from "home-assistant-js-websocket"; - -import { translationMetadata } from "../../resources/translations-metadata"; - -import LocalizeMixin from "../../mixins/localize-mixin"; -import EventsMixin from "../../mixins/events-mixin"; - -import { getState } from "../../util/ha-pref-storage"; -import { getLocalLanguage } from "../../util/hass-translation"; -import { fetchWithAuth } from "../../util/fetch-with-auth"; -import hassCallApi from "../../util/hass-call-api"; -import { subscribePanels } from "../../data/ws-panels"; -import { forwardHaptic } from "../../util/haptics"; -import { fireEvent } from "../../common/dom/fire_event"; - -export default (superClass) => - class extends EventsMixin(LocalizeMixin(superClass)) { - firstUpdated(changedProps) { - super.firstUpdated(changedProps); - this._handleConnProm(); - } - - async _handleConnProm() { - let auth; - let conn; - try { - const result = await window.hassConnection; - auth = result.auth; - conn = result.conn; - } catch (err) { - this._error = true; - return; - } - - this.hass = Object.assign( - { - auth, - connection: conn, - connected: true, - states: null, - config: null, - themes: null, - panels: null, - services: null, - user: null, - panelUrl: this._panelUrl, - - language: getLocalLanguage(), - // If resources are already loaded, don't discard them - resources: (this.hass && this.hass.resources) || null, - localize: () => "", - - translationMetadata: translationMetadata, - dockedSidebar: false, - moreInfoEntityId: null, - callService: async (domain, service, serviceData = {}) => { - if (__DEV__) { - // eslint-disable-next-line - console.log("Calling service", domain, service, serviceData); - } - try { - await callService(conn, domain, service, serviceData); - } catch (err) { - if (__DEV__) { - // eslint-disable-next-line - console.error( - "Error calling service", - domain, - service, - serviceData, - err - ); - } - forwardHaptic(this, "error"); - const message = - this.hass.localize( - "ui.notification_toast.service_call_failed", - "service", - `${domain}/${service}` - ) + ` ${err.message}`; - this.fire("hass-notification", { message }); - throw err; - } - }, - callApi: async (method, path, parameters) => - hassCallApi(auth, method, path, parameters), - fetchWithAuth: (path, init) => - fetchWithAuth(auth, `${auth.data.hassUrl}${path}`, init), - // For messages that do not get a response - sendWS: (msg) => { - if (__DEV__) { - // eslint-disable-next-line - console.log("Sending", msg); - } - conn.sendMessage(msg); - }, - // For messages that expect a response - callWS: (msg) => { - if (__DEV__) { - /* eslint-disable no-console */ - console.log("Sending", msg); - } - - const resp = conn.sendMessagePromise(msg); - - if (__DEV__) { - resp.then( - (result) => console.log("Received", result), - (err) => console.error("Error", err) - ); - } - return resp; - }, - }, - getState() - ); - - this.hassConnected(); - } - - hassConnected() { - super.hassConnected(); - - const conn = this.hass.connection; - - fireEvent(document, "connection-status", "connected"); - - conn.addEventListener("ready", () => this.hassReconnected()); - conn.addEventListener("disconnected", () => this.hassDisconnected()); - // If we reconnect after losing connection and auth is no longer valid. - conn.addEventListener("reconnect-error", (_conn, err) => { - if (err === ERR_INVALID_AUTH) { - fireEvent(document, "connection-status", "auth-invalid"); - location.reload(); - } - }); - - subscribeEntities(conn, (states) => this._updateHass({ states })); - subscribeConfig(conn, (config) => this._updateHass({ config })); - subscribeServices(conn, (services) => this._updateHass({ services })); - subscribePanels(conn, (panels) => this._updateHass({ panels })); - } - - hassReconnected() { - super.hassReconnected(); - this._updateHass({ connected: true }); - fireEvent(document, "connection-status", "connected"); - } - - hassDisconnected() { - super.hassDisconnected(); - this._updateHass({ connected: false }); - fireEvent(document, "connection-status", "disconnected"); - } - }; diff --git a/src/layouts/app/home-assistant.ts b/src/layouts/home-assistant.ts similarity index 64% rename from src/layouts/app/home-assistant.ts rename to src/layouts/home-assistant.ts index fe7307f8d9..894a90f107 100644 --- a/src/layouts/app/home-assistant.ts +++ b/src/layouts/home-assistant.ts @@ -1,45 +1,20 @@ import "@polymer/app-route/app-location"; import { html, LitElement, PropertyValues, css, property } from "lit-element"; -import "../home-assistant-main"; -import "../ha-init-page"; -import "../../resources/ha-style"; -import { registerServiceWorker } from "../../util/register-service-worker"; -import { DEFAULT_PANEL } from "../../common/const"; +import "./home-assistant-main"; +import "./ha-init-page"; +import "../resources/ha-style"; +import { registerServiceWorker } from "../util/register-service-worker"; +import { DEFAULT_PANEL } from "../common/const"; -import HassBaseMixin from "./hass-base-mixin"; -import AuthMixin from "./auth-mixin"; -import TranslationsMixin from "./translations-mixin"; -import ThemesMixin from "./themes-mixin"; -import MoreInfoMixin from "./more-info-mixin"; -import SidebarMixin from "./sidebar-mixin"; -import { dialogManagerMixin } from "./dialog-manager-mixin"; -import ConnectionMixin from "./connection-mixin"; -import NotificationMixin from "./notification-mixin"; -import DisconnectToastMixin from "./disconnect-toast-mixin"; -import { urlSyncMixin } from "./url-sync-mixin"; - -import { Route, HomeAssistant } from "../../types"; -import { navigate } from "../../common/navigate"; +import { Route, HomeAssistant } from "../types"; +import { navigate } from "../common/navigate"; +import { HassElement } from "../state/hass-element"; (LitElement.prototype as any).html = html; (LitElement.prototype as any).css = css; -const ext = (baseClass: T, mixins): T => - mixins.reduceRight((base, mixin) => mixin(base), baseClass); - -export class HomeAssistantAppEl extends ext(HassBaseMixin(LitElement), [ - AuthMixin, - ThemesMixin, - TranslationsMixin, - MoreInfoMixin, - SidebarMixin, - DisconnectToastMixin, - ConnectionMixin, - NotificationMixin, - dialogManagerMixin, - urlSyncMixin, -]) { +export class HomeAssistantAppEl extends HassElement { @property() private _route?: Route; @property() private _error?: boolean; @property() private _panelUrl?: string; @@ -69,6 +44,7 @@ export class HomeAssistantAppEl extends ext(HassBaseMixin(LitElement), [ protected firstUpdated(changedProps) { super.firstUpdated(changedProps); + this._initialize(); setTimeout(registerServiceWorker, 1000); /* polyfill for paper-dropdown */ import(/* webpackChunkName: "polyfill-web-animations-next" */ "web-animations-js/web-animations-next-lite.min"); @@ -86,6 +62,16 @@ export class HomeAssistantAppEl extends ext(HassBaseMixin(LitElement), [ } } + protected async _initialize() { + try { + const { auth, conn } = await window.hassConnection; + this.initializeHass(auth, conn); + } catch (err) { + this._error = true; + return; + } + } + private _routeChanged(ev) { const route = ev.detail.value as Route; // If it's the first route that we process, diff --git a/src/panels/lovelace/components/hui-entities-toggle.ts b/src/panels/lovelace/components/hui-entities-toggle.ts index 88927f1535..b135cd854e 100644 --- a/src/panels/lovelace/components/hui-entities-toggle.ts +++ b/src/panels/lovelace/components/hui-entities-toggle.ts @@ -13,7 +13,7 @@ import { PaperToggleButtonElement } from "@polymer/paper-toggle-button/paper-tog import { DOMAINS_TOGGLE } from "../../../common/const"; import { turnOnOffEntities } from "../common/entity/turn-on-off-entities"; import { HomeAssistant } from "../../../types"; -import { forwardHaptic } from "../../../util/haptics"; +import { forwardHaptic } from "../../../data/haptics"; @customElement("hui-entities-toggle") class HuiEntitiesToggle extends LitElement { @@ -66,7 +66,7 @@ class HuiEntitiesToggle extends LitElement { } private _callService(ev: MouseEvent): void { - forwardHaptic(this, "light"); + forwardHaptic("light"); const turnOn = (ev.target as PaperToggleButtonElement).checked; turnOnOffEntities(this.hass!, this._toggleEntities!, turnOn!); } diff --git a/src/panels/lovelace/entity-rows/hui-input-select-entity-row.ts b/src/panels/lovelace/entity-rows/hui-input-select-entity-row.ts index 3568196454..ef4ac3f22c 100644 --- a/src/panels/lovelace/entity-rows/hui-input-select-entity-row.ts +++ b/src/panels/lovelace/entity-rows/hui-input-select-entity-row.ts @@ -21,7 +21,7 @@ import { HomeAssistant, InputSelectEntity } from "../../../types"; import { EntityRow, EntityConfig } from "./types"; import { setInputSelectOption } from "../../../data/input-select"; import { hasConfigOrEntityChanged } from "../common/has-changed"; -import { forwardHaptic } from "../../../util/haptics"; +import { forwardHaptic } from "../../../data/haptics"; import { stopPropagation } from "../../../common/dom/stop_propagation"; @customElement("hui-input-select-entity-row") @@ -128,7 +128,7 @@ class HuiInputSelectEntityRow extends LitElement implements EntityRow { return; } - forwardHaptic(this, "light"); + forwardHaptic("light"); setInputSelectOption( this.hass!, diff --git a/src/resources/translations-metadata.ts b/src/resources/translations-metadata.ts index 31cb0c157f..0957a46cbc 100644 --- a/src/resources/translations-metadata.ts +++ b/src/resources/translations-metadata.ts @@ -1,16 +1,5 @@ import * as translationMetadata_ from "../../build-translations/translationMetadata.json"; - -interface TranslationMetadata { - fragments: string[]; - translations: { - [language: string]: { - nativeName: string; - fingerprints: { - [filename: string]: string; - }; - }; - }; -} +import { TranslationMetadata } from "../types.js"; export const translationMetadata = (translationMetadata_ as any) .default as TranslationMetadata; diff --git a/src/layouts/app/auth-mixin.ts b/src/state/auth-mixin.ts similarity index 86% rename from src/layouts/app/auth-mixin.ts rename to src/state/auth-mixin.ts index 2fa5d3bf1f..c97730ac3f 100644 --- a/src/layouts/app/auth-mixin.ts +++ b/src/state/auth-mixin.ts @@ -1,6 +1,6 @@ -import { clearState } from "../../util/ha-pref-storage"; -import { askWrite } from "../../common/auth/token_storage"; -import { subscribeUser, userCollection } from "../../data/ws-user"; +import { clearState } from "../util/ha-pref-storage"; +import { askWrite } from "../common/auth/token_storage"; +import { subscribeUser, userCollection } from "../data/ws-user"; import { Constructor, LitElement } from "lit-element"; import { HassBaseEl } from "./hass-base-mixin"; @@ -30,7 +30,7 @@ export default (superClass: Constructor) => if (askWrite()) { this.updateComplete .then(() => - import(/* webpackChunkName: "ha-store-auth-card" */ "../../dialogs/ha-store-auth-card") + import(/* webpackChunkName: "ha-store-auth-card" */ "../dialogs/ha-store-auth-card") ) .then(() => { const el = document.createElement("ha-store-auth-card"); diff --git a/src/state/connection-mixin.ts b/src/state/connection-mixin.ts new file mode 100644 index 0000000000..ee34177bde --- /dev/null +++ b/src/state/connection-mixin.ts @@ -0,0 +1,149 @@ +import { + ERR_INVALID_AUTH, + subscribeEntities, + subscribeConfig, + subscribeServices, + callService, + Auth, + Connection, +} from "home-assistant-js-websocket"; + +import { translationMetadata } from "../resources/translations-metadata"; + +import { getState } from "../util/ha-pref-storage"; +import { getLocalLanguage } from "../util/hass-translation"; +import { fetchWithAuth } from "../util/fetch-with-auth"; +import hassCallApi from "../util/hass-call-api"; +import { subscribePanels } from "../data/ws-panels"; +import { forwardHaptic } from "../data/haptics"; +import { fireEvent } from "../common/dom/fire_event"; +import { Constructor, LitElement } from "lit-element"; +import { HassBaseEl } from "./hass-base-mixin"; +import { broadcastConnectionStatus } from "../data/connection-status"; + +export const connectionMixin = ( + superClass: Constructor +) => + class extends superClass { + protected initializeHass(auth: Auth, conn: Connection) { + this.hass = { + auth, + connection: conn, + connected: true, + states: null as any, + config: null as any, + themes: null as any, + panels: null as any, + services: null as any, + user: null as any, + panelUrl: (this as any)._panelUrl, + + language: getLocalLanguage(), + selectedLanguage: null, + resources: null as any, + localize: () => "", + + translationMetadata, + dockedSidebar: false, + moreInfoEntityId: null, + callService: async (domain, service, serviceData = {}) => { + if (__DEV__) { + // tslint:disable-next-line: no-console + console.log("Calling service", domain, service, serviceData); + } + try { + await callService(conn, domain, service, serviceData); + } catch (err) { + if (__DEV__) { + // tslint:disable-next-line: no-console + console.error( + "Error calling service", + domain, + service, + serviceData, + err + ); + } + forwardHaptic("failure"); + const message = + (this as any).hass.localize( + "ui.notification_toast.service_call_failed", + "service", + `${domain}/${service}` + ) + ` ${err.message}`; + fireEvent(this as any, "hass-notification", { message }); + throw err; + } + }, + callApi: async (method, path, parameters) => + hassCallApi(auth, method, path, parameters), + fetchWithAuth: (path, init) => + fetchWithAuth(auth, `${auth.data.hassUrl}${path}`, init), + // For messages that do not get a response + sendWS: (msg) => { + if (__DEV__) { + // tslint:disable-next-line: no-console + console.log("Sending", msg); + } + conn.sendMessage(msg); + }, + // For messages that expect a response + callWS: (msg) => { + if (__DEV__) { + // tslint:disable-next-line: no-console + console.log("Sending", msg); + } + + const resp = conn.sendMessagePromise(msg); + + if (__DEV__) { + resp.then( + // tslint:disable-next-line: no-console + (result) => console.log("Received", result), + // tslint:disable-next-line: no-console + (err) => console.error("Error", err) + ); + } + return resp; + }, + ...getState(), + }; + + this.hassConnected(); + } + + protected hassConnected() { + super.hassConnected(); + + const conn = this.hass!.connection; + + broadcastConnectionStatus("connected"); + + conn.addEventListener("ready", () => this.hassReconnected()); + conn.addEventListener("disconnected", () => this.hassDisconnected()); + // If we reconnect after losing connection and auth is no longer valid. + conn.addEventListener("reconnect-error", (_conn, err) => { + if (err === ERR_INVALID_AUTH) { + broadcastConnectionStatus("auth-invalid"); + location.reload(); + } + }); + + subscribeEntities(conn, (states) => this._updateHass({ states })); + subscribeConfig(conn, (config) => this._updateHass({ config })); + subscribeServices(conn, (services) => this._updateHass({ services })); + subscribePanels(conn, (panels) => this._updateHass({ panels })); + } + + protected hassReconnected() { + super.hassReconnected(); + this._updateHass({ connected: true }); + broadcastConnectionStatus("connected"); + } + + protected hassDisconnected() { + super.hassDisconnected(); + this._updateHass({ connected: false }); + broadcastConnectionStatus("disconnected"); + } + }; diff --git a/src/layouts/app/dialog-manager-mixin.ts b/src/state/dialog-manager-mixin.ts similarity index 89% rename from src/layouts/app/dialog-manager-mixin.ts rename to src/state/dialog-manager-mixin.ts index b260703d89..5fcae876a3 100644 --- a/src/layouts/app/dialog-manager-mixin.ts +++ b/src/state/dialog-manager-mixin.ts @@ -1,10 +1,7 @@ import { Constructor, LitElement } from "lit-element"; -import { HASSDomEvent } from "../../common/dom/fire_event"; +import { HASSDomEvent } from "../common/dom/fire_event"; import { HassBaseEl } from "./hass-base-mixin"; -import { - makeDialogManager, - showDialog, -} from "../../dialogs/make-dialog-manager"; +import { makeDialogManager, showDialog } from "../dialogs/make-dialog-manager"; interface RegisterDialogParams { dialogShowEvent: keyof HASSDomEvents; diff --git a/src/layouts/app/disconnect-toast-mixin.ts b/src/state/disconnect-toast-mixin.ts similarity index 84% rename from src/layouts/app/disconnect-toast-mixin.ts rename to src/state/disconnect-toast-mixin.ts index 2905ed40f6..853fa3f392 100644 --- a/src/layouts/app/disconnect-toast-mixin.ts +++ b/src/state/disconnect-toast-mixin.ts @@ -1,7 +1,7 @@ import { Constructor, LitElement } from "lit-element"; import { HassBaseEl } from "./hass-base-mixin"; -import { HaToast } from "../../components/ha-toast"; -import { computeRTL } from "../../common/util/compute_rtl"; +import { HaToast } from "../components/ha-toast"; +import { computeRTL } from "../common/util/compute_rtl"; export default (superClass: Constructor) => class extends superClass { @@ -10,7 +10,7 @@ export default (superClass: Constructor) => protected firstUpdated(changedProps) { super.firstUpdated(changedProps); // Need to load in advance because when disconnected, can't dynamically load code. - import(/* webpackChunkName: "ha-toast" */ "../../components/ha-toast"); + import(/* webpackChunkName: "ha-toast" */ "../components/ha-toast"); } protected hassReconnected() { diff --git a/src/layouts/app/hass-base-mixin.ts b/src/state/hass-base-mixin.ts similarity index 89% rename from src/layouts/app/hass-base-mixin.ts rename to src/state/hass-base-mixin.ts index 9ef1d7034d..8810d60403 100644 --- a/src/layouts/app/hass-base-mixin.ts +++ b/src/state/hass-base-mixin.ts @@ -3,12 +3,14 @@ import { // @ts-ignore property, } from "lit-element"; -import { HomeAssistant } from "../../types"; +import { Auth, Connection } from "home-assistant-js-websocket"; +import { HomeAssistant } from "../types"; /* tslint:disable */ export class HassBaseEl { protected hass?: HomeAssistant; + protected initializeHass(_auth: Auth, _conn: Connection) {} protected hassConnected() {} protected hassReconnected() {} protected hassDisconnected() {} diff --git a/src/state/hass-element.ts b/src/state/hass-element.ts new file mode 100644 index 0000000000..c837aafecf --- /dev/null +++ b/src/state/hass-element.ts @@ -0,0 +1,28 @@ +import HassBaseMixin from "./hass-base-mixin"; +import AuthMixin from "./auth-mixin"; +import TranslationsMixin from "./translations-mixin"; +import ThemesMixin from "./themes-mixin"; +import MoreInfoMixin from "./more-info-mixin"; +import SidebarMixin from "./sidebar-mixin"; +import { dialogManagerMixin } from "./dialog-manager-mixin"; +import { connectionMixin } from "./connection-mixin"; +import NotificationMixin from "./notification-mixin"; +import DisconnectToastMixin from "./disconnect-toast-mixin"; +import { urlSyncMixin } from "./url-sync-mixin"; +import { LitElement } from "lit-element"; + +const ext = (baseClass: T, mixins): T => + mixins.reduceRight((base, mixin) => mixin(base), baseClass); + +export class HassElement extends ext(HassBaseMixin(LitElement), [ + AuthMixin, + ThemesMixin, + TranslationsMixin, + MoreInfoMixin, + SidebarMixin, + DisconnectToastMixin, + connectionMixin, + NotificationMixin, + dialogManagerMixin, + urlSyncMixin, +]) {} diff --git a/src/layouts/app/more-info-mixin.ts b/src/state/more-info-mixin.ts similarity index 90% rename from src/layouts/app/more-info-mixin.ts rename to src/state/more-info-mixin.ts index 66c442cf90..9cd8a12939 100644 --- a/src/layouts/app/more-info-mixin.ts +++ b/src/state/more-info-mixin.ts @@ -20,7 +20,7 @@ export default (superClass: Constructor) => this.addEventListener("hass-more-info", (e) => this._handleMoreInfo(e)); // Load it once we are having the initial rendering done. - import(/* webpackChunkName: "more-info-dialog" */ "../../dialogs/ha-more-info-dialog"); + import(/* webpackChunkName: "more-info-dialog" */ "../dialogs/ha-more-info-dialog"); } private async _handleMoreInfo(ev) { diff --git a/src/layouts/app/notification-mixin.js b/src/state/notification-mixin.js similarity index 90% rename from src/layouts/app/notification-mixin.js rename to src/state/notification-mixin.js index 43cf2461c3..bf722741d2 100644 --- a/src/layouts/app/notification-mixin.js +++ b/src/state/notification-mixin.js @@ -6,7 +6,7 @@ export default (superClass) => dialogShowEvent: "hass-notification", dialogTag: "notification-manager", dialogImport: () => - import(/* webpackChunkName: "notification-manager" */ "../../managers/notification-manager"), + import(/* webpackChunkName: "notification-manager" */ "../managers/notification-manager"), }); } }; diff --git a/src/layouts/app/sidebar-mixin.ts b/src/state/sidebar-mixin.ts similarity index 86% rename from src/layouts/app/sidebar-mixin.ts rename to src/state/sidebar-mixin.ts index b38efb3792..507e22c3bf 100644 --- a/src/layouts/app/sidebar-mixin.ts +++ b/src/state/sidebar-mixin.ts @@ -1,7 +1,7 @@ -import { storeState } from "../../util/ha-pref-storage"; +import { storeState } from "../util/ha-pref-storage"; import { Constructor, LitElement } from "lit-element"; import { HassBaseEl } from "./hass-base-mixin"; -import { HASSDomEvent } from "../../common/dom/fire_event"; +import { HASSDomEvent } from "../common/dom/fire_event"; interface DockSidebarParams { dock: boolean; diff --git a/src/layouts/app/themes-mixin.ts b/src/state/themes-mixin.ts similarity index 79% rename from src/layouts/app/themes-mixin.ts rename to src/state/themes-mixin.ts index af6685ba97..b97419237e 100644 --- a/src/layouts/app/themes-mixin.ts +++ b/src/state/themes-mixin.ts @@ -1,9 +1,9 @@ -import applyThemesOnElement from "../../common/dom/apply_themes_on_element"; -import { storeState } from "../../util/ha-pref-storage"; -import { subscribeThemes } from "../../data/ws-themes"; +import applyThemesOnElement from "../common/dom/apply_themes_on_element"; +import { storeState } from "../util/ha-pref-storage"; +import { subscribeThemes } from "../data/ws-themes"; import { Constructor, LitElement } from "lit-element"; import { HassBaseEl } from "./hass-base-mixin"; -import { HASSDomEvent } from "../../common/dom/fire_event"; +import { HASSDomEvent } from "../common/dom/fire_event"; declare global { // for add event listener diff --git a/src/layouts/app/translations-mixin.ts b/src/state/translations-mixin.ts similarity index 88% rename from src/layouts/app/translations-mixin.ts rename to src/state/translations-mixin.ts index 5914f7c38f..8bf9f8f5ee 100644 --- a/src/layouts/app/translations-mixin.ts +++ b/src/state/translations-mixin.ts @@ -1,17 +1,17 @@ -import { translationMetadata } from "../../resources/translations-metadata"; +import { translationMetadata } from "../resources/translations-metadata"; import { getTranslation, getLocalLanguage, getUserLanguage, -} from "../../util/hass-translation"; +} from "../util/hass-translation"; import { Constructor, LitElement } from "lit-element"; import { HassBaseEl } from "./hass-base-mixin"; -import { computeLocalize } from "../../common/translations/localize"; -import { computeRTL } from "../../common/util/compute_rtl"; -import { HomeAssistant } from "../../types"; -import { saveFrontendUserData } from "../../data/frontend"; -import { storeState } from "../../util/ha-pref-storage"; -import { getHassTranslations } from "../../data/translation"; +import { computeLocalize } from "../common/translations/localize"; +import { computeRTL } from "../common/util/compute_rtl"; +import { HomeAssistant } from "../types"; +import { saveFrontendUserData } from "../data/frontend"; +import { storeState } from "../util/ha-pref-storage"; +import { getHassTranslations } from "../data/translation"; /* * superClass needs to contain `this.hass` and `this._updateHass`. diff --git a/src/layouts/app/url-sync-mixin.ts b/src/state/url-sync-mixin.ts similarity index 97% rename from src/layouts/app/url-sync-mixin.ts rename to src/state/url-sync-mixin.ts index c6817760a6..920066bd85 100644 --- a/src/layouts/app/url-sync-mixin.ts +++ b/src/state/url-sync-mixin.ts @@ -1,6 +1,6 @@ import { Constructor, LitElement } from "lit-element"; import { HassBaseEl } from "./hass-base-mixin"; -import { fireEvent } from "../../common/dom/fire_event"; +import { fireEvent } from "../common/dom/fire_event"; /* tslint:disable:no-console */ const DEBUG = false; diff --git a/src/types.ts b/src/types.ts index 9a5a731a3b..b0d4aee814 100644 --- a/src/types.ts +++ b/src/types.ts @@ -10,7 +10,6 @@ import { } from "home-assistant-js-websocket"; import { LocalizeFunc } from "./common/translations/localize"; import { ExternalMessaging } from "./external_app/external_messaging"; -import { HASSDomEvent } from "./common/dom/fire_event"; declare global { var __DEV__: boolean; @@ -38,16 +37,9 @@ declare global { value: unknown; }; change: undefined; - "connection-status": ConnectionStatus; - } - - interface GlobalEventHandlersEventMap { - "connection-status": HASSDomEvent; } } -type ConnectionStatus = "connected" | "auth-invalid" | "disconnected"; - export interface WebhookError { code: number; message: string; @@ -103,6 +95,13 @@ export interface Translation { fingerprints: { [fragment: string]: string }; } +export interface TranslationMetadata { + fragments: string[]; + translations: { + [lang: string]: Translation; + }; +} + export interface Notification { notification_id: string; message: string; @@ -135,18 +134,13 @@ export interface HomeAssistant { // - english (en) language: string; // local stored language, keep that name for backward compability - selectedLanguage: string; + selectedLanguage: string | null; resources: Resources; localize: LocalizeFunc; - translationMetadata: { - fragments: string[]; - translations: { - [lang: string]: Translation; - }; - }; + translationMetadata: TranslationMetadata; dockedSidebar: boolean; - moreInfoEntityId: string; + moreInfoEntityId: string | null; user?: CurrentUser; callService: ( domain: string, @@ -162,7 +156,7 @@ export interface HomeAssistant { path: string, init?: { [key: string]: any } ) => Promise; - sendWS: (msg: MessageBase) => Promise; + sendWS: (msg: MessageBase) => void; callWS: (msg: MessageBase) => Promise; }