Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2,29 +2,20 @@ import type { FC } from 'react';
import { TextInputTypes } from '@patternfly/react-core';
import { Formik, FormikProps, FormikValues } from 'formik';
import { useTranslation, Trans } from 'react-i18next';
import { useNavigate } from 'react-router-dom-v5-compat';
import type { OverlayComponent } from '@console/dynamic-plugin-sdk/src/app/modal-support/OverlayProvider';
import {
createModalLauncher,
ModalTitle,
ModalBody,
ModalSubmitFooter,
ModalWrapper,
} from '@console/internal/components/factory/modal';
import { history } from '@console/internal/components/utils/router';
import type { ModalComponentProps } from '@console/internal/components/factory/modal';
import { K8sResourceKind } from '@console/internal/module/k8s';
import { usePromiseHandler } from '../../hooks/promise-handler';
import { InputField } from '../formik-fields';
import { YellowExclamationTriangleIcon } from '../status';

type DeleteResourceModalProps = {
resourceName: string;
resourceType: string;
actionLabel?: string; // Used to send translated strings as action label.
actionLabelKey?: string; // Used to send translation key for action label.
redirect?: string;
onSubmit: (values: FormikValues) => Promise<K8sResourceKind[]>;
cancel?: () => void;
close?: () => void;
};

const DeleteResourceForm: FC<FormikProps<FormikValues> & DeleteResourceModalProps> = ({
handleSubmit,
resourceName,
Expand Down Expand Up @@ -73,6 +64,7 @@ const DeleteResourceForm: FC<FormikProps<FormikValues> & DeleteResourceModalProp

const DeleteResourceModal: FC<DeleteResourceModalProps> = (props) => {
const [handlePromise] = usePromiseHandler();
const navigate = useNavigate();

const handleSubmit = (values: FormikValues, actions) => {
const { onSubmit, close, redirect } = props;
Expand All @@ -82,7 +74,9 @@ const DeleteResourceModal: FC<DeleteResourceModalProps> = (props) => {
handlePromise(onSubmit(values))
.then(() => {
close();
redirect && history.push(redirect);
if (redirect) {
navigate(redirect);
}
})
.catch((errorMessage) => {
actions.setStatus({ submitError: errorMessage });
Expand All @@ -101,6 +95,28 @@ const DeleteResourceModal: FC<DeleteResourceModalProps> = (props) => {
);
};

export const deleteResourceModal = createModalLauncher((props: DeleteResourceModalProps) => (
<DeleteResourceModal {...props} />
));
export const DeleteResourceModalOverlay: OverlayComponent<DeleteResourceModalProps> = (props) => {
return (
<ModalWrapper blocking onClose={props.closeOverlay}>
<DeleteResourceModal
close={props.closeOverlay}
cancel={props.closeOverlay}
resourceName={props.resourceName}
resourceType={props.resourceType}
actionLabel={props.actionLabel}
actionLabelKey={props.actionLabelKey}
redirect={props.redirect}
onSubmit={props.onSubmit}
/>
</ModalWrapper>
);
};

type DeleteResourceModalProps = ModalComponentProps & {
resourceName: string;
resourceType: string;
actionLabel?: string; // Used to send translated strings as action label.
actionLabelKey?: string; // Used to send translation key for action label.
redirect?: string;
onSubmit: (values: FormikValues) => Promise<K8sResourceKind[]>;
};
11 changes: 7 additions & 4 deletions frontend/packages/console-shared/src/components/modals/index.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
import { lazy } from 'react';

export const consolePluginModal = (props) =>
import('./ConsolePluginModal' /* webpackChunkName: "shared-modals" */).then((m) =>
m.consolePluginModal(props),
);

export const deleteResourceModal = (props) =>
import('./DeleteResourceModal' /* webpackChunkName: "shared-modals" */).then((m) =>
m.deleteResourceModal(props),
);
export const LazyDeleteResourceModalOverlay = lazy(() =>
import('./DeleteResourceModal' /* webpackChunkName: "delete-resource-modal" */).then((m) => ({
default: m.DeleteResourceModalOverlay,
})),
);
57 changes: 32 additions & 25 deletions frontend/packages/dev-console/src/actions/context-menu.ts
Original file line number Diff line number Diff line change
@@ -1,42 +1,49 @@
import { useMemo } from 'react';
import i18next from 'i18next';
import { useTranslation } from 'react-i18next';
import { Action, K8sModel } from '@console/dynamic-plugin-sdk';
import { useOverlay } from '@console/dynamic-plugin-sdk/src/app/modal-support/useOverlay';
import { TopologyApplicationObject } from '@console/dynamic-plugin-sdk/src/extensions/topology-types';
import { LazyDeleteModalOverlay } from '@console/internal/components/modals';
import { asAccessReview } from '@console/internal/components/utils';
import { K8sResourceKind } from '@console/internal/module/k8s';
import { deleteResourceModal } from '@console/shared';
import { LazyDeleteResourceModalOverlay } from '@console/shared';
import { ApplicationModel } from '@console/topology/src/models';
import { cleanUpWorkload } from '@console/topology/src/utils';

export const DeleteApplicationAction = (
export const useDeleteApplicationAction = (
application: TopologyApplicationObject,
resourceModel: K8sModel,
): Action => {
// accessReview needs a resource but group is not a k8s resource,
// so currently picking the first resource to do the rbac checks (might change in future)
const primaryResource = application.resources[0].resource;
return {
id: 'delete-application',
label: i18next.t('devconsole~Delete application'),
cta: () => {
const reqs = [];
deleteResourceModal({
blocking: true,
resourceName: application.name,
resourceType: ApplicationModel.label,
onSubmit: () => {
application.resources.forEach((resource) => {
reqs.push(cleanUpWorkload(resource.resource));
});
return Promise.all(reqs);
},
});
},
accessReview: asAccessReview(resourceModel, primaryResource, 'delete'),
};
const { t } = useTranslation();
const launchModal = useOverlay();

return useMemo(() => {
if (!application?.resources?.[0]?.resource) {
return null;
}

// accessReview needs a resource but group is not a k8s resource,
// so currently picking the first resource to do the rbac checks (might change in future)
const primaryResource = application.resources[0].resource;
return {
id: 'delete-application',
label: t('devconsole~Delete application'),
cta: () => {
const reqs = [];
launchModal(LazyDeleteResourceModalOverlay, {
resourceName: application.name,
resourceType: ApplicationModel.label,
onSubmit: () => {
application.resources.forEach((resource) => {
reqs.push(cleanUpWorkload(resource.resource));
});
return Promise.all(reqs);
},
});
},
accessReview: asAccessReview(resourceModel, primaryResource, 'delete'),
};
}, [application, resourceModel, t, launchModal]);
};

export const useDeleteResourceAction = (
Expand Down
8 changes: 4 additions & 4 deletions frontend/packages/dev-console/src/actions/providers.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ import {
ADD_TO_PROJECT,
} from '../const';
import { AddActions, disabledActionsFilter } from './add-resources';
import { DeleteApplicationAction } from './context-menu';
import { useDeleteApplicationAction } from './context-menu';
import { EditImportApplication } from './creators';

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

return useMemo(() => {
if (element.getType() === TYPE_APPLICATION_GROUP) {
Expand All @@ -307,7 +308,7 @@ export const useTopologyApplicationActionProvider: TopologyActionProvider = ({
? `${referenceFor(sourceObj)}/${sourceObj?.metadata?.name}`
: undefined;
const actions = [
...(connectorSource ? [] : [DeleteApplicationAction(appData, kindObj)]),
...(connectorSource ? [] : [deleteApplicationAction]),
AddActions.FromGit(namespace, application, sourceReference, path, !isImportResourceAccess),
AddActions.ContainerImage(
namespace,
Expand Down Expand Up @@ -354,13 +355,12 @@ export const useTopologyApplicationActionProvider: TopologyActionProvider = ({
element,
inFlight,
connectorSource,
appData,
kindObj,
namespace,
application,
isImportResourceAccess,
isCatalogImageResourceAccess,
isServerlessEnabled,
isJavaImageStreamEnabled,
deleteApplicationAction,
]);
};
66 changes: 40 additions & 26 deletions frontend/packages/helm-plugin/src/actions/creators.ts
Original file line number Diff line number Diff line change
@@ -1,38 +1,52 @@
import { useMemo } from 'react';
import { TFunction } from 'i18next';
import { Action, K8sKind } from '@console/dynamic-plugin-sdk';
import { useOverlay } from '@console/dynamic-plugin-sdk/src/app/modal-support/useOverlay';
import { coFetchJSON } from '@console/internal/co-fetch';
import { K8sResourceKind, referenceFor } from '@console/internal/module/k8s';
import { deleteResourceModal } from '@console/shared';
import { LazyDeleteResourceModalOverlay } from '@console/shared';
import { ProjectHelmChartRepositoryModel } from '../models';
import { HelmActionsScope } from './types';

export const getHelmDeleteAction = (
{
release: { name: releaseName, namespace, version: releaseVersion },
redirect,
}: HelmActionsScope,
t: TFunction,
): Action => ({
id: 'delete-helm',
label: t('helm-plugin~Delete Helm Release'),
cta: () => {
deleteResourceModal({
blocking: true,
resourceName: releaseName,
resourceType: 'Helm Release',
actionLabel: t('helm-plugin~Delete'),
export const useHelmDeleteAction = (scope: HelmActionsScope, t: TFunction): Action => {
const launchModal = useOverlay();

return useMemo(() => {
if (!scope?.release) {
return {
id: 'delete-helm',
label: t('helm-plugin~Delete Helm Release'),
cta: () => {},
};
}

const {
release: { name: releaseName, namespace, version: releaseVersion },
redirect,
onSubmit: () => {
return coFetchJSON.delete(
`/api/helm/release/async?name=${releaseName}&ns=${namespace}&version=${releaseVersion}`,
null,
null,
-1,
);
} = scope;

return {
id: 'delete-helm',
label: t('helm-plugin~Delete Helm Release'),
cta: () => {
launchModal(LazyDeleteResourceModalOverlay, {
resourceName: releaseName,
resourceType: 'Helm Release',
actionLabel: t('helm-plugin~Delete'),
redirect,
onSubmit: () => {
return coFetchJSON.delete(
`/api/helm/release/async?name=${releaseName}&ns=${namespace}&version=${releaseVersion}`,
null,
null,
-1,
);
},
});
},
});
},
});
};
}, [scope, t, launchModal]);
};

export const getHelmUpgradeAction = (
{ release: { name: releaseName, namespace }, actionOrigin }: HelmActionsScope,
Expand Down
9 changes: 5 additions & 4 deletions frontend/packages/helm-plugin/src/actions/providers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import { TYPE_HELM_RELEASE } from '../topology/components/const';
import { HelmReleaseStatus } from '../types/helm-types';
import { AddHelmChartAction } from './add-resources';
import {
getHelmDeleteAction,
useHelmDeleteAction,
getHelmRollbackAction,
getHelmUpgradeAction,
editChartRepository,
Expand All @@ -26,25 +26,26 @@ import { HelmActionsScope } from './types';

export const useHelmActionProvider = (scope: HelmActionsScope) => {
const { t } = useTranslation();
const helmDeleteAction = useHelmDeleteAction(scope, t);
const result = useMemo(() => {
if (!scope) return [[], true, undefined];
switch (scope?.release?.info?.status) {
case HelmReleaseStatus.PendingInstall:
case HelmReleaseStatus.PendingRollback:
case HelmReleaseStatus.PendingUpgrade:
return [[getHelmDeleteAction(scope, t)], true, undefined];
return [[helmDeleteAction], true, undefined];
default:
return [
[
getHelmUpgradeAction(scope, t),
...(Number(scope.release.version) > 1 ? [getHelmRollbackAction(scope, t)] : []),
getHelmDeleteAction(scope, t),
helmDeleteAction,
],
true,
undefined,
];
}
}, [scope, t]);
}, [scope, t, helmDeleteAction]);
return result;
};

Expand Down
2 changes: 1 addition & 1 deletion frontend/packages/helm-plugin/src/actions/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,5 @@ type HelmActionObj = {
export type HelmActionsScope = {
release: HelmRelease | HelmActionObj;
actionOrigin?: string;
redirect?: boolean;
redirect?: string;
};