@@ -213,9 +219,8 @@ export const ClusterPieCharts = observer(() => {
);
};
- const renderContent = () => {
+ const renderContent = ({ metricNodeRole, metricsLoaded }: ClusterOverviewStore) => {
const { masterNodes, workerNodes } = nodesStore;
- const { metricNodeRole, metricsLoaded } = clusterOverviewStore;
const nodes = metricNodeRole === MetricNodeRole.MASTER ? masterNodes : workerNodes;
if (!nodes.length) {
@@ -245,7 +250,17 @@ export const ClusterPieCharts = observer(() => {
return (
- {renderContent()}
+ {renderContent(clusterOverviewStore)}
);
});
+
+export const ClusterPieCharts = withInjectables
(
+ NonInjectedClusterPieCharts,
+
+ {
+ getProps: (di) => ({
+ clusterOverviewStore: di.inject(clusterOverviewStoreInjectable),
+ }),
+ },
+);
diff --git a/src/renderer/components/+events/kube-event-details.tsx b/src/renderer/components/+events/kube-event-details.tsx
index e573f97303..65e87ae5a2 100644
--- a/src/renderer/components/+events/kube-event-details.tsx
+++ b/src/renderer/components/+events/kube-event-details.tsx
@@ -25,21 +25,28 @@ import React from "react";
import { disposeOnUnmount, observer } from "mobx-react";
import { KubeObject } from "../../../common/k8s-api/kube-object";
import { DrawerItem, DrawerTitle } from "../drawer";
-import { cssNames } from "../../utils";
+import { cssNames, Disposer } from "../../utils";
import { LocaleDate } from "../locale-date";
import { eventStore } from "./event.store";
import logger from "../../../common/logger";
-import { kubeWatchApi } from "../../../common/k8s-api/kube-watch-api";
+import type { KubeObjectStore } from "../../../common/k8s-api/kube-object.store";
+import { withInjectables } from "@ogre-tools/injectable-react";
+import kubeWatchApiInjectable
+ from "../../kube-watch-api/kube-watch-api.injectable";
export interface KubeEventDetailsProps {
object: KubeObject;
}
+interface Dependencies {
+ subscribeStores: (stores: KubeObjectStore[]) => Disposer
+}
+
@observer
-export class KubeEventDetails extends React.Component {
+class NonInjectedKubeEventDetails extends React.Component {
componentDidMount() {
disposeOnUnmount(this, [
- kubeWatchApi.subscribeStores([
+ this.props.subscribeStores([
eventStore,
]),
]);
@@ -102,3 +109,17 @@ export class KubeEventDetails extends React.Component {
);
}
}
+
+export const KubeEventDetails = withInjectables(
+ NonInjectedKubeEventDetails,
+
+ {
+ getProps: (di, props) => ({
+ subscribeStores: di.inject(kubeWatchApiInjectable).subscribeStores,
+ ...props,
+ }),
+ },
+);
+
+
+
diff --git a/src/renderer/components/+extensions/__tests__/extensions.test.tsx b/src/renderer/components/+extensions/__tests__/extensions.test.tsx
index 16c927a796..da5c6e72c2 100644
--- a/src/renderer/components/+extensions/__tests__/extensions.test.tsx
+++ b/src/renderer/components/+extensions/__tests__/extensions.test.tsx
@@ -30,13 +30,13 @@ import { ConfirmDialog } from "../../confirm-dialog";
import { Extensions } from "../extensions";
import mockFs from "mock-fs";
import { mockWindow } from "../../../../../__mocks__/windowMock";
-import { AppPaths } from "../../../../common/app-paths";
-import extensionLoaderInjectable
- from "../../../../extensions/extension-loader/extension-loader.injectable";
+import extensionLoaderInjectable from "../../../../extensions/extension-loader/extension-loader.injectable";
import { getDiForUnitTesting } from "../../getDiForUnitTesting";
import { DiRender, renderFor } from "../../test-utils/renderFor";
-import extensionDiscoveryInjectable
- from "../../../../extensions/extension-discovery/extension-discovery.injectable";
+import extensionDiscoveryInjectable from "../../../../extensions/extension-discovery/extension-discovery.injectable";
+import directoryForUserDataInjectable from "../../../../common/app-paths/directory-for-user-data/directory-for-user-data.injectable";
+import directoryForDownloadsInjectable
+ from "../../../../common/app-paths/directory-for-downloads/directory-for-downloads.injectable";
mockWindow();
@@ -59,42 +59,28 @@ jest.mock("../../../../common/utils/downloadFile", () => ({
jest.mock("../../../../common/utils/tar");
-jest.mock("electron", () => ({
- app: {
- getVersion: () => "99.99.99",
- getName: () => "lens",
- setName: jest.fn(),
- setPath: jest.fn(),
- getPath: () => "tmp",
- getLocale: () => "en",
- setLoginItemSettings: jest.fn(),
- },
- ipcMain: {
- on: jest.fn(),
- handle: jest.fn(),
- },
-}));
-
-AppPaths.init();
-
describe("Extensions", () => {
let extensionLoader: ExtensionLoader;
let extensionDiscovery: ExtensionDiscovery;
let render: DiRender;
beforeEach(async () => {
- const di = getDiForUnitTesting();
+ const di = getDiForUnitTesting({ doGeneralOverrides: true });
+
+ di.override(directoryForUserDataInjectable, () => "some-directory-for-user-data");
+ di.override(directoryForDownloadsInjectable, () => "some-directory-for-downloads");
+
+ mockFs({
+ "some-directory-for-user-data": {},
+ });
+
+ await di.runSetups();
render = renderFor(di);
extensionLoader = di.inject(extensionLoaderInjectable);
-
extensionDiscovery = di.inject(extensionDiscoveryInjectable);
- mockFs({
- "tmp": {},
- });
-
extensionLoader.addExtension({
id: "extensionId",
manifest: {
diff --git a/src/renderer/components/+extensions/install-from-select-file-dialog/install-from-select-file-dialog.injectable.ts b/src/renderer/components/+extensions/install-from-select-file-dialog/install-from-select-file-dialog.injectable.ts
index 34af624c46..84fe047576 100644
--- a/src/renderer/components/+extensions/install-from-select-file-dialog/install-from-select-file-dialog.injectable.ts
+++ b/src/renderer/components/+extensions/install-from-select-file-dialog/install-from-select-file-dialog.injectable.ts
@@ -21,11 +21,13 @@
import { getInjectable, lifecycleEnum } from "@ogre-tools/injectable";
import { installFromSelectFileDialog } from "./install-from-select-file-dialog";
import attemptInstallsInjectable from "../attempt-installs/attempt-installs.injectable";
+import directoryForDownloadsInjectable from "../../../../common/app-paths/directory-for-downloads/directory-for-downloads.injectable";
const installFromSelectFileDialogInjectable = getInjectable({
instantiate: (di) =>
installFromSelectFileDialog({
attemptInstalls: di.inject(attemptInstallsInjectable),
+ directoryForDownloads: di.inject(directoryForDownloadsInjectable),
}),
lifecycle: lifecycleEnum.singleton,
diff --git a/src/renderer/components/+extensions/install-from-select-file-dialog/install-from-select-file-dialog.ts b/src/renderer/components/+extensions/install-from-select-file-dialog/install-from-select-file-dialog.ts
index bb8e12e17e..d19efed945 100644
--- a/src/renderer/components/+extensions/install-from-select-file-dialog/install-from-select-file-dialog.ts
+++ b/src/renderer/components/+extensions/install-from-select-file-dialog/install-from-select-file-dialog.ts
@@ -19,18 +19,18 @@
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
import { dialog } from "../../../remote-helpers";
-import { AppPaths } from "../../../../common/app-paths";
import { supportedExtensionFormats } from "../supported-extension-formats";
interface Dependencies {
attemptInstalls: (filePaths: string[]) => Promise
+ directoryForDownloads: string
}
export const installFromSelectFileDialog =
- ({ attemptInstalls }: Dependencies) =>
+ ({ attemptInstalls, directoryForDownloads }: Dependencies) =>
async () => {
const { canceled, filePaths } = await dialog.showOpenDialog({
- defaultPath: AppPaths.get("downloads"),
+ defaultPath: directoryForDownloads,
properties: ["openFile", "multiSelections"],
message: `Select extensions to install (formats: ${supportedExtensionFormats.join(
", ",
diff --git a/src/renderer/components/+namespaces/add-namespace-dialog-model/add-namespace-dialog-model.injectable.ts b/src/renderer/components/+namespaces/add-namespace-dialog-model/add-namespace-dialog-model.injectable.ts
new file mode 100644
index 0000000000..d2667eca06
--- /dev/null
+++ b/src/renderer/components/+namespaces/add-namespace-dialog-model/add-namespace-dialog-model.injectable.ts
@@ -0,0 +1,29 @@
+/**
+ * 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 { getInjectable, lifecycleEnum } from "@ogre-tools/injectable";
+import { AddNamespaceDialogModel } from "./add-namespace-dialog-model";
+
+const addNamespaceDialogModelInjectable = getInjectable({
+ instantiate: () => new AddNamespaceDialogModel(),
+ lifecycle: lifecycleEnum.singleton,
+});
+
+export default addNamespaceDialogModelInjectable;
diff --git a/src/renderer/hooks/useStorage.ts b/src/renderer/components/+namespaces/add-namespace-dialog-model/add-namespace-dialog-model.ts
similarity index 73%
rename from src/renderer/hooks/useStorage.ts
rename to src/renderer/components/+namespaces/add-namespace-dialog-model/add-namespace-dialog-model.ts
index 92ed73ac46..5f4ff9f531 100644
--- a/src/renderer/hooks/useStorage.ts
+++ b/src/renderer/components/+namespaces/add-namespace-dialog-model/add-namespace-dialog-model.ts
@@ -18,17 +18,24 @@
* 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, makeObservable, action } from "mobx";
-import { useState } from "react";
-import { createStorage } from "../utils";
+export class AddNamespaceDialogModel {
+ isOpen = false;
-export function useStorage(key: string, initialValue: T) {
- const storage = createStorage(key, initialValue);
- const [storageValue, setStorageValue] = useState(storage.get());
- const setValue = (value: T) => {
- setStorageValue(value);
- storage.set(value);
+ constructor() {
+ makeObservable(this, {
+ isOpen: observable,
+ open: action,
+ close: action,
+ });
+ }
+
+ open = () => {
+ this.isOpen = true;
};
- return [storageValue, setValue] as [T, (value: T) => void];
+ close = () => {
+ this.isOpen = false;
+ };
}
diff --git a/src/renderer/components/+namespaces/add-namespace-dialog.tsx b/src/renderer/components/+namespaces/add-namespace-dialog.tsx
index e01381efe9..0963c24565 100644
--- a/src/renderer/components/+namespaces/add-namespace-dialog.tsx
+++ b/src/renderer/components/+namespaces/add-namespace-dialog.tsx
@@ -26,38 +26,35 @@ import { observable, makeObservable } from "mobx";
import { observer } from "mobx-react";
import { Dialog, DialogProps } from "../dialog";
import { Wizard, WizardStep } from "../wizard";
-import { namespaceStore } from "./namespace.store";
import type { Namespace } from "../../../common/k8s-api/endpoints";
import { Input } from "../input";
import { systemName } from "../input/input_validators";
import { Notifications } from "../notifications";
+import { withInjectables } from "@ogre-tools/injectable-react";
+import namespaceStoreInjectable from "./namespace-store/namespace-store.injectable";
+import type { AddNamespaceDialogModel } from "./add-namespace-dialog-model/add-namespace-dialog-model";
+import addNamespaceDialogModelInjectable
+ from "./add-namespace-dialog-model/add-namespace-dialog-model.injectable";
interface Props extends DialogProps {
onSuccess?(ns: Namespace): void;
onError?(error: any): void;
}
-const dialogState = observable.object({
- isOpen: false,
-});
+interface Dependencies {
+ createNamespace: (params: { name: string }) => Promise,
+ model: AddNamespaceDialogModel
+}
@observer
-export class AddNamespaceDialog extends React.Component {
+class NonInjectedAddNamespaceDialog extends React.Component {
@observable namespace = "";
- constructor(props: Props) {
+ constructor(props: Props & Dependencies) {
super(props);
makeObservable(this);
}
- static open() {
- dialogState.isOpen = true;
- }
-
- static close() {
- dialogState.isOpen = false;
- }
-
reset = () => {
this.namespace = "";
};
@@ -67,10 +64,10 @@ export class AddNamespaceDialog extends React.Component {
const { onSuccess, onError } = this.props;
try {
- const created = await namespaceStore.create({ name: namespace });
+ const created = await this.props.createNamespace({ name: namespace });
onSuccess?.(created);
- AddNamespaceDialog.close();
+ this.props.close();
} catch (err) {
Notifications.error(err);
onError?.(err);
@@ -78,7 +75,7 @@ export class AddNamespaceDialog extends React.Component {
};
render() {
- const { ...dialogProps } = this.props;
+ const { model, createNamespace, ...dialogProps } = this.props;
const { namespace } = this;
const header = Create Namespace
;
@@ -86,11 +83,11 @@ export class AddNamespaceDialog extends React.Component {