mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
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:
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",
|
||||
});
|
||||
@@ -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;
|
||||
Reference in new issue
Block a user