From 1fb97b0d95422bc56c8d0fad1e8261ab83b77d4b Mon Sep 17 00:00:00 2001 From: "Hung-Han (Henry) Chen" Date: Mon, 23 Aug 2021 12:22:41 +0300 Subject: [PATCH] Add welcomeBanners extension api Signed-off-by: Hung-Han (Henry) Chen --- src/extensions/extension-loader.ts | 1 + src/extensions/lens-renderer-extension.ts | 1 + src/extensions/registries/index.ts | 1 + .../registries/welcome-banner-registry.ts | 35 +++++++++++++++++++ src/main/window-manager.ts | 30 ++++++++++++++++ .../+welcome/__test__/welcome.test.tsx | 25 ++++++++++--- src/renderer/components/+welcome/welcome.tsx | 18 ++++++++-- src/renderer/initializers/registries.ts | 1 + 8 files changed, 106 insertions(+), 6 deletions(-) create mode 100644 src/extensions/registries/welcome-banner-registry.ts diff --git a/src/extensions/extension-loader.ts b/src/extensions/extension-loader.ts index 321ab80259..0f860a964d 100644 --- a/src/extensions/extension-loader.ts +++ b/src/extensions/extension-loader.ts @@ -278,6 +278,7 @@ export class ExtensionLoader extends Singleton { registries.StatusBarRegistry.getInstance().add(extension.statusBarItems), registries.CommandRegistry.getInstance().add(extension.commands), registries.WelcomeMenuRegistry.getInstance().add(extension.welcomeMenus), + registries.WelcomeBannerRegistry.getInstance().add(extension.welcomeBanners), registries.CatalogEntityDetailRegistry.getInstance().add(extension.catalogEntityDetailItems), registries.TopBarRegistry.getInstance().add(extension.topBarItems), ]; diff --git a/src/extensions/lens-renderer-extension.ts b/src/extensions/lens-renderer-extension.ts index dd5670fd67..0ae8a44323 100644 --- a/src/extensions/lens-renderer-extension.ts +++ b/src/extensions/lens-renderer-extension.ts @@ -38,6 +38,7 @@ export class LensRendererExtension extends LensExtension { kubeWorkloadsOverviewItems: registries.WorkloadsOverviewDetailRegistration[] = []; commands: registries.CommandRegistration[] = []; welcomeMenus: registries.WelcomeMenuRegistration[] = []; + welcomeBanners: registries.WelcomeBannerRegistration[] = []; catalogEntityDetailItems: registries.CatalogEntityDetailRegistration[] = []; topBarItems: registries.TopBarRegistration[] = []; diff --git a/src/extensions/registries/index.ts b/src/extensions/registries/index.ts index febc0ba7ca..99809265a2 100644 --- a/src/extensions/registries/index.ts +++ b/src/extensions/registries/index.ts @@ -32,6 +32,7 @@ export * from "./kube-object-status-registry"; export * from "./command-registry"; export * from "./entity-setting-registry"; export * from "./welcome-menu-registry"; +export * from "./welcome-banner-registry"; export * from "./catalog-entity-detail-registry"; export * from "./workloads-overview-detail-registry"; export * from "./topbar-registry"; diff --git a/src/extensions/registries/welcome-banner-registry.ts b/src/extensions/registries/welcome-banner-registry.ts new file mode 100644 index 0000000000..ef36da8444 --- /dev/null +++ b/src/extensions/registries/welcome-banner-registry.ts @@ -0,0 +1,35 @@ +/** + * Copyright (c) 2021 OpenLens Authors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +import { BaseRegistry } from "./base-registry"; + +/** + * WelcomeBannerRegistration is for an extension to register + * Provide a Banner component to be renderered in the welcome screen. + */ +export interface WelcomeBannerRegistration { + /** + * The banner component to be shown on the welcome screen. + */ + Banner?: React.ComponentType +} + +export class WelcomeBannerRegistry extends BaseRegistry { } diff --git a/src/main/window-manager.ts b/src/main/window-manager.ts index 88d7dff0af..f1715a4284 100644 --- a/src/main/window-manager.ts +++ b/src/main/window-manager.ts @@ -89,6 +89,7 @@ export class WindowManager extends Singleton { nodeIntegration: true, nodeIntegrationInSubFrames: true, enableRemoteModule: true, + webviewTag: true }, }); this.windowState.manage(this.mainWindow); @@ -121,6 +122,35 @@ export class WindowManager extends Singleton { }) .on("did-finish-load", () => { logger.info("[WINDOW-MANAGER]: Main window loaded"); + }) + .on("will-attach-webview", (event, webPreferences, params) => { + logger.info("[WINDOW-MANAGER]: Attaching webview"); + // Following is security recommendations because we allow webview tag (webviewTag: true) + // suggested by https://www.electronjs.org/docs/tutorial/security#11-verify-webview-options-before-creation + // and https://www.electronjs.org/docs/tutorial/security#10-do-not-use-allowpopups + + if (webPreferences.preload) { + logger.warn("[WINDOW-MANAGER]: Strip away preload scripts of webview"); + delete webPreferences.preload; + } + + // @ts-expect-error some electron version uses webPreferences.preloadURL/webPreferences.preload + if (webPreferences.preloadURL) { + logger.warn("[WINDOW-MANAGER]: Strip away preload scripts of webview"); + delete webPreferences.preload; + } + + if (params.allowpopups) { + logger.warn("[WINDOW-MANAGER]: We do not allow allowpopups props, stop webview from renderer"); + + // event.preventDefault() will destroy the guest page. + event.preventDefault(); + + return; + } + + // Always disable Node.js integration for all webviews + webPreferences.nodeIntegration = false; }); } diff --git a/src/renderer/components/+welcome/__test__/welcome.test.tsx b/src/renderer/components/+welcome/__test__/welcome.test.tsx index 97493e07ff..52f579643f 100644 --- a/src/renderer/components/+welcome/__test__/welcome.test.tsx +++ b/src/renderer/components/+welcome/__test__/welcome.test.tsx @@ -20,20 +20,22 @@ */ import React from "react"; -import { render } from "@testing-library/react"; +import { render, screen } from "@testing-library/react"; import "@testing-library/jest-dom/extend-expect"; import { Welcome } from "../welcome"; -import { TopBarRegistry, WelcomeMenuRegistry } from "../../../../extensions/registries"; +import { TopBarRegistry, WelcomeMenuRegistry, WelcomeBannerRegistry } from "../../../../extensions/registries"; describe("", () => { beforeEach(() => { TopBarRegistry.createInstance(); WelcomeMenuRegistry.createInstance(); + WelcomeBannerRegistry.createInstance(); }); afterEach(() => { TopBarRegistry.resetInstance(); WelcomeMenuRegistry.resetInstance(); + WelcomeBannerRegistry.resetInstance(); }); it("renders items in the top bar", async () => { @@ -48,8 +50,23 @@ describe("", () => { } ]); - const { getByTestId } = render(); + render(); - expect(await getByTestId(testId)).toHaveTextContent(text); + expect(screen.getByTestId(testId)).toHaveTextContent(text); + }); + + it("renders registered in WelcomeBannerRegistry and hide logo", async () => { + const testId = "testId"; + + WelcomeBannerRegistry.getInstance().getItems = jest.fn().mockImplementationOnce(() => [ + { + Banner: () =>
+ } + ]); + + const { container } = render(); + + expect(screen.queryByTestId(testId)).toBeInTheDocument(); + expect(container.getElementsByClassName("logo").length).toBe(0); }); }); diff --git a/src/renderer/components/+welcome/welcome.tsx b/src/renderer/components/+welcome/welcome.tsx index feb676d8fd..ffb290fb09 100644 --- a/src/renderer/components/+welcome/welcome.tsx +++ b/src/renderer/components/+welcome/welcome.tsx @@ -22,20 +22,34 @@ import "./welcome.scss"; import React from "react"; import { observer } from "mobx-react"; +import Carousel from "react-material-ui-carousel"; import { Icon } from "../icon"; import { productName, slackUrl } from "../../../common/vars"; import { WelcomeMenuRegistry } from "../../../extensions/registries"; import { WelcomeTopbar } from "../cluster-manager/welcome-topbar"; +import { WelcomeBannerRegistry } from "../../../extensions/registries"; @observer export class Welcome extends React.Component { render() { + const welcomeBanner = WelcomeBannerRegistry.getInstance().getItems(); + return ( <> -
+
- + {welcomeBanner.length > 0 ? ( + 1} + autoPlay={true} + > + {welcomeBanner.map((item, index) => + + )} + + ) : }

Welcome to {productName} 5!

diff --git a/src/renderer/initializers/registries.ts b/src/renderer/initializers/registries.ts index 1d455a0bcc..3063213bc8 100644 --- a/src/renderer/initializers/registries.ts +++ b/src/renderer/initializers/registries.ts @@ -34,6 +34,7 @@ export function initRegistries() { registries.KubeObjectStatusRegistry.createInstance(); registries.StatusBarRegistry.createInstance(); registries.WelcomeMenuRegistry.createInstance(); + registries.WelcomeBannerRegistry.createInstance(); registries.WorkloadsOverviewDetailRegistry.createInstance(); registries.TopBarRegistry.createInstance(); }