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,17 @@
/**
* 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 { IComputedValue } from "mobx";
export interface ClusterFrameChildComponent {
id: string;
Component: React.ElementType;
shouldRender: IComputedValue<boolean>;
}
export const clusterFrameChildComponentInjectionToken = getInjectionToken<ClusterFrameChildComponent>({
id: "cluster-frame-child-component",
});
@@ -0,0 +1,42 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { pipeline } from "@ogre-tools/fp";
import { getInjectable } from "@ogre-tools/injectable";
import { map } from "lodash/fp";
import { extensionRegistratorInjectionToken } from "../../../extensions/extension-loader/extension-registrator-injection-token";
import type { ExtensionRegistrator } from "../../../extensions/extension-loader/extension-registrator-injection-token";
import type { LensRendererExtension } from "../../../extensions/lens-renderer-extension";
import { clusterFrameChildComponentInjectionToken } from "./cluster-frame-child-component-injection-token";
const clusterFrameComponentRegistratorInjectable = getInjectable({
id: "cluster-frame-component-registrator",
instantiate: (): ExtensionRegistrator => {
return (ext) => {
const extension = ext as LensRendererExtension;
return pipeline(
extension.clusterFrameComponents,
map((clusterFrameComponentRegistration) => {
const id = `${extension.sanitizedExtensionId}-${clusterFrameComponentRegistration.id}`;
return getInjectable({
id,
injectionToken: clusterFrameChildComponentInjectionToken,
instantiate: () => ({
id,
shouldRender: clusterFrameComponentRegistration.shouldRender,
Component: clusterFrameComponentRegistration.Component,
}),
});
}),
);
};
},
injectionToken: extensionRegistratorInjectionToken,
});
export default clusterFrameComponentRegistratorInjectable;
@@ -0,0 +1,72 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import React from "react";
import { getInjectable } from "@ogre-tools/injectable";
import { clusterFrameChildComponentInjectionToken } from "./cluster-frame-child-component-injection-token";
import { MainLayout } from "../../components/layout/main-layout";
import { Sidebar } from "../../components/layout/sidebar";
import { Dock } from "../../components/dock";
import styles from "./cluster-frame.module.css";
import type { IComputedValue } from "mobx";
import { computed } from "mobx";
import currentRouteComponentInjectable from "../../routes/current-route-component.injectable";
import { Redirect } from "react-router";
import startUrlInjectable from "./start-url.injectable";
import currentPathInjectable from "../../routes/current-path.injectable";
import { observer } from "mobx-react";
import { withInjectables } from "@ogre-tools/injectable-react";
interface Dependencies {
currentRouteComponent: IComputedValue<React.ElementType<any> | undefined>;
startUrl: IComputedValue<string>;
currentPath: IComputedValue<string>;
}
const NonInjectedClusterFrameLayout = observer((props: Dependencies) => {
const Component = props.currentRouteComponent.get();
const starting = props.startUrl.get();
const current = props.currentPath.get();
return (
<MainLayout sidebar={<Sidebar />} footer={<Dock />}>
{Component ? (
<Component />
) : // NOTE: this check is to prevent an infinite loop
starting !== current ? (
<Redirect to={starting} />
) : (
<div className={styles.centering}>
<div className="error">
An error has occured. No route can be found matching the
current route, which is also the starting route.
</div>
</div>
)}
</MainLayout>
);
});
const ClusterFrameLayout = withInjectables<Dependencies>(NonInjectedClusterFrameLayout, {
getProps: (di, props) => ({
...props,
currentRouteComponent: di.inject(currentRouteComponentInjectable),
startUrl: di.inject(startUrlInjectable),
currentPath: di.inject(currentPathInjectable),
}),
});
const clusterFrameLayoutChildComponentInjectable = getInjectable({
id: "cluster-frame-layout-child-component",
instantiate: () => ({
id: "cluster-frame-layout",
shouldRender: computed(() => true),
Component: ClusterFrameLayout,
}),
injectionToken: clusterFrameChildComponentInjectionToken,
});
export default clusterFrameLayoutChildComponentInjectable;
@@ -0,0 +1,11 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
.centering {
height: 100%;
display: flex;
justify-content: center;
align-items: center;
}
@@ -0,0 +1,129 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import type { DiContainer } from "@ogre-tools/injectable";
import type { RenderResult } from "@testing-library/react";
import { getDiForUnitTesting } from "../../getDiForUnitTesting";
import { render as testingLibraryRender } from "@testing-library/react";
import React from "react";
import { DiContextProvider } from "@ogre-tools/injectable-react";
import { Router } from "react-router";
import { DefaultProps } from "../../mui-base-theme";
import { ClusterFrame } from "./cluster-frame";
import historyInjectable from "../../navigation/history.injectable";
import { computed } from "mobx";
import type { Cluster } from "../../../common/cluster/cluster";
import createClusterInjectable from "../../cluster/create-cluster.injectable";
import subscribeStoresInjectable from "../../kube-watch-api/subscribe-stores.injectable";
import directoryForUserDataInjectable from "../../../common/app-paths/directory-for-user-data/directory-for-user-data.injectable";
import storesAndApisCanBeCreatedInjectable from "../../stores-apis-can-be-created.injectable";
import legacyOnChannelListenInjectable from "../../ipc/legacy-channel-listen.injectable";
import currentRouteComponentInjectable from "../../routes/current-route-component.injectable";
import hostedClusterIdInjectable from "../../cluster-frame-context/hosted-cluster-id.injectable";
import hostedClusterInjectable from "../../cluster-frame-context/hosted-cluster.injectable";
import { testUsingFakeTime } from "../../../common/test-utils/use-fake-time";
import currentlyInClusterFrameInjectable from "../../routes/currently-in-cluster-frame.injectable";
describe("<ClusterFrame />", () => {
let render: () => RenderResult;
let di: DiContainer;
let cluster: Cluster;
beforeEach(() => {
di = getDiForUnitTesting({ doGeneralOverrides: true });
render = () => testingLibraryRender((
<DiContextProvider value={{ di }}>
<Router history={di.inject(historyInjectable)}>
{DefaultProps(ClusterFrame)}
</Router>
</DiContextProvider>
));
di.override(subscribeStoresInjectable, () => jest.fn().mockImplementation(() => jest.fn()));
di.override(legacyOnChannelListenInjectable, () => jest.fn().mockImplementation(() => jest.fn()));
di.override(directoryForUserDataInjectable, () => "/some/irrelavent/path");
di.override(storesAndApisCanBeCreatedInjectable, () => true);
di.override(currentlyInClusterFrameInjectable, () => true);
testUsingFakeTime("2000-01-01 12:00:00am");
const createCluster = di.inject(createClusterInjectable);
cluster = createCluster(
{
contextName: "my-cluster",
id: "123456",
kubeConfigPath: "/irrelavent",
},
{
clusterServerUrl: "https://localhost",
},
);
di.override(hostedClusterInjectable, () => cluster);
di.override(hostedClusterIdInjectable, () => cluster.id);
});
describe("given cluster with list nodes and namespaces permissions", () => {
beforeEach(() => {
// TODO: replace with not using private info
(cluster as unknown as { readonly allowedResources: Cluster["allowedResources"] }).allowedResources.replace(["nodes", "namespaces"]);
});
it("renders", () => {
const result = render();
expect(result.container).toMatchSnapshot();
});
it("shows cluster overview sidebar item as active", () => {
const result = render();
const clusterOverviewSidebarItem = result.getByTestId("sidebar-item-cluster-overview");
expect(clusterOverviewSidebarItem.getAttribute("data-is-active-test")).toBe("true");
});
describe("given no matching component", () => {
beforeEach(() => {
di.override(currentRouteComponentInjectable, () => computed(() => undefined));
});
describe("given current url is starting url", () => {
it("renders", () => {
const result = render();
expect(result.container).toMatchSnapshot();
});
it("shows warning message", () => {
const result = render();
expect(
result.getByText("An error has occured. No route can be found matching the current route, which is also the starting route."),
).toBeInTheDocument();
});
});
});
});
describe("given cluster without list nodes, but with namespaces permissions", () => {
beforeEach(() => {
(cluster as unknown as { readonly allowedResources: Cluster["allowedResources"] }).allowedResources.replace(["namespaces"]);
});
it("renders", () => {
const result = render();
expect(result.container).toMatchSnapshot();
});
it("shows workloads overview sidebar item as active", () => {
const result = render();
const workloadsOverviewSidebarItem = result.getByTestId("sidebar-item-workloads");
expect(workloadsOverviewSidebarItem.getAttribute("data-is-active-test")).toBe("true");
});
});
});
@@ -0,0 +1,65 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import React, { useEffect } from "react";
import { Observer, observer } from "mobx-react";
import { ErrorBoundary } from "../../components/error-boundary";
import type { NamespaceStore } from "../../components/+namespaces/store";
import { withInjectables } from "@ogre-tools/injectable-react";
import namespaceStoreInjectable from "../../components/+namespaces/store.injectable";
import type { SubscribeStores } from "../../kube-watch-api/kube-watch-api";
import { disposer } from "../../utils";
import subscribeStoresInjectable from "../../kube-watch-api/subscribe-stores.injectable";
import type { ClusterFrameChildComponent } from "./cluster-frame-child-component-injection-token";
import { clusterFrameChildComponentInjectionToken } from "./cluster-frame-child-component-injection-token";
import watchHistoryStateInjectable from "../../remote-helpers/watch-history-state.injectable";
import { computedInjectManyInjectable } from "@ogre-tools/injectable-extension-for-mobx";
import type { IComputedValue } from "mobx";
interface Dependencies {
namespaceStore: NamespaceStore;
subscribeStores: SubscribeStores;
childComponents: IComputedValue<ClusterFrameChildComponent[]>;
watchHistoryState: () => () => void;
}
const NonInjectedClusterFrame = observer(({
namespaceStore,
subscribeStores,
childComponents,
watchHistoryState,
}: Dependencies) => {
useEffect(() => disposer(
subscribeStores([
namespaceStore,
]),
watchHistoryState(),
), []);
return (
<ErrorBoundary>
{childComponents.get()
.map((child) => (
<Observer key={child.id}>
{() => (child.shouldRender.get() ? <child.Component /> : null) }
</Observer>
))}
</ErrorBoundary>
);
});
export const ClusterFrame = withInjectables<Dependencies>(NonInjectedClusterFrame, {
getProps: di => {
const computedInjectMany = di.inject(computedInjectManyInjectable);
return {
namespaceStore: di.inject(namespaceStoreInjectable),
subscribeStores: di.inject(subscribeStoresInjectable),
childComponents: computedInjectMany(clusterFrameChildComponentInjectionToken),
watchHistoryState: di.inject(watchHistoryStateInjectable),
};
},
});
ClusterFrame.displayName = "ClusterFrame";
@@ -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";
import webFrameInjectable from "./web-frame/web-frame.injectable";
const frameRoutingIdInjectable = getInjectable({
id: "frame-routing-id",
instantiate: (di) => di.inject(webFrameInjectable).routingId,
});
export default frameRoutingIdInjectable;
@@ -0,0 +1,14 @@
/**
* 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 { webFrame } from "electron";
const webFrameInjectable = getInjectable({
id: "web-frame",
instantiate: () => webFrame,
causesSideEffects: true,
});
export default webFrameInjectable;
@@ -0,0 +1,36 @@
/**
* 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 { initClusterFrame } from "./init-cluster-frame";
import catalogEntityRegistryInjectable from "../../../api/catalog/entity/registry.injectable";
import frameRoutingIdInjectable from "./frame-routing-id/frame-routing-id.injectable";
import hostedClusterInjectable from "../../../cluster-frame-context/hosted-cluster.injectable";
import assert from "assert";
import emitAppEventInjectable from "../../../../common/app-event-bus/emit-event.injectable";
import loadExtensionsInjectable from "../../load-extensions.injectable";
import loggerInjectable from "../../../../common/logger.injectable";
import showErrorNotificationInjectable from "../../../components/notifications/show-error-notification.injectable";
const initClusterFrameInjectable = getInjectable({
id: "init-cluster-frame",
instantiate: (di) => {
const hostedCluster = di.inject(hostedClusterInjectable);
assert(hostedCluster, "This can only be injected within a cluster frame");
return initClusterFrame({
hostedCluster,
loadExtensions: di.inject(loadExtensionsInjectable),
catalogEntityRegistry: di.inject(catalogEntityRegistryInjectable),
frameRoutingId: di.inject(frameRoutingIdInjectable),
emitAppEvent: di.inject(emitAppEventInjectable),
logger: di.inject(loggerInjectable),
showErrorNotification: di.inject(showErrorNotificationInjectable),
});
},
});
export default initClusterFrameInjectable;
@@ -0,0 +1,83 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import type { Cluster } from "../../../../common/cluster/cluster";
import type { CatalogEntityRegistry } from "../../../api/catalog/entity/registry";
import type { ShowNotification } from "../../../components/notifications";
import { when } from "mobx";
import { requestSetClusterFrameId } from "../../../ipc";
import type { EmitAppEvent } from "../../../../common/app-event-bus/emit-event.injectable";
import type { Logger } from "../../../../common/logger";
interface Dependencies {
hostedCluster: Cluster;
loadExtensions: () => void;
catalogEntityRegistry: CatalogEntityRegistry;
frameRoutingId: number;
emitAppEvent: EmitAppEvent;
logger: Logger;
showErrorNotification: ShowNotification;
}
const logPrefix = "[CLUSTER-FRAME]:";
export const initClusterFrame = ({
hostedCluster,
loadExtensions,
catalogEntityRegistry,
frameRoutingId,
emitAppEvent,
logger,
showErrorNotification,
}: Dependencies) =>
async (unmountRoot: () => void) => {
// TODO: Make catalogEntityRegistry already initialized when passed as dependency
catalogEntityRegistry.init();
logger.info(
`${logPrefix} Init dashboard, clusterId=${hostedCluster.id}, frameId=${frameRoutingId}`,
);
await requestSetClusterFrameId(hostedCluster.id);
await hostedCluster.whenReady; // cluster.activate() is done at this point
catalogEntityRegistry.activeEntity = hostedCluster.id;
// Only load the extensions once the catalog has been populated.
// Note that the Catalog might still have unprocessed entities until the extensions are fully loaded.
when(
() => catalogEntityRegistry.items.get().length > 0,
() =>
loadExtensions(),
{
timeout: 15_000,
onError: (error) => {
logger.warn(
"[CLUSTER-FRAME]: error from activeEntity when()",
error,
);
showErrorNotification("Failed to get KubernetesCluster for this view. Extensions will not be loaded.");
},
},
);
setTimeout(() => {
emitAppEvent({
name: "cluster",
action: "open",
params: {
clusterId: hostedCluster.id,
},
});
});
window.onbeforeunload = () => {
logger.info(
`${logPrefix} Unload dashboard, clusterId=${(hostedCluster.id)}, frameId=${frameRoutingId}`,
);
unmountRoot();
};
};
@@ -0,0 +1,35 @@
/**
* 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 clusterOverviewRouteInjectable from "../../../common/front-end-routing/routes/cluster/overview/cluster-overview-route.injectable";
import workloadsOverviewRouteInjectable from "../../../common/front-end-routing/routes/cluster/workloads/overview/workloads-overview-route.injectable";
const startUrlInjectable = getInjectable({
id: "start-url",
instantiate: (di) => {
const clusterOverviewRoute = di.inject(clusterOverviewRouteInjectable);
const workloadOverviewRoute = di.inject(workloadsOverviewRouteInjectable);
return computed(() => {
if (clusterOverviewRoute.isEnabled.get()) {
return clusterOverviewRoute.path;
}
if (workloadOverviewRoute.isEnabled.get()) {
return workloadOverviewRoute.path;
}
/**
* NOTE: This will never be executed as `workloadOverviewRoute.isEnabled` always is true. It
* is here is guard against accidental changes at a distance within `workloadOverviewRoute`.
*/
throw new Error("Exhausted all possible starting locations and none are active. This is a bug.");
});
},
});
export default startUrlInjectable;
@@ -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 extensionLoaderInjectable from "../../extensions/extension-loader/extension-loader.injectable";
const loadExtensionsInjectable = getInjectable({
id: "load-extensions",
instantiate: (di) => {
const extensionLoader = di.inject(extensionLoaderInjectable);
return () => extensionLoader.autoInitExtensions();
},
});
export default loadExtensionsInjectable;
@@ -0,0 +1,21 @@
/**
* 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 { sendMessageToChannelInjectionToken } from "../../../common/utils/channel/message-to-channel-injection-token";
import { rootFrameHasRenderedChannel } from "../../../common/root-frame/root-frame-rendered-channel";
const broadcastThatRootFrameIsRenderedInjectable = getInjectable({
id: "broadcast-that-root-frame-is-rendered",
instantiate: (di) => {
const messageToChannel = di.inject(sendMessageToChannelInjectionToken);
return () => {
messageToChannel(rootFrameHasRenderedChannel);
};
},
});
export default broadcastThatRootFrameIsRenderedInjectable;
@@ -0,0 +1,69 @@
/**
* 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 ipcRendererInjectable from "../../utils/channel/ipc-renderer.injectable";
import bindProtocolAddRouteHandlersInjectable from "../../protocol-handler/bind-protocol-add-route-handlers/bind-protocol-add-route-handlers.injectable";
import lensProtocolRouterRendererInjectable from "../../protocol-handler/lens-protocol-router-renderer/lens-protocol-router-renderer.injectable";
import catalogEntityRegistryInjectable from "../../api/catalog/entity/registry.injectable";
import registerIpcListenersInjectable from "../../ipc/register-ipc-listeners.injectable";
import loadExtensionsInjectable from "../load-extensions.injectable";
import loggerInjectable from "../../../common/logger.injectable";
import { delay } from "../../../common/utils";
import { broadcastMessage } from "../../../common/ipc";
import { bundledExtensionsLoaded } from "../../../common/ipc/extension-handling";
const initRootFrameInjectable = getInjectable({
id: "init-root-frame",
instantiate: (di) => {
const loadExtensions = di.inject(loadExtensionsInjectable);
const registerIpcListeners = di.inject(registerIpcListenersInjectable);
const ipcRenderer = di.inject(ipcRendererInjectable);
const bindProtocolAddRouteHandlers = di.inject(bindProtocolAddRouteHandlersInjectable);
const lensProtocolRouterRenderer = di.inject(lensProtocolRouterRendererInjectable);
const catalogEntityRegistry = di.inject(catalogEntityRegistryInjectable);
const logger = di.inject(loggerInjectable);
return async (unmountRoot: () => void) => {
catalogEntityRegistry.init();
try {
// maximum time to let bundled extensions finish loading
const timeout = delay(10000);
const loadingExtensions = await loadExtensions();
const loadingBundledExtensions = loadingExtensions
.filter((e) => e.isBundled)
.map((e) => e.loaded);
const bundledExtensionsFinished = Promise.all(loadingBundledExtensions);
await Promise.race([bundledExtensionsFinished, timeout]);
} finally {
ipcRenderer.send(bundledExtensionsLoaded);
}
lensProtocolRouterRenderer.init();
bindProtocolAddRouteHandlers();
window.addEventListener("offline", () =>
broadcastMessage("network:offline"),
);
window.addEventListener("online", () => broadcastMessage("network:online"));
registerIpcListeners();
window.addEventListener("beforeunload", () => {
logger.info("[ROOT-FRAME]: Unload app");
unmountRoot();
});
};
},
});
export default initRootFrameInjectable;
@@ -0,0 +1,17 @@
/**
* 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 { IComputedValue } from "mobx";
export interface RootFrameChildComponent {
id: string;
Component: React.ElementType;
shouldRender: IComputedValue<boolean>;
}
export const rootFrameChildComponentInjectionToken = getInjectionToken<RootFrameChildComponent>({
id: "root-frame-child-component",
});
@@ -0,0 +1,49 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import React from "react";
import { Observer } from "mobx-react";
import { withInjectables } from "@ogre-tools/injectable-react";
import broadcastThatRootFrameIsRenderedInjectable from "./broadcast-that-root-frame-is-rendered.injectable";
import type { RootFrameChildComponent } from "./root-frame-child-component-injection-token";
import { rootFrameChildComponentInjectionToken } from "./root-frame-child-component-injection-token";
interface Dependencies {
broadcastThatRootFrameIsRendered: () => void;
childComponents: RootFrameChildComponent[];
}
class NonInjectedRootFrame extends React.Component<Dependencies> {
static displayName = "RootFrame";
componentDidMount() {
this.props.broadcastThatRootFrameIsRendered();
}
render() {
return (
<>
{this.props.childComponents
.map((child) => (
<Observer key={child.id}>
{() => (child.shouldRender.get() ? <child.Component /> : null) }
</Observer>
))}
</>
);
}
}
export const RootFrame = withInjectables<Dependencies>(
NonInjectedRootFrame,
{
getProps: (di, props) => ({
broadcastThatRootFrameIsRendered: di.inject(broadcastThatRootFrameIsRenderedInjectable),
childComponents: di.injectMany(rootFrameChildComponentInjectionToken),
...props,
}),
},
);
@@ -0,0 +1,18 @@
/**
* 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 { beforeFrameStartsSecondInjectionToken } from "../../before-frame-starts/tokens";
import injectSystemCAsInjectable from "../../../features/certificate-authorities/common/inject-system-cas.injectable";
const setupSystemCaInjectable = getInjectable({
id: "setup-system-ca",
instantiate: (di) => ({
id: "setup-system-ca",
run: di.inject(injectSystemCAsInjectable),
}),
injectionToken: beforeFrameStartsSecondInjectionToken,
});
export default setupSystemCaInjectable;