diff --git a/integration/__tests__/cluster-pages.tests.ts b/integration/__tests__/cluster-pages.tests.ts index 24ad38dcfc..9fa04500b8 100644 --- a/integration/__tests__/cluster-pages.tests.ts +++ b/integration/__tests__/cluster-pages.tests.ts @@ -45,7 +45,6 @@ describe("Lens cluster pages", () => { utils.describeIf(ready)("test common pages", () => { let clusterAdded = false; const addCluster = async () => { - await app.client.waitUntilTextExists("div", "Catalog"); await waitForMinikubeDashboard(app); await app.client.click('a[href="/nodes"]'); await app.client.waitUntilTextExists("div.TableCell", "Ready"); diff --git a/integration/helpers/minikube.ts b/integration/helpers/minikube.ts index bbe411047b..8698bd6be2 100644 --- a/integration/helpers/minikube.ts +++ b/integration/helpers/minikube.ts @@ -65,6 +65,7 @@ export async function waitForMinikubeDashboard(app: Application) { await app.client.waitUntilTextExists("div.TableCell", "minikube"); await app.client.click("div.TableRow"); await app.client.waitUntilTextExists("div.drawer-title-text", "KubernetesCluster: minikube"); + await app.client.waitForExist("div.EntityIcon div.HotbarIcon div div.MuiAvatar-root"); await app.client.click("div.EntityIcon div.HotbarIcon div div.MuiAvatar-root"); await app.client.waitUntilTextExists("pre.kube-auth-out", "Authentication proxy started"); await app.client.waitForExist(`iframe[name="minikube"]`); diff --git a/integration/helpers/utils.ts b/integration/helpers/utils.ts index 9ce33b21c3..b509b3d342 100644 --- a/integration/helpers/utils.ts +++ b/integration/helpers/utils.ts @@ -99,8 +99,8 @@ export async function appStart() { } export async function showCatalog(app: Application) { - await app.client.waitUntilTextExists("[data-test-id=catalog-link]", "Catalog"); - await app.client.click("[data-test-id=catalog-link]"); + await app.client.waitForExist("#hotbarIcon-catalog-entity .Icon"); + await app.client.click("#hotbarIcon-catalog-entity .Icon"); } type AsyncPidGetter = () => Promise; diff --git a/src/common/__tests__/hotbar-store.test.ts b/src/common/__tests__/hotbar-store.test.ts index 51002fee23..9f54e8731d 100644 --- a/src/common/__tests__/hotbar-store.test.ts +++ b/src/common/__tests__/hotbar-store.test.ts @@ -156,6 +156,13 @@ describe("HotbarStore", () => { expect(hotbarStore.getActive().items.length).toEqual(12); }); + it("initially adds catalog entity as first item", () => { + const hotbarStore = HotbarStore.createInstance(); + + hotbarStore.load(); + expect(hotbarStore.getActive().items[0].entity.name).toEqual("Catalog"); + }); + it("adds items", () => { const hotbarStore = HotbarStore.createInstance(); @@ -163,7 +170,7 @@ describe("HotbarStore", () => { hotbarStore.addToHotbar(testCluster); const items = hotbarStore.getActive().items.filter(Boolean); - expect(items.length).toEqual(1); + expect(items.length).toEqual(2); }); it("removes items", () => { @@ -172,6 +179,7 @@ describe("HotbarStore", () => { hotbarStore.load(); hotbarStore.addToHotbar(testCluster); hotbarStore.removeFromHotbar("test"); + hotbarStore.removeFromHotbar("catalog-entity"); const items = hotbarStore.getActive().items.filter(Boolean); expect(items.length).toEqual(0); @@ -185,7 +193,7 @@ describe("HotbarStore", () => { hotbarStore.removeFromHotbar("invalid uid"); const items = hotbarStore.getActive().items.filter(Boolean); - expect(items.length).toEqual(1); + expect(items.length).toEqual(2); }); it("moves item to empty cell", () => { @@ -196,12 +204,12 @@ describe("HotbarStore", () => { hotbarStore.addToHotbar(minikubeCluster); hotbarStore.addToHotbar(awsCluster); - expect(hotbarStore.getActive().items[5]).toBeNull(); + expect(hotbarStore.getActive().items[6]).toBeNull(); hotbarStore.restackItems(1, 5); expect(hotbarStore.getActive().items[5]).toBeTruthy(); - expect(hotbarStore.getActive().items[5].entity.uid).toEqual("minikube"); + expect(hotbarStore.getActive().items[5].entity.uid).toEqual("test"); }); it("moves items down", () => { @@ -212,12 +220,12 @@ describe("HotbarStore", () => { hotbarStore.addToHotbar(minikubeCluster); hotbarStore.addToHotbar(awsCluster); - // aws -> test - hotbarStore.restackItems(2, 0); + // aws -> catalog + hotbarStore.restackItems(3, 0); const items = hotbarStore.getActive().items.map(item => item?.entity.uid || null); - expect(items.slice(0, 4)).toEqual(["aws", "test", "minikube", null]); + expect(items.slice(0, 4)).toEqual(["aws", "catalog-entity", "test", "minikube"]); }); it("moves items up", () => { @@ -229,11 +237,11 @@ describe("HotbarStore", () => { hotbarStore.addToHotbar(awsCluster); // test -> aws - hotbarStore.restackItems(0, 2); + hotbarStore.restackItems(1, 3); const items = hotbarStore.getActive().items.map(item => item?.entity.uid || null); - expect(items.slice(0, 4)).toEqual(["minikube", "aws", "test", null]); + expect(items.slice(0, 4)).toEqual(["catalog-entity", "minikube", "aws", "test"]); }); it("does nothing when item moved to same cell", () => { @@ -241,9 +249,9 @@ describe("HotbarStore", () => { hotbarStore.load(); hotbarStore.addToHotbar(testCluster); - hotbarStore.restackItems(0, 0); + hotbarStore.restackItems(1, 1); - expect(hotbarStore.getActive().items[0].entity.uid).toEqual("test"); + expect(hotbarStore.getActive().items[1].entity.uid).toEqual("test"); }); it("new items takes first empty cell", () => { diff --git a/src/common/catalog-entities/general.ts b/src/common/catalog-entities/general.ts new file mode 100644 index 0000000000..5d13eeabee --- /dev/null +++ b/src/common/catalog-entities/general.ts @@ -0,0 +1,76 @@ +/** + * 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 { navigate } from "../../renderer/navigation"; +import { CatalogCategory, CatalogEntity, CatalogEntityMetadata, CatalogEntitySpec, CatalogEntityStatus } from "../catalog"; +import { catalogCategoryRegistry } from "../catalog/catalog-category-registry"; + +interface GeneralEntitySpec extends CatalogEntitySpec { + path: string; + icon?: { + material?: string; + background?: string; + }; +} + +export class GeneralEntity extends CatalogEntity { + public readonly apiVersion = "entity.k8slens.dev/v1alpha1"; + public readonly kind = "General"; + + async onRun() { + navigate(this.spec.path); + } + + public onSettingsOpen(): void { + return; + } + + public onDetailsOpen(): void { + return; + } + + public onContextMenuOpen(): void { + return; + } +} + +export class GeneralCategory extends CatalogCategory { + public readonly apiVersion = "catalog.k8slens.dev/v1alpha1"; + public readonly kind = "CatalogCategory"; + public metadata = { + name: "General", + icon: "settings" + }; + public spec = { + group: "entity.k8slens.dev", + versions: [ + { + name: "v1alpha1", + entityClass: GeneralEntity + } + ], + names: { + kind: "General" + } + }; +} + +catalogCategoryRegistry.add(new GeneralCategory()); diff --git a/src/common/catalog-entities/index.ts b/src/common/catalog-entities/index.ts index 621383c6ec..ee8a41b552 100644 --- a/src/common/catalog-entities/index.ts +++ b/src/common/catalog-entities/index.ts @@ -19,5 +19,6 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +export * from "./general"; export * from "./kubernetes-cluster"; export * from "./web-link"; diff --git a/src/common/catalog-entities/kubernetes-cluster.ts b/src/common/catalog-entities/kubernetes-cluster.ts index 1f28f3453f..322675b23a 100644 --- a/src/common/catalog-entities/kubernetes-cluster.ts +++ b/src/common/catalog-entities/kubernetes-cluster.ts @@ -27,9 +27,10 @@ import { requestMain } from "../ipc"; import { CatalogCategory, CatalogCategorySpec } from "../catalog"; import { addClusterURL } from "../routes"; import { app } from "electron"; +import type { CatalogEntitySpec } from "../catalog/catalog-entity"; import { HotbarStore } from "../hotbar-store"; -export type KubernetesClusterPrometheusMetrics = { +export interface KubernetesClusterPrometheusMetrics { address?: { namespace: string; service: string; @@ -37,17 +38,19 @@ export type KubernetesClusterPrometheusMetrics = { prefix: string; }; type?: string; -}; + icon?: { + src?: string; + }; +} -export type KubernetesClusterSpec = { +export interface KubernetesClusterSpec extends CatalogEntitySpec { kubeconfigPath: string; kubeconfigContext: string; - iconData?: string; metrics?: { source: string; prometheus?: KubernetesClusterPrometheusMetrics; } -}; +} export interface KubernetesClusterStatus extends CatalogEntityStatus { phase: "connected" | "disconnected" | "deleting"; diff --git a/src/common/catalog/catalog-entity.ts b/src/common/catalog/catalog-entity.ts index 8b8d04f6cb..bc3e360a7b 100644 --- a/src/common/catalog/catalog-entity.ts +++ b/src/common/catalog/catalog-entity.ts @@ -149,6 +149,7 @@ export interface CatalogEntityAddMenuContext { export type CatalogEntitySpec = Record; + export interface CatalogEntityData< Metadata extends CatalogEntityMetadata = CatalogEntityMetadata, Status extends CatalogEntityStatus = CatalogEntityStatus, diff --git a/src/common/hotbar-store.ts b/src/common/hotbar-store.ts index 6d15ace11e..ab41583b0a 100644 --- a/src/common/hotbar-store.ts +++ b/src/common/hotbar-store.ts @@ -26,6 +26,7 @@ import * as uuid from "uuid"; import isNull from "lodash/isNull"; import { toJS } from "./utils"; import { CatalogEntity } from "./catalog"; +import { catalogEntity } from "../main/catalog-sources/general"; export interface HotbarItem { entity: { @@ -91,6 +92,16 @@ export class HotbarStore extends BaseStore { return this.hotbarIndex(this.activeHotbarId); } + get defaultHotbarInitialItems() { + const { metadata: { uid, name, source } } = catalogEntity; + const initialItem = { entity: { uid, name, source }}; + + return [ + initialItem, + ...Array.from(Array(defaultHotbarCells - 1).fill(null)) + ]; + } + get initialItems() { return [...Array.from(Array(defaultHotbarCells).fill(null))]; } @@ -100,7 +111,7 @@ export class HotbarStore extends BaseStore { this.hotbars = [{ id: uuid.v4(), name: "Default", - items: this.initialItems, + items: this.defaultHotbarInitialItems, }]; } else { this.hotbars = data.hotbars; diff --git a/src/extensions/registries/welcome-menu-registry.ts b/src/extensions/registries/welcome-menu-registry.ts index 7092028459..681de6c8f3 100644 --- a/src/extensions/registries/welcome-menu-registry.ts +++ b/src/extensions/registries/welcome-menu-registry.ts @@ -25,6 +25,7 @@ export interface WelcomeMenuRegistration { title: string | (() => string); icon: string; click: () => void | Promise; + testId?: string; } export class WelcomeMenuRegistry extends BaseRegistry {} diff --git a/src/main/catalog-sources/general.ts b/src/main/catalog-sources/general.ts new file mode 100644 index 0000000000..9f64f46b6d --- /dev/null +++ b/src/main/catalog-sources/general.ts @@ -0,0 +1,72 @@ +/** + * 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 { observable } from "mobx"; +import { GeneralEntity } from "../../common/catalog-entities/general"; +import { catalogURL, preferencesURL } from "../../common/routes"; +import { catalogEntityRegistry } from "../catalog"; + +export const catalogEntity = new GeneralEntity({ + metadata: { + uid: "catalog-entity", + name: "Catalog", + source: "app", + labels: {} + }, + spec: { + path: catalogURL(), + icon: { + material: "view_list", + background: "#3d90ce" + } + }, + status: { + phase: "active", + } +}); + +const preferencesEntity = new GeneralEntity({ + metadata: { + uid: "preferences-entity", + name: "Preferences", + source: "app", + labels: {} + }, + spec: { + path: preferencesURL(), + icon: { + material: "settings", + background: "#3d90ce" + } + }, + status: { + phase: "active", + } +}); + +const generalEntities = observable([ + catalogEntity, + preferencesEntity +]); + +export function initializeGeneralEntities() { + catalogEntityRegistry.addObservableSource("lens:general", generalEntities); +} diff --git a/src/main/catalog-sources/index.ts b/src/main/catalog-sources/index.ts index 81f0182ca7..17f383185b 100644 --- a/src/main/catalog-sources/index.ts +++ b/src/main/catalog-sources/index.ts @@ -21,3 +21,4 @@ export { initializeWeblinks } from "./weblinks"; export { KubeconfigSyncManager } from "./kubeconfig-sync"; +export { initializeGeneralEntities } from "./general"; diff --git a/src/main/cluster-manager.ts b/src/main/cluster-manager.ts index 5f2ef9899d..66c9bda601 100644 --- a/src/main/cluster-manager.ts +++ b/src/main/cluster-manager.ts @@ -119,7 +119,7 @@ export class ClusterManager extends Singleton { entity.spec.metrics.prometheus = prometheus; } - entity.spec.iconData = cluster.preferences.icon; + entity.spec.icon.src = cluster.preferences.icon; catalogEntityRegistry.items.splice(index, 1, entity); } @@ -220,7 +220,8 @@ export function catalogEntityFromCluster(cluster: Cluster) { }, spec: { kubeconfigPath: cluster.kubeConfigPath, - kubeconfigContext: cluster.contextName + kubeconfigContext: cluster.contextName, + icon: {} }, status: { phase: cluster.disconnected ? "disconnected" : "connected", diff --git a/src/main/index.ts b/src/main/index.ts index dc36de80dc..d9013cf1ba 100644 --- a/src/main/index.ts +++ b/src/main/index.ts @@ -132,7 +132,7 @@ app.on("ready", async () => { handleWsUpgrade, req => ClusterManager.getInstance().getClusterForRequest(req), ); - + ClusterManager.createInstance().init(); KubeconfigSyncManager.createInstance(); @@ -182,6 +182,7 @@ app.on("ready", async () => { ipcMainOn(IpcRendererNavigationEvents.LOADED, () => { cleanup.push(pushCatalogToRenderer(catalogEntityRegistry)); KubeconfigSyncManager.getInstance().startSync(); + initializers.initializeGeneralEntities(); startUpdateChecking(); LensProtocolRouterMain.getInstance().rendererLoaded = true; }); diff --git a/src/main/initializers/general-entities.ts b/src/main/initializers/general-entities.ts new file mode 100644 index 0000000000..b2e39d8a39 --- /dev/null +++ b/src/main/initializers/general-entities.ts @@ -0,0 +1,22 @@ +/** + * 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. + */ + +export { initializeGeneralEntities } from "../catalog-sources"; diff --git a/src/main/initializers/index.ts b/src/main/initializers/index.ts index 37ff00bd77..6cd9330bac 100644 --- a/src/main/initializers/index.ts +++ b/src/main/initializers/index.ts @@ -24,3 +24,4 @@ export * from "./metrics-providers"; export * from "./ipc"; export * from "./weblinks"; export * from "./stores"; +export * from "./general-entities"; diff --git a/src/renderer/components/+catalog/catalog-entity-details.tsx b/src/renderer/components/+catalog/catalog-entity-details.tsx index b0df7371a6..1a6f0ab03a 100644 --- a/src/renderer/components/+catalog/catalog-entity-details.tsx +++ b/src/renderer/components/+catalog/catalog-entity-details.tsx @@ -63,7 +63,9 @@ export class CatalogEntityDetails extends Component item.onRun(catalogEntityRunContext)} size={128} /> diff --git a/src/renderer/components/+catalog/catalog.tsx b/src/renderer/components/+catalog/catalog.tsx index a55b2ae0af..747adc97c7 100644 --- a/src/renderer/components/+catalog/catalog.tsx +++ b/src/renderer/components/+catalog/catalog.tsx @@ -169,9 +169,12 @@ export class Catalog extends React.Component { uid={item.getId()} title={item.getName()} source={item.source} - icon={item.entity.spec.iconData} + src={item.entity.spec.icon?.src} + material={item.entity.spec.icon?.material} + background={item.entity.spec.icon?.background} onClick={() => this.onDetails(item)} - size={24} /> + size={24} + /> ); } diff --git a/src/renderer/components/+welcome/welcome.tsx b/src/renderer/components/+welcome/welcome.tsx index 703520fa17..d6f24b076b 100644 --- a/src/renderer/components/+welcome/welcome.tsx +++ b/src/renderer/components/+welcome/welcome.tsx @@ -44,7 +44,7 @@ export class Welcome extends React.Component {
    {WelcomeMenuRegistry.getInstance().getItems().map((item, index) => ( -
  • item.click()}> +
  • item.click()} data-testId={item.testId}> {typeof item.title === "string" ? item.title : item.title()}
  • ))} diff --git a/src/renderer/components/avatar/avatar.tsx b/src/renderer/components/avatar/avatar.tsx index 2cf78866f4..cd27497bbb 100644 --- a/src/renderer/components/avatar/avatar.tsx +++ b/src/renderer/components/avatar/avatar.tsx @@ -32,6 +32,7 @@ interface Props extends DOMAttributes, Partial { height?: number; src?: string; className?: string; + background?: string; } function getNameParts(name: string): string[] { @@ -69,11 +70,11 @@ function getIconString(title: string) { } export function Avatar(props: Props) { - const { title, src, width = 32, height = 32, colorHash, ...settings } = props; + const { title, width = 32, height = 32, colorHash, children, background, ...settings } = props; const generateAvatarStyle = (): React.CSSProperties => { return { - backgroundColor: randomColor({ seed: colorHash, luminosity: "dark" }), + backgroundColor: background || randomColor({ seed: colorHash, luminosity: "dark" }), width, height, textTransform: "uppercase" @@ -86,7 +87,7 @@ export function Avatar(props: Props) { style={generateAvatarStyle()} {...settings} > - {getIconString(title)} + {children || getIconString(title)} ); } diff --git a/src/renderer/components/cluster-manager/bottom-bar.scss b/src/renderer/components/cluster-manager/bottom-bar.scss index d89eefdc3e..c09e75889f 100644 --- a/src/renderer/components/cluster-manager/bottom-bar.scss +++ b/src/renderer/components/cluster-manager/bottom-bar.scss @@ -27,18 +27,6 @@ padding: 0 2px; height: var(--bottom-bar-height); - #catalog-link { - font-size: var(--font-size-small); - color: white; - padding: $padding / 4 $padding / 2; - cursor: pointer; - - &:hover { - background-color: #ffffff33; - cursor: pointer; - } - } - .extensions { font-size: var(--font-size-small); color: white; diff --git a/src/renderer/components/cluster-manager/bottom-bar.tsx b/src/renderer/components/cluster-manager/bottom-bar.tsx index 8e37128198..0f61a03833 100644 --- a/src/renderer/components/cluster-manager/bottom-bar.tsx +++ b/src/renderer/components/cluster-manager/bottom-bar.tsx @@ -24,9 +24,6 @@ import "./bottom-bar.scss"; import React from "react"; import { observer } from "mobx-react"; import { StatusBarRegistration, StatusBarRegistry } from "../../../extensions/registries"; -import { navigate } from "../../navigation"; -import { Icon } from "../icon"; -import { catalogURL } from "../../../common/routes"; @observer export class BottomBar extends React.Component { @@ -67,10 +64,6 @@ export class BottomBar extends React.Component { render() { return (
    - {this.renderRegisteredItems()}
    ); diff --git a/src/renderer/components/cluster-settings/components/cluster-icon-settings.tsx b/src/renderer/components/cluster-settings/components/cluster-icon-settings.tsx index 2800586a11..148395872b 100644 --- a/src/renderer/components/cluster-settings/components/cluster-icon-settings.tsx +++ b/src/renderer/components/cluster-settings/components/cluster-icon-settings.tsx @@ -86,7 +86,7 @@ export class ClusterIconSetting extends React.Component { uid={entity.metadata.uid} title={entity.metadata.name} source={entity.metadata.source} - icon={entity.spec.iconData} + src={entity.spec.icon?.src} /> Browse for new icon... diff --git a/src/renderer/components/hotbar/hotbar-entity-icon.tsx b/src/renderer/components/hotbar/hotbar-entity-icon.tsx index bde9347d39..8620db124d 100644 --- a/src/renderer/components/hotbar/hotbar-entity-icon.tsx +++ b/src/renderer/components/hotbar/hotbar-entity-icon.tsx @@ -129,7 +129,9 @@ export class HotbarEntityIcon extends React.Component { uid={entity.metadata.uid} title={entity.metadata.name} source={entity.metadata.source} - icon={entity.spec.iconData} + src={entity.spec.icon?.src} + material={entity.spec.icon?.material} + background={entity.spec.icon?.background} className={className} active={isActive} onMenuOpen={onOpen} diff --git a/src/renderer/components/hotbar/hotbar-icon.scss b/src/renderer/components/hotbar/hotbar-icon.scss index 9e3451ab94..26cc9b4e1e 100644 --- a/src/renderer/components/hotbar/hotbar-icon.scss +++ b/src/renderer/components/hotbar/hotbar-icon.scss @@ -20,7 +20,6 @@ */ .HotbarMenu { - .HotbarIconMenu { left: 30px; min-width: 250px; @@ -126,4 +125,11 @@ } } } + + .materialIcon { + margin-left: 1px; + margin-top: 1px; + text-shadow: none; + font-size: 180%; + } } diff --git a/src/renderer/components/hotbar/hotbar-icon.tsx b/src/renderer/components/hotbar/hotbar-icon.tsx index 7d3008231e..a24e9bb237 100644 --- a/src/renderer/components/hotbar/hotbar-icon.tsx +++ b/src/renderer/components/hotbar/hotbar-icon.tsx @@ -30,18 +30,21 @@ import { Menu, MenuItem } from "../menu"; import { MaterialTooltip } from "../material-tooltip/material-tooltip"; import { observer } from "mobx-react"; import { Avatar } from "../avatar/avatar"; +import { Icon } from "../icon"; export interface HotbarIconProps extends DOMAttributes { uid: string; title: string; source: string; - icon?: string; + src?: string; + material?: string; onMenuOpen?: () => void; className?: IClassName; active?: boolean; menuItems?: CatalogEntityContextMenu[]; disabled?: boolean; size?: number; + background?: string; } function onMenuItemClick(menuItem: CatalogEntityContextMenu) { @@ -62,7 +65,7 @@ function onMenuItemClick(menuItem: CatalogEntityContextMenu) { } export const HotbarIcon = observer(({menuItems = [], size = 40, ...props}: HotbarIconProps) => { - const { uid, title, icon, active, className, source, disabled, onMenuOpen, onClick, children, ...rest } = props; + const { uid, title, src, material, active, className, source, disabled, onMenuOpen, onClick, children, ...rest } = props; const id = `hotbarIcon-${uid}`; const [menuOpen, setMenuOpen] = useState(false); @@ -71,38 +74,28 @@ export const HotbarIcon = observer(({menuItems = [], size = 40, ...props}: Hotba }; const renderIcon = () => { - if (icon) { - return { - if (!disabled) { - onClick?.(event); - } - }} - />; - } else { - return { if (!disabled) { onClick?.(event); } }} - />; - } + > + {material && } + + ); }; return ( -
    +
    {renderIcon()} diff --git a/src/renderer/initializers/welcome-menu-registry.ts b/src/renderer/initializers/welcome-menu-registry.ts index 9fce6a8c61..c5dd6d2724 100644 --- a/src/renderer/initializers/welcome-menu-registry.ts +++ b/src/renderer/initializers/welcome-menu-registry.ts @@ -29,7 +29,8 @@ export function initWelcomeMenuRegistry() { { title: "Browse Clusters", icon: "view_list", - click: () => navigate(catalogURL({ params: { group: "entity.k8slens.dev", kind: "KubernetesCluster" } } )) + click: () => navigate(catalogURL({ params: { group: "entity.k8slens.dev", kind: "KubernetesCluster" } } )), + testId: "browseClustersButton" } ]); }