mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
E2C: Delete cloud migration token (#90548)
This commit is contained in:
parent
f8645f73ea
commit
9a06510490
@ -8,13 +8,17 @@ export const cloudMigrationAPI = generatedAPI.enhanceEndpoints({
|
||||
|
||||
endpoints: {
|
||||
// Cloud-side - create token
|
||||
getCloudMigrationToken(endpoint) {
|
||||
suppressErrorsOnQuery(endpoint);
|
||||
endpoint.providesTags = ['cloud-migration-token'];
|
||||
},
|
||||
createCloudMigrationToken(endpoint) {
|
||||
suppressErrorsOnQuery(endpoint);
|
||||
endpoint.invalidatesTags = ['cloud-migration-token'];
|
||||
},
|
||||
getCloudMigrationToken(endpoint) {
|
||||
deleteCloudMigrationToken(endpoint) {
|
||||
suppressErrorsOnQuery(endpoint);
|
||||
endpoint.providesTags = ['cloud-migration-token'];
|
||||
endpoint.invalidatesTags = ['cloud-migration-token'];
|
||||
},
|
||||
|
||||
// List Cloud Configs
|
||||
|
@ -11,7 +11,7 @@ interface Props {
|
||||
migrationToken?: string;
|
||||
}
|
||||
|
||||
export const MigrationTokenModal = ({ isOpen, hideModal, migrationToken }: Props) => {
|
||||
export const CreateTokenModal = ({ isOpen, hideModal, migrationToken }: Props) => {
|
||||
return (
|
||||
<Modal
|
||||
isOpen={isOpen}
|
@ -0,0 +1,42 @@
|
||||
import { Alert, ConfirmModal } from '@grafana/ui';
|
||||
import { Trans, t } from 'app/core/internationalization';
|
||||
|
||||
interface DeleteTokenConfirmationModalProps {
|
||||
isOpen: boolean;
|
||||
hasError: boolean;
|
||||
onConfirm: () => void;
|
||||
onDismiss: () => void;
|
||||
}
|
||||
|
||||
export function DeleteTokenConfirmationModal(props: DeleteTokenConfirmationModalProps) {
|
||||
const { isOpen, hasError, onConfirm, onDismiss } = props;
|
||||
|
||||
const body = (
|
||||
<>
|
||||
<p>
|
||||
<Trans i18nKey="migrate-to-cloud.delete-migration-token-confirm.body">
|
||||
If you've already used this token with a self-managed installation, that installation will no longer be
|
||||
able to upload content.
|
||||
</Trans>
|
||||
</p>
|
||||
|
||||
{hasError && (
|
||||
<Alert
|
||||
severity="error"
|
||||
title={t('migrate-to-cloud.delete-migration-token-confirm.error-title', 'Error deleting token')}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
|
||||
return (
|
||||
<ConfirmModal
|
||||
isOpen={isOpen}
|
||||
title={t('migrate-to-cloud.delete-migration-token-confirm.title', 'Delete migration token')}
|
||||
body={body}
|
||||
confirmText={t('migrate-to-cloud.delete-migration-token-confirm.confirm-button', 'Delete token')}
|
||||
onConfirm={onConfirm}
|
||||
onDismiss={onDismiss}
|
||||
/>
|
||||
);
|
||||
}
|
@ -4,10 +4,15 @@ import { isFetchError } from '@grafana/runtime';
|
||||
import { Box, Button, Text } from '@grafana/ui';
|
||||
import { t, Trans } from 'app/core/internationalization';
|
||||
|
||||
import { useCreateCloudMigrationTokenMutation, useGetCloudMigrationTokenQuery } from '../../api';
|
||||
import {
|
||||
useCreateCloudMigrationTokenMutation,
|
||||
useDeleteCloudMigrationTokenMutation,
|
||||
useGetCloudMigrationTokenQuery,
|
||||
} from '../../api';
|
||||
import { TokenErrorAlert } from '../TokenErrorAlert';
|
||||
|
||||
import { MigrationTokenModal } from './MigrationTokenModal';
|
||||
import { CreateTokenModal } from './CreateTokenModal';
|
||||
import { DeleteTokenConfirmationModal } from './DeleteTokenConfirmationModal';
|
||||
import { TokenStatus } from './TokenStatus';
|
||||
|
||||
// TODO: candidate to hoist and share
|
||||
@ -29,22 +34,41 @@ function maybeAPIError(err: unknown) {
|
||||
}
|
||||
|
||||
export const MigrationTokenPane = () => {
|
||||
const [showModal, setShowModal] = useState(false);
|
||||
const [showCreateModal, setShowCreateModal] = useState(false);
|
||||
const [showDeleteModal, setShowDeleteModal] = useState(false);
|
||||
|
||||
const getTokenQuery = useGetCloudMigrationTokenQuery();
|
||||
const [createTokenMutation, createTokenResponse] = useCreateCloudMigrationTokenMutation();
|
||||
const [deleteTokenMutation, deleteTokenResponse] = useDeleteCloudMigrationTokenMutation();
|
||||
|
||||
const getTokenQueryError = maybeAPIError(getTokenQuery.error);
|
||||
|
||||
const hasToken = Boolean(createTokenResponse.data?.token) || Boolean(getTokenQuery.data?.id);
|
||||
// GetCloudMigrationToken returns a 404 error if no token exists.
|
||||
// When a token is deleted and the GetCloudMigrationToken query is refreshed, RTKQ will retain
|
||||
// both the last successful data ("we have a token!") AND the new error. So we need to explicitly
|
||||
// check that we don't have an error AND that we have a token.
|
||||
const hasToken = Boolean(getTokenQuery.data?.id) && getTokenQueryError?.statusCode !== 404;
|
||||
const isLoading = getTokenQuery.isFetching || createTokenResponse.isLoading;
|
||||
|
||||
const handleGenerateToken = useCallback(async () => {
|
||||
const resp = await createTokenMutation();
|
||||
|
||||
if (!('error' in resp)) {
|
||||
setShowModal(true);
|
||||
setShowCreateModal(true);
|
||||
}
|
||||
}, [createTokenMutation]);
|
||||
|
||||
const handleDeleteToken = useCallback(async () => {
|
||||
if (!getTokenQuery.data?.id) {
|
||||
return;
|
||||
}
|
||||
|
||||
const resp = await deleteTokenMutation({ uid: getTokenQuery.data.id });
|
||||
if (!('error' in resp)) {
|
||||
setShowDeleteModal(false);
|
||||
}
|
||||
}, [deleteTokenMutation, getTokenQuery.data]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Box display="flex" alignItems="flex-start" direction="column" gap={2}>
|
||||
@ -59,18 +83,31 @@ export const MigrationTokenPane = () => {
|
||||
</Text>
|
||||
)}
|
||||
|
||||
<Button disabled={isLoading || hasToken} onClick={handleGenerateToken}>
|
||||
{createTokenResponse.isLoading
|
||||
? t('migrate-to-cloud.migration-token.generate-button-loading', 'Generating a migration token...')
|
||||
: t('migrate-to-cloud.migration-token.generate-button', 'Generate a migration token')}
|
||||
</Button>
|
||||
{hasToken ? (
|
||||
<Button onClick={() => setShowDeleteModal(true)} variant="destructive">
|
||||
{t('migrate-to-cloud.migration-token.delete-button', 'Delete token')}
|
||||
</Button>
|
||||
) : (
|
||||
<Button disabled={isLoading} onClick={handleGenerateToken}>
|
||||
{createTokenResponse.isLoading
|
||||
? t('migrate-to-cloud.migration-token.generate-button-loading', 'Generating a migration token...')
|
||||
: t('migrate-to-cloud.migration-token.generate-button', 'Generate a migration token')}
|
||||
</Button>
|
||||
)}
|
||||
</Box>
|
||||
|
||||
<MigrationTokenModal
|
||||
isOpen={showModal}
|
||||
hideModal={() => setShowModal(false)}
|
||||
<CreateTokenModal
|
||||
isOpen={showCreateModal}
|
||||
hideModal={() => setShowCreateModal(false)}
|
||||
migrationToken={createTokenResponse.data?.token}
|
||||
/>
|
||||
|
||||
<DeleteTokenConfirmationModal
|
||||
isOpen={showDeleteModal}
|
||||
onConfirm={handleDeleteToken}
|
||||
onDismiss={() => setShowDeleteModal(false)}
|
||||
hasError={Boolean(deleteTokenResponse.error)}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
@ -995,6 +995,12 @@
|
||||
"button": "Migrate this instance to Cloud",
|
||||
"header": "Let us manage your Grafana stack"
|
||||
},
|
||||
"delete-migration-token-confirm": {
|
||||
"body": "If you've already used this token with a self-managed installation, that installation will no longer be able to upload content.",
|
||||
"confirm-button": "Delete token",
|
||||
"error-title": "Error deleting token",
|
||||
"title": "Delete migration token"
|
||||
},
|
||||
"disconnect-modal": {
|
||||
"body": "This will remove the migration token from this installation. If you wish to upload more resources in the future, you will need to enter a new migration token.",
|
||||
"cancel": "Cancel",
|
||||
@ -1025,6 +1031,7 @@
|
||||
"title": "Let us help you migrate to this stack"
|
||||
},
|
||||
"migration-token": {
|
||||
"delete-button": "Delete token",
|
||||
"delete-modal-body": "If you've already used this token with a self-managed installation, that installation will no longer be able to upload content.",
|
||||
"delete-modal-cancel": "Cancel",
|
||||
"delete-modal-confirm": "Delete",
|
||||
|
@ -995,6 +995,12 @@
|
||||
"button": "Mįģřäŧę ŧĥįş įʼnşŧäʼnčę ŧő Cľőūđ",
|
||||
"header": "Ŀęŧ ūş mäʼnäģę yőūř Ğřäƒäʼnä şŧäčĸ"
|
||||
},
|
||||
"delete-migration-token-confirm": {
|
||||
"body": "Ĩƒ yőū'vę äľřęäđy ūşęđ ŧĥįş ŧőĸęʼn ŵįŧĥ ä şęľƒ-mäʼnäģęđ įʼnşŧäľľäŧįőʼn, ŧĥäŧ įʼnşŧäľľäŧįőʼn ŵįľľ ʼnő ľőʼnģęř þę äþľę ŧő ūpľőäđ čőʼnŧęʼnŧ.",
|
||||
"confirm-button": "Đęľęŧę ŧőĸęʼn",
|
||||
"error-title": "Ēřřőř đęľęŧįʼnģ ŧőĸęʼn",
|
||||
"title": "Đęľęŧę mįģřäŧįőʼn ŧőĸęʼn"
|
||||
},
|
||||
"disconnect-modal": {
|
||||
"body": "Ŧĥįş ŵįľľ řęmővę ŧĥę mįģřäŧįőʼn ŧőĸęʼn ƒřőm ŧĥįş įʼnşŧäľľäŧįőʼn. Ĩƒ yőū ŵįşĥ ŧő ūpľőäđ mőřę řęşőūřčęş įʼn ŧĥę ƒūŧūřę, yőū ŵįľľ ʼnęęđ ŧő ęʼnŧęř ä ʼnęŵ mįģřäŧįőʼn ŧőĸęʼn.",
|
||||
"cancel": "Cäʼnčęľ",
|
||||
@ -1025,6 +1031,7 @@
|
||||
"title": "Ŀęŧ ūş ĥęľp yőū mįģřäŧę ŧő ŧĥįş şŧäčĸ"
|
||||
},
|
||||
"migration-token": {
|
||||
"delete-button": "Đęľęŧę ŧőĸęʼn",
|
||||
"delete-modal-body": "Ĩƒ yőū'vę äľřęäđy ūşęđ ŧĥįş ŧőĸęʼn ŵįŧĥ ä şęľƒ-mäʼnäģęđ įʼnşŧäľľäŧįőʼn, ŧĥäŧ įʼnşŧäľľäŧįőʼn ŵįľľ ʼnő ľőʼnģęř þę äþľę ŧő ūpľőäđ čőʼnŧęʼnŧ.",
|
||||
"delete-modal-cancel": "Cäʼnčęľ",
|
||||
"delete-modal-confirm": "Đęľęŧę",
|
||||
|
Loading…
Reference in New Issue
Block a user