diff --git a/packages/core/src/common/protocol-handler/logger.injectable.ts b/packages/core/src/common/protocol-handler/logger.injectable.ts new file mode 100644 index 0000000000..15f965d1d9 --- /dev/null +++ b/packages/core/src/common/protocol-handler/logger.injectable.ts @@ -0,0 +1,13 @@ +/** + * Copyright (c) OpenLens Authors. All rights reserved. + * Licensed under MIT License. See LICENSE in root directory for more information. + */ +import { getInjectable } from "@ogre-tools/injectable"; +import prefixedLoggerInjectable from "../logger/prefixed-logger.injectable"; + +const protocolHandlerLoggerInjectable = getInjectable({ + id: "protocol-handler-logger", + instantiate: (di) => di.inject(prefixedLoggerInjectable, "PROTOCOL-HANDLER"), +}); + +export default protocolHandlerLoggerInjectable; diff --git a/packages/core/src/common/protocol-handler/router.ts b/packages/core/src/common/protocol-handler/router.ts index 31b4f41e52..383972c601 100644 --- a/packages/core/src/common/protocol-handler/router.ts +++ b/packages/core/src/common/protocol-handler/router.ts @@ -7,7 +7,6 @@ import type { match } from "react-router"; import { matchPath } from "react-router"; import { countBy } from "lodash"; import { isDefined, iter } from "../utils"; -import { pathToRegexp } from "path-to-regexp"; import type Url from "url-parse"; import { RoutingError, RoutingErrorType } from "./error"; import type { ExtensionsStore } from "../../extensions/extensions-store/extensions-store"; @@ -62,17 +61,13 @@ export function foldAttemptResults(mainAttempt: RouteAttempt, rendererAttempt: R export interface LensProtocolRouterDependencies { readonly extensionsStore: ExtensionsStore; readonly logger: Logger; + readonly internalRoutes: Map; findExtensionInstanceByName: FindExtensionInstanceByName; } +export const extensionUrlDeepLinkingSchema = `/:${EXTENSION_PUBLISHER_MATCH}(@[A-Za-z0-9_]+)?/:${EXTENSION_NAME_MATCH}`; + export abstract class LensProtocolRouter { - // Map between path schemas and the handlers - protected internalRoutes = new Map(); - - public static readonly LoggingPrefix = "[PROTOCOL ROUTER]"; - - static readonly ExtensionUrlSchema = `/:${EXTENSION_PUBLISHER_MATCH}(@[A-Za-z0-9_]+)?/:${EXTENSION_NAME_MATCH}`; - constructor(protected readonly dependencies: LensProtocolRouterDependencies) {} /** @@ -81,7 +76,7 @@ export abstract class LensProtocolRouter { * @returns true if a route has been found */ protected _routeToInternal(url: Url>): RouteAttempt { - return this._route(this.internalRoutes.entries(), url); + return this._route(this.dependencies.internalRoutes.entries(), url); } /** @@ -137,7 +132,7 @@ export abstract class LensProtocolRouter { data.extensionName = extensionName; } - this.dependencies.logger.info(`${LensProtocolRouter.LoggingPrefix}: No handler found`, data); + this.dependencies.logger.info(`No handler found`, data); return RouteAttempt.MISSING; } @@ -171,7 +166,7 @@ export abstract class LensProtocolRouter { [EXTENSION_NAME_MATCH]: string; } - const match = matchPath(url.pathname, LensProtocolRouter.ExtensionUrlSchema); + const match = matchPath(url.pathname, extensionUrlDeepLinkingSchema); if (!match) { throw new RoutingError(RoutingErrorType.NO_EXTENSION_ID, url); @@ -186,7 +181,7 @@ export abstract class LensProtocolRouter { }); } catch (error) { this.dependencies.logger.info( - `${LensProtocolRouter.LoggingPrefix}: Extension ${name} matched, but not installed (${error})`, + `Extension ${name} matched, but not installed (${error})`, ); return name; @@ -195,18 +190,18 @@ export abstract class LensProtocolRouter { const extension = this.dependencies.findExtensionInstanceByName(name); if (typeof extension === "string") { - this.dependencies.logger.info(`${LensProtocolRouter.LoggingPrefix}: Extension ${name} matched, but ${extension}`); + this.dependencies.logger.info(`Extension ${name} matched, but ${extension}`); return name; } if (!extension.isBundled && !this.dependencies.extensionsStore.isEnabled(extension.id)) { - this.dependencies.logger.info(`${LensProtocolRouter.LoggingPrefix}: Extension ${name} matched, but not enabled`); + this.dependencies.logger.info(`Extension ${name} matched, but not enabled`); return name; } - this.dependencies.logger.info(`${LensProtocolRouter.LoggingPrefix}: Extension ${name} matched`); + this.dependencies.logger.info(`Extension ${name} matched`); return extension; } @@ -244,25 +239,4 @@ export abstract class LensProtocolRouter { throw error; } } - - /** - * Add a handler under the `lens://app` tree of routing. - * @param pathSchema the URI path schema to match against for this handler - * @param handler a function that will be called if a protocol path matches - */ - public addInternalHandler(urlSchema: string, handler: RouteHandler): this { - pathToRegexp(urlSchema); // verify now that the schema is valid - this.dependencies.logger.info(`${LensProtocolRouter.LoggingPrefix}: internal registering ${urlSchema}`); - this.internalRoutes.set(urlSchema, handler); - - return this; - } - - /** - * Remove an internal protocol handler. - * @param pathSchema the path schema that the handler was registered under - */ - public removeInternalHandler(urlSchema: string): void { - this.internalRoutes.delete(urlSchema); - } } diff --git a/packages/core/src/features/deep-linking/common/internal-handler-token.ts b/packages/core/src/features/deep-linking/common/internal-handler-token.ts new file mode 100644 index 0000000000..847ecf9281 --- /dev/null +++ b/packages/core/src/features/deep-linking/common/internal-handler-token.ts @@ -0,0 +1,17 @@ +/** + * Copyright (c) OpenLens Authors. All rights reserved. + * Licensed under MIT License. See LICENSE in root directory for more information. + */ + +import { getInjectionToken } from "@ogre-tools/injectable"; +import type { RouteHandler } from "../../../common/protocol-handler/registration"; + + +export interface InternalRouteRegistration { + path: string; + handler: RouteHandler; +} + +export const internalDeepLinkingRouteInjectionToken = getInjectionToken({ + id: "internal-protocol-route-token", +}); diff --git a/packages/core/src/features/deep-linking/renderer/add-cluster-handler.injectable.ts b/packages/core/src/features/deep-linking/renderer/add-cluster-handler.injectable.ts new file mode 100644 index 0000000000..0cd0b0de25 --- /dev/null +++ b/packages/core/src/features/deep-linking/renderer/add-cluster-handler.injectable.ts @@ -0,0 +1,22 @@ +/** + * 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 navigateToAddClusterInjectable from "../../../common/front-end-routing/routes/add-cluster/navigate-to-add-cluster.injectable"; +import { internalDeepLinkingRouteInjectionToken } from "../common/internal-handler-token"; + +const addClusterDeepLinkingHandlerInjectable = getInjectable({ + id: "add-cluster-deep-linking-handler", + instantiate: (di) => { + const navigateToAddCluster = di.inject(navigateToAddClusterInjectable); + + return { + path: "/cluster", + handler: () => navigateToAddCluster(), + }; + }, + injectionToken: internalDeepLinkingRouteInjectionToken, +}); + +export default addClusterDeepLinkingHandlerInjectable; diff --git a/packages/core/src/features/deep-linking/renderer/deprecated-view-cluster-handler.injectable.tsx b/packages/core/src/features/deep-linking/renderer/deprecated-view-cluster-handler.injectable.tsx new file mode 100644 index 0000000000..bfa92c2aad --- /dev/null +++ b/packages/core/src/features/deep-linking/renderer/deprecated-view-cluster-handler.injectable.tsx @@ -0,0 +1,45 @@ +/** + * 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 React from "react"; +import getClusterByIdInjectable from "../../../common/cluster-store/get-by-id.injectable"; +import navigateToClusterViewInjectable from "../../../common/front-end-routing/routes/cluster-view/navigate-to-cluster-view.injectable"; +import showShortInfoNotificationInjectable from "../../../renderer/components/notifications/show-short-info.injectable"; +import { internalDeepLinkingRouteInjectionToken } from "../common/internal-handler-token"; + +const deprecatedViewClusterDeepLinkingHandlerInjectable = getInjectable({ + id: "deprecated-view-cluster-deep-linking-handler", + instantiate: (di) => { + const getClusterById = di.inject(getClusterByIdInjectable); + const navigateToClusterView = di.inject(navigateToClusterViewInjectable); + const showShortInfoNotification = di.inject(showShortInfoNotificationInjectable); + + return { + path: "/cluster/:clusterId", + handler: ({ pathname: { clusterId }}) => { + if (!clusterId) { + return; + } + + const cluster = getClusterById(clusterId); + + if (cluster) { + navigateToClusterView(clusterId); + } else { + showShortInfoNotification( +

+ {"Unknown catalog entity "} + {clusterId} + . +

, + ); + } + }, + }; + }, + injectionToken: internalDeepLinkingRouteInjectionToken, +}); + +export default deprecatedViewClusterDeepLinkingHandlerInjectable; diff --git a/packages/core/src/features/deep-linking/renderer/deprecated-view-cluster-settings-handler.injectable.tsx b/packages/core/src/features/deep-linking/renderer/deprecated-view-cluster-settings-handler.injectable.tsx new file mode 100644 index 0000000000..dc7fc9a947 --- /dev/null +++ b/packages/core/src/features/deep-linking/renderer/deprecated-view-cluster-settings-handler.injectable.tsx @@ -0,0 +1,45 @@ +/** + * 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 React from "react"; +import getClusterByIdInjectable from "../../../common/cluster-store/get-by-id.injectable"; +import navigateToEntitySettingsInjectable from "../../../common/front-end-routing/routes/entity-settings/navigate-to-entity-settings.injectable"; +import showShortInfoNotificationInjectable from "../../../renderer/components/notifications/show-short-info.injectable"; +import { internalDeepLinkingRouteInjectionToken } from "../common/internal-handler-token"; + +const depcratedViewClusterSettingsDeepLinkingHandlerInjectable = getInjectable({ + id: "depcrated-view-cluster-settings-deep-linking-handler", + instantiate: (di) => { + const getClusterById = di.inject(getClusterByIdInjectable); + const navigateToEntitySettings = di.inject(navigateToEntitySettingsInjectable); + const showShortInfoNotification = di.inject(showShortInfoNotificationInjectable); + + return { + path: "/cluster/:clusterId/settings", + handler: ({ pathname: { clusterId }}) => { + if (!clusterId) { + return; + } + + const cluster = getClusterById(clusterId); + + if (cluster) { + navigateToEntitySettings(clusterId); + } else { + showShortInfoNotification( +

+ {"Unknown catalog entity "} + {clusterId} + . +

, + ); + } + }, + }; + }, + injectionToken: internalDeepLinkingRouteInjectionToken, +}); + +export default depcratedViewClusterSettingsDeepLinkingHandlerInjectable; diff --git a/packages/core/src/features/deep-linking/renderer/install-extension-handler.injectable.ts b/packages/core/src/features/deep-linking/renderer/install-extension-handler.injectable.ts new file mode 100644 index 0000000000..820c2b79f1 --- /dev/null +++ b/packages/core/src/features/deep-linking/renderer/install-extension-handler.injectable.ts @@ -0,0 +1,35 @@ +/** + * Copyright (c) OpenLens Authors. All rights reserved. + * Licensed under MIT License. See LICENSE in root directory for more information. + */ +import { getInjectable } from "@ogre-tools/injectable"; +import navigateToExtensionsInjectable from "../../../common/front-end-routing/routes/extensions/navigate-to-extensions.injectable"; +import { extensionUrlDeepLinkingSchema, EXTENSION_NAME_MATCH, EXTENSION_PUBLISHER_MATCH } from "../../../common/protocol-handler"; +import attemptInstallByInfoInjectable from "../../../renderer/components/+extensions/attempt-install-by-info.injectable"; +import { internalDeepLinkingRouteInjectionToken } from "../common/internal-handler-token"; + +const installExtensionDeepLinkingHandlerInjectable = getInjectable({ + id: "install-extension-deep-linking-handler", + instantiate: (di) => { + const navigateToExtensions = di.inject(navigateToExtensionsInjectable); + const attemptInstallByInfo = di.inject(attemptInstallByInfoInjectable); + + return { + path: `/extensions/install${extensionUrlDeepLinkingSchema}`, + handler: ({ pathname, search: { version }}) => { + const name = [ + pathname[EXTENSION_PUBLISHER_MATCH], + pathname[EXTENSION_NAME_MATCH], + ] + .filter(Boolean) + .join("/"); + + navigateToExtensions(); + attemptInstallByInfo({ name, version, requireConfirmation: true }); + }, + }; + }, + injectionToken: internalDeepLinkingRouteInjectionToken, +}); + +export default installExtensionDeepLinkingHandlerInjectable; diff --git a/packages/core/src/features/deep-linking/renderer/internal-deep-linking-routes.injectable.ts b/packages/core/src/features/deep-linking/renderer/internal-deep-linking-routes.injectable.ts new file mode 100644 index 0000000000..60c00c4029 --- /dev/null +++ b/packages/core/src/features/deep-linking/renderer/internal-deep-linking-routes.injectable.ts @@ -0,0 +1,22 @@ +/** + * 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 { pathToRegexp } from "path-to-regexp"; +import { internalDeepLinkingRouteInjectionToken } from "../common/internal-handler-token"; + +const internalDeepLinkingRoutesInjectable = getInjectable({ + id: "internal-deep-linking-routes", + instantiate: (di) => { + const registrations = di.injectMany(internalDeepLinkingRouteInjectionToken); + + return new Map(registrations.map(registration => { + pathToRegexp(registration.path); // verify now that the schema is valid + + return [registration.path, registration.handler]; + })); + }, +}); + +export default internalDeepLinkingRoutesInjectable; diff --git a/packages/core/src/features/deep-linking/renderer/landing-page-handler.injectable.ts b/packages/core/src/features/deep-linking/renderer/landing-page-handler.injectable.ts new file mode 100644 index 0000000000..32868c97e5 --- /dev/null +++ b/packages/core/src/features/deep-linking/renderer/landing-page-handler.injectable.ts @@ -0,0 +1,22 @@ +/** + * 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 navigateToCatalogInjectable from "../../../common/front-end-routing/routes/catalog/navigate-to-catalog.injectable"; +import { internalDeepLinkingRouteInjectionToken } from "../common/internal-handler-token"; + +const landingPageDeepLinkingHandlerInjectable = getInjectable({ + id: "landing-page-deep-linking-handler", + instantiate: (di) => { + const navigateToCatalog = di.inject(navigateToCatalogInjectable); + + return { + path: "/landing", + handler: () => navigateToCatalog(), + }; + }, + injectionToken: internalDeepLinkingRouteInjectionToken, +}); + +export default landingPageDeepLinkingHandlerInjectable; diff --git a/packages/core/src/features/deep-linking/renderer/preferences-handler.injectable.ts b/packages/core/src/features/deep-linking/renderer/preferences-handler.injectable.ts new file mode 100644 index 0000000000..c15435567d --- /dev/null +++ b/packages/core/src/features/deep-linking/renderer/preferences-handler.injectable.ts @@ -0,0 +1,26 @@ +/** + * 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 navigateToPreferencesInjectable from "../../preferences/common/navigate-to-preferences.injectable"; +import { internalDeepLinkingRouteInjectionToken } from "../common/internal-handler-token"; + +const preferencesDeepLinkHandlerInjectable = getInjectable({ + id: "preferences-deep-link-handler", + instantiate: (di) => { + const navigateToPreferences = di.inject(navigateToPreferencesInjectable); + + return { + path: "/preferences", + handler: ({ search: { highlight: tabId }}) => { + if (tabId) { + navigateToPreferences(tabId); + } + }, + }; + }, + injectionToken: internalDeepLinkingRouteInjectionToken, +}); + +export default preferencesDeepLinkHandlerInjectable; diff --git a/packages/core/src/features/deep-linking/renderer/specific-landing-page-handler.injectable.ts b/packages/core/src/features/deep-linking/renderer/specific-landing-page-handler.injectable.ts new file mode 100644 index 0000000000..64c050c6c8 --- /dev/null +++ b/packages/core/src/features/deep-linking/renderer/specific-landing-page-handler.injectable.ts @@ -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 navigateToCatalogInjectable from "../../../common/front-end-routing/routes/catalog/navigate-to-catalog.injectable"; +import { internalDeepLinkingRouteInjectionToken } from "../common/internal-handler-token"; + +const specificLandingPageDeepLinkingHandlerInjectable = getInjectable({ + id: "specific-landing-page-deep-linking-handler", + instantiate: (di) => { + const navigateToCatalog = di.inject(navigateToCatalogInjectable); + + return { + path: "/landing/view/:group/:kind", + handler: ({ pathname: { group, kind }}) => { + navigateToCatalog({ group, kind }); + }, + }; + }, + injectionToken: internalDeepLinkingRouteInjectionToken, +}); + +export default specificLandingPageDeepLinkingHandlerInjectable; diff --git a/packages/core/src/features/deep-linking/renderer/unknown-action-handler.injectable.tsx b/packages/core/src/features/deep-linking/renderer/unknown-action-handler.injectable.tsx new file mode 100644 index 0000000000..05189fb471 --- /dev/null +++ b/packages/core/src/features/deep-linking/renderer/unknown-action-handler.injectable.tsx @@ -0,0 +1,40 @@ +/** + * Copyright (c) OpenLens Authors. All rights reserved. + * Licensed under MIT License. See LICENSE in root directory for more information. + */ +import { getInjectable } from "@ogre-tools/injectable"; +import React from "react"; +import navigateToCatalogInjectable from "../../../common/front-end-routing/routes/catalog/navigate-to-catalog.injectable"; +import showShortInfoNotificationInjectable from "../../../renderer/components/notifications/show-short-info.injectable"; +import { internalDeepLinkingRouteInjectionToken } from "../common/internal-handler-token"; + +const unknownDeepLinkingActionHandlerInjectable = getInjectable({ + id: "unknown-deep-linking-action-handler", + instantiate: (di) => { + const showShortInfoNotification = di.inject(showShortInfoNotificationInjectable); + const navigateToCatalog = di.inject(navigateToCatalogInjectable); + + return { + path: "/", + handler: ({ tail }) => { + if (tail) { + showShortInfoNotification( +

+ {"Unknown Action for "} + + lens://app/ + {tail} + + . Are you on the latest version? +

, + ); + } + + navigateToCatalog(); + }, + }; + }, + injectionToken: internalDeepLinkingRouteInjectionToken, +}); + +export default unknownDeepLinkingActionHandlerInjectable; diff --git a/packages/core/src/features/deep-linking/renderer/view-entity-settings-handler.injectable.tsx b/packages/core/src/features/deep-linking/renderer/view-entity-settings-handler.injectable.tsx new file mode 100644 index 0000000000..2396780cbb --- /dev/null +++ b/packages/core/src/features/deep-linking/renderer/view-entity-settings-handler.injectable.tsx @@ -0,0 +1,46 @@ +/** + * 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 React from "react"; +import navigateToEntitySettingsInjectable from "../../../common/front-end-routing/routes/entity-settings/navigate-to-entity-settings.injectable"; +import catalogEntityRegistryInjectable from "../../../renderer/api/catalog/entity/registry.injectable"; +import showShortInfoNotificationInjectable from "../../../renderer/components/notifications/show-short-info.injectable"; +import { internalDeepLinkingRouteInjectionToken } from "../common/internal-handler-token"; + +const viewEntitySettingsDeepLinkingHandlerInjectable = getInjectable({ + id: "view-entity-settings-deep-linking-handler", + instantiate: (di) => { + const entityRegistry = di.inject(catalogEntityRegistryInjectable); + const navigateToEntitySettings = di.inject(navigateToEntitySettingsInjectable); + const showShortInfoNotification = di.inject(showShortInfoNotificationInjectable); + + return { + path: "/entity/:entityId/settings", + handler: ({ pathname: { entityId }}) => { + // TODO: maybe improve typing in the future + if (!entityId) { + return; + } + + const entity = entityRegistry.getById(entityId); + + if (entity) { + navigateToEntitySettings(entityId); + } else { + showShortInfoNotification( +

+ {"Unknown catalog entity "} + {entityId} + . +

, + ); + } + }, + }; + }, + injectionToken: internalDeepLinkingRouteInjectionToken, +}); + +export default viewEntitySettingsDeepLinkingHandlerInjectable; diff --git a/packages/core/src/features/deep-linking/renderer/view-extensions-handler.injectable.ts b/packages/core/src/features/deep-linking/renderer/view-extensions-handler.injectable.ts new file mode 100644 index 0000000000..080e41c281 --- /dev/null +++ b/packages/core/src/features/deep-linking/renderer/view-extensions-handler.injectable.ts @@ -0,0 +1,22 @@ +/** + * 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 navigateToExtensionsInjectable from "../../../common/front-end-routing/routes/extensions/navigate-to-extensions.injectable"; +import { internalDeepLinkingRouteInjectionToken } from "../common/internal-handler-token"; + +const viewExtensionsDeepLinkingHandlerInjectable = getInjectable({ + id: "view-extensions-deep-linking-handler", + instantiate: (di) => { + const navigateToExtensions = di.inject(navigateToExtensionsInjectable); + + return { + path: "/extensions", + handler: () => navigateToExtensions(), + }; + }, + injectionToken: internalDeepLinkingRouteInjectionToken, +}); + +export default viewExtensionsDeepLinkingHandlerInjectable; diff --git a/packages/core/src/main/protocol-handler/lens-protocol-router-main/lens-protocol-router-main.injectable.ts b/packages/core/src/main/protocol-handler/lens-protocol-router-main/lens-protocol-router-main.injectable.ts index d12626d92f..4551f493c2 100644 --- a/packages/core/src/main/protocol-handler/lens-protocol-router-main/lens-protocol-router-main.injectable.ts +++ b/packages/core/src/main/protocol-handler/lens-protocol-router-main/lens-protocol-router-main.injectable.ts @@ -7,8 +7,9 @@ import { LensProtocolRouterMain } from "./lens-protocol-router-main"; import extensionsStoreInjectable from "../../../extensions/extensions-store/extensions-store.injectable"; import showApplicationWindowInjectable from "../../start-main-application/lens-window/show-application-window.injectable"; import broadcastMessageInjectable from "../../../common/ipc/broadcast-message.injectable"; -import loggerInjectable from "../../../common/logger.injectable"; import findExtensionInstanceByNameInjectable from "../../../features/extensions/loader/common/find-instance-by-name.injectable"; +import internalDeepLinkingRoutesInjectable from "../../../features/deep-linking/renderer/internal-deep-linking-routes.injectable"; +import protocolHandlerLoggerInjectable from "../../../common/protocol-handler/logger.injectable"; const lensProtocolRouterMainInjectable = getInjectable({ id: "lens-protocol-router-main", @@ -17,8 +18,9 @@ const lensProtocolRouterMainInjectable = getInjectable({ extensionsStore: di.inject(extensionsStoreInjectable), showApplicationWindow: di.inject(showApplicationWindowInjectable), broadcastMessage: di.inject(broadcastMessageInjectable), - logger: di.inject(loggerInjectable), + logger: di.inject(protocolHandlerLoggerInjectable), findExtensionInstanceByName: di.inject(findExtensionInstanceByNameInjectable), + internalRoutes: di.inject(internalDeepLinkingRoutesInjectable), }), }); diff --git a/packages/core/src/main/protocol-handler/lens-protocol-router-main/lens-protocol-router-main.ts b/packages/core/src/main/protocol-handler/lens-protocol-router-main/lens-protocol-router-main.ts index bcf727a6a0..04ff7e43ec 100644 --- a/packages/core/src/main/protocol-handler/lens-protocol-router-main/lens-protocol-router-main.ts +++ b/packages/core/src/main/protocol-handler/lens-protocol-router-main/lens-protocol-router-main.ts @@ -71,7 +71,7 @@ export class LensProtocolRouterMain extends proto.LensProtocolRouter { this.dependencies.showApplicationWindow().catch(noop); const routeInternally = checkHost(url); - this.dependencies.logger.info(`${proto.LensProtocolRouter.LoggingPrefix}: routing ${url.toString()}`); + this.dependencies.logger.info(`routing ${url.toString()}`); if (routeInternally) { this._routeToInternal(url); @@ -82,9 +82,9 @@ export class LensProtocolRouterMain extends proto.LensProtocolRouter { this.dependencies.broadcastMessage(ProtocolHandlerInvalid, error ? String(error) : "unknown error", rawUrl); if (error instanceof proto.RoutingError) { - this.dependencies.logger.error(`${proto.LensProtocolRouter.LoggingPrefix}: ${error}`, { url: error.url }); + this.dependencies.logger.error(`${error}`, { url: error.url }); } else { - this.dependencies.logger.error(`${proto.LensProtocolRouter.LoggingPrefix}: ${error}`, { rawUrl }); + this.dependencies.logger.error(`${error}`, { rawUrl }); } } } diff --git a/packages/core/src/renderer/frames/root-frame/init-root-frame.injectable.ts b/packages/core/src/renderer/frames/root-frame/init-root-frame.injectable.ts index 4551c07ea6..f785f5c6c8 100644 --- a/packages/core/src/renderer/frames/root-frame/init-root-frame.injectable.ts +++ b/packages/core/src/renderer/frames/root-frame/init-root-frame.injectable.ts @@ -3,8 +3,7 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ import { getInjectable } from "@ogre-tools/injectable"; -import bindProtocolAddRouteHandlersInjectable from "../../protocol-handler/bind-protocol-add-route-handlers/bind-protocol-add-route-handlers.injectable"; -import lensProtocolRouterRendererInjectable from "../../protocol-handler/lens-protocol-router-renderer/lens-protocol-router-renderer.injectable"; +import lensProtocolRouterRendererInjectable from "../../protocol-handler/lens-protocol-router-renderer.injectable"; import registerIpcListenersInjectable from "../../ipc/register-ipc-listeners.injectable"; import loggerInjectable from "../../../common/logger.injectable"; import unmountRootComponentInjectable from "../../window/unmount-root-component.injectable"; @@ -13,7 +12,6 @@ const initRootFrameInjectable = getInjectable({ id: "init-root-frame", instantiate: (di) => { const registerIpcListeners = di.inject(registerIpcListenersInjectable); - const bindProtocolAddRouteHandlers = di.inject(bindProtocolAddRouteHandlersInjectable); const lensProtocolRouterRenderer = di.inject(lensProtocolRouterRendererInjectable); const logger = di.inject(loggerInjectable); const unmountRootComponent = di.inject(unmountRootComponentInjectable); @@ -21,7 +19,6 @@ const initRootFrameInjectable = getInjectable({ return async () => { lensProtocolRouterRenderer.init(); - bindProtocolAddRouteHandlers(); registerIpcListeners(); window.addEventListener("beforeunload", () => { diff --git a/packages/core/src/renderer/protocol-handler/bind-protocol-add-route-handlers/bind-protocol-add-route-handlers.injectable.ts b/packages/core/src/renderer/protocol-handler/bind-protocol-add-route-handlers/bind-protocol-add-route-handlers.injectable.ts deleted file mode 100644 index 1d378df375..0000000000 --- a/packages/core/src/renderer/protocol-handler/bind-protocol-add-route-handlers/bind-protocol-add-route-handlers.injectable.ts +++ /dev/null @@ -1,39 +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 attemptInstallByInfoInjectable from "../../components/+extensions/attempt-install-by-info.injectable"; -import { bindProtocolAddRouteHandlers } from "./bind-protocol-add-route-handlers"; -import lensProtocolRouterRendererInjectable from "../lens-protocol-router-renderer/lens-protocol-router-renderer.injectable"; -import navigateToCatalogInjectable from "../../../common/front-end-routing/routes/catalog/navigate-to-catalog.injectable"; -import navigateToAddClusterInjectable from "../../../common/front-end-routing/routes/add-cluster/navigate-to-add-cluster.injectable"; -import navigateToExtensionsInjectable from "../../../common/front-end-routing/routes/extensions/navigate-to-extensions.injectable"; -import navigateToEntitySettingsInjectable from "../../../common/front-end-routing/routes/entity-settings/navigate-to-entity-settings.injectable"; -import navigateToClusterViewInjectable from "../../../common/front-end-routing/routes/cluster-view/navigate-to-cluster-view.injectable"; -import catalogEntityRegistryInjectable from "../../api/catalog/entity/registry.injectable"; - -// TODO: Importing from features is not OK. Make protocol-router to comply with Open Closed Principle to allow moving implementation under a feature -import navigateToPreferencesInjectable from "../../../features/preferences/common/navigate-to-preferences.injectable"; -import getClusterByIdInjectable from "../../../common/cluster-store/get-by-id.injectable"; -import showShortInfoNotificationInjectable from "../../components/notifications/show-short-info.injectable"; - -const bindProtocolAddRouteHandlersInjectable = getInjectable({ - id: "bind-protocol-add-route-handlers", - - instantiate: (di) => bindProtocolAddRouteHandlers({ - attemptInstallByInfo: di.inject(attemptInstallByInfoInjectable), - lensProtocolRouterRenderer: di.inject(lensProtocolRouterRendererInjectable ), - navigateToCatalog: di.inject(navigateToCatalogInjectable), - navigateToAddCluster: di.inject(navigateToAddClusterInjectable), - navigateToExtensions: di.inject(navigateToExtensionsInjectable), - navigateToEntitySettings: di.inject(navigateToEntitySettingsInjectable), - navigateToClusterView: di.inject(navigateToClusterViewInjectable), - navigateToPreferences: di.inject(navigateToPreferencesInjectable), - entityRegistry: di.inject(catalogEntityRegistryInjectable), - getClusterById: di.inject(getClusterByIdInjectable), - showShortInfoNotification: di.inject(showShortInfoNotificationInjectable), - }), -}); - -export default bindProtocolAddRouteHandlersInjectable; diff --git a/packages/core/src/renderer/protocol-handler/bind-protocol-add-route-handlers/bind-protocol-add-route-handlers.tsx b/packages/core/src/renderer/protocol-handler/bind-protocol-add-route-handlers/bind-protocol-add-route-handlers.tsx deleted file mode 100644 index 4bcf207340..0000000000 --- a/packages/core/src/renderer/protocol-handler/bind-protocol-add-route-handlers/bind-protocol-add-route-handlers.tsx +++ /dev/null @@ -1,143 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ - -import React from "react"; -import type { LensProtocolRouterRenderer } from "../lens-protocol-router-renderer/lens-protocol-router-renderer"; -import type { CatalogEntityRegistry } from "../../api/catalog/entity/registry"; -import { - EXTENSION_NAME_MATCH, - EXTENSION_PUBLISHER_MATCH, - LensProtocolRouter, -} from "../../../common/protocol-handler"; -import type { ShowNotification } from "../../components/notifications"; -import type { NavigateToCatalog } from "../../../common/front-end-routing/routes/catalog/navigate-to-catalog.injectable"; -import type { NavigateToEntitySettings } from "../../../common/front-end-routing/routes/entity-settings/navigate-to-entity-settings.injectable"; -import type { NavigateToClusterView } from "../../../common/front-end-routing/routes/cluster-view/navigate-to-cluster-view.injectable"; -import assert from "assert"; -import type { AttemptInstallByInfo } from "../../components/+extensions/attempt-install-by-info.injectable"; -import type { GetClusterById } from "../../../common/cluster-store/get-by-id.injectable"; - -interface Dependencies { - attemptInstallByInfo: AttemptInstallByInfo; - lensProtocolRouterRenderer: LensProtocolRouterRenderer; - navigateToCatalog: NavigateToCatalog; - navigateToAddCluster: () => void; - navigateToExtensions: () => void; - navigateToEntitySettings: NavigateToEntitySettings; - navigateToClusterView: NavigateToClusterView; - navigateToPreferences: (tabId: string) => void; - entityRegistry: CatalogEntityRegistry; - getClusterById: GetClusterById; - showShortInfoNotification: ShowNotification; -} - -export const bindProtocolAddRouteHandlers = ({ - attemptInstallByInfo, - lensProtocolRouterRenderer, - navigateToCatalog, - navigateToAddCluster, - navigateToExtensions, - navigateToEntitySettings, - navigateToClusterView, - navigateToPreferences, - entityRegistry, - getClusterById, - showShortInfoNotification, -}: Dependencies) => () => { - lensProtocolRouterRenderer - .addInternalHandler("/preferences", ({ search: { highlight: tabId }}) => { - if (tabId) { - navigateToPreferences(tabId); - } - }) - .addInternalHandler("/", ({ tail }) => { - if (tail) { - showShortInfoNotification( -

- {"Unknown Action for "} - - lens://app/ - {tail} - - . Are you on the latest version? -

, - ); - } - - navigateToCatalog(); - }) - .addInternalHandler("/landing", () => { - navigateToCatalog(); - }) - .addInternalHandler("/landing/view/:group/:kind", ({ pathname: { group, kind }}) => { - navigateToCatalog({ group, kind }); - }) - .addInternalHandler("/cluster", () => { - navigateToAddCluster(); - }) - .addInternalHandler("/entity/:entityId/settings", ({ pathname: { entityId }}) => { - assert(entityId); - const entity = entityRegistry.getById(entityId); - - if (entity) { - navigateToEntitySettings(entityId); - } else { - showShortInfoNotification( -

- {"Unknown catalog entity "} - {entityId} - . -

, - ); - } - }) - // Handlers below are deprecated and only kept for backward compact purposes - .addInternalHandler("/cluster/:clusterId", ({ pathname: { clusterId }}) => { - assert(clusterId); - const cluster = getClusterById(clusterId); - - if (cluster) { - navigateToClusterView(clusterId); - } else { - showShortInfoNotification( -

- {"Unknown catalog entity "} - {clusterId} - . -

, - ); - } - }) - .addInternalHandler("/cluster/:clusterId/settings", ({ pathname: { clusterId }}) => { - assert(clusterId); - const cluster = getClusterById(clusterId); - - if (cluster) { - navigateToEntitySettings(clusterId); - } else { - showShortInfoNotification( -

- {"Unknown catalog entity "} - {clusterId} - . -

, - ); - } - }) - .addInternalHandler("/extensions", () => { - navigateToExtensions(); - }) - .addInternalHandler(`/extensions/install${LensProtocolRouter.ExtensionUrlSchema}`, ({ pathname, search: { version }}) => { - const name = [ - pathname[EXTENSION_PUBLISHER_MATCH], - pathname[EXTENSION_NAME_MATCH], - ] - .filter(Boolean) - .join("/"); - - navigateToExtensions(); - attemptInstallByInfo({ name, version, requireConfirmation: true }); - }); -}; diff --git a/packages/core/src/renderer/protocol-handler/index.ts b/packages/core/src/renderer/protocol-handler/index.ts deleted file mode 100644 index c338f50114..0000000000 --- a/packages/core/src/renderer/protocol-handler/index.ts +++ /dev/null @@ -1,7 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ - -export { LensProtocolRouterRenderer } from "./lens-protocol-router-renderer/lens-protocol-router-renderer"; -export { bindProtocolAddRouteHandlers } from "./bind-protocol-add-route-handlers/bind-protocol-add-route-handlers"; diff --git a/packages/core/src/renderer/protocol-handler/lens-protocol-router-renderer/lens-protocol-router-renderer.injectable.ts b/packages/core/src/renderer/protocol-handler/lens-protocol-router-renderer.injectable.ts similarity index 50% rename from packages/core/src/renderer/protocol-handler/lens-protocol-router-renderer/lens-protocol-router-renderer.injectable.ts rename to packages/core/src/renderer/protocol-handler/lens-protocol-router-renderer.injectable.ts index 5126f210c0..3a3f283de5 100644 --- a/packages/core/src/renderer/protocol-handler/lens-protocol-router-renderer/lens-protocol-router-renderer.injectable.ts +++ b/packages/core/src/renderer/protocol-handler/lens-protocol-router-renderer.injectable.ts @@ -4,21 +4,23 @@ */ import { getInjectable } from "@ogre-tools/injectable"; import { LensProtocolRouterRenderer } from "./lens-protocol-router-renderer"; -import extensionsStoreInjectable from "../../../extensions/extensions-store/extensions-store.injectable"; -import loggerInjectable from "../../../common/logger.injectable"; -import showErrorNotificationInjectable from "../../components/notifications/show-error-notification.injectable"; -import showShortInfoNotificationInjectable from "../../components/notifications/show-short-info.injectable"; -import findExtensionInstanceByNameInjectable from "../../../features/extensions/loader/common/find-instance-by-name.injectable"; +import extensionsStoreInjectable from "../../extensions/extensions-store/extensions-store.injectable"; +import showErrorNotificationInjectable from "../components/notifications/show-error-notification.injectable"; +import showShortInfoNotificationInjectable from "../components/notifications/show-short-info.injectable"; +import findExtensionInstanceByNameInjectable from "../../features/extensions/loader/common/find-instance-by-name.injectable"; +import internalDeepLinkingRoutesInjectable from "../../features/deep-linking/renderer/internal-deep-linking-routes.injectable"; +import protocolHandlerLoggerInjectable from "../../common/protocol-handler/logger.injectable"; const lensProtocolRouterRendererInjectable = getInjectable({ id: "lens-protocol-router-renderer", instantiate: (di) => new LensProtocolRouterRenderer({ extensionsStore: di.inject(extensionsStoreInjectable), - logger: di.inject(loggerInjectable), + logger: di.inject(protocolHandlerLoggerInjectable), showErrorNotification: di.inject(showErrorNotificationInjectable), showShortInfoNotification: di.inject(showShortInfoNotificationInjectable), findExtensionInstanceByName: di.inject(findExtensionInstanceByNameInjectable), + internalRoutes: di.inject(internalDeepLinkingRoutesInjectable), }), }); diff --git a/packages/core/src/renderer/protocol-handler/lens-protocol-router-renderer/lens-protocol-router-renderer.tsx b/packages/core/src/renderer/protocol-handler/lens-protocol-router-renderer.tsx similarity index 90% rename from packages/core/src/renderer/protocol-handler/lens-protocol-router-renderer/lens-protocol-router-renderer.tsx rename to packages/core/src/renderer/protocol-handler/lens-protocol-router-renderer.tsx index 3c9959aa87..66561788a1 100644 --- a/packages/core/src/renderer/protocol-handler/lens-protocol-router-renderer/lens-protocol-router-renderer.tsx +++ b/packages/core/src/renderer/protocol-handler/lens-protocol-router-renderer.tsx @@ -5,11 +5,11 @@ import React from "react"; import { ipcRenderer } from "electron"; -import * as proto from "../../../common/protocol-handler"; +import * as proto from "../../common/protocol-handler"; import Url from "url-parse"; -import type { LensProtocolRouterDependencies } from "../../../common/protocol-handler"; -import { foldAttemptResults, ProtocolHandlerInvalid, RouteAttempt } from "../../../common/protocol-handler"; -import type { ShowNotification } from "../../components/notifications"; +import type { LensProtocolRouterDependencies } from "../../common/protocol-handler"; +import { foldAttemptResults, ProtocolHandlerInvalid, RouteAttempt } from "../../common/protocol-handler"; +import type { ShowNotification } from "../components/notifications"; interface Dependencies extends LensProtocolRouterDependencies { showShortInfoNotification: ShowNotification;