1
0
mirror of https://github.com/lensapp/lens.git synced 2025-05-20 05:10:56 +00:00

Convert internal deep linking handlers to be open/closed

Signed-off-by: Sebastian Malton <sebastian@malton.name>
This commit is contained in:
Sebastian Malton 2023-02-17 15:48:12 -05:00
parent b0ff941314
commit db9472de36
22 changed files with 409 additions and 244 deletions

View File

@ -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;

View File

@ -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<string, RouteHandler>;
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<string, RouteHandler>();
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<Record<string, string | undefined>>): 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<ExtensionUrlMatch>(url.pathname, LensProtocolRouter.ExtensionUrlSchema);
const match = matchPath<ExtensionUrlMatch>(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);
}
}

View File

@ -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<InternalRouteRegistration>({
id: "internal-protocol-route-token",
});

View File

@ -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;

View File

@ -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(
<p>
{"Unknown catalog entity "}
<code>{clusterId}</code>
.
</p>,
);
}
},
};
},
injectionToken: internalDeepLinkingRouteInjectionToken,
});
export default deprecatedViewClusterDeepLinkingHandlerInjectable;

View File

@ -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(
<p>
{"Unknown catalog entity "}
<code>{clusterId}</code>
.
</p>,
);
}
},
};
},
injectionToken: internalDeepLinkingRouteInjectionToken,
});
export default depcratedViewClusterSettingsDeepLinkingHandlerInjectable;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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(
<p>
{"Unknown Action for "}
<code>
lens://app/
{tail}
</code>
. Are you on the latest version?
</p>,
);
}
navigateToCatalog();
},
};
},
injectionToken: internalDeepLinkingRouteInjectionToken,
});
export default unknownDeepLinkingActionHandlerInjectable;

View File

@ -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(
<p>
{"Unknown catalog entity "}
<code>{entityId}</code>
.
</p>,
);
}
},
};
},
injectionToken: internalDeepLinkingRouteInjectionToken,
});
export default viewEntitySettingsDeepLinkingHandlerInjectable;

View File

@ -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;

View File

@ -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),
}),
});

View File

@ -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 });
}
}
}

View File

@ -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", () => {

View File

@ -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;

View File

@ -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(
<p>
{"Unknown Action for "}
<code>
lens://app/
{tail}
</code>
. Are you on the latest version?
</p>,
);
}
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(
<p>
{"Unknown catalog entity "}
<code>{entityId}</code>
.
</p>,
);
}
})
// 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(
<p>
{"Unknown catalog entity "}
<code>{clusterId}</code>
.
</p>,
);
}
})
.addInternalHandler("/cluster/:clusterId/settings", ({ pathname: { clusterId }}) => {
assert(clusterId);
const cluster = getClusterById(clusterId);
if (cluster) {
navigateToEntitySettings(clusterId);
} else {
showShortInfoNotification(
<p>
{"Unknown catalog entity "}
<code>{clusterId}</code>
.
</p>,
);
}
})
.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 });
});
};

View File

@ -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";

View File

@ -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),
}),
});

View File

@ -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;