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

@@ -0,0 +1,39 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { getInjectable } from "@ogre-tools/injectable";
import { overSome } from "lodash/fp";
import { computed } from "mobx";
import rendererExtensionsInjectable from "../../extensions/renderer-extensions.injectable";
import type { LensRendererExtension } from "../../extensions/lens-renderer-extension";
import { Route, routeInjectionToken } from "../../common/front-end-routing/route-injection-token";
const allRoutesInjectable = getInjectable({
id: "all-routes",
instantiate: (di) => {
const extensions = di.inject(rendererExtensionsInjectable);
return computed(() => {
const enabledExtensions = extensions.get();
return di
.injectMany(routeInjectionToken)
.filter((route) =>
overSome([
isNonExtensionRoute,
isEnabledExtensionRouteFor(enabledExtensions),
])(route),
);
});
},
});
const isNonExtensionRoute = (route: Route<unknown>) => !route.extension;
const isEnabledExtensionRouteFor =
(enabledExtensions: LensRendererExtension[]) => (route: Route<unknown>) =>
!!enabledExtensions.find((x) => x === route.extension);
export default allRoutesInjectable;
@@ -0,0 +1,23 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { getInjectable } from "@ogre-tools/injectable";
import { computed } from "mobx";
import matchingRouteInjectable from "./matching-route.injectable";
const currentPathParametersInjectable = getInjectable({
id: "current-path-parameters",
instantiate: (di) => {
const matchingRoute = di.inject(matchingRouteInjectable);
return computed((): Record<string, string> => {
const match = matchingRoute.get();
return match ? match.pathParameters: {};
});
},
});
export default currentPathParametersInjectable;
@@ -0,0 +1,19 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { getInjectable } from "@ogre-tools/injectable";
import { computed } from "mobx";
import observableHistoryInjectable from "../navigation/observable-history.injectable";
const currentPathInjectable = getInjectable({
id: "current-path",
instantiate: (di) => {
const observableHistory = di.inject(observableHistoryInjectable);
return computed(() => observableHistory.location.pathname);
},
});
export default currentPathInjectable;
@@ -0,0 +1,33 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { getInjectable } from "@ogre-tools/injectable";
import { matches } from "lodash/fp";
import { computed } from "mobx";
import currentRouteInjectable from "./current-route.injectable";
import { routeSpecificComponentInjectionToken } from "./route-specific-component-injection-token";
const currentRouteComponentInjectable = getInjectable({
id: "current-route-component",
instantiate: (di) => {
const route = di.inject(currentRouteInjectable);
return computed(() => {
const currentRoute = route.get();
if (!currentRoute) {
return null;
}
const routeSpecificComponent = di
.injectMany(routeSpecificComponentInjectionToken)
.find(matches({ route: currentRoute }));
return routeSpecificComponent.Component;
});
},
});
export default currentRouteComponentInjectable;
@@ -0,0 +1,27 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { getInjectable } from "@ogre-tools/injectable";
import { computed } from "mobx";
import matchingRouteInjectable from "./matching-route.injectable";
const currentRouteInjectable = getInjectable({
id: "current-route",
instantiate: (di) => {
const matchingRoute = di.inject(matchingRouteInjectable);
return computed(() => {
const match = matchingRoute.get();
if (match && match.route.isEnabled.get()) {
return match.route;
}
return null;
});
},
});
export default currentRouteInjectable;
@@ -0,0 +1,12 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { getInjectable } from "@ogre-tools/injectable";
const currentlyInClusterFrameInjectable = getInjectable({
id: "currently-in-cluster-frame",
instantiate: () => !process.isMainFrame,
});
export default currentlyInClusterFrameInjectable;
@@ -0,0 +1,68 @@
/**
* 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 { pipeline } from "@ogre-tools/fp";
import { PageParam, PageParamInit } from "../navigation";
import observableHistoryInjectable from "../navigation/observable-history.injectable";
import type { LensRendererExtension } from "../../extensions/lens-renderer-extension";
import type { PageRegistration } from "../../extensions/registries";
import { fromPairs, map, toPairs } from "lodash/fp";
interface InstantiationParameter {
extension: LensRendererExtension;
registration: PageRegistration;
}
const extensionPageParametersInjectable = getInjectable({
id: "extension-page-parameters",
instantiate: (di, { registration }: InstantiationParameter) => {
const observableHistory = di.inject(observableHistoryInjectable);
return pipeline(
registration.params,
(params) => toPairs(params),
map(([key, value]): [string, PageParamInit] => [
key,
typeof value === "string"
? convertStringToPageParamInit(key, value)
: convertPartialPageParamInitToFull(key, value as PageParamInit),
]),
map(([key, value]) => [key, new PageParam(value, observableHistory)]),
(paramsTuple) => fromPairs(paramsTuple),
);
},
lifecycle: lifecycleEnum.keyedSingleton({
getInstanceKey: (
di,
{ extension, registration }: InstantiationParameter,
) => `${extension.sanitizedExtensionId}-${registration?.id}`,
}),
});
const convertPartialPageParamInitToFull = (
key: string,
value: PageParamInit,
): PageParamInit => ({
name: key,
defaultValue: value.defaultValue,
stringify: value.stringify,
parse: value.parse,
});
const convertStringToPageParamInit = (
key: string,
value: string,
): PageParamInit => ({
name: key,
defaultValue: value,
});
export default extensionPageParametersInjectable;
@@ -0,0 +1,116 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { DiContainer, getInjectable } from "@ogre-tools/injectable";
import type { LensRendererExtension } from "../../extensions/lens-renderer-extension";
import { observer } from "mobx-react";
import React from "react";
import { isEmpty, matches } from "lodash/fp";
import type { PageRegistration } from "../../extensions/registries";
import observableHistoryInjectable from "../navigation/observable-history.injectable";
import type { ObservableHistory } from "mobx-observable-history";
import { extensionRegistratorInjectionToken } from "../../extensions/extension-loader/extension-registrator-injection-token";
import { SiblingsInTabLayout } from "../components/layout/siblings-in-tab-layout";
import extensionPageParametersInjectable from "./extension-page-parameters.injectable";
import { routeSpecificComponentInjectionToken } from "./route-specific-component-injection-token";
import { computed } from "mobx";
import { getExtensionRoutePath } from "./get-extension-route-path";
import { routeInjectionToken } from "../../common/front-end-routing/route-injection-token";
const extensionRouteRegistratorInjectable = getInjectable({
id: "extension-route-registrator",
instantiate: (di: DiContainer) => {
const observableHistory = di.inject(observableHistoryInjectable);
return (
extension: LensRendererExtension,
extensionInstallationCount: number,
) => {
const toRouteInjectable = toRouteInjectableFor(
di,
extension,
observableHistory,
extensionInstallationCount,
);
const routeInjectables = [
...extension.globalPages.map(toRouteInjectable(false)),
...extension.clusterPages.map(toRouteInjectable(true)),
].flat();
routeInjectables.forEach(di.register);
};
},
injectionToken: extensionRegistratorInjectionToken,
});
export default extensionRouteRegistratorInjectable;
const toRouteInjectableFor =
(
di: DiContainer,
extension: LensRendererExtension,
observableHistory: ObservableHistory,
extensionInstallationCount: number,
) =>
(clusterFrame: boolean) =>
(registration: PageRegistration) => {
const routeInjectable = getInjectable({
id: `route-${registration.id}-for-extension-${extension.sanitizedExtensionId}-installation-${extensionInstallationCount}`,
instantiate: () => ({
path: getExtensionRoutePath(extension, registration.id),
clusterFrame,
isEnabled: computed(() => true),
extension,
}),
injectionToken: routeInjectionToken,
});
const normalizedParams = di.inject(extensionPageParametersInjectable, {
extension,
registration,
});
const currentSidebarRegistration = extension.clusterPageMenus.find(
matches({ target: { pageId: registration.id }}),
);
const siblingRegistrations = currentSidebarRegistration?.parentId
? extension.clusterPageMenus.filter(
matches({ parentId: currentSidebarRegistration.parentId }),
)
: [];
const ObserverPage = observer(registration.components.Page);
const Component = () => {
if (isEmpty(siblingRegistrations)) {
return <ObserverPage params={normalizedParams} />;
}
return (
<SiblingsInTabLayout>
<ObserverPage params={normalizedParams} />
</SiblingsInTabLayout>
);
};
const routeSpecificComponentInjectable = getInjectable({
id: `route-${registration.id}-component-for-extension-${extension.sanitizedExtensionId}-installation-${extensionInstallationCount}`,
instantiate: (di) => ({
route: di.inject(routeInjectable),
Component,
}),
injectionToken: routeSpecificComponentInjectionToken,
});
return [routeInjectable, routeSpecificComponentInjectable];
};
@@ -0,0 +1,9 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
export const getExtensionRouteId = (
extensionId: string,
registrationId: string,
) => (registrationId ? `${extensionId}/${registrationId}` : extensionId);
@@ -0,0 +1,19 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { getExtensionRouteId } from "./get-extension-route-id";
import { getSanitizedPath } from "../../extensions/lens-extension";
import type { LensRendererExtension } from "../../extensions/lens-renderer-extension";
export const getExtensionRoutePath = (
extension: LensRendererExtension,
pageId?: string,
) => {
const routeId = getExtensionRouteId(
extension.sanitizedExtensionId,
pageId,
);
return getSanitizedPath("/extension", routeId);
};
@@ -0,0 +1,38 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { getInjectable } from "@ogre-tools/injectable";
import routesInjectable from "./routes.injectable";
import { matches } from "lodash/fp";
import { computed } from "mobx";
import { matchPath } from "react-router";
import currentPathInjectable from "./current-path.injectable";
const matchingRouteInjectable = getInjectable({
id: "matching-route",
instantiate: (di) => {
const routes = di.inject(routesInjectable);
const currentPath = di.inject(currentPathInjectable);
return computed(() => {
const matchedRoutes = routes.get().map((route) => {
const match = matchPath(currentPath.get(), {
path: route.path,
exact: true,
});
return {
route,
isMatching: !!match,
pathParameters: match ? match.params : {},
};
});
return matchedRoutes.find(matches({ isMatching: true }));
});
},
});
export default matchingRouteInjectable;
@@ -0,0 +1,39 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { getInjectable } from "@ogre-tools/injectable";
import { navigateToUrlInjectionToken } from "../../common/front-end-routing/navigate-to-url-injection-token";
import { navigateToRouteInjectionToken } from "../../common/front-end-routing/navigate-to-route-injection-token";
import currentlyInClusterFrameInjectable from "./currently-in-cluster-frame.injectable";
import { buildURL } from "../../common/utils/buildUrl";
const navigateToRouteInjectable = getInjectable({
id: "navigate-to-route",
instantiate: (di) => {
const navigateToUrl = di.inject(navigateToUrlInjectionToken);
const currentlyInClusterFrame = di.inject(
currentlyInClusterFrameInjectable,
);
return (route, options) => {
const url = buildURL(route.path, {
// TODO: enhance typing
params: options?.parameters as any,
query: options?.query,
fragment: options?.fragment,
});
navigateToUrl(url, {
...options,
forceRootFrame: currentlyInClusterFrame && route.clusterFrame === false,
});
};
},
injectionToken: navigateToRouteInjectionToken,
});
export default navigateToRouteInjectable;
@@ -0,0 +1,40 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { getInjectable } from "@ogre-tools/injectable";
import observableHistoryInjectable from "../navigation/observable-history.injectable";
import { runInAction } from "mobx";
import { navigateToUrlInjectionToken } from "../../common/front-end-routing/navigate-to-url-injection-token";
import { broadcastMessage } from "../../common/ipc";
import { IpcRendererNavigationEvents } from "../navigation/events";
const navigateToUrlInjectable = getInjectable({
id: "navigate-to-url",
instantiate: (di) => {
const observableHistory = di.inject(observableHistoryInjectable);
return (url, options = {}) => {
if (options.forceRootFrame) {
broadcastMessage(IpcRendererNavigationEvents.NAVIGATE_IN_APP, url);
return;
}
runInAction(() => {
if (options.withoutAffectingBackButton) {
observableHistory.replace(url);
return;
}
observableHistory.push(url);
});
};
},
injectionToken: navigateToUrlInjectionToken,
});
export default navigateToUrlInjectable;
@@ -0,0 +1,24 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { getInjectable } from "@ogre-tools/injectable";
import { computed } from "mobx";
import { parse as parseQueryString } from "query-string";
import observableHistoryInjectable from "../navigation/observable-history.injectable";
const queryParametersInjectable = getInjectable({
id: "query-parameters",
instantiate: (di) => {
const observableHistory = di.inject(observableHistoryInjectable);
return computed(() => {
const queryString = observableHistory.location.search;
return parseQueryString(queryString);
});
},
});
export default queryParametersInjectable;
@@ -0,0 +1,24 @@
/**
* 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 currentRouteInjectable from "./current-route.injectable";
import type { Route } from "../../common/front-end-routing/route-injection-token";
const routeIsActiveInjectable = getInjectable({
id: "route-is-active",
instantiate: (di, route: Route<unknown>) => {
const currentRoute = di.inject(currentRouteInjectable);
return computed(() => currentRoute.get() === route);
},
lifecycle: lifecycleEnum.keyedSingleton({
getInstanceKey: (di, route: Route<unknown>) => route.path,
}),
});
export default routeIsActiveInjectable;
@@ -0,0 +1,33 @@
/**
* 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 { matchPath } from "react-router";
import currentPathInjectable from "./current-path.injectable";
import type { Route } from "../../common/front-end-routing/route-injection-token";
const routePathParametersInjectable = getInjectable({
id: "route-path-parameters",
instantiate: (di, route: Route<unknown>) => {
const currentPath = di.inject(currentPathInjectable);
// TODO: Reuse typing from route for accuracy
return computed((): Record<string, string> => {
const match = matchPath(currentPath.get(), {
path: route.path,
exact: true,
});
return match ? match.params : {};
});
},
lifecycle: lifecycleEnum.keyedSingleton({
getInstanceKey: (di, route: Route<unknown>) => route,
}),
});
export default routePathParametersInjectable;
@@ -0,0 +1,13 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { getInjectionToken } from "@ogre-tools/injectable";
import type { Route } from "../../common/front-end-routing/route-injection-token";
export const routeSpecificComponentInjectionToken = getInjectionToken<{
route: Route<unknown>;
Component: React.ElementType;
}>({
id: "route-specific-component-injection-token",
});
+30
View File
@@ -0,0 +1,30 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { getInjectable } from "@ogre-tools/injectable";
import { computed } from "mobx";
import currentlyInClusterFrameInjectable from "./currently-in-cluster-frame.injectable";
import allRoutesInjectable from "./all-routes.injectable";
import { matches } from "lodash/fp";
const routesInjectable = getInjectable({
id: "routes",
instantiate: (di) => {
const allRoutes = di.inject(allRoutesInjectable);
const currentlyInClusterFrame = di.inject(
currentlyInClusterFrameInjectable,
);
return computed(() =>
allRoutes
.get()
.filter(matches({ clusterFrame: currentlyInClusterFrame }))
.filter((route) => route.isEnabled.get()),
);
},
});
export default routesInjectable;
@@ -0,0 +1,28 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { computed } from "mobx";
import { getInjectable } from "@ogre-tools/injectable";
import sidebarItemsInjectable, { HierarchicalSidebarItem } from "../components/layout/sidebar-items.injectable";
import { find } from "lodash/fp";
import { pipeline } from "@ogre-tools/fp";
const siblingTabsInjectable = getInjectable({
id: "sibling-tabs",
instantiate: (di) => {
const sidebarItems = di.inject(sidebarItemsInjectable);
return computed((): HierarchicalSidebarItem[] =>
pipeline(
sidebarItems.get(),
find(({ isActive }) => isActive.get()),
({ children = [] }) => children,
),
);
},
});
export default siblingTabsInjectable;