From 27d230d12b43487b4756b39e61b8313395696252 Mon Sep 17 00:00:00 2001 From: Alex Date: Thu, 20 May 2021 15:57:56 +0300 Subject: [PATCH 1/5] Enable deep navigation/routing to catalog (#2818) * Enable route-based navigation to catalog items Signed-off-by: Alex Culliere Co-authored-by: Sebastian Malton * Enable custom protocol handle to process routing in catalog Signed-off-by: Alex Culliere Co-authored-by: Sebastian Malton * Fix type imports Signed-off-by: Alex Culliere Co-authored-by: Alex Culliere --- .../components/+catalog/catalog.route.ts | 8 +++-- src/renderer/components/+catalog/catalog.tsx | 31 +++++++++++++++++-- src/renderer/protocol-handler/app-handlers.ts | 7 +++++ 3 files changed, 41 insertions(+), 5 deletions(-) diff --git a/src/renderer/components/+catalog/catalog.route.ts b/src/renderer/components/+catalog/catalog.route.ts index 39ad958650..b7bbe8c993 100644 --- a/src/renderer/components/+catalog/catalog.route.ts +++ b/src/renderer/components/+catalog/catalog.route.ts @@ -22,8 +22,12 @@ import type { RouteProps } from "react-router"; import { buildURL } from "../../../common/utils/buildUrl"; +export interface ICatalogViewRouteParam { + group?: string; + kind?: string; +} export const catalogRoute: RouteProps = { - path: "/catalog" + path: "/catalog/:group?/:kind?" }; -export const catalogURL = buildURL(catalogRoute.path); +export const catalogURL = buildURL(catalogRoute.path); diff --git a/src/renderer/components/+catalog/catalog.tsx b/src/renderer/components/+catalog/catalog.tsx index 63239eb5d1..5211e034c2 100644 --- a/src/renderer/components/+catalog/catalog.tsx +++ b/src/renderer/components/+catalog/catalog.tsx @@ -23,7 +23,7 @@ import "./catalog.scss"; import React from "react"; import { disposeOnUnmount, observer } from "mobx-react"; import { ItemListLayout } from "../item-object-list"; -import { action, observable, reaction } from "mobx"; +import { action, observable, reaction, when } from "mobx"; import { CatalogEntityItem, CatalogEntityStore } from "./catalog-entity.store"; import { navigate } from "../../navigation"; import { kebabCase } from "lodash"; @@ -37,18 +37,33 @@ import { ConfirmDialog } from "../confirm-dialog"; import { Tab, Tabs } from "../tabs"; import { catalogCategoryRegistry } from "../../../common/catalog"; import { CatalogAddButton } from "./catalog-add-button"; +import type { RouteComponentProps } from "react-router"; +import type { ICatalogViewRouteParam } from "./catalog.route"; +import { Notifications } from "../notifications"; enum sortBy { name = "name", source = "source", status = "status" } + +interface Props extends RouteComponentProps {} @observer -export class Catalog extends React.Component { +export class Catalog extends React.Component { @observable private catalogEntityStore?: CatalogEntityStore; @observable.deep private contextMenu: CatalogEntityContextMenuContext; @observable activeTab?: string; + get routeActiveTab(): string | undefined { + const { group, kind } = this.props.match.params ?? {}; + + if (group && kind) { + return `${group}/${kind}`; + } + + return undefined; + } + async componentDidMount() { this.contextMenu = { menuItems: [], @@ -57,12 +72,22 @@ export class Catalog extends React.Component { this.catalogEntityStore = new CatalogEntityStore(); disposeOnUnmount(this, [ this.catalogEntityStore.watch(), + when(() => catalogCategoryRegistry.items.length > 0, () => { + const item = catalogCategoryRegistry.items.find(i => i.getId() === this.routeActiveTab); + + if (item || this.routeActiveTab === undefined) { + this.activeTab = this.routeActiveTab; + this.catalogEntityStore.activeCategory = item; + } else { + Notifications.error(

Unknown category: {this.routeActiveTab}

); + } + }), reaction(() => catalogCategoryRegistry.items, (items) => { if (!this.activeTab && items.length > 0) { this.activeTab = items[0].getId(); this.catalogEntityStore.activeCategory = items[0]; } - }, { fireImmediately: true }) + }), ]); } diff --git a/src/renderer/protocol-handler/app-handlers.ts b/src/renderer/protocol-handler/app-handlers.ts index 0e5e2f3ee6..bbd91ab19b 100644 --- a/src/renderer/protocol-handler/app-handlers.ts +++ b/src/renderer/protocol-handler/app-handlers.ts @@ -43,6 +43,13 @@ export function bindProtocolAddRouteHandlers() { .addInternalHandler("/landing", () => { navigate(catalogURL()); }) + .addInternalHandler("/landing/view/:group/:kind", ({ pathname: { group, kind } }) => { + navigate(catalogURL({ + params: { + group, kind + } + })); + }) .addInternalHandler("/cluster", () => { navigate(addClusterURL()); }) From c8421e47403a7c8e8e2946f9a81cfe1b965aabce Mon Sep 17 00:00:00 2001 From: Jari Kolehmainen Date: Thu, 20 May 2021 16:05:12 +0300 Subject: [PATCH 2/5] handle missing data on disabled hotbar items (#2829) Signed-off-by: Jari Kolehmainen --- src/renderer/components/hotbar/hotbar-icon.tsx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/renderer/components/hotbar/hotbar-icon.tsx b/src/renderer/components/hotbar/hotbar-icon.tsx index bdd00859c2..7c567ff681 100644 --- a/src/renderer/components/hotbar/hotbar-icon.tsx +++ b/src/renderer/components/hotbar/hotbar-icon.tsx @@ -93,6 +93,10 @@ export const HotbarIcon = observer(({menuItems = [], ...props}: Props) => { }; const getIconString = () => { + if (!title) { + return "??"; + } + const [rawFirst, rawSecond, rawThird] = getNameParts(title); const splitter = new GraphemeSplitter(); const first = splitter.iterateGraphemes(rawFirst); @@ -108,7 +112,7 @@ export const HotbarIcon = observer(({menuItems = [], ...props}: Props) => { return (
- +
Date: Thu, 20 May 2021 09:40:47 -0400 Subject: [PATCH 3/5] Fix kube sync items not visible on reopening (#2815) Signed-off-by: Sebastian Malton Co-authored-by: Jari Kolehmainen --- src/main/catalog-pusher.ts | 33 +++++---------------- src/main/index.ts | 11 ++++--- src/renderer/api/catalog-entity-registry.ts | 3 +- 3 files changed, 15 insertions(+), 32 deletions(-) diff --git a/src/main/catalog-pusher.ts b/src/main/catalog-pusher.ts index c2971017cc..c2d7267b92 100644 --- a/src/main/catalog-pusher.ts +++ b/src/main/catalog-pusher.ts @@ -20,33 +20,14 @@ */ import { reaction, toJS } from "mobx"; -import { broadcastMessage, subscribeToBroadcast, unsubscribeFromBroadcast } from "../common/ipc"; +import { broadcastMessage } from "../common/ipc"; import type { CatalogEntityRegistry} from "./catalog"; import "../common/catalog-entities/kubernetes-cluster"; -import type { Disposer } from "../common/utils"; -export class CatalogPusher { - static init(catalog: CatalogEntityRegistry) { - new CatalogPusher(catalog).init(); - } - - private constructor(private catalog: CatalogEntityRegistry) {} - - init() { - const disposers: Disposer[] = []; - - disposers.push(reaction(() => toJS(this.catalog.items, { recurseEverything: true }), (items) => { - broadcastMessage("catalog:items", items); - }, { - fireImmediately: true, - })); - - const listener = subscribeToBroadcast("catalog:broadcast", () => { - broadcastMessage("catalog:items", toJS(this.catalog.items, { recurseEverything: true })); - }); - - disposers.push(() => unsubscribeFromBroadcast("catalog:broadcast", listener)); - - return disposers; - } +export function pushCatalogToRenderer(catalog: CatalogEntityRegistry) { + return reaction(() => toJS(catalog.items, { recurseEverything: true }), (items) => { + broadcastMessage("catalog:items", items); + }, { + fireImmediately: true, + }); } diff --git a/src/main/index.ts b/src/main/index.ts index d54babde8b..2585b0740e 100644 --- a/src/main/index.ts +++ b/src/main/index.ts @@ -45,11 +45,11 @@ import type { LensExtensionId } from "../extensions/lens-extension"; import { FilesystemProvisionerStore } from "./extension-filesystem"; import { installDeveloperTools } from "./developer-tools"; import { LensProtocolRouterMain } from "./protocol-handler"; -import { getAppVersion, getAppVersionFromProxyServer } from "../common/utils"; +import { disposer, getAppVersion, getAppVersionFromProxyServer } from "../common/utils"; import { bindBroadcastHandlers } from "../common/ipc"; import { startUpdateChecking } from "./app-updater"; import { IpcRendererNavigationEvents } from "../renderer/navigation/events"; -import { CatalogPusher } from "./catalog-pusher"; +import { pushCatalogToRenderer } from "./catalog-pusher"; import { catalogEntityRegistry } from "./catalog"; import { HotbarStore } from "../common/hotbar-store"; import { HelmRepoManager } from "./helm/helm-repo-manager"; @@ -57,6 +57,7 @@ import { KubeconfigSyncManager } from "./catalog-sources"; import { handleWsUpgrade } from "./proxy/ws-upgrade"; const workingDir = path.join(app.getPath("appData"), appName); +const cleanup = disposer(); app.setName(appName); @@ -142,7 +143,7 @@ app.on("ready", async () => { const lensProxy = LensProxy.createInstance(handleWsUpgrade); ClusterManager.createInstance(); - KubeconfigSyncManager.createInstance().startSync(); + KubeconfigSyncManager.createInstance(); try { logger.info("🔌 Starting LensProxy"); @@ -187,7 +188,8 @@ app.on("ready", async () => { } ipcMain.on(IpcRendererNavigationEvents.LOADED, () => { - CatalogPusher.init(catalogEntityRegistry); + cleanup.push(pushCatalogToRenderer(catalogEntityRegistry)); + KubeconfigSyncManager.getInstance().startSync(); startUpdateChecking(); LensProtocolRouterMain .getInstance() @@ -251,6 +253,7 @@ app.on("will-quit", (event) => { appEventBus.emit({name: "app", action: "close"}); ClusterManager.getInstance(false)?.stop(); // close cluster connections KubeconfigSyncManager.getInstance(false)?.stopSync(); + cleanup(); if (blockQuit) { event.preventDefault(); // prevent app's default shutdown (e.g. required for telemetry, etc.) diff --git a/src/renderer/api/catalog-entity-registry.ts b/src/renderer/api/catalog-entity-registry.ts index ac4e6748dc..d6e2059edf 100644 --- a/src/renderer/api/catalog-entity-registry.ts +++ b/src/renderer/api/catalog-entity-registry.ts @@ -20,7 +20,7 @@ */ import { computed, observable } from "mobx"; -import { broadcastMessage, subscribeToBroadcast } from "../../common/ipc"; +import { subscribeToBroadcast } from "../../common/ipc"; import { CatalogCategory, CatalogEntity, CatalogEntityData, catalogCategoryRegistry, CatalogCategoryRegistry, CatalogEntityKindData } from "../../common/catalog"; import "../../common/catalog-entities"; import { iter } from "../utils"; @@ -35,7 +35,6 @@ export class CatalogEntityRegistry { subscribeToBroadcast("catalog:items", (ev, items: (CatalogEntityData & CatalogEntityKindData)[]) => { this.rawItems.replace(items); }); - broadcastMessage("catalog:broadcast"); } set activeEntity(entity: CatalogEntity) { From dd81fb6a0ff1f104fe42ad9cd80002f8b02c3fca Mon Sep 17 00:00:00 2001 From: Sebastian Malton Date: Thu, 20 May 2021 09:45:56 -0400 Subject: [PATCH 4/5] release v5.0.0-beta.5 (#2801) From 99a0361f1abceeb5c69bdadc97925971f7423700 Mon Sep 17 00:00:00 2001 From: Jari Kolehmainen Date: Thu, 20 May 2021 17:01:04 +0300 Subject: [PATCH 5/5] Allow unpin disabled hotbar items (#2833) Signed-off-by: Jari Kolehmainen --- src/renderer/components/hotbar/hotbar-menu.tsx | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/renderer/components/hotbar/hotbar-menu.tsx b/src/renderer/components/hotbar/hotbar-menu.tsx index 33a8d4e0b7..d3bb838ac7 100644 --- a/src/renderer/components/hotbar/hotbar-menu.tsx +++ b/src/renderer/components/hotbar/hotbar-menu.tsx @@ -28,7 +28,7 @@ import { HotbarEntityIcon } from "./hotbar-entity-icon"; import { cssNames, IClassName } from "../../utils"; import { catalogEntityRegistry } from "../../api/catalog-entity-registry"; import { defaultHotbarCells, HotbarItem, HotbarStore } from "../../../common/hotbar-store"; -import { CatalogEntity, catalogEntityRunContext } from "../../api/catalog-entity"; +import { CatalogEntity, CatalogEntityContextMenu, catalogEntityRunContext } from "../../api/catalog-entity"; import { DragDropContext, Draggable, Droppable, DropResult } from "react-beautiful-dnd"; import { HotbarSelector } from "./hotbar-selector"; import { HotbarCell } from "./hotbar-cell"; @@ -111,6 +111,12 @@ export class HotbarMenu extends React.Component { renderGrid() { return this.items.map((item, index) => { const entity = this.getEntity(item); + const disabledMenuItems: CatalogEntityContextMenu[] = [ + { + title: "Unpin from Hotbar", + onClick: () => this.removeItem(item.entity.uid) + } + ]; return ( @@ -157,6 +163,7 @@ export class HotbarMenu extends React.Component { uid={item.entity.uid} title={item.entity.name} source={item.entity.source} + menuItems={disabledMenuItems} disabled /> )}