diff --git a/src/extensions/common-api/registrations.ts b/src/extensions/common-api/registrations.ts
index 20512afb22..5178dd9ee4 100644
--- a/src/extensions/common-api/registrations.ts
+++ b/src/extensions/common-api/registrations.ts
@@ -2,13 +2,12 @@
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
-
+export type { StatusBarRegistration } from "../../renderer/components/cluster-manager/status-bar-registration";
export type { AppPreferenceRegistration, AppPreferenceComponents } from "../../renderer/components/+preferences/app-preferences/app-preference-registration";
export type { KubeObjectDetailRegistration, KubeObjectDetailComponents } from "../registries/kube-object-detail-registry";
export type { KubeObjectMenuRegistration, KubeObjectMenuComponents } from "../registries/kube-object-menu-registry";
export type { KubeObjectStatusRegistration } from "../registries/kube-object-status-registry";
export type { PageRegistration, RegisteredPage, PageParams, PageComponentProps, PageComponents, PageTarget } from "../registries/page-registry";
export type { ClusterPageMenuRegistration, ClusterPageMenuComponents } from "../registries/page-menu-registry";
-export type { StatusBarRegistration } from "../registries/status-bar-registry";
export type { ProtocolHandlerRegistration, RouteParams as ProtocolRouteParams, RouteHandler as ProtocolRouteHandler } from "../registries/protocol-handler";
export type { CustomCategoryViewProps, CustomCategoryViewComponents, CustomCategoryViewRegistration } from "../../renderer/components/+catalog/custom-views";
diff --git a/src/extensions/extension-loader/extension-loader.ts b/src/extensions/extension-loader/extension-loader.ts
index afe09cce19..0400431e06 100644
--- a/src/extensions/extension-loader/extension-loader.ts
+++ b/src/extensions/extension-loader/extension-loader.ts
@@ -253,7 +253,6 @@ export class ExtensionLoader {
const removeItems = [
registries.GlobalPageRegistry.getInstance().add(extension.globalPages, extension),
registries.EntitySettingRegistry.getInstance().add(extension.entitySettings),
- registries.StatusBarRegistry.getInstance().add(extension.statusBarItems),
registries.CatalogEntityDetailRegistry.getInstance().add(extension.catalogEntityDetailItems),
];
diff --git a/src/extensions/lens-renderer-extension.ts b/src/extensions/lens-renderer-extension.ts
index 7d511c5504..9104f8871b 100644
--- a/src/extensions/lens-renderer-extension.ts
+++ b/src/extensions/lens-renderer-extension.ts
@@ -18,6 +18,7 @@ import type { CommandRegistration } from "../renderer/components/command-palette
import type { AppPreferenceRegistration } from "../renderer/components/+preferences/app-preferences/app-preference-registration";
import type { AdditionalCategoryColumnRegistration } from "../renderer/components/+catalog/custom-category-columns";
import type { CustomCategoryViewRegistration } from "../renderer/components/+catalog/custom-views";
+import type { StatusBarRegistration } from "../renderer/components/cluster-manager/status-bar-registration";
export class LensRendererExtension extends LensExtension {
globalPages: registries.PageRegistration[] = [];
@@ -26,7 +27,7 @@ export class LensRendererExtension extends LensExtension {
kubeObjectStatusTexts: registries.KubeObjectStatusRegistration[] = [];
appPreferences: AppPreferenceRegistration[] = [];
entitySettings: registries.EntitySettingRegistration[] = [];
- statusBarItems: registries.StatusBarRegistration[] = [];
+ statusBarItems: StatusBarRegistration[] = [];
kubeObjectDetailItems: registries.KubeObjectDetailRegistration[] = [];
kubeObjectMenuItems: registries.KubeObjectMenuRegistration[] = [];
kubeWorkloadsOverviewItems: registries.WorkloadsOverviewDetailRegistration[] = [];
diff --git a/src/extensions/registries/index.ts b/src/extensions/registries/index.ts
index 477f406b2c..464d19cd4e 100644
--- a/src/extensions/registries/index.ts
+++ b/src/extensions/registries/index.ts
@@ -7,7 +7,6 @@
export * from "./page-registry";
export * from "./page-menu-registry";
-export * from "./status-bar-registry";
export * from "./kube-object-detail-registry";
export * from "./kube-object-menu-registry";
export * from "./kube-object-status-registry";
diff --git a/src/renderer/components/cluster-manager/bottom-bar-items.injectable.ts b/src/renderer/components/cluster-manager/bottom-bar-items.injectable.ts
new file mode 100644
index 0000000000..9f32831ca6
--- /dev/null
+++ b/src/renderer/components/cluster-manager/bottom-bar-items.injectable.ts
@@ -0,0 +1,28 @@
+/**
+ * Copyright (c) OpenLens Authors. All rights reserved.
+ * Licensed under MIT License. See LICENSE in root directory for more information.
+ */
+import { getInjectable, lifecycleEnum } from "@ogre-tools/injectable";
+import { computed } from "mobx";
+import rendererExtensionsInjectable from "../../../extensions/renderer-extensions.injectable";
+import type { StatusBarRegistration } from "./status-bar-registration";
+
+const bottomBarItemsInjectable = getInjectable({
+ instantiate: (di) => {
+ const extensions = di.inject(rendererExtensionsInjectable);
+
+ return computed(() =>
+ extensions
+ .get()
+ .flatMap((extension) => extension.statusBarItems)
+ .sort(leftItemsBeforeRight),
+ );
+ },
+
+ lifecycle: lifecycleEnum.singleton,
+});
+
+export default bottomBarItemsInjectable;
+
+const leftItemsBeforeRight = (firstItem: StatusBarRegistration, secondItem: StatusBarRegistration) =>
+ firstItem.components?.position?.localeCompare(secondItem.components?.position);
diff --git a/src/renderer/components/cluster-manager/bottom-bar.test.tsx b/src/renderer/components/cluster-manager/bottom-bar.test.tsx
index 97539f0ea3..ab69395a81 100644
--- a/src/renderer/components/cluster-manager/bottom-bar.test.tsx
+++ b/src/renderer/components/cluster-manager/bottom-bar.test.tsx
@@ -4,10 +4,15 @@
*/
import React from "react";
-import { render } from "@testing-library/react";
import "@testing-library/jest-dom/extend-expect";
import { BottomBar } from "./bottom-bar";
-import { StatusBarRegistry } from "../../../extensions/registries";
+import { getDiForUnitTesting } from "../../getDiForUnitTesting";
+import type { DiRender } from "../test-utils/renderFor";
+import { renderFor } from "../test-utils/renderFor";
+import directoryForUserDataInjectable from "../../../common/app-paths/directory-for-user-data/directory-for-user-data.injectable";
+import { LensRendererExtension } from "../../../extensions/lens-renderer-extension";
+import { computed, IObservableArray, observable, runInAction } from "mobx";
+import rendererExtensionsInjectable from "../../../extensions/renderer-extensions.injectable";
jest.mock("electron", () => ({
app: {
@@ -15,13 +20,43 @@ jest.mock("electron", () => ({
},
}));
-describe("", () => {
- beforeEach(() => {
- StatusBarRegistry.createInstance();
- });
+class SomeTestExtension extends LensRendererExtension {
+ constructor(statusBarItems: IObservableArray) {
+ super({
+ id: 'some-id',
+ absolutePath: "irrelevant",
+ isBundled: false,
+ isCompatible: false,
+ isEnabled: false,
+ manifest: { name: 'some-id', version: "some-version" },
+ manifestPath: "irrelevant",
+ });
- afterEach(() => {
- StatusBarRegistry.resetInstance();
+ this.statusBarItems = statusBarItems;
+ }
+}
+
+describe("", () => {
+ let render: DiRender;
+ let statusBarItems: IObservableArray;
+
+ beforeEach(async () => {
+
+ statusBarItems = observable.array([]);
+
+ const someTestExtension = new SomeTestExtension(statusBarItems);
+
+ const di = getDiForUnitTesting({ doGeneralOverrides: true });
+
+ di.override(directoryForUserDataInjectable, () => 'some-directory-for-user-data')
+
+ di.override(rendererExtensionsInjectable, () => {
+ return computed(() => [someTestExtension]);
+ });
+
+ render = renderFor(di);
+
+ await di.runSetups();
});
it("renders w/o errors", () => {
@@ -30,6 +65,7 @@ describe("", () => {
expect(container).toBeInstanceOf(HTMLElement);
});
+
it.each([
undefined,
"hello",
@@ -39,7 +75,10 @@ describe("", () => {
[{}],
{},
])("renders w/o errors when .getItems() returns not type compliant (%p)", val => {
- StatusBarRegistry.getInstance().getItems = jest.fn().mockImplementationOnce(() => val);
+ runInAction(() => {
+ statusBarItems.replace([val]);
+ })
+
expect(() => render()).not.toThrow();
});
@@ -47,9 +86,12 @@ describe("", () => {
const testId = "testId";
const text = "heee";
- StatusBarRegistry.getInstance().getItems = jest.fn().mockImplementationOnce(() => [
- { item: {text} },
- ]);
+ runInAction(() => {
+ statusBarItems.replace([
+ { item: {text} }
+ ]);
+ })
+
const { getByTestId } = render();
expect(getByTestId(testId)).toHaveTextContent(text);
@@ -59,9 +101,12 @@ describe("", () => {
const testId = "testId";
const text = "heee";
- StatusBarRegistry.getInstance().getItems = jest.fn().mockImplementationOnce(() => [
- { item: () => {text} },
- ]);
+ runInAction(() => {
+ statusBarItems.replace([
+ { item: () => {text} },
+ ]);
+ })
+
const { getByTestId } = render();
expect(getByTestId(testId)).toHaveTextContent(text);
@@ -69,31 +114,33 @@ describe("", () => {
it("sort positioned items properly", () => {
- StatusBarRegistry.getInstance().getItems = jest.fn().mockImplementationOnce(() => [
- {
- components: {
- Item: () => right
,
+ runInAction(() => {
+ statusBarItems.replace([
+ {
+ components: {
+ Item: () => right
,
+ },
},
- },
- {
- components: {
- Item: () => right
,
- position: "right",
+ {
+ components: {
+ Item: () => right
,
+ position: "right",
+ },
},
- },
- {
- components: {
- Item: () => left
,
- position: "left",
+ {
+ components: {
+ Item: () => left
,
+ position: "left",
+ },
},
- },
- {
- components: {
- Item: () => left
,
- position: "left",
+ {
+ components: {
+ Item: () => left
,
+ position: "left",
+ },
},
- },
- ]);
+ ]);
+ });
const { getAllByTestId } = render();
const elems = getAllByTestId("sortedElem");
diff --git a/src/renderer/components/cluster-manager/bottom-bar.tsx b/src/renderer/components/cluster-manager/bottom-bar.tsx
index 84e0f7bbc8..ecbb1634cc 100644
--- a/src/renderer/components/cluster-manager/bottom-bar.tsx
+++ b/src/renderer/components/cluster-manager/bottom-bar.tsx
@@ -7,11 +7,18 @@ import styles from "./bottom-bar.module.scss";
import React from "react";
import { observer } from "mobx-react";
-import { StatusBarRegistration, StatusBarRegistry } from "../../../extensions/registries";
import { cssNames } from "../../utils";
+import { withInjectables } from "@ogre-tools/injectable-react";
+import bottomBarItemsInjectable from "./bottom-bar-items.injectable";
+import type { IComputedValue } from "mobx";
+import type { StatusBarRegistration } from "./status-bar-registration";
+
+interface Dependencies {
+ items: IComputedValue
+}
@observer
-export class BottomBar extends React.Component {
+class NonInjectedBottomBar extends React.Component {
renderRegisteredItem(registration: StatusBarRegistration) {
const { item } = registration;
@@ -23,19 +30,9 @@ export class BottomBar extends React.Component {
}
renderRegisteredItems() {
- const items = StatusBarRegistry.getInstance().getItems();
-
- if (!Array.isArray(items)) {
- return null;
- }
-
- items.sort(function sortLeftPositionFirst(a, b) {
- return a.components?.position?.localeCompare(b.components?.position);
- });
-
return (
<>
- {items.map((registration, index) => {
+ {this.props.items.get().map((registration, index) => {
if (!registration?.item && !registration?.components?.Item) {
return null;
}
@@ -64,3 +61,14 @@ export class BottomBar extends React.Component {
);
}
}
+
+export const BottomBar = withInjectables(
+ NonInjectedBottomBar,
+
+ {
+ getProps: (di, props) => ({
+ items: di.inject(bottomBarItemsInjectable),
+ ...props,
+ }),
+ },
+);
diff --git a/src/extensions/registries/status-bar-registry.ts b/src/renderer/components/cluster-manager/status-bar-registration.d.ts
similarity index 74%
rename from src/extensions/registries/status-bar-registry.ts
rename to src/renderer/components/cluster-manager/status-bar-registration.d.ts
index e8d4661abc..2faea55cc5 100644
--- a/src/extensions/registries/status-bar-registry.ts
+++ b/src/renderer/components/cluster-manager/status-bar-registration.d.ts
@@ -2,12 +2,6 @@
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
-
-// Extensions API -> Status bar customizations
-
-import type React from "react";
-import { BaseRegistry } from "./base-registry";
-
interface StatusBarComponents {
Item?: React.ComponentType;
/**
@@ -28,6 +22,3 @@ export interface StatusBarRegistration extends StatusBarRegistrationV2 {
*/
item?: React.ReactNode;
}
-
-export class StatusBarRegistry extends BaseRegistry {
-}
diff --git a/src/renderer/initializers/registries.ts b/src/renderer/initializers/registries.ts
index 93caeee51e..1c9e5662d4 100644
--- a/src/renderer/initializers/registries.ts
+++ b/src/renderer/initializers/registries.ts
@@ -14,6 +14,5 @@ export function initRegistries() {
registries.KubeObjectDetailRegistry.createInstance();
registries.KubeObjectMenuRegistry.createInstance();
registries.KubeObjectStatusRegistry.createInstance();
- registries.StatusBarRegistry.createInstance();
registries.WorkloadsOverviewDetailRegistry.createInstance();
}