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

Remove usage of deprecated xtermjs's registerLinkMatcher API (#5996)

* Make openBrowser->openLinkInBrowser injectable

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* Remove use of deprecated link matcher API from XtermJS

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* Fix type errors

Signed-off-by: Sebastian Malton <sebastian@malton.name>
This commit is contained in:
Sebastian Malton 2022-08-09 19:25:11 -07:00 committed by GitHub
parent 5c11d7f7fe
commit 09f2919946
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 144 additions and 77 deletions

View File

@ -282,7 +282,8 @@
"winston": "^3.8.1", "winston": "^3.8.1",
"winston-console-format": "^1.0.8", "winston-console-format": "^1.0.8",
"winston-transport-browserconsole": "^1.0.5", "winston-transport-browserconsole": "^1.0.5",
"ws": "^8.8.1" "ws": "^8.8.1",
"xterm-link-provider": "^1.3.1"
}, },
"devDependencies": { "devDependencies": {
"@async-fn/jest": "1.6.4", "@async-fn/jest": "1.6.4",

View File

@ -22,7 +22,6 @@ export * from "./hash-set";
export * from "./n-fircate"; export * from "./n-fircate";
export * from "./noop"; export * from "./noop";
export * from "./observable-crate/impl"; export * from "./observable-crate/impl";
export * from "./openBrowser";
export * from "./paths"; export * from "./paths";
export * from "./promise-exec"; export * from "./promise-exec";
export * from "./readonly"; export * from "./readonly";

View File

@ -0,0 +1,9 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { getGlobalOverride } from "../test-utils/get-global-override";
import openLinkInBrowserInjectable from "./open-link-in-browser.injectable";
export default getGlobalOverride(openLinkInBrowserInjectable, () => async () => {});

View File

@ -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 { shell } from "electron";
const allowedProtocols = new Set(["http:", "https:"]);
export type OpenLinkInBrowser = (url: string) => Promise<void>;
const openLinkInBrowserInjectable = getInjectable({
id: "open-link-in-browser",
instantiate: (): OpenLinkInBrowser => (
async (url) => {
const { protocol } = new URL(url);
if (!allowedProtocols.has(protocol)) {
throw new TypeError("not an http(s) URL");
}
await shell.openExternal(url);
}
),
causesSideEffects: true,
});
export default openLinkInBrowserInjectable;

View File

@ -1,29 +0,0 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { shell } from "electron";
const allowedProtocols = new Set(["http:", "https:"]);
/**
* Opens a link using the program configured as the default browser
* on the target platform. Will reject URLs with a scheme other than
* http or https to prevent programs other than the default browser
* running.
*
* @param url The URL to open
*/
export function openBrowser(url: string): Promise<void> {
if (allowedProtocols.has(new URL(url).protocol)) {
return shell.openExternal(url);
}
return Promise.reject(new TypeError("not an http(s) URL"));
}
/**
* @deprecated use openBrowser
*/
export const openExternal = openBrowser;

View File

@ -3,6 +3,15 @@
* Licensed under MIT License. See LICENSE in root directory for more information. * Licensed under MIT License. See LICENSE in root directory for more information.
*/ */
export { Singleton, openExternal, openBrowser, getAppVersion } from "../../common/utils"; import openLinkInBrowserInjectable from "../../common/utils/open-link-in-browser.injectable";
import { asLegacyGlobalFunctionForExtensionApi } from "../as-legacy-globals-for-extension-api/as-legacy-global-function-for-extension-api";
export { Singleton, getAppVersion } from "../../common/utils";
export { prevDefault, stopPropagation } from "../../renderer/utils/prevDefault"; export { prevDefault, stopPropagation } from "../../renderer/utils/prevDefault";
export { cssNames } from "../../renderer/utils/cssNames"; export { cssNames } from "../../renderer/utils/cssNames";
/**
* @deprecated Use {@link openBrowser} instead
*/
export const openExternal = asLegacyGlobalFunctionForExtensionApi(openLinkInBrowserInjectable);
export const openBrowser = asLegacyGlobalFunctionForExtensionApi(openLinkInBrowserInjectable);

View File

@ -5,7 +5,6 @@
import { getInjectable } from "@ogre-tools/injectable"; import { getInjectable } from "@ogre-tools/injectable";
import { docsUrl, productName, supportUrl } from "../../common/vars"; import { docsUrl, productName, supportUrl } from "../../common/vars";
import { broadcastMessage } from "../../common/ipc"; import { broadcastMessage } from "../../common/ipc";
import { openBrowser } from "../../common/utils";
import type { MenuItemConstructorOptions } from "electron"; import type { MenuItemConstructorOptions } from "electron";
import { webContents } from "electron"; import { webContents } from "electron";
import loggerInjectable from "../../common/logger.injectable"; import loggerInjectable from "../../common/logger.injectable";
@ -25,6 +24,7 @@ import applicationWindowInjectable from "../start-main-application/lens-window/a
import reloadWindowInjectable from "../start-main-application/lens-window/reload-window.injectable"; import reloadWindowInjectable from "../start-main-application/lens-window/reload-window.injectable";
import showApplicationWindowInjectable from "../start-main-application/lens-window/show-application-window.injectable"; import showApplicationWindowInjectable from "../start-main-application/lens-window/show-application-window.injectable";
import processCheckingForUpdatesInjectable from "../application-update/check-for-updates/process-checking-for-updates.injectable"; import processCheckingForUpdatesInjectable from "../application-update/check-for-updates/process-checking-for-updates.injectable";
import openLinkInBrowserInjectable from "../../common/utils/open-link-in-browser.injectable";
function ignoreIf(check: boolean, menuItems: MenuItemOpts[]) { function ignoreIf(check: boolean, menuItems: MenuItemOpts[]) {
return check ? [] : menuItems; return check ? [] : menuItems;
@ -54,6 +54,7 @@ const applicationMenuItemsInjectable = getInjectable({
const navigateToAddCluster = di.inject(navigateToAddClusterInjectable); const navigateToAddCluster = di.inject(navigateToAddClusterInjectable);
const stopServicesAndExitApp = di.inject(stopServicesAndExitAppInjectable); const stopServicesAndExitApp = di.inject(stopServicesAndExitAppInjectable);
const processCheckingForUpdates = di.inject(processCheckingForUpdatesInjectable); const processCheckingForUpdates = di.inject(processCheckingForUpdatesInjectable);
const openLinkInBrowser = di.inject(openLinkInBrowserInjectable);
logger.info(`[MENU]: autoUpdateEnabled=${updatingIsEnabled}`); logger.info(`[MENU]: autoUpdateEnabled=${updatingIsEnabled}`);
@ -260,7 +261,7 @@ const applicationMenuItemsInjectable = getInjectable({
label: "Documentation", label: "Documentation",
id: "documentation", id: "documentation",
click: async () => { click: async () => {
openBrowser(docsUrl).catch((error) => { openLinkInBrowser(docsUrl).catch((error) => {
logger.error("[MENU]: failed to open browser", { error }); logger.error("[MENU]: failed to open browser", { error });
}); });
}, },
@ -269,7 +270,7 @@ const applicationMenuItemsInjectable = getInjectable({
label: "Support", label: "Support",
id: "support", id: "support",
click: async () => { click: async () => {
openBrowser(supportUrl).catch((error) => { openLinkInBrowser(supportUrl).catch((error) => {
logger.error("[MENU]: failed to open browser", { error }); logger.error("[MENU]: failed to open browser", { error });
}); });
}, },

View File

@ -6,10 +6,10 @@ import { getInjectable } from "@ogre-tools/injectable";
import loggerInjectable from "../../../../common/logger.injectable"; import loggerInjectable from "../../../../common/logger.injectable";
import applicationWindowStateInjectable from "./application-window-state.injectable"; import applicationWindowStateInjectable from "./application-window-state.injectable";
import { BrowserWindow } from "electron"; import { BrowserWindow } from "electron";
import { openBrowser } from "../../../../common/utils";
import sendToChannelInElectronBrowserWindowInjectable from "./send-to-channel-in-electron-browser-window.injectable"; import sendToChannelInElectronBrowserWindowInjectable from "./send-to-channel-in-electron-browser-window.injectable";
import type { ElectronWindow } from "./create-lens-window.injectable"; import type { ElectronWindow } from "./create-lens-window.injectable";
import type { RequireExactlyOne } from "type-fest"; import type { RequireExactlyOne } from "type-fest";
import openLinkInBrowserInjectable from "../../../../common/utils/open-link-in-browser.injectable";
export type ElectronWindowTitleBarStyle = "hiddenInset" | "hidden" | "default" | "customButtonsOnHover"; export type ElectronWindowTitleBarStyle = "hiddenInset" | "hidden" | "default" | "customButtonsOnHover";
@ -46,6 +46,7 @@ const createElectronWindowInjectable = getInjectable({
instantiate: (di): CreateElectronWindow => { instantiate: (di): CreateElectronWindow => {
const logger = di.inject(loggerInjectable); const logger = di.inject(loggerInjectable);
const sendToChannelInLensWindow = di.inject(sendToChannelInElectronBrowserWindowInjectable); const sendToChannelInLensWindow = di.inject(sendToChannelInElectronBrowserWindowInjectable);
const openLinkInBrowser = di.inject(openLinkInBrowserInjectable);
return (configuration) => { return (configuration) => {
const applicationWindowState = di.inject( const applicationWindowState = di.inject(
@ -158,7 +159,7 @@ const createElectronWindowInjectable = getInjectable({
}) })
.setWindowOpenHandler((details) => { .setWindowOpenHandler((details) => {
openBrowser(details.url).catch((error) => { openLinkInBrowser(details.url).catch((error) => {
logger.error("[CREATE-ELECTRON-WINDOW]: failed to open browser", { logger.error("[CREATE-ELECTRON-WINDOW]: failed to open browser", {
error, error,
}); });

View File

@ -6,7 +6,6 @@
import React from "react"; import React from "react";
import { autoBind, cssNames } from "../../utils"; import { autoBind, cssNames } from "../../utils";
import type { PortForwardItem, PortForwardStore } from "../../port-forward"; import type { PortForwardItem, PortForwardStore } from "../../port-forward";
import { openPortForward } from "../../port-forward";
import type { MenuActionsProps } from "../menu/menu-actions"; import type { MenuActionsProps } from "../menu/menu-actions";
import { MenuActions } from "../menu/menu-actions"; import { MenuActions } from "../menu/menu-actions";
import { MenuItem } from "../menu"; import { MenuItem } from "../menu";
@ -15,6 +14,8 @@ import { Notifications } from "../notifications";
import { withInjectables } from "@ogre-tools/injectable-react"; import { withInjectables } from "@ogre-tools/injectable-react";
import portForwardDialogModelInjectable from "../../port-forward/port-forward-dialog-model/port-forward-dialog-model.injectable"; import portForwardDialogModelInjectable from "../../port-forward/port-forward-dialog-model/port-forward-dialog-model.injectable";
import portForwardStoreInjectable from "../../port-forward/port-forward-store/port-forward-store.injectable"; import portForwardStoreInjectable from "../../port-forward/port-forward-store/port-forward-store.injectable";
import type { OpenPortForward } from "../../port-forward/open-port-forward.injectable";
import openPortForwardInjectable from "../../port-forward/open-port-forward.injectable";
export interface PortForwardMenuProps extends MenuActionsProps { export interface PortForwardMenuProps extends MenuActionsProps {
portForward: PortForwardItem; portForward: PortForwardItem;
@ -24,6 +25,7 @@ export interface PortForwardMenuProps extends MenuActionsProps {
interface Dependencies { interface Dependencies {
portForwardStore: PortForwardStore; portForwardStore: PortForwardStore;
openPortForwardDialog: (item: PortForwardItem) => void; openPortForwardDialog: (item: PortForwardItem) => void;
openPortForward: OpenPortForward;
} }
class NonInjectedPortForwardMenu<Props extends PortForwardMenuProps & Dependencies> extends React.Component<Props> { class NonInjectedPortForwardMenu<Props extends PortForwardMenuProps & Dependencies> extends React.Component<Props> {
@ -94,7 +96,7 @@ class NonInjectedPortForwardMenu<Props extends PortForwardMenuProps & Dependenci
return ( return (
<> <>
{ portForward.status === "Active" && ( { portForward.status === "Active" && (
<MenuItem onClick={() => openPortForward(portForward)}> <MenuItem onClick={() => this.props.openPortForward(portForward)}>
<Icon <Icon
material="open_in_browser" material="open_in_browser"
interactive={toolbar} interactive={toolbar}
@ -139,6 +141,7 @@ export const PortForwardMenu = withInjectables<Dependencies, PortForwardMenuProp
getProps: (di, props) => ({ getProps: (di, props) => ({
portForwardStore: di.inject(portForwardStoreInjectable), portForwardStore: di.inject(portForwardStoreInjectable),
openPortForwardDialog: di.inject(portForwardDialogModelInjectable).open, openPortForwardDialog: di.inject(portForwardDialogModelInjectable).open,
openPortForward: di.inject(openPortForwardInjectable),
...props, ...props,
}), }),
}, },

View File

@ -13,7 +13,7 @@ import { cssNames } from "../../utils";
import { Notifications } from "../notifications"; import { Notifications } from "../notifications";
import { Button } from "../button"; import { Button } from "../button";
import type { ForwardedPort, PortForwardStore } from "../../port-forward"; import type { ForwardedPort, PortForwardStore } from "../../port-forward";
import { openPortForward, predictProtocol } from "../../port-forward"; import { predictProtocol } from "../../port-forward";
import { Spinner } from "../spinner"; import { Spinner } from "../spinner";
import { withInjectables } from "@ogre-tools/injectable-react"; import { withInjectables } from "@ogre-tools/injectable-react";
import portForwardStoreInjectable from "../../port-forward/port-forward-store/port-forward-store.injectable"; import portForwardStoreInjectable from "../../port-forward/port-forward-store/port-forward-store.injectable";
@ -21,6 +21,8 @@ import portForwardDialogModelInjectable from "../../port-forward/port-forward-di
import logger from "../../../common/logger"; import logger from "../../../common/logger";
import aboutPortForwardingInjectable from "../../port-forward/about-port-forwarding.injectable"; import aboutPortForwardingInjectable from "../../port-forward/about-port-forwarding.injectable";
import notifyErrorPortForwardingInjectable from "../../port-forward/notify-error-port-forwarding.injectable"; import notifyErrorPortForwardingInjectable from "../../port-forward/notify-error-port-forwarding.injectable";
import type { OpenPortForward } from "../../port-forward/open-port-forward.injectable";
import openPortForwardInjectable from "../../port-forward/open-port-forward.injectable";
export interface ServicePortComponentProps { export interface ServicePortComponentProps {
service: Service; service: Service;
@ -32,6 +34,7 @@ interface Dependencies {
openPortForwardDialog: (item: ForwardedPort, options: { openInBrowser: boolean; onClose: () => void }) => void; openPortForwardDialog: (item: ForwardedPort, options: { openInBrowser: boolean; onClose: () => void }) => void;
aboutPortForwarding: () => void; aboutPortForwarding: () => void;
notifyErrorPortForwarding: (message: string) => void; notifyErrorPortForwarding: (message: string) => void;
openPortForward: OpenPortForward;
} }
@observer @observer
@ -88,7 +91,7 @@ class NonInjectedServicePortComponent extends React.Component<ServicePortCompone
@action @action
async portForward() { async portForward() {
const { service, port } = this.props; const { service, port, openPortForward } = this.props;
let portForward: ForwardedPort = { let portForward: ForwardedPort = {
kind: "service", kind: "service",
name: service.getName(), name: service.getName(),
@ -202,6 +205,7 @@ export const ServicePortComponent = withInjectables<Dependencies, ServicePortCom
openPortForwardDialog: di.inject(portForwardDialogModelInjectable).open, openPortForwardDialog: di.inject(portForwardDialogModelInjectable).open,
aboutPortForwarding: di.inject(aboutPortForwardingInjectable), aboutPortForwarding: di.inject(aboutPortForwardingInjectable),
notifyErrorPortForwarding: di.inject(notifyErrorPortForwardingInjectable), notifyErrorPortForwarding: di.inject(notifyErrorPortForwardingInjectable),
openPortForward: di.inject(openPortForwardInjectable),
...props, ...props,
}), }),
}, },

View File

@ -13,7 +13,7 @@ import { cssNames } from "../../utils";
import { Notifications } from "../notifications"; import { Notifications } from "../notifications";
import { Button } from "../button"; import { Button } from "../button";
import type { ForwardedPort, PortForwardStore } from "../../port-forward"; import type { ForwardedPort, PortForwardStore } from "../../port-forward";
import { openPortForward, predictProtocol } from "../../port-forward"; import { predictProtocol } from "../../port-forward";
import { Spinner } from "../spinner"; import { Spinner } from "../spinner";
import { withInjectables } from "@ogre-tools/injectable-react"; import { withInjectables } from "@ogre-tools/injectable-react";
import portForwardStoreInjectable from "../../port-forward/port-forward-store/port-forward-store.injectable"; import portForwardStoreInjectable from "../../port-forward/port-forward-store/port-forward-store.injectable";
@ -21,6 +21,8 @@ import portForwardDialogModelInjectable from "../../port-forward/port-forward-di
import logger from "../../../common/logger"; import logger from "../../../common/logger";
import aboutPortForwardingInjectable from "../../port-forward/about-port-forwarding.injectable"; import aboutPortForwardingInjectable from "../../port-forward/about-port-forwarding.injectable";
import notifyErrorPortForwardingInjectable from "../../port-forward/notify-error-port-forwarding.injectable"; import notifyErrorPortForwardingInjectable from "../../port-forward/notify-error-port-forwarding.injectable";
import type { OpenPortForward } from "../../port-forward/open-port-forward.injectable";
import openPortForwardInjectable from "../../port-forward/open-port-forward.injectable";
export interface PodContainerPortProps { export interface PodContainerPortProps {
pod: Pod; pod: Pod;
@ -32,6 +34,7 @@ interface Dependencies {
openPortForwardDialog: (item: ForwardedPort, options: { openInBrowser: boolean; onClose: () => void }) => void; openPortForwardDialog: (item: ForwardedPort, options: { openInBrowser: boolean; onClose: () => void }) => void;
aboutPortForwarding: () => void; aboutPortForwarding: () => void;
notifyErrorPortForwarding: (message: string) => void; notifyErrorPortForwarding: (message: string) => void;
openPortForward: OpenPortForward;
} }
@observer @observer
@ -86,7 +89,7 @@ class NonInjectedPodContainerPort extends React.Component<PodContainerPortProps
@action @action
async portForward() { async portForward() {
const { pod, port } = this.props; const { pod, port, openPortForward } = this.props;
let portForward: ForwardedPort = { let portForward: ForwardedPort = {
kind: "pod", kind: "pod",
name: pod.getName(), name: pod.getName(),
@ -200,6 +203,7 @@ export const PodContainerPort = withInjectables<Dependencies, PodContainerPortPr
openPortForwardDialog: di.inject(portForwardDialogModelInjectable).open, openPortForwardDialog: di.inject(portForwardDialogModelInjectable).open,
aboutPortForwarding: di.inject(aboutPortForwardingInjectable), aboutPortForwarding: di.inject(aboutPortForwardingInjectable),
notifyErrorPortForwarding: di.inject(notifyErrorPortForwardingInjectable), notifyErrorPortForwarding: di.inject(notifyErrorPortForwardingInjectable),
openPortForward: di.inject(openPortForwardInjectable),
...props, ...props,
}), }),
}, },

View File

@ -11,6 +11,8 @@ import terminalSpawningPoolInjectable from "./terminal-spawning-pool.injectable"
import terminalConfigInjectable from "../../../../common/user-store/terminal-config.injectable"; import terminalConfigInjectable from "../../../../common/user-store/terminal-config.injectable";
import terminalCopyOnSelectInjectable from "../../../../common/user-store/terminal-copy-on-select.injectable"; import terminalCopyOnSelectInjectable from "../../../../common/user-store/terminal-copy-on-select.injectable";
import themeStoreInjectable from "../../../themes/store.injectable"; import themeStoreInjectable from "../../../themes/store.injectable";
import isMacInjectable from "../../../../common/vars/is-mac.injectable";
import openLinkInBrowserInjectable from "../../../../common/utils/open-link-in-browser.injectable";
export type CreateTerminal = (tabId: TabId, api: TerminalApi) => Terminal; export type CreateTerminal = (tabId: TabId, api: TerminalApi) => Terminal;
@ -22,6 +24,8 @@ const createTerminalInjectable = getInjectable({
terminalConfig: di.inject(terminalConfigInjectable), terminalConfig: di.inject(terminalConfigInjectable),
terminalCopyOnSelect: di.inject(terminalCopyOnSelectInjectable), terminalCopyOnSelect: di.inject(terminalCopyOnSelectInjectable),
themeStore: di.inject(themeStoreInjectable), themeStore: di.inject(themeStoreInjectable),
isMac: di.inject(isMacInjectable),
openLinkInBrowser: di.inject(openLinkInBrowserInjectable),
}; };
return (tabId, api) => new Terminal(dependencies, { tabId, api }); return (tabId, api) => new Terminal(dependencies, { tabId, api });

View File

@ -12,19 +12,22 @@ import type { TabId } from "../dock/store";
import type { TerminalApi } from "../../../api/terminal-api"; import type { TerminalApi } from "../../../api/terminal-api";
import type { ThemeStore } from "../../../themes/store"; import type { ThemeStore } from "../../../themes/store";
import { disposer } from "../../../utils"; import { disposer } from "../../../utils";
import { isMac } from "../../../../common/vars";
import { once } from "lodash"; import { once } from "lodash";
import { clipboard } from "electron"; import { clipboard } from "electron";
import logger from "../../../../common/logger"; import logger from "../../../../common/logger";
import type { TerminalConfig } from "../../../../common/user-store/preferences-helpers"; import type { TerminalConfig } from "../../../../common/user-store/preferences-helpers";
import assert from "assert"; import assert from "assert";
import { TerminalChannels } from "../../../../common/terminal/channels"; import { TerminalChannels } from "../../../../common/terminal/channels";
import { LinkProvider } from "xterm-link-provider";
import type { OpenLinkInBrowser } from "../../../../common/utils/open-link-in-browser.injectable";
export interface TerminalDependencies { export interface TerminalDependencies {
readonly spawningPool: HTMLElement; readonly spawningPool: HTMLElement;
readonly terminalConfig: IComputedValue<TerminalConfig>; readonly terminalConfig: IComputedValue<TerminalConfig>;
readonly terminalCopyOnSelect: IComputedValue<boolean>; readonly terminalCopyOnSelect: IComputedValue<boolean>;
readonly themeStore: ThemeStore; readonly themeStore: ThemeStore;
readonly isMac: boolean;
openLinkInBrowser: OpenLinkInBrowser;
} }
export interface TerminalArguments { export interface TerminalArguments {
@ -93,7 +96,6 @@ export class Terminal {
this.xterm.loadAddon(this.fitAddon); this.xterm.loadAddon(this.fitAddon);
this.xterm.open(this.dependencies.spawningPool); this.xterm.open(this.dependencies.spawningPool);
this.xterm.registerLinkMatcher(/https?:\/\/[^\s]+/i, this.onClickLink);
this.xterm.attachCustomKeyEventHandler(this.keyHandler); this.xterm.attachCustomKeyEventHandler(this.keyHandler);
this.xterm.onSelectionChange(this.onSelectionChange); this.xterm.onSelectionChange(this.onSelectionChange);
@ -108,7 +110,16 @@ export class Terminal {
this.api.on("data", this.onApiData); this.api.on("data", this.onApiData);
window.addEventListener("resize", this.onResize); window.addEventListener("resize", this.onResize);
const linkProvider = new LinkProvider(
this.xterm,
/https?:\/\/[^\s]+/i,
(event, link) => this.dependencies.openLinkInBrowser(link),
undefined,
0,
);
this.disposer.push( this.disposer.push(
this.xterm.registerLinkProvider(linkProvider),
reaction(() => this.theme, colors => this.xterm.setOption("theme", colors), { reaction(() => this.theme, colors => this.xterm.setOption("theme", colors), {
fireImmediately: true, fireImmediately: true,
}), }),
@ -169,10 +180,6 @@ export class Terminal {
this.viewport.scrollTop = this.scrollPos; // restore last scroll position this.viewport.scrollTop = this.scrollPos; // restore last scroll position
}; };
onClickLink = (evt: MouseEvent, link: string) => {
window.open(link, "_blank");
};
onContextMenu = () => { onContextMenu = () => {
if ( if (
// don't paste if user hasn't turned on the feature // don't paste if user hasn't turned on the feature
@ -229,7 +236,7 @@ export class Terminal {
} }
//Ctrl+K: clear the entire buffer, making the prompt line the new first line on mac os //Ctrl+K: clear the entire buffer, making the prompt line the new first line on mac os
if (isMac && metaKey) { if (this.dependencies.isMac && metaKey) {
switch (code) { switch (code) {
case "KeyK": case "KeyK":
this.onClear(); this.onClear();

View File

@ -0,0 +1,38 @@
/**
* 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 openLinkInBrowserInjectable from "../../common/utils/open-link-in-browser.injectable";
import showErrorNotificationInjectable from "../components/notifications/show-error-notification.injectable";
import type { ForwardedPort } from "./port-forward-item";
import { portForwardAddress } from "./port-forward-utils";
export type OpenPortForward = (portForward: ForwardedPort) => void;
const openPortForwardInjectable = getInjectable({
id: "open-port-forward",
instantiate: (di): OpenPortForward => {
const openLinkInBrowser = di.inject(openLinkInBrowserInjectable);
const showErrorNotification = di.inject(showErrorNotificationInjectable);
const logger = di.inject(loggerInjectable);
return (portForward) => {
const browseTo = portForwardAddress(portForward);
openLinkInBrowser(browseTo)
.catch(error => {
logger.error(`failed to open in browser: ${error}`, {
port: portForward.port,
kind: portForward.kind,
namespace: portForward.namespace,
name: portForward.name,
});
showErrorNotification(`Failed to open ${browseTo} in browser`);
});
};
},
});
export default openPortForwardInjectable;

View File

@ -14,7 +14,6 @@ import { Wizard, WizardStep } from "../components/wizard";
import { Input } from "../components/input"; import { Input } from "../components/input";
import { cssNames } from "../utils"; import { cssNames } from "../utils";
import type { PortForwardStore } from "./port-forward-store/port-forward-store"; import type { PortForwardStore } from "./port-forward-store/port-forward-store";
import { openPortForward } from "./port-forward-utils";
import { Checkbox } from "../components/checkbox"; import { Checkbox } from "../components/checkbox";
import { withInjectables } from "@ogre-tools/injectable-react"; import { withInjectables } from "@ogre-tools/injectable-react";
import type { PortForwardDialogData, PortForwardDialogModel } from "./port-forward-dialog-model/port-forward-dialog-model"; import type { PortForwardDialogData, PortForwardDialogModel } from "./port-forward-dialog-model/port-forward-dialog-model";
@ -23,6 +22,8 @@ import logger from "../../common/logger";
import portForwardStoreInjectable from "./port-forward-store/port-forward-store.injectable"; import portForwardStoreInjectable from "./port-forward-store/port-forward-store.injectable";
import aboutPortForwardingInjectable from "./about-port-forwarding.injectable"; import aboutPortForwardingInjectable from "./about-port-forwarding.injectable";
import notifyErrorPortForwardingInjectable from "./notify-error-port-forwarding.injectable"; import notifyErrorPortForwardingInjectable from "./notify-error-port-forwarding.injectable";
import type { OpenPortForward } from "./open-port-forward.injectable";
import openPortForwardInjectable from "./open-port-forward.injectable";
export interface PortForwardDialogProps extends Partial<DialogProps> {} export interface PortForwardDialogProps extends Partial<DialogProps> {}
@ -31,6 +32,7 @@ interface Dependencies {
model: PortForwardDialogModel; model: PortForwardDialogModel;
aboutPortForwarding: () => void; aboutPortForwarding: () => void;
notifyErrorPortForwarding: (message: string) => void; notifyErrorPortForwarding: (message: string) => void;
openPortForward: OpenPortForward;
} }
@observer @observer
@ -89,7 +91,7 @@ class NonInjectedPortForwardDialog extends Component<PortForwardDialogProps & De
} }
if (portForward.status === "Active" && data.openInBrowser) { if (portForward.status === "Active" && data.openInBrowser) {
openPortForward(portForward); this.props.openPortForward(portForward);
} }
} catch (error) { } catch (error) {
logger.error(`[PORT-FORWARD-DIALOG]: ${error}`, portForward); logger.error(`[PORT-FORWARD-DIALOG]: ${error}`, portForward);
@ -177,6 +179,7 @@ export const PortForwardDialog = withInjectables<Dependencies, PortForwardDialog
model: di.inject(portForwardDialogModelInjectable), model: di.inject(portForwardDialogModelInjectable),
aboutPortForwarding: di.inject(aboutPortForwardingInjectable), aboutPortForwarding: di.inject(aboutPortForwardingInjectable),
notifyErrorPortForwarding: di.inject(notifyErrorPortForwardingInjectable), notifyErrorPortForwarding: di.inject(notifyErrorPortForwardingInjectable),
openPortForward: di.inject(openPortForwardInjectable),
...props, ...props,
}), }),
}, },

View File

@ -3,34 +3,12 @@
* Licensed under MIT License. See LICENSE in root directory for more information. * Licensed under MIT License. See LICENSE in root directory for more information.
*/ */
import { openBrowser } from "../utils";
import { Notifications } from "../components/notifications";
import type { ForwardedPort } from "./port-forward-item"; import type { ForwardedPort } from "./port-forward-item";
import logger from "../../common/logger";
export function portForwardAddress(portForward: ForwardedPort) { export function portForwardAddress(portForward: ForwardedPort) {
return `${portForward.protocol ?? "http"}://localhost:${portForward.forwardPort}`; return `${portForward.protocol ?? "http"}://localhost:${portForward.forwardPort}`;
} }
export function openPortForward(portForward: ForwardedPort) {
const browseTo = portForwardAddress(portForward);
openBrowser(browseTo)
.catch(error => {
logger.error(`failed to open in browser: ${error}`, {
port: portForward.port,
kind: portForward.kind,
namespace: portForward.namespace,
name: portForward.name,
});
Notifications.error(`Failed to open ${browseTo} in browser`);
},
);
}
export function predictProtocol(name: string | undefined) { export function predictProtocol(name: string | undefined) {
return name === "https" ? "https" : "http"; return name === "https" ? "https" : "http";
} }

View File

@ -13699,7 +13699,14 @@ xterm-addon-fit@^0.5.0:
resolved "https://registry.yarnpkg.com/xterm-addon-fit/-/xterm-addon-fit-0.5.0.tgz#2d51b983b786a97dcd6cde805e700c7f913bc596" resolved "https://registry.yarnpkg.com/xterm-addon-fit/-/xterm-addon-fit-0.5.0.tgz#2d51b983b786a97dcd6cde805e700c7f913bc596"
integrity sha512-DsS9fqhXHacEmsPxBJZvfj2la30Iz9xk+UKjhQgnYNkrUIN5CYLbw7WEfz117c7+S86S/tpHPfvNxJsF5/G8wQ== integrity sha512-DsS9fqhXHacEmsPxBJZvfj2la30Iz9xk+UKjhQgnYNkrUIN5CYLbw7WEfz117c7+S86S/tpHPfvNxJsF5/G8wQ==
xterm@^4.19.0: xterm-link-provider@^1.3.1:
version "1.3.1"
resolved "https://registry.yarnpkg.com/xterm-link-provider/-/xterm-link-provider-1.3.1.tgz#69727223220dfa8758056ad6b2b5394a8454b9cb"
integrity sha512-uOlaIeUED6kJeL2nIIf5YwreO0obMhsC0RWypEUmWkz7SAQewzgwdWFjQ2He7NGcT93c4KUf8bRgAu8cV9bAYA==
dependencies:
xterm "^4.6.0"
xterm@^4.19.0, xterm@^4.6.0:
version "4.19.0" version "4.19.0"
resolved "https://registry.yarnpkg.com/xterm/-/xterm-4.19.0.tgz#c0f9d09cd61de1d658f43ca75f992197add9ef6d" resolved "https://registry.yarnpkg.com/xterm/-/xterm-4.19.0.tgz#c0f9d09cd61de1d658f43ca75f992197add9ef6d"
integrity sha512-c3Cp4eOVsYY5Q839dR5IejghRPpxciGmLWWaP9g+ppfMeBChMeLa1DCA+pmX/jyDZ+zxFOmlJL/82qVdayVoGQ== integrity sha512-c3Cp4eOVsYY5Q839dR5IejghRPpxciGmLWWaP9g+ppfMeBChMeLa1DCA+pmX/jyDZ+zxFOmlJL/82qVdayVoGQ==