mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
Extract responsibilities of WindowManager as injectables
Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com> Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>
This commit is contained in:
parent
5842db2cc3
commit
5ac9b2aa87
14
src/common/cluster-frames.injectable.ts
Normal file
14
src/common/cluster-frames.injectable.ts
Normal file
@ -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 { clusterFrameMap } from "./cluster-frames";
|
||||
|
||||
const clusterFramesInjectable = getInjectable({
|
||||
id: "cluster-frames",
|
||||
instantiate: () => clusterFrameMap,
|
||||
causesSideEffects: true,
|
||||
});
|
||||
|
||||
export default clusterFramesInjectable;
|
||||
@ -3,13 +3,13 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import type { DiContainer } from "@ogre-tools/injectable";
|
||||
import { beforeApplicationIsReadyInjectionToken } from "../../main/start-main-application/before-application-is-ready/before-application-is-ready-injection-token";
|
||||
import { beforeElectronIsReadyInjectionToken } from "../../main/start-main-application/before-electron-is-ready/before-electron-is-ready-injection-token";
|
||||
import { afterApplicationIsReadyInjectionToken } from "../../main/start-main-application/after-application-is-ready/after-application-is-ready-injection-token";
|
||||
|
||||
export const runSetups = async (di: DiContainer) => {
|
||||
await Promise.all(
|
||||
di
|
||||
.injectMany(beforeApplicationIsReadyInjectionToken)
|
||||
.injectMany(beforeElectronIsReadyInjectionToken)
|
||||
.map((setupable) => setupable.run()),
|
||||
);
|
||||
|
||||
|
||||
@ -10,8 +10,8 @@ import type { MenuRegistration } from "../main/menu/menu-registration";
|
||||
import type { TrayMenuRegistration } from "../main/tray/tray-menu-registration";
|
||||
import type { ShellEnvModifier } from "../main/shell-session/shell-env-modifier/shell-env-modifier-registration";
|
||||
import { Environments, getEnvironmentSpecificLegacyGlobalDiForExtensionApi } from "./as-legacy-globals-for-extension-api/legacy-global-di-for-extension-api";
|
||||
import windowManagerInjectable from "../main/window-manager.injectable";
|
||||
import catalogEntityRegistryInjectable from "../main/catalog/catalog-entity-registry.injectable";
|
||||
import navigateForExtensionInjectable from "../main/start-main-application/lens-window/navigate-for-extension.injectable";
|
||||
|
||||
export class LensMainExtension extends LensExtension {
|
||||
appMenus: MenuRegistration[] = [];
|
||||
@ -35,9 +35,9 @@ export class LensMainExtension extends LensExtension {
|
||||
async navigate(pageId?: string, params?: Record<string, any>, frameId?: number) {
|
||||
const di = getEnvironmentSpecificLegacyGlobalDiForExtensionApi(Environments.main);
|
||||
|
||||
const windowManager = di.inject(windowManagerInjectable);
|
||||
const navigate = di.inject(navigateForExtensionInjectable);
|
||||
|
||||
return windowManager.navigateExtension(this.id, pageId, params, frameId);
|
||||
return navigate(this.id, pageId, params, frameId);
|
||||
}
|
||||
|
||||
addCatalogSource(id: string, source: IObservableArray<CatalogEntity>) {
|
||||
|
||||
@ -8,12 +8,12 @@ import {
|
||||
getEnvironmentSpecificLegacyGlobalDiForExtensionApi,
|
||||
} from "../as-legacy-globals-for-extension-api/legacy-global-di-for-extension-api";
|
||||
|
||||
import windowManagerInjectable from "../../main/window-manager.injectable";
|
||||
import navigateInjectable from "../../main/start-main-application/lens-window/navigate.injectable";
|
||||
|
||||
export function navigate(url: string) {
|
||||
const di = getEnvironmentSpecificLegacyGlobalDiForExtensionApi(Environments.main);
|
||||
|
||||
const windowManager = di.inject(windowManagerInjectable);
|
||||
const navigate = di.inject(navigateInjectable);
|
||||
|
||||
return windowManager.navigate(url);
|
||||
return navigate(url);
|
||||
}
|
||||
|
||||
@ -16,8 +16,8 @@ import { appPathsIpcChannel } from "../../common/app-paths/app-path-injection-to
|
||||
import registerChannelInjectable from "./register-channel/register-channel.injectable";
|
||||
import joinPathsInjectable from "../../common/path/join-paths.injectable";
|
||||
import {
|
||||
beforeApplicationIsReadyInjectionToken,
|
||||
} from "../start-main-application/before-application-is-ready/before-application-is-ready-injection-token";
|
||||
beforeElectronIsReadyInjectionToken,
|
||||
} from "../start-main-application/before-electron-is-ready/before-electron-is-ready-injection-token";
|
||||
|
||||
const setupAppPathsInjectable = getInjectable({
|
||||
id: "setup-app-paths",
|
||||
@ -54,7 +54,7 @@ const setupAppPathsInjectable = getInjectable({
|
||||
};
|
||||
},
|
||||
|
||||
injectionToken: beforeApplicationIsReadyInjectionToken,
|
||||
injectionToken: beforeElectronIsReadyInjectionToken,
|
||||
});
|
||||
|
||||
export default setupAppPathsInjectable;
|
||||
|
||||
@ -6,12 +6,11 @@ import { getInjectable } from "@ogre-tools/injectable";
|
||||
import electronAppInjectable from "../electron-app.injectable";
|
||||
import openDeepLinkInjectable from "../../protocol-handler/lens-protocol-router-main/open-deep-link-for-url/open-deep-link.injectable";
|
||||
import loggerInjectable from "../../../common/logger.injectable";
|
||||
import { afterApplicationIsReadyInjectionToken } from "../../start-main-application/after-application-is-ready/after-application-is-ready-injection-token";
|
||||
import commandLineArgumentsInjectable from "../../utils/command-line-arguments.injectable";
|
||||
import { pipeline } from "@ogre-tools/fp";
|
||||
import { find, startsWith, toLower, map } from "lodash/fp";
|
||||
import ensureMainWindowInjectable from "../../ensure-main-window/ensure-main-window.injectable";
|
||||
import enforceSingleApplicationInstanceInjectable from "./enforce-single-application-instance.injectable";
|
||||
import { whenApplicationIsLoadingInjectionToken } from "../../start-main-application/when-application-is-loading/when-application-is-loading-injection-token";
|
||||
import applicationWindowInjectable from "../../start-main-application/lens-window/application-window/application-window.injectable";
|
||||
|
||||
const setupDeepLinkingInjectable = getInjectable({
|
||||
id: "setup-deep-linking",
|
||||
@ -20,57 +19,52 @@ const setupDeepLinkingInjectable = getInjectable({
|
||||
const app = di.inject(electronAppInjectable);
|
||||
const logger = di.inject(loggerInjectable);
|
||||
const openDeepLinkForUrl = di.inject(openDeepLinkInjectable);
|
||||
const applicationWindow = di.inject(applicationWindowInjectable);
|
||||
|
||||
const firstInstanceCommandLineArguments = di.inject(
|
||||
commandLineArgumentsInjectable,
|
||||
);
|
||||
|
||||
const ensureMainWindow = di.inject(ensureMainWindowInjectable);
|
||||
|
||||
return {
|
||||
runAfter: di.inject(enforceSingleApplicationInstanceInjectable),
|
||||
|
||||
run: async () => {
|
||||
{
|
||||
logger.info(`📟 Setting protocol client for lens://`);
|
||||
logger.info(`📟 Setting protocol client for lens://`);
|
||||
|
||||
if (app.setAsDefaultProtocolClient("lens")) {
|
||||
logger.info("📟 Protocol client register succeeded ✅");
|
||||
} else {
|
||||
logger.info("📟 Protocol client register failed ❗");
|
||||
}
|
||||
|
||||
app.on("open-url", async (event, url) => {
|
||||
event.preventDefault();
|
||||
|
||||
await openDeepLinkForUrl(url);
|
||||
});
|
||||
|
||||
app.on(
|
||||
"second-instance",
|
||||
|
||||
async (_, secondInstanceCommandLineArguments) => {
|
||||
const url = getDeepLinkUrl(secondInstanceCommandLineArguments);
|
||||
|
||||
await ensureMainWindow();
|
||||
|
||||
if (url) {
|
||||
await openDeepLinkForUrl(url);
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
const url = getDeepLinkUrl(firstInstanceCommandLineArguments);
|
||||
|
||||
if (url) {
|
||||
await openDeepLinkForUrl(url);
|
||||
}
|
||||
if (app.setAsDefaultProtocolClient("lens")) {
|
||||
logger.info("📟 Protocol client register succeeded ✅");
|
||||
} else {
|
||||
logger.info("📟 Protocol client register failed ❗");
|
||||
}
|
||||
|
||||
const url = getDeepLinkUrl(firstInstanceCommandLineArguments);
|
||||
|
||||
if (url) {
|
||||
await openDeepLinkForUrl(url);
|
||||
}
|
||||
|
||||
app.on("open-url", async (event, url) => {
|
||||
event.preventDefault();
|
||||
|
||||
await openDeepLinkForUrl(url);
|
||||
});
|
||||
|
||||
app.on(
|
||||
"second-instance",
|
||||
|
||||
async (_, secondInstanceCommandLineArguments) => {
|
||||
const url = getDeepLinkUrl(secondInstanceCommandLineArguments);
|
||||
|
||||
await applicationWindow.show();
|
||||
|
||||
if (url) {
|
||||
await openDeepLinkForUrl(url);
|
||||
}
|
||||
},
|
||||
);
|
||||
},
|
||||
};
|
||||
},
|
||||
|
||||
injectionToken: afterApplicationIsReadyInjectionToken,
|
||||
injectionToken: whenApplicationIsLoadingInjectionToken,
|
||||
});
|
||||
|
||||
export default setupDeepLinkingInjectable;
|
||||
|
||||
@ -3,8 +3,8 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { afterApplicationIsReadyInjectionToken } from "../../start-main-application/after-application-is-ready/after-application-is-ready-injection-token";
|
||||
import loggerInjectable from "../../../common/logger.injectable";
|
||||
import { whenApplicationIsLoadingInjectionToken } from "../../start-main-application/when-application-is-loading/when-application-is-loading-injection-token";
|
||||
|
||||
const setupDeveloperToolsInDevelopmentEnvironmentInjectable = getInjectable({
|
||||
id: "setup-developer-tools-in-development-environment",
|
||||
@ -34,7 +34,7 @@ const setupDeveloperToolsInDevelopmentEnvironmentInjectable = getInjectable({
|
||||
};
|
||||
},
|
||||
|
||||
injectionToken: afterApplicationIsReadyInjectionToken,
|
||||
injectionToken: whenApplicationIsLoadingInjectionToken,
|
||||
});
|
||||
|
||||
export default setupDeveloperToolsInDevelopmentEnvironmentInjectable;
|
||||
|
||||
@ -3,9 +3,9 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { afterApplicationIsReadyInjectionToken } from "../../start-main-application/after-application-is-ready/after-application-is-ready-injection-token";
|
||||
import powerMonitorInjectable from "../features/power-monitor.injectable";
|
||||
import exitAppInjectable from "../features/exit-app.injectable";
|
||||
import { whenApplicationIsLoadingInjectionToken } from "../../start-main-application/when-application-is-loading/when-application-is-loading-injection-token";
|
||||
|
||||
const setupDeviceShutdownInjectable = getInjectable({
|
||||
id: "setup-device-shutdown",
|
||||
@ -23,7 +23,7 @@ const setupDeviceShutdownInjectable = getInjectable({
|
||||
};
|
||||
},
|
||||
|
||||
injectionToken: afterApplicationIsReadyInjectionToken,
|
||||
injectionToken: whenApplicationIsLoadingInjectionToken,
|
||||
});
|
||||
|
||||
export default setupDeviceShutdownInjectable;
|
||||
|
||||
@ -9,9 +9,9 @@ import loggerInjectable from "../../../../common/logger.injectable";
|
||||
import clusterManagerInjectable from "../../../cluster-manager.injectable";
|
||||
import applicationMenuItemsInjectable from "../../../menu/application-menu-items.injectable";
|
||||
import getAbsolutePathInjectable from "../../../../common/path/get-absolute-path.injectable";
|
||||
import { afterApplicationIsReadyInjectionToken } from "../../../start-main-application/after-application-is-ready/after-application-is-ready-injection-token";
|
||||
import catalogEntityRegistryInjectable from "../../../catalog/catalog-entity-registry.injectable";
|
||||
import clusterStoreInjectable from "../../../../common/cluster-store/cluster-store.injectable";
|
||||
import { whenApplicationIsLoadingInjectionToken } from "../../../start-main-application/when-application-is-loading/when-application-is-loading-injection-token";
|
||||
|
||||
const setupIpcMainHandlersInjectable = getInjectable({
|
||||
id: "setup-ipc-main-handlers",
|
||||
@ -45,7 +45,7 @@ const setupIpcMainHandlersInjectable = getInjectable({
|
||||
};
|
||||
},
|
||||
|
||||
injectionToken: afterApplicationIsReadyInjectionToken,
|
||||
injectionToken: whenApplicationIsLoadingInjectionToken,
|
||||
});
|
||||
|
||||
export default setupIpcMainHandlersInjectable;
|
||||
|
||||
@ -4,16 +4,16 @@
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import electronAppInjectable from "../electron-app.injectable";
|
||||
import { afterApplicationIsReadyInjectionToken } from "../../start-main-application/after-application-is-ready/after-application-is-ready-injection-token";
|
||||
import ensureMainWindowInjectable from "../../ensure-main-window/ensure-main-window.injectable";
|
||||
import loggerInjectable from "../../../common/logger.injectable";
|
||||
import { whenApplicationIsLoadingInjectionToken } from "../../start-main-application/when-application-is-loading/when-application-is-loading-injection-token";
|
||||
import applicationWindowInjectable from "../../start-main-application/lens-window/application-window/application-window.injectable";
|
||||
|
||||
const setupMainWindowVisibilityAfterActivationInjectable = getInjectable({
|
||||
id: "setup-main-window-visibility-after-activation",
|
||||
|
||||
instantiate: (di) => {
|
||||
const app = di.inject(electronAppInjectable);
|
||||
const ensureMainWindow = di.inject(ensureMainWindowInjectable);
|
||||
const applicationWindow = di.inject(applicationWindowInjectable);
|
||||
const logger = di.inject(loggerInjectable);
|
||||
|
||||
return {
|
||||
@ -22,14 +22,14 @@ const setupMainWindowVisibilityAfterActivationInjectable = getInjectable({
|
||||
logger.info("APP:ACTIVATE", { hasVisibleWindows: windowIsVisible });
|
||||
|
||||
if (!windowIsVisible) {
|
||||
await ensureMainWindow(false);
|
||||
await applicationWindow.show();
|
||||
}
|
||||
});
|
||||
},
|
||||
};
|
||||
},
|
||||
|
||||
injectionToken: afterApplicationIsReadyInjectionToken,
|
||||
injectionToken: whenApplicationIsLoadingInjectionToken,
|
||||
});
|
||||
|
||||
export default setupMainWindowVisibilityAfterActivationInjectable;
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { broadcastNativeThemeOnUpdate } from "../../native-theme";
|
||||
import { afterApplicationIsReadyInjectionToken } from "../../start-main-application/after-application-is-ready/after-application-is-ready-injection-token";
|
||||
import { whenApplicationIsLoadingInjectionToken } from "../../start-main-application/when-application-is-loading/when-application-is-loading-injection-token";
|
||||
|
||||
const setupOsThemeUpdatesInjectable = getInjectable({
|
||||
id: "setup-os-theme-updates",
|
||||
@ -18,7 +18,7 @@ const setupOsThemeUpdatesInjectable = getInjectable({
|
||||
// Todo: remove explicit usage of IPC to get rid of this.
|
||||
causesSideEffects: true,
|
||||
|
||||
injectionToken: afterApplicationIsReadyInjectionToken,
|
||||
injectionToken: whenApplicationIsLoadingInjectionToken,
|
||||
});
|
||||
|
||||
export default setupOsThemeUpdatesInjectable;
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { beforeApplicationIsReadyInjectionToken } from "../../start-main-application/before-application-is-ready/before-application-is-ready-injection-token";
|
||||
import { beforeElectronIsReadyInjectionToken } from "../../start-main-application/before-electron-is-ready/before-electron-is-ready-injection-token";
|
||||
import requestSingleInstanceLockInjectable from "../features/request-single-instance-lock.injectable";
|
||||
import exitAppInjectable from "../features/exit-app.injectable";
|
||||
|
||||
@ -23,7 +23,7 @@ const enforceSingleApplicationInstanceInjectable = getInjectable({
|
||||
};
|
||||
},
|
||||
|
||||
injectionToken: beforeApplicationIsReadyInjectionToken,
|
||||
injectionToken: beforeElectronIsReadyInjectionToken,
|
||||
});
|
||||
|
||||
export default enforceSingleApplicationInstanceInjectable;
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import appNameInjectable from "../../app-paths/app-name/app-name.injectable";
|
||||
import { beforeApplicationIsReadyInjectionToken } from "../../start-main-application/before-application-is-ready/before-application-is-ready-injection-token";
|
||||
import { beforeElectronIsReadyInjectionToken } from "../../start-main-application/before-electron-is-ready/before-electron-is-ready-injection-token";
|
||||
import electronAppInjectable from "../electron-app.injectable";
|
||||
|
||||
const setupApplicationNameInjectable = getInjectable({
|
||||
@ -21,7 +21,7 @@ const setupApplicationNameInjectable = getInjectable({
|
||||
};
|
||||
},
|
||||
|
||||
injectionToken: beforeApplicationIsReadyInjectionToken,
|
||||
injectionToken: beforeElectronIsReadyInjectionToken,
|
||||
});
|
||||
|
||||
export default setupApplicationNameInjectable;
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { beforeApplicationIsReadyInjectionToken } from "../../start-main-application/before-application-is-ready/before-application-is-ready-injection-token";
|
||||
import { beforeElectronIsReadyInjectionToken } from "../../start-main-application/before-electron-is-ready/before-electron-is-ready-injection-token";
|
||||
import { beforeQuitOfFrontEndInjectionToken } from "../../start-main-application/before-quit-of-front-end/before-quit-of-front-end-injection-token";
|
||||
import { beforeQuitOfBackEndInjectionToken } from "../../start-main-application/before-quit-of-back-end/before-quit-of-back-end-injection-token";
|
||||
import electronAppInjectable from "../electron-app.injectable";
|
||||
@ -54,7 +54,7 @@ const setupRunnablesBeforeClosingOfApplicationInjectable = getInjectable({
|
||||
};
|
||||
},
|
||||
|
||||
injectionToken: beforeApplicationIsReadyInjectionToken,
|
||||
injectionToken: beforeElectronIsReadyInjectionToken,
|
||||
});
|
||||
|
||||
export default setupRunnablesBeforeClosingOfApplicationInjectable;
|
||||
|
||||
@ -0,0 +1,28 @@
|
||||
/**
|
||||
* 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 electronDialogInjectable from "./electron-dialog.injectable";
|
||||
|
||||
export type ShowMessagePopup = (title: string, message: string, detail: string) => void;
|
||||
|
||||
const showMessagePopupInjectable = getInjectable({
|
||||
id: "show-message-popup",
|
||||
|
||||
instantiate: (di): ShowMessagePopup => {
|
||||
const dialog = di.inject(electronDialogInjectable);
|
||||
|
||||
return async (title, message, detail) => {
|
||||
await dialog.showMessageBox({
|
||||
title,
|
||||
message,
|
||||
detail,
|
||||
type: "info",
|
||||
buttons: ["Close"],
|
||||
});
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
export default showMessagePopupInjectable;
|
||||
@ -1,20 +0,0 @@
|
||||
/**
|
||||
* 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 windowManagerInjectable from "../window-manager.injectable";
|
||||
|
||||
const ensureMainWindowInjectable = getInjectable({
|
||||
id: "ensure-main-window",
|
||||
|
||||
instantiate: (di) => {
|
||||
const windowManager = di.inject(windowManagerInjectable);
|
||||
|
||||
return async (showSplash = true) => {
|
||||
await windowManager.ensureMainWindow(showSplash);
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
export default ensureMainWindowInjectable;
|
||||
@ -38,25 +38,24 @@ import appEventBusInjectable from "../common/app-event-bus/app-event-bus.injecta
|
||||
import { EventEmitter } from "../common/event-emitter";
|
||||
import type { AppEvent } from "../common/app-event-bus/event-bus";
|
||||
import commandLineArgumentsInjectable from "./utils/command-line-arguments.injectable";
|
||||
import initializeExtensionsInjectable from "./start-main-application/after-application-is-ready/implementations/initialize-extensions.injectable";
|
||||
import initializeExtensionsInjectable from "./start-main-application/when-application-is-loading/implementations/initialize-extensions.injectable";
|
||||
import lensResourcesDirInjectable from "../common/vars/lens-resources-dir.injectable";
|
||||
import registerFileProtocolInjectable from "./electron-app/features/register-file-protocol.injectable";
|
||||
import environmentVariablesInjectable from "../common/utils/environment-variables.injectable";
|
||||
import { CatalogCategoryRegistry } from "../common/catalog";
|
||||
import catalogCategoryRegistryInjectable from "../common/catalog/catalog-category-registry.injectable";
|
||||
import setupIpcMainHandlersInjectable from "./electron-app/after-application-is-ready/setup-ipc-main-handlers/setup-ipc-main-handlers.injectable";
|
||||
import setupLensProxyInjectable from "./start-main-application/after-application-is-ready/implementations/setup-lens-proxy.injectable";
|
||||
import setupRunnablesForAfterRootFrameIsReadyInjectable from "./start-main-application/after-application-is-ready/implementations/setup-runnables-for-after-root-frame-is-ready.injectable";
|
||||
import setupLensProxyInjectable from "./start-main-application/before-application-is-loading/implementations/setup-lens-proxy.injectable";
|
||||
import setupRunnablesForAfterRootFrameIsReadyInjectable from "./start-main-application/when-application-is-loading/implementations/setup-runnables-for-after-root-frame-is-ready.injectable";
|
||||
import setupOsThemeUpdatesInjectable from "./electron-app/after-application-is-ready/setup-os-theme-updates.injectable";
|
||||
import setupSentryInjectable from "./start-main-application/after-application-is-ready/implementations/setup-sentry.injectable";
|
||||
import setupShellInjectable from "./start-main-application/after-application-is-ready/implementations/setup-shell.injectable";
|
||||
import setupSyncingOfWeblinksInjectable from "./start-main-application/after-application-is-ready/implementations/setup-syncing-of-weblinks.injectable";
|
||||
import setupSentryInjectable from "./start-main-application/when-application-is-loading/implementations/setup-sentry.injectable";
|
||||
import setupShellInjectable from "./start-main-application/when-application-is-loading/implementations/setup-shell.injectable";
|
||||
import setupSyncingOfWeblinksInjectable from "./start-main-application/when-application-is-loading/implementations/setup-syncing-of-weblinks.injectable";
|
||||
import stopServicesAndExitAppInjectable from "./stop-services-and-exit-app.injectable";
|
||||
import trayInjectable from "./tray/tray.injectable";
|
||||
import applicationMenuInjectable from "./menu/application-menu.injectable";
|
||||
import windowManagerInjectable from "./window-manager.injectable";
|
||||
import isDevelopmentInjectable from "../common/vars/is-development.injectable";
|
||||
import setupSystemCaInjectable from "./start-main-application/after-application-is-ready/implementations/setup-system-ca.injectable";
|
||||
import setupSystemCaInjectable from "./start-main-application/before-application-is-loading/implementations/setup-system-ca.injectable";
|
||||
import setupDeepLinkingInjectable from "./electron-app/after-application-is-ready/setup-deep-linking.injectable";
|
||||
import exitAppInjectable from "./electron-app/features/exit-app.injectable";
|
||||
import getCommandLineSwitchInjectable from "./electron-app/features/get-command-line-switch.injectable";
|
||||
@ -69,6 +68,12 @@ import setupMainWindowVisibilityAfterActivationInjectable from "./electron-app/a
|
||||
import setupDeviceShutdownInjectable from "./electron-app/after-application-is-ready/setup-device-shutdown.injectable";
|
||||
import setupApplicationNameInjectable from "./electron-app/before-application-is-ready/setup-application-name.injectable";
|
||||
import setupRunnablesBeforeClosingOfApplicationInjectable from "./electron-app/before-application-is-ready/setup-runnables-before-closing-of-application.injectable";
|
||||
import showMessagePopupInjectable from "./electron-app/features/show-message-popup.injectable";
|
||||
import clusterFramesInjectable from "../common/cluster-frames.injectable";
|
||||
import type { ClusterFrameInfo } from "../common/cluster-frames";
|
||||
import { observable } from "mobx";
|
||||
import createBrowserWindowInjectable from "./start-main-application/lens-window/application-window/create-browser-window.injectable";
|
||||
import type { BrowserWindow } from "electron";
|
||||
|
||||
export const getDiForUnitTesting = (
|
||||
{ doGeneralOverrides } = { doGeneralOverrides: false },
|
||||
@ -98,9 +103,10 @@ export const getDiForUnitTesting = (
|
||||
di.override(environmentVariablesInjectable, () => ({}));
|
||||
di.override(commandLineArgumentsInjectable, () => []);
|
||||
|
||||
di.override(clusterFramesInjectable, () => observable.map<string, ClusterFrameInfo>());
|
||||
|
||||
di.override(stopServicesAndExitAppInjectable, () => () => {});
|
||||
di.override(lensResourcesDirInjectable, () => "/irrelevant");
|
||||
di.override(windowManagerInjectable, () => ({ ensureMainWindow: () => Promise.resolve(null) }));
|
||||
|
||||
di.override(trayInjectable, () => ({ start: () => {}, stop: () => {} }));
|
||||
di.override(applicationMenuInjectable, () => ({ start: () => {}, stop: () => {} }));
|
||||
@ -204,6 +210,12 @@ const overrideElectronFeatures = (di: DiContainer) => {
|
||||
di.override(requestSingleInstanceLockInjectable, () => () => true);
|
||||
di.override(disableHardwareAccelerationInjectable, () => () => {});
|
||||
di.override(shouldStartHiddenInjectable, () => true);
|
||||
di.override(showMessagePopupInjectable, () => () => {});
|
||||
|
||||
di.override(createBrowserWindowInjectable, () => async () => ({
|
||||
show: () => {},
|
||||
hide: () => {},
|
||||
}) as unknown as BrowserWindow);
|
||||
|
||||
di.override(
|
||||
getElectronAppPathInjectable,
|
||||
|
||||
@ -7,12 +7,8 @@ import { checkForUpdates } from "../app-updater";
|
||||
import { docsUrl, productName, supportUrl } from "../../common/vars";
|
||||
import { broadcastMessage } from "../../common/ipc";
|
||||
import { openBrowser } from "../../common/utils";
|
||||
import { showAbout } from "./menu";
|
||||
import windowManagerInjectable from "../window-manager.injectable";
|
||||
import type { MenuItemConstructorOptions } from "electron";
|
||||
import {
|
||||
webContents,
|
||||
} from "electron";
|
||||
import { webContents } from "electron";
|
||||
import loggerInjectable from "../../common/logger.injectable";
|
||||
import appNameInjectable from "../app-paths/app-name/app-name.injectable";
|
||||
import electronMenuItemsInjectable from "./electron-menu-items.injectable";
|
||||
@ -25,6 +21,9 @@ import navigateToAddClusterInjectable from "../../common/front-end-routing/route
|
||||
import stopServicesAndExitAppInjectable from "../stop-services-and-exit-app.injectable";
|
||||
import isMacInjectable from "../../common/vars/is-mac.injectable";
|
||||
import { computed } from "mobx";
|
||||
import showAboutInjectable from "./show-about.injectable";
|
||||
import applicationWindowInjectable from "../start-main-application/lens-window/application-window/application-window.injectable";
|
||||
import reloadWindowInjectable from "../start-main-application/lens-window/reload-window.injectable";
|
||||
|
||||
function ignoreIf(check: boolean, menuItems: MenuItemConstructorOptions[]) {
|
||||
return check ? [] : menuItems;
|
||||
@ -43,12 +42,14 @@ const applicationMenuItemsInjectable = getInjectable({
|
||||
const isMac = di.inject(isMacInjectable);
|
||||
const isAutoUpdateEnabled = di.inject(isAutoUpdateEnabledInjectable);
|
||||
const electronMenuItems = di.inject(electronMenuItemsInjectable);
|
||||
const showAbout = di.inject(showAboutInjectable);
|
||||
const applicationWindow = di.inject(applicationWindowInjectable);
|
||||
const reloadApplicationWindow = di.inject(reloadWindowInjectable, applicationWindow);
|
||||
|
||||
return computed((): MenuItemOpts[] => {
|
||||
|
||||
// TODO: These injects should happen outside of the computed.
|
||||
// TODO: Remove temporal dependencies in WindowManager to make sure timing is correct.
|
||||
const windowManager = di.inject(windowManagerInjectable);
|
||||
const stopServicesAndExitApp = di.inject(stopServicesAndExitAppInjectable);
|
||||
const navigateToPreferences = di.inject(navigateToPreferencesInjectable);
|
||||
const navigateToExtensions = di.inject(navigateToExtensionsInjectable);
|
||||
@ -75,7 +76,7 @@ const applicationMenuItemsInjectable = getInjectable({
|
||||
{
|
||||
label: "Check for updates",
|
||||
click() {
|
||||
checkForUpdates().then(() => windowManager.ensureMainWindow());
|
||||
checkForUpdates().then(() => applicationWindow.show());
|
||||
},
|
||||
},
|
||||
]),
|
||||
@ -239,7 +240,7 @@ const applicationMenuItemsInjectable = getInjectable({
|
||||
accelerator: "CmdOrCtrl+R",
|
||||
id: "reload",
|
||||
click() {
|
||||
windowManager.reload();
|
||||
reloadApplicationWindow();
|
||||
},
|
||||
},
|
||||
{ role: "toggleDevTools" },
|
||||
@ -293,7 +294,7 @@ const applicationMenuItemsInjectable = getInjectable({
|
||||
label: "Check for updates",
|
||||
click() {
|
||||
checkForUpdates().then(() =>
|
||||
windowManager.ensureMainWindow(),
|
||||
applicationWindow.show(),
|
||||
);
|
||||
},
|
||||
},
|
||||
|
||||
@ -2,14 +2,19 @@
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { app, dialog, Menu } from "electron";
|
||||
import { app, Menu } from "electron";
|
||||
import { appName, isWindows, productName } from "../../common/vars";
|
||||
import packageJson from "../../../package.json";
|
||||
import type { MenuItemOpts } from "./application-menu-items.injectable";
|
||||
import type { ShowMessagePopup } from "../electron-app/features/show-message-popup.injectable";
|
||||
|
||||
export type MenuTopId = "mac" | "file" | "edit" | "view" | "help";
|
||||
|
||||
export function showAbout() {
|
||||
interface Dependencies {
|
||||
showMessagePopup: ShowMessagePopup;
|
||||
}
|
||||
|
||||
export const showAbout = ({ showMessagePopup }: Dependencies) => async () => {
|
||||
const appInfo = [
|
||||
`${appName}: ${app.getVersion()}`,
|
||||
`Electron: ${process.versions.electron}`,
|
||||
@ -18,14 +23,12 @@ export function showAbout() {
|
||||
packageJson.copyright,
|
||||
];
|
||||
|
||||
dialog.showMessageBoxSync({
|
||||
title: `${isWindows ? " ".repeat(2) : ""}${appName}`,
|
||||
type: "info",
|
||||
buttons: ["Close"],
|
||||
message: productName,
|
||||
detail: appInfo.join("\r\n"),
|
||||
});
|
||||
}
|
||||
await showMessagePopup(
|
||||
`${isWindows ? " ".repeat(2) : ""}${appName}`,
|
||||
productName,
|
||||
appInfo.join("\r\n"),
|
||||
);
|
||||
};
|
||||
|
||||
export function buildMenu(
|
||||
applicationMenuItems: MenuItemOpts[],
|
||||
|
||||
16
src/main/menu/show-about.injectable.ts
Normal file
16
src/main/menu/show-about.injectable.ts
Normal file
@ -0,0 +1,16 @@
|
||||
/**
|
||||
* 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 { showAbout } from "./menu";
|
||||
import showMessagePopupInjectable from "../electron-app/features/show-message-popup.injectable";
|
||||
|
||||
const showAboutInjectable = getInjectable({
|
||||
id: "show-about",
|
||||
|
||||
instantiate: (di) =>
|
||||
showAbout({ showMessagePopup: di.inject(showMessagePopupInjectable) }),
|
||||
});
|
||||
|
||||
export default showAboutInjectable;
|
||||
@ -3,8 +3,8 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { afterApplicationIsReadyInjectionToken } from "../start-main-application/after-application-is-ready/after-application-is-ready-injection-token";
|
||||
import applicationMenuInjectable from "./application-menu.injectable";
|
||||
import { whenApplicationIsLoadingInjectionToken } from "../start-main-application/when-application-is-loading/when-application-is-loading-injection-token";
|
||||
|
||||
const startApplicationMenuInjectable = getInjectable({
|
||||
id: "start-application-menu",
|
||||
@ -21,7 +21,7 @@ const startApplicationMenuInjectable = getInjectable({
|
||||
};
|
||||
},
|
||||
|
||||
injectionToken: afterApplicationIsReadyInjectionToken,
|
||||
injectionToken: whenApplicationIsLoadingInjectionToken,
|
||||
});
|
||||
|
||||
export default startApplicationMenuInjectable;
|
||||
|
||||
@ -3,17 +3,17 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import windowManagerInjectable from "../window-manager.injectable";
|
||||
import { navigateToUrlInjectionToken } from "../../common/front-end-routing/navigate-to-url-injection-token";
|
||||
import navigateInjectable from "../start-main-application/lens-window/navigate.injectable";
|
||||
|
||||
const navigateToUrlInjectable = getInjectable({
|
||||
id: "navigate-to-url",
|
||||
|
||||
instantiate: (di) => {
|
||||
const windowManager = di.inject(windowManagerInjectable);
|
||||
const navigate = di.inject(navigateInjectable);
|
||||
|
||||
return (url) => {
|
||||
windowManager.navigateSync(url);
|
||||
navigate(url);
|
||||
};
|
||||
},
|
||||
|
||||
|
||||
@ -6,7 +6,7 @@ import { getInjectable } from "@ogre-tools/injectable";
|
||||
import extensionLoaderInjectable from "../../../extensions/extension-loader/extension-loader.injectable";
|
||||
import { LensProtocolRouterMain } from "./lens-protocol-router-main";
|
||||
import extensionsStoreInjectable from "../../../extensions/extensions-store/extensions-store.injectable";
|
||||
import windowManagerInjectable from "../../window-manager.injectable";
|
||||
import applicationWindowInjectable from "../../start-main-application/lens-window/application-window/application-window.injectable";
|
||||
|
||||
const lensProtocolRouterMainInjectable = getInjectable({
|
||||
id: "lens-protocol-router-main",
|
||||
@ -15,7 +15,7 @@ const lensProtocolRouterMainInjectable = getInjectable({
|
||||
new LensProtocolRouterMain({
|
||||
extensionLoader: di.inject(extensionLoaderInjectable),
|
||||
extensionsStore: di.inject(extensionsStoreInjectable),
|
||||
windowManager: di.inject(windowManagerInjectable),
|
||||
applicationWindow: di.inject(applicationWindowInjectable),
|
||||
}),
|
||||
});
|
||||
|
||||
|
||||
@ -12,9 +12,11 @@ import { observable, when, makeObservable } from "mobx";
|
||||
import type { RouteAttempt } from "../../../common/protocol-handler";
|
||||
import { ProtocolHandlerInvalid } from "../../../common/protocol-handler";
|
||||
import { disposer, noop } from "../../../common/utils";
|
||||
import type { WindowManager } from "../../window-manager";
|
||||
import type { ExtensionLoader } from "../../../extensions/extension-loader";
|
||||
import type { ExtensionsStore } from "../../../extensions/extensions-store/extensions-store";
|
||||
import type {
|
||||
LensWindow,
|
||||
} from "../../start-main-application/lens-window/application-window/lens-window-injection-token";
|
||||
|
||||
export interface FallbackHandler {
|
||||
(name: string): Promise<boolean>;
|
||||
@ -40,7 +42,7 @@ function checkHost<Query>(url: URLParse<Query>): boolean {
|
||||
interface Dependencies {
|
||||
extensionLoader: ExtensionLoader;
|
||||
extensionsStore: ExtensionsStore;
|
||||
windowManager: WindowManager;
|
||||
applicationWindow: LensWindow;
|
||||
}
|
||||
|
||||
export class LensProtocolRouterMain extends proto.LensProtocolRouter {
|
||||
@ -77,7 +79,7 @@ export class LensProtocolRouterMain extends proto.LensProtocolRouter {
|
||||
throw new proto.RoutingError(proto.RoutingErrorType.INVALID_PROTOCOL, url);
|
||||
}
|
||||
|
||||
this.dependencies.windowManager.ensureMainWindow().catch(noop);
|
||||
this.dependencies.applicationWindow.show().catch(noop);
|
||||
const routeInternally = checkHost(url);
|
||||
|
||||
logger.info(`${proto.LensProtocolRouter.LoggingPrefix}: routing ${url.toString()}`);
|
||||
|
||||
@ -9,10 +9,10 @@ const openDeepLinkInjectable = getInjectable({
|
||||
id: "open-deep-link",
|
||||
|
||||
instantiate: (di) => {
|
||||
const protocolRouter = di.inject(lensProtocolRouterMainInjectable);
|
||||
const getProtocolRouter = () => di.inject(lensProtocolRouterMainInjectable);
|
||||
|
||||
return async (url: string) => {
|
||||
await protocolRouter.route(url);
|
||||
await getProtocolRouter().route(url);
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
@ -0,0 +1,10 @@
|
||||
/**
|
||||
* 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 { Runnable } from "../run-many-for";
|
||||
|
||||
export const afterApplicationIsLoadedInjectionToken = getInjectionToken<Runnable>({
|
||||
id: "after-application-is-loaded",
|
||||
});
|
||||
@ -3,8 +3,8 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { afterApplicationIsReadyInjectionToken } from "../after-application-is-ready-injection-token";
|
||||
import appEventBusInjectable from "../../../../common/app-event-bus/app-event-bus.injectable";
|
||||
import { afterApplicationIsLoadedInjectionToken } from "../after-application-is-loaded-injection-token";
|
||||
|
||||
const emitServiceStartToCommandBusInjectable = getInjectable({
|
||||
id: "emit-service-start-to-command-bus",
|
||||
@ -19,7 +19,7 @@ const emitServiceStartToCommandBusInjectable = getInjectable({
|
||||
};
|
||||
},
|
||||
|
||||
injectionToken: afterApplicationIsReadyInjectionToken,
|
||||
injectionToken: afterApplicationIsLoadedInjectionToken,
|
||||
});
|
||||
|
||||
export default emitServiceStartToCommandBusInjectable;
|
||||
@ -1,36 +0,0 @@
|
||||
/**
|
||||
* 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 windowManagerInjectable from "../../../window-manager.injectable";
|
||||
import loggerInjectable from "../../../../common/logger.injectable";
|
||||
import { afterApplicationIsReadyInjectionToken } from "../after-application-is-ready-injection-token";
|
||||
import shouldStartHiddenInjectable from "../../../electron-app/features/should-start-hidden.injectable";
|
||||
import setupLensProxyInjectable from "./setup-lens-proxy.injectable";
|
||||
|
||||
const startMainWindowInjectable = getInjectable({
|
||||
id: "start-main-window",
|
||||
|
||||
instantiate: (di) => {
|
||||
const windowManager = di.inject(windowManagerInjectable);
|
||||
const logger = di.inject(loggerInjectable);
|
||||
const shouldStartHidden = di.inject(shouldStartHiddenInjectable);
|
||||
|
||||
return {
|
||||
runAfter: di.inject(setupLensProxyInjectable),
|
||||
|
||||
run: async () => {
|
||||
logger.info("🖥️ Starting WindowManager");
|
||||
|
||||
if (!shouldStartHidden) {
|
||||
await windowManager.ensureMainWindow();
|
||||
}
|
||||
},
|
||||
};
|
||||
},
|
||||
|
||||
injectionToken: afterApplicationIsReadyInjectionToken,
|
||||
});
|
||||
|
||||
export default startMainWindowInjectable;
|
||||
@ -0,0 +1,10 @@
|
||||
/**
|
||||
* 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 { Runnable } from "../run-many-for";
|
||||
|
||||
export const beforeApplicationIsLoadingInjectionToken = getInjectionToken<Runnable>({
|
||||
id: "before-application-is-loading",
|
||||
});
|
||||
@ -3,9 +3,9 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { afterApplicationIsReadyInjectionToken } from "../after-application-is-ready-injection-token";
|
||||
import registerFileProtocolInjectable from "../../../electron-app/features/register-file-protocol.injectable";
|
||||
import staticFilesDirectoryInjectable from "../../../../common/vars/static-files-directory.injectable";
|
||||
import { beforeApplicationIsLoadingInjectionToken } from "../before-application-is-loading-injection-token";
|
||||
|
||||
const setupFileProtocolInjectable = getInjectable({
|
||||
id: "setup-file-protocol",
|
||||
@ -21,7 +21,7 @@ const setupFileProtocolInjectable = getInjectable({
|
||||
};
|
||||
},
|
||||
|
||||
injectionToken: afterApplicationIsReadyInjectionToken,
|
||||
injectionToken: beforeApplicationIsLoadingInjectionToken,
|
||||
});
|
||||
|
||||
export default setupFileProtocolInjectable;
|
||||
@ -3,7 +3,6 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { afterApplicationIsReadyInjectionToken } from "../after-application-is-ready-injection-token";
|
||||
import {
|
||||
getAppVersion,
|
||||
getAppVersionFromProxyServer,
|
||||
@ -14,6 +13,7 @@ import loggerInjectable from "../../../../common/logger.injectable";
|
||||
import lensProxyPortNumberStateInjectable from "../../../lens-proxy-port-number-state.injectable";
|
||||
import isWindowsInjectable from "../../../../common/vars/is-windows.injectable";
|
||||
import showErrorPopupInjectable from "../../../electron-app/features/show-error-popup.injectable";
|
||||
import { beforeApplicationIsLoadingInjectionToken } from "../before-application-is-loading-injection-token";
|
||||
|
||||
const setupLensProxyInjectable = getInjectable({
|
||||
id: "setup-lens-proxy",
|
||||
@ -74,7 +74,7 @@ const setupLensProxyInjectable = getInjectable({
|
||||
|
||||
causesSideEffects: true,
|
||||
|
||||
injectionToken: afterApplicationIsReadyInjectionToken,
|
||||
injectionToken: beforeApplicationIsLoadingInjectionToken,
|
||||
});
|
||||
|
||||
export default setupLensProxyInjectable;
|
||||
@ -4,7 +4,7 @@
|
||||
*/
|
||||
import { injectSystemCAs } from "../../../../common/system-ca";
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { afterApplicationIsReadyInjectionToken } from "../after-application-is-ready-injection-token";
|
||||
import { beforeApplicationIsLoadingInjectionToken } from "../before-application-is-loading-injection-token";
|
||||
|
||||
const setupSystemCaInjectable = getInjectable({
|
||||
id: "setup-system-ca",
|
||||
@ -17,7 +17,7 @@ const setupSystemCaInjectable = getInjectable({
|
||||
|
||||
causesSideEffects: true,
|
||||
|
||||
injectionToken: afterApplicationIsReadyInjectionToken,
|
||||
injectionToken: beforeApplicationIsLoadingInjectionToken,
|
||||
});
|
||||
|
||||
export default setupSystemCaInjectable;
|
||||
@ -5,7 +5,7 @@
|
||||
import { getInjectionToken } from "@ogre-tools/injectable";
|
||||
import type { RunnableSync } from "../run-many-sync-for";
|
||||
|
||||
export const beforeApplicationIsReadyInjectionToken =
|
||||
export const beforeElectronIsReadyInjectionToken =
|
||||
getInjectionToken<RunnableSync>({
|
||||
id: "before-application-is-ready",
|
||||
id: "before-electron-is-ready",
|
||||
});
|
||||
@ -5,7 +5,7 @@
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import environmentVariablesInjectable from "../../../../common/utils/environment-variables.injectable";
|
||||
import disableHardwareAccelerationInjectable from "../../../electron-app/features/disable-hardware-acceleration.injectable";
|
||||
import { beforeApplicationIsReadyInjectionToken } from "../before-application-is-ready-injection-token";
|
||||
import { beforeElectronIsReadyInjectionToken } from "../before-electron-is-ready-injection-token";
|
||||
|
||||
const setupHardwareAccelerationInjectable = getInjectable({
|
||||
id: "setup-hardware-acceleration",
|
||||
@ -23,7 +23,7 @@ const setupHardwareAccelerationInjectable = getInjectable({
|
||||
};
|
||||
},
|
||||
|
||||
injectionToken: beforeApplicationIsReadyInjectionToken,
|
||||
injectionToken: beforeElectronIsReadyInjectionToken,
|
||||
});
|
||||
|
||||
export default setupHardwareAccelerationInjectable;
|
||||
@ -4,7 +4,7 @@
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import * as Immer from "immer";
|
||||
import { beforeApplicationIsReadyInjectionToken } from "../before-application-is-ready-injection-token";
|
||||
import { beforeElectronIsReadyInjectionToken } from "../before-electron-is-ready-injection-token";
|
||||
|
||||
const setupImmerInjectable = getInjectable({
|
||||
id: "setup-immer",
|
||||
@ -18,7 +18,7 @@ const setupImmerInjectable = getInjectable({
|
||||
},
|
||||
}),
|
||||
|
||||
injectionToken: beforeApplicationIsReadyInjectionToken,
|
||||
injectionToken: beforeElectronIsReadyInjectionToken,
|
||||
});
|
||||
|
||||
export default setupImmerInjectable;
|
||||
@ -4,7 +4,7 @@
|
||||
*/
|
||||
import * as Mobx from "mobx";
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { beforeApplicationIsReadyInjectionToken } from "../before-application-is-ready-injection-token";
|
||||
import { beforeElectronIsReadyInjectionToken } from "../before-electron-is-ready-injection-token";
|
||||
|
||||
const setupMobxInjectable = getInjectable({
|
||||
id: "setup-mobx",
|
||||
@ -23,7 +23,7 @@ const setupMobxInjectable = getInjectable({
|
||||
},
|
||||
}),
|
||||
|
||||
injectionToken: beforeApplicationIsReadyInjectionToken,
|
||||
injectionToken: beforeElectronIsReadyInjectionToken,
|
||||
});
|
||||
|
||||
export default setupMobxInjectable;
|
||||
@ -3,7 +3,7 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { beforeApplicationIsReadyInjectionToken } from "../before-application-is-ready-injection-token";
|
||||
import { beforeElectronIsReadyInjectionToken } from "../before-electron-is-ready-injection-token";
|
||||
import getCommandLineSwitchInjectable from "../../../electron-app/features/get-command-line-switch.injectable";
|
||||
|
||||
const setupProxyEnvInjectable = getInjectable({
|
||||
@ -37,7 +37,7 @@ const setupProxyEnvInjectable = getInjectable({
|
||||
};
|
||||
},
|
||||
|
||||
injectionToken: beforeApplicationIsReadyInjectionToken,
|
||||
injectionToken: beforeElectronIsReadyInjectionToken,
|
||||
});
|
||||
|
||||
export default setupProxyEnvInjectable;
|
||||
@ -0,0 +1,88 @@
|
||||
/**
|
||||
* 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 { BrowserWindow } from "electron";
|
||||
import type {
|
||||
SendToViewArgs,
|
||||
} from "../application-window/lens-window-injection-token";
|
||||
import {
|
||||
lensWindowInjectionToken,
|
||||
} from "../application-window/lens-window-injection-token";
|
||||
|
||||
const applicationIsLoadingWindowInjectable = getInjectable({
|
||||
id: "application-is-loading-window",
|
||||
|
||||
instantiate: () => {
|
||||
let loadingWindow: BrowserWindow;
|
||||
|
||||
const hideWindow = () => {
|
||||
loadingWindow?.hide();
|
||||
};
|
||||
|
||||
return {
|
||||
show: async () => {
|
||||
if (!loadingWindow) {
|
||||
loadingWindow = await createLoadingWindow();
|
||||
}
|
||||
|
||||
loadingWindow.show();
|
||||
},
|
||||
|
||||
hide: hideWindow,
|
||||
|
||||
close: () => {
|
||||
hideWindow();
|
||||
|
||||
loadingWindow = null;
|
||||
},
|
||||
|
||||
send: async ({ channel, frameInfo, data = [] }: SendToViewArgs) => {
|
||||
if (!loadingWindow) {
|
||||
loadingWindow = await createLoadingWindow();
|
||||
}
|
||||
|
||||
if (frameInfo) {
|
||||
loadingWindow.webContents.sendToFrame(
|
||||
[frameInfo.processId, frameInfo.frameId],
|
||||
channel,
|
||||
...data,
|
||||
);
|
||||
|
||||
} else {
|
||||
loadingWindow.webContents.send(channel, ...data);
|
||||
}
|
||||
},
|
||||
};
|
||||
},
|
||||
|
||||
injectionToken: lensWindowInjectionToken,
|
||||
|
||||
causesSideEffects: true,
|
||||
});
|
||||
|
||||
export default applicationIsLoadingWindowInjectable;
|
||||
|
||||
const createLoadingWindow = async () => {
|
||||
const loadingWindow = new BrowserWindow({
|
||||
width: 500,
|
||||
height: 300,
|
||||
backgroundColor: "#1e2124",
|
||||
center: true,
|
||||
frame: false,
|
||||
resizable: false,
|
||||
show: false,
|
||||
|
||||
webPreferences: {
|
||||
nodeIntegration: true,
|
||||
contextIsolation: false,
|
||||
nodeIntegrationInSubFrames: true,
|
||||
nativeWindowOpen: true,
|
||||
},
|
||||
});
|
||||
|
||||
await loadingWindow.loadURL("static://splash.html");
|
||||
|
||||
return loadingWindow;
|
||||
};
|
||||
@ -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 windowStateKeeper from "electron-window-state";
|
||||
|
||||
const applicationWindowStateInjectable = getInjectable({
|
||||
id: "application-window-state",
|
||||
|
||||
instantiate: () => {
|
||||
console.log("asdasd");
|
||||
|
||||
return windowStateKeeper({
|
||||
defaultHeight: 900,
|
||||
defaultWidth: 1440,
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
export default applicationWindowStateInjectable;
|
||||
@ -0,0 +1,61 @@
|
||||
/**
|
||||
* 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 createBrowserWindowInjectable from "./create-browser-window.injectable";
|
||||
import type {
|
||||
SendToViewArgs } from "./lens-window-injection-token";
|
||||
import {
|
||||
lensWindowInjectionToken,
|
||||
} from "./lens-window-injection-token";
|
||||
import type { BrowserWindow } from "electron";
|
||||
import sendToChannelInElectronBrowserWindowInjectable from "./send-to-channel-in-electron-browser-window.injectable";
|
||||
|
||||
const applicationWindowInjectable = getInjectable({
|
||||
id: "application-window",
|
||||
|
||||
instantiate: (di) => {
|
||||
const createBrowserWindow = di.inject(createBrowserWindowInjectable);
|
||||
|
||||
let browserWindow: BrowserWindow = null;
|
||||
|
||||
const hideWindow = () => {
|
||||
browserWindow?.hide();
|
||||
};
|
||||
|
||||
const sendToChannelInLensWindow = di.inject(
|
||||
sendToChannelInElectronBrowserWindowInjectable,
|
||||
);
|
||||
|
||||
return {
|
||||
show: async () => {
|
||||
if (!browserWindow) {
|
||||
browserWindow = await createBrowserWindow("only-application-window");
|
||||
}
|
||||
|
||||
browserWindow.show();
|
||||
},
|
||||
|
||||
hide: hideWindow,
|
||||
|
||||
close: () => {
|
||||
hideWindow();
|
||||
|
||||
browserWindow = null;
|
||||
},
|
||||
|
||||
send: async (args: SendToViewArgs) => {
|
||||
if (!browserWindow) {
|
||||
browserWindow = await createBrowserWindow("only-application-window");
|
||||
}
|
||||
|
||||
return sendToChannelInLensWindow(browserWindow, args);
|
||||
},
|
||||
};
|
||||
},
|
||||
|
||||
injectionToken: lensWindowInjectionToken,
|
||||
});
|
||||
|
||||
export default applicationWindowInjectable;
|
||||
@ -0,0 +1,158 @@
|
||||
/**
|
||||
* 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 loggerInjectable from "../../../../common/logger.injectable";
|
||||
import appNameInjectable from "../../../app-paths/app-name/app-name.injectable";
|
||||
import applicationWindowStateInjectable from "./application-window-state.injectable";
|
||||
import lensProxyPortNumberStateInjectable from "../../../lens-proxy-port-number-state.injectable";
|
||||
import isMacInjectable from "../../../../common/vars/is-mac.injectable";
|
||||
import { BrowserWindow, ipcMain } from "electron";
|
||||
import { delay, openBrowser } from "../../../../common/utils";
|
||||
import { bundledExtensionsLoaded } from "../../../../common/ipc/extension-handling";
|
||||
import electronAppInjectable from "../../../electron-app/electron-app.injectable";
|
||||
import appEventBusInjectable from "../../../../common/app-event-bus/app-event-bus.injectable";
|
||||
|
||||
const createBrowserWindowInjectable = getInjectable({
|
||||
id: "create-browser-window",
|
||||
|
||||
instantiate: (di) => {
|
||||
const logger = di.inject(loggerInjectable);
|
||||
const applicationName = di.inject(appNameInjectable);
|
||||
const isMac = di.inject(isMacInjectable);
|
||||
const appEventBus = di.inject(appEventBusInjectable);
|
||||
|
||||
const lensProxyPortNumberState = di.inject(
|
||||
lensProxyPortNumberStateInjectable,
|
||||
);
|
||||
|
||||
return async (id: string) => {
|
||||
const applicationWindowState = di.inject(applicationWindowStateInjectable);
|
||||
const app = di.inject(electronAppInjectable);
|
||||
|
||||
const { width, height, x, y } = applicationWindowState;
|
||||
|
||||
const browserWindow = new BrowserWindow({
|
||||
x,
|
||||
y,
|
||||
width,
|
||||
height,
|
||||
title: applicationName,
|
||||
show: false,
|
||||
minWidth: 700, // accommodate 800 x 600 display minimum
|
||||
minHeight: 500, // accommodate 800 x 600 display minimum
|
||||
titleBarStyle: isMac ? "hiddenInset" : "hidden",
|
||||
frame: isMac,
|
||||
backgroundColor: "#1e2124",
|
||||
webPreferences: {
|
||||
nodeIntegration: true,
|
||||
nodeIntegrationInSubFrames: true,
|
||||
webviewTag: true,
|
||||
contextIsolation: false,
|
||||
nativeWindowOpen: false,
|
||||
},
|
||||
});
|
||||
|
||||
applicationWindowState.manage(browserWindow);
|
||||
|
||||
// open external links in default browser (target=_blank, window.open)
|
||||
browserWindow
|
||||
.on("focus", () => {
|
||||
appEventBus.emit({ name: "app", action: "focus" });
|
||||
})
|
||||
|
||||
.on("blur", () => {
|
||||
appEventBus.emit({ name: "app", action: "blur" });
|
||||
})
|
||||
|
||||
.on("closed", () => {
|
||||
// clean up
|
||||
applicationWindowState.unmanage();
|
||||
// this.mainWindow = null;
|
||||
// this.splashWindow = null;
|
||||
app.dock?.hide(); // hide icon in dock (mac-os)
|
||||
})
|
||||
|
||||
.webContents.on("dom-ready", () => {
|
||||
appEventBus.emit({ name: "app", action: "dom-ready" });
|
||||
})
|
||||
|
||||
.on("did-fail-load", (_event, code, desc) => {
|
||||
logger.error(`[WINDOW-MANAGER]: Failed to load Main window`, {
|
||||
code,
|
||||
desc,
|
||||
});
|
||||
})
|
||||
|
||||
.on("did-finish-load", () => {
|
||||
logger.info("[WINDOW-MANAGER]: Main window loaded");
|
||||
})
|
||||
|
||||
.on("will-attach-webview", (event, webPreferences, params) => {
|
||||
logger.debug("[WINDOW-MANAGER]: Attaching webview");
|
||||
// Following is security recommendations because we allow webview tag (webviewTag: true)
|
||||
// suggested by https://www.electronjs.org/docs/tutorial/security#11-verify-webview-options-before-creation
|
||||
// and https://www.electronjs.org/docs/tutorial/security#10-do-not-use-allowpopups
|
||||
|
||||
if (webPreferences.preload) {
|
||||
logger.warn(
|
||||
"[WINDOW-MANAGER]: Strip away preload scripts of webview",
|
||||
);
|
||||
delete webPreferences.preload;
|
||||
}
|
||||
|
||||
// @ts-expect-error some electron version uses webPreferences.preloadURL/webPreferences.preload
|
||||
if (webPreferences.preloadURL) {
|
||||
logger.warn(
|
||||
"[WINDOW-MANAGER]: Strip away preload scripts of webview",
|
||||
);
|
||||
delete webPreferences.preload;
|
||||
}
|
||||
|
||||
if (params.allowpopups) {
|
||||
logger.warn(
|
||||
"[WINDOW-MANAGER]: We do not allow allowpopups props, stop webview from renderer",
|
||||
);
|
||||
|
||||
// event.preventDefault() will destroy the guest page.
|
||||
event.preventDefault();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Always disable Node.js integration for all webviews
|
||||
webPreferences.nodeIntegration = false;
|
||||
})
|
||||
|
||||
.setWindowOpenHandler((details) => {
|
||||
openBrowser(details.url).catch((error) => {
|
||||
logger.error("[WINDOW-MANAGER]: failed to open browser", { error });
|
||||
});
|
||||
|
||||
return { action: "deny" };
|
||||
});
|
||||
|
||||
const contentUrl = `http://localhost:${lensProxyPortNumberState.get()}`;
|
||||
|
||||
logger.info(
|
||||
`[WINDOW-MANAGER]: Loading Main window from url: ${contentUrl} ...`,
|
||||
);
|
||||
|
||||
await browserWindow.loadURL(contentUrl);
|
||||
|
||||
const viewHasLoaded = new Promise<void>((resolve) => {
|
||||
ipcMain.once(bundledExtensionsLoaded, () => resolve());
|
||||
});
|
||||
|
||||
await viewHasLoaded;
|
||||
await delay(50); // wait just a bit longer to let the first round of rendering happen
|
||||
|
||||
return browserWindow;
|
||||
};
|
||||
},
|
||||
|
||||
causesSideEffects: true,
|
||||
});
|
||||
|
||||
export default createBrowserWindowInjectable;
|
||||
@ -0,0 +1,23 @@
|
||||
/**
|
||||
* 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 { ClusterFrameInfo } from "../../../../common/cluster-frames";
|
||||
|
||||
export interface SendToViewArgs {
|
||||
channel: string;
|
||||
frameInfo?: ClusterFrameInfo;
|
||||
data?: any[];
|
||||
}
|
||||
|
||||
export interface LensWindow {
|
||||
show: () => Promise<void>;
|
||||
hide: () => void;
|
||||
close: () => void;
|
||||
send: (args: SendToViewArgs) => Promise<void>;
|
||||
}
|
||||
|
||||
export const lensWindowInjectionToken = getInjectionToken<LensWindow>({
|
||||
id: "lens-window",
|
||||
});
|
||||
@ -0,0 +1,32 @@
|
||||
/**
|
||||
* 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 { BrowserWindow } from "electron";
|
||||
import type { SendToViewArgs } from "./lens-window-injection-token";
|
||||
|
||||
const sendToChannelInElectronBrowserWindowInjectable = getInjectable({
|
||||
id: "send-to-channel-in-electron-browser-window",
|
||||
|
||||
instantiate:
|
||||
() =>
|
||||
async (
|
||||
browserWindow: BrowserWindow,
|
||||
{ channel, frameInfo, data = [] }: SendToViewArgs,
|
||||
) => {
|
||||
if (frameInfo) {
|
||||
browserWindow.webContents.sendToFrame(
|
||||
[frameInfo.processId, frameInfo.frameId],
|
||||
channel,
|
||||
...data,
|
||||
);
|
||||
} else {
|
||||
browserWindow.webContents.send(channel, ...data);
|
||||
}
|
||||
},
|
||||
|
||||
causesSideEffects: true,
|
||||
});
|
||||
|
||||
export default sendToChannelInElectronBrowserWindowInjectable;
|
||||
@ -0,0 +1,15 @@
|
||||
/**
|
||||
* 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 { observable } from "mobx";
|
||||
import type { ClusterId } from "../../../../common/cluster-types";
|
||||
|
||||
const currentClusterFrameClusterIdStateInjectable = getInjectable({
|
||||
id: "current-cluster-frame-cluster-id-state",
|
||||
|
||||
instantiate: () => observable.box<ClusterId>(),
|
||||
});
|
||||
|
||||
export default currentClusterFrameClusterIdStateInjectable;
|
||||
@ -0,0 +1,25 @@
|
||||
/**
|
||||
* 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 currentClusterFrameClusterIdStateInjectable from "./current-cluster-frame-cluster-id-state.injectable";
|
||||
import clusterFramesInjectable from "../../../../common/cluster-frames.injectable";
|
||||
|
||||
const currentClusterFrameInjectable = getInjectable({
|
||||
id: "current-cluster-frame",
|
||||
|
||||
instantiate: (di) => {
|
||||
const currentClusterFrameState = di.inject(currentClusterFrameClusterIdStateInjectable);
|
||||
const clusterFrames = di.inject(clusterFramesInjectable);
|
||||
|
||||
return computed(() => {
|
||||
const clusterId = currentClusterFrameState.get();
|
||||
|
||||
return clusterFrames.get(clusterId);
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
export default currentClusterFrameInjectable;
|
||||
@ -0,0 +1,32 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { ipcMainOn } from "../../../../common/ipc";
|
||||
import { IpcRendererNavigationEvents } from "../../../../renderer/navigation/events";
|
||||
import type { ClusterId } from "../../../../common/cluster-types";
|
||||
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { whenApplicationIsLoadingInjectionToken } from "../../when-application-is-loading/when-application-is-loading-injection-token";
|
||||
import currentClusterFrameClusterIdStateInjectable from "./current-cluster-frame-cluster-id-state.injectable";
|
||||
|
||||
const setupListenerForCurrentClusterFrameInjectable = getInjectable({
|
||||
id: "setup-listener-for-current-cluster-frame",
|
||||
|
||||
instantiate: (di) => ({
|
||||
run: () => {
|
||||
const currentClusterFrameState = di.inject(currentClusterFrameClusterIdStateInjectable);
|
||||
|
||||
ipcMainOn(
|
||||
IpcRendererNavigationEvents.CLUSTER_VIEW_CURRENT_ID,
|
||||
(event, clusterId: ClusterId) => {
|
||||
currentClusterFrameState.set(clusterId);
|
||||
},
|
||||
);
|
||||
},
|
||||
}),
|
||||
|
||||
injectionToken: whenApplicationIsLoadingInjectionToken,
|
||||
});
|
||||
|
||||
export default setupListenerForCurrentClusterFrameInjectable;
|
||||
@ -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 { lensWindowInjectionToken } from "../application-window/lens-window-injection-token";
|
||||
|
||||
const hideAllWindowsInjectable = getInjectable({
|
||||
id: "hide-all-windows",
|
||||
|
||||
instantiate: (di) => () => {
|
||||
const lensWindows = di.injectMany(lensWindowInjectionToken);
|
||||
|
||||
lensWindows.forEach((lensWindow) => {
|
||||
lensWindow.hide();
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
export default hideAllWindowsInjectable;
|
||||
@ -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 { iter } from "../../../common/utils";
|
||||
import applicationWindowInjectable from "./application-window/application-window.injectable";
|
||||
import clusterFramesInjectable from "../../../common/cluster-frames.injectable";
|
||||
|
||||
const navigateForExtensionInjectable = getInjectable({
|
||||
id: "navigate-for-extension",
|
||||
|
||||
instantiate: (di) => {
|
||||
const applicationWindow = di.inject(applicationWindowInjectable);
|
||||
const clusterFrames = di.inject(clusterFramesInjectable);
|
||||
|
||||
return async (
|
||||
extId: string,
|
||||
pageId?: string,
|
||||
params?: Record<string, any>,
|
||||
frameId?: number,
|
||||
) => {
|
||||
await applicationWindow.show();
|
||||
|
||||
const frameInfo = iter.find(
|
||||
clusterFrames.values(),
|
||||
(frameInfo) => frameInfo.frameId === frameId,
|
||||
);
|
||||
|
||||
await applicationWindow.send({
|
||||
channel: "extension:navigate",
|
||||
frameInfo,
|
||||
data: [extId, pageId, params],
|
||||
});
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
export default navigateForExtensionInjectable;
|
||||
@ -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 { iter } from "../../../common/utils";
|
||||
import applicationWindowInjectable from "./application-window/application-window.injectable";
|
||||
import clusterFramesInjectable from "../../../common/cluster-frames.injectable";
|
||||
import { IpcRendererNavigationEvents } from "../../../renderer/navigation/events";
|
||||
|
||||
const navigateInjectable = getInjectable({
|
||||
id: "navigate",
|
||||
|
||||
instantiate: (di) => {
|
||||
const applicationWindow = di.inject(applicationWindowInjectable);
|
||||
const clusterFrames = di.inject(clusterFramesInjectable);
|
||||
|
||||
return async (url: string, frameId?: number) => {
|
||||
await applicationWindow.show();
|
||||
|
||||
const frameInfo = iter.find(
|
||||
clusterFrames.values(),
|
||||
(frameInfo) => frameInfo.frameId === frameId,
|
||||
);
|
||||
|
||||
const channel = frameInfo
|
||||
? IpcRendererNavigationEvents.NAVIGATE_IN_CLUSTER
|
||||
: IpcRendererNavigationEvents.NAVIGATE_IN_APP;
|
||||
|
||||
await applicationWindow.send({
|
||||
channel,
|
||||
frameInfo,
|
||||
data: [url],
|
||||
});
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
export default navigateInjectable;
|
||||
@ -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 { webContents } from "electron";
|
||||
|
||||
const reloadAllWindowsInjectable = getInjectable({
|
||||
id: "reload-all-windows",
|
||||
|
||||
instantiate: () => () => {
|
||||
webContents
|
||||
.getAllWebContents()
|
||||
.filter((wc) => wc.getType() === "window")
|
||||
.forEach((wc) => {
|
||||
wc.reload();
|
||||
wc.clearHistory();
|
||||
});
|
||||
},
|
||||
|
||||
causesSideEffects: true,
|
||||
});
|
||||
|
||||
export default reloadAllWindowsInjectable;
|
||||
@ -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 type { LensWindow } from "./application-window/lens-window-injection-token";
|
||||
import { IpcRendererNavigationEvents } from "../../../renderer/navigation/events";
|
||||
import currentClusterFrameInjectable from "./current-cluster-frame/current-cluster-frame.injectable";
|
||||
import reloadAllWindowsInjectable from "./reload-all-windows.injectable";
|
||||
|
||||
const reloadWindowInjectable = getInjectable({
|
||||
id: "reload-window",
|
||||
|
||||
instantiate: (di, lensWindow: LensWindow) => () => {
|
||||
const currentClusterIframe = di.inject(currentClusterFrameInjectable);
|
||||
const reloadAllWindows = di.inject(reloadAllWindowsInjectable);
|
||||
|
||||
const frameInfo = currentClusterIframe.get();
|
||||
|
||||
if (frameInfo) {
|
||||
lensWindow.send({
|
||||
channel: IpcRendererNavigationEvents.RELOAD_PAGE,
|
||||
frameInfo,
|
||||
});
|
||||
} else {
|
||||
reloadAllWindows();
|
||||
}
|
||||
},
|
||||
|
||||
lifecycle: lifecycleEnum.transient,
|
||||
});
|
||||
|
||||
export default reloadWindowInjectable;
|
||||
@ -5,10 +5,20 @@
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
|
||||
import electronAppInjectable from "../electron-app/electron-app.injectable";
|
||||
import { beforeApplicationIsReadyInjectionToken } from "./before-application-is-ready/before-application-is-ready-injection-token";
|
||||
import { afterApplicationIsReadyInjectionToken } from "./after-application-is-ready/after-application-is-ready-injection-token";
|
||||
import { runManyFor } from "./run-many-for";
|
||||
import { runManySyncFor } from "./run-many-sync-for";
|
||||
import { beforeElectronIsReadyInjectionToken } from "./before-electron-is-ready/before-electron-is-ready-injection-token";
|
||||
import { beforeApplicationIsLoadingInjectionToken } from "./before-application-is-loading/before-application-is-loading-injection-token";
|
||||
import { whenApplicationIsLoadingInjectionToken } from "./when-application-is-loading/when-application-is-loading-injection-token";
|
||||
import { afterApplicationIsLoadedInjectionToken } from "./after-application-is-loaded/after-application-is-loaded-injection-token";
|
||||
import applicationIsLoadingWindowInjectable from "./lens-window/application-is-loading-window/application-is-loading-window.injectable";
|
||||
|
||||
import applicationWindowInjectable from "./lens-window/application-window/application-window.injectable";
|
||||
import shouldStartHiddenInjectable from "../electron-app/features/should-start-hidden.injectable";
|
||||
import openDeepLinkInjectable from "../protocol-handler/lens-protocol-router-main/open-deep-link-for-url/open-deep-link.injectable";
|
||||
import { pipeline } from "@ogre-tools/fp";
|
||||
import { find, map, startsWith, toLower } from "lodash/fp";
|
||||
import commandLineArgumentsInjectable from "../utils/command-line-arguments.injectable";
|
||||
|
||||
const startMainApplicationInjectable = getInjectable({
|
||||
id: "start-main-application",
|
||||
@ -16,21 +26,52 @@ const startMainApplicationInjectable = getInjectable({
|
||||
instantiate: (di) => {
|
||||
const runMany = runManyFor(di);
|
||||
const runManySync = runManySyncFor(di);
|
||||
const app = di.inject(electronAppInjectable);
|
||||
const electronApp = di.inject(electronAppInjectable);
|
||||
const applicationWindow = di.inject(applicationWindowInjectable);
|
||||
const applicationIsLoadingWindow = di.inject(applicationIsLoadingWindowInjectable);
|
||||
const shouldStartHidden = di.inject(shouldStartHiddenInjectable);
|
||||
const openDeepLink = di.inject(openDeepLinkInjectable);
|
||||
const commandLineArguments = di.inject(commandLineArgumentsInjectable);
|
||||
|
||||
const beforeElectronIsReady = runManySync(beforeElectronIsReadyInjectionToken);
|
||||
const beforeApplicationIsLoading = runMany(beforeApplicationIsLoadingInjectionToken);
|
||||
const whenApplicationIsLoading = runMany(whenApplicationIsLoadingInjectionToken);
|
||||
const afterApplicationIsLoaded = runMany(afterApplicationIsLoadedInjectionToken);
|
||||
|
||||
return async () => {
|
||||
// Stuff happening before application is ready needs to be synchronous because of
|
||||
// https://github.com/electron/electron/issues/21370
|
||||
runManySync(beforeApplicationIsReadyInjectionToken)();
|
||||
beforeElectronIsReady();
|
||||
|
||||
await app.whenReady();
|
||||
await electronApp.whenReady();
|
||||
|
||||
await runMany(afterApplicationIsReadyInjectionToken)();
|
||||
await beforeApplicationIsLoading();
|
||||
|
||||
if (!shouldStartHidden) {
|
||||
await applicationIsLoadingWindow.show();
|
||||
}
|
||||
|
||||
await whenApplicationIsLoading();
|
||||
|
||||
if (!shouldStartHidden) {
|
||||
const url = getDeepLinkUrl(commandLineArguments);
|
||||
|
||||
if (url) {
|
||||
await openDeepLink(url);
|
||||
} else {
|
||||
await applicationWindow.show();
|
||||
}
|
||||
|
||||
applicationIsLoadingWindow.close();
|
||||
}
|
||||
|
||||
await afterApplicationIsLoaded();
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
const getDeepLinkUrl = (commandLineArguments: string[]) =>
|
||||
pipeline(commandLineArguments, map(toLower), find(startsWith("lens://")));
|
||||
|
||||
|
||||
export default startMainApplicationInjectable;
|
||||
|
||||
|
||||
|
||||
|
||||
@ -3,13 +3,13 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { afterApplicationIsReadyInjectionToken } from "../after-application-is-ready-injection-token";
|
||||
import type { InstalledExtension } from "../../../../extensions/extension-discovery/extension-discovery";
|
||||
import type { LensExtensionId } from "../../../../extensions/lens-extension";
|
||||
import loggerInjectable from "../../../../common/logger.injectable";
|
||||
import extensionDiscoveryInjectable from "../../../../extensions/extension-discovery/extension-discovery.injectable";
|
||||
import extensionLoaderInjectable from "../../../../extensions/extension-loader/extension-loader.injectable";
|
||||
import showErrorPopupInjectable from "../../../electron-app/features/show-error-popup.injectable";
|
||||
import { whenApplicationIsLoadingInjectionToken } from "../when-application-is-loading-injection-token";
|
||||
|
||||
const initializeExtensionsInjectable = getInjectable({
|
||||
id: "initialize-extensions",
|
||||
@ -61,7 +61,7 @@ const initializeExtensionsInjectable = getInjectable({
|
||||
|
||||
causesSideEffects: true,
|
||||
|
||||
injectionToken: afterApplicationIsReadyInjectionToken,
|
||||
injectionToken: whenApplicationIsLoadingInjectionToken,
|
||||
});
|
||||
|
||||
export default initializeExtensionsInjectable;
|
||||
@ -3,13 +3,13 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { afterApplicationIsReadyInjectionToken } from "../after-application-is-ready-injection-token";
|
||||
import { ClusterIdDetector } from "../../../cluster-detectors/cluster-id-detector";
|
||||
import { LastSeenDetector } from "../../../cluster-detectors/last-seen-detector";
|
||||
import { VersionDetector } from "../../../cluster-detectors/version-detector";
|
||||
import { DistributionDetector } from "../../../cluster-detectors/distribution-detector";
|
||||
import { NodesCountDetector } from "../../../cluster-detectors/nodes-count-detector";
|
||||
import detectorRegistryInjectable from "../../../cluster-detectors/detector-registry.injectable";
|
||||
import { whenApplicationIsLoadingInjectionToken } from "../when-application-is-loading-injection-token";
|
||||
|
||||
const setupDetectorRegistryInjectable = getInjectable({
|
||||
id: "setup-detector-registry",
|
||||
@ -29,7 +29,7 @@ const setupDetectorRegistryInjectable = getInjectable({
|
||||
};
|
||||
},
|
||||
|
||||
injectionToken: afterApplicationIsReadyInjectionToken,
|
||||
injectionToken: whenApplicationIsLoadingInjectionToken,
|
||||
});
|
||||
|
||||
export default setupDetectorRegistryInjectable;
|
||||
@ -3,9 +3,9 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { afterApplicationIsReadyInjectionToken } from "../after-application-is-ready-injection-token";
|
||||
import hotbarStoreInjectable from "../../../../common/hotbar-store.injectable";
|
||||
import setupSyncingOfGeneralCatalogEntitiesInjectable from "./setup-syncing-of-general-catalog-entities.injectable";
|
||||
import { whenApplicationIsLoadingInjectionToken } from "../when-application-is-loading-injection-token";
|
||||
|
||||
const setupHotbarStoreInjectable = getInjectable({
|
||||
id: "setup-hotbar-store",
|
||||
@ -20,7 +20,7 @@ const setupHotbarStoreInjectable = getInjectable({
|
||||
runAfter: di.inject(setupSyncingOfGeneralCatalogEntitiesInjectable),
|
||||
}),
|
||||
|
||||
injectionToken: afterApplicationIsReadyInjectionToken,
|
||||
injectionToken: whenApplicationIsLoadingInjectionToken,
|
||||
});
|
||||
|
||||
export default setupHotbarStoreInjectable;
|
||||
@ -3,12 +3,12 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { afterApplicationIsReadyInjectionToken } from "../after-application-is-ready-injection-token";
|
||||
import { PrometheusLens } from "../../../prometheus/lens";
|
||||
import { PrometheusHelm } from "../../../prometheus/helm";
|
||||
import { PrometheusOperator } from "../../../prometheus/operator";
|
||||
import { PrometheusStacklight } from "../../../prometheus/stacklight";
|
||||
import prometheusProviderRegistryInjectable from "../../../prometheus/prometheus-provider-registry.injectable";
|
||||
import { whenApplicationIsLoadingInjectionToken } from "../when-application-is-loading-injection-token";
|
||||
|
||||
const setupPrometheusRegistryInjectable = getInjectable({
|
||||
id: "setup-prometheus-registry",
|
||||
@ -27,7 +27,7 @@ const setupPrometheusRegistryInjectable = getInjectable({
|
||||
};
|
||||
},
|
||||
|
||||
injectionToken: afterApplicationIsReadyInjectionToken,
|
||||
injectionToken: whenApplicationIsLoadingInjectionToken,
|
||||
});
|
||||
|
||||
export default setupPrometheusRegistryInjectable;
|
||||
@ -3,8 +3,8 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { afterApplicationIsReadyInjectionToken } from "../after-application-is-ready-injection-token";
|
||||
import userStoreInjectable from "../../../../common/user-store/user-store.injectable";
|
||||
import { whenApplicationIsLoadingInjectionToken } from "../when-application-is-loading-injection-token";
|
||||
|
||||
const setupReactionsInUserStoreInjectable = getInjectable({
|
||||
id: "setup-reactions-in-user-store",
|
||||
@ -19,7 +19,7 @@ const setupReactionsInUserStoreInjectable = getInjectable({
|
||||
};
|
||||
},
|
||||
|
||||
injectionToken: afterApplicationIsReadyInjectionToken,
|
||||
injectionToken: whenApplicationIsLoadingInjectionToken,
|
||||
});
|
||||
|
||||
export default setupReactionsInUserStoreInjectable;
|
||||
@ -6,8 +6,8 @@ import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { ipcMainOn } from "../../../../common/ipc";
|
||||
import { IpcRendererNavigationEvents } from "../../../../renderer/navigation/events";
|
||||
import { afterRootFrameIsReadyInjectionToken } from "../../after-root-frame-is-ready/after-root-frame-is-ready-injection-token";
|
||||
import { afterApplicationIsReadyInjectionToken } from "../after-application-is-ready-injection-token";
|
||||
import { runManyFor } from "../../run-many-for";
|
||||
import { whenApplicationIsLoadingInjectionToken } from "../when-application-is-loading-injection-token";
|
||||
|
||||
const setupRunnablesForAfterRootFrameIsReadyInjectable = getInjectable({
|
||||
id: "setup-runnables-for-after-root-frame-is-ready",
|
||||
@ -31,7 +31,7 @@ const setupRunnablesForAfterRootFrameIsReadyInjectable = getInjectable({
|
||||
// Direct usage of IPC
|
||||
causesSideEffects: true,
|
||||
|
||||
injectionToken: afterApplicationIsReadyInjectionToken,
|
||||
injectionToken: whenApplicationIsLoadingInjectionToken,
|
||||
});
|
||||
|
||||
export default setupRunnablesForAfterRootFrameIsReadyInjectable;
|
||||
@ -3,9 +3,9 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { afterApplicationIsReadyInjectionToken } from "../after-application-is-ready-injection-token";
|
||||
import { initializeSentryReporting } from "../../../../common/sentry";
|
||||
import { init } from "@sentry/electron/main";
|
||||
import { whenApplicationIsLoadingInjectionToken } from "../when-application-is-loading-injection-token";
|
||||
|
||||
const setupSentryInjectable = getInjectable({
|
||||
id: "setup-sentry",
|
||||
@ -18,7 +18,7 @@ const setupSentryInjectable = getInjectable({
|
||||
|
||||
causesSideEffects: true,
|
||||
|
||||
injectionToken: afterApplicationIsReadyInjectionToken,
|
||||
injectionToken: whenApplicationIsLoadingInjectionToken,
|
||||
});
|
||||
|
||||
export default setupSentryInjectable;
|
||||
@ -3,9 +3,9 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { afterApplicationIsReadyInjectionToken } from "../after-application-is-ready-injection-token";
|
||||
import { shellSync } from "../../../shell-sync";
|
||||
import loggerInjectable from "../../../../common/logger.injectable";
|
||||
import { whenApplicationIsLoadingInjectionToken } from "../when-application-is-loading-injection-token";
|
||||
|
||||
const setupShellInjectable = getInjectable({
|
||||
id: "setup-shell",
|
||||
@ -22,7 +22,7 @@ const setupShellInjectable = getInjectable({
|
||||
};
|
||||
},
|
||||
|
||||
injectionToken: afterApplicationIsReadyInjectionToken,
|
||||
injectionToken: whenApplicationIsLoadingInjectionToken,
|
||||
causesSideEffects: true,
|
||||
});
|
||||
|
||||
@ -3,8 +3,8 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { afterApplicationIsReadyInjectionToken } from "../after-application-is-ready-injection-token";
|
||||
import syncGeneralCatalogEntitiesInjectable from "../../../catalog-sources/sync-general-catalog-entities.injectable";
|
||||
import { whenApplicationIsLoadingInjectionToken } from "../when-application-is-loading-injection-token";
|
||||
|
||||
const setupSyncingOfGeneralCatalogEntitiesInjectable = getInjectable({
|
||||
id: "setup-syncing-of-general-catalog-entities",
|
||||
@ -21,7 +21,7 @@ const setupSyncingOfGeneralCatalogEntitiesInjectable = getInjectable({
|
||||
};
|
||||
},
|
||||
|
||||
injectionToken: afterApplicationIsReadyInjectionToken,
|
||||
injectionToken: whenApplicationIsLoadingInjectionToken,
|
||||
});
|
||||
|
||||
export default setupSyncingOfGeneralCatalogEntitiesInjectable;
|
||||
@ -3,10 +3,10 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { afterApplicationIsReadyInjectionToken } from "../after-application-is-ready-injection-token";
|
||||
import { syncWeblinks } from "../../../catalog-sources";
|
||||
import weblinkStoreInjectable from "../../../../common/weblink-store.injectable";
|
||||
import catalogEntityRegistryInjectable from "../../../catalog/catalog-entity-registry.injectable";
|
||||
import { whenApplicationIsLoadingInjectionToken } from "../when-application-is-loading-injection-token";
|
||||
|
||||
const setupSyncingOfWeblinksInjectable = getInjectable({
|
||||
id: "setup-syncing-of-weblinks",
|
||||
@ -22,7 +22,7 @@ const setupSyncingOfWeblinksInjectable = getInjectable({
|
||||
};
|
||||
},
|
||||
|
||||
injectionToken: afterApplicationIsReadyInjectionToken,
|
||||
injectionToken: whenApplicationIsLoadingInjectionToken,
|
||||
});
|
||||
|
||||
export default setupSyncingOfWeblinksInjectable;
|
||||
@ -0,0 +1,10 @@
|
||||
/**
|
||||
* 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 { Runnable } from "../run-many-for";
|
||||
|
||||
export const whenApplicationIsLoadingInjectionToken = getInjectionToken<Runnable>({
|
||||
id: "when-application-is-loading",
|
||||
});
|
||||
@ -5,23 +5,23 @@
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import exitAppInjectable from "./electron-app/features/exit-app.injectable";
|
||||
import clusterManagerInjectable from "./cluster-manager.injectable";
|
||||
import windowManagerInjectable from "./window-manager.injectable";
|
||||
import appEventBusInjectable from "../common/app-event-bus/app-event-bus.injectable";
|
||||
import loggerInjectable from "../common/logger.injectable";
|
||||
import hideAllWindowsInjectable from "./start-main-application/lens-window/hide-all-windows/hide-all-windows.injectable";
|
||||
|
||||
const stopServicesAndExitAppInjectable = getInjectable({
|
||||
id: "stop-services-and-exit-app",
|
||||
|
||||
instantiate: (di) => {
|
||||
const exitApp = di.inject(exitAppInjectable);
|
||||
const windowManager = di.inject(windowManagerInjectable);
|
||||
const clusterManager = di.inject(clusterManagerInjectable);
|
||||
const appEventBus = di.inject(appEventBusInjectable);
|
||||
const logger = di.inject(loggerInjectable);
|
||||
const hideAllWindows = di.inject(hideAllWindowsInjectable);
|
||||
|
||||
return () => {
|
||||
appEventBus.emit({ name: "service", action: "close" });
|
||||
windowManager.hide();
|
||||
hideAllWindows();
|
||||
clusterManager.stop();
|
||||
logger.info("SERVICE:QUIT");
|
||||
setTimeout(exitApp, 1000);
|
||||
|
||||
@ -3,8 +3,8 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { afterApplicationIsReadyInjectionToken } from "../start-main-application/after-application-is-ready/after-application-is-ready-injection-token";
|
||||
import trayInjectable from "./tray.injectable";
|
||||
import { whenApplicationIsLoadingInjectionToken } from "../start-main-application/when-application-is-loading/when-application-is-loading-injection-token";
|
||||
|
||||
const startTrayInjectable = getInjectable({
|
||||
id: "start-tray",
|
||||
@ -19,7 +19,7 @@ const startTrayInjectable = getInjectable({
|
||||
};
|
||||
},
|
||||
|
||||
injectionToken: afterApplicationIsReadyInjectionToken,
|
||||
injectionToken: whenApplicationIsLoadingInjectionToken,
|
||||
});
|
||||
|
||||
export default startTrayInjectable;
|
||||
|
||||
@ -4,33 +4,36 @@
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { initTray } from "./tray";
|
||||
import windowManagerInjectable from "../window-manager.injectable";
|
||||
import trayMenuItemsInjectable from "./tray-menu-items.injectable";
|
||||
import navigateToPreferencesInjectable from "../../common/front-end-routing/routes/preferences/navigate-to-preferences.injectable";
|
||||
import stopServicesAndExitAppInjectable from "../stop-services-and-exit-app.injectable";
|
||||
import { getStartableStoppable } from "../../common/utils/get-startable-stoppable";
|
||||
import isAutoUpdateEnabledInjectable from "../is-auto-update-enabled.injectable";
|
||||
import trayIconPathInjectable from "./tray-icon-path.injectable";
|
||||
import applicationWindowInjectable from "../start-main-application/lens-window/application-window/application-window.injectable";
|
||||
import showAboutInjectable from "../menu/show-about.injectable";
|
||||
|
||||
const trayInjectable = getInjectable({
|
||||
id: "tray",
|
||||
|
||||
instantiate: (di) => {
|
||||
const windowManager = di.inject(windowManagerInjectable);
|
||||
const trayMenuItems = di.inject(trayMenuItemsInjectable);
|
||||
const navigateToPreferences = di.inject(navigateToPreferencesInjectable);
|
||||
const stopServicesAndExitApp = di.inject(stopServicesAndExitAppInjectable);
|
||||
const isAutoUpdateEnabled = di.inject(isAutoUpdateEnabledInjectable);
|
||||
const trayIconPath = di.inject(trayIconPathInjectable);
|
||||
const applicationWindow = di.inject(applicationWindowInjectable);
|
||||
const showAboutPopup = di.inject(showAboutInjectable);
|
||||
|
||||
return getStartableStoppable("build-of-tray", () =>
|
||||
initTray(
|
||||
windowManager,
|
||||
trayMenuItems,
|
||||
navigateToPreferences,
|
||||
stopServicesAndExitApp,
|
||||
isAutoUpdateEnabled,
|
||||
trayIconPath,
|
||||
applicationWindow,
|
||||
showAboutPopup,
|
||||
),
|
||||
);
|
||||
},
|
||||
|
||||
@ -7,15 +7,14 @@ import packageInfo from "../../../package.json";
|
||||
import { Menu, Tray } from "electron";
|
||||
import type { IComputedValue } from "mobx";
|
||||
import { autorun } from "mobx";
|
||||
import { showAbout } from "../menu/menu";
|
||||
import { checkForUpdates } from "../app-updater";
|
||||
import type { WindowManager } from "../window-manager";
|
||||
import logger from "../logger";
|
||||
import { isDevelopment, isWindows, productName, staticFilesDirectory } from "../../common/vars";
|
||||
import type { Disposer } from "../../common/utils";
|
||||
import { disposer, toJS } from "../../common/utils";
|
||||
import type { TrayMenuRegistration } from "./tray-menu-registration";
|
||||
import path from "path";
|
||||
import type { LensWindow } from "../start-main-application/lens-window/application-window/lens-window-injection-token";
|
||||
|
||||
const TRAY_LOG_PREFIX = "[TRAY]";
|
||||
|
||||
@ -31,11 +30,12 @@ function getTrayIconPath(): string {
|
||||
}
|
||||
|
||||
export function initTray(
|
||||
windowManager: WindowManager,
|
||||
trayMenuItems: IComputedValue<TrayMenuRegistration[]>,
|
||||
navigateToPreferences: () => void,
|
||||
stopServicesAndExitApp: () => void,
|
||||
isAutoUpdateEnabled: () => boolean,
|
||||
applicationWindow: LensWindow,
|
||||
showAbout: () => void,
|
||||
): Disposer {
|
||||
const icon = getTrayIconPath();
|
||||
|
||||
@ -45,8 +45,7 @@ export function initTray(
|
||||
|
||||
if (isWindows) {
|
||||
tray.on("click", () => {
|
||||
windowManager
|
||||
.ensureMainWindow()
|
||||
applicationWindow.show()
|
||||
.catch(error => logger.error(`${TRAY_LOG_PREFIX}: Failed to open lens`, { error }));
|
||||
});
|
||||
}
|
||||
@ -54,7 +53,7 @@ export function initTray(
|
||||
return disposer(
|
||||
autorun(() => {
|
||||
try {
|
||||
const menu = createTrayMenu(windowManager, toJS(trayMenuItems.get()), navigateToPreferences, stopServicesAndExitApp, isAutoUpdateEnabled);
|
||||
const menu = createTrayMenu(toJS(trayMenuItems.get()), navigateToPreferences, stopServicesAndExitApp, isAutoUpdateEnabled, applicationWindow, showAbout);
|
||||
|
||||
tray.setContextMenu(menu);
|
||||
} catch (error) {
|
||||
@ -79,19 +78,18 @@ function getMenuItemConstructorOptions(trayItem: TrayMenuRegistration): Electron
|
||||
}
|
||||
|
||||
function createTrayMenu(
|
||||
windowManager: WindowManager,
|
||||
extensionTrayItems: TrayMenuRegistration[],
|
||||
navigateToPreferences: () => void,
|
||||
stopServicesAndExitApp: () => void,
|
||||
isAutoUpdateEnabled: () => boolean,
|
||||
applicationWindow: LensWindow,
|
||||
showAbout: () => void,
|
||||
): Menu {
|
||||
let template: Electron.MenuItemConstructorOptions[] = [
|
||||
{
|
||||
label: `Open ${productName}`,
|
||||
click() {
|
||||
windowManager
|
||||
.ensureMainWindow()
|
||||
.catch(error => logger.error(`${TRAY_LOG_PREFIX}: Failed to open lens`, { error }));
|
||||
applicationWindow.show().catch(error => logger.error(`${TRAY_LOG_PREFIX}: Failed to open lens`, { error }));
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -107,7 +105,7 @@ function createTrayMenu(
|
||||
label: "Check for updates",
|
||||
click() {
|
||||
checkForUpdates()
|
||||
.then(() => windowManager.ensureMainWindow());
|
||||
.then(() => applicationWindow.show());
|
||||
},
|
||||
});
|
||||
}
|
||||
@ -118,7 +116,7 @@ function createTrayMenu(
|
||||
{
|
||||
label: `About ${productName}`,
|
||||
click() {
|
||||
windowManager.ensureMainWindow()
|
||||
applicationWindow.show()
|
||||
.then(showAbout)
|
||||
.catch(error => logger.error(`${TRAY_LOG_PREFIX}: Failed to show Lens About view`, { error }));
|
||||
},
|
||||
|
||||
@ -1,20 +0,0 @@
|
||||
/**
|
||||
* 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 { WindowManager } from "./window-manager";
|
||||
import lensProxyPortNumberStateInjectable from "./lens-proxy-port-number-state.injectable";
|
||||
|
||||
const windowManagerInjectable = getInjectable({
|
||||
id: "window-manager",
|
||||
|
||||
instantiate: (di) =>
|
||||
new WindowManager({
|
||||
lensProxyPortNumberState: di.inject(lensProxyPortNumberStateInjectable),
|
||||
}),
|
||||
|
||||
causesSideEffects: true,
|
||||
});
|
||||
|
||||
export default windowManagerInjectable;
|
||||
@ -1,289 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import type { ClusterId } from "../common/cluster-types";
|
||||
import { makeObservable, observable } from "mobx";
|
||||
import { app, BrowserWindow, dialog, ipcMain, webContents } from "electron";
|
||||
import windowStateKeeper from "electron-window-state";
|
||||
import { appEventBus } from "../common/app-event-bus/event-bus";
|
||||
import { ipcMainOn } from "../common/ipc";
|
||||
import { delay, iter, openBrowser } from "../common/utils";
|
||||
import type { ClusterFrameInfo } from "../common/cluster-frames";
|
||||
import { clusterFrameMap } from "../common/cluster-frames";
|
||||
import { IpcRendererNavigationEvents } from "../renderer/navigation/events";
|
||||
import logger from "./logger";
|
||||
import { isMac, productName } from "../common/vars";
|
||||
import { bundledExtensionsLoaded } from "../common/ipc/extension-handling";
|
||||
|
||||
function isHideable(window: BrowserWindow | null): boolean {
|
||||
return Boolean(window && !window.isDestroyed());
|
||||
}
|
||||
|
||||
export interface SendToViewArgs {
|
||||
channel: string;
|
||||
frameInfo?: ClusterFrameInfo;
|
||||
data?: any[];
|
||||
}
|
||||
|
||||
interface Dependencies {
|
||||
lensProxyPortNumberState: { get: () => number };
|
||||
}
|
||||
|
||||
export class WindowManager {
|
||||
protected mainWindow: BrowserWindow;
|
||||
protected splashWindow: BrowserWindow;
|
||||
protected windowState: windowStateKeeper.State;
|
||||
protected disposers: Record<string, Function> = {};
|
||||
|
||||
@observable activeClusterId: ClusterId;
|
||||
|
||||
constructor(private dependencies: Dependencies) {
|
||||
makeObservable(this);
|
||||
this.bindEvents();
|
||||
}
|
||||
|
||||
get mainContentUrl() {
|
||||
return `http://localhost:${this.dependencies.lensProxyPortNumberState.get()}`;
|
||||
}
|
||||
|
||||
private async initMainWindow(showSplash: boolean) {
|
||||
// Manage main window size and position with state persistence
|
||||
if (!this.windowState) {
|
||||
this.windowState = windowStateKeeper({
|
||||
defaultHeight: 900,
|
||||
defaultWidth: 1440,
|
||||
});
|
||||
}
|
||||
|
||||
if (!this.mainWindow) {
|
||||
// show icon in dock (mac-os only)
|
||||
app.dock?.show();
|
||||
|
||||
const { width, height, x, y } = this.windowState;
|
||||
|
||||
this.mainWindow = new BrowserWindow({
|
||||
x, y, width, height,
|
||||
title: productName,
|
||||
show: false,
|
||||
minWidth: 700, // accommodate 800 x 600 display minimum
|
||||
minHeight: 500, // accommodate 800 x 600 display minimum
|
||||
titleBarStyle: isMac ? "hiddenInset" : "hidden",
|
||||
frame: isMac,
|
||||
backgroundColor: "#1e2124",
|
||||
webPreferences: {
|
||||
nodeIntegration: true,
|
||||
nodeIntegrationInSubFrames: true,
|
||||
webviewTag: true,
|
||||
contextIsolation: false,
|
||||
nativeWindowOpen: false,
|
||||
},
|
||||
});
|
||||
this.windowState.manage(this.mainWindow);
|
||||
|
||||
// open external links in default browser (target=_blank, window.open)
|
||||
this.mainWindow
|
||||
.on("focus", () => {
|
||||
appEventBus.emit({ name: "app", action: "focus" });
|
||||
})
|
||||
.on("blur", () => {
|
||||
appEventBus.emit({ name: "app", action: "blur" });
|
||||
})
|
||||
.on("closed", () => {
|
||||
// clean up
|
||||
this.windowState.unmanage();
|
||||
this.mainWindow = null;
|
||||
this.splashWindow = null;
|
||||
app.dock?.hide(); // hide icon in dock (mac-os)
|
||||
})
|
||||
.webContents
|
||||
.on("dom-ready", () => {
|
||||
appEventBus.emit({ name: "app", action: "dom-ready" });
|
||||
})
|
||||
.on("did-fail-load", (_event, code, desc) => {
|
||||
logger.error(`[WINDOW-MANAGER]: Failed to load Main window`, { code, desc });
|
||||
})
|
||||
.on("did-finish-load", () => {
|
||||
logger.info("[WINDOW-MANAGER]: Main window loaded");
|
||||
})
|
||||
.on("will-attach-webview", (event, webPreferences, params) => {
|
||||
logger.debug("[WINDOW-MANAGER]: Attaching webview");
|
||||
// Following is security recommendations because we allow webview tag (webviewTag: true)
|
||||
// suggested by https://www.electronjs.org/docs/tutorial/security#11-verify-webview-options-before-creation
|
||||
// and https://www.electronjs.org/docs/tutorial/security#10-do-not-use-allowpopups
|
||||
|
||||
if (webPreferences.preload) {
|
||||
logger.warn("[WINDOW-MANAGER]: Strip away preload scripts of webview");
|
||||
delete webPreferences.preload;
|
||||
}
|
||||
|
||||
// @ts-expect-error some electron version uses webPreferences.preloadURL/webPreferences.preload
|
||||
if (webPreferences.preloadURL) {
|
||||
logger.warn("[WINDOW-MANAGER]: Strip away preload scripts of webview");
|
||||
delete webPreferences.preload;
|
||||
}
|
||||
|
||||
if (params.allowpopups) {
|
||||
logger.warn("[WINDOW-MANAGER]: We do not allow allowpopups props, stop webview from renderer");
|
||||
|
||||
// event.preventDefault() will destroy the guest page.
|
||||
event.preventDefault();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Always disable Node.js integration for all webviews
|
||||
webPreferences.nodeIntegration = false;
|
||||
})
|
||||
.setWindowOpenHandler((details) => {
|
||||
openBrowser(details.url).catch(error => {
|
||||
logger.error("[WINDOW-MANAGER]: failed to open browser", { error });
|
||||
});
|
||||
|
||||
return { action: "deny" };
|
||||
});
|
||||
}
|
||||
|
||||
try {
|
||||
if (showSplash) await this.showSplash();
|
||||
logger.info(`[WINDOW-MANAGER]: Loading Main window from url: ${this.mainContentUrl} ...`);
|
||||
await this.mainWindow.loadURL(this.mainContentUrl);
|
||||
} catch (error) {
|
||||
logger.error("Loading main window failed", { error });
|
||||
dialog.showErrorBox("ERROR!", error.toString());
|
||||
}
|
||||
}
|
||||
|
||||
protected bindEvents() {
|
||||
// track visible cluster from ui
|
||||
ipcMainOn(IpcRendererNavigationEvents.CLUSTER_VIEW_CURRENT_ID, (event, clusterId: ClusterId) => {
|
||||
this.activeClusterId = clusterId;
|
||||
});
|
||||
}
|
||||
|
||||
async ensureMainWindow(showSplash = true): Promise<BrowserWindow> {
|
||||
// This needs to be ready to hear the IPC message before the window is loaded
|
||||
let viewHasLoaded = Promise.resolve();
|
||||
|
||||
if (!this.mainWindow) {
|
||||
viewHasLoaded = new Promise<void>(resolve => {
|
||||
ipcMain.once(bundledExtensionsLoaded, () => resolve());
|
||||
});
|
||||
await this.initMainWindow(showSplash);
|
||||
}
|
||||
|
||||
try {
|
||||
await viewHasLoaded;
|
||||
await delay(50); // wait just a bit longer to let the first round of rendering happen
|
||||
logger.info("[WINDOW-MANAGER]: Main window has reported that it has loaded");
|
||||
|
||||
this.mainWindow.show();
|
||||
this.splashWindow?.close();
|
||||
this.splashWindow = undefined;
|
||||
setTimeout(() => {
|
||||
appEventBus.emit({ name: "app", action: "start" });
|
||||
}, 1000);
|
||||
} catch (error) {
|
||||
logger.error(`Showing main window failed: ${error.stack || error}`);
|
||||
dialog.showErrorBox("ERROR!", error.toString());
|
||||
}
|
||||
|
||||
return this.mainWindow;
|
||||
}
|
||||
|
||||
sendToView({ channel, frameInfo, data = [] }: SendToViewArgs) {
|
||||
if (frameInfo) {
|
||||
this.mainWindow.webContents.sendToFrame([frameInfo.processId, frameInfo.frameId], channel, ...data);
|
||||
} else {
|
||||
this.mainWindow.webContents.send(channel, ...data);
|
||||
}
|
||||
}
|
||||
|
||||
async navigateExtension(extId: string, pageId?: string, params?: Record<string, any>, frameId?: number) {
|
||||
await this.ensureMainWindow();
|
||||
|
||||
const frameInfo = iter.find(clusterFrameMap.values(), frameInfo => frameInfo.frameId === frameId);
|
||||
|
||||
this.sendToView({
|
||||
channel: "extension:navigate",
|
||||
frameInfo,
|
||||
data: [extId, pageId, params],
|
||||
});
|
||||
}
|
||||
|
||||
async navigate(url: string, frameId?: number) {
|
||||
await this.ensureMainWindow();
|
||||
|
||||
this.navigateSync(url, frameId);
|
||||
}
|
||||
|
||||
navigateSync(url: string, frameId?: number) {
|
||||
const frameInfo = iter.find(clusterFrameMap.values(), frameInfo => frameInfo.frameId === frameId);
|
||||
const channel = frameInfo
|
||||
? IpcRendererNavigationEvents.NAVIGATE_IN_CLUSTER
|
||||
: IpcRendererNavigationEvents.NAVIGATE_IN_APP;
|
||||
|
||||
this.sendToView({
|
||||
channel,
|
||||
frameInfo,
|
||||
data: [url],
|
||||
});
|
||||
}
|
||||
|
||||
reload() {
|
||||
const frameInfo = clusterFrameMap.get(this.activeClusterId);
|
||||
|
||||
if (frameInfo) {
|
||||
this.sendToView({ channel: IpcRendererNavigationEvents.RELOAD_PAGE, frameInfo });
|
||||
} else {
|
||||
webContents.getAllWebContents().filter(wc => wc.getType() === "window").forEach(wc => {
|
||||
wc.reload();
|
||||
wc.clearHistory();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
async showSplash() {
|
||||
if (!this.splashWindow) {
|
||||
this.splashWindow = new BrowserWindow({
|
||||
width: 500,
|
||||
height: 300,
|
||||
backgroundColor: "#1e2124",
|
||||
center: true,
|
||||
frame: false,
|
||||
resizable: false,
|
||||
show: false,
|
||||
webPreferences: {
|
||||
nodeIntegration: true,
|
||||
contextIsolation: false,
|
||||
nodeIntegrationInSubFrames: true,
|
||||
nativeWindowOpen: true,
|
||||
},
|
||||
});
|
||||
await this.splashWindow.loadURL("static://splash.html");
|
||||
}
|
||||
this.splashWindow.show();
|
||||
}
|
||||
|
||||
hide() {
|
||||
if (isHideable(this.mainWindow)) {
|
||||
this.mainWindow.hide();
|
||||
}
|
||||
|
||||
if (isHideable(this.splashWindow)) {
|
||||
this.splashWindow.hide();
|
||||
}
|
||||
}
|
||||
|
||||
destroy() {
|
||||
this.mainWindow.destroy();
|
||||
this.splashWindow.destroy();
|
||||
this.mainWindow = null;
|
||||
this.splashWindow = null;
|
||||
Object.entries(this.disposers).forEach(([name, dispose]) => {
|
||||
dispose();
|
||||
delete this.disposers[name];
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -36,6 +36,7 @@ import hotbarStoreInjectable from "../common/hotbar-store.injectable";
|
||||
import themeStoreInjectable from "./theme-store.injectable";
|
||||
import apiManagerInjectable from "./components/kube-object-menu/dependencies/api-manager.injectable";
|
||||
import { ApiManager } from "../common/k8s-api/api-manager";
|
||||
import lensResourcesDirInjectable from "../common/vars/lens-resources-dir.injectable";
|
||||
|
||||
export const getDiForUnitTesting = (
|
||||
{ doGeneralOverrides } = { doGeneralOverrides: false },
|
||||
@ -63,6 +64,8 @@ export const getDiForUnitTesting = (
|
||||
di.override(getAbsolutePathInjectable, () => getAbsolutePathFake);
|
||||
di.override(joinPathsInjectable, () => joinPathsFake);
|
||||
|
||||
di.override(lensResourcesDirInjectable, () => "/irrelevant");
|
||||
|
||||
// eslint-disable-next-line unused-imports/no-unused-vars-ts
|
||||
di.override(extensionsStoreInjectable, () => ({ isEnabled: ({ id, isBundled }) => false }) as ExtensionsStore);
|
||||
|
||||
|
||||
@ -8,9 +8,9 @@ import getValueFromRegisteredChannelInjectable from "../renderer/app-paths/get-v
|
||||
import registerChannelInjectable from "../main/app-paths/register-channel/register-channel.injectable";
|
||||
import asyncFn from "@async-fn/jest";
|
||||
import registerIpcChannelListenerInjectable from "../renderer/app-paths/get-value-from-registered-channel/register-ipc-channel-listener.injectable";
|
||||
import windowManagerInjectable from "../main/window-manager.injectable";
|
||||
import type { SendToViewArgs, WindowManager } from "../main/window-manager";
|
||||
import { appNavigationIpcChannel } from "../common/front-end-routing/navigation-ipc-channel";
|
||||
import type { SendToViewArgs } from "../main/start-main-application/lens-window/application-window/lens-window-injection-token";
|
||||
import sendToChannelInElectronBrowserWindowInjectable from "../main/start-main-application/lens-window/application-window/send-to-channel-in-electron-browser-window.injectable";
|
||||
|
||||
|
||||
export const overrideIpcBridge = ({
|
||||
rendererDi,
|
||||
@ -68,7 +68,10 @@ export const overrideIpcBridge = ({
|
||||
mainIpcRegistrations.set(channel, callback);
|
||||
});
|
||||
|
||||
const rendererIpcFakeHandles = new Map<string, ((...args: any[]) => void)[]>();
|
||||
const rendererIpcFakeHandles = new Map<
|
||||
string,
|
||||
((...args: any[]) => void)[]
|
||||
>();
|
||||
|
||||
rendererDi.override(
|
||||
registerIpcChannelListenerInjectable,
|
||||
@ -81,21 +84,14 @@ export const overrideIpcBridge = ({
|
||||
);
|
||||
|
||||
mainDi.override(
|
||||
windowManagerInjectable,
|
||||
sendToChannelInElectronBrowserWindowInjectable,
|
||||
() =>
|
||||
({
|
||||
ensureMainWindow: () => Promise.resolve(),
|
||||
(browserWindow, { channel: channelName, data }: SendToViewArgs) => {
|
||||
const handles = rendererIpcFakeHandles.get(channelName);
|
||||
|
||||
sendToView: ({ channel: channelName, data }: SendToViewArgs) => {
|
||||
const handles = rendererIpcFakeHandles.get(channelName);
|
||||
handles.forEach((handle) => handle(...data));
|
||||
|
||||
handles.forEach(handle => handle(...data));
|
||||
},
|
||||
|
||||
navigateSync(url: string) {
|
||||
this.sendToView({ channel: appNavigationIpcChannel.name, data: [url] });
|
||||
},
|
||||
|
||||
} as unknown as WindowManager),
|
||||
return Promise.resolve();
|
||||
},
|
||||
);
|
||||
};
|
||||
|
||||
Loading…
Reference in New Issue
Block a user