Technical requirements for behavioural unit tests (#5084)

* Implement a lot of technical requirements for behavioural unit tests

Note: the crux of this was to make routing env-agnostic, and not based on URLs as magic strings, but instead something type-enforced.

Note: extension-based routes comply to same exact interface by "late-registering" their routes when installed. Routes are just injectables.

Note: another chunk of global shared state is no more.

Note: a lot of explicit side effects have been cornered to injectables.

Note: a lot of stuff has become reactive as part if this.

Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com>

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Make a directory commonly available

Signed-off-by: Iku-turso <mikko.aspiala@gmail.com>

* Require id for <Select /> to prevent non-deterministic renders

This was caused by global state in a 3rd party lib: "react-select".

Signed-off-by: Iku-turso <mikko.aspiala@gmail.com>

* Specify id for all <Select /> to satisfy previous commit

Signed-off-by: Iku-turso <mikko.aspiala@gmail.com>

* Prevent explicit side effect in component by using existing dependency instead

Signed-off-by: Iku-turso <mikko.aspiala@gmail.com>

* Extract instantiation of "conf" as injectables for causing side effects

Signed-off-by: Iku-turso <mikko.aspiala@gmail.com>

* Introduce a legacy-helper to make gradual refactoring of inheritors of Singleton easier

Signed-off-by: Iku-turso <mikko.aspiala@gmail.com>

* Make legacy unit tests for hotbar green and more simple by using the new legacy helper

Signed-off-by: Iku-turso <mikko.aspiala@gmail.com>

* Temporarily kludge all unit tests green with a disclaimer about allowing side-effects

Signed-off-by: Iku-turso <mikko.aspiala@gmail.com>

* Remove kludge in previous commit by explicitly permitting specific side effects where old unit tests require it

Signed-off-by: Iku-turso <mikko.aspiala@gmail.com>

* Prevent old unit test with side effects from accessing file system

Signed-off-by: Iku-turso <mikko.aspiala@gmail.com>

* Migrate to actual typing for di.permitSideEffects

Signed-off-by: Iku-turso <mikko.aspiala@gmail.com>

* Prevent unit tests from failing because of non-standard method of HTML-element not present in js-dom

Signed-off-by: Iku-turso <mikko.aspiala@gmail.com>

* Adapt integration tests to recent changes

Signed-off-by: Iku-turso <mikko.aspiala@gmail.com>

* Fix code style

Signed-off-by: Iku-turso <mikko.aspiala@gmail.com>

* Fix artifact from bad rebase

Signed-off-by: Iku-turso <mikko.aspiala@gmail.com>

* Add a deprecation from a review comment

Signed-off-by: Iku-turso <mikko.aspiala@gmail.com>

* Remove change that is not required

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Remove redundant comment

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Fix code style

Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com>

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Remove redundant file

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Fix bad merge

Signed-off-by: Iku-turso <mikko.aspiala@gmail.com>

* Improve variable name

Signed-off-by: Iku-turso <mikko.aspiala@gmail.com>

* Tweak logger interface to be more descriptive

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Make injecting legacy singleton always provide new instance

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Remove conditional typing when not needed

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Improve naming of variable

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Remove unnecessary code style changes

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Remove flag for causing side effects from too broad scope

Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com>

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Override side-effects in unit test using injectable instead of monkey patching

Co-authored-by: Janne Savolainen <janne.savolainen@live.fi>

Signed-off-by: Iku-turso <mikko.aspiala@gmail.com>

* Flag some side-effects and add general overrides

Co-authored-by: Janne Savolainen <janne.savolainen@live.fi>

Signed-off-by: Iku-turso <mikko.aspiala@gmail.com>

* Fix unit tests in CI by removing explicit side-effect

Co-authored-by: Janne Savolainen <janne.savolainen@live.fi>

Signed-off-by: Iku-turso <mikko.aspiala@gmail.com>

* Remove explicit side-effect from getting default shell

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Introduce abstraction for getting absolute paths

Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com>

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Switch to using abstraction for getting absolute path to control explicit side effect

Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com>

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Introduce abstraction for joining paths

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Switch to using abstraction for joining paths to control explicit side effect

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Fix fake implementation for join paths

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Fix test after removing explicit side effect

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Remove explicit side effects from kubeconfig-syncs

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Fix arguments after removing explicit side effect

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Make registrators not async for not being needed anymore

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Make generalCatalogEntities non-observable, as there is no requirement

Co-authored-by: Janne Savolainen <janne.savolainen@live.fi>

Signed-off-by: Iku-turso <mikko.aspiala@gmail.com>

* Remove redundant code

Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com>

Signed-off-by: Iku-turso <mikko.aspiala@gmail.com>

* Simplify logic for registering general catalog entity sources

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Add TODO

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Replace function for getting application menu items with reactive solution

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Fix typo in interface name

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Remove global shared state usages of hot bar store

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Remove redundant enum

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

Co-authored-by: Janne Savolainen <janne.savolainen@live.fi>
This commit is contained in:
Iku-tursoandJanne Savolainen authored and GitHub committed 2022-03-31 16:57:05 +03:00
1 parent ab2cd27a27
commit a277cfcf02
583 files changed
+13073 -6556

No files matched your search

@@ -14,22 +14,22 @@ import commandOverlayInjectable, { CommandOverlay } from "./command-overlay.inje
import { isMac } from "../../../common/vars";
import { catalogEntityRegistry } from "../../api/catalog-entity-registry";
import { broadcastMessage, ipcRendererOn } from "../../../common/ipc";
import { getMatchedClusterId } from "../../navigation";
import type { Disposer } from "../../utils";
import { withInjectables } from "@ogre-tools/injectable-react";
import windowAddEventListenerInjectable from "../../window/event-listener.injectable";
export interface CommandContainerProps {
clusterId?: ClusterId;
}
import hostedClusterInjectable from "../../../common/cluster-store/hosted-cluster.injectable";
import type { IComputedValue } from "mobx";
import matchedClusterIdInjectable from "../../navigation/matched-cluster-id.injectable";
interface Dependencies {
addWindowEventListener: <K extends keyof WindowEventMap>(type: K, listener: (this: Window, ev: WindowEventMap[K]) => any, options?: boolean | AddEventListenerOptions) => Disposer;
commandOverlay: CommandOverlay;
clusterId?: ClusterId;
matchedClusterId: IComputedValue<ClusterId>;
}
@observer
class NonInjectedCommandContainer extends React.Component<CommandContainerProps & Dependencies> {
class NonInjectedCommandContainer extends React.Component<Dependencies> {
private escHandler(event: KeyboardEvent) {
const { commandOverlay } = this.props;
@@ -41,7 +41,7 @@ class NonInjectedCommandContainer extends React.Component<CommandContainerProps
handleCommandPalette = () => {
const { commandOverlay } = this.props;
const clusterIsActive = getMatchedClusterId() !== undefined;
const clusterIsActive = this.props.matchedClusterId.get() !== undefined;
if (clusterIsActive) {
broadcastMessage(`command-palette:${catalogEntityRegistry.activeEntity.getId()}:open`);
@@ -95,10 +95,19 @@ class NonInjectedCommandContainer extends React.Component<CommandContainerProps
}
}
export const CommandContainer = withInjectables<Dependencies, CommandContainerProps>(NonInjectedCommandContainer, {
getProps: (di, props) => ({
addWindowEventListener: di.inject(windowAddEventListenerInjectable),
commandOverlay: di.inject(commandOverlayInjectable),
...props,
}),
});
export const CommandContainer = withInjectables<Dependencies>(
NonInjectedCommandContainer,
{
getProps: (di, props) => {
const hostedCluster = di.inject(hostedClusterInjectable);
return {
clusterId: hostedCluster?.id,
addWindowEventListener: di.inject(windowAddEventListenerInjectable),
commandOverlay: di.inject(commandOverlayInjectable),
matchedClusterId: di.inject(matchedClusterIdInjectable),
...props,
};
},
},
);
@@ -79,6 +79,7 @@ const NonInjectedCommandDialog = observer(({ commands, activeEntity, closeComman
return (
<Select
id="command-palette-search-input"
menuPortalTarget={null}
onChange={v => executeAction(v.value)}
components={{
@@ -4,7 +4,6 @@
*/
import React from "react";
import * as routes from "../../../../common/routes";
import { EntitySettingRegistry, RegisteredEntitySetting } from "../../../../extensions/registries";
import { HotbarAddCommand } from "../../hotbar/hotbar-add-command";
import { HotbarRemoveCommand } from "../../hotbar/hotbar-remove-command";
@@ -16,6 +15,28 @@ import { getInjectable } from "@ogre-tools/injectable";
import commandOverlayInjectable from "../command-overlay.injectable";
import createTerminalTabInjectable from "../../dock/terminal/create-terminal-tab.injectable";
import type { DockTabCreate } from "../../dock/dock/store";
import navigateToPreferencesInjectable from "../../../../common/front-end-routing/routes/preferences/navigate-to-preferences.injectable";
import navigateToHelmChartsInjectable from "../../../../common/front-end-routing/routes/cluster/helm/charts/navigate-to-helm-charts.injectable";
import navigateToHelmReleasesInjectable from "../../../../common/front-end-routing/routes/cluster/helm/releases/navigate-to-helm-releases.injectable";
import navigateToConfigMapsInjectable from "../../../../common/front-end-routing/routes/cluster/config/config-maps/navigate-to-config-maps.injectable";
import navigateToSecretsInjectable from "../../../../common/front-end-routing/routes/cluster/config/secrets/navigate-to-secrets.injectable";
import navigateToResourceQuotasInjectable from "../../../../common/front-end-routing/routes/cluster/config/resource-quotas/navigate-to-resource-quotas.injectable";
import navigateToLimitRangesInjectable from "../../../../common/front-end-routing/routes/cluster/config/limit-ranges/navigate-to-limit-ranges.injectable";
import navigateToHorizontalPodAutoscalersInjectable from "../../../../common/front-end-routing/routes/cluster/config/horizontal-pod-autoscalers/navigate-to-horizontal-pod-autoscalers.injectable";
import navigateToPodDisruptionBudgetsInjectable from "../../../../common/front-end-routing/routes/cluster/config/pod-disruption-budgets/navigate-to-pod-disruption-budgets.injectable";
import navigateToServicesInjectable from "../../../../common/front-end-routing/routes/cluster/network/services/navigate-to-services.injectable";
import navigateToEndpointsInjectable from "../../../../common/front-end-routing/routes/cluster/network/endpoints/navigate-to-endpoints.injectable";
import navigateToIngressesInjectable from "../../../../common/front-end-routing/routes/cluster/network/ingresses/navigate-to-ingresses.injectable";
import navigateToNetworkPoliciesInjectable from "../../../../common/front-end-routing/routes/cluster/network/network-policies/navigate-to-network-policies.injectable";
import navigateToNodesInjectable from "../../../../common/front-end-routing/routes/cluster/nodes/navigate-to-nodes.injectable";
import navigateToPodsInjectable from "../../../../common/front-end-routing/routes/cluster/workloads/pods/navigate-to-pods.injectable";
import navigateToDeploymentsInjectable from "../../../../common/front-end-routing/routes/cluster/workloads/deployments/navigate-to-deployments.injectable";
import navigateToDaemonsetsInjectable from "../../../../common/front-end-routing/routes/cluster/workloads/daemonsets/navigate-to-daemonsets.injectable";
import navigateToStatefulsetsInjectable from "../../../../common/front-end-routing/routes/cluster/workloads/statefulsets/navigate-to-statefulsets.injectable";
import navigateToJobsInjectable from "../../../../common/front-end-routing/routes/cluster/workloads/jobs/navigate-to-jobs.injectable";
import navigateToCronJobsInjectable from "../../../../common/front-end-routing/routes/cluster/workloads/cron-jobs/navigate-to-cron-jobs.injectable";
import navigateToCustomResourcesInjectable from "../../../../common/front-end-routing/routes/cluster/custom-resources/custom-resources/navigate-to-custom-resources.injectable";
import navigateToEntitySettingsInjectable from "../../../../common/front-end-routing/routes/entity-settings/navigate-to-entity-settings.injectable";
export function isKubernetesClusterActive(context: CommandContext): boolean {
return context.entity?.kind === "KubernetesCluster";
@@ -25,181 +46,200 @@ interface Dependencies {
openCommandDialog: (component: React.ReactElement) => void;
getEntitySettingItems: (kind: string, apiVersion: string, source?: string) => RegisteredEntitySetting[];
createTerminalTab: () => DockTabCreate;
navigateToPreferences: () => void;
navigateToHelmCharts: () => void;
navigateToHelmReleases: () => void;
navigateToConfigMaps: () => void;
navigateToSecrets: () => void;
navigateToResourceQuotas: () => void;
navigateToLimitRanges: () => void;
navigateToHorizontalPodAutoscalers: () => void;
navigateToPodDisruptionBudgets: () => void;
navigateToServices: () => void;
navigateToEndpoints: () => void;
navigateToIngresses: () => void;
navigateToNetworkPolicies: () => void;
navigateToNodes: () => void;
navigateToPods: () => void;
navigateToDeployments: () => void;
navigateToDaemonsets: () => void;
navigateToStatefulsets: () => void;
navigateToJobs: () => void;
navigateToCronJobs: () => void;
navigateToCustomResources: () => void;
navigateToEntitySettings: (entityId: string) => void;
}
function getInternalCommands({ openCommandDialog, getEntitySettingItems, createTerminalTab }: Dependencies): CommandRegistration[] {
function getInternalCommands(dependencies: Dependencies): CommandRegistration[] {
return [
{
id: "app.showPreferences",
title: "Preferences: Open",
action: ({ navigate }) => navigate(routes.preferencesURL(), {
forceRootFrame: true,
}),
action: () => dependencies.navigateToPreferences(),
},
{
id: "cluster.viewHelmCharts",
title: "Cluster: View Helm Charts",
isActive: isKubernetesClusterActive,
action: ({ navigate }) => navigate(routes.helmChartsURL()),
action: () => dependencies.navigateToHelmCharts(),
},
{
id: "cluster.viewHelmReleases",
title: "Cluster: View Helm Releases",
isActive: isKubernetesClusterActive,
action: ({ navigate }) => navigate(routes.releaseURL()),
action: () => dependencies.navigateToHelmReleases(),
},
{
id: "cluster.viewConfigMaps",
title: "Cluster: View ConfigMaps",
isActive: isKubernetesClusterActive,
action: ({ navigate }) => navigate(routes.configMapsURL()),
action: () => dependencies.navigateToConfigMaps(),
},
{
id: "cluster.viewSecrets",
title: "Cluster: View Secrets",
isActive: isKubernetesClusterActive,
action: ({ navigate }) => navigate(routes.secretsURL()),
action: () => dependencies.navigateToSecrets(),
},
{
id: "cluster.viewResourceQuotas",
title: "Cluster: View ResourceQuotas",
isActive: isKubernetesClusterActive,
action: ({ navigate }) => navigate(routes.resourceQuotaURL()),
action: () => dependencies.navigateToResourceQuotas(),
},
{
id: "cluster.viewLimitRanges",
title: "Cluster: View LimitRanges",
isActive: isKubernetesClusterActive,
action: ({ navigate }) => navigate(routes.limitRangeURL()),
action: () => dependencies.navigateToLimitRanges(),
},
{
id: "cluster.viewHorizontalPodAutoscalers",
title: "Cluster: View HorizontalPodAutoscalers (HPA)",
isActive: isKubernetesClusterActive,
action: ({ navigate }) => navigate(routes.hpaURL()),
action: () => dependencies.navigateToHorizontalPodAutoscalers(),
},
{
id: "cluster.viewPodDisruptionBudget",
title: "Cluster: View PodDisruptionBudgets",
isActive: isKubernetesClusterActive,
action: ({ navigate }) => navigate(routes.pdbURL()),
action: () => dependencies.navigateToPodDisruptionBudgets(),
},
{
id: "cluster.viewServices",
title: "Cluster: View Services",
isActive: isKubernetesClusterActive,
action: ({ navigate }) => navigate(routes.servicesURL()),
action: () => dependencies.navigateToServices(),
},
{
id: "cluster.viewEndpoints",
title: "Cluster: View Endpoints",
isActive: isKubernetesClusterActive,
action: ({ navigate }) => navigate(routes.endpointURL()),
action: () => dependencies.navigateToEndpoints(),
},
{
id: "cluster.viewIngresses",
title: "Cluster: View Ingresses",
isActive: isKubernetesClusterActive,
action: ({ navigate }) => navigate(routes.ingressURL()),
action: () => dependencies.navigateToIngresses(),
},
{
id: "cluster.viewNetworkPolicies",
title: "Cluster: View NetworkPolicies",
isActive: isKubernetesClusterActive,
action: ({ navigate }) => navigate(routes.networkPoliciesURL()),
action: () => dependencies.navigateToNetworkPolicies,
},
{
id: "cluster.viewNodes",
title: "Cluster: View Nodes",
isActive: isKubernetesClusterActive,
action: ({ navigate }) => navigate(routes.nodesURL()),
action: () => dependencies.navigateToNodes(),
},
{
id: "cluster.viewPods",
title: "Cluster: View Pods",
isActive: isKubernetesClusterActive,
action: ({ navigate }) => navigate(routes.podsURL()),
action: () => dependencies.navigateToPods(),
},
{
id: "cluster.viewDeployments",
title: "Cluster: View Deployments",
isActive: isKubernetesClusterActive,
action: ({ navigate }) => navigate(routes.deploymentsURL()),
action: () => dependencies.navigateToDeployments(),
},
{
id: "cluster.viewDaemonSets",
title: "Cluster: View DaemonSets",
isActive: isKubernetesClusterActive,
action: ({ navigate }) => navigate(routes.daemonSetsURL()),
action: () => dependencies.navigateToDaemonsets(),
},
{
id: "cluster.viewStatefulSets",
title: "Cluster: View StatefulSets",
isActive: isKubernetesClusterActive,
action: ({ navigate }) => navigate(routes.statefulSetsURL()),
action: () => dependencies.navigateToStatefulsets(),
},
{
id: "cluster.viewJobs",
title: "Cluster: View Jobs",
isActive: isKubernetesClusterActive,
action: ({ navigate }) => navigate(routes.jobsURL()),
action: () => dependencies.navigateToJobs(),
},
{
id: "cluster.viewCronJobs",
title: "Cluster: View CronJobs",
isActive: isKubernetesClusterActive,
action: ({ navigate }) => navigate(routes.cronJobsURL()),
action: () => dependencies.navigateToCronJobs(),
},
{
id: "cluster.viewCustomResourceDefinitions",
title: "Cluster: View Custom Resource Definitions",
isActive: isKubernetesClusterActive,
action: ({ navigate }) => navigate(routes.crdURL()),
action: () => dependencies.navigateToCustomResources(),
},
{
id: "entity.viewSettings",
title: ({ entity }) => `${entity.kind}/${entity.getName()}: View Settings`,
action: ({ entity, navigate }) => navigate(`/entity/${entity.getId()}/settings`, {
forceRootFrame: true,
}),
action: ({ entity }) => dependencies.navigateToEntitySettings(entity.getId()),
isActive: ({ entity }) => {
if (!entity) {
return false;
}
return getEntitySettingItems(entity.kind, entity.apiVersion, entity.metadata.source).length > 0;
return dependencies.getEntitySettingItems(entity.kind, entity.apiVersion, entity.metadata.source).length > 0;
},
},
{
id: "cluster.openTerminal",
title: "Cluster: Open terminal",
action: () => createTerminalTab(),
action: () => dependencies.createTerminalTab(),
isActive: isKubernetesClusterActive,
},
{
id: "hotbar.switchHotbar",
title: "Hotbar: Switch ...",
action: () => openCommandDialog(<HotbarSwitchCommand />),
action: () => dependencies.openCommandDialog(<HotbarSwitchCommand />),
},
{
id: "hotbar.addHotbar",
title: "Hotbar: Add Hotbar ...",
action: () => openCommandDialog(<HotbarAddCommand />),
action: () => dependencies.openCommandDialog(<HotbarAddCommand />),
},
{
id: "hotbar.removeHotbar",
title: "Hotbar: Remove Hotbar ...",
action: () => openCommandDialog(<HotbarRemoveCommand />),
action: () => dependencies.openCommandDialog(<HotbarRemoveCommand />),
},
{
id: "hotbar.renameHotbar",
title: "Hotbar: Rename Hotbar ...",
action: () => openCommandDialog(<HotbarRenameCommand />),
action: () => dependencies.openCommandDialog(<HotbarRenameCommand />),
},
{
id: "catalog.searchEntities",
title: "Catalog: Activate Entity ...",
action: () => openCommandDialog(<ActivateEntityCommand />),
action: () => dependencies.openCommandDialog(<ActivateEntityCommand />),
},
];
}
@@ -213,6 +253,29 @@ const internalCommandsInjectable = getInjectable({
.getInstance()
.getItemsForKind,
createTerminalTab: di.inject(createTerminalTabInjectable),
navigateToPreferences: di.inject(navigateToPreferencesInjectable),
navigateToHelmCharts: di.inject(navigateToHelmChartsInjectable),
navigateToHelmReleases: di.inject(navigateToHelmReleasesInjectable),
navigateToConfigMaps: di.inject(navigateToConfigMapsInjectable),
navigateToSecrets: di.inject(navigateToSecretsInjectable),
navigateToResourceQuotas: di.inject(navigateToResourceQuotasInjectable),
navigateToLimitRanges: di.inject(navigateToLimitRangesInjectable),
navigateToHorizontalPodAutoscalers: di.inject(navigateToHorizontalPodAutoscalersInjectable),
navigateToPodDisruptionBudgets: di.inject(navigateToPodDisruptionBudgetsInjectable),
navigateToServices: di.inject(navigateToServicesInjectable),
navigateToEndpoints: di.inject(navigateToEndpointsInjectable),
navigateToIngresses: di.inject(navigateToIngressesInjectable),
navigateToNetworkPolicies: di.inject(navigateToNetworkPoliciesInjectable),
navigateToNodes: di.inject(navigateToNodesInjectable),
navigateToPods: di.inject(navigateToPodsInjectable),
navigateToDeployments: di.inject(navigateToDeploymentsInjectable),
navigateToDaemonsets: di.inject(navigateToDaemonsetsInjectable),
navigateToStatefulsets: di.inject(navigateToStatefulsetsInjectable),
navigateToJobs: di.inject(navigateToJobsInjectable),
navigateToCronJobs: di.inject(navigateToCronJobsInjectable),
navigateToCustomResources: di.inject(navigateToCustomResourcesInjectable),
navigateToEntitySettings: di.inject(navigateToEntitySettingsInjectable),
}),
});