From c5b2dcf67d1bdcd073e0ad20ca0d5dfc215f890b Mon Sep 17 00:00:00 2001
From: Steve Goodwin
Date: Tue, 20 Jan 2026 13:45:01 -0500
Subject: [PATCH 1/7] Migrate DeleteHPAModal and ConsolePluginModal from
createModalLauncher to useOverlay Assisted by: Claude Code
---
.../src/actions/creators/hpa-factory.ts | 124 +++++++++---------
.../ConsoleOperatorConfig.tsx | 6 +-
.../src/components/hpa/DeleteHPAModal.tsx | 27 +++-
.../src/components/hpa/index.ts | 2 +-
.../components/modals/ConsolePluginModal.tsx | 52 +++++---
.../src/components/modals/index.ts | 2 +-
.../src/components/clusterserviceversion.tsx | 6 +-
7 files changed, 128 insertions(+), 91 deletions(-)
diff --git a/frontend/packages/console-app/src/actions/creators/hpa-factory.ts b/frontend/packages/console-app/src/actions/creators/hpa-factory.ts
index 5ce95f4d1c3..53676d3db38 100644
--- a/frontend/packages/console-app/src/actions/creators/hpa-factory.ts
+++ b/frontend/packages/console-app/src/actions/creators/hpa-factory.ts
@@ -1,6 +1,7 @@
import { useMemo } from 'react';
import i18next from 'i18next';
import { Action } from '@console/dynamic-plugin-sdk';
+import { useOverlay } from '@console/dynamic-plugin-sdk/src/app/modal-support/useOverlay';
import { useK8sWatchResources } from '@console/internal/components/utils/k8s-watch-hook';
import { HorizontalPodAutoscalerModel } from '@console/internal/models';
import {
@@ -14,84 +15,23 @@ import {
ClusterServiceVersionModel,
ClusterServiceVersionKind,
} from '@console/operator-lifecycle-manager';
-import deleteHPAModal from '@console/shared/src/components/hpa/DeleteHPAModal';
+import DeleteHPAModalProvider from '@console/shared/src/components/hpa/DeleteHPAModal';
import { isHelmResource } from '@console/shared/src/utils/helm-utils';
import { doesHpaMatch } from '@console/shared/src/utils/hpa-utils';
import { isOperatorBackedService } from '@console/shared/src/utils/operator-utils';
-import { ResourceActionFactory } from './types';
const hpaRoute = (
{ metadata: { name = '', namespace = '' } = {} }: K8sResourceCommon,
kind: K8sKind,
) => `/workload-hpa/ns/${namespace}/${referenceForModel(kind)}/${name}`;
-export const HpaActionFactory: ResourceActionFactory = {
- AddHorizontalPodAutoScaler: (kind: K8sKind, obj: K8sResourceKind) => ({
- id: 'add-hpa',
- label: i18next.t('console-app~Add HorizontalPodAutoscaler'),
- cta: { href: hpaRoute(obj, kind) },
- insertBefore: 'add-pdb',
- accessReview: {
- group: HorizontalPodAutoscalerModel.apiGroup,
- resource: HorizontalPodAutoscalerModel.plural,
- namespace: obj.metadata?.namespace,
- verb: 'create',
- },
- }),
- EditHorizontalPodAutoScaler: (kind: K8sKind, obj: K8sResourceCommon) => ({
- id: 'edit-hpa',
- label: i18next.t('console-app~Edit HorizontalPodAutoscaler'),
- cta: { href: hpaRoute(obj, kind) },
- insertBefore: 'add-pdb',
- accessReview: {
- group: HorizontalPodAutoscalerModel.apiGroup,
- resource: HorizontalPodAutoscalerModel.plural,
- namespace: obj.metadata?.namespace,
- verb: 'update',
- },
- }),
- DeleteHorizontalPodAutoScaler: (
- kind: K8sKind,
- obj: K8sResourceCommon,
- relatedHPA: HorizontalPodAutoscalerKind,
- ) => ({
- id: 'delete-hpa',
- label: i18next.t('console-app~Remove HorizontalPodAutoscaler'),
- insertBefore: 'delete-pdb',
- cta: () => {
- deleteHPAModal({
- workload: obj,
- hpa: relatedHPA,
- });
- },
- accessReview: {
- group: HorizontalPodAutoscalerModel.apiGroup,
- resource: HorizontalPodAutoscalerModel.plural,
- namespace: obj.metadata?.namespace,
- verb: 'delete',
- },
- }),
-};
-
-export const getHpaActions = (
- kind: K8sKind,
- obj: K8sResourceKind,
- relatedHPAs: K8sResourceKind[],
-): Action[] => {
- if (relatedHPAs.length === 0) return [HpaActionFactory.AddHorizontalPodAutoScaler(kind, obj)];
-
- return [
- HpaActionFactory.EditHorizontalPodAutoScaler(kind, obj),
- HpaActionFactory.DeleteHorizontalPodAutoScaler(kind, obj, relatedHPAs[0]),
- ];
-};
-
type DeploymentActionExtraResources = {
hpas: HorizontalPodAutoscalerKind[];
csvs: ClusterServiceVersionKind[];
};
export const useHPAActions = (kindObj: K8sKind, resource: K8sResourceKind) => {
+ const launchOverlay = useOverlay();
const namespace = resource?.metadata?.namespace;
const watchedResources = useMemo(
@@ -123,9 +63,63 @@ export const useHPAActions = (kindObj: K8sKind, resource: K8sResourceKind) => {
[extraResources.csvs.data, resource],
);
- const result = useMemo<[Action[], HorizontalPodAutoscalerKind[]]>(() => {
- return [supportsHPA ? getHpaActions(kindObj, resource, relatedHPAs) : [], relatedHPAs];
+ const actions = useMemo(() => {
+ if (!supportsHPA) return [];
+
+ if (relatedHPAs.length === 0) {
+ return [
+ {
+ id: 'add-hpa',
+ label: i18next.t('console-app~Add HorizontalPodAutoscaler'),
+ cta: { href: hpaRoute(resource, kindObj) },
+ insertBefore: 'add-pdb',
+ accessReview: {
+ group: HorizontalPodAutoscalerModel.apiGroup,
+ resource: HorizontalPodAutoscalerModel.plural,
+ namespace: resource.metadata?.namespace,
+ verb: 'create',
+ },
+ },
+ ];
+ }
+ return [
+ {
+ id: 'edit-hpa',
+ label: i18next.t('console-app~Edit HorizontalPodAutoscaler'),
+ cta: { href: hpaRoute(resource, kindObj) },
+ insertBefore: 'add-pdb',
+ accessReview: {
+ group: HorizontalPodAutoscalerModel.apiGroup,
+ resource: HorizontalPodAutoscalerModel.plural,
+ namespace: resource.metadata?.namespace,
+ verb: 'update',
+ },
+ },
+ {
+ id: 'delete-hpa',
+ label: i18next.t('console-app~Remove HorizontalPodAutoscaler'),
+ insertBefore: 'delete-pdb',
+ cta: () => {
+ launchOverlay(DeleteHPAModalProvider, {
+ workload: resource,
+ hpa: relatedHPAs[0],
+ });
+ },
+ accessReview: {
+ group: HorizontalPodAutoscalerModel.apiGroup,
+ resource: HorizontalPodAutoscalerModel.plural,
+ namespace: resource.metadata?.namespace,
+ verb: 'delete',
+ },
+ },
+ ];
+ // missing launchModal dependency, that causes max depth exceeded error
+ // eslint-disable-next-line react-hooks/exhaustive-deps
}, [kindObj, relatedHPAs, resource, supportsHPA]);
+ const result = useMemo<[Action[], HorizontalPodAutoscalerKind[]]>(() => {
+ return [actions, relatedHPAs];
+ }, [actions, relatedHPAs]);
+
return result;
};
diff --git a/frontend/packages/console-app/src/components/console-operator/ConsoleOperatorConfig.tsx b/frontend/packages/console-app/src/components/console-operator/ConsoleOperatorConfig.tsx
index a152aed5bf2..f97c48f6ddc 100644
--- a/frontend/packages/console-app/src/components/console-operator/ConsoleOperatorConfig.tsx
+++ b/frontend/packages/console-app/src/components/console-operator/ConsoleOperatorConfig.tsx
@@ -19,6 +19,7 @@ import { useSelector } from 'react-redux';
import { Link } from 'react-router-dom';
import { useLocation } from 'react-router-dom-v5-compat';
import { useAccessReview, WatchK8sResource } from '@console/dynamic-plugin-sdk';
+import { useOverlay } from '@console/dynamic-plugin-sdk/src/app/modal-support/useOverlay';
import {
getGroupVersionKindForModel,
getReferenceForModel,
@@ -43,7 +44,7 @@ import {
import { RootState } from '@console/internal/redux';
import { usePluginInfo } from '@console/plugin-sdk/src/api/usePluginInfo';
import PaneBody from '@console/shared/src/components/layout/PaneBody';
-import { consolePluginModal } from '@console/shared/src/components/modals/ConsolePluginModal';
+import { LazyConsolePluginModalOverlay } from '@console/shared/src/components/modals';
import {
GreenCheckCircleIcon,
YellowExclamationTriangleIcon,
@@ -113,6 +114,7 @@ export const ConsolePluginEnabledStatus: FC = (
enabled,
}) => {
const { t } = useTranslation('console-app');
+ const launchModal = useOverlay();
const {
consoleOperatorConfig,
@@ -132,7 +134,7 @@ export const ConsolePluginEnabledStatus: FC = (
type="button"
isInline
onClick={() =>
- consolePluginModal({
+ launchModal(LazyConsolePluginModalOverlay, {
consoleOperatorConfig,
pluginName,
trusted: false,
diff --git a/frontend/packages/console-shared/src/components/hpa/DeleteHPAModal.tsx b/frontend/packages/console-shared/src/components/hpa/DeleteHPAModal.tsx
index a343b0a5d6f..4ee04aa7640 100644
--- a/frontend/packages/console-shared/src/components/hpa/DeleteHPAModal.tsx
+++ b/frontend/packages/console-shared/src/components/hpa/DeleteHPAModal.tsx
@@ -4,12 +4,13 @@ import { Form } from '@patternfly/react-core';
import { ExclamationTriangleIcon } from '@patternfly/react-icons/dist/esm/icons/exclamation-triangle-icon';
import { t_global_icon_color_status_warning_default as warningColor } from '@patternfly/react-tokens';
import { useTranslation } from 'react-i18next';
+import { OverlayComponent } from '@console/dynamic-plugin-sdk/src/app/modal-support/OverlayProvider';
import {
- createModalLauncher,
ModalBody,
ModalComponentProps,
ModalSubmitFooter,
ModalTitle,
+ ModalWrapper,
} from '@console/internal/components/factory/modal';
import { LoadingInline } from '@console/internal/components/utils/status-box';
import { HorizontalPodAutoscalerModel } from '@console/internal/models';
@@ -24,7 +25,7 @@ type DeleteHPAModalProps = ModalComponentProps & {
workload: K8sResourceCommon;
};
-const DeleteHPAModal: FC = ({ close, hpa, workload }) => {
+const DeleteHPAModal: FC = ({ close, cancel, hpa, workload }) => {
const [submitError, setSubmitError] = useState(null);
const [isSubmitting, setIsSubmitting] = useState(false);
const { t } = useTranslation();
@@ -82,11 +83,29 @@ const DeleteHPAModal: FC = ({ close, hpa, workload }) => {
submitText={t('console-shared~Remove')}
submitDanger
submitDisabled={!!submitError}
- cancel={close}
+ cancel={cancel}
/>
);
};
-export default createModalLauncher(DeleteHPAModal);
+type DeleteHPAModalProviderProps = {
+ hpa: HorizontalPodAutoscalerKind;
+ workload: K8sResourceCommon;
+};
+
+const DeleteHPAModalProvider: OverlayComponent = (props) => {
+ return (
+
+
+
+ );
+};
+
+export default DeleteHPAModalProvider;
diff --git a/frontend/packages/console-shared/src/components/hpa/index.ts b/frontend/packages/console-shared/src/components/hpa/index.ts
index fc131d9b545..de11a4852e1 100644
--- a/frontend/packages/console-shared/src/components/hpa/index.ts
+++ b/frontend/packages/console-shared/src/components/hpa/index.ts
@@ -1 +1 @@
-export { default as deleteHPAModal } from './DeleteHPAModal';
+export { default as DeleteHPAModalProvider } from './DeleteHPAModal';
diff --git a/frontend/packages/console-shared/src/components/modals/ConsolePluginModal.tsx b/frontend/packages/console-shared/src/components/modals/ConsolePluginModal.tsx
index 8a4d1306c69..557b11273be 100644
--- a/frontend/packages/console-shared/src/components/modals/ConsolePluginModal.tsx
+++ b/frontend/packages/console-shared/src/components/modals/ConsolePluginModal.tsx
@@ -1,11 +1,11 @@
import { useState } from 'react';
-import { Form } from '@patternfly/react-core';
import { useTranslation } from 'react-i18next';
+import { OverlayComponent } from '@console/dynamic-plugin-sdk/src/app/modal-support/OverlayProvider';
import {
- createModalLauncher,
ModalTitle,
ModalBody,
ModalSubmitFooter,
+ ModalWrapper,
} from '@console/internal/components/factory/modal';
import { ConsoleOperatorConfigModel } from '@console/internal/models';
import { k8sPatch, K8sResourceKind } from '@console/internal/module/k8s';
@@ -48,19 +48,17 @@ export const ConsolePluginModal = (props: ConsolePluginModalProps) => {
'console-shared~This console plugin provides a custom interface that can be included in the console. Updating the enablement of this console plugin will prompt for the console to be refreshed once it has been updated. Make sure you trust this console plugin before enabling.',
)}
-
+
+
{
);
};
-export const consolePluginModal = createModalLauncher(ConsolePluginModal);
+type ConsolePluginModalProviderProps = {
+ consoleOperatorConfig: K8sResourceKind;
+ csvPluginsCount?: number;
+ pluginName: string;
+ trusted: boolean;
+};
+
+const ConsolePluginModalProvider: OverlayComponent = (props) => {
+ return (
+
+
+
+ );
+};
+
+export default ConsolePluginModalProvider;
export type ConsolePluginModalProps = {
consoleOperatorConfig: K8sResourceKind;
diff --git a/frontend/packages/console-shared/src/components/modals/index.ts b/frontend/packages/console-shared/src/components/modals/index.ts
index ac902b242de..53f05c1275a 100644
--- a/frontend/packages/console-shared/src/components/modals/index.ts
+++ b/frontend/packages/console-shared/src/components/modals/index.ts
@@ -1,6 +1,6 @@
export const consolePluginModal = (props) =>
import('./ConsolePluginModal' /* webpackChunkName: "shared-modals" */).then((m) =>
- m.consolePluginModal(props),
+ m.default(props),
);
export const deleteResourceModal = (props) =>
diff --git a/frontend/packages/operator-lifecycle-manager/src/components/clusterserviceversion.tsx b/frontend/packages/operator-lifecycle-manager/src/components/clusterserviceversion.tsx
index 4657eca88f4..e70813514f8 100644
--- a/frontend/packages/operator-lifecycle-manager/src/components/clusterserviceversion.tsx
+++ b/frontend/packages/operator-lifecycle-manager/src/components/clusterserviceversion.tsx
@@ -30,6 +30,7 @@ import {
useAccessReviewAllowed,
useAccessReview,
} from '@console/dynamic-plugin-sdk';
+import { useOverlay } from '@console/dynamic-plugin-sdk/src/app/modal-support/useOverlay';
import { getGroupVersionKindForModel } from '@console/dynamic-plugin-sdk/src/lib-core';
import { Conditions, ConditionTypes } from '@console/internal/components/conditions';
import { ResourceEventStream } from '@console/internal/components/events';
@@ -77,7 +78,7 @@ import { DocumentTitle } from '@console/shared/src/components/document-title/Doc
import { withFallback } from '@console/shared/src/components/error';
import PaneBody from '@console/shared/src/components/layout/PaneBody';
import { ExternalLink } from '@console/shared/src/components/links/ExternalLink';
-import { consolePluginModal } from '@console/shared/src/components/modals';
+import ConsolePluginModalProvider from '@console/shared/src/components/modals/ConsolePluginModal';
import { RedExclamationCircleIcon } from '@console/shared/src/components/status/icons';
import { CONSOLE_OPERATOR_CONFIG_NAME } from '@console/shared/src/constants';
import { useActiveNamespace } from '@console/shared/src/hooks/redux-selectors';
@@ -239,6 +240,7 @@ const ManagedNamespaces: FC = ({ obj }) => {
};
const ConsolePlugins: FC = ({ csvPlugins, trusted }) => {
+ const launchOverlay = useOverlay();
const console: WatchK8sResource = {
kind: referenceForModel(ConsoleOperatorConfigModel),
isList: false,
@@ -273,7 +275,7 @@ const ConsolePlugins: FC = ({ csvPlugins, trusted }) => {
type="button"
isInline
onClick={() =>
- consolePluginModal({
+ launchOverlay(ConsolePluginModalProvider, {
consoleOperatorConfig,
pluginName,
trusted,
From b77bef3fa4349b024d8ad14319b43c24757042a3 Mon Sep 17 00:00:00 2001
From: Steve Goodwin
Date: Fri, 30 Jan 2026 17:21:25 -0500
Subject: [PATCH 2/7] Address comments
Assisted by: Claude Code
---
.../console-app/src/actions/creators/hpa-factory.ts | 2 +-
.../console-shared/src/components/hpa/DeleteHPAModal.tsx | 2 +-
.../packages/console-shared/src/components/hpa/index.ts | 2 +-
.../src/components/modals/ConsolePluginModal.tsx | 6 +++---
.../packages/console-shared/src/components/modals/index.ts | 2 +-
.../src/components/clusterserviceversion.tsx | 4 ++--
6 files changed, 9 insertions(+), 9 deletions(-)
diff --git a/frontend/packages/console-app/src/actions/creators/hpa-factory.ts b/frontend/packages/console-app/src/actions/creators/hpa-factory.ts
index 53676d3db38..f672399a2bf 100644
--- a/frontend/packages/console-app/src/actions/creators/hpa-factory.ts
+++ b/frontend/packages/console-app/src/actions/creators/hpa-factory.ts
@@ -15,7 +15,7 @@ import {
ClusterServiceVersionModel,
ClusterServiceVersionKind,
} from '@console/operator-lifecycle-manager';
-import DeleteHPAModalProvider from '@console/shared/src/components/hpa/DeleteHPAModal';
+import { DeleteHPAModalProvider } from '@console/shared/src/components/hpa/DeleteHPAModal';
import { isHelmResource } from '@console/shared/src/utils/helm-utils';
import { doesHpaMatch } from '@console/shared/src/utils/hpa-utils';
import { isOperatorBackedService } from '@console/shared/src/utils/operator-utils';
diff --git a/frontend/packages/console-shared/src/components/hpa/DeleteHPAModal.tsx b/frontend/packages/console-shared/src/components/hpa/DeleteHPAModal.tsx
index 4ee04aa7640..0e55164dfb1 100644
--- a/frontend/packages/console-shared/src/components/hpa/DeleteHPAModal.tsx
+++ b/frontend/packages/console-shared/src/components/hpa/DeleteHPAModal.tsx
@@ -108,4 +108,4 @@ const DeleteHPAModalProvider: OverlayComponent = (p
);
};
-export default DeleteHPAModalProvider;
+export { DeleteHPAModalProvider };
diff --git a/frontend/packages/console-shared/src/components/hpa/index.ts b/frontend/packages/console-shared/src/components/hpa/index.ts
index de11a4852e1..7156a812f4d 100644
--- a/frontend/packages/console-shared/src/components/hpa/index.ts
+++ b/frontend/packages/console-shared/src/components/hpa/index.ts
@@ -1 +1 @@
-export { default as DeleteHPAModalProvider } from './DeleteHPAModal';
+export { DeleteHPAModalProvider } from './DeleteHPAModal';
diff --git a/frontend/packages/console-shared/src/components/modals/ConsolePluginModal.tsx b/frontend/packages/console-shared/src/components/modals/ConsolePluginModal.tsx
index 557b11273be..205bc0b97cf 100644
--- a/frontend/packages/console-shared/src/components/modals/ConsolePluginModal.tsx
+++ b/frontend/packages/console-shared/src/components/modals/ConsolePluginModal.tsx
@@ -71,14 +71,14 @@ export const ConsolePluginModal = (props: ConsolePluginModalProps) => {
);
};
-type ConsolePluginModalProviderProps = {
+type ConsolePluginModalOverlayProps = {
consoleOperatorConfig: K8sResourceKind;
csvPluginsCount?: number;
pluginName: string;
trusted: boolean;
};
-const ConsolePluginModalProvider: OverlayComponent = (props) => {
+const ConsolePluginModalOverlay: OverlayComponent = (props) => {
return (
import('./ConsolePluginModal' /* webpackChunkName: "shared-modals" */).then((m) =>
- m.default(props),
+ m.ConsolePluginModalOverlay(props),
);
export const deleteResourceModal = (props) =>
diff --git a/frontend/packages/operator-lifecycle-manager/src/components/clusterserviceversion.tsx b/frontend/packages/operator-lifecycle-manager/src/components/clusterserviceversion.tsx
index e70813514f8..d3063fa3e8f 100644
--- a/frontend/packages/operator-lifecycle-manager/src/components/clusterserviceversion.tsx
+++ b/frontend/packages/operator-lifecycle-manager/src/components/clusterserviceversion.tsx
@@ -78,7 +78,7 @@ import { DocumentTitle } from '@console/shared/src/components/document-title/Doc
import { withFallback } from '@console/shared/src/components/error';
import PaneBody from '@console/shared/src/components/layout/PaneBody';
import { ExternalLink } from '@console/shared/src/components/links/ExternalLink';
-import ConsolePluginModalProvider from '@console/shared/src/components/modals/ConsolePluginModal';
+import { ConsolePluginModalOverlay } from '@console/shared/src/components/modals/ConsolePluginModal';
import { RedExclamationCircleIcon } from '@console/shared/src/components/status/icons';
import { CONSOLE_OPERATOR_CONFIG_NAME } from '@console/shared/src/constants';
import { useActiveNamespace } from '@console/shared/src/hooks/redux-selectors';
@@ -275,7 +275,7 @@ const ConsolePlugins: FC = ({ csvPlugins, trusted }) => {
type="button"
isInline
onClick={() =>
- launchOverlay(ConsolePluginModalProvider, {
+ launchOverlay(ConsolePluginModalOverlay, {
consoleOperatorConfig,
pluginName,
trusted,
From f9c226215cef4405781b1fb73809810e9e56581a Mon Sep 17 00:00:00 2001
From: Steve Goodwin
Date: Tue, 3 Feb 2026 15:25:36 -0500
Subject: [PATCH 3/7] Batch renaming for consistency. Assisted-by Claude
---
.../console-app/src/actions/creators/hpa-factory.ts | 8 ++++----
.../console-shared/src/components/hpa/DeleteHPAModal.tsx | 6 +++---
.../packages/console-shared/src/components/hpa/index.ts | 2 +-
.../src/components/clusterserviceversion.tsx | 4 ++--
4 files changed, 10 insertions(+), 10 deletions(-)
diff --git a/frontend/packages/console-app/src/actions/creators/hpa-factory.ts b/frontend/packages/console-app/src/actions/creators/hpa-factory.ts
index f672399a2bf..3779c8add13 100644
--- a/frontend/packages/console-app/src/actions/creators/hpa-factory.ts
+++ b/frontend/packages/console-app/src/actions/creators/hpa-factory.ts
@@ -15,7 +15,7 @@ import {
ClusterServiceVersionModel,
ClusterServiceVersionKind,
} from '@console/operator-lifecycle-manager';
-import { DeleteHPAModalProvider } from '@console/shared/src/components/hpa/DeleteHPAModal';
+import { DeleteHPAModalOverlay } from '@console/shared/src/components/hpa/DeleteHPAModal';
import { isHelmResource } from '@console/shared/src/utils/helm-utils';
import { doesHpaMatch } from '@console/shared/src/utils/hpa-utils';
import { isOperatorBackedService } from '@console/shared/src/utils/operator-utils';
@@ -31,7 +31,7 @@ type DeploymentActionExtraResources = {
};
export const useHPAActions = (kindObj: K8sKind, resource: K8sResourceKind) => {
- const launchOverlay = useOverlay();
+ const launchModal = useOverlay();
const namespace = resource?.metadata?.namespace;
const watchedResources = useMemo(
@@ -100,7 +100,7 @@ export const useHPAActions = (kindObj: K8sKind, resource: K8sResourceKind) => {
label: i18next.t('console-app~Remove HorizontalPodAutoscaler'),
insertBefore: 'delete-pdb',
cta: () => {
- launchOverlay(DeleteHPAModalProvider, {
+ launchModal(DeleteHPAModalOverlay, {
workload: resource,
hpa: relatedHPAs[0],
});
@@ -113,7 +113,7 @@ export const useHPAActions = (kindObj: K8sKind, resource: K8sResourceKind) => {
},
},
];
- // missing launchModal dependency, that causes max depth exceeded error
+ // Missing launchModal dependency causes max depth exceeded error
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [kindObj, relatedHPAs, resource, supportsHPA]);
diff --git a/frontend/packages/console-shared/src/components/hpa/DeleteHPAModal.tsx b/frontend/packages/console-shared/src/components/hpa/DeleteHPAModal.tsx
index 0e55164dfb1..600282747e6 100644
--- a/frontend/packages/console-shared/src/components/hpa/DeleteHPAModal.tsx
+++ b/frontend/packages/console-shared/src/components/hpa/DeleteHPAModal.tsx
@@ -90,12 +90,12 @@ const DeleteHPAModal: FC = ({ close, cancel, hpa, workload
);
};
-type DeleteHPAModalProviderProps = {
+type DeleteHPAModalOverlayProps = {
hpa: HorizontalPodAutoscalerKind;
workload: K8sResourceCommon;
};
-const DeleteHPAModalProvider: OverlayComponent = (props) => {
+const DeleteHPAModalOverlay: OverlayComponent = (props) => {
return (
= (p
);
};
-export { DeleteHPAModalProvider };
+export { DeleteHPAModalOverlay };
diff --git a/frontend/packages/console-shared/src/components/hpa/index.ts b/frontend/packages/console-shared/src/components/hpa/index.ts
index 7156a812f4d..eb289f99ea4 100644
--- a/frontend/packages/console-shared/src/components/hpa/index.ts
+++ b/frontend/packages/console-shared/src/components/hpa/index.ts
@@ -1 +1 @@
-export { DeleteHPAModalProvider } from './DeleteHPAModal';
+export { DeleteHPAModalOverlay } from './DeleteHPAModal';
diff --git a/frontend/packages/operator-lifecycle-manager/src/components/clusterserviceversion.tsx b/frontend/packages/operator-lifecycle-manager/src/components/clusterserviceversion.tsx
index d3063fa3e8f..fa793b4381c 100644
--- a/frontend/packages/operator-lifecycle-manager/src/components/clusterserviceversion.tsx
+++ b/frontend/packages/operator-lifecycle-manager/src/components/clusterserviceversion.tsx
@@ -240,7 +240,7 @@ const ManagedNamespaces: FC = ({ obj }) => {
};
const ConsolePlugins: FC = ({ csvPlugins, trusted }) => {
- const launchOverlay = useOverlay();
+ const launchModal = useOverlay();
const console: WatchK8sResource = {
kind: referenceForModel(ConsoleOperatorConfigModel),
isList: false,
@@ -275,7 +275,7 @@ const ConsolePlugins: FC = ({ csvPlugins, trusted }) => {
type="button"
isInline
onClick={() =>
- launchOverlay(ConsolePluginModalOverlay, {
+ launchModal(ConsolePluginModalOverlay, {
consoleOperatorConfig,
pluginName,
trusted,
From 355cb66d935c8b9655ea05e5562825e2f732670a Mon Sep 17 00:00:00 2001
From: Steve Goodwin
Date: Tue, 3 Feb 2026 18:11:08 -0500
Subject: [PATCH 4/7] Include launchModal in dependency array
---
.../packages/console-app/src/actions/creators/hpa-factory.ts | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/frontend/packages/console-app/src/actions/creators/hpa-factory.ts b/frontend/packages/console-app/src/actions/creators/hpa-factory.ts
index 3779c8add13..f6129b4efaa 100644
--- a/frontend/packages/console-app/src/actions/creators/hpa-factory.ts
+++ b/frontend/packages/console-app/src/actions/creators/hpa-factory.ts
@@ -113,9 +113,7 @@ export const useHPAActions = (kindObj: K8sKind, resource: K8sResourceKind) => {
},
},
];
- // Missing launchModal dependency causes max depth exceeded error
- // eslint-disable-next-line react-hooks/exhaustive-deps
- }, [kindObj, relatedHPAs, resource, supportsHPA]);
+ }, [kindObj, launchModal, relatedHPAs, resource, supportsHPA]);
const result = useMemo<[Action[], HorizontalPodAutoscalerKind[]]>(() => {
return [actions, relatedHPAs];
From 78ea34a6212e8ae78bc2939b41c76f5511128950 Mon Sep 17 00:00:00 2001
From: Steve Goodwin
Date: Thu, 5 Feb 2026 16:23:17 -0500
Subject: [PATCH 5/7] Revert clusterserviceversion.tsx changes to avoid
conflict with PR #15968
The ConsolePluginModal consumer changes in clusterserviceversion.tsx are
being migrated in PR #15968 (OLM modals migration). This PR should only
focus on the modal component migrations (DeleteHPAModal and ConsolePluginModal).
The file now uses the backwards-compatible consolePluginModal() function
which internally calls the new ConsolePluginModalOverlay pattern.
Assisted by: Claude Code
---
.../src/components/clusterserviceversion.tsx | 6 ++----
1 file changed, 2 insertions(+), 4 deletions(-)
diff --git a/frontend/packages/operator-lifecycle-manager/src/components/clusterserviceversion.tsx b/frontend/packages/operator-lifecycle-manager/src/components/clusterserviceversion.tsx
index fa793b4381c..4657eca88f4 100644
--- a/frontend/packages/operator-lifecycle-manager/src/components/clusterserviceversion.tsx
+++ b/frontend/packages/operator-lifecycle-manager/src/components/clusterserviceversion.tsx
@@ -30,7 +30,6 @@ import {
useAccessReviewAllowed,
useAccessReview,
} from '@console/dynamic-plugin-sdk';
-import { useOverlay } from '@console/dynamic-plugin-sdk/src/app/modal-support/useOverlay';
import { getGroupVersionKindForModel } from '@console/dynamic-plugin-sdk/src/lib-core';
import { Conditions, ConditionTypes } from '@console/internal/components/conditions';
import { ResourceEventStream } from '@console/internal/components/events';
@@ -78,7 +77,7 @@ import { DocumentTitle } from '@console/shared/src/components/document-title/Doc
import { withFallback } from '@console/shared/src/components/error';
import PaneBody from '@console/shared/src/components/layout/PaneBody';
import { ExternalLink } from '@console/shared/src/components/links/ExternalLink';
-import { ConsolePluginModalOverlay } from '@console/shared/src/components/modals/ConsolePluginModal';
+import { consolePluginModal } from '@console/shared/src/components/modals';
import { RedExclamationCircleIcon } from '@console/shared/src/components/status/icons';
import { CONSOLE_OPERATOR_CONFIG_NAME } from '@console/shared/src/constants';
import { useActiveNamespace } from '@console/shared/src/hooks/redux-selectors';
@@ -240,7 +239,6 @@ const ManagedNamespaces: FC = ({ obj }) => {
};
const ConsolePlugins: FC = ({ csvPlugins, trusted }) => {
- const launchModal = useOverlay();
const console: WatchK8sResource = {
kind: referenceForModel(ConsoleOperatorConfigModel),
isList: false,
@@ -275,7 +273,7 @@ const ConsolePlugins: FC = ({ csvPlugins, trusted }) => {
type="button"
isInline
onClick={() =>
- launchModal(ConsolePluginModalOverlay, {
+ consolePluginModal({
consoleOperatorConfig,
pluginName,
trusted,
From aaa11eedda0d30000b5aae84b0e8da70fc4bc9e0 Mon Sep 17 00:00:00 2001
From: Steve Goodwin
Date: Thu, 5 Feb 2026 16:29:46 -0500
Subject: [PATCH 6/7] Fix modal pattern violations to comply with migration
guide
Updated DeleteHPAModal and ConsolePluginModal to follow the patterns
from PR #15939 and the modal-migration-guide.md:
1. Export Pattern: Changed from const + export { } to export const
2. Type Positioning: Moved overlay props types to bottom of files
3. ModalComponentProps: Updated ConsolePluginModalProps to extend it
Changes:
- DeleteHPAModal.tsx: export const pattern, type at bottom
- ConsolePluginModal.tsx: export const pattern, extends ModalComponentProps,
removed explicit cancel/close props, moved overlay props to bottom
Assisted by: Claude Code
---
.../src/components/hpa/DeleteHPAModal.tsx | 12 ++++------
.../components/modals/ConsolePluginModal.tsx | 23 +++++++++----------
2 files changed, 16 insertions(+), 19 deletions(-)
diff --git a/frontend/packages/console-shared/src/components/hpa/DeleteHPAModal.tsx b/frontend/packages/console-shared/src/components/hpa/DeleteHPAModal.tsx
index 600282747e6..d1ecf2b5f0c 100644
--- a/frontend/packages/console-shared/src/components/hpa/DeleteHPAModal.tsx
+++ b/frontend/packages/console-shared/src/components/hpa/DeleteHPAModal.tsx
@@ -90,12 +90,7 @@ const DeleteHPAModal: FC = ({ close, cancel, hpa, workload
);
};
-type DeleteHPAModalOverlayProps = {
- hpa: HorizontalPodAutoscalerKind;
- workload: K8sResourceCommon;
-};
-
-const DeleteHPAModalOverlay: OverlayComponent = (props) => {
+export const DeleteHPAModalOverlay: OverlayComponent = (props) => {
return (
= (pro
);
};
-export { DeleteHPAModalOverlay };
+type DeleteHPAModalOverlayProps = {
+ hpa: HorizontalPodAutoscalerKind;
+ workload: K8sResourceCommon;
+};
diff --git a/frontend/packages/console-shared/src/components/modals/ConsolePluginModal.tsx b/frontend/packages/console-shared/src/components/modals/ConsolePluginModal.tsx
index 205bc0b97cf..b1f05bff180 100644
--- a/frontend/packages/console-shared/src/components/modals/ConsolePluginModal.tsx
+++ b/frontend/packages/console-shared/src/components/modals/ConsolePluginModal.tsx
@@ -6,6 +6,7 @@ import {
ModalBody,
ModalSubmitFooter,
ModalWrapper,
+ ModalComponentProps,
} from '@console/internal/components/factory/modal';
import { ConsoleOperatorConfigModel } from '@console/internal/models';
import { k8sPatch, K8sResourceKind } from '@console/internal/module/k8s';
@@ -71,14 +72,9 @@ export const ConsolePluginModal = (props: ConsolePluginModalProps) => {
);
};
-type ConsolePluginModalOverlayProps = {
- consoleOperatorConfig: K8sResourceKind;
- csvPluginsCount?: number;
- pluginName: string;
- trusted: boolean;
-};
-
-const ConsolePluginModalOverlay: OverlayComponent = (props) => {
+export const ConsolePluginModalOverlay: OverlayComponent = (
+ props,
+) => {
return (
void;
- close?: () => void;
-};
+} & ModalComponentProps;
From f405e086a0fa5ea0efd80be6cdb1bacdf5083bf3 Mon Sep 17 00:00:00 2001
From: Steve Goodwin
Date: Tue, 10 Feb 2026 14:34:08 -0500
Subject: [PATCH 7/7] Add lazy loading to modals and remove duplicate types
---
.../console-app/src/actions/creators/hpa-factory.ts | 4 ++--
.../src/components/hpa/DeleteHPAModal.tsx | 9 ++-------
.../console-shared/src/components/hpa/index.ts | 9 +++++++++
.../src/components/modals/ConsolePluginModal.tsx | 11 +----------
.../console-shared/src/components/modals/index.ts | 9 +++++++++
.../src/components/clusterserviceversion.tsx | 7 +++++--
6 files changed, 28 insertions(+), 21 deletions(-)
diff --git a/frontend/packages/console-app/src/actions/creators/hpa-factory.ts b/frontend/packages/console-app/src/actions/creators/hpa-factory.ts
index f6129b4efaa..83fa37b106f 100644
--- a/frontend/packages/console-app/src/actions/creators/hpa-factory.ts
+++ b/frontend/packages/console-app/src/actions/creators/hpa-factory.ts
@@ -15,7 +15,7 @@ import {
ClusterServiceVersionModel,
ClusterServiceVersionKind,
} from '@console/operator-lifecycle-manager';
-import { DeleteHPAModalOverlay } from '@console/shared/src/components/hpa/DeleteHPAModal';
+import { LazyDeleteHPAModalOverlay } from '@console/shared/src/components/hpa';
import { isHelmResource } from '@console/shared/src/utils/helm-utils';
import { doesHpaMatch } from '@console/shared/src/utils/hpa-utils';
import { isOperatorBackedService } from '@console/shared/src/utils/operator-utils';
@@ -100,7 +100,7 @@ export const useHPAActions = (kindObj: K8sKind, resource: K8sResourceKind) => {
label: i18next.t('console-app~Remove HorizontalPodAutoscaler'),
insertBefore: 'delete-pdb',
cta: () => {
- launchModal(DeleteHPAModalOverlay, {
+ launchModal(LazyDeleteHPAModalOverlay, {
workload: resource,
hpa: relatedHPAs[0],
});
diff --git a/frontend/packages/console-shared/src/components/hpa/DeleteHPAModal.tsx b/frontend/packages/console-shared/src/components/hpa/DeleteHPAModal.tsx
index d1ecf2b5f0c..b1d02c0c514 100644
--- a/frontend/packages/console-shared/src/components/hpa/DeleteHPAModal.tsx
+++ b/frontend/packages/console-shared/src/components/hpa/DeleteHPAModal.tsx
@@ -20,11 +20,6 @@ import {
K8sResourceCommon,
} from '@console/internal/module/k8s';
-type DeleteHPAModalProps = ModalComponentProps & {
- hpa: HorizontalPodAutoscalerKind;
- workload: K8sResourceCommon;
-};
-
const DeleteHPAModal: FC = ({ close, cancel, hpa, workload }) => {
const [submitError, setSubmitError] = useState(null);
const [isSubmitting, setIsSubmitting] = useState(false);
@@ -90,7 +85,7 @@ const DeleteHPAModal: FC = ({ close, cancel, hpa, workload
);
};
-export const DeleteHPAModalOverlay: OverlayComponent = (props) => {
+export const DeleteHPAModalOverlay: OverlayComponent = (props) => {
return (
);
};
-type DeleteHPAModalOverlayProps = {
+type DeleteHPAModalProps = ModalComponentProps & {
hpa: HorizontalPodAutoscalerKind;
workload: K8sResourceCommon;
};
diff --git a/frontend/packages/console-shared/src/components/hpa/index.ts b/frontend/packages/console-shared/src/components/hpa/index.ts
index eb289f99ea4..43a3b40d153 100644
--- a/frontend/packages/console-shared/src/components/hpa/index.ts
+++ b/frontend/packages/console-shared/src/components/hpa/index.ts
@@ -1 +1,10 @@
+import { lazy } from 'react';
+
export { DeleteHPAModalOverlay } from './DeleteHPAModal';
+
+// Lazy-loaded OverlayComponent for DeleteHPAModal
+export const LazyDeleteHPAModalOverlay = lazy(() =>
+ import('./DeleteHPAModal' /* webpackChunkName: "delete-hpa-modal" */).then((m) => ({
+ default: m.DeleteHPAModalOverlay,
+ })),
+);
diff --git a/frontend/packages/console-shared/src/components/modals/ConsolePluginModal.tsx b/frontend/packages/console-shared/src/components/modals/ConsolePluginModal.tsx
index b1f05bff180..f9f1225a226 100644
--- a/frontend/packages/console-shared/src/components/modals/ConsolePluginModal.tsx
+++ b/frontend/packages/console-shared/src/components/modals/ConsolePluginModal.tsx
@@ -72,9 +72,7 @@ export const ConsolePluginModal = (props: ConsolePluginModalProps) => {
);
};
-export const ConsolePluginModalOverlay: OverlayComponent = (
- props,
-) => {
+export const ConsolePluginModalOverlay: OverlayComponent = (props) => {
return (
+ import('./ConsolePluginModal' /* webpackChunkName: "console-plugin-modal" */).then((m) => ({
+ default: m.ConsolePluginModalOverlay,
+ })),
+);
+
export const consolePluginModal = (props) =>
import('./ConsolePluginModal' /* webpackChunkName: "shared-modals" */).then((m) =>
m.ConsolePluginModalOverlay(props),
diff --git a/frontend/packages/operator-lifecycle-manager/src/components/clusterserviceversion.tsx b/frontend/packages/operator-lifecycle-manager/src/components/clusterserviceversion.tsx
index 4657eca88f4..73598429b05 100644
--- a/frontend/packages/operator-lifecycle-manager/src/components/clusterserviceversion.tsx
+++ b/frontend/packages/operator-lifecycle-manager/src/components/clusterserviceversion.tsx
@@ -30,6 +30,7 @@ import {
useAccessReviewAllowed,
useAccessReview,
} from '@console/dynamic-plugin-sdk';
+import { useOverlay } from '@console/dynamic-plugin-sdk/src/app/modal-support/useOverlay';
import { getGroupVersionKindForModel } from '@console/dynamic-plugin-sdk/src/lib-core';
import { Conditions, ConditionTypes } from '@console/internal/components/conditions';
import { ResourceEventStream } from '@console/internal/components/events';
@@ -77,7 +78,7 @@ import { DocumentTitle } from '@console/shared/src/components/document-title/Doc
import { withFallback } from '@console/shared/src/components/error';
import PaneBody from '@console/shared/src/components/layout/PaneBody';
import { ExternalLink } from '@console/shared/src/components/links/ExternalLink';
-import { consolePluginModal } from '@console/shared/src/components/modals';
+import { LazyConsolePluginModalOverlay } from '@console/shared/src/components/modals';
import { RedExclamationCircleIcon } from '@console/shared/src/components/status/icons';
import { CONSOLE_OPERATOR_CONFIG_NAME } from '@console/shared/src/constants';
import { useActiveNamespace } from '@console/shared/src/hooks/redux-selectors';
@@ -246,6 +247,7 @@ const ConsolePlugins: FC = ({ csvPlugins, trusted }) => {
};
const [consoleOperatorConfig] = useK8sWatchResource(console);
const { t } = useTranslation();
+ const launchModal = useOverlay();
const [canPatchConsoleOperatorConfig] = useAccessReview({
group: ConsoleOperatorConfigModel.apiGroup,
resource: ConsoleOperatorConfigModel.plural,
@@ -273,8 +275,9 @@ const ConsolePlugins: FC = ({ csvPlugins, trusted }) => {
type="button"
isInline
onClick={() =>
- consolePluginModal({
+ launchModal(LazyConsolePluginModalOverlay, {
consoleOperatorConfig,
+ csvPluginsCount,
pluginName,
trusted,
})