mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-23 09:16:38 +00:00
Add my support to supervisor (#8405)
* Add my support to supervisor * Remove localize * Comments * Update ha-panel-my.ts
This commit is contained in:
parent
e8daf88729
commit
0ec58007c9
@ -9,16 +9,21 @@ import {
|
|||||||
CSSResult,
|
CSSResult,
|
||||||
customElement,
|
customElement,
|
||||||
html,
|
html,
|
||||||
|
internalProperty,
|
||||||
LitElement,
|
LitElement,
|
||||||
property,
|
property,
|
||||||
TemplateResult,
|
TemplateResult,
|
||||||
} from "lit-element";
|
} from "lit-element";
|
||||||
import memoizeOne from "memoize-one";
|
import memoizeOne from "memoize-one";
|
||||||
|
import { navigate } from "../../../src/common/navigate";
|
||||||
|
import { extractSearchParam } from "../../../src/common/url/search-params";
|
||||||
import "../../../src/components/ha-circular-progress";
|
import "../../../src/components/ha-circular-progress";
|
||||||
import {
|
import {
|
||||||
fetchHassioAddonInfo,
|
fetchHassioAddonInfo,
|
||||||
HassioAddonDetails,
|
HassioAddonDetails,
|
||||||
} from "../../../src/data/hassio/addon";
|
} from "../../../src/data/hassio/addon";
|
||||||
|
import "../../../src/layouts/hass-loading-screen";
|
||||||
|
import "../../../src/layouts/hass-error-screen";
|
||||||
import { Supervisor } from "../../../src/data/supervisor/supervisor";
|
import { Supervisor } from "../../../src/data/supervisor/supervisor";
|
||||||
import "../../../src/layouts/hass-tabs-subpage";
|
import "../../../src/layouts/hass-tabs-subpage";
|
||||||
import type { PageNavigation } from "../../../src/layouts/hass-tabs-subpage";
|
import type { PageNavigation } from "../../../src/layouts/hass-tabs-subpage";
|
||||||
@ -31,6 +36,7 @@ import "./config/hassio-addon-network";
|
|||||||
import "./hassio-addon-router";
|
import "./hassio-addon-router";
|
||||||
import "./info/hassio-addon-info";
|
import "./info/hassio-addon-info";
|
||||||
import "./log/hassio-addon-logs";
|
import "./log/hassio-addon-logs";
|
||||||
|
import { extractApiErrorMessage } from "../../../src/data/hassio/common";
|
||||||
|
|
||||||
@customElement("hassio-addon-dashboard")
|
@customElement("hassio-addon-dashboard")
|
||||||
class HassioAddonDashboard extends LitElement {
|
class HassioAddonDashboard extends LitElement {
|
||||||
@ -44,6 +50,8 @@ class HassioAddonDashboard extends LitElement {
|
|||||||
|
|
||||||
@property({ type: Boolean }) public narrow!: boolean;
|
@property({ type: Boolean }) public narrow!: boolean;
|
||||||
|
|
||||||
|
@internalProperty() _error?: string;
|
||||||
|
|
||||||
private _computeTail = memoizeOne((route: Route) => {
|
private _computeTail = memoizeOne((route: Route) => {
|
||||||
const dividerPos = route.path.indexOf("/", 1);
|
const dividerPos = route.path.indexOf("/", 1);
|
||||||
return dividerPos === -1
|
return dividerPos === -1
|
||||||
@ -58,8 +66,14 @@ class HassioAddonDashboard extends LitElement {
|
|||||||
});
|
});
|
||||||
|
|
||||||
protected render(): TemplateResult {
|
protected render(): TemplateResult {
|
||||||
|
if (this._error) {
|
||||||
|
return html`<hass-error-screen
|
||||||
|
.error=${this._error}
|
||||||
|
></hass-error-screen>`;
|
||||||
|
}
|
||||||
|
|
||||||
if (!this.addon) {
|
if (!this.addon) {
|
||||||
return html`<ha-circular-progress active></ha-circular-progress>`;
|
return html`<hass-loading-screen></hass-loading-screen>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
const addonTabs: PageNavigation[] = [
|
const addonTabs: PageNavigation[] = [
|
||||||
@ -156,7 +170,12 @@ class HassioAddonDashboard extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected async firstUpdated(): Promise<void> {
|
protected async firstUpdated(): Promise<void> {
|
||||||
await this._routeDataChanged(this.route);
|
if (this.route.path === "") {
|
||||||
|
const addon = extractSearchParam("addon");
|
||||||
|
if (addon) {
|
||||||
|
navigate(this, `/hassio/addon/${addon}`, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
this.addEventListener("hass-api-called", (ev) => this._apiCalled(ev));
|
this.addEventListener("hass-api-called", (ev) => this._apiCalled(ev));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -170,16 +189,26 @@ class HassioAddonDashboard extends LitElement {
|
|||||||
if (path === "uninstall") {
|
if (path === "uninstall") {
|
||||||
history.back();
|
history.back();
|
||||||
} else {
|
} else {
|
||||||
await this._routeDataChanged(this.route);
|
await this._routeDataChanged();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async _routeDataChanged(routeData: Route): Promise<void> {
|
protected updated(changedProperties) {
|
||||||
const addon = routeData.path.split("/")[1];
|
if (changedProperties.has("route") && !this.addon) {
|
||||||
|
this._routeDataChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async _routeDataChanged(): Promise<void> {
|
||||||
|
const addon = this.route.path.split("/")[1];
|
||||||
|
if (!addon) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
const addoninfo = await fetchHassioAddonInfo(this.hass, addon);
|
const addoninfo = await fetchHassioAddonInfo(this.hass, addon);
|
||||||
this.addon = addoninfo;
|
this.addon = addoninfo;
|
||||||
} catch {
|
} catch (err) {
|
||||||
|
this._error = `Error fetching addon info: ${extractApiErrorMessage(err)}`;
|
||||||
this.addon = undefined;
|
this.addon = undefined;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
125
hassio/src/hassio-my-redirect.ts
Normal file
125
hassio/src/hassio-my-redirect.ts
Normal file
@ -0,0 +1,125 @@
|
|||||||
|
import {
|
||||||
|
customElement,
|
||||||
|
html,
|
||||||
|
internalProperty,
|
||||||
|
LitElement,
|
||||||
|
property,
|
||||||
|
TemplateResult,
|
||||||
|
} from "lit-element";
|
||||||
|
import { sanitizeUrl } from "@braintree/sanitize-url";
|
||||||
|
import {
|
||||||
|
createSearchParam,
|
||||||
|
extractSearchParamsObject,
|
||||||
|
} from "../../src/common/url/search-params";
|
||||||
|
import "../../src/layouts/hass-error-screen";
|
||||||
|
import {
|
||||||
|
ParamType,
|
||||||
|
Redirect,
|
||||||
|
Redirects,
|
||||||
|
} from "../../src/panels/my/ha-panel-my";
|
||||||
|
import { navigate } from "../../src/common/navigate";
|
||||||
|
import { HomeAssistant, Route } from "../../src/types";
|
||||||
|
|
||||||
|
const REDIRECTS: Redirects = {
|
||||||
|
supervisor_system: {
|
||||||
|
redirect: "/hassio/system",
|
||||||
|
},
|
||||||
|
supervisor_snapshots: {
|
||||||
|
redirect: "/hassio/snapshots",
|
||||||
|
},
|
||||||
|
supervisor_store: {
|
||||||
|
redirect: "/hassio/store",
|
||||||
|
},
|
||||||
|
supervisor: {
|
||||||
|
redirect: "/hassio/dashboard",
|
||||||
|
},
|
||||||
|
supervisor_addon: {
|
||||||
|
redirect: "/hassio/addon",
|
||||||
|
params: {
|
||||||
|
addon: "string",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
@customElement("hassio-my-redirect")
|
||||||
|
class HassioMyRedirect extends LitElement {
|
||||||
|
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||||
|
|
||||||
|
@property() public route!: Route;
|
||||||
|
|
||||||
|
@internalProperty() public _error?: TemplateResult | string;
|
||||||
|
|
||||||
|
connectedCallback() {
|
||||||
|
super.connectedCallback();
|
||||||
|
const path = this.route.path.substr(1);
|
||||||
|
const redirect = REDIRECTS[path];
|
||||||
|
|
||||||
|
if (!redirect) {
|
||||||
|
this._error = html`This redirect is not supported by your Home Assistant
|
||||||
|
instance. Check the
|
||||||
|
<a
|
||||||
|
target="_blank"
|
||||||
|
rel="noreferrer noopener"
|
||||||
|
href="https://my.home-assistant.io/faq.html#supported-pages"
|
||||||
|
>My Home Assistant FAQ</a
|
||||||
|
>
|
||||||
|
for the supported redirects and the version they where introduced.`;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let url: string;
|
||||||
|
try {
|
||||||
|
url = this._createRedirectUrl(redirect);
|
||||||
|
} catch (err) {
|
||||||
|
this._error = "An unknown error occured";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
navigate(this, url, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected render(): TemplateResult {
|
||||||
|
if (this._error) {
|
||||||
|
return html`<hass-error-screen
|
||||||
|
.error=${this._error}
|
||||||
|
></hass-error-screen>`;
|
||||||
|
}
|
||||||
|
return html``;
|
||||||
|
}
|
||||||
|
|
||||||
|
private _createRedirectUrl(redirect: Redirect): string {
|
||||||
|
const params = this._createRedirectParams(redirect);
|
||||||
|
return `${redirect.redirect}${params}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
private _createRedirectParams(redirect: Redirect): string {
|
||||||
|
const params = extractSearchParamsObject();
|
||||||
|
if (!redirect.params && !Object.keys(params).length) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
const resultParams = {};
|
||||||
|
Object.entries(redirect.params || {}).forEach(([key, type]) => {
|
||||||
|
if (!params[key] || !this._checkParamType(type, params[key])) {
|
||||||
|
throw Error();
|
||||||
|
}
|
||||||
|
resultParams[key] = params[key];
|
||||||
|
});
|
||||||
|
return `?${createSearchParam(resultParams)}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
private _checkParamType(type: ParamType, value: string) {
|
||||||
|
if (type === "string") {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (type === "url") {
|
||||||
|
return value && value === sanitizeUrl(value);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
"hassio-my-redirect": HassioMyRedirect;
|
||||||
|
}
|
||||||
|
}
|
@ -41,6 +41,10 @@ class HassioRouter extends HassRouterPage {
|
|||||||
tag: "hassio-ingress-view",
|
tag: "hassio-ingress-view",
|
||||||
load: () => import("./ingress-view/hassio-ingress-view"),
|
load: () => import("./ingress-view/hassio-ingress-view"),
|
||||||
},
|
},
|
||||||
|
_my_redirect: {
|
||||||
|
tag: "hassio-my-redirect",
|
||||||
|
load: () => import("./hassio-my-redirect"),
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -380,22 +380,24 @@ export class QuickBar extends LitElement {
|
|||||||
QuickBarNavigationItem,
|
QuickBarNavigationItem,
|
||||||
"action"
|
"action"
|
||||||
>[] {
|
>[] {
|
||||||
return Object.keys(this.hass.panels).map((panelKey) => {
|
return Object.keys(this.hass.panels)
|
||||||
const panel = this.hass.panels[panelKey];
|
.filter((panelKey) => panelKey !== "_my_redirect")
|
||||||
const translationKey = getPanelNameTranslationKey(panel);
|
.map((panelKey) => {
|
||||||
|
const panel = this.hass.panels[panelKey];
|
||||||
|
const translationKey = getPanelNameTranslationKey(panel);
|
||||||
|
|
||||||
const text = this.hass.localize(
|
const text = this.hass.localize(
|
||||||
"ui.dialogs.quick-bar.commands.navigation.navigate_to",
|
"ui.dialogs.quick-bar.commands.navigation.navigate_to",
|
||||||
"panel",
|
"panel",
|
||||||
this.hass.localize(translationKey) || panel.title || panel.url_path
|
this.hass.localize(translationKey) || panel.title || panel.url_path
|
||||||
);
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
text,
|
text,
|
||||||
icon: getPanelIcon(panel) || DEFAULT_NAVIGATION_ICON,
|
icon: getPanelIcon(panel) || DEFAULT_NAVIGATION_ICON,
|
||||||
path: `/${panel.url_path}`,
|
path: `/${panel.url_path}`,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private _generateNavigationConfigSectionCommands(): Partial<
|
private _generateNavigationConfigSectionCommands(): Partial<
|
||||||
|
@ -13,8 +13,10 @@ import {
|
|||||||
extractSearchParamsObject,
|
extractSearchParamsObject,
|
||||||
} from "../../common/url/search-params";
|
} from "../../common/url/search-params";
|
||||||
import "../../layouts/hass-error-screen";
|
import "../../layouts/hass-error-screen";
|
||||||
|
import { isComponentLoaded } from "../../common/config/is_component_loaded";
|
||||||
|
import { domainToName } from "../../data/integration";
|
||||||
|
|
||||||
const REDIRECTS = {
|
const REDIRECTS: Redirects = {
|
||||||
info: {
|
info: {
|
||||||
redirect: "/config/info",
|
redirect: "/config/info",
|
||||||
},
|
},
|
||||||
@ -38,10 +40,12 @@ const REDIRECTS = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
type ParamType = "url" | "string";
|
export type ParamType = "url" | "string";
|
||||||
|
|
||||||
interface Redirect {
|
export type Redirects = { [key: string]: Redirect };
|
||||||
|
export interface Redirect {
|
||||||
redirect: string;
|
redirect: string;
|
||||||
|
component?: string;
|
||||||
params?: {
|
params?: {
|
||||||
[key: string]: ParamType;
|
[key: string]: ParamType;
|
||||||
};
|
};
|
||||||
@ -58,7 +62,25 @@ class HaPanelMy extends LitElement {
|
|||||||
connectedCallback() {
|
connectedCallback() {
|
||||||
super.connectedCallback();
|
super.connectedCallback();
|
||||||
const path = this.route.path.substr(1);
|
const path = this.route.path.substr(1);
|
||||||
const redirect: Redirect | undefined = REDIRECTS[path];
|
|
||||||
|
if (path.startsWith("supervisor")) {
|
||||||
|
if (!isComponentLoaded(this.hass, "hassio")) {
|
||||||
|
this._error = this.hass.localize(
|
||||||
|
"ui.panel.my.component_not_loaded",
|
||||||
|
"integration",
|
||||||
|
domainToName(this.hass.localize, "hassio")
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
navigate(
|
||||||
|
this,
|
||||||
|
`/hassio/_my_redirect/${path}${window.location.search}`,
|
||||||
|
true
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const redirect = REDIRECTS[path];
|
||||||
|
|
||||||
if (!redirect) {
|
if (!redirect) {
|
||||||
this._error = this.hass.localize(
|
this._error = this.hass.localize(
|
||||||
@ -74,6 +96,18 @@ class HaPanelMy extends LitElement {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
redirect.component &&
|
||||||
|
!isComponentLoaded(this.hass, redirect.component)
|
||||||
|
) {
|
||||||
|
this._error = this.hass.localize(
|
||||||
|
"ui.panel.my.component_not_loaded",
|
||||||
|
"integration",
|
||||||
|
domainToName(this.hass.localize, redirect.component)
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
let url: string;
|
let url: string;
|
||||||
try {
|
try {
|
||||||
url = this._createRedirectUrl(redirect);
|
url = this._createRedirectUrl(redirect);
|
||||||
|
@ -806,6 +806,7 @@
|
|||||||
"panel": {
|
"panel": {
|
||||||
"my": {
|
"my": {
|
||||||
"not_supported": "This redirect is not supported by your Home Assistant instance. Check the {link} for the supported redirects and the version they where introduced.",
|
"not_supported": "This redirect is not supported by your Home Assistant instance. Check the {link} for the supported redirects and the version they where introduced.",
|
||||||
|
"component_not_loaded": "This redirect is not supported by your Home Assistant instance. You need the integration {integration} to use this redirect.",
|
||||||
"faq_link": "My Home Assistant FAQ",
|
"faq_link": "My Home Assistant FAQ",
|
||||||
"error": "An unknown error occured"
|
"error": "An unknown error occured"
|
||||||
},
|
},
|
||||||
|
Loading…
x
Reference in New Issue
Block a user