Skip to content

Commit 234ba09

Browse files
committed
Migrate DeleteResourceModal and router-dependent modals to React Router v6
Update DeleteResourceModal, dev-console actions, and helm-plugin actions from history.push() to useNavigate() for React Router v7 compatibility. Assisted by: Claude Code
1 parent a00af1a commit 234ba09

7 files changed

Lines changed: 122 additions & 81 deletions

File tree

frontend/packages/console-shared/src/components/modals/DeleteResourceModal.tsx

Lines changed: 33 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2,29 +2,20 @@ import type { FC } from 'react';
22
import { TextInputTypes } from '@patternfly/react-core';
33
import { Formik, FormikProps, FormikValues } from 'formik';
44
import { useTranslation, Trans } from 'react-i18next';
5+
import { useNavigate } from 'react-router-dom-v5-compat';
6+
import type { OverlayComponent } from '@console/dynamic-plugin-sdk/src/app/modal-support/OverlayProvider';
57
import {
6-
createModalLauncher,
78
ModalTitle,
89
ModalBody,
910
ModalSubmitFooter,
11+
ModalWrapper,
1012
} from '@console/internal/components/factory/modal';
11-
import { history } from '@console/internal/components/utils/router';
13+
import type { ModalComponentProps } from '@console/internal/components/factory/modal';
1214
import { K8sResourceKind } from '@console/internal/module/k8s';
1315
import { usePromiseHandler } from '../../hooks/promise-handler';
1416
import { InputField } from '../formik-fields';
1517
import { YellowExclamationTriangleIcon } from '../status';
1618

17-
type DeleteResourceModalProps = {
18-
resourceName: string;
19-
resourceType: string;
20-
actionLabel?: string; // Used to send translated strings as action label.
21-
actionLabelKey?: string; // Used to send translation key for action label.
22-
redirect?: string;
23-
onSubmit: (values: FormikValues) => Promise<K8sResourceKind[]>;
24-
cancel?: () => void;
25-
close?: () => void;
26-
};
27-
2819
const DeleteResourceForm: FC<FormikProps<FormikValues> & DeleteResourceModalProps> = ({
2920
handleSubmit,
3021
resourceName,
@@ -73,6 +64,7 @@ const DeleteResourceForm: FC<FormikProps<FormikValues> & DeleteResourceModalProp
7364

7465
const DeleteResourceModal: FC<DeleteResourceModalProps> = (props) => {
7566
const [handlePromise] = usePromiseHandler();
67+
const navigate = useNavigate();
7668

7769
const handleSubmit = (values: FormikValues, actions) => {
7870
const { onSubmit, close, redirect } = props;
@@ -82,7 +74,9 @@ const DeleteResourceModal: FC<DeleteResourceModalProps> = (props) => {
8274
handlePromise(onSubmit(values))
8375
.then(() => {
8476
close();
85-
redirect && history.push(redirect);
77+
if (redirect) {
78+
navigate(redirect);
79+
}
8680
})
8781
.catch((errorMessage) => {
8882
actions.setStatus({ submitError: errorMessage });
@@ -101,6 +95,28 @@ const DeleteResourceModal: FC<DeleteResourceModalProps> = (props) => {
10195
);
10296
};
10397

104-
export const deleteResourceModal = createModalLauncher((props: DeleteResourceModalProps) => (
105-
<DeleteResourceModal {...props} />
106-
));
98+
export const DeleteResourceModalOverlay: OverlayComponent<DeleteResourceModalProps> = (props) => {
99+
return (
100+
<ModalWrapper blocking onClose={props.closeOverlay}>
101+
<DeleteResourceModal
102+
close={props.closeOverlay}
103+
cancel={props.closeOverlay}
104+
resourceName={props.resourceName}
105+
resourceType={props.resourceType}
106+
actionLabel={props.actionLabel}
107+
actionLabelKey={props.actionLabelKey}
108+
redirect={props.redirect}
109+
onSubmit={props.onSubmit}
110+
/>
111+
</ModalWrapper>
112+
);
113+
};
114+
115+
type DeleteResourceModalProps = ModalComponentProps & {
116+
resourceName: string;
117+
resourceType: string;
118+
actionLabel?: string; // Used to send translated strings as action label.
119+
actionLabelKey?: string; // Used to send translation key for action label.
120+
redirect?: string;
121+
onSubmit: (values: FormikValues) => Promise<K8sResourceKind[]>;
122+
};
Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
1+
import { lazy } from 'react';
2+
13
export const consolePluginModal = (props) =>
24
import('./ConsolePluginModal' /* webpackChunkName: "shared-modals" */).then((m) =>
35
m.consolePluginModal(props),
46
);
57

6-
export const deleteResourceModal = (props) =>
7-
import('./DeleteResourceModal' /* webpackChunkName: "shared-modals" */).then((m) =>
8-
m.deleteResourceModal(props),
9-
);
8+
export const LazyDeleteResourceModalOverlay = lazy(() =>
9+
import('./DeleteResourceModal' /* webpackChunkName: "delete-resource-modal" */).then((m) => ({
10+
default: m.DeleteResourceModalOverlay,
11+
})),
12+
);

frontend/packages/dev-console/src/actions/context-menu.ts

Lines changed: 32 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,49 @@
11
import { useMemo } from 'react';
2-
import i18next from 'i18next';
32
import { useTranslation } from 'react-i18next';
43
import { Action, K8sModel } from '@console/dynamic-plugin-sdk';
54
import { useOverlay } from '@console/dynamic-plugin-sdk/src/app/modal-support/useOverlay';
65
import { TopologyApplicationObject } from '@console/dynamic-plugin-sdk/src/extensions/topology-types';
76
import { LazyDeleteModalOverlay } from '@console/internal/components/modals';
87
import { asAccessReview } from '@console/internal/components/utils';
98
import { K8sResourceKind } from '@console/internal/module/k8s';
10-
import { deleteResourceModal } from '@console/shared';
9+
import { LazyDeleteResourceModalOverlay } from '@console/shared';
1110
import { ApplicationModel } from '@console/topology/src/models';
1211
import { cleanUpWorkload } from '@console/topology/src/utils';
1312

14-
export const DeleteApplicationAction = (
13+
export const useDeleteApplicationAction = (
1514
application: TopologyApplicationObject,
1615
resourceModel: K8sModel,
1716
): Action => {
18-
// accessReview needs a resource but group is not a k8s resource,
19-
// so currently picking the first resource to do the rbac checks (might change in future)
20-
const primaryResource = application.resources[0].resource;
21-
return {
22-
id: 'delete-application',
23-
label: i18next.t('devconsole~Delete application'),
24-
cta: () => {
25-
const reqs = [];
26-
deleteResourceModal({
27-
blocking: true,
28-
resourceName: application.name,
29-
resourceType: ApplicationModel.label,
30-
onSubmit: () => {
31-
application.resources.forEach((resource) => {
32-
reqs.push(cleanUpWorkload(resource.resource));
33-
});
34-
return Promise.all(reqs);
35-
},
36-
});
37-
},
38-
accessReview: asAccessReview(resourceModel, primaryResource, 'delete'),
39-
};
17+
const { t } = useTranslation();
18+
const launchModal = useOverlay();
19+
20+
return useMemo(() => {
21+
if (!application?.resources?.[0]?.resource) {
22+
return null;
23+
}
24+
25+
// accessReview needs a resource but group is not a k8s resource,
26+
// so currently picking the first resource to do the rbac checks (might change in future)
27+
const primaryResource = application.resources[0].resource;
28+
return {
29+
id: 'delete-application',
30+
label: t('devconsole~Delete application'),
31+
cta: () => {
32+
const reqs = [];
33+
launchModal(LazyDeleteResourceModalOverlay, {
34+
resourceName: application.name,
35+
resourceType: ApplicationModel.label,
36+
onSubmit: () => {
37+
application.resources.forEach((resource) => {
38+
reqs.push(cleanUpWorkload(resource.resource));
39+
});
40+
return Promise.all(reqs);
41+
},
42+
});
43+
},
44+
accessReview: asAccessReview(resourceModel, primaryResource, 'delete'),
45+
};
46+
}, [application, resourceModel, t, launchModal]);
4047
};
4148

4249
export const useDeleteResourceAction = (

frontend/packages/dev-console/src/actions/providers.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ import {
3636
ADD_TO_PROJECT,
3737
} from '../const';
3838
import { AddActions, disabledActionsFilter } from './add-resources';
39-
import { DeleteApplicationAction } from './context-menu';
39+
import { useDeleteApplicationAction } from './context-menu';
4040
import { EditImportApplication } from './creators';
4141

4242
type TopologyActionProvider = (data: {
@@ -297,6 +297,7 @@ export const useTopologyApplicationActionProvider: TopologyActionProvider = ({
297297
);
298298
const primaryResource = appData.resources?.[0]?.resource || {};
299299
const [kindObj, inFlight] = useK8sModel(referenceFor(primaryResource));
300+
const deleteApplicationAction = useDeleteApplicationAction(appData, kindObj);
300301

301302
return useMemo(() => {
302303
if (element.getType() === TYPE_APPLICATION_GROUP) {
@@ -307,7 +308,7 @@ export const useTopologyApplicationActionProvider: TopologyActionProvider = ({
307308
? `${referenceFor(sourceObj)}/${sourceObj?.metadata?.name}`
308309
: undefined;
309310
const actions = [
310-
...(connectorSource ? [] : [DeleteApplicationAction(appData, kindObj)]),
311+
...(connectorSource ? [] : [deleteApplicationAction]),
311312
AddActions.FromGit(namespace, application, sourceReference, path, !isImportResourceAccess),
312313
AddActions.ContainerImage(
313314
namespace,
@@ -354,13 +355,12 @@ export const useTopologyApplicationActionProvider: TopologyActionProvider = ({
354355
element,
355356
inFlight,
356357
connectorSource,
357-
appData,
358-
kindObj,
359358
namespace,
360359
application,
361360
isImportResourceAccess,
362361
isCatalogImageResourceAccess,
363362
isServerlessEnabled,
364363
isJavaImageStreamEnabled,
364+
deleteApplicationAction,
365365
]);
366366
};

frontend/packages/helm-plugin/src/actions/creators.ts

Lines changed: 40 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,52 @@
1+
import { useMemo } from 'react';
12
import { TFunction } from 'i18next';
23
import { Action, K8sKind } from '@console/dynamic-plugin-sdk';
4+
import { useOverlay } from '@console/dynamic-plugin-sdk/src/app/modal-support/useOverlay';
35
import { coFetchJSON } from '@console/internal/co-fetch';
46
import { K8sResourceKind, referenceFor } from '@console/internal/module/k8s';
5-
import { deleteResourceModal } from '@console/shared';
7+
import { LazyDeleteResourceModalOverlay } from '@console/shared';
68
import { ProjectHelmChartRepositoryModel } from '../models';
79
import { HelmActionsScope } from './types';
810

9-
export const getHelmDeleteAction = (
10-
{
11-
release: { name: releaseName, namespace, version: releaseVersion },
12-
redirect,
13-
}: HelmActionsScope,
14-
t: TFunction,
15-
): Action => ({
16-
id: 'delete-helm',
17-
label: t('helm-plugin~Delete Helm Release'),
18-
cta: () => {
19-
deleteResourceModal({
20-
blocking: true,
21-
resourceName: releaseName,
22-
resourceType: 'Helm Release',
23-
actionLabel: t('helm-plugin~Delete'),
11+
export const useHelmDeleteAction = (scope: HelmActionsScope, t: TFunction): Action => {
12+
const launchModal = useOverlay();
13+
14+
return useMemo(() => {
15+
if (!scope?.release) {
16+
return {
17+
id: 'delete-helm',
18+
label: t('helm-plugin~Delete Helm Release'),
19+
cta: () => {},
20+
};
21+
}
22+
23+
const {
24+
release: { name: releaseName, namespace, version: releaseVersion },
2425
redirect,
25-
onSubmit: () => {
26-
return coFetchJSON.delete(
27-
`/api/helm/release/async?name=${releaseName}&ns=${namespace}&version=${releaseVersion}`,
28-
null,
29-
null,
30-
-1,
31-
);
26+
} = scope;
27+
28+
return {
29+
id: 'delete-helm',
30+
label: t('helm-plugin~Delete Helm Release'),
31+
cta: () => {
32+
launchModal(LazyDeleteResourceModalOverlay, {
33+
resourceName: releaseName,
34+
resourceType: 'Helm Release',
35+
actionLabel: t('helm-plugin~Delete'),
36+
redirect,
37+
onSubmit: () => {
38+
return coFetchJSON.delete(
39+
`/api/helm/release/async?name=${releaseName}&ns=${namespace}&version=${releaseVersion}`,
40+
null,
41+
null,
42+
-1,
43+
);
44+
},
45+
});
3246
},
33-
});
34-
},
35-
});
47+
};
48+
}, [scope, t, launchModal]);
49+
};
3650

3751
export const getHelmUpgradeAction = (
3852
{ release: { name: releaseName, namespace }, actionOrigin }: HelmActionsScope,

frontend/packages/helm-plugin/src/actions/providers.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import { TYPE_HELM_RELEASE } from '../topology/components/const';
1717
import { HelmReleaseStatus } from '../types/helm-types';
1818
import { AddHelmChartAction } from './add-resources';
1919
import {
20-
getHelmDeleteAction,
20+
useHelmDeleteAction,
2121
getHelmRollbackAction,
2222
getHelmUpgradeAction,
2323
editChartRepository,
@@ -26,25 +26,26 @@ import { HelmActionsScope } from './types';
2626

2727
export const useHelmActionProvider = (scope: HelmActionsScope) => {
2828
const { t } = useTranslation();
29+
const helmDeleteAction = useHelmDeleteAction(scope, t);
2930
const result = useMemo(() => {
3031
if (!scope) return [[], true, undefined];
3132
switch (scope?.release?.info?.status) {
3233
case HelmReleaseStatus.PendingInstall:
3334
case HelmReleaseStatus.PendingRollback:
3435
case HelmReleaseStatus.PendingUpgrade:
35-
return [[getHelmDeleteAction(scope, t)], true, undefined];
36+
return [[helmDeleteAction], true, undefined];
3637
default:
3738
return [
3839
[
3940
getHelmUpgradeAction(scope, t),
4041
...(Number(scope.release.version) > 1 ? [getHelmRollbackAction(scope, t)] : []),
41-
getHelmDeleteAction(scope, t),
42+
helmDeleteAction,
4243
],
4344
true,
4445
undefined,
4546
];
4647
}
47-
}, [scope, t]);
48+
}, [scope, t, helmDeleteAction]);
4849
return result;
4950
};
5051

frontend/packages/helm-plugin/src/actions/types.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,5 @@ type HelmActionObj = {
1010
export type HelmActionsScope = {
1111
release: HelmRelease | HelmActionObj;
1212
actionOrigin?: string;
13-
redirect?: boolean;
13+
redirect?: string;
1414
};

0 commit comments

Comments
 (0)