Skip to content

Commit

Permalink
misc: refactor keys page and add actions
Browse files Browse the repository at this point in the history
  • Loading branch information
ansmonjol committed Nov 14, 2024
1 parent 3d4fd0f commit 02d52c3
Show file tree
Hide file tree
Showing 6 changed files with 688 additions and 152 deletions.
107 changes: 107 additions & 0 deletions src/components/developers/RollApiKeyDialog.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
import { gql } from '@apollo/client'
import { forwardRef, useImperativeHandle, useRef, useState } from 'react'

import { Button, Dialog, DialogRef, Typography } from '~/components/designSystem'
import { addToast } from '~/core/apolloClient'
import { formatDateToTZ } from '~/core/timezone/utils'
import {
ApiKeyForRollApiKeyDialogFragment,
TimezoneEnum,
useRotateApiKeyMutation,
} from '~/generated/graphql'
import { useInternationalization } from '~/hooks/core/useInternationalization'

gql`
fragment ApiKeyForRollApiKeyDialog on SanitizedApiKey {
id
lastUsedAt
}
mutation rotateApiKey($input: RotateApiKeyInput!) {
rotateApiKey(input: $input) {
id
}
}
`

export interface RollApiKeyDialogRef {
openDialog: (data: ApiKeyForRollApiKeyDialogFragment) => unknown
closeDialog: () => unknown
}

export const RollApiKeyDialog = forwardRef<RollApiKeyDialogRef>((_, ref) => {
const { translate } = useInternationalization()
const dialogRef = useRef<DialogRef>(null)
const [localData, setLocalData] = useState<ApiKeyForRollApiKeyDialogFragment | undefined>(
undefined,
)
const [rotateApiKey] = useRotateApiKeyMutation({
onCompleted(data) {
if (!!data?.rotateApiKey?.id) {
addToast({
message: translate('text_1731506310510htbvgegpzd8'),
severity: 'success',
})
}
},
refetchQueries: ['getApiKeys'],
})

useImperativeHandle(ref, () => ({
openDialog: (data) => {
setLocalData(data)
dialogRef.current?.openDialog()
},
closeDialog: () => {
dialogRef.current?.closeDialog()
},
}))

return (
<Dialog
ref={dialogRef}
title={translate('text_173151476175058ugha8fd08')}
description={translate('text_1731514761750dnh1s073j9o')}
actions={({ closeDialog }) => (
<>
<Button variant="quaternary" onClick={closeDialog}>
{translate('text_64352657267c3d916f962769')}
</Button>
<Button
danger
variant="primary"
onClick={async () => {
try {
await rotateApiKey({
variables: { input: { id: localData?.id || '' } },
})

closeDialog()
} catch {
addToast({
severity: 'danger',
translateKey: 'text_62b31e1f6a5b8b1b745ece48',
})
}
}}
>
{translate('text_173151476175058ugha8fd08')}
</Button>
</>
)}
>
<div className="mb-8 flex w-full items-center">
<Typography className="w-35" variant="caption" color="grey600">
{translate('text_1731515447290xbe4iqm5n6r')}
</Typography>
<Typography className="flex-1" variant="body" color="grey700">
{!!localData?.lastUsedAt
? formatDateToTZ(localData?.lastUsedAt, TimezoneEnum.TzUtc, 'LLL. dd, yyyy')
: '-'}
</Typography>
</div>
</Dialog>
)
})

RollApiKeyDialog.displayName = 'RollApiKeyDialog'
202 changes: 183 additions & 19 deletions src/generated/graphql.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6590,6 +6590,15 @@ export type DeleteWebhookMutation = { __typename?: 'Mutation', destroyWebhookEnd

export type EventItemFragment = { __typename?: 'Event', id: string, code: string, receivedAt?: any | null, matchBillableMetric?: boolean | null, matchCustomField?: boolean | null };

export type ApiKeyForRollApiKeyDialogFragment = { __typename?: 'SanitizedApiKey', id: string, lastUsedAt?: any | null };

export type RotateApiKeyMutationVariables = Exact<{
input: RotateApiKeyInput;
}>;


export type RotateApiKeyMutation = { __typename?: 'Mutation', rotateApiKey?: { __typename?: 'ApiKey', id: string } | null };

export type WebhookLogDetailsFragment = { __typename?: 'Webhook', id: string, webhookType: string, status: WebhookStatusEnum, payload?: string | null, response?: string | null, httpStatus?: number | null, endpoint: string, retries: number, updatedAt: any };

export type RetryWebhookMutationVariables = Exact<{
Expand Down Expand Up @@ -8341,10 +8350,27 @@ export type GetPortalOrgaInfosQueryVariables = Exact<{ [key: string]: never; }>;

export type GetPortalOrgaInfosQuery = { __typename?: 'Query', customerPortalOrganization?: { __typename?: 'CustomerPortalOrganization', id: string, name: string, logoUrl?: string | null, premiumIntegrations: Array<PremiumIntegrationTypeEnum> } | null };

export type GetOrganizationApiKeyQueryVariables = Exact<{ [key: string]: never; }>;
export type ApiKeyForApiKeysListFragment = { __typename?: 'ApiKey', id: string, createdAt: any, value: string };

export type GetOrganizationInfosForApiKeyQueryVariables = Exact<{ [key: string]: never; }>;


export type GetOrganizationInfosForApiKeyQuery = { __typename?: 'Query', organization?: { __typename?: 'CurrentOrganization', id: string, name: string, createdAt: any } | null };

export type GetApiKeysQueryVariables = Exact<{
page?: InputMaybe<Scalars['Int']['input']>;
limit?: InputMaybe<Scalars['Int']['input']>;
}>;


export type GetOrganizationApiKeyQuery = { __typename?: 'Query', organization?: { __typename?: 'CurrentOrganization', id: string, apiKey?: string | null } | null };
export type GetApiKeysQuery = { __typename?: 'Query', apiKeys: { __typename?: 'SanitizedApiKeyCollection', collection: Array<{ __typename?: 'SanitizedApiKey', id: string, createdAt: any, value: string, lastUsedAt?: any | null }>, metadata: { __typename?: 'CollectionMetadata', currentPage: number, totalPages: number, totalCount: number } } };

export type GetApiKeyValueQueryVariables = Exact<{
id: Scalars['ID']['input'];
}>;


export type GetApiKeyValueQuery = { __typename?: 'Query', apiKey: { __typename?: 'ApiKey', value: string } };

export type EventListFragment = { __typename?: 'Event', id: string, code: string, transactionId?: string | null, timestamp?: any | null, receivedAt?: any | null, payload: any, billableMetricName?: string | null, matchBillableMetric?: boolean | null, matchCustomField?: boolean | null, apiClient?: string | null, ipAddress?: string | null, externalSubscriptionId?: string | null, customerTimezone: TimezoneEnum };

Expand Down Expand Up @@ -9244,6 +9270,12 @@ export const WebhookForCreateAndEditFragmentDoc = gql`
signatureAlgo
}
`;
export const ApiKeyForRollApiKeyDialogFragmentDoc = gql`
fragment ApiKeyForRollApiKeyDialog on SanitizedApiKey {
id
lastUsedAt
}
`;
export const CustomerForDunningEmailFragmentDoc = gql`
fragment CustomerForDunningEmail on Customer {
displayName
Expand Down Expand Up @@ -11192,6 +11224,13 @@ export const HubspotIntegrationInfosForInvoiceOverviewFragmentDoc = gql`
invoicesObjectTypeId
}
`;
export const ApiKeyForApiKeysListFragmentDoc = gql`
fragment ApiKeyForApiKeysList on ApiKey {
id
createdAt
value
}
`;
export const EventItemFragmentDoc = gql`
fragment EventItem on Event {
id
Expand Down Expand Up @@ -14207,6 +14246,39 @@ export function useDeleteWebhookMutation(baseOptions?: Apollo.MutationHookOption
export type DeleteWebhookMutationHookResult = ReturnType<typeof useDeleteWebhookMutation>;
export type DeleteWebhookMutationResult = Apollo.MutationResult<DeleteWebhookMutation>;
export type DeleteWebhookMutationOptions = Apollo.BaseMutationOptions<DeleteWebhookMutation, DeleteWebhookMutationVariables>;
export const RotateApiKeyDocument = gql`
mutation rotateApiKey($input: RotateApiKeyInput!) {
rotateApiKey(input: $input) {
id
}
}
`;
export type RotateApiKeyMutationFn = Apollo.MutationFunction<RotateApiKeyMutation, RotateApiKeyMutationVariables>;

/**
* __useRotateApiKeyMutation__
*
* To run a mutation, you first call `useRotateApiKeyMutation` within a React component and pass it any options that fit your needs.
* When your component renders, `useRotateApiKeyMutation` returns a tuple that includes:
* - A mutate function that you can call at any time to execute the mutation
* - An object with fields that represent the current status of the mutation's execution
*
* @param baseOptions options that will be passed into the mutation, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options-2;
*
* @example
* const [rotateApiKeyMutation, { data, loading, error }] = useRotateApiKeyMutation({
* variables: {
* input: // value for 'input'
* },
* });
*/
export function useRotateApiKeyMutation(baseOptions?: Apollo.MutationHookOptions<RotateApiKeyMutation, RotateApiKeyMutationVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useMutation<RotateApiKeyMutation, RotateApiKeyMutationVariables>(RotateApiKeyDocument, options);
}
export type RotateApiKeyMutationHookResult = ReturnType<typeof useRotateApiKeyMutation>;
export type RotateApiKeyMutationResult = Apollo.MutationResult<RotateApiKeyMutation>;
export type RotateApiKeyMutationOptions = Apollo.BaseMutationOptions<RotateApiKeyMutation, RotateApiKeyMutationVariables>;
export const RetryWebhookDocument = gql`
mutation retryWebhook($input: RetryWebhookInput!) {
retryWebhook(input: $input) {
Expand Down Expand Up @@ -22206,46 +22278,138 @@ export type GetPortalOrgaInfosQueryHookResult = ReturnType<typeof useGetPortalOr
export type GetPortalOrgaInfosLazyQueryHookResult = ReturnType<typeof useGetPortalOrgaInfosLazyQuery>;
export type GetPortalOrgaInfosSuspenseQueryHookResult = ReturnType<typeof useGetPortalOrgaInfosSuspenseQuery>;
export type GetPortalOrgaInfosQueryResult = Apollo.QueryResult<GetPortalOrgaInfosQuery, GetPortalOrgaInfosQueryVariables>;
export const GetOrganizationApiKeyDocument = gql`
query getOrganizationApiKey {
export const GetOrganizationInfosForApiKeyDocument = gql`
query getOrganizationInfosForApiKey {
organization {
id
apiKey
name
createdAt
}
}
`;

/**
* __useGetOrganizationApiKeyQuery__
* __useGetOrganizationInfosForApiKeyQuery__
*
* To run a query within a React component, call `useGetOrganizationApiKeyQuery` and pass it any options that fit your needs.
* When your component renders, `useGetOrganizationApiKeyQuery` returns an object from Apollo Client that contains loading, error, and data properties
* To run a query within a React component, call `useGetOrganizationInfosForApiKeyQuery` and pass it any options that fit your needs.
* When your component renders, `useGetOrganizationInfosForApiKeyQuery` returns an object from Apollo Client that contains loading, error, and data properties
* you can use to render your UI.
*
* @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options;
*
* @example
* const { data, loading, error } = useGetOrganizationApiKeyQuery({
* const { data, loading, error } = useGetOrganizationInfosForApiKeyQuery({
* variables: {
* },
* });
*/
export function useGetOrganizationApiKeyQuery(baseOptions?: Apollo.QueryHookOptions<GetOrganizationApiKeyQuery, GetOrganizationApiKeyQueryVariables>) {
export function useGetOrganizationInfosForApiKeyQuery(baseOptions?: Apollo.QueryHookOptions<GetOrganizationInfosForApiKeyQuery, GetOrganizationInfosForApiKeyQueryVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useQuery<GetOrganizationInfosForApiKeyQuery, GetOrganizationInfosForApiKeyQueryVariables>(GetOrganizationInfosForApiKeyDocument, options);
}
export function useGetOrganizationInfosForApiKeyLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<GetOrganizationInfosForApiKeyQuery, GetOrganizationInfosForApiKeyQueryVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useLazyQuery<GetOrganizationInfosForApiKeyQuery, GetOrganizationInfosForApiKeyQueryVariables>(GetOrganizationInfosForApiKeyDocument, options);
}
export function useGetOrganizationInfosForApiKeySuspenseQuery(baseOptions?: Apollo.SkipToken | Apollo.SuspenseQueryHookOptions<GetOrganizationInfosForApiKeyQuery, GetOrganizationInfosForApiKeyQueryVariables>) {
const options = baseOptions === Apollo.skipToken ? baseOptions : {...defaultOptions, ...baseOptions}
return Apollo.useSuspenseQuery<GetOrganizationInfosForApiKeyQuery, GetOrganizationInfosForApiKeyQueryVariables>(GetOrganizationInfosForApiKeyDocument, options);
}
export type GetOrganizationInfosForApiKeyQueryHookResult = ReturnType<typeof useGetOrganizationInfosForApiKeyQuery>;
export type GetOrganizationInfosForApiKeyLazyQueryHookResult = ReturnType<typeof useGetOrganizationInfosForApiKeyLazyQuery>;
export type GetOrganizationInfosForApiKeySuspenseQueryHookResult = ReturnType<typeof useGetOrganizationInfosForApiKeySuspenseQuery>;
export type GetOrganizationInfosForApiKeyQueryResult = Apollo.QueryResult<GetOrganizationInfosForApiKeyQuery, GetOrganizationInfosForApiKeyQueryVariables>;
export const GetApiKeysDocument = gql`
query getApiKeys($page: Int, $limit: Int) {
apiKeys(page: $page, limit: $limit) {
collection {
id
createdAt
value
...ApiKeyForRollApiKeyDialog
}
metadata {
currentPage
totalPages
totalCount
}
}
}
${ApiKeyForRollApiKeyDialogFragmentDoc}`;

/**
* __useGetApiKeysQuery__
*
* To run a query within a React component, call `useGetApiKeysQuery` and pass it any options that fit your needs.
* When your component renders, `useGetApiKeysQuery` returns an object from Apollo Client that contains loading, error, and data properties
* you can use to render your UI.
*
* @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options;
*
* @example
* const { data, loading, error } = useGetApiKeysQuery({
* variables: {
* page: // value for 'page'
* limit: // value for 'limit'
* },
* });
*/
export function useGetApiKeysQuery(baseOptions?: Apollo.QueryHookOptions<GetApiKeysQuery, GetApiKeysQueryVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useQuery<GetApiKeysQuery, GetApiKeysQueryVariables>(GetApiKeysDocument, options);
}
export function useGetApiKeysLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<GetApiKeysQuery, GetApiKeysQueryVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useLazyQuery<GetApiKeysQuery, GetApiKeysQueryVariables>(GetApiKeysDocument, options);
}
export function useGetApiKeysSuspenseQuery(baseOptions?: Apollo.SkipToken | Apollo.SuspenseQueryHookOptions<GetApiKeysQuery, GetApiKeysQueryVariables>) {
const options = baseOptions === Apollo.skipToken ? baseOptions : {...defaultOptions, ...baseOptions}
return Apollo.useSuspenseQuery<GetApiKeysQuery, GetApiKeysQueryVariables>(GetApiKeysDocument, options);
}
export type GetApiKeysQueryHookResult = ReturnType<typeof useGetApiKeysQuery>;
export type GetApiKeysLazyQueryHookResult = ReturnType<typeof useGetApiKeysLazyQuery>;
export type GetApiKeysSuspenseQueryHookResult = ReturnType<typeof useGetApiKeysSuspenseQuery>;
export type GetApiKeysQueryResult = Apollo.QueryResult<GetApiKeysQuery, GetApiKeysQueryVariables>;
export const GetApiKeyValueDocument = gql`
query getApiKeyValue($id: ID!) {
apiKey(id: $id) {
value
}
}
`;

/**
* __useGetApiKeyValueQuery__
*
* To run a query within a React component, call `useGetApiKeyValueQuery` and pass it any options that fit your needs.
* When your component renders, `useGetApiKeyValueQuery` returns an object from Apollo Client that contains loading, error, and data properties
* you can use to render your UI.
*
* @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options;
*
* @example
* const { data, loading, error } = useGetApiKeyValueQuery({
* variables: {
* id: // value for 'id'
* },
* });
*/
export function useGetApiKeyValueQuery(baseOptions: Apollo.QueryHookOptions<GetApiKeyValueQuery, GetApiKeyValueQueryVariables> & ({ variables: GetApiKeyValueQueryVariables; skip?: boolean; } | { skip: boolean; }) ) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useQuery<GetOrganizationApiKeyQuery, GetOrganizationApiKeyQueryVariables>(GetOrganizationApiKeyDocument, options);
return Apollo.useQuery<GetApiKeyValueQuery, GetApiKeyValueQueryVariables>(GetApiKeyValueDocument, options);
}
export function useGetOrganizationApiKeyLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<GetOrganizationApiKeyQuery, GetOrganizationApiKeyQueryVariables>) {
export function useGetApiKeyValueLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<GetApiKeyValueQuery, GetApiKeyValueQueryVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useLazyQuery<GetOrganizationApiKeyQuery, GetOrganizationApiKeyQueryVariables>(GetOrganizationApiKeyDocument, options);
return Apollo.useLazyQuery<GetApiKeyValueQuery, GetApiKeyValueQueryVariables>(GetApiKeyValueDocument, options);
}
export function useGetOrganizationApiKeySuspenseQuery(baseOptions?: Apollo.SkipToken | Apollo.SuspenseQueryHookOptions<GetOrganizationApiKeyQuery, GetOrganizationApiKeyQueryVariables>) {
export function useGetApiKeyValueSuspenseQuery(baseOptions?: Apollo.SkipToken | Apollo.SuspenseQueryHookOptions<GetApiKeyValueQuery, GetApiKeyValueQueryVariables>) {
const options = baseOptions === Apollo.skipToken ? baseOptions : {...defaultOptions, ...baseOptions}
return Apollo.useSuspenseQuery<GetOrganizationApiKeyQuery, GetOrganizationApiKeyQueryVariables>(GetOrganizationApiKeyDocument, options);
return Apollo.useSuspenseQuery<GetApiKeyValueQuery, GetApiKeyValueQueryVariables>(GetApiKeyValueDocument, options);
}
export type GetOrganizationApiKeyQueryHookResult = ReturnType<typeof useGetOrganizationApiKeyQuery>;
export type GetOrganizationApiKeyLazyQueryHookResult = ReturnType<typeof useGetOrganizationApiKeyLazyQuery>;
export type GetOrganizationApiKeySuspenseQueryHookResult = ReturnType<typeof useGetOrganizationApiKeySuspenseQuery>;
export type GetOrganizationApiKeyQueryResult = Apollo.QueryResult<GetOrganizationApiKeyQuery, GetOrganizationApiKeyQueryVariables>;
export type GetApiKeyValueQueryHookResult = ReturnType<typeof useGetApiKeyValueQuery>;
export type GetApiKeyValueLazyQueryHookResult = ReturnType<typeof useGetApiKeyValueLazyQuery>;
export type GetApiKeyValueSuspenseQueryHookResult = ReturnType<typeof useGetApiKeyValueSuspenseQuery>;
export type GetApiKeyValueQueryResult = Apollo.QueryResult<GetApiKeyValueQuery, GetApiKeyValueQueryVariables>;
export const EventsDocument = gql`
query events($page: Int, $limit: Int) {
events(page: $page, limit: $limit) {
Expand Down
Loading

0 comments on commit 02d52c3

Please sign in to comment.