E2C: Hook Cloud Receiver-side up to real CreateCloudMigrationToken API (#85490)

E2C: Hook Cloud Reciever-side up to real CreateCloudMigrationToken API
This commit is contained in:
Josh Hunt
2024-04-03 09:55:38 +01:00
committed by GitHub
parent ff39067605
commit ffb5d23a13
5 changed files with 85 additions and 72 deletions

View File

@@ -3,43 +3,54 @@ import React, { useId } from 'react';
import { Modal, Button, Input, Stack, ClipboardButton, Field } from '@grafana/ui';
import { Trans, t } from 'app/core/internationalization';
import { TokenErrorAlert } from '../TokenErrorAlert';
interface Props {
hideModal: () => void;
migrationToken: string;
migrationToken?: string;
}
export const MigrationTokenModal = ({ hideModal, migrationToken }: Props) => {
const inputId = useId();
return (
<Modal
isOpen
title={t('migrate-to-cloud.migration-token.modal-title', 'Migration token created')}
onDismiss={hideModal}
>
<Field
description={t(
'migrate-to-cloud.migration-token.modal-field-description',
'Copy the token now as you will not be able to see it again. Losing a token requires creating a new one.'
)}
htmlFor={inputId}
label={t('migrate-to-cloud.migration-token.modal-field-label', 'Token')}
>
<Stack>
<Input id={inputId} value={migrationToken} readOnly />
<ClipboardButton icon="clipboard-alt" getText={() => migrationToken}>
<Trans i18nKey="migrate-to-cloud.migration-token.modal-copy-button">Copy to clipboard</Trans>
</ClipboardButton>
</Stack>
</Field>
{migrationToken ? <TokenSuccessContent migrationToken={migrationToken} /> : <TokenErrorAlert />}
<Modal.ButtonRow>
<Button variant="secondary" onClick={hideModal}>
<Trans i18nKey="migrate-to-cloud.migration-token.modal-close">Close</Trans>
</Button>
<ClipboardButton variant="primary" getText={() => migrationToken} onClipboardCopy={hideModal}>
<Trans i18nKey="migrate-to-cloud.migration-token.modal-copy-and-close">Copy to clipboard and close</Trans>
</ClipboardButton>
{migrationToken && (
<ClipboardButton variant="primary" getText={() => migrationToken} onClipboardCopy={hideModal}>
<Trans i18nKey="migrate-to-cloud.migration-token.modal-copy-and-close">Copy to clipboard and close</Trans>
</ClipboardButton>
)}
</Modal.ButtonRow>
</Modal>
);
};
function TokenSuccessContent({ migrationToken }: { migrationToken: string }) {
const inputId = useId();
return (
<Field
description={t(
'migrate-to-cloud.migration-token.modal-field-description',
'Copy the token now as you will not be able to see it again. Losing a token requires creating a new one.'
)}
htmlFor={inputId}
label={t('migrate-to-cloud.migration-token.modal-field-label', 'Token')}
>
<Stack>
<Input id={inputId} value={migrationToken} readOnly />
<ClipboardButton icon="clipboard-alt" getText={() => migrationToken}>
<Trans i18nKey="migrate-to-cloud.migration-token.modal-copy-button">Copy to clipboard</Trans>
</ClipboardButton>
</Stack>
</Field>
);
}

View File

@@ -3,21 +3,20 @@ import React from 'react';
import { Box, Button, ModalsController, Text } from '@grafana/ui';
import { t, Trans } from 'app/core/internationalization';
import {
useCreateMigrationTokenMutationMock,
useDeleteMigrationTokenMutationMock,
useHasMigrationTokenQueryMock,
} from '../../mockAPI';
import { useCreateCloudMigrationTokenMutation } from '../../api';
import { InfoItem } from '../../shared/InfoItem';
import { TokenErrorAlert } from '../TokenErrorAlert';
import { DeleteMigrationTokenModal } from './DeleteMigrationTokenModal';
import { MigrationTokenModal } from './MigrationTokenModal';
import { TokenStatus } from './TokenStatus';
export const MigrationTokenPane = () => {
const { data: hasToken, isFetching } = useHasMigrationTokenQueryMock();
const [createToken, createTokenResponse] = useCreateMigrationTokenMutationMock();
const [deleteToken, deleteTokenResponse] = useDeleteMigrationTokenMutationMock();
const isFetchingStatus = false; // TODO: No API for this yet
const [createToken, createTokenResponse] = useCreateCloudMigrationTokenMutation();
const hasToken = Boolean(createTokenResponse.data?.token);
const isLoading = isFetchingStatus || createTokenResponse.isLoading; /* || deleteTokenResponse.isLoading */
return (
<ModalsController>
@@ -29,46 +28,33 @@ export const MigrationTokenPane = () => {
cloud stack.
</Trans>
</InfoItem>
<Text color="secondary">
<Trans i18nKey="migrate-to-cloud.migration-token.status">
Current status:{' '}
<TokenStatus
hasToken={Boolean(hasToken)}
isFetching={isFetching || createTokenResponse.isLoading || deleteTokenResponse.isLoading}
/>
</Trans>
</Text>
{hasToken ? (
<Button
variant="destructive"
onClick={() =>
showModal(DeleteMigrationTokenModal, {
hideModal,
onConfirm: deleteToken,
})
}
disabled={isFetching || deleteTokenResponse.isLoading}
>
<Trans i18nKey="migrate-to-cloud.migration-token.delete-button">Delete this migration token</Trans>
</Button>
{createTokenResponse?.isError ? (
<TokenErrorAlert />
) : (
<Button
disabled={createTokenResponse.isLoading || isFetching}
onClick={async () => {
const response = await createToken();
if ('data' in response) {
showModal(MigrationTokenModal, {
hideModal,
migrationToken: response.data.token,
});
}
}}
>
{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>
<Text color="secondary">
<Trans i18nKey="migrate-to-cloud.migration-token.status">
Current status: <TokenStatus hasToken={hasToken} isFetching={isLoading} />
</Trans>
</Text>
)}
<Button
disabled={isLoading || hasToken}
onClick={async () => {
const response = await createToken();
if ('data' in response) {
showModal(MigrationTokenModal, {
hideModal,
migrationToken: response.data.token,
});
}
}}
>
{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>
)}
</ModalsController>

View File

@@ -0,0 +1,14 @@
import React from 'react';
import { Alert } from '@grafana/ui';
import { Trans, t } from 'app/core/internationalization';
export function TokenErrorAlert() {
return (
<Alert severity="error" title={t('migrate-to-cloud.migration-token.error-title', 'Something went wrong')}>
<Trans i18nKey="migrate-to-cloud.migration-token.error-body">
Unable to generate a migration token. Please try again later.
</Trans>
</Alert>
);
}

View File

@@ -753,12 +753,13 @@
},
"migration-token": {
"body": "Your self-managed Grafana instance will require a special authentication token to securely connect to this cloud stack.",
"delete-button": "Delete this migration 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",
"delete-modal-deleting": "Deleting...",
"delete-modal-title": "Delete migration token",
"error-body": "Unable to generate a migration token. Please try again later.",
"error-title": "Something went wrong",
"generate-button": "Generate a migration token",
"generate-button-loading": "Generating a migration token...",
"modal-close": "Close",
@@ -767,7 +768,7 @@
"modal-field-description": "Copy the token now as you will not be able to see it again. Losing a token requires creating a new one.",
"modal-field-label": "Token",
"modal-title": "Migration token created",
"status": "Current status: <2></2>",
"status": "Current status: <1></1>",
"title": "Migration token"
},
"pdc": {

View File

@@ -753,12 +753,13 @@
},
"migration-token": {
"body": "Ÿőūř şęľƒ-mäʼnäģęđ Ğřäƒäʼnä įʼnşŧäʼnčę ŵįľľ řęqūįřę ä şpęčįäľ äūŧĥęʼnŧįčäŧįőʼn ŧőĸęʼn ŧő şęčūřęľy čőʼnʼnęčŧ ŧő ŧĥįş čľőūđ şŧäčĸ.",
"delete-button": "Đęľęŧę ŧĥįş mįģřäŧįőʼn ŧőĸęʼ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": "Đęľęŧę",
"delete-modal-deleting": "Đęľęŧįʼnģ...",
"delete-modal-title": "Đęľęŧę mįģřäŧįőʼn ŧőĸęʼn",
"error-body": "Ůʼnäþľę ŧő ģęʼnęřäŧę ä mįģřäŧįőʼn ŧőĸęʼn. Pľęäşę ŧřy äģäįʼn ľäŧęř.",
"error-title": "Ŝőmęŧĥįʼnģ ŵęʼnŧ ŵřőʼnģ",
"generate-button": "Ğęʼnęřäŧę ä mįģřäŧįőʼn ŧőĸęʼn",
"generate-button-loading": "Ğęʼnęřäŧįʼnģ ä mįģřäŧįőʼn ŧőĸęʼn...",
"modal-close": "Cľőşę",
@@ -767,7 +768,7 @@
"modal-field-description": "Cőpy ŧĥę ŧőĸęʼn ʼnőŵ äş yőū ŵįľľ ʼnőŧ þę äþľę ŧő şęę įŧ äģäįʼn. Ŀőşįʼnģ ä ŧőĸęʼn řęqūįřęş čřęäŧįʼnģ ä ʼnęŵ őʼnę.",
"modal-field-label": "Ŧőĸęʼn",
"modal-title": "Mįģřäŧįőʼn ŧőĸęʼn čřęäŧęđ",
"status": "Cūřřęʼnŧ şŧäŧūş: <2></2>",
"status": "Cūřřęʼnŧ şŧäŧūş: <1></1>",
"title": "Mįģřäŧįőʼn ŧőĸęʼn"
},
"pdc": {