From a4e3c26415180bf80cea260669e5beb208355394 Mon Sep 17 00:00:00 2001 From: logonoff Date: Wed, 27 May 2026 09:43:32 -0400 Subject: [PATCH 1/2] OCPBUGS-86491: Fix macOS Option key in pod terminal The NodePolyfillPlugin injects a `process` polyfill with `process.title` set, which causes xterm.js to misidentify the browser as Node.js. This breaks platform detection (`isMac = false`), so the Option key is treated as Meta instead of a compose key on macOS. Delete `process.title` as a workaround as xterm did not release this patch yet --- frontend/public/components/app.tsx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/frontend/public/components/app.tsx b/frontend/public/components/app.tsx index 0262bec25bf..03d2f5ebb64 100644 --- a/frontend/public/components/app.tsx +++ b/frontend/public/components/app.tsx @@ -87,6 +87,9 @@ import { useCSPViolationDetector } from '@console/app/src/hooks/useCSPViolationD import { useNotificationPoller } from '@console/app/src/hooks/useNotificationPoller'; import { useImpersonateRefreshFeatures } from './useImpersonateRefreshFeatures'; +// TODO: remove when upgrading to @xterm/xterm 7.0.0 - github.com/openshift/console/issues/16486 +delete process.title; + initI18n(); // Disable linkify 'fuzzy links' across the app. From a9947c7bfb5986fb19b08ad0d18c0ceba9830500 Mon Sep 17 00:00:00 2001 From: logonoff Date: Tue, 2 Jun 2026 17:27:42 -0400 Subject: [PATCH 2/2] OCPBUGS-79363: Move xterm to its own chunk --- .../src/components/cloud-shell/CloudShellTerminal.tsx | 9 +++++++-- frontend/public/components/pod-connect.tsx | 1 + frontend/public/components/terminal.tsx | 5 +++++ 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/frontend/packages/webterminal-plugin/src/components/cloud-shell/CloudShellTerminal.tsx b/frontend/packages/webterminal-plugin/src/components/cloud-shell/CloudShellTerminal.tsx index 81375de78c3..2360ebe42d0 100644 --- a/frontend/packages/webterminal-plugin/src/components/cloud-shell/CloudShellTerminal.tsx +++ b/frontend/packages/webterminal-plugin/src/components/cloud-shell/CloudShellTerminal.tsx @@ -3,6 +3,7 @@ import { useState, useEffect } from 'react'; import { useTranslation } from 'react-i18next'; import { connect } from 'react-redux'; import { getUser } from '@console/dynamic-plugin-sdk'; +import { AsyncComponent } from '@console/internal/components/utils'; import { useAccessReview2 } from '@console/internal/components/utils/rbac'; import { StatusBox, LoadError } from '@console/internal/components/utils/status-box'; import type { UserInfo } from '@console/internal/module/k8s'; @@ -14,7 +15,6 @@ import { v1alpha1WorkspaceModel, WorkspaceModel } from '../../../models'; import { FLAG_V1ALPHA2DEVWORKSPACE } from '../../const'; import type { TerminalInitData } from './cloud-shell-utils'; import { initTerminal, startWorkspace, CLOUD_SHELL_PHASE } from './cloud-shell-utils'; -import CloudshellExec from './CloudShellExec'; import { CLOUD_SHELL_NAMESPACE_CONFIG_USER_PREFERENCE_KEY } from './const'; import CloudShellAdminSetup from './setup/CloudShellAdminSetup'; import CloudShellDeveloperSetup from './setup/CloudShellDeveloperSetup'; @@ -209,7 +209,12 @@ const CloudShellTerminal: FC + import('./CloudShellExec' /* webpackChunkName: "cloud-shell-exec" */).then( + (m) => m.default, + ) + } workspaceName={workspaceName} namespace={workspaceNamespace} workspaceId={workspaceId} diff --git a/frontend/public/components/pod-connect.tsx b/frontend/public/components/pod-connect.tsx index a79dca21bc8..596ee09d7c5 100644 --- a/frontend/public/components/pod-connect.tsx +++ b/frontend/public/components/pod-connect.tsx @@ -49,6 +49,7 @@ type PodConnectProps = { infoMessage?: React.ReactNode; }; +/** @internal Use PodConnectLoader instead for tree shaking to work */ export const PodConnect: FC = ({ obj, attach, diff --git a/frontend/public/components/terminal.tsx b/frontend/public/components/terminal.tsx index adc559325c8..b715099d4b3 100644 --- a/frontend/public/components/terminal.tsx +++ b/frontend/public/components/terminal.tsx @@ -25,6 +25,11 @@ export interface TerminalProps { className?: string; } +/** + * This component loads the entire `xterm` library with it. + * Use `AsyncComponent` on components that consume this one to dynamically + * load xterm only when used. + */ export const Terminal = forwardRef( ({ onData, onResize, padding = 52, options = defaultOptions, className }, ref) => { const terminal = useRef();