mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-25 18:26:35 +00:00
Add iframe strategy (#20068)
* Add iframe strategy with editor * Unify sandbox parameters * Update translations * Remove title from editor * Add editor when creating iframe strategy * Update src/translations/en.json
This commit is contained in:
parent
c30b9cdfcf
commit
90e9f79841
@ -1,5 +1,5 @@
|
|||||||
import "@material/mwc-list/mwc-list";
|
import "@material/mwc-list/mwc-list";
|
||||||
import { mdiMap, mdiPencilOutline, mdiShape } from "@mdi/js";
|
import { mdiMap, mdiPencilOutline, mdiShape, mdiWeb } from "@mdi/js";
|
||||||
import { CSSResultGroup, LitElement, css, html, nothing } from "lit";
|
import { CSSResultGroup, LitElement, css, html, nothing } from "lit";
|
||||||
import { customElement, property, state } from "lit/decorators";
|
import { customElement, property, state } from "lit/decorators";
|
||||||
import { fireEvent } from "../../../common/dom/fire_event";
|
import { fireEvent } from "../../../common/dom/fire_event";
|
||||||
@ -25,6 +25,10 @@ const STRATEGIES = [
|
|||||||
type: "map",
|
type: "map",
|
||||||
iconPath: mdiMap,
|
iconPath: mdiMap,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
type: "iframe",
|
||||||
|
iconPath: mdiWeb,
|
||||||
|
},
|
||||||
] as const satisfies Strategy[];
|
] as const satisfies Strategy[];
|
||||||
|
|
||||||
@customElement("ha-dialog-new-dashboard")
|
@customElement("ha-dialog-new-dashboard")
|
||||||
|
@ -0,0 +1,101 @@
|
|||||||
|
import { css, CSSResultGroup, html, LitElement, nothing } from "lit";
|
||||||
|
import { customElement, property, state } from "lit/decorators";
|
||||||
|
import { fireEvent } from "../../../../common/dom/fire_event";
|
||||||
|
import "../../../../components/ha-button";
|
||||||
|
import { createCloseHeading } from "../../../../components/ha-dialog";
|
||||||
|
import "../../../../components/ha-form/ha-form";
|
||||||
|
import { LovelaceStrategyConfig } from "../../../../data/lovelace/config/strategy";
|
||||||
|
import { haStyleDialog } from "../../../../resources/styles";
|
||||||
|
import { HomeAssistant } from "../../../../types";
|
||||||
|
import "../../../lovelace/editor/dashboard-strategy-editor/hui-dashboard-strategy-element-editor";
|
||||||
|
import { LovelaceDashboardConfigureStrategyDialogParams } from "./show-dialog-lovelace-dashboard-configure-strategy";
|
||||||
|
|
||||||
|
@customElement("dialog-lovelace-dashboard-configure-strategy")
|
||||||
|
export class DialogLovelaceDashboardDetail extends LitElement {
|
||||||
|
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||||
|
|
||||||
|
@state() private _params?: LovelaceDashboardConfigureStrategyDialogParams;
|
||||||
|
|
||||||
|
@state() private _submitting = false;
|
||||||
|
|
||||||
|
@state() private _data?: LovelaceStrategyConfig;
|
||||||
|
|
||||||
|
public showDialog(
|
||||||
|
params: LovelaceDashboardConfigureStrategyDialogParams
|
||||||
|
): void {
|
||||||
|
this._params = params;
|
||||||
|
this._data = params.config.strategy;
|
||||||
|
}
|
||||||
|
|
||||||
|
public closeDialog(): void {
|
||||||
|
this._params = undefined;
|
||||||
|
this._data = undefined;
|
||||||
|
fireEvent(this, "dialog-closed", { dialog: this.localName });
|
||||||
|
}
|
||||||
|
|
||||||
|
protected render() {
|
||||||
|
if (!this._params || !this._data) {
|
||||||
|
return nothing;
|
||||||
|
}
|
||||||
|
|
||||||
|
return html`
|
||||||
|
<ha-dialog
|
||||||
|
open
|
||||||
|
@closed=${this.closeDialog}
|
||||||
|
scrimClickAction
|
||||||
|
escapeKeyAction
|
||||||
|
.heading=${createCloseHeading(
|
||||||
|
this.hass,
|
||||||
|
this.hass.localize(
|
||||||
|
"ui.panel.config.lovelace.dashboards.detail.new_dashboard"
|
||||||
|
)
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<div>
|
||||||
|
<hui-dashboard-strategy-element-editor
|
||||||
|
.hass=${this.hass}
|
||||||
|
.lovelace=${this._params.config}
|
||||||
|
.value=${this._data}
|
||||||
|
@config-changed=${this._handleConfigChanged}
|
||||||
|
dialogInitialFocus
|
||||||
|
></hui-dashboard-strategy-element-editor>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<ha-button
|
||||||
|
slot="primaryAction"
|
||||||
|
@click=${this._save}
|
||||||
|
.disabled=${this._submitting}
|
||||||
|
>
|
||||||
|
${this.hass.localize("ui.common.next")}
|
||||||
|
</ha-button>
|
||||||
|
</ha-dialog>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
private _handleConfigChanged(ev: CustomEvent): void {
|
||||||
|
this._data = ev.detail.config;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async _save() {
|
||||||
|
if (!this._data) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this._submitting = true;
|
||||||
|
await this._params!.saveConfig({
|
||||||
|
...this._params!.config,
|
||||||
|
strategy: this._data,
|
||||||
|
});
|
||||||
|
this._submitting = false;
|
||||||
|
this.closeDialog();
|
||||||
|
}
|
||||||
|
|
||||||
|
static get styles(): CSSResultGroup {
|
||||||
|
return [haStyleDialog, css``];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
"dialog-lovelace-dashboard-configure-strategy": DialogLovelaceDashboardDetail;
|
||||||
|
}
|
||||||
|
}
|
@ -24,7 +24,8 @@ import "../../../../components/ha-icon-button";
|
|||||||
import "../../../../components/ha-svg-icon";
|
import "../../../../components/ha-svg-icon";
|
||||||
import { LovelacePanelConfig } from "../../../../data/lovelace";
|
import { LovelacePanelConfig } from "../../../../data/lovelace";
|
||||||
import {
|
import {
|
||||||
LovelaceConfig,
|
LovelaceRawConfig,
|
||||||
|
isStrategyDashboard,
|
||||||
saveConfig,
|
saveConfig,
|
||||||
} from "../../../../data/lovelace/config/types";
|
} from "../../../../data/lovelace/config/types";
|
||||||
import {
|
import {
|
||||||
@ -39,8 +40,10 @@ import { showConfirmationDialog } from "../../../../dialogs/generic/show-dialog-
|
|||||||
import "../../../../layouts/hass-loading-screen";
|
import "../../../../layouts/hass-loading-screen";
|
||||||
import "../../../../layouts/hass-tabs-subpage-data-table";
|
import "../../../../layouts/hass-tabs-subpage-data-table";
|
||||||
import { HomeAssistant, Route } from "../../../../types";
|
import { HomeAssistant, Route } from "../../../../types";
|
||||||
|
import { getLovelaceStrategy } from "../../../lovelace/strategies/get-strategy";
|
||||||
import { showNewDashboardDialog } from "../../dashboard/show-dialog-new-dashboard";
|
import { showNewDashboardDialog } from "../../dashboard/show-dialog-new-dashboard";
|
||||||
import { lovelaceTabs } from "../ha-config-lovelace";
|
import { lovelaceTabs } from "../ha-config-lovelace";
|
||||||
|
import { showDashboardConfigureStrategyDialog } from "./show-dialog-lovelace-dashboard-configure-strategy";
|
||||||
import { showDashboardDetailDialog } from "./show-dialog-lovelace-dashboard-detail";
|
import { showDashboardDetailDialog } from "./show-dialog-lovelace-dashboard-detail";
|
||||||
|
|
||||||
type DataTableItem = Pick<
|
type DataTableItem = Pick<
|
||||||
@ -64,6 +67,12 @@ export class HaConfigLovelaceDashboards extends LitElement {
|
|||||||
|
|
||||||
@state() private _dashboards: LovelaceDashboard[] = [];
|
@state() private _dashboards: LovelaceDashboard[] = [];
|
||||||
|
|
||||||
|
public willUpdate() {
|
||||||
|
if (!this.hasUpdated) {
|
||||||
|
this.hass.loadFragmentTranslation("lovelace");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private _columns = memoize(
|
private _columns = memoize(
|
||||||
(narrow: boolean, _language, dashboards): DataTableColumnContainer => {
|
(narrow: boolean, _language, dashboards): DataTableColumnContainer => {
|
||||||
const columns: DataTableColumnContainer<DataTableItem> = {
|
const columns: DataTableColumnContainer<DataTableItem> = {
|
||||||
@ -339,7 +348,25 @@ export class HaConfigLovelaceDashboards extends LitElement {
|
|||||||
|
|
||||||
private async _addDashboard() {
|
private async _addDashboard() {
|
||||||
showNewDashboardDialog(this, {
|
showNewDashboardDialog(this, {
|
||||||
selectConfig: (config) => {
|
selectConfig: async (config) => {
|
||||||
|
if (config && isStrategyDashboard(config)) {
|
||||||
|
const strategyType = config.strategy.type;
|
||||||
|
const strategyClass = await getLovelaceStrategy(
|
||||||
|
"dashboard",
|
||||||
|
strategyType
|
||||||
|
);
|
||||||
|
|
||||||
|
if (strategyClass.configRequired) {
|
||||||
|
showDashboardConfigureStrategyDialog(this, {
|
||||||
|
config: config,
|
||||||
|
saveConfig: async (updatedConfig) => {
|
||||||
|
this._openDetailDialog(undefined, undefined, updatedConfig);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
this._openDetailDialog(undefined, undefined, config);
|
this._openDetailDialog(undefined, undefined, config);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@ -348,7 +375,7 @@ export class HaConfigLovelaceDashboards extends LitElement {
|
|||||||
private async _openDetailDialog(
|
private async _openDetailDialog(
|
||||||
dashboard?: LovelaceDashboard,
|
dashboard?: LovelaceDashboard,
|
||||||
urlPath?: string,
|
urlPath?: string,
|
||||||
defaultConfig?: LovelaceConfig
|
defaultConfig?: LovelaceRawConfig
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
showDashboardDetailDialog(this, {
|
showDashboardDetailDialog(this, {
|
||||||
dashboard,
|
dashboard,
|
||||||
|
@ -0,0 +1,21 @@
|
|||||||
|
import { fireEvent } from "../../../../common/dom/fire_event";
|
||||||
|
import { LovelaceDashboardStrategyConfig } from "../../../../data/lovelace/config/types";
|
||||||
|
|
||||||
|
export interface LovelaceDashboardConfigureStrategyDialogParams {
|
||||||
|
config: LovelaceDashboardStrategyConfig;
|
||||||
|
saveConfig: (values: LovelaceDashboardStrategyConfig) => Promise<unknown>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const loadDashboardConfigureStrategyDialog = () =>
|
||||||
|
import("./dialog-lovelace-dashboard-configure-strategy");
|
||||||
|
|
||||||
|
export const showDashboardConfigureStrategyDialog = (
|
||||||
|
element: HTMLElement,
|
||||||
|
dialogParams: LovelaceDashboardConfigureStrategyDialogParams
|
||||||
|
) => {
|
||||||
|
fireEvent(element, "show-dialog", {
|
||||||
|
dialogTag: "dialog-lovelace-dashboard-configure-strategy",
|
||||||
|
dialogImport: loadDashboardConfigureStrategyDialog,
|
||||||
|
dialogParams,
|
||||||
|
});
|
||||||
|
};
|
@ -4,6 +4,7 @@ import { ifDefined } from "lit/directives/if-defined";
|
|||||||
import "../../layouts/hass-error-screen";
|
import "../../layouts/hass-error-screen";
|
||||||
import "../../layouts/hass-subpage";
|
import "../../layouts/hass-subpage";
|
||||||
import { HomeAssistant, PanelInfo } from "../../types";
|
import { HomeAssistant, PanelInfo } from "../../types";
|
||||||
|
import { IFRAME_SANDBOX } from "../../util/iframe";
|
||||||
|
|
||||||
@customElement("ha-panel-iframe")
|
@customElement("ha-panel-iframe")
|
||||||
class HaPanelIframe extends LitElement {
|
class HaPanelIframe extends LitElement {
|
||||||
@ -40,7 +41,7 @@ class HaPanelIframe extends LitElement {
|
|||||||
this.panel.title === null ? undefined : this.panel.title
|
this.panel.title === null ? undefined : this.panel.title
|
||||||
)}
|
)}
|
||||||
src=${this.panel.config.url}
|
src=${this.panel.config.url}
|
||||||
sandbox="allow-forms allow-popups allow-pointer-lock allow-same-origin allow-scripts allow-modals allow-downloads"
|
.sandbox=${IFRAME_SANDBOX}
|
||||||
allow="fullscreen"
|
allow="fullscreen"
|
||||||
></iframe>
|
></iframe>
|
||||||
</hass-subpage>
|
</hass-subpage>
|
||||||
|
@ -6,6 +6,7 @@ import parseAspectRatio from "../../../common/util/parse-aspect-ratio";
|
|||||||
import "../../../components/ha-alert";
|
import "../../../components/ha-alert";
|
||||||
import "../../../components/ha-card";
|
import "../../../components/ha-card";
|
||||||
import type { HomeAssistant } from "../../../types";
|
import type { HomeAssistant } from "../../../types";
|
||||||
|
import { IFRAME_SANDBOX } from "../../../util/iframe";
|
||||||
import { LovelaceCard, LovelaceCardEditor } from "../types";
|
import { LovelaceCard, LovelaceCardEditor } from "../types";
|
||||||
import { IframeCardConfig } from "./types";
|
import { IframeCardConfig } from "./types";
|
||||||
|
|
||||||
@ -96,7 +97,7 @@ export class HuiIframeCard extends LitElement implements LovelaceCard {
|
|||||||
<iframe
|
<iframe
|
||||||
title=${ifDefined(this._config.title)}
|
title=${ifDefined(this._config.title)}
|
||||||
src=${this._config.url}
|
src=${this._config.url}
|
||||||
sandbox="${sandbox_user_params} allow-forms allow-modals allow-popups allow-pointer-lock allow-same-origin allow-scripts"
|
.sandbox=${`${sandbox_user_params} ${IFRAME_SANDBOX}`}
|
||||||
allow="fullscreen"
|
allow="fullscreen"
|
||||||
></iframe>
|
></iframe>
|
||||||
</div>
|
</div>
|
||||||
|
@ -0,0 +1,75 @@
|
|||||||
|
import { html, LitElement, nothing } from "lit";
|
||||||
|
import { customElement, property, state } from "lit/decorators";
|
||||||
|
import { fireEvent } from "../../../../common/dom/fire_event";
|
||||||
|
import "../../../../components/ha-form/ha-form";
|
||||||
|
import type {
|
||||||
|
HaFormSchema,
|
||||||
|
SchemaUnion,
|
||||||
|
} from "../../../../components/ha-form/types";
|
||||||
|
import type { HomeAssistant } from "../../../../types";
|
||||||
|
import { IframeDashboardStrategyConfig } from "../../strategies/iframe/iframe-dashboard-strategy";
|
||||||
|
import { LovelaceStrategyEditor } from "../../strategies/types";
|
||||||
|
|
||||||
|
const SCHEMA = [
|
||||||
|
{
|
||||||
|
name: "url",
|
||||||
|
selector: {
|
||||||
|
text: {
|
||||||
|
type: "url",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
] as const satisfies readonly HaFormSchema[];
|
||||||
|
|
||||||
|
@customElement("hui-iframe-dashboard-strategy-editor")
|
||||||
|
export class HuiIframeDashboarStrategyEditor
|
||||||
|
extends LitElement
|
||||||
|
implements LovelaceStrategyEditor
|
||||||
|
{
|
||||||
|
@property({ attribute: false }) public hass?: HomeAssistant;
|
||||||
|
|
||||||
|
@state()
|
||||||
|
private _config?: IframeDashboardStrategyConfig;
|
||||||
|
|
||||||
|
public setConfig(config: IframeDashboardStrategyConfig): void {
|
||||||
|
this._config = config;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected render() {
|
||||||
|
if (!this.hass || !this._config) {
|
||||||
|
return nothing;
|
||||||
|
}
|
||||||
|
|
||||||
|
return html`
|
||||||
|
<ha-form
|
||||||
|
.hass=${this.hass}
|
||||||
|
.data=${this._config}
|
||||||
|
.schema=${SCHEMA}
|
||||||
|
.computeLabel=${this._computeLabelCallback}
|
||||||
|
@value-changed=${this._valueChanged}
|
||||||
|
></ha-form>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
private _valueChanged(ev: CustomEvent): void {
|
||||||
|
const data = ev.detail.value;
|
||||||
|
fireEvent(this, "config-changed", { config: data });
|
||||||
|
}
|
||||||
|
|
||||||
|
private _computeLabelCallback = (schema: SchemaUnion<typeof SCHEMA>) => {
|
||||||
|
switch (schema.name) {
|
||||||
|
case "url":
|
||||||
|
return this.hass?.localize(
|
||||||
|
`ui.panel.lovelace.editor.strategy.iframe.${schema.name}`
|
||||||
|
);
|
||||||
|
default:
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
"hui-iframe-dashboard-strategy-editor": HuiIframeDashboarStrategyEditor;
|
||||||
|
}
|
||||||
|
}
|
@ -25,12 +25,14 @@ const STRATEGIES: Record<LovelaceStrategyConfigType, Record<string, any>> = {
|
|||||||
"original-states": () =>
|
"original-states": () =>
|
||||||
import("./original-states/original-states-dashboard-strategy"),
|
import("./original-states/original-states-dashboard-strategy"),
|
||||||
map: () => import("./map/map-dashboard-strategy"),
|
map: () => import("./map/map-dashboard-strategy"),
|
||||||
|
iframe: () => import("./iframe/iframe-dashboard-strategy"),
|
||||||
},
|
},
|
||||||
view: {
|
view: {
|
||||||
"original-states": () =>
|
"original-states": () =>
|
||||||
import("./original-states/original-states-view-strategy"),
|
import("./original-states/original-states-view-strategy"),
|
||||||
energy: () => import("../../energy/strategies/energy-view-strategy"),
|
energy: () => import("../../energy/strategies/energy-view-strategy"),
|
||||||
map: () => import("./map/map-view-strategy"),
|
map: () => import("./map/map-view-strategy"),
|
||||||
|
iframe: () => import("./iframe/iframe-view-strategy"),
|
||||||
},
|
},
|
||||||
section: {},
|
section: {},
|
||||||
};
|
};
|
||||||
|
@ -0,0 +1,38 @@
|
|||||||
|
import { ReactiveElement } from "lit";
|
||||||
|
import { customElement } from "lit/decorators";
|
||||||
|
import { LovelaceConfig } from "../../../../data/lovelace/config/types";
|
||||||
|
import { LovelaceStrategyEditor } from "../types";
|
||||||
|
import { IframeViewStrategyConfig } from "./iframe-view-strategy";
|
||||||
|
|
||||||
|
export type IframeDashboardStrategyConfig = IframeViewStrategyConfig;
|
||||||
|
|
||||||
|
@customElement("iframe-dashboard-strategy")
|
||||||
|
export class IframeDashboardStrategy extends ReactiveElement {
|
||||||
|
static async generate(
|
||||||
|
config: IframeDashboardStrategyConfig
|
||||||
|
): Promise<LovelaceConfig> {
|
||||||
|
return {
|
||||||
|
title: config.title,
|
||||||
|
views: [
|
||||||
|
{
|
||||||
|
strategy: config,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async getConfigElement(): Promise<LovelaceStrategyEditor> {
|
||||||
|
await import(
|
||||||
|
"../../editor/dashboard-strategy-editor/hui-iframe-dashboard-strategy-editor"
|
||||||
|
);
|
||||||
|
return document.createElement("hui-iframe-dashboard-strategy-editor");
|
||||||
|
}
|
||||||
|
|
||||||
|
static configRequired = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
"iframe-dashboard-strategy": IframeDashboardStrategy;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,34 @@
|
|||||||
|
import { ReactiveElement } from "lit";
|
||||||
|
import { customElement } from "lit/decorators";
|
||||||
|
import { LovelaceViewConfig } from "../../../../data/lovelace/config/view";
|
||||||
|
import { IframeCardConfig } from "../../cards/types";
|
||||||
|
|
||||||
|
export type IframeViewStrategyConfig = {
|
||||||
|
type: "iframe";
|
||||||
|
url: string;
|
||||||
|
title?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
@customElement("iframe-view-strategy")
|
||||||
|
export class IframeViewStrategy extends ReactiveElement {
|
||||||
|
static async generate(
|
||||||
|
config: IframeViewStrategyConfig
|
||||||
|
): Promise<LovelaceViewConfig> {
|
||||||
|
return {
|
||||||
|
type: "panel",
|
||||||
|
title: config.title,
|
||||||
|
cards: [
|
||||||
|
{
|
||||||
|
type: "iframe",
|
||||||
|
url: config.url,
|
||||||
|
} as IframeCardConfig,
|
||||||
|
],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
"iframe-view-strategy": IframeViewStrategy;
|
||||||
|
}
|
||||||
|
}
|
@ -9,6 +9,7 @@ export type LovelaceStrategy<T = any> = {
|
|||||||
generate(config: LovelaceStrategyConfig, hass: HomeAssistant): Promise<T>;
|
generate(config: LovelaceStrategyConfig, hass: HomeAssistant): Promise<T>;
|
||||||
getConfigElement?: () => LovelaceStrategyEditor;
|
getConfigElement?: () => LovelaceStrategyEditor;
|
||||||
noEditor?: boolean;
|
noEditor?: boolean;
|
||||||
|
configRequired?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
export interface LovelaceDashboardStrategy
|
export interface LovelaceDashboardStrategy
|
||||||
|
@ -2212,6 +2212,10 @@
|
|||||||
"map": {
|
"map": {
|
||||||
"title": "[%key:panel::map%]",
|
"title": "[%key:panel::map%]",
|
||||||
"description": "Display people and your devices on a map"
|
"description": "Display people and your devices on a map"
|
||||||
|
},
|
||||||
|
"iframe": {
|
||||||
|
"title": "Webpage",
|
||||||
|
"description": "Integrate a webpage as a dashboard."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -5785,6 +5789,9 @@
|
|||||||
"areas": "Areas",
|
"areas": "Areas",
|
||||||
"hide_entities_without_area": "Hide entities without area",
|
"hide_entities_without_area": "Hide entities without area",
|
||||||
"hide_energy": "Hide energy"
|
"hide_energy": "Hide energy"
|
||||||
|
},
|
||||||
|
"iframe": {
|
||||||
|
"url": "URL"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"view": {
|
"view": {
|
||||||
|
2
src/util/iframe.ts
Normal file
2
src/util/iframe.ts
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
export const IFRAME_SANDBOX =
|
||||||
|
"allow-forms allow-popups allow-pointer-lock allow-same-origin allow-scripts allow-modals allow-downloads";
|
Loading…
x
Reference in New Issue
Block a user