this.contentElem = e}>
{this.props.children}
diff --git a/src/renderer/components/kube-object-menu/__snapshots__/kube-object-menu.test.tsx.snap b/src/renderer/components/kube-object-menu/__snapshots__/kube-object-menu.test.tsx.snap
new file mode 100644
index 0000000000..c7b3a53142
--- /dev/null
+++ b/src/renderer/components/kube-object-menu/__snapshots__/kube-object-menu.test.tsx.snap
@@ -0,0 +1,371 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`kube-object-menu given kube object renders 1`] = `
+
+
+
+
+
+ Some menu item
+
+
+
+
+ delete
+
+
+
+
+ Delete
+
+
+
+
+
+
+
+ Delete
+
+
+`;
+
+exports[`kube-object-menu given kube object when removing kube object renders 1`] = `
+
+
+
+
+
+ Some menu item
+
+
+
+
+ delete
+
+
+
+
+ Delete
+
+
+
+
+
+
+
+
+
+
+ warning
+
+
+
+
+
+ Remove
+ some-kind
+
+
+ some-namespace/some-name
+
+ from
+
+ Some name
+
+ ?
+
+
+
+
+
+
+
+
+
+
+ Delete
+
+
+`;
+
+exports[`kube-object-menu given kube object with namespace when removing kube object, renders confirmation dialog with namespace 1`] = `
+
+
+
+
+
+ Some menu item
+
+
+
+
+ delete
+
+
+
+
+ Delete
+
+
+
+
+
+
+
+
+
+
+ warning
+
+
+
+
+
+ Remove
+ some-kind
+
+
+ some-namespace/some-name
+
+ from
+
+ Some name
+
+ ?
+
+
+
+
+
+
+
+
+
+
+ Delete
+
+
+`;
+
+exports[`kube-object-menu given kube object without namespace when removing kube object, renders confirmation dialog without namespace 1`] = `
+
+
+
+
+
+ Some menu item
+
+
+
+
+ delete
+
+
+
+
+ Delete
+
+
+
+
+
+
+
+
+
+
+ warning
+
+
+
+
+
+ Remove
+ some-kind
+
+
+ some-name
+
+ from
+
+ Some name
+
+ ?
+
+
+
+
+
+
+
+
+
+
+ Delete
+
+
+`;
+
+exports[`kube-object-menu given no kube object, renders 1`] = `
+
+
+
+
+
+`;
diff --git a/src/renderer/components/kube-object-menu/dependencies/api-manager.injectable.ts b/src/renderer/components/kube-object-menu/dependencies/api-manager.injectable.ts
new file mode 100644
index 0000000000..ecc4614788
--- /dev/null
+++ b/src/renderer/components/kube-object-menu/dependencies/api-manager.injectable.ts
@@ -0,0 +1,32 @@
+/**
+ * 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 type { ApiManager } from "../../../../common/k8s-api/api-manager";
+import { apiManager } from "../../../../common/k8s-api/api-manager";
+import type { Injectable } from "@ogre-tools/injectable";
+import { lifecycleEnum } from "@ogre-tools/injectable";
+
+const apiManagerInjectable: Injectable = {
+ getDependencies: () => ({}),
+ instantiate: () => apiManager,
+ lifecycle: lifecycleEnum.singleton,
+};
+
+export default apiManagerInjectable;
diff --git a/src/renderer/components/kube-object-menu/dependencies/cluster-name.injectable.ts b/src/renderer/components/kube-object-menu/dependencies/cluster-name.injectable.ts
new file mode 100644
index 0000000000..992ceb27be
--- /dev/null
+++ b/src/renderer/components/kube-object-menu/dependencies/cluster-name.injectable.ts
@@ -0,0 +1,41 @@
+/**
+ * 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 type { Injectable } from "@ogre-tools/injectable";
+import { lifecycleEnum } from "@ogre-tools/injectable";
+import type { Cluster } from "../../../../main/cluster";
+import clusterInjectable from "./cluster.injectable";
+
+interface Dependencies {
+ cluster: Cluster;
+}
+
+const clusterNameInjectable: Injectable = {
+ getDependencies: di => ({
+ cluster: di.inject(clusterInjectable),
+ }),
+
+ instantiate: ({ cluster }) => cluster?.name,
+
+ lifecycle: lifecycleEnum.transient,
+};
+
+export default clusterNameInjectable;
diff --git a/src/renderer/components/kube-object-menu/dependencies/cluster.injectable.ts b/src/renderer/components/kube-object-menu/dependencies/cluster.injectable.ts
new file mode 100644
index 0000000000..17c4bab8d3
--- /dev/null
+++ b/src/renderer/components/kube-object-menu/dependencies/cluster.injectable.ts
@@ -0,0 +1,33 @@
+/**
+ * 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 { getActiveClusterEntity } from "../../../api/catalog-entity-registry";
+
+import type { Injectable } from "@ogre-tools/injectable";
+import { lifecycleEnum } from "@ogre-tools/injectable";
+import type { Cluster } from "../../../../main/cluster";
+
+const clusterInjectable: Injectable = {
+ getDependencies: () => ({}),
+ instantiate: () => getActiveClusterEntity(),
+ lifecycle: lifecycleEnum.transient,
+};
+
+export default clusterInjectable;
diff --git a/src/renderer/components/kube-object-menu/dependencies/edit-resource-tab.injectable.ts b/src/renderer/components/kube-object-menu/dependencies/edit-resource-tab.injectable.ts
new file mode 100644
index 0000000000..d11a4b95a6
--- /dev/null
+++ b/src/renderer/components/kube-object-menu/dependencies/edit-resource-tab.injectable.ts
@@ -0,0 +1,31 @@
+/**
+ * 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 { editResourceTab } from "../../dock/edit-resource.store";
+import type { Injectable } from "@ogre-tools/injectable";
+import { lifecycleEnum } from "@ogre-tools/injectable";
+
+const editResourceTabInjectable: Injectable = {
+ getDependencies: () => ({}),
+ instantiate: () => editResourceTab,
+ lifecycle: lifecycleEnum.singleton,
+};
+
+export default editResourceTabInjectable;
diff --git a/src/renderer/components/kube-object-menu/dependencies/hide-details.injectable.ts b/src/renderer/components/kube-object-menu/dependencies/hide-details.injectable.ts
new file mode 100644
index 0000000000..1f86eafc23
--- /dev/null
+++ b/src/renderer/components/kube-object-menu/dependencies/hide-details.injectable.ts
@@ -0,0 +1,31 @@
+/**
+ * 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 { hideDetails } from "../../kube-detail-params";
+import type { Injectable } from "@ogre-tools/injectable";
+import { lifecycleEnum } from "@ogre-tools/injectable";
+
+export const hideDetailsInjectable: Injectable = {
+ getDependencies: () => ({}),
+ instantiate: () => hideDetails,
+ lifecycle: lifecycleEnum.singleton,
+};
+
+export default hideDetailsInjectable;
diff --git a/src/renderer/components/kube-object-menu/dependencies/kube-object-menu-items/get-kube-object-menu-items.ts b/src/renderer/components/kube-object-menu/dependencies/kube-object-menu-items/get-kube-object-menu-items.ts
new file mode 100644
index 0000000000..f027b8667c
--- /dev/null
+++ b/src/renderer/components/kube-object-menu/dependencies/kube-object-menu-items/get-kube-object-menu-items.ts
@@ -0,0 +1,43 @@
+/**
+ * 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 type { KubeObjectMenuRegistry } from "../../../../../extensions/registries";
+import type { KubeObject } from "../../../../../common/k8s-api/kube-object";
+
+export interface Dependencies {
+ kubeObjectMenuRegistry: KubeObjectMenuRegistry;
+}
+
+export interface InstantiationParameter {
+ kubeObject: KubeObject;
+}
+
+export const getKubeObjectMenuItems = (
+ { kubeObjectMenuRegistry }: Dependencies,
+ { kubeObject }: InstantiationParameter,
+) => {
+ if (!kubeObject) {
+ return [];
+ }
+
+ return kubeObjectMenuRegistry
+ .getItemsForKind(kubeObject.kind, kubeObject.apiVersion)
+ .map(item => item.components.MenuItem);
+};
diff --git a/src/renderer/components/kube-object-menu/dependencies/kube-object-menu-items/kube-object-menu-items.injectable.ts b/src/renderer/components/kube-object-menu/dependencies/kube-object-menu-items/kube-object-menu-items.injectable.ts
new file mode 100644
index 0000000000..fd4b28c93d
--- /dev/null
+++ b/src/renderer/components/kube-object-menu/dependencies/kube-object-menu-items/kube-object-menu-items.injectable.ts
@@ -0,0 +1,44 @@
+/**
+ * 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 { Injectable, lifecycleEnum } from "@ogre-tools/injectable";
+import kubeObjectMenuRegistryInjectable from "./kube-object-menu-registry.injectable";
+
+import {
+ InstantiationParameter,
+ Dependencies,
+ getKubeObjectMenuItems,
+} from "./get-kube-object-menu-items";
+
+const kubeObjectMenuItemsInjectable: Injectable<
+ ReturnType,
+ Dependencies,
+ InstantiationParameter
+> = {
+ getDependencies: di => ({
+ kubeObjectMenuRegistry: di.inject(kubeObjectMenuRegistryInjectable),
+ }),
+
+ instantiate: getKubeObjectMenuItems,
+
+ lifecycle: lifecycleEnum.transient,
+};
+
+export default kubeObjectMenuItemsInjectable;
diff --git a/src/renderer/components/kube-object-menu/dependencies/kube-object-menu-items/kube-object-menu-registry.injectable.ts b/src/renderer/components/kube-object-menu/dependencies/kube-object-menu-items/kube-object-menu-registry.injectable.ts
new file mode 100644
index 0000000000..cb52cd7322
--- /dev/null
+++ b/src/renderer/components/kube-object-menu/dependencies/kube-object-menu-items/kube-object-menu-registry.injectable.ts
@@ -0,0 +1,31 @@
+/**
+ * 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 { KubeObjectMenuRegistry } from "../../../../../extensions/registries";
+import type { Injectable } from "@ogre-tools/injectable";
+import { lifecycleEnum } from "@ogre-tools/injectable";
+
+const kubeObjectMenuRegistryInjectable: Injectable = {
+ getDependencies: () => ({}),
+ instantiate: () => KubeObjectMenuRegistry.getInstance(),
+ lifecycle: lifecycleEnum.singleton,
+};
+
+export default kubeObjectMenuRegistryInjectable;
diff --git a/src/renderer/components/kube-object-menu/index.ts b/src/renderer/components/kube-object-menu/index.ts
index 43cd5ea4a0..2a9f7fb5c6 100644
--- a/src/renderer/components/kube-object-menu/index.ts
+++ b/src/renderer/components/kube-object-menu/index.ts
@@ -19,4 +19,5 @@
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
-export * from "./kube-object-menu";
+export type { KubeObjectMenuProps } from "./kube-object-menu";
+export { KubeObjectMenu } from "./kube-object-menu-container";
diff --git a/src/renderer/components/kube-object-menu/kube-object-menu-container.tsx b/src/renderer/components/kube-object-menu/kube-object-menu-container.tsx
new file mode 100644
index 0000000000..9ac49a131e
--- /dev/null
+++ b/src/renderer/components/kube-object-menu/kube-object-menu-container.tsx
@@ -0,0 +1,24 @@
+/**
+ * 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 { getInjectedComponent } from "@ogre-tools/injectable-react";
+import KubeObjectMenuInjectable from "./kube-object-menu.injectable";
+
+export const KubeObjectMenu = getInjectedComponent(KubeObjectMenuInjectable);
diff --git a/src/renderer/components/kube-object-menu/kube-object-menu.injectable.tsx b/src/renderer/components/kube-object-menu/kube-object-menu.injectable.tsx
new file mode 100644
index 0000000000..fdc7851854
--- /dev/null
+++ b/src/renderer/components/kube-object-menu/kube-object-menu.injectable.tsx
@@ -0,0 +1,60 @@
+/**
+ * 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 React from "react";
+
+import {
+ KubeObjectMenu,
+ KubeObjectMenuDependencies,
+ KubeObjectMenuProps,
+} from "./kube-object-menu";
+
+import type { KubeObject } from "../../../common/k8s-api/kube-object";
+import { lifecycleEnum, Injectable } from "@ogre-tools/injectable";
+import apiManagerInjectable from "./dependencies/api-manager.injectable";
+import clusterNameInjectable from "./dependencies/cluster-name.injectable";
+import editResourceTabInjectable from "./dependencies/edit-resource-tab.injectable";
+import hideDetailsInjectable from "./dependencies/hide-details.injectable";
+import kubeObjectMenuItemsInjectable from "./dependencies/kube-object-menu-items/kube-object-menu-items.injectable";
+
+const KubeObjectMenuInjectable: Injectable<
+ JSX.Element,
+ KubeObjectMenuDependencies,
+ KubeObjectMenuProps
+> = {
+ getDependencies: (di, props) => ({
+ clusterName: di.inject(clusterNameInjectable),
+ apiManager: di.inject(apiManagerInjectable),
+ editResourceTab: di.inject(editResourceTabInjectable),
+ hideDetails: di.inject(hideDetailsInjectable),
+
+ kubeObjectMenuItems: di.inject(kubeObjectMenuItemsInjectable, {
+ kubeObject: props.object,
+ }),
+ }),
+
+ instantiate: (dependencies, props) => (
+
+ ),
+
+ lifecycle: lifecycleEnum.transient,
+};
+
+export default KubeObjectMenuInjectable;
diff --git a/src/renderer/components/kube-object-menu/kube-object-menu.test.tsx b/src/renderer/components/kube-object-menu/kube-object-menu.test.tsx
new file mode 100644
index 0000000000..d626065004
--- /dev/null
+++ b/src/renderer/components/kube-object-menu/kube-object-menu.test.tsx
@@ -0,0 +1,284 @@
+/**
+ * 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 React from "react";
+import { screen } from "@testing-library/react";
+import "@testing-library/jest-dom/extend-expect";
+import { KubeObject } from "../../../common/k8s-api/kube-object";
+import userEvent from "@testing-library/user-event";
+import type { ConfigurableDependencyInjectionContainer } from "@ogre-tools/injectable";
+import type { KubeObjectMenuRegistration } from "../../../extensions/registries";
+import { KubeObjectMenuRegistry } from "../../../extensions/registries";
+import { ConfirmDialog } from "../confirm-dialog";
+import asyncFn, { AsyncFnMock } from "@async-fn/jest";
+import { getDiForUnitTesting } from "../getDiForUnitTesting";
+
+import clusterInjectable from "./dependencies/cluster.injectable";
+import hideDetailsInjectable from "./dependencies/hide-details.injectable";
+import editResourceTabInjectable from "./dependencies/edit-resource-tab.injectable";
+import { TabKind } from "../dock/dock.store";
+import kubeObjectMenuRegistryInjectable from "./dependencies/kube-object-menu-items/kube-object-menu-registry.injectable";
+import { DiRender, renderFor } from "../test-utils/renderFor";
+import type { Cluster } from "../../../main/cluster";
+import type { ApiManager } from "../../../common/k8s-api/api-manager";
+import apiManagerInjectable from "./dependencies/api-manager.injectable";
+import { KubeObjectMenu } from "./index";
+
+describe("kube-object-menu", () => {
+ let di: ConfigurableDependencyInjectionContainer;
+ let render: DiRender;
+
+ beforeEach(() => {
+ di = getDiForUnitTesting();
+
+ // TODO: Remove global shared state
+ KubeObjectMenuRegistry.resetInstance();
+ KubeObjectMenuRegistry.createInstance();
+
+ render = renderFor(di);
+
+ di.override(clusterInjectable, {
+ name: "Some name",
+ } as Cluster);
+
+ di.override(apiManagerInjectable, {
+ // eslint-disable-next-line unused-imports/no-unused-vars-ts
+ getStore: api => undefined,
+ } as ApiManager);
+
+ di.override(hideDetailsInjectable, () => {});
+
+ di.override(editResourceTabInjectable, () => ({
+ id: "irrelevant",
+ kind: TabKind.TERMINAL,
+ pinned: false,
+ title: "irrelevant",
+ }));
+
+ addDynamicMenuItem({
+ di,
+ apiVersions: ["some-api-version"],
+ kind: "some-kind",
+ });
+
+ addDynamicMenuItem({
+ di,
+ apiVersions: ["some-unrelated-api-version"],
+ kind: "some-kind",
+ });
+
+ addDynamicMenuItem({
+ di,
+ apiVersions: ["some-api-version"],
+ kind: "some-unrelated-kind",
+ });
+ });
+
+ it("given no cluster, does not crash", () => {
+ di.override(clusterInjectable, null);
+
+ expect(() => {
+ render();
+ }).not.toThrow();
+ });
+
+ it("given no kube object, renders", () => {
+ const { baseElement } = render(
+ ,
+ );
+
+ expect(baseElement).toMatchSnapshot();
+ });
+
+ describe("given kube object", () => {
+ let baseElement: Element;
+ let removeActionMock: AsyncFnMock;
+
+ beforeEach(async () => {
+ const objectStub = KubeObject.create({
+ apiVersion: "some-api-version",
+ kind: "some-kind",
+ metadata: {
+ uid: "some-uid",
+ name: "some-name",
+ resourceVersion: "some-resource-version",
+ namespace: "some-namespace",
+ },
+ });
+
+ removeActionMock = asyncFn();
+
+ ({ baseElement } = render(
+