From 16c4656a7d77595553620abb977b71161f2370b8 Mon Sep 17 00:00:00 2001 From: Alex Andreev Date: Tue, 7 Sep 2021 15:18:46 +0300 Subject: [PATCH] TopBar home icon (#3740) * Adding home button Signed-off-by: Alex Andreev * Highlight catalog entity on route match Signed-off-by: Alex Andreev * Wait for general entites to load Signed-off-by: Alex Andreev * Adding WelcomePage catalog entity Signed-off-by: Alex Andreev * Highlight general entities in hotbar if their route matches Signed-off-by: Alex Andreev * Fixing tests Signed-off-by: Alex Andreev * Moving active entities sync to helper function Signed-off-by: Alex Andreev * Fix welcome page test Signed-off-by: Alex Andreev --- .../catalog/catalog-category-registry.ts | 4 +++ src/main/catalog-sources/general.ts | 24 +++++++++++-- .../helpers/general-active-sync.ts | 36 +++++++++++++++++++ src/renderer/components/+catalog/catalog.tsx | 1 - .../+welcome/__test__/welcome.test.tsx | 3 ++ .../cluster-manager/cluster-manager.tsx | 11 +++++- .../layout/__tests__/topbar.test.tsx | 13 +++++++ src/renderer/components/layout/topbar.tsx | 14 ++++++++ 8 files changed, 102 insertions(+), 4 deletions(-) create mode 100644 src/main/catalog-sources/helpers/general-active-sync.ts diff --git a/src/common/catalog/catalog-category-registry.ts b/src/common/catalog/catalog-category-registry.ts index 207dc2af3d..bad1570c9c 100644 --- a/src/common/catalog/catalog-category-registry.ts +++ b/src/common/catalog/catalog-category-registry.ts @@ -76,6 +76,10 @@ export class CatalogCategoryRegistry { return this.getForGroupKind(group, data.kind); } + + getByName(name: string) { + return this.items.find(category => category.metadata?.name == name); + } } export const catalogCategoryRegistry = new CatalogCategoryRegistry(); diff --git a/src/main/catalog-sources/general.ts b/src/main/catalog-sources/general.ts index 6b16984d1d..a002228274 100644 --- a/src/main/catalog-sources/general.ts +++ b/src/main/catalog-sources/general.ts @@ -21,7 +21,7 @@ import { observable } from "mobx"; import { GeneralEntity } from "../../common/catalog-entities/general"; -import { catalogURL, preferencesURL } from "../../common/routes"; +import { catalogURL, preferencesURL, welcomeURL } from "../../common/routes"; import { catalogEntityRegistry } from "../catalog"; export const catalogEntity = new GeneralEntity({ @@ -62,9 +62,29 @@ const preferencesEntity = new GeneralEntity({ } }); +const welcomePageEntity = new GeneralEntity({ + metadata: { + uid: "welcome-page-entity", + name: "Welcome Page", + source: "app", + labels: {} + }, + spec: { + path: welcomeURL(), + icon: { + material: "meeting_room", + background: "#3d90ce" + } + }, + status: { + phase: "active", + } +}); + const generalEntities = observable([ catalogEntity, - preferencesEntity + preferencesEntity, + welcomePageEntity ]); export function syncGeneralEntities() { diff --git a/src/main/catalog-sources/helpers/general-active-sync.ts b/src/main/catalog-sources/helpers/general-active-sync.ts new file mode 100644 index 0000000000..e46e27f827 --- /dev/null +++ b/src/main/catalog-sources/helpers/general-active-sync.ts @@ -0,0 +1,36 @@ +/** + * 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 { when } from "mobx"; +import { catalogCategoryRegistry } from "../../../common/catalog"; +import { catalogEntityRegistry } from "../../../renderer/api/catalog-entity-registry"; +import { isActiveRoute } from "../../../renderer/navigation"; + +export async function setEntityOnRouteMatch() { + await when(() => catalogEntityRegistry.entities.size > 0); + + const entities = catalogEntityRegistry.getItemsForCategory(catalogCategoryRegistry.getByName("General")); + const activeEntity = entities.find(entity => isActiveRoute(entity.spec.path)); + + if (activeEntity) { + catalogEntityRegistry.activeEntity = activeEntity; + } +} diff --git a/src/renderer/components/+catalog/catalog.tsx b/src/renderer/components/+catalog/catalog.tsx index 658c91273f..7f6347f5e3 100644 --- a/src/renderer/components/+catalog/catalog.tsx +++ b/src/renderer/components/+catalog/catalog.tsx @@ -104,7 +104,6 @@ export class Catalog extends React.Component { }, {fireImmediately: true}), ]); } - addToHotbar(item: CatalogEntityItem): void { HotbarStore.getInstance().addToHotbar(item.entity); } diff --git a/src/renderer/components/+welcome/__test__/welcome.test.tsx b/src/renderer/components/+welcome/__test__/welcome.test.tsx index d2eda315c4..c0d17faebe 100644 --- a/src/renderer/components/+welcome/__test__/welcome.test.tsx +++ b/src/renderer/components/+welcome/__test__/welcome.test.tsx @@ -32,6 +32,9 @@ jest.mock( ipcRenderer: { on: jest.fn(), }, + app: { + getPath: () => "tmp", + }, }) ); diff --git a/src/renderer/components/cluster-manager/cluster-manager.tsx b/src/renderer/components/cluster-manager/cluster-manager.tsx index 4bd14e7805..3b6cf1a434 100644 --- a/src/renderer/components/cluster-manager/cluster-manager.tsx +++ b/src/renderer/components/cluster-manager/cluster-manager.tsx @@ -23,7 +23,7 @@ import "./cluster-manager.scss"; import React from "react"; import { Redirect, Route, Switch } from "react-router"; -import { observer } from "mobx-react"; +import { disposeOnUnmount, observer } from "mobx-react"; import { BottomBar } from "./bottom-bar"; import { Catalog } from "../+catalog"; import { Preferences } from "../+preferences"; @@ -35,9 +35,18 @@ import { HotbarMenu } from "../hotbar/hotbar-menu"; import { EntitySettings } from "../+entity-settings"; import { Welcome } from "../+welcome"; import * as routes from "../../../common/routes"; +import { reaction } from "mobx"; +import { navigation } from "../../navigation"; +import { setEntityOnRouteMatch } from "../../../main/catalog-sources/helpers/general-active-sync"; @observer export class ClusterManager extends React.Component { + componentDidMount() { + disposeOnUnmount(this, [ + reaction(() => navigation.location, () => setEntityOnRouteMatch(), { fireImmediately: true }) + ]); + } + render() { return (
diff --git a/src/renderer/components/layout/__tests__/topbar.test.tsx b/src/renderer/components/layout/__tests__/topbar.test.tsx index db71135658..c519d6b881 100644 --- a/src/renderer/components/layout/__tests__/topbar.test.tsx +++ b/src/renderer/components/layout/__tests__/topbar.test.tsx @@ -41,9 +41,16 @@ jest.mock( } ), }, + app: { + getPath: () => "tmp", + }, }) ); +jest.mock("../../+catalog", () => ({ + previousActiveTab: jest.fn() +})); + const goBack = jest.fn(); const goForward = jest.fn(); @@ -76,6 +83,12 @@ describe("", () => { expect(container).toBeInstanceOf(HTMLElement); }); + it("renders home button", async () => { + const { getByTestId } = render(); + + expect(await getByTestId("home-button")).toBeInTheDocument(); + }); + it("renders history arrows", async () => { const { getByTestId } = render(); diff --git a/src/renderer/components/layout/topbar.tsx b/src/renderer/components/layout/topbar.tsx index 404a4fec7d..2783471bb3 100644 --- a/src/renderer/components/layout/topbar.tsx +++ b/src/renderer/components/layout/topbar.tsx @@ -28,6 +28,9 @@ import { webContents } from "@electron/remote"; import { observable } from "mobx"; import { ipcRendererOn } from "../../../common/ipc"; import { watchHistoryState } from "../../remote-helpers/history-updater"; +import { isActiveRoute, navigate } from "../../navigation"; +import { catalogRoute, catalogURL } from "../../../common/routes"; +import { previousActiveTab } from "../+catalog"; interface Props extends React.HTMLAttributes { } @@ -68,6 +71,10 @@ export const TopBar = observer(({ children, ...rest }: Props) => { ); }; + const goHome = () => { + navigate(`${catalogURL()}/${previousActiveTab.get()}`); + }; + const goBack = () => { webContents.getAllWebContents().find((webContent) => webContent.getType() === "window")?.goBack(); }; @@ -85,6 +92,13 @@ export const TopBar = observer(({ children, ...rest }: Props) => { return (
+