Restructure to monorepo (#6907)

* wip: restructure to monorepo

Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com>

* refactor create-release-pr to a package

Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com>

* build fixes

Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com>

* github workflow fixes

Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com>

* fix typo

Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com>

* add webpack-env types to core

Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com>

* fix github workflows

Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com>

* refactor/fix integration tests

Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com>

* lint fix

Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com>

* yarn run dev

Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com>

* eslint settings for vscode

Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com>

* move templates to right package

Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com>

* open-lens build fixes

Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com>

* integration test fix

Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com>

* fix nx task dependencies

Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com>

* use bash shell for unit tests in test workflow

Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com>

* fix test:unit for windows

Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com>

* fix win-ca webpack error in open-lens

Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com>

* fix win-ca webpack error in open-lens

Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com>

* fix build:app on windows

Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com>

* remove ELECTRON_BUILDER_EXTRA_ARGS

Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com>

* sync src/ from master

Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com>

* remove Makefile from core

Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com>

Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com>
This commit is contained in:
Jari Kolehmainen authored and GitHub committed 2023-01-24 10:46:26 -08:00
1 parent 0066ca4ea2
commit 2657df2293
3321 files changed
+28699 -11447

No files matched your search

@@ -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,37 @@
/**
* 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 { computedInjectManyInjectable } from "@ogre-tools/injectable-extension-for-mobx";
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);
const computedInjectMany = di.inject(computedInjectManyInjectable);
const routeComponents = computedInjectMany(routeSpecificComponentInjectionToken);
return computed(() => {
const currentRoute = route.get();
if (!currentRoute) {
return undefined;
}
return routeComponents
.get()
.find(({ route }) => (
route.path === currentRoute.path
&& route.clusterFrame === currentRoute.clusterFrame
))
?.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,13 @@
/**
* 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,
causesSideEffects: true,
});
export default currentlyInClusterFrameInjectable;
@@ -0,0 +1,65 @@
/**
* 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 type { PageParamInit } from "../navigation/page-param";
import type { LensRendererExtension } from "../../extensions/lens-renderer-extension";
import { map } from "lodash/fp";
import createPageParamInjectable from "../navigation/create-page-param.injectable";
import { object } from "../utils";
import type { PageRegistration } from "./page-registration";
export interface ExtensionPageParametersInstantiationParam {
extension: LensRendererExtension;
registration: PageRegistration;
}
const extensionPageParametersInjectable = getInjectable({
id: "extension-page-parameters",
instantiate: (di, { registration }: ExtensionPageParametersInstantiationParam) => {
const createPageParam = di.inject(createPageParamInjectable);
return pipeline(
registration.params ?? {},
Object.entries,
map(([key, value]): [string, PageParamInit<unknown>] => [
key,
typeof value === "string"
? convertStringToPageParamInit(key, value)
: convertPartialPageParamInitToFull(key, value),
]),
map(([key, value]) => [key, createPageParam(value)] as const),
object.fromEntries,
);
},
lifecycle: lifecycleEnum.keyedSingleton({
getInstanceKey: (
di,
{ extension, registration }: ExtensionPageParametersInstantiationParam,
) => `${extension.sanitizedExtensionId}-${registration?.id}`,
}),
});
const convertPartialPageParamInitToFull = <V>(
key: string,
value: PageParamInit<V>,
): PageParamInit<V> => ({
name: key,
defaultValue: value.defaultValue,
stringify: value.stringify,
parse: value.parse,
});
const convertStringToPageParamInit = (
key: string,
value: string,
): PageParamInit<string> => ({
name: key,
defaultValue: value,
});
export default extensionPageParametersInjectable;
@@ -0,0 +1,126 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import type { DiContainerForInjection } from "@ogre-tools/injectable";
import { 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 { 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 type { IComputedValue } from "mobx";
import { computed } from "mobx";
import { frontEndRouteInjectionToken } from "../../common/front-end-routing/front-end-route-injection-token";
import { getExtensionRoutePath } from "./for-extension";
import extensionShouldBeEnabledForClusterFrameInjectable from "../extension-loader/extension-should-be-enabled-for-cluster-frame.injectable";
import type { PageRegistration } from "./page-registration";
const extensionRouteRegistratorInjectable = getInjectable({
id: "extension-route-registrator",
instantiate: (di) => {
return (ext) => {
const extension = ext as LensRendererExtension;
const toRouteInjectable = toRouteInjectableFor(di, extension);
const extensionShouldBeEnabledForClusterFrame = di.inject(
extensionShouldBeEnabledForClusterFrameInjectable,
extension,
);
return [
...extension.globalPages.map(
toRouteInjectable(false, (registration) =>
computed(() =>
registration.enabled ? registration.enabled.get() : true,
),
),
),
...extension.clusterPages.map(
toRouteInjectable(true, (registration) =>
computed(() => {
if (!extensionShouldBeEnabledForClusterFrame.value.get()) {
return false;
}
return registration.enabled ? registration.enabled.get() : true;
}),
),
),
].flat();
};
},
injectionToken: extensionRegistratorInjectionToken,
});
export default extensionRouteRegistratorInjectable;
const toRouteInjectableFor =
(
di: DiContainerForInjection,
extension: LensRendererExtension,
) =>
(clusterFrame: boolean, getIsEnabled: (registration: PageRegistration) => IComputedValue<boolean>) =>
(registration: PageRegistration) => {
const routeInjectable = getInjectable({
id: `route-${registration.id}-for-extension-${extension.sanitizedExtensionId}`,
instantiate: () => ({
path: getExtensionRoutePath(extension, registration.id),
clusterFrame,
isEnabled: getIsEnabled(registration),
extension,
}),
injectionToken: frontEndRouteInjectionToken,
});
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}`,
instantiate: (di) => ({
route: di.inject(routeInjectable),
Component,
}),
injectionToken: routeSpecificComponentInjectionToken,
});
return [routeInjectable, routeSpecificComponentInjectable];
};
@@ -0,0 +1,21 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { getSanitizedPath } from "../../extensions/lens-extension";
import type { LensRendererExtension } from "../../extensions/lens-renderer-extension";
export function getExtensionRoutePath(extension: LensRendererExtension, pageId: string | undefined) {
const routeId = getExtensionRouteId(
extension.sanitizedExtensionId,
pageId,
);
return getSanitizedPath("/extension", routeId);
}
export function getExtensionRouteId(extensionId: string, registrationId: string | undefined) {
return registrationId
? `${extensionId}/${registrationId}`
: extensionId;
}
@@ -0,0 +1,17 @@
/**
* 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 type { PageParam } from "../navigation/page-param";
import type { ExtensionPageParametersInstantiationParam } from "./extension-page-parameters.injectable";
import extensionPageParametersInjectable from "./extension-page-parameters.injectable";
export type GetExtensionPageParameters = (param: ExtensionPageParametersInstantiationParam) => Record<string, PageParam<unknown>>;
const getExtensionPageParametersInjectable = getInjectable({
id: "get-extension-page-parameters",
instantiate: (di): GetExtensionPageParameters => (param) => di.inject(extensionPageParametersInjectable, param),
});
export default getExtensionPageParametersInjectable;
@@ -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,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 observableHistoryInjectable from "../navigation/observable-history.injectable";
import { runInAction } from "mobx";
import type { NavigateToUrl } from "../../common/front-end-routing/navigate-to-url-injection-token";
import { navigateToUrlInjectionToken } from "../../common/front-end-routing/navigate-to-url-injection-token";
import { IpcRendererNavigationEvents } from "../../common/ipc/navigation-events";
import broadcastMessageInjectable from "../../common/ipc/broadcast-message.injectable";
const navigateToUrlInjectable = getInjectable({
id: "navigate-to-url",
instantiate: (di): NavigateToUrl => {
const observableHistory = di.inject(observableHistoryInjectable);
const broadcastMessage = di.inject(broadcastMessageInjectable);
return (url, options = {}): void => {
if (options.forceRootFrame) {
return void broadcastMessage(IpcRendererNavigationEvents.NAVIGATE_IN_APP, url);
}
runInAction(() => {
if (options.withoutAffectingBackButton) {
observableHistory.replace(url);
} else {
observableHistory.push(url);
}
});
};
},
injectionToken: navigateToUrlInjectionToken,
});
export default navigateToUrlInjectable;
@@ -0,0 +1,47 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import type { IComputedValue } from "mobx";
import type { PageParamInit, PageParam } from "../navigation/page-param";
// Extensions-api -> Custom page registration
export interface PageRegistration {
/**
* Page ID, part of extension's page url, must be unique within same extension
* When not provided, first registered page without "id" would be used for page-menus without target.pageId for same extension
*/
id?: string;
params?: PageParams<string | Omit<PageParamInit<any>, "name" | "prefix">>;
components: PageComponents;
enabled?: IComputedValue<boolean>;
}
export interface PageComponents {
Page: React.ComponentType<any>;
}
export interface PageTarget {
extensionId?: string;
pageId?: string;
params?: PageParams;
}
export interface PageParams<V = any> {
[paramName: string]: V;
}
export interface PageComponentProps<P extends PageParams = {}> {
params?: {
[N in keyof P]: PageParam<P[N]>;
};
}
export interface RegisteredPage {
id: string;
extensionId: string;
url: string; // registered extension's page URL (without page params)
params: PageParams<PageParam<any>>; // normalized params
components: PageComponents; // normalized components
}
@@ -0,0 +1,20 @@
/**
* 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(() => parseQueryString(observableHistory.location.search));
},
});
export default queryParametersInjectable;
@@ -0,0 +1,31 @@
/**
* 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 type { Route } from "../../common/front-end-routing/front-end-route-injection-token";
import currentPathInjectable from "./current-path.injectable";
import { matchPath } from "react-router-dom";
const routeIsActiveInjectable = getInjectable({
id: "route-is-active",
instantiate: (di, route: Route<unknown>) => {
const currentPath = di.inject(currentPathInjectable);
return computed(
() =>
!!matchPath(currentPath.get(), {
path: route.path,
exact: true,
}),
);
},
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/front-end-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/front-end-route-injection-token";
export const routeSpecificComponentInjectionToken = getInjectionToken<{
route: Route<unknown>;
Component: React.ElementType<any>;
}>({
id: "route-specific-component-injection-token",
});
@@ -0,0 +1,29 @@
/**
* 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 { matches } from "lodash/fp";
import { frontEndRouteInjectionToken } from "../../common/front-end-routing/front-end-route-injection-token";
import { computedInjectManyInjectable } from "@ogre-tools/injectable-extension-for-mobx";
const routesInjectable = getInjectable({
id: "routes",
instantiate: (di) => {
const computedInjectMany = di.inject(computedInjectManyInjectable);
const currentlyInClusterFrame = di.inject(currentlyInClusterFrameInjectable);
const routes = computedInjectMany(frontEndRouteInjectionToken);
return computed(() =>
routes
.get()
.filter(matches({ clusterFrame: currentlyInClusterFrame }))
.filter((route) => route.isEnabled.get()),
);
},
});
export default routesInjectable;
@@ -0,0 +1,23 @@
/**
* 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 from "../components/layout/sidebar-items.injectable";
const siblingTabsInjectable = getInjectable({
id: "sibling-tabs",
instantiate: (di) => {
const sidebarItems = di.inject(sidebarItemsInjectable);
return computed(() => {
const item = sidebarItems.get().find(({ isActive }) => isActive.get());
return item?.children ?? [];
});
},
});
export default siblingTabsInjectable;