mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
Add notification in renderer if lens protocol handler fails to find any routes (#2787)
- Add notifications on missing lens:// handlers, and invalid URIs - add notifications on unknown entity IDs Signed-off-by: Sebastian Malton <sebastian@malton.name>
This commit is contained in:
1 parent
36e8888ecb
commit
5fd2d5501c
8 files changed
+273
-130
No files matched your search
@@ -37,7 +37,7 @@ export class Notifications extends React.Component {
|
||||
static ok(message: NotificationMessage) {
|
||||
notificationsStore.add({
|
||||
message,
|
||||
timeout: 2500,
|
||||
timeout: 2_500,
|
||||
status: NotificationStatus.OK
|
||||
});
|
||||
}
|
||||
@@ -45,12 +45,19 @@ export class Notifications extends React.Component {
|
||||
static error(message: NotificationMessage, customOpts: Partial<Notification> = {}) {
|
||||
notificationsStore.add({
|
||||
message,
|
||||
timeout: 10000,
|
||||
timeout: 10_000,
|
||||
status: NotificationStatus.ERROR,
|
||||
...customOpts
|
||||
});
|
||||
}
|
||||
|
||||
static shortInfo(message: NotificationMessage, customOpts: Partial<Notification> = {}) {
|
||||
this.info(message, {
|
||||
timeout: 5_000,
|
||||
...customOpts
|
||||
});
|
||||
}
|
||||
|
||||
static info(message: NotificationMessage, customOpts: Partial<Notification> = {}) {
|
||||
return notificationsStore.add({
|
||||
status: NotificationStatus.INFO,
|
||||
|
||||
+27
-4
@@ -19,6 +19,7 @@
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
import React from "react";
|
||||
import { addClusterURL } from "../components/+add-cluster";
|
||||
import { catalogURL } from "../components/+catalog";
|
||||
import { attemptInstallByInfo, extensionsURL } from "../components/+extensions";
|
||||
@@ -30,6 +31,7 @@ import { entitySettingsURL } from "../components/+entity-settings";
|
||||
import { catalogEntityRegistry } from "../api/catalog-entity-registry";
|
||||
import { ClusterStore } from "../../common/cluster-store";
|
||||
import { EXTENSION_NAME_MATCH, EXTENSION_PUBLISHER_MATCH, LensProtocolRouter } from "../../common/protocol-handler";
|
||||
import { Notifications } from "../components/notifications";
|
||||
|
||||
export function bindProtocolAddRouteHandlers() {
|
||||
LensProtocolRouterRenderer
|
||||
@@ -37,7 +39,16 @@ export function bindProtocolAddRouteHandlers() {
|
||||
.addInternalHandler("/preferences", ({ search: { highlight }}) => {
|
||||
navigate(preferencesURL({ fragment: highlight }));
|
||||
})
|
||||
.addInternalHandler("/", () => {
|
||||
.addInternalHandler("/", ({ tail }) => {
|
||||
if (tail) {
|
||||
Notifications.shortInfo(
|
||||
<p>
|
||||
Unknown Action for <code>lens://app/{tail}</code>.{" "}
|
||||
Are you on the latest version?
|
||||
</p>
|
||||
);
|
||||
}
|
||||
|
||||
navigate(catalogURL());
|
||||
})
|
||||
.addInternalHandler("/landing", () => {
|
||||
@@ -59,7 +70,11 @@ export function bindProtocolAddRouteHandlers() {
|
||||
if (entity) {
|
||||
navigate(entitySettingsURL({ params: { entityId } }));
|
||||
} else {
|
||||
console.log("[APP-HANDLER]: catalog entity with given ID does not exist", { entityId });
|
||||
Notifications.shortInfo(
|
||||
<p>
|
||||
Unknown catalog entity <code>{entityId}</code>.
|
||||
</p>
|
||||
);
|
||||
}
|
||||
})
|
||||
// Handlers below are deprecated and only kept for backward compact purposes
|
||||
@@ -69,7 +84,11 @@ export function bindProtocolAddRouteHandlers() {
|
||||
if (cluster) {
|
||||
navigate(clusterViewURL({ params: { clusterId } }));
|
||||
} else {
|
||||
console.log("[APP-HANDLER]: cluster with given ID does not exist", { clusterId });
|
||||
Notifications.shortInfo(
|
||||
<p>
|
||||
Unknown catalog entity <code>{clusterId}</code>.
|
||||
</p>
|
||||
);
|
||||
}
|
||||
})
|
||||
.addInternalHandler("/cluster/:clusterId/settings", ({ pathname: { clusterId } }) => {
|
||||
@@ -78,7 +97,11 @@ export function bindProtocolAddRouteHandlers() {
|
||||
if (cluster) {
|
||||
navigate(entitySettingsURL({ params: { entityId: clusterId } }));
|
||||
} else {
|
||||
console.log("[APP-HANDLER]: cluster with given ID does not exist", { clusterId });
|
||||
Notifications.shortInfo(
|
||||
<p>
|
||||
Unknown catalog entity <code>{clusterId}</code>.
|
||||
</p>
|
||||
);
|
||||
}
|
||||
})
|
||||
.addInternalHandler("/extensions", () => {
|
||||
@@ -1,61 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2021 OpenLens Authors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
import { ipcRenderer } from "electron";
|
||||
import * as proto from "../../common/protocol-handler";
|
||||
import logger from "../../main/logger";
|
||||
import Url from "url-parse";
|
||||
import { boundMethod } from "../utils";
|
||||
|
||||
export class LensProtocolRouterRenderer extends proto.LensProtocolRouter {
|
||||
/**
|
||||
* This function is needed to be called early on in the renderers lifetime.
|
||||
*/
|
||||
public init(): void {
|
||||
ipcRenderer
|
||||
.on(proto.ProtocolHandlerInternal, this.ipcInternalHandler)
|
||||
.on(proto.ProtocolHandlerExtension, this.ipcExtensionHandler);
|
||||
}
|
||||
|
||||
@boundMethod
|
||||
private ipcInternalHandler(event: Electron.IpcRendererEvent, ...args: any[]): void {
|
||||
if (args.length !== 1) {
|
||||
return void logger.warn(`${proto.LensProtocolRouter.LoggingPrefix}: unexpected number of args`, { args });
|
||||
}
|
||||
|
||||
const [rawUrl] = args;
|
||||
const url = new Url(rawUrl, true);
|
||||
|
||||
this._routeToInternal(url);
|
||||
}
|
||||
|
||||
@boundMethod
|
||||
private ipcExtensionHandler(event: Electron.IpcRendererEvent, ...args: any[]): void {
|
||||
if (args.length !== 1) {
|
||||
return void logger.warn(`${proto.LensProtocolRouter.LoggingPrefix}: unexpected number of args`, { args });
|
||||
}
|
||||
|
||||
const [rawUrl] = args;
|
||||
const url = new Url(rawUrl, true);
|
||||
|
||||
this._routeToExtension(url);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,119 @@
|
||||
/**
|
||||
* Copyright (c) 2021 OpenLens Authors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
import React from "react";
|
||||
import { ipcRenderer } from "electron";
|
||||
import * as proto from "../../common/protocol-handler";
|
||||
import Url from "url-parse";
|
||||
import { onCorrect } from "../../common/ipc";
|
||||
import { foldAttemptResults, ProtocolHandlerInvalid, RouteAttempt } from "../../common/protocol-handler";
|
||||
import { Notifications } from "../components/notifications";
|
||||
|
||||
function verifyIpcArgs(args: unknown[]): args is [string, RouteAttempt] {
|
||||
if (args.length !== 2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (typeof args[0] !== "string") {
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (args[1]) {
|
||||
case RouteAttempt.MATCHED:
|
||||
case RouteAttempt.MISSING:
|
||||
case RouteAttempt.MISSING_EXTENSION:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
export class LensProtocolRouterRenderer extends proto.LensProtocolRouter {
|
||||
/**
|
||||
* This function is needed to be called early on in the renderers lifetime.
|
||||
*/
|
||||
public init(): void {
|
||||
onCorrect({
|
||||
channel: proto.ProtocolHandlerInternal,
|
||||
source: ipcRenderer,
|
||||
verifier: verifyIpcArgs,
|
||||
listener: (event, rawUrl, mainAttemptResult) => {
|
||||
const rendererAttempt = this._routeToInternal(new Url(rawUrl, true));
|
||||
|
||||
if (foldAttemptResults(mainAttemptResult, rendererAttempt) === RouteAttempt.MISSING) {
|
||||
Notifications.shortInfo(
|
||||
<p>
|
||||
Unknown action <code>{rawUrl}</code>.{" "}
|
||||
Are you on the latest version?
|
||||
</p>
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
onCorrect({
|
||||
channel: proto.ProtocolHandlerExtension,
|
||||
source: ipcRenderer,
|
||||
verifier: verifyIpcArgs,
|
||||
listener: async (event, rawUrl, mainAttemptResult) => {
|
||||
const rendererAttempt = await this._routeToExtension(new Url(rawUrl, true));
|
||||
|
||||
switch (foldAttemptResults(mainAttemptResult, rendererAttempt)) {
|
||||
case RouteAttempt.MISSING:
|
||||
Notifications.shortInfo(
|
||||
<p>
|
||||
Unknown action <code>{rawUrl}</code>.{" "}
|
||||
Are you on the latest version of the extension?
|
||||
</p>
|
||||
);
|
||||
break;
|
||||
case RouteAttempt.MISSING_EXTENSION:
|
||||
Notifications.shortInfo(
|
||||
<p>
|
||||
Missing extension for action <code>{rawUrl}</code>.{" "}
|
||||
Not able to find extension in our known list.{" "}
|
||||
Try installing it manually.
|
||||
</p>
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
onCorrect({
|
||||
channel: ProtocolHandlerInvalid,
|
||||
source: ipcRenderer,
|
||||
listener: (event, error, rawUrl) => {
|
||||
Notifications.error((
|
||||
<>
|
||||
<p>
|
||||
Failed to route <code>{rawUrl}</code>.
|
||||
</p>
|
||||
<p>
|
||||
<b>Error:</b> {error}
|
||||
</p>
|
||||
</>
|
||||
));
|
||||
},
|
||||
verifier: (args): args is [string, string] => {
|
||||
return args.length === 2 && typeof args[0] === "string";
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user