diff --git a/src/common/__tests__/catalog-entity.test.ts b/src/common/__tests__/catalog-entity.test.tsx
similarity index 52%
rename from src/common/__tests__/catalog-entity.test.ts
rename to src/common/__tests__/catalog-entity.test.tsx
index 3785ed1d49..e6d2e939c7 100644
--- a/src/common/__tests__/catalog-entity.test.ts
+++ b/src/common/__tests__/catalog-entity.test.tsx
@@ -3,15 +3,18 @@
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
+import React from "react";
import { CatalogCategory, CatalogCategorySpec } from "../catalog";
-class TestCatalogCategory extends CatalogCategory {
+class TestCatalogCategoryWithoutBadge extends CatalogCategory {
public readonly apiVersion = "catalog.k8slens.dev/v1alpha1";
public readonly kind = "CatalogCategory";
+
public metadata = {
name: "Test Category",
icon: "",
};
+
public spec: CatalogCategorySpec = {
group: "entity.k8slens.dev",
versions: [],
@@ -21,10 +24,28 @@ class TestCatalogCategory extends CatalogCategory {
};
}
+class TestCatalogCategoryWithBadge extends TestCatalogCategoryWithoutBadge {
+ getBadge() {
+ return (
Test Badge
);
+ }
+}
+
describe("CatalogCategory", () => {
it("returns name", () => {
- const category = new TestCatalogCategory();
+ const category = new TestCatalogCategoryWithoutBadge();
expect(category.getName()).toEqual("Test Category");
});
+
+ it("doesn't return badge by default", () => {
+ const category = new TestCatalogCategoryWithoutBadge();
+
+ expect(category.getBadge()).toEqual(null);
+ });
+
+ it("returns a badge", () => {
+ const category = new TestCatalogCategoryWithBadge();
+
+ expect(category.getBadge()).toBeTruthy();
+ });
});
diff --git a/src/common/catalog/catalog-entity.ts b/src/common/catalog/catalog-entity.ts
index 2704bed2e0..7bc396d377 100644
--- a/src/common/catalog/catalog-entity.ts
+++ b/src/common/catalog/catalog-entity.ts
@@ -180,6 +180,15 @@ export abstract class CatalogCategory extends (EventEmitter as new () => TypedEm
return this.metadata.name;
}
+ /**
+ * Get the badge of this category.
+ * Defaults to no badge.
+ * The badge is displayed next to the Category name in the Catalog Category menu
+ */
+ public getBadge(): React.ReactNode {
+ return null;
+ }
+
/**
* Add a filter for menu items of catalogAddMenu
* @param fn The function that should return a truthy value if that menu item should be displayed
diff --git a/src/renderer/components/+catalog/__tests__/catalog-category-label.test.tsx b/src/renderer/components/+catalog/__tests__/catalog-category-label.test.tsx
new file mode 100644
index 0000000000..015929b643
--- /dev/null
+++ b/src/renderer/components/+catalog/__tests__/catalog-category-label.test.tsx
@@ -0,0 +1,53 @@
+/**
+ * Copyright (c) OpenLens Authors. All rights reserved.
+ * Licensed under MIT License. See LICENSE in root directory for more information.
+ */
+
+import { render, screen } from "@testing-library/react";
+import React from "react";
+import "@testing-library/jest-dom/extend-expect";
+import { CatalogCategory, CatalogCategorySpec } from "../../../../common/catalog";
+import { CatalogCategoryLabel } from "../catalog-category-label";
+
+class CatalogCategoryWithoutBadge extends CatalogCategory {
+ public readonly apiVersion = "catalog.k8slens.dev/v1alpha1";
+ public readonly kind = "CatalogCategory";
+
+ public metadata = {
+ name: "Test Category",
+ icon: "",
+ };
+
+ public spec: CatalogCategorySpec = {
+ group: "entity.k8slens.dev",
+ versions: [],
+ names: {
+ kind: "Test",
+ },
+ };
+}
+
+class CatalogCategoryWithBadge extends CatalogCategoryWithoutBadge {
+ getBadge() {
+ return (Test Badge
);
+ }
+}
+
+describe("CatalogCategoryLabel", () => {
+ it("renders without a badge", async () => {
+ const category = new CatalogCategoryWithoutBadge();
+
+ render();
+
+ expect(await screen.findByText("Test Category")).toBeInTheDocument();
+ });
+
+ it("renders with a badge", async () => {
+ const category = new CatalogCategoryWithBadge();
+
+ render();
+
+ expect(await screen.findByText("Test Category")).toBeInTheDocument();
+ expect(await screen.findByText("Test Badge")).toBeInTheDocument();
+ });
+});
diff --git a/src/renderer/components/+catalog/catalog-category-label.tsx b/src/renderer/components/+catalog/catalog-category-label.tsx
new file mode 100644
index 0000000000..170d8e92b6
--- /dev/null
+++ b/src/renderer/components/+catalog/catalog-category-label.tsx
@@ -0,0 +1,24 @@
+/**
+ * Copyright (c) OpenLens Authors. All rights reserved.
+ * Licensed under MIT License. See LICENSE in root directory for more information.
+ */
+import React from "react";
+import type { CatalogCategory } from "../../../common/catalog/catalog-entity";
+
+interface CatalogCategoryLabelProps {
+ category: CatalogCategory;
+}
+
+/**
+ * Display label for Catalog Category for the Catalog menu
+ */
+export const CatalogCategoryLabel = ({ category }: CatalogCategoryLabelProps) => {
+ const badge = category.getBadge();
+
+ return (
+
+
{category.metadata.name}
+ {badge ? (
{badge}
) : null}
+
+ );
+};
diff --git a/src/renderer/components/+catalog/catalog-menu.tsx b/src/renderer/components/+catalog/catalog-menu.tsx
index 2cc543c25f..36590b82a8 100644
--- a/src/renderer/components/+catalog/catalog-menu.tsx
+++ b/src/renderer/components/+catalog/catalog-menu.tsx
@@ -14,6 +14,7 @@ import { StylesProvider } from "@material-ui/core";
import { cssNames } from "../../utils";
import type { CatalogCategory } from "../../api/catalog-entity";
import { observer } from "mobx-react";
+import { CatalogCategoryLabel } from "./catalog-category-label";
export interface CatalogMenuProps {
activeItem: string;
@@ -66,7 +67,7 @@ export const CatalogMenu = observer((props: CatalogMenuProps) => {
icon={getCategoryIcon(category)}
key={category.getId()}
nodeId={category.getId()}
- label={category.metadata.name}
+ label={}
data-testid={`${category.getId()}-tab`}
onClick={() => props.onItemClick(category.getId())}
/>
diff --git a/src/renderer/themes/lens-dark.json b/src/renderer/themes/lens-dark.json
index f30d48197e..f0b8a97282 100644
--- a/src/renderer/themes/lens-dark.json
+++ b/src/renderer/themes/lens-dark.json
@@ -29,6 +29,7 @@
"sidebarActiveColor": "#ffffff",
"sidebarSubmenuActiveColor": "#ffffff",
"sidebarItemHoverBackground": "#3a3e44",
+ "badgeBackgroundColor": "#ffba44",
"buttonPrimaryBackground": "#3d90ce",
"buttonDefaultBackground": "#414448",
"buttonLightBackground": "#f1f1f1",
diff --git a/src/renderer/themes/lens-light.json b/src/renderer/themes/lens-light.json
index 06ef6d79b2..d240d7df8a 100644
--- a/src/renderer/themes/lens-light.json
+++ b/src/renderer/themes/lens-light.json
@@ -29,6 +29,7 @@
"sidebarSubmenuActiveColor": "#3d90ce",
"sidebarBackground": "#e8e8e8",
"sidebarItemHoverBackground": "#f0f2f5",
+ "badgeBackgroundColor": "#ffba44",
"buttonPrimaryBackground": "#3d90ce",
"buttonDefaultBackground": "#414448",
"buttonLightBackground": "#f1f1f1",
diff --git a/src/renderer/themes/theme-vars.css b/src/renderer/themes/theme-vars.css
index e0a695b72d..ffae94e401 100644
--- a/src/renderer/themes/theme-vars.css
+++ b/src/renderer/themes/theme-vars.css
@@ -29,6 +29,7 @@
--sidebarActiveColor: #ffffff;
--sidebarSubmenuActiveColor: #ffffff;
--sidebarItemHoverBackground: #3a3e44;
+--badgeBackgroundColor: #ffba44;
--buttonPrimaryBackground: #3d90ce;
--buttonDefaultBackground: #414448;
--buttonLightBackground: #f1f1f1;
@@ -73,6 +74,8 @@
--dockEditorComment: #808080;
--dockEditorActiveLineBackground: #3a3d41;
--dockBadgeBackground: #36393e;
+--dockTabBorderColor: #43424d;
+--dockTabActiveBackground: #3a3e45;
--logsBackground: #000000;
--logsForeground: #ffffff;
--logRowHoverBackground: #35373a;
@@ -125,7 +128,7 @@
--inputControlHoverBorder: #474a4f;
--lineProgressBackground: #414448;
--radioActiveBackground: #36393e;
---menuActiveBackground: #36393e;
+--menuActiveBackground: #3d90ce;
--menuSelectedOptionBgc: #36393e;
--canvasBackground: #24292e;
--scrollBarColor: #5f6064;