Make EntitySettingRegistry fully injectable (#6604)

* Make EntitySettingRegistry fully injectable

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* Add behavioural tests

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* Fix lint

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* Revert tsconfig change

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* Fix type errors

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* Update snapshot

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* Improve naming

Signed-off-by: Sebastian Malton <sebastian@malton.name>

Signed-off-by: Sebastian Malton <sebastian@malton.name>
This commit is contained in:
Sebastian Malton authored and GitHub committed 2022-11-28 12:13:15 -05:00
1 parent 8897bfc26b
commit 9589175604
51 files changed
+2103 -540

No files matched your search

@@ -0,0 +1,226 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import type { DiContainer } from "@ogre-tools/injectable";
import type { RenderResult } from "@testing-library/react";
import { KubernetesCluster, WebLink } from "../../common/catalog-entities";
import getClusterByIdInjectable from "../../common/cluster-store/get-by-id.injectable";
import type { Cluster } from "../../common/cluster/cluster";
import navigateToEntitySettingsInjectable from "../../common/front-end-routing/routes/entity-settings/navigate-to-entity-settings.injectable";
import catalogEntityRegistryInjectable from "../../renderer/api/catalog/entity/registry.injectable";
import { type ApplicationBuilder, getApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
import createClusterInjectable from "../../renderer/create-cluster/create-cluster.injectable";
describe("Showing correct entity settings", () => {
let builder: ApplicationBuilder;
let rendered: RenderResult;
let windowDi: DiContainer;
let clusterEntity: KubernetesCluster;
let localClusterEntity: KubernetesCluster;
let otherEntity: WebLink;
let cluster: Cluster;
beforeEach(async () => {
builder = getApplicationBuilder();
builder.afterWindowStart((windowDi) => {
const createCluster = windowDi.inject(createClusterInjectable);
clusterEntity = new KubernetesCluster({
metadata: {
labels: {},
name: "some-kubernetes-cluster",
uid: "some-entity-id",
},
spec: {
kubeconfigContext: "some-context",
kubeconfigPath: "/some/path/to/kubeconfig",
},
status: {
phase: "connecting",
},
});
localClusterEntity = new KubernetesCluster({
metadata: {
labels: {},
name: "some-local-kubernetes-cluster",
uid: "some-entity-id-2",
source: "local",
},
spec: {
kubeconfigContext: "some-context",
kubeconfigPath: "/some/path/to/local/kubeconfig",
},
status: {
phase: "connecting",
},
});
otherEntity = new WebLink({
metadata: {
labels: {},
name: "some-weblink",
uid: "some-weblink-id",
},
spec: {
url: "https://my-websome.com",
},
status: {
phase: "available",
},
});
cluster = createCluster({
contextName: clusterEntity.spec.kubeconfigContext,
id: clusterEntity.getId(),
kubeConfigPath: clusterEntity.spec.kubeconfigPath,
}, {
clusterServerUrl: "https://localhost:9999",
});
// TODO: remove once ClusterStore can be used without overriding it
windowDi.override(getClusterByIdInjectable, () => (clusterId) => {
if (clusterId === cluster.id) {
return cluster;
}
return undefined;
});
// TODO: replace with proper entity source once syncing entities between main and windows is injectable
const catalogEntityRegistry = windowDi.inject(catalogEntityRegistryInjectable);
catalogEntityRegistry.updateItems([clusterEntity, otherEntity, localClusterEntity]);
});
rendered = await builder.render();
windowDi = builder.applicationWindow.only.di;
});
it("renders", () => {
expect(rendered.baseElement).toMatchSnapshot();
});
it("does not show entity settings page yet", () => {
expect(rendered.queryByTestId("entity-settings")).not.toBeInTheDocument();
});
describe("when navigating to non-local cluster entity settings", () => {
beforeEach(() => {
const navigateToEntitySettings = windowDi.inject(navigateToEntitySettingsInjectable);
navigateToEntitySettings(clusterEntity.getId());
});
it("renders", () => {
expect(rendered.baseElement).toMatchSnapshot();
});
it("shows entity settings page", () => {
expect(rendered.queryByTestId("entity-settings")).toBeInTheDocument();
});
it("does not show the General setting tab header for non-local cluster", () => {
expect(rendered.queryByTestId("general-tab")).not.toBeInTheDocument();
});
it("shows Proxy setting tab header", () => {
expect(rendered.queryByTestId("proxy-tab")).toBeInTheDocument();
});
it("shows Terminal setting tab header", () => {
expect(rendered.queryByTestId("terminal-tab")).toBeInTheDocument();
});
it("shows Namespaces setting tab header", () => {
expect(rendered.queryByTestId("namespace-tab")).toBeInTheDocument();
});
it("shows Metrics setting tab header", () => {
expect(rendered.queryByTestId("metrics-tab")).toBeInTheDocument();
});
it("shows Node Shell setting tab header", () => {
expect(rendered.queryByTestId("node-shell-tab")).toBeInTheDocument();
});
it("shows the setting tabs in the correct order", () => {
expect(rendered.getByTestId("proxy-tab").nextSibling).toHaveAttribute("data-testid", "terminal-tab");
expect(rendered.getByTestId("terminal-tab").nextSibling).toHaveAttribute("data-testid", "namespace-tab");
expect(rendered.getByTestId("namespace-tab").nextSibling).toHaveAttribute("data-testid", "metrics-tab");
expect(rendered.getByTestId("metrics-tab").nextSibling).toHaveAttribute("data-testid", "node-shell-tab");
});
});
describe("when navigating to local cluster entity settings", () => {
beforeEach(() => {
const navigateToEntitySettings = windowDi.inject(navigateToEntitySettingsInjectable);
navigateToEntitySettings(localClusterEntity.getId());
});
it("renders", () => {
expect(rendered.baseElement).toMatchSnapshot();
});
it("shows entity settings page", () => {
expect(rendered.queryByTestId("entity-settings")).toBeInTheDocument();
});
it("shows the General setting tab header", () => {
expect(rendered.queryByTestId("general-tab")).toBeInTheDocument();
});
it("shows Proxy setting tab header", () => {
expect(rendered.queryByTestId("proxy-tab")).toBeInTheDocument();
});
it("shows Terminal setting tab header", () => {
expect(rendered.queryByTestId("terminal-tab")).toBeInTheDocument();
});
it("shows Namespaces setting tab header", () => {
expect(rendered.queryByTestId("namespace-tab")).toBeInTheDocument();
});
it("shows Metrics setting tab header", () => {
expect(rendered.queryByTestId("metrics-tab")).toBeInTheDocument();
});
it("shows Node Shell setting tab header", () => {
expect(rendered.queryByTestId("node-shell-tab")).toBeInTheDocument();
});
it("shows the setting tabs in the correct order", () => {
expect(rendered.getByTestId("general-tab").nextSibling).toHaveAttribute("data-testid", "proxy-tab");
expect(rendered.getByTestId("proxy-tab").nextSibling).toHaveAttribute("data-testid", "terminal-tab");
expect(rendered.getByTestId("terminal-tab").nextSibling).toHaveAttribute("data-testid", "namespace-tab");
expect(rendered.getByTestId("namespace-tab").nextSibling).toHaveAttribute("data-testid", "metrics-tab");
expect(rendered.getByTestId("metrics-tab").nextSibling).toHaveAttribute("data-testid", "node-shell-tab");
});
});
describe("when navigating to weblink entity settings", () => {
beforeEach(() => {
const navigateToEntitySettings = windowDi.inject(navigateToEntitySettingsInjectable);
navigateToEntitySettings(otherEntity.getId());
});
it("renders", () => {
expect(rendered.baseElement).toMatchSnapshot();
});
it("shows entity settings page", () => {
expect(rendered.queryByTestId("entity-settings")).toBeInTheDocument();
});
it("does not show the unrelated settings", () => {
expect(rendered.queryByTestId("general-tab")).not.toBeInTheDocument();
});
it("shows no settings page info", () => {
expect(rendered.baseElement.querySelector("[data-preference-page-does-not-exist-test='true']")).toBeInTheDocument();
});
});
});
@@ -6,14 +6,16 @@ import { getInjectable } from "@ogre-tools/injectable";
import { navigateToRouteInjectionToken } from "../../../../../common/front-end-routing/navigate-to-route-injection-token";
import preferencesRouteInjectable from "../../../common/preferences-route.injectable";
const navigateToPreferenceTabInjectable = getInjectable({
id: "navigate-to-preference-tab-2",
export type NavigateToPreferenceTab = (tabId: string) => void;
instantiate: (di) => {
const navigateToPreferenceTabInjectable = getInjectable({
id: "navigate-to-preference-tab",
instantiate: (di): NavigateToPreferenceTab => {
const navigateToRoute = di.inject(navigateToRouteInjectionToken);
const route = di.inject(preferencesRouteInjectable);
return (preferenceTabId: string) => {
return (preferenceTabId) => {
navigateToRoute(route, {
withoutAffectingBackButton: true,
parameters: { preferenceTabId },
@@ -3,7 +3,6 @@
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { Tab } from "../../../../renderer/components/tabs";
import navigateToPreferenceTabInjectable from "./navigate-to-preference-tab/navigate-to-preference-tab.injectable";
import { withInjectables } from "@ogre-tools/injectable-react";
import { observer } from "mobx-react";
import type { PreferenceTab } from "../preference-items/preference-item-injection-token";
@@ -12,7 +11,6 @@ import preferenceTabIsActiveInjectable from "./navigate-to-preference-tab/prefer
import React from "react";
interface Dependencies {
navigateToTab: (tabId: string) => void;
tabIsActive: IComputedValue<boolean>;
}
@@ -20,23 +18,21 @@ interface PreferenceNavigationTabProps {
tab: PreferenceTab;
}
const NonInjectedPreferencesNavigationTab = observer(({ navigateToTab, tabIsActive, tab } : Dependencies & PreferenceNavigationTabProps) => (
const NonInjectedPreferencesNavigationTab = observer(({
tabIsActive,
tab,
}: Dependencies & PreferenceNavigationTabProps) => (
<Tab
onClick={() => navigateToTab(tab.pathId)}
active={tabIsActive.get()}
label={tab.label}
data-preference-tab-link-test={tab.pathId}
value={tab.pathId}
/>
));
export const PreferencesNavigationTab = withInjectables<Dependencies, PreferenceNavigationTabProps>(
NonInjectedPreferencesNavigationTab,
{
getProps: (di, props) => ({
navigateToTab: di.inject(navigateToPreferenceTabInjectable),
tabIsActive: di.inject(preferenceTabIsActiveInjectable, props.tab.pathId),
...props,
}),
},
);
export const PreferencesNavigationTab = withInjectables<Dependencies, PreferenceNavigationTabProps>(NonInjectedPreferencesNavigationTab, {
getProps: (di, props) => ({
...props,
tabIsActive: di.inject(preferenceTabIsActiveInjectable, props.tab.pathId),
}),
});
@@ -16,26 +16,33 @@ import { compositeHasDescendant } from "../../../../common/utils/composite/compo
import type { PreferenceTabsRoot } from "../preference-items/preference-tab-root";
import { Icon } from "../../../../renderer/components/icon";
import { checkThatAllDiscriminablesAreExhausted } from "../../../../common/utils/composable-responsibilities/discriminable/discriminable";
import type { NavigateToPreferenceTab } from "./navigate-to-preference-tab/navigate-to-preference-tab.injectable";
import navigateToPreferenceTabInjectable from "./navigate-to-preference-tab/navigate-to-preference-tab.injectable";
interface Dependencies {
composite: IComputedValue<Composite<PreferenceItemTypes | PreferenceTabsRoot>>;
navigateToPreferenceTab: NavigateToPreferenceTab;
}
const NonInjectedPreferencesNavigation = observer(({ composite }: Dependencies) => (
<Tabs className="flex column" scrollable={false}>
const NonInjectedPreferencesNavigation = observer(({
composite,
navigateToPreferenceTab,
}: Dependencies) => (
<Tabs<string>
className="flex column"
scrollable={false}
onChange={navigateToPreferenceTab}
>
{toNavigationHierarchy(composite.get())}
</Tabs>
));
export const PreferencesNavigation = withInjectables<Dependencies>(
NonInjectedPreferencesNavigation,
{
getProps: (di) => ({
composite: di.inject(preferencesCompositeInjectable),
}),
},
);
export const PreferencesNavigation = withInjectables<Dependencies>(NonInjectedPreferencesNavigation, {
getProps: (di) => ({
composite: di.inject(preferencesCompositeInjectable),
navigateToPreferenceTab: di.inject(navigateToPreferenceTabInjectable),
}),
});
const toNavigationHierarchy = (composite: Composite<PreferenceItemTypes | PreferenceTabsRoot>) => {
const value = composite.value;