mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
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:
1 parent
0066ca4ea2
commit
2657df2293
3321 files changed
+28699
-11447
No files matched your search
+1593
File diff suppressed because it is too large.
Load diff
+17
@@ -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",
|
||||
});
|
||||
+42
@@ -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;
|
||||
+72
@@ -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";
|
||||
+13
@@ -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;
|
||||
+14
@@ -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;
|
||||
+36
@@ -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;
|
||||
+83
@@ -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;
|
||||
+21
@@ -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;
|
||||
+17
@@ -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;
|
||||
Reference in new issue
Block a user