feat(tokens): improve delete confirmation dialog (#6651)

This commit is contained in:
Kira Pilot 2023-03-17 10:29:51 -07:00 committed by GitHub
parent db40c29f26
commit 5b07f1e2a3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 88 additions and 39 deletions

View File

@ -6,7 +6,7 @@
"addToken": "Add token",
"deleteToken": {
"delete": "Delete Token",
"deleteCaption": "Are you sure you want to delete this token?<br/><br/><4>{{tokenId}}</4>",
"deleteCaption": "Are you sure you want to permanently delete token <strong><4>{{tokenName}}</4></strong>?",
"deleteSuccess": "Token has been deleted",
"deleteFailure": "Failed to delete token"
}

View File

@ -9,6 +9,7 @@ import { Stack } from "components/Stack/Stack"
import Button from "@material-ui/core/Button"
import { Link as RouterLink } from "react-router-dom"
import AddIcon from "@material-ui/icons/AddOutlined"
import { APIKeyWithOwner } from "api/typesGenerated"
export const TokensPage: FC<PropsWithChildren<unknown>> = () => {
const styles = useStyles()
@ -30,9 +31,9 @@ export const TokensPage: FC<PropsWithChildren<unknown>> = () => {
</Stack>
)
const [tokenIdToDelete, setTokenIdToDelete] = useState<string | undefined>(
undefined,
)
const [tokenToDelete, setTokenToDelete] = useState<
APIKeyWithOwner | undefined
>(undefined)
const {
data: tokens,
@ -60,15 +61,15 @@ export const TokensPage: FC<PropsWithChildren<unknown>> = () => {
isLoading={isFetching}
hasLoaded={isFetched}
getTokensError={getTokensError}
onDelete={(id) => {
setTokenIdToDelete(id)
onDelete={(token) => {
setTokenToDelete(token)
}}
/>
</Section>
<ConfirmDeleteDialog
queryKey={queryKey}
tokenId={tokenIdToDelete}
setTokenId={setTokenIdToDelete}
token={tokenToDelete}
setToken={setTokenToDelete}
/>
</>
)

View File

@ -28,7 +28,7 @@ export interface TokensPageViewProps {
getTokensError?: Error | unknown
isLoading: boolean
hasLoaded: boolean
onDelete: (id: string) => void
onDelete: (token: APIKeyWithOwner) => void
deleteTokenError?: Error | unknown
}
@ -114,7 +114,7 @@ export const TokensPageView: FC<
<span style={{ color: theme.palette.text.secondary }}>
<IconButton
onClick={() => {
onDelete(token.id)
onDelete(token)
}}
size="medium"
aria-label={t("tokenActions.deleteToken.delete")}

View File

@ -0,0 +1,39 @@
import { Story } from "@storybook/react"
import { MockToken } from "testHelpers/entities"
import {
ConfirmDeleteDialog,
ConfirmDeleteDialogProps,
} from "./ConfirmDeleteDialog"
import { QueryClient, QueryClientProvider } from "@tanstack/react-query"
const queryClient = new QueryClient({
defaultOptions: {
queries: {
retry: false,
cacheTime: 0,
refetchOnWindowFocus: false,
},
},
})
export default {
title: "components/ConfirmDeleteDialog",
component: ConfirmDeleteDialog,
}
const Template: Story<ConfirmDeleteDialogProps> = (
args: ConfirmDeleteDialogProps,
) => (
<QueryClientProvider client={queryClient}>
<ConfirmDeleteDialog {...args} />
</QueryClientProvider>
)
export const DeleteDialog = Template.bind({})
DeleteDialog.args = {
queryKey: ["tokens"],
token: MockToken,
setToken: () => {
return null
},
}

View File

@ -4,24 +4,28 @@ import { useTranslation, Trans } from "react-i18next"
import { useDeleteToken } from "../hooks"
import { displaySuccess, displayError } from "components/GlobalSnackbar/utils"
import { getErrorMessage } from "api/errors"
import { APIKeyWithOwner } from "api/typesGenerated"
export const ConfirmDeleteDialog: FC<{
export interface ConfirmDeleteDialogProps {
queryKey: (string | boolean)[]
tokenId: string | undefined
setTokenId: (arg: string | undefined) => void
}> = ({ queryKey, tokenId, setTokenId }) => {
const { t } = useTranslation("tokensPage")
token: APIKeyWithOwner | undefined
setToken: (arg: APIKeyWithOwner | undefined) => void
}
export const ConfirmDeleteDialog: FC<ConfirmDeleteDialogProps> = ({
queryKey,
token,
setToken,
}) => {
const { t } = useTranslation("tokensPage")
const tokenName = token?.token_name
const description = (
<Trans
t={t}
i18nKey="tokenActions.deleteToken.deleteCaption"
values={{ tokenId }}
values={{ tokenName }}
>
Are you sure you want to delete this token?
<br />
<br />
{{ tokenId }}
Are you sure you want to permanently delete token {{ tokenName }}?
</Trans>
)
@ -30,7 +34,7 @@ export const ConfirmDeleteDialog: FC<{
const onDeleteSuccess = () => {
displaySuccess(t("tokenActions.deleteToken.deleteSuccess"))
setTokenId(undefined)
setToken(undefined)
}
const onDeleteError = (error: unknown) => {
@ -39,26 +43,27 @@ export const ConfirmDeleteDialog: FC<{
t("tokenActions.deleteToken.deleteFailure"),
)
displayError(message)
setTokenId(undefined)
setToken(undefined)
}
return (
<ConfirmDialog
type="delete"
title={t("tokenActions.deleteToken.delete")}
description={description}
open={Boolean(tokenId) || isDeleting}
open={Boolean(token) || isDeleting}
confirmLoading={isDeleting}
onConfirm={() => {
if (!tokenId) {
if (!token) {
return
}
deleteToken(tokenId, {
deleteToken(token.id, {
onError: onDeleteError,
onSuccess: onDeleteSuccess,
})
}}
onClose={() => {
setTokenId(undefined)
setToken(undefined)
}}
/>
)

View File

@ -37,19 +37,22 @@ export const MockAPIKey: TypesGen.GenerateAPIKeyResponse = {
key: "my-api-key",
}
export const MockTokens: TypesGen.APIKey[] = [
{
id: "tBoVE3dqLl",
user_id: "f9ee61d8-1d84-4410-ab6e-c1ec1a641e0b",
last_used: "0001-01-01T00:00:00Z",
expires_at: "2023-01-15T20:10:45.637438Z",
created_at: "2022-12-16T20:10:45.637452Z",
updated_at: "2022-12-16T20:10:45.637452Z",
login_type: "token",
scope: "all",
lifetime_seconds: 2592000,
token_name: "token-one",
},
export const MockToken: TypesGen.APIKeyWithOwner = {
id: "tBoVE3dqLl",
user_id: "f9ee61d8-1d84-4410-ab6e-c1ec1a641e0b",
last_used: "0001-01-01T00:00:00Z",
expires_at: "2023-01-15T20:10:45.637438Z",
created_at: "2022-12-16T20:10:45.637452Z",
updated_at: "2022-12-16T20:10:45.637452Z",
login_type: "token",
scope: "all",
lifetime_seconds: 2592000,
token_name: "token-one",
username: "admin",
}
export const MockTokens: TypesGen.APIKeyWithOwner[] = [
MockToken,
{
id: "tBoVE3dqLl",
user_id: "f9ee61d8-1d84-4410-ab6e-c1ec1a641e0b",
@ -61,6 +64,7 @@ export const MockTokens: TypesGen.APIKey[] = [
scope: "all",
lifetime_seconds: 2592000,
token_name: "token-two",
username: "admin",
},
]