diff --git a/apps/studio/components/interfaces/Account/AccessTokens/AccessTokenList.tsx b/apps/studio/components/interfaces/Account/AccessTokens/AccessTokenList.tsx index 8ca560cbf6d..72de6b84163 100644 --- a/apps/studio/components/interfaces/Account/AccessTokens/AccessTokenList.tsx +++ b/apps/studio/components/interfaces/Account/AccessTokens/AccessTokenList.tsx @@ -1,4 +1,4 @@ -import { MoreVertical, Trash } from 'lucide-react' +import { Key, MoreVertical, Trash } from 'lucide-react' import { parseAsStringLiteral, useQueryState } from 'nuqs' import { useMemo, useState } from 'react' import { toast } from 'sonner' @@ -22,6 +22,7 @@ import { RowLoading } from './AccessTokenTable/RowLoading' import { TableContainer } from './AccessTokenTable/TableContainer' import { ExpiresCell, LastUsedCell, TokenNameCell } from './AccessTokenTable/TokenCells' import { useMergedAccessTokens, type MergedAccessToken } from './hooks/useMergedAccessTokens' +import { ViewTokenSheet } from './Scoped/ViewTokenSheet' import { AlertError } from '@/components/ui/AlertError' import { useAccessTokenDeleteMutation } from '@/data/access-tokens/access-tokens-delete-mutation' import { useScopedAccessTokenDeleteMutation } from '@/data/scoped-access-tokens/scoped-access-tokens-delete-mutation' @@ -39,16 +40,14 @@ export const AccessTokenList = ({ onDeleteSuccess, }: AccessTokenListProps) => { const track = useTrack() - const [isDeleteOpen, setIsDeleteOpen] = useState(false) - const [token, setToken] = useState(undefined) + const [tokenToShow, setTokenToShow] = useState(undefined) + const [tokenToDelete, setTokenToDelete] = useState(undefined) const [sort, setSort] = useQueryState( 'sort', parseAsStringLiteral(ACCESS_TOKEN_SORT_VALUES).withDefault('created_at:desc') ) - const { tokens, error, isLoading, isError } = useMergedAccessTokens({ - scopedTokensEnabled, - }) + const { tokens, error, isLoading, isError } = useMergedAccessTokens({ scopedTokensEnabled }) const { mutate: deleteClassicToken, isPending: isPendingClassicToken } = useAccessTokenDeleteMutation({ @@ -56,7 +55,7 @@ export const AccessTokenList = ({ track('access_token_removed', { tokenType: 'classic' }) onDeleteSuccess(vars.id) toast.success('Successfully deleted access token') - setIsDeleteOpen(false) + setTokenToDelete(undefined) }, onError: (error) => { toast.error(`Failed to delete access token: ${error.message}`) @@ -69,7 +68,7 @@ export const AccessTokenList = ({ track('access_token_removed', { tokenType: 'scoped' }) onDeleteSuccess(vars.id) toast.success('Successfully deleted access token') - setIsDeleteOpen(false) + setTokenToDelete(undefined) }, onError: (error) => { toast.error(`Failed to delete access token: ${error.message}`) @@ -88,9 +87,9 @@ export const AccessTokenList = ({ const empty = filteredTokens?.length === 0 && !isLoading const handleConfirmDelete = () => { - if (!token) return - if (token.kind === 'classic') deleteClassicToken({ id: token.id }) - else deleteScopedToken({ id: token.id }) + if (!tokenToDelete) return + if (tokenToDelete.kind === 'classic') deleteClassicToken({ id: tokenToDelete.id as number }) + else deleteScopedToken({ id: tokenToDelete.id as string }) } if (isError) { @@ -158,13 +157,13 @@ export const AccessTokenList = ({ /> - { - setToken(x) - setIsDeleteOpen(true) - }} - > + {x.kind === 'scoped' && ( + setTokenToShow(x)}> + +

View permissions

+
+ )} + setTokenToDelete(x)}>

Delete token

@@ -177,19 +176,26 @@ export const AccessTokenList = ({ setIsDeleteOpen(false)} + onCancel={() => setTokenToDelete(undefined)} onConfirm={handleConfirmDelete} loading={isPendingClassicToken || isPendingScopedToken} >

- This action cannot be undone. Are you sure you want to delete "{token?.name}" token? + This action cannot be undone. Are you sure you want to delete "{tokenToDelete?.name}" + token?

+ + setTokenToShow(undefined)} + tokenId={tokenToShow ? String(tokenToShow.id) : undefined} + /> ) } diff --git a/apps/studio/components/interfaces/Account/AccessTokens/hooks/useMergedAccessTokens.ts b/apps/studio/components/interfaces/Account/AccessTokens/hooks/useMergedAccessTokens.ts index f6484df7bef..3a4c14854ab 100644 --- a/apps/studio/components/interfaces/Account/AccessTokens/hooks/useMergedAccessTokens.ts +++ b/apps/studio/components/interfaces/Account/AccessTokens/hooks/useMergedAccessTokens.ts @@ -30,10 +30,10 @@ interface UseMergedAccessTokensOptions { * the consuming list (via filterAndSortTokens), so this only merges + tags. */ export const useMergedAccessTokens = ({ - scopedTokensEnabled: scopedEnabled, + scopedTokensEnabled, }: UseMergedAccessTokensOptions = {}) => { const classic = useAccessTokensQuery() - const scoped = useScopedAccessTokensQuery({ enabled: scopedEnabled }) + const scoped = useScopedAccessTokensQuery({ enabled: scopedTokensEnabled }) return useMemo(() => { const classicTokens: MergedAccessToken[] = (classic.data ?? []).map((token) => ({ @@ -47,7 +47,7 @@ export const useMergedAccessTokens = ({ return { tokens: [...classicTokens, ...scopedTokens], // Classic drives the primary states; a scoped fetch that is still loading shouldn't block the list. - isLoading: classic.isPending || (scopedEnabled && scoped.isPending), + isLoading: classic.isPending || (scopedTokensEnabled && scoped.isPending), isError: classic.isError, error: classic.error, isSuccess: classic.isSuccess, @@ -60,6 +60,6 @@ export const useMergedAccessTokens = ({ classic.isSuccess, scoped.data, scoped.isPending, - scopedEnabled, + scopedTokensEnabled, ]) }