diff --git a/hassio/src/addon-view/hassio-addon-network.js b/hassio/src/addon-view/hassio-addon-network.js index b516c5e576..3c5b768188 100644 --- a/hassio/src/addon-view/hassio-addon-network.js +++ b/hassio/src/addon-view/hassio-addon-network.js @@ -44,6 +44,7 @@ class HassioAddonNetwork extends EventsMixin(PolymerElement) { [[item.container]] diff --git a/hassio/src/hassio-main.ts b/hassio/src/hassio-main.ts index cc4123630c..fb0766c77e 100644 --- a/hassio/src/hassio-main.ts +++ b/hassio/src/hassio-main.ts @@ -17,6 +17,9 @@ import { HassioSupervisorInfo, HassioHostInfo, HassioHomeAssistantInfo, + fetchHassioAddonInfo, + createHassioSession, + HassioPanelInfo, } from "../../src/data/hassio"; import { makeDialogManager } from "../../src/dialogs/make-dialog-manager"; import { ProvideHassLitMixin } from "../../src/mixins/provide-hass-lit-mixin"; @@ -32,6 +35,7 @@ customElements.get("paper-icon-button").prototype._keyBindings = {}; @customElement("hassio-main") class HassioMain extends ProvideHassLitMixin(HassRouterPage) { @property() public hass!: HomeAssistant; + @property() public panel!: HassioPanelInfo; protected routerOptions: RouterOptions = { // Hass.io has a page with tabs, so we route all non-matching routes to it. @@ -117,6 +121,11 @@ class HassioMain extends ProvideHassLitMixin(HassRouterPage) { } private async _fetchData() { + if (this.panel.config && this.panel.config.ingress) { + await this._redirectIngress(this.panel.config.ingress); + return; + } + const [supervisorInfo, hostInfo, hassInfo] = await Promise.all([ fetchHassioSupervisorInfo(this.hass), fetchHassioHostInfo(this.hass), @@ -127,6 +136,28 @@ class HassioMain extends ProvideHassLitMixin(HassRouterPage) { this._hassInfo = hassInfo; } + private async _redirectIngress(addonSlug: string) { + try { + const [addon] = await Promise.all([ + fetchHassioAddonInfo(this.hass, addonSlug).catch(() => { + throw new Error("Failed to fetch add-on info"); + }), + createHassioSession(this.hass).catch(() => { + throw new Error("Failed to create an ingress session"); + }), + ]); + if (!addon.ingress_url) { + throw new Error("Add-on does not support Ingress"); + } + location.assign(addon.ingress_url); + // await a promise that doesn't resolve, so we show the loading screen + // while we load the next page. + await new Promise(() => undefined); + } catch (err) { + alert(`Unable to open ingress connection `); + } + } + private _apiCalled(ev) { if (!ev.detail.success) { return; diff --git a/src/components/ha-sidebar.ts b/src/components/ha-sidebar.ts index 98d0a5e097..50428786ad 100644 --- a/src/components/ha-sidebar.ts +++ b/src/components/ha-sidebar.ts @@ -15,7 +15,7 @@ import "./ha-icon"; import "../components/user/ha-user-badge"; import isComponentLoaded from "../common/config/is_component_loaded"; -import { HomeAssistant, Panel } from "../types"; +import { HomeAssistant, PanelInfo } from "../types"; import { fireEvent } from "../common/dom/fire_event"; import { DEFAULT_PANEL } from "../common/const"; @@ -32,7 +32,9 @@ const computePanels = (hass: HomeAssistant) => { logbook: 2, history: 3, }; - const result: Panel[] = Object.values(panels).filter((panel) => panel.title); + const result: PanelInfo[] = Object.values(panels).filter( + (panel) => panel.title + ); result.sort((a, b) => { const aBuiltIn = a.component_name in sortValue; diff --git a/src/data/hassio.ts b/src/data/hassio.ts index ab3b840df3..5790a90e40 100644 --- a/src/data/hassio.ts +++ b/src/data/hassio.ts @@ -1,4 +1,11 @@ -import { HomeAssistant } from "../types"; +import { HomeAssistant, PanelInfo } from "../types"; + +export type HassioPanelInfo = PanelInfo< + | undefined + | { + ingress?: string; + } +>; interface HassioResponse { data: T; diff --git a/src/data/panel_custom.ts b/src/data/panel_custom.ts index 7f8ad4a29e..ce09a24408 100644 --- a/src/data/panel_custom.ts +++ b/src/data/panel_custom.ts @@ -1,3 +1,5 @@ +import { PanelInfo } from "../types"; + export interface CustomPanelConfig { name: string; embed_iframe: boolean; @@ -6,3 +8,7 @@ export interface CustomPanelConfig { module_url?: string; html_url?: string; } + +export type CustomPanelInfo = PanelInfo< + T & { _panel_custom: CustomPanelConfig } +>; diff --git a/src/entrypoints/custom-panel.ts b/src/entrypoints/custom-panel.ts index 7f0bc53dd0..46e3eb2527 100644 --- a/src/entrypoints/custom-panel.ts +++ b/src/entrypoints/custom-panel.ts @@ -4,8 +4,7 @@ import { createCustomPanelElement } from "../util/custom-panel/create-custom-pan import { setCustomPanelProperties } from "../util/custom-panel/set-custom-panel-properties"; import { fireEvent } from "../common/dom/fire_event"; import { PolymerElement } from "@polymer/polymer"; -import { Panel } from "../types"; -import { CustomPanelConfig } from "../data/panel_custom"; +import { CustomPanelInfo } from "../data/panel_custom"; declare global { interface Window { @@ -39,12 +38,12 @@ function setProperties(properties) { setCustomPanelProperties(panelEl, properties); } -function initialize(panel: Panel, properties: {}) { +function initialize(panel: CustomPanelInfo, properties: {}) { const style = document.createElement("style"); style.innerHTML = "body{margin:0}"; document.head.appendChild(style); - const config = panel.config!._panel_custom as CustomPanelConfig; + const config = panel.config._panel_custom; let start: Promise = Promise.resolve(); if (!webComponentsSupported) { diff --git a/src/panels/custom/ha-panel-custom.ts b/src/panels/custom/ha-panel-custom.ts index b7de1b6b30..563ccb6a18 100644 --- a/src/panels/custom/ha-panel-custom.ts +++ b/src/panels/custom/ha-panel-custom.ts @@ -2,8 +2,8 @@ import { property, PropertyValues, UpdatingElement } from "lit-element"; import { loadCustomPanel } from "../../util/custom-panel/load-custom-panel"; import { createCustomPanelElement } from "../../util/custom-panel/create-custom-panel-element"; import { setCustomPanelProperties } from "../../util/custom-panel/set-custom-panel-properties"; -import { HomeAssistant, Route, Panel } from "../../types"; -import { CustomPanelConfig } from "../../data/panel_custom"; +import { HomeAssistant, Route } from "../../types"; +import { CustomPanelInfo } from "../../data/panel_custom"; import { navigate } from "../../common/navigate"; declare global { @@ -16,7 +16,7 @@ export class HaPanelCustom extends UpdatingElement { @property() public hass!: HomeAssistant; @property() public narrow!: boolean; @property() public route!: Route; - @property() public panel!: Panel; + @property() public panel!: CustomPanelInfo; private _setProperties?: (props: {}) => void | undefined; // Since navigate fires events on `window`, we need to expose this as a function @@ -66,8 +66,8 @@ export class HaPanelCustom extends UpdatingElement { } } - private _createPanel(panel: Panel) { - const config = panel.config!._panel_custom as CustomPanelConfig; + private _createPanel(panel: CustomPanelInfo) { + const config = panel.config!._panel_custom; const tempA = document.createElement("a"); tempA.href = config.html_url || config.js_url || config.module_url || ""; diff --git a/src/types.ts b/src/types.ts index 33665a4594..d5ffd71605 100644 --- a/src/types.ts +++ b/src/types.ts @@ -78,16 +78,16 @@ export interface Themes { themes: { [key: string]: Theme }; } -export interface Panel { +export interface PanelInfo { component_name: string; - config: { [key: string]: any } | null; + config: T; icon: string | null; title: string | null; url_path: string; } export interface Panels { - [name: string]: Panel; + [name: string]: PanelInfo; } export interface Translation { @@ -212,14 +212,6 @@ export type CameraEntity = HassEntityBase & { }; }; -export interface PanelInfo { - component_name: string; - icon?: string; - title?: string; - url_path: string; - config: T; -} - export interface Route { prefix: string; path: string; @@ -229,7 +221,7 @@ export interface PanelElement extends HTMLElement { hass?: HomeAssistant; narrow?: boolean; route?: Route | null; - panel?: Panel; + panel?: PanelInfo; } export interface LocalizeMixin {