diff --git a/front/src/generated-metadata/gql.ts b/front/src/generated-metadata/gql.ts index ba1c733da..87e608cc6 100644 --- a/front/src/generated-metadata/gql.ts +++ b/front/src/generated-metadata/gql.ts @@ -19,7 +19,7 @@ const documents = { "\n mutation UpdateOneMetadataObject(\n $idToUpdate: ID!\n $updatePayload: UpdateObjectInput!\n ) {\n updateOneObject(input: { id: $idToUpdate, update: $updatePayload }) {\n id\n dataSourceId\n nameSingular\n namePlural\n labelSingular\n labelPlural\n description\n icon\n isCustom\n isActive\n createdAt\n updatedAt\n }\n }\n": types.UpdateOneMetadataObjectDocument, "\n mutation DeleteOneMetadataObject($idToDelete: ID!) {\n deleteOneObject(input: { id: $idToDelete }) {\n id\n dataSourceId\n nameSingular\n namePlural\n labelSingular\n labelPlural\n description\n icon\n isCustom\n isActive\n createdAt\n updatedAt\n }\n }\n": types.DeleteOneMetadataObjectDocument, "\n mutation DeleteOneMetadataField($idToDelete: ID!) {\n deleteOneField(input: { id: $idToDelete }) {\n id\n type\n name\n label\n description\n icon\n placeholder\n isCustom\n isActive\n isNullable\n createdAt\n updatedAt\n }\n }\n": types.DeleteOneMetadataFieldDocument, - "\n query MetadataObjects {\n objects {\n edges {\n node {\n id\n dataSourceId\n nameSingular\n namePlural\n labelSingular\n labelPlural\n description\n icon\n isCustom\n isActive\n createdAt\n updatedAt\n fields {\n edges {\n node {\n id\n type\n name\n label\n description\n icon\n placeholder\n isCustom\n isActive\n isNullable\n createdAt\n updatedAt\n }\n }\n pageInfo {\n hasNextPage\n hasPreviousPage\n startCursor\n endCursor\n }\n totalCount\n }\n }\n }\n pageInfo {\n hasNextPage\n hasPreviousPage\n startCursor\n endCursor\n }\n totalCount\n }\n }\n": types.MetadataObjectsDocument, + "\n query MetadataObjects {\n objects(paging: { first: 100 }) {\n edges {\n node {\n id\n dataSourceId\n nameSingular\n namePlural\n labelSingular\n labelPlural\n description\n icon\n isCustom\n isActive\n createdAt\n updatedAt\n fields(paging: { first: 100 }) {\n edges {\n node {\n id\n type\n name\n label\n description\n icon\n placeholder\n isCustom\n isActive\n isNullable\n createdAt\n updatedAt\n }\n }\n pageInfo {\n hasNextPage\n hasPreviousPage\n startCursor\n endCursor\n }\n totalCount\n }\n }\n }\n pageInfo {\n hasNextPage\n hasPreviousPage\n startCursor\n endCursor\n }\n totalCount\n }\n }\n": types.MetadataObjectsDocument, }; /** @@ -63,7 +63,7 @@ export function graphql(source: "\n mutation DeleteOneMetadataField($idToDelete /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function graphql(source: "\n query MetadataObjects {\n objects {\n edges {\n node {\n id\n dataSourceId\n nameSingular\n namePlural\n labelSingular\n labelPlural\n description\n icon\n isCustom\n isActive\n createdAt\n updatedAt\n fields {\n edges {\n node {\n id\n type\n name\n label\n description\n icon\n placeholder\n isCustom\n isActive\n isNullable\n createdAt\n updatedAt\n }\n }\n pageInfo {\n hasNextPage\n hasPreviousPage\n startCursor\n endCursor\n }\n totalCount\n }\n }\n }\n pageInfo {\n hasNextPage\n hasPreviousPage\n startCursor\n endCursor\n }\n totalCount\n }\n }\n"): (typeof documents)["\n query MetadataObjects {\n objects {\n edges {\n node {\n id\n dataSourceId\n nameSingular\n namePlural\n labelSingular\n labelPlural\n description\n icon\n isCustom\n isActive\n createdAt\n updatedAt\n fields {\n edges {\n node {\n id\n type\n name\n label\n description\n icon\n placeholder\n isCustom\n isActive\n isNullable\n createdAt\n updatedAt\n }\n }\n pageInfo {\n hasNextPage\n hasPreviousPage\n startCursor\n endCursor\n }\n totalCount\n }\n }\n }\n pageInfo {\n hasNextPage\n hasPreviousPage\n startCursor\n endCursor\n }\n totalCount\n }\n }\n"]; +export function graphql(source: "\n query MetadataObjects {\n objects(paging: { first: 100 }) {\n edges {\n node {\n id\n dataSourceId\n nameSingular\n namePlural\n labelSingular\n labelPlural\n description\n icon\n isCustom\n isActive\n createdAt\n updatedAt\n fields(paging: { first: 100 }) {\n edges {\n node {\n id\n type\n name\n label\n description\n icon\n placeholder\n isCustom\n isActive\n isNullable\n createdAt\n updatedAt\n }\n }\n pageInfo {\n hasNextPage\n hasPreviousPage\n startCursor\n endCursor\n }\n totalCount\n }\n }\n }\n pageInfo {\n hasNextPage\n hasPreviousPage\n startCursor\n endCursor\n }\n totalCount\n }\n }\n"): (typeof documents)["\n query MetadataObjects {\n objects(paging: { first: 100 }) {\n edges {\n node {\n id\n dataSourceId\n nameSingular\n namePlural\n labelSingular\n labelPlural\n description\n icon\n isCustom\n isActive\n createdAt\n updatedAt\n fields(paging: { first: 100 }) {\n edges {\n node {\n id\n type\n name\n label\n description\n icon\n placeholder\n isCustom\n isActive\n isNullable\n createdAt\n updatedAt\n }\n }\n pageInfo {\n hasNextPage\n hasPreviousPage\n startCursor\n endCursor\n }\n totalCount\n }\n }\n }\n pageInfo {\n hasNextPage\n hasPreviousPage\n startCursor\n endCursor\n }\n totalCount\n }\n }\n"]; export function graphql(source: string) { return (documents as any)[source] ?? {}; diff --git a/front/src/generated-metadata/graphql.ts b/front/src/generated-metadata/graphql.ts index 446dbd496..0b730b809 100644 --- a/front/src/generated-metadata/graphql.ts +++ b/front/src/generated-metadata/graphql.ts @@ -929,4 +929,4 @@ export const UpdateOneMetadataFieldDocument = {"kind":"Document","definitions":[ export const UpdateOneMetadataObjectDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"UpdateOneMetadataObject"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"idToUpdate"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"updatePayload"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"UpdateObjectInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"updateOneObject"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"idToUpdate"}}},{"kind":"ObjectField","name":{"kind":"Name","value":"update"},"value":{"kind":"Variable","name":{"kind":"Name","value":"updatePayload"}}}]}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"dataSourceId"}},{"kind":"Field","name":{"kind":"Name","value":"nameSingular"}},{"kind":"Field","name":{"kind":"Name","value":"namePlural"}},{"kind":"Field","name":{"kind":"Name","value":"labelSingular"}},{"kind":"Field","name":{"kind":"Name","value":"labelPlural"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"icon"}},{"kind":"Field","name":{"kind":"Name","value":"isCustom"}},{"kind":"Field","name":{"kind":"Name","value":"isActive"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}}]}}]}}]} as unknown as DocumentNode; export const DeleteOneMetadataObjectDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"DeleteOneMetadataObject"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"idToDelete"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"deleteOneObject"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"idToDelete"}}}]}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"dataSourceId"}},{"kind":"Field","name":{"kind":"Name","value":"nameSingular"}},{"kind":"Field","name":{"kind":"Name","value":"namePlural"}},{"kind":"Field","name":{"kind":"Name","value":"labelSingular"}},{"kind":"Field","name":{"kind":"Name","value":"labelPlural"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"icon"}},{"kind":"Field","name":{"kind":"Name","value":"isCustom"}},{"kind":"Field","name":{"kind":"Name","value":"isActive"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}}]}}]}}]} as unknown as DocumentNode; export const DeleteOneMetadataFieldDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"DeleteOneMetadataField"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"idToDelete"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"deleteOneField"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"idToDelete"}}}]}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"type"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"label"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"icon"}},{"kind":"Field","name":{"kind":"Name","value":"placeholder"}},{"kind":"Field","name":{"kind":"Name","value":"isCustom"}},{"kind":"Field","name":{"kind":"Name","value":"isActive"}},{"kind":"Field","name":{"kind":"Name","value":"isNullable"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}}]}}]}}]} as unknown as DocumentNode; -export const MetadataObjectsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"MetadataObjects"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"objects"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"edges"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"node"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"dataSourceId"}},{"kind":"Field","name":{"kind":"Name","value":"nameSingular"}},{"kind":"Field","name":{"kind":"Name","value":"namePlural"}},{"kind":"Field","name":{"kind":"Name","value":"labelSingular"}},{"kind":"Field","name":{"kind":"Name","value":"labelPlural"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"icon"}},{"kind":"Field","name":{"kind":"Name","value":"isCustom"}},{"kind":"Field","name":{"kind":"Name","value":"isActive"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}},{"kind":"Field","name":{"kind":"Name","value":"fields"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"edges"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"node"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"type"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"label"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"icon"}},{"kind":"Field","name":{"kind":"Name","value":"placeholder"}},{"kind":"Field","name":{"kind":"Name","value":"isCustom"}},{"kind":"Field","name":{"kind":"Name","value":"isActive"}},{"kind":"Field","name":{"kind":"Name","value":"isNullable"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"pageInfo"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"hasNextPage"}},{"kind":"Field","name":{"kind":"Name","value":"hasPreviousPage"}},{"kind":"Field","name":{"kind":"Name","value":"startCursor"}},{"kind":"Field","name":{"kind":"Name","value":"endCursor"}}]}},{"kind":"Field","name":{"kind":"Name","value":"totalCount"}}]}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"pageInfo"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"hasNextPage"}},{"kind":"Field","name":{"kind":"Name","value":"hasPreviousPage"}},{"kind":"Field","name":{"kind":"Name","value":"startCursor"}},{"kind":"Field","name":{"kind":"Name","value":"endCursor"}}]}},{"kind":"Field","name":{"kind":"Name","value":"totalCount"}}]}}]}}]} as unknown as DocumentNode; \ No newline at end of file +export const MetadataObjectsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"MetadataObjects"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"objects"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"paging"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"first"},"value":{"kind":"IntValue","value":"100"}}]}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"edges"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"node"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"dataSourceId"}},{"kind":"Field","name":{"kind":"Name","value":"nameSingular"}},{"kind":"Field","name":{"kind":"Name","value":"namePlural"}},{"kind":"Field","name":{"kind":"Name","value":"labelSingular"}},{"kind":"Field","name":{"kind":"Name","value":"labelPlural"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"icon"}},{"kind":"Field","name":{"kind":"Name","value":"isCustom"}},{"kind":"Field","name":{"kind":"Name","value":"isActive"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}},{"kind":"Field","name":{"kind":"Name","value":"fields"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"paging"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"first"},"value":{"kind":"IntValue","value":"100"}}]}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"edges"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"node"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"type"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"label"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"icon"}},{"kind":"Field","name":{"kind":"Name","value":"placeholder"}},{"kind":"Field","name":{"kind":"Name","value":"isCustom"}},{"kind":"Field","name":{"kind":"Name","value":"isActive"}},{"kind":"Field","name":{"kind":"Name","value":"isNullable"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"pageInfo"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"hasNextPage"}},{"kind":"Field","name":{"kind":"Name","value":"hasPreviousPage"}},{"kind":"Field","name":{"kind":"Name","value":"startCursor"}},{"kind":"Field","name":{"kind":"Name","value":"endCursor"}}]}},{"kind":"Field","name":{"kind":"Name","value":"totalCount"}}]}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"pageInfo"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"hasNextPage"}},{"kind":"Field","name":{"kind":"Name","value":"hasPreviousPage"}},{"kind":"Field","name":{"kind":"Name","value":"startCursor"}},{"kind":"Field","name":{"kind":"Name","value":"endCursor"}}]}},{"kind":"Field","name":{"kind":"Name","value":"totalCount"}}]}}]}}]} as unknown as DocumentNode; \ No newline at end of file diff --git a/front/src/generated/graphql.tsx b/front/src/generated/graphql.tsx index add5635d7..934512a4d 100644 --- a/front/src/generated/graphql.tsx +++ b/front/src/generated/graphql.tsx @@ -484,9 +484,12 @@ export enum ApiKeyScalarFieldEnum { export type ApiKeyToken = { __typename?: 'ApiKeyToken'; - expiresAt: Scalars['DateTime']; - id: Scalars['String']; + createdAt: Scalars['DateTime']; + expiresAt?: Maybe; + id: Scalars['ID']; + name: Scalars['String']; token: Scalars['String']; + updatedAt: Scalars['DateTime']; }; export type ApiKeyUpdateManyWithoutWorkspaceNestedInput = { @@ -4203,7 +4206,7 @@ export type InsertOneApiKeyMutationVariables = Exact<{ }>; -export type InsertOneApiKeyMutation = { __typename?: 'Mutation', createOneApiKey: { __typename?: 'ApiKeyToken', id: string, token: string, expiresAt: string } }; +export type InsertOneApiKeyMutation = { __typename?: 'Mutation', createOneApiKey: { __typename?: 'ApiKeyToken', id: string, name: string, token: string, createdAt: string, expiresAt?: string | null } }; export type GetApiKeyQueryVariables = Exact<{ apiKeyId: Scalars['String']; @@ -6907,7 +6910,9 @@ export const InsertOneApiKeyDocument = gql` mutation InsertOneApiKey($data: ApiKeyCreateInput!) { createOneApiKey(data: $data) { id + name token + createdAt expiresAt } } diff --git a/front/src/modules/apollo/optimistic-effect/hooks/useOptimisticEffect.ts b/front/src/modules/apollo/optimistic-effect/hooks/useOptimisticEffect.ts index d1bfaf274..a197d349e 100644 --- a/front/src/modules/apollo/optimistic-effect/hooks/useOptimisticEffect.ts +++ b/front/src/modules/apollo/optimistic-effect/hooks/useOptimisticEffect.ts @@ -8,7 +8,12 @@ import { useRecoilCallback } from 'recoil'; import { GET_COMPANIES } from '@/companies/graphql/queries/getCompanies'; import { GET_PEOPLE } from '@/people/graphql/queries/getPeople'; -import { GetCompaniesQuery, GetPeopleQuery } from '~/generated/graphql'; +import { GET_API_KEYS } from '@/settings/developers/graphql/queries/getApiKeys'; +import { + GetApiKeysQuery, + GetCompaniesQuery, + GetPeopleQuery, +} from '~/generated/graphql'; import { optimisticEffectState } from '../states/optimisticEffectState'; import { OptimisticEffectDefinition } from '../types/OptimisticEffectDefinition'; @@ -77,6 +82,20 @@ export const useOptimisticEffect = () => { }, }); } + if (query === GET_API_KEYS) { + cache.writeQuery({ + query, + variables, + data: { + findManyApiKey: definition.resolver({ + currentData: (existingData as GetApiKeysQuery) + .findManyApiKey as T[], + newData: newData as T[], + variables, + }), + }, + }); + } }; const optimisticEffect = { diff --git a/front/src/modules/settings/developers/graphql/mutations/insertOneApiKey.ts b/front/src/modules/settings/developers/graphql/mutations/insertOneApiKey.ts index 63f4898c8..b15f1a693 100644 --- a/front/src/modules/settings/developers/graphql/mutations/insertOneApiKey.ts +++ b/front/src/modules/settings/developers/graphql/mutations/insertOneApiKey.ts @@ -4,7 +4,9 @@ export const INSERT_ONE_API_KEY = gql` mutation InsertOneApiKey($data: ApiKeyCreateInput!) { createOneApiKey(data: $data) { id + name token + createdAt expiresAt } } diff --git a/front/src/modules/settings/developers/optimistic-effect-definitions/getApiKeysOptimisticEffectDefinition.ts b/front/src/modules/settings/developers/optimistic-effect-definitions/getApiKeysOptimisticEffectDefinition.ts new file mode 100644 index 000000000..fa03e7565 --- /dev/null +++ b/front/src/modules/settings/developers/optimistic-effect-definitions/getApiKeysOptimisticEffectDefinition.ts @@ -0,0 +1,17 @@ +import { GET_API_KEYS } from '@/settings/developers/graphql/queries/getApiKeys'; +import { ApiKey } from '~/generated/graphql'; + +export const getApiKeysOptimisticEffectDefinition = { + key: 'generic-entity-table-data-api-keys', + typename: 'ApiKey', + query: GET_API_KEYS, + resolver: ({ + currentData, + newData, + }: { + currentData: ApiKey[]; + newData: ApiKey[]; + }) => { + return [...newData, ...currentData]; + }, +}; diff --git a/front/src/pages/settings/developers/api-keys/SettingsDevelopersApiKeyDetail.tsx b/front/src/pages/settings/developers/api-keys/SettingsDevelopersApiKeyDetail.tsx index 04b9efd43..fbf1bc8b1 100644 --- a/front/src/pages/settings/developers/api-keys/SettingsDevelopersApiKeyDetail.tsx +++ b/front/src/pages/settings/developers/api-keys/SettingsDevelopersApiKeyDetail.tsx @@ -1,13 +1,12 @@ import { useEffect } from 'react'; import { useNavigate, useParams } from 'react-router-dom'; -import { getOperationName } from '@apollo/client/utilities'; import styled from '@emotion/styled'; import { useRecoilState } from 'recoil'; +import { useOptimisticEffect } from '@/apollo/optimistic-effect/hooks/useOptimisticEffect'; import { SettingsHeaderContainer } from '@/settings/components/SettingsHeaderContainer'; import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer'; import { ApiKeyInput } from '@/settings/developers/components/ApiKeyInput'; -import { GET_API_KEYS } from '@/settings/developers/graphql/queries/getApiKeys'; import { useGeneratedApiKeys } from '@/settings/developers/hooks/useGeneratedApiKeys'; import { generatedApiKeyFamilyState } from '@/settings/developers/states/generatedApiKeyFamilyState'; import { computeNewExpirationDate } from '@/settings/developers/utils/compute-new-expiration-date'; @@ -42,6 +41,7 @@ const StyledInputContainer = styled.div` export const SettingsDevelopersApiKeyDetail = () => { const navigate = useNavigate(); const { apiKeyId = '' } = useParams(); + const { triggerOptimisticEffects } = useOptimisticEffect(); const setGeneratedApi = useGeneratedApiKeys(); const [generatedApiKey] = useRecoilState( @@ -59,7 +59,10 @@ export const SettingsDevelopersApiKeyDetail = () => { const deleteIntegration = async (redirect = true) => { await deleteApiKey({ variables: { apiKeyId }, - refetchQueries: [getOperationName(GET_API_KEYS) ?? ''], + update: (cache) => + cache.evict({ + id: cache.identify({ __typename: 'ApiKey', id: apiKeyId }), + }), }); if (redirect) { navigate('/settings/developers/api-keys'); @@ -79,7 +82,11 @@ export const SettingsDevelopersApiKeyDetail = () => { expiresAt: newExpiresAt, }, }, - refetchQueries: [getOperationName(GET_API_KEYS) ?? ''], + update: (_cache, { data }) => { + if (data?.createOneApiKey) { + triggerOptimisticEffects('ApiKey', [data?.createOneApiKey]); + } + }, }); await deleteIntegration(false); if (apiKey.data?.createOneApiKey) { diff --git a/front/src/pages/settings/developers/api-keys/SettingsDevelopersApiKeys.tsx b/front/src/pages/settings/developers/api-keys/SettingsDevelopersApiKeys.tsx index ec43cfb73..b09b5d215 100644 --- a/front/src/pages/settings/developers/api-keys/SettingsDevelopersApiKeys.tsx +++ b/front/src/pages/settings/developers/api-keys/SettingsDevelopersApiKeys.tsx @@ -1,8 +1,10 @@ import { useNavigate } from 'react-router-dom'; import styled from '@emotion/styled'; +import { useOptimisticEffect } from '@/apollo/optimistic-effect/hooks/useOptimisticEffect'; import { objectSettingsWidth } from '@/settings/data-model/constants/objectSettings'; import { SettingsApiKeysFieldItemTableRow } from '@/settings/developers/components/SettingsApiKeysFieldItemTableRow'; +import { getApiKeysOptimisticEffectDefinition } from '@/settings/developers/optimistic-effect-definitions/getApiKeysOptimisticEffectDefinition'; import { formatExpirations } from '@/settings/developers/utils/format-expiration'; import { IconPlus, IconSettings } from '@/ui/display/icon'; import { H1Title } from '@/ui/display/typography/components/H1Title'; @@ -37,7 +39,15 @@ const StyledH1Title = styled(H1Title)` export const SettingsDevelopersApiKeys = () => { const navigate = useNavigate(); - const apiKeysQuery = useGetApiKeysQuery(); + const { registerOptimisticEffect } = useOptimisticEffect(); + const apiKeysQuery = useGetApiKeysQuery({ + onCompleted: () => { + registerOptimisticEffect({ + variables: {}, + definition: getApiKeysOptimisticEffectDefinition, + }); + }, + }); const apiKeys = apiKeysQuery.data ? formatExpirations(apiKeysQuery.data) : []; return ( diff --git a/front/src/pages/settings/developers/api-keys/SettingsDevelopersApiKeysNew.tsx b/front/src/pages/settings/developers/api-keys/SettingsDevelopersApiKeysNew.tsx index 3e20d2688..44fb5713c 100644 --- a/front/src/pages/settings/developers/api-keys/SettingsDevelopersApiKeysNew.tsx +++ b/front/src/pages/settings/developers/api-keys/SettingsDevelopersApiKeysNew.tsx @@ -1,13 +1,12 @@ import { useState } from 'react'; import { useNavigate } from 'react-router-dom'; -import { getOperationName } from '@apollo/client/utilities'; import { DateTime } from 'luxon'; +import { useOptimisticEffect } from '@/apollo/optimistic-effect/hooks/useOptimisticEffect'; import { SaveAndCancelButtons } from '@/settings/components/SaveAndCancelButtons/SaveAndCancelButtons'; import { SettingsHeaderContainer } from '@/settings/components/SettingsHeaderContainer'; import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer'; import { ExpirationDates } from '@/settings/developers/constants/expirationDates'; -import { GET_API_KEYS } from '@/settings/developers/graphql/queries/getApiKeys'; import { useGeneratedApiKeys } from '@/settings/developers/hooks/useGeneratedApiKeys'; import { IconSettings } from '@/ui/display/icon'; import { H2Title } from '@/ui/display/typography/components/H2Title'; @@ -20,6 +19,7 @@ import { useInsertOneApiKeyMutation } from '~/generated/graphql'; export const SettingsDevelopersApiKeysNew = () => { const [insertOneApiKey] = useInsertOneApiKeyMutation(); + const { triggerOptimisticEffects } = useOptimisticEffect(); const navigate = useNavigate(); const setGeneratedApi = useGeneratedApiKeys(); const [formValues, setFormValues] = useState<{ @@ -41,7 +41,11 @@ export const SettingsDevelopersApiKeysNew = () => { : null, }, }, - refetchQueries: [getOperationName(GET_API_KEYS) ?? ''], + update: (_cache, { data }) => { + if (data?.createOneApiKey) { + triggerOptimisticEffects('ApiKey', [data?.createOneApiKey]); + } + }, }); if (apiKey.data?.createOneApiKey) { setGeneratedApi( diff --git a/server/src/core/api-key/api-key.service.ts b/server/src/core/api-key/api-key.service.ts index 38e25ff49..64c133c7e 100644 --- a/server/src/core/api-key/api-key.service.ts +++ b/server/src/core/api-key/api-key.service.ts @@ -1,9 +1,6 @@ import { Injectable, InternalServerErrorException } from '@nestjs/common'; import { JwtService } from '@nestjs/jwt'; -import { addMilliseconds, addSeconds } from 'date-fns'; -import ms from 'ms'; - import { PrismaService } from 'src/database/prisma.service'; import { ApiKeyToken } from 'src/core/auth/dto/token.entity'; import { assert } from 'src/utils/assert'; @@ -31,20 +28,17 @@ export class ApiKeyService { ): Promise { const secret = this.environmentService.getAccessTokenSecret(); let expiresIn: string | number; - let expirationDate: Date; const now = new Date().getTime(); if (expiresAt) { expiresIn = Math.floor((new Date(expiresAt).getTime() - now) / 1000); - expirationDate = addSeconds(now, expiresIn); } else { expiresIn = this.environmentService.getApiTokenExpiresIn(); - expirationDate = addMilliseconds(now, ms(expiresIn)); } assert(expiresIn, '', InternalServerErrorException); const jwtPayload = { sub: workspaceId, }; - const { id } = await this.prismaService.client.apiKey.create({ + const newApiKey = await this.prismaService.client.apiKey.create({ data: { expiresAt: expiresAt, name: name, @@ -52,13 +46,12 @@ export class ApiKeyService { }, }); return { - id, + ...newApiKey, token: this.jwtService.sign(jwtPayload, { secret, expiresIn, - jwtid: id, + jwtid: newApiKey.id, }), - expiresAt: expirationDate, }; } } diff --git a/server/src/core/auth/dto/token.entity.ts b/server/src/core/auth/dto/token.entity.ts index 2487a9f94..3ffdf4420 100644 --- a/server/src/core/auth/dto/token.entity.ts +++ b/server/src/core/auth/dto/token.entity.ts @@ -1,5 +1,7 @@ import { Field, ObjectType } from '@nestjs/graphql'; +import { ApiKey } from 'src/core/@generated/api-key/api-key.model'; + @ObjectType() export class AuthToken { @Field(() => String) @@ -10,15 +12,9 @@ export class AuthToken { } @ObjectType() -export class ApiKeyToken { - @Field(() => String) - id: string; - +export class ApiKeyToken extends ApiKey { @Field(() => String) token: string; - - @Field(() => Date) - expiresAt: Date; } @ObjectType()