Provisioning: Add option to keep resources when deleting repository (#109955)

* Provisioning: Add option to keep deleted repository resources

* Use existing repository

* Update confirm modal

* Update text
This commit is contained in:
Alex Khomenko
2025-08-22 13:20:03 +03:00
committed by GitHub
parent 6976ac4caa
commit 3e79ccabe9
4 changed files with 96 additions and 30 deletions
@@ -1,50 +1,116 @@
import { useCallback, useEffect, useState } from 'react'; import { useCallback, useEffect, useState } from 'react';
import { useNavigate } from 'react-router-dom-v5-compat'; import { useNavigate } from 'react-router-dom-v5-compat';
import { t } from '@grafana/i18n'; import { t, Trans } from '@grafana/i18n';
import { ConfirmModal, IconButton } from '@grafana/ui'; import { Button, ConfirmModal, Dropdown, Icon, Menu, Stack } from '@grafana/ui';
import { useDeleteRepositoryMutation } from 'app/api/clients/provisioning/v0alpha1'; import {
Repository,
useDeleteRepositoryMutation,
useReplaceRepositoryMutation,
} from 'app/api/clients/provisioning/v0alpha1';
type DeleteAction = 'remove-resources' | 'keep-resources';
interface Props { interface Props {
name: string; name: string;
repository: Repository;
redirectTo?: string; redirectTo?: string;
} }
export function DeleteRepositoryButton({ name, redirectTo }: Props) { export function DeleteRepositoryButton({ name, repository, redirectTo }: Props) {
const [deleteRepository, request] = useDeleteRepositoryMutation(); const [deleteRepository, deleteRequest] = useDeleteRepositoryMutation();
const [replaceRepository, replaceRequest] = useReplaceRepositoryMutation();
const [showModal, setShowModal] = useState(false); const [showModal, setShowModal] = useState(false);
const [selectedAction, setSelectedAction] = useState<DeleteAction>('remove-resources');
const navigate = useNavigate(); const navigate = useNavigate();
useEffect(() => { useEffect(() => {
if (request.isSuccess) { if (deleteRequest.isSuccess) {
setShowModal(false); setShowModal(false);
if (redirectTo) { if (redirectTo) {
navigate(redirectTo); navigate(redirectTo);
} }
} }
}, [request.isSuccess, redirectTo, navigate]); }, [deleteRequest.isSuccess, redirectTo, navigate]);
const onConfirm = useCallback(() => { const onConfirm = useCallback(async () => {
if (selectedAction === 'keep-resources' && repository) {
const updatedRepository = {
...repository,
metadata: {
...repository.metadata,
finalizers: ['cleanup', 'release-orphan-resources'],
},
};
await replaceRepository({ name, repository: updatedRepository });
}
deleteRepository({ name }); deleteRepository({ name });
}, [deleteRepository, name]); }, [deleteRepository, replaceRepository, name, selectedAction, repository]);
const getConfirmationMessage = () => {
if (selectedAction === 'remove-resources') {
return t(
'provisioning.delete-repository-button.confirm-delete-with-resources',
'Are you sure you want to delete the repository configuration and all its resources?'
);
}
return t(
'provisioning.delete-repository-button.confirm-delete-keep-resources',
'Are you sure you want to delete the repository configuration but keep its resources?'
);
};
const getModalTitle = () => {
if (selectedAction === 'remove-resources') {
return t(
'provisioning.delete-repository-button.title-delete-repository-and-resources',
'Delete repository configuration and resources'
);
}
return t(
'provisioning.delete-repository-button.title-delete-repository-only',
'Delete repository configuration only'
);
};
const isLoading = deleteRequest.isLoading || replaceRequest.isLoading;
return ( return (
<> <>
<IconButton <Dropdown
name="trash-alt" overlay={
tooltip={t('provisioning.delete-repository-button.tooltip-delete-this-repository', 'Delete this repository')} <Menu>
disabled={request.isLoading} <Menu.Item
onClick={() => { label={t(
setShowModal(true); 'provisioning.delete-repository-button.delete-and-remove-resources',
}} 'Delete and remove resources (default)'
/> )}
onClick={() => {
setSelectedAction('remove-resources');
setShowModal(true);
}}
/>
<Menu.Item
label={t('provisioning.delete-repository-button.delete-and-keep-resources', 'Delete and keep resources')}
onClick={() => {
setSelectedAction('keep-resources');
setShowModal(true);
}}
/>
</Menu>
}
>
<Button variant="destructive" icon="trash-alt" disabled={isLoading}>
<Stack alignItems="center">
<Trans i18nKey="provisioning.delete-repository-button.delete">Delete</Trans>
<Icon name={'angle-down'} />
</Stack>
</Button>
</Dropdown>
<ConfirmModal <ConfirmModal
isOpen={showModal} isOpen={showModal}
title={t('provisioning.delete-repository-button.title-delete-repository', 'Delete repository config')} title={getModalTitle()}
body={t( body={getConfirmationMessage()}
'provisioning.delete-repository-button.confirm-delete-repository',
'Are you sure you want to delete the repository config?'
)}
confirmText={t('provisioning.delete-repository-button.button-delete', 'Delete')} confirmText={t('provisioning.delete-repository-button.button-delete', 'Delete')}
onConfirm={onConfirm} onConfirm={onConfirm}
onDismiss={() => setShowModal(false)} onDismiss={() => setShowModal(false)}
@@ -37,7 +37,7 @@ export function RepositoryActions({ repository }: RepositoryActionsProps) {
<LinkButton variant="secondary" icon="cog" href={`${PROVISIONING_URL}/${name}/edit`}> <LinkButton variant="secondary" icon="cog" href={`${PROVISIONING_URL}/${name}/edit`}>
<Trans i18nKey="provisioning.repository-actions.settings">Settings</Trans> <Trans i18nKey="provisioning.repository-actions.settings">Settings</Trans>
</LinkButton> </LinkButton>
<DeleteRepositoryButton name={name} redirectTo={PROVISIONING_URL} /> <DeleteRepositoryButton name={name} repository={repository} redirectTo={PROVISIONING_URL} />
</Stack> </Stack>
); );
} }
@@ -9,7 +9,6 @@ import { StatusBadge } from '../Shared/StatusBadge';
import { PROVISIONING_URL } from '../constants'; import { PROVISIONING_URL } from '../constants';
import { getIsReadOnlyWorkflows } from '../utils/repository'; import { getIsReadOnlyWorkflows } from '../utils/repository';
import { DeleteRepositoryButton } from './DeleteRepositoryButton';
import { SyncRepository } from './SyncRepository'; import { SyncRepository } from './SyncRepository';
interface Props { interface Props {
@@ -109,9 +108,6 @@ export function RepositoryCard({ repository }: Props) {
</LinkButton> </LinkButton>
</Stack> </Stack>
</Card.Actions> </Card.Actions>
<Card.SecondaryActions>
<DeleteRepositoryButton name={name} />
</Card.SecondaryActions>
</Card> </Card>
); );
} }
+7 -3
View File
@@ -11254,11 +11254,15 @@
}, },
"delete-repository-button": { "delete-repository-button": {
"button-delete": "Delete", "button-delete": "Delete",
"confirm-delete-repository": "Are you sure you want to delete the repository config?", "confirm-delete-keep-resources": "Are you sure you want to delete the repository configuration but keep its resources?",
"confirm-delete-with-resources": "Are you sure you want to delete the repository configuration and all its resources?",
"delete": "Delete",
"delete-and-keep-resources": "Delete and keep resources",
"delete-and-remove-resources": "Delete and remove resources (default)",
"error-repository-delete": "Failed to delete repository", "error-repository-delete": "Failed to delete repository",
"success-repository-deleted": "Repository settings queued for deletion", "success-repository-deleted": "Repository settings queued for deletion",
"title-delete-repository": "Delete repository config", "title-delete-repository-and-resources": "Delete repository configuration and resources",
"tooltip-delete-this-repository": "Delete this repository" "title-delete-repository-only": "Delete repository configuration only"
}, },
"edit-repository-page": { "edit-repository-page": {
"back-to-repositories": "Back to repositories", "back-to-repositories": "Back to repositories",