From 547a17b145939d3d6528d2dfb3e2866d188a7a70 Mon Sep 17 00:00:00 2001 From: Lucas Bordeau Date: Wed, 18 Oct 2023 16:48:11 +0200 Subject: [PATCH] Feat/metadata add update and delete on frontend (#2102) * Reworked metadata creation * Wip * Fix from PR * Removed consolelog * Post merge * Fixed seeds --- front/src/generated-metadata/gql.ts | 18 +++- front/src/generated-metadata/graphql.ts | 30 +++++-- front/src/index.tsx | 2 +- ...r.tsx => ApolloMetadataClientProvider.tsx} | 0 .../components/FetchMetadataEffect.tsx | 43 +++++++-- .../components/ObjectDataTableEffect.tsx | 4 +- .../metadata/components/ObjectTable.tsx | 2 +- .../src/modules/metadata/graphql/mutations.ts | 30 ++++++- front/src/modules/metadata/graphql/queries.ts | 2 +- ...Metadata.ts => useApolloMetadataClient.ts} | 4 +- .../hooks/useCreateOneMetadataField.ts | 20 ++--- .../hooks/useCreateOneMetadataObject.ts | 20 ++--- .../metadata/hooks/useCreateOneObject.ts | 49 +++++++++++ .../hooks/useFindManyMetadataObjects.ts | 60 +++++++++++++ ...CustomObjects.ts => useFindManyObjects.ts} | 8 +- .../hooks/useSeedCustomObjectsTemp.ts | 88 +++++++++++++------ .../hooks/useUpdateOneMetadataField.ts | 76 ++++++++++++++++ .../hooks/useUpdateOneMetadataObject.ts | 71 +++++++++++++++ .../utils/formatPagedObjectsToObjects.ts | 2 +- .../utils/generateCreateOneObjectMutation.ts | 21 +++++ front/src/pages/companies/ObjectsTable.tsx | 4 +- front/src/utils/isNonEmptyArray.ts | 2 +- front/src/utils/string/capitalize.ts | 3 + 23 files changed, 482 insertions(+), 77 deletions(-) rename front/src/modules/metadata/components/{ApolloClientMetadataProvider.tsx => ApolloMetadataClientProvider.tsx} (100%) rename front/src/modules/metadata/hooks/{useApolloClientMetadata.ts => useApolloMetadataClient.ts} (62%) create mode 100644 front/src/modules/metadata/hooks/useCreateOneObject.ts create mode 100644 front/src/modules/metadata/hooks/useFindManyMetadataObjects.ts rename front/src/modules/metadata/hooks/{useFindManyCustomObjects.ts => useFindManyObjects.ts} (85%) create mode 100644 front/src/modules/metadata/hooks/useUpdateOneMetadataField.ts create mode 100644 front/src/modules/metadata/hooks/useUpdateOneMetadataObject.ts create mode 100644 front/src/modules/metadata/utils/generateCreateOneObjectMutation.ts create mode 100644 front/src/utils/string/capitalize.ts diff --git a/front/src/generated-metadata/gql.ts b/front/src/generated-metadata/gql.ts index 32e4dd97b..f62496527 100644 --- a/front/src/generated-metadata/gql.ts +++ b/front/src/generated-metadata/gql.ts @@ -13,8 +13,10 @@ import { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/ * Therefore it is highly recommended to use the babel or swc plugin for production. */ const documents = { - "\n mutation CreateOneObject($input: CreateOneObjectInput!) {\n createOneObject(input: $input) {\n id\n }\n }\n": types.CreateOneObjectDocument, - "\n mutation CreateOneField($input: CreateOneFieldInput!) {\n createOneField(input: $input) {\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.CreateOneFieldDocument, + "\n mutation CreateOneMetadataObject($input: CreateOneObjectInput!) {\n createOneObject(input: $input) {\n id\n }\n }\n": types.CreateOneMetadataObjectDocument, + "\n mutation CreateOneMetadataField($input: CreateOneFieldInput!) {\n createOneField(input: $input) {\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.CreateOneMetadataFieldDocument, + "\n mutation UpdateOneMetadataField(\n $idToUpdate: ID!\n $updatePayload: UpdateFieldInput!\n ) {\n updateOneField(input: { id: $idToUpdate, update: $updatePayload }) {\n id\n }\n }\n": types.UpdateOneMetadataFieldDocument, + "\n mutation UpdateOneMetadataObject(\n $idToUpdate: ID!\n $updatePayload: UpdateObjectInput!\n ) {\n updateOneObject(input: { id: $idToUpdate, update: $updatePayload }) {\n id\n }\n }\n": types.UpdateOneMetadataObjectDocument, "\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, }; @@ -35,11 +37,19 @@ export function graphql(source: string): unknown; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function graphql(source: "\n mutation CreateOneObject($input: CreateOneObjectInput!) {\n createOneObject(input: $input) {\n id\n }\n }\n"): (typeof documents)["\n mutation CreateOneObject($input: CreateOneObjectInput!) {\n createOneObject(input: $input) {\n id\n }\n }\n"]; +export function graphql(source: "\n mutation CreateOneMetadataObject($input: CreateOneObjectInput!) {\n createOneObject(input: $input) {\n id\n }\n }\n"): (typeof documents)["\n mutation CreateOneMetadataObject($input: CreateOneObjectInput!) {\n createOneObject(input: $input) {\n id\n }\n }\n"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function graphql(source: "\n mutation CreateOneField($input: CreateOneFieldInput!) {\n createOneField(input: $input) {\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"): (typeof documents)["\n mutation CreateOneField($input: CreateOneFieldInput!) {\n createOneField(input: $input) {\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"]; +export function graphql(source: "\n mutation CreateOneMetadataField($input: CreateOneFieldInput!) {\n createOneField(input: $input) {\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"): (typeof documents)["\n mutation CreateOneMetadataField($input: CreateOneFieldInput!) {\n createOneField(input: $input) {\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"]; +/** + * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. + */ +export function graphql(source: "\n mutation UpdateOneMetadataField(\n $idToUpdate: ID!\n $updatePayload: UpdateFieldInput!\n ) {\n updateOneField(input: { id: $idToUpdate, update: $updatePayload }) {\n id\n }\n }\n"): (typeof documents)["\n mutation UpdateOneMetadataField(\n $idToUpdate: ID!\n $updatePayload: UpdateFieldInput!\n ) {\n updateOneField(input: { id: $idToUpdate, update: $updatePayload }) {\n id\n }\n }\n"]; +/** + * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. + */ +export function graphql(source: "\n mutation UpdateOneMetadataObject(\n $idToUpdate: ID!\n $updatePayload: UpdateObjectInput!\n ) {\n updateOneObject(input: { id: $idToUpdate, update: $updatePayload }) {\n id\n }\n }\n"): (typeof documents)["\n mutation UpdateOneMetadataObject(\n $idToUpdate: ID!\n $updatePayload: UpdateObjectInput!\n ) {\n updateOneObject(input: { id: $idToUpdate, update: $updatePayload }) {\n id\n }\n }\n"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ diff --git a/front/src/generated-metadata/graphql.ts b/front/src/generated-metadata/graphql.ts index 46e72f72d..7d370da40 100644 --- a/front/src/generated-metadata/graphql.ts +++ b/front/src/generated-metadata/graphql.ts @@ -862,19 +862,35 @@ export type ObjectEdge = { node: Object; }; -export type CreateOneObjectMutationVariables = Exact<{ +export type CreateOneMetadataObjectMutationVariables = Exact<{ input: CreateOneObjectInput; }>; -export type CreateOneObjectMutation = { __typename?: 'Mutation', createOneObject: { __typename?: 'object', id: string } }; +export type CreateOneMetadataObjectMutation = { __typename?: 'Mutation', createOneObject: { __typename?: 'object', id: string } }; -export type CreateOneFieldMutationVariables = Exact<{ +export type CreateOneMetadataFieldMutationVariables = Exact<{ input: CreateOneFieldInput; }>; -export type CreateOneFieldMutation = { __typename?: 'Mutation', createOneField: { __typename?: 'field', id: string, type: string, name: string, label: string, description?: string | null, icon?: string | null, placeholder?: string | null, isCustom: boolean, isActive: boolean, isNullable: boolean, createdAt: any, updatedAt: any } }; +export type CreateOneMetadataFieldMutation = { __typename?: 'Mutation', createOneField: { __typename?: 'field', id: string, type: string, name: string, label: string, description?: string | null, icon?: string | null, placeholder?: string | null, isCustom: boolean, isActive: boolean, isNullable: boolean, createdAt: any, updatedAt: any } }; + +export type UpdateOneMetadataFieldMutationVariables = Exact<{ + idToUpdate: Scalars['ID']['input']; + updatePayload: UpdateFieldInput; +}>; + + +export type UpdateOneMetadataFieldMutation = { __typename?: 'Mutation', updateOneField: { __typename?: 'field', id: string } }; + +export type UpdateOneMetadataObjectMutationVariables = Exact<{ + idToUpdate: Scalars['ID']['input']; + updatePayload: UpdateObjectInput; +}>; + + +export type UpdateOneMetadataObjectMutation = { __typename?: 'Mutation', updateOneObject: { __typename?: 'object', id: string } }; export type MetadataObjectsQueryVariables = Exact<{ [key: string]: never; }>; @@ -882,6 +898,8 @@ export type MetadataObjectsQueryVariables = Exact<{ [key: string]: never; }>; export type MetadataObjectsQuery = { __typename?: 'Query', objects: { __typename?: 'ObjectConnection', totalCount: number, edges: Array<{ __typename?: 'objectEdge', node: { __typename?: 'object', id: string, dataSourceId: string, nameSingular: string, namePlural: string, labelSingular: string, labelPlural: string, description?: string | null, icon?: string | null, isCustom: boolean, isActive: boolean, createdAt: any, updatedAt: any, fields: { __typename?: 'ObjectFieldsConnection', totalCount: number, edges: Array<{ __typename?: 'fieldEdge', node: { __typename?: 'field', id: string, type: string, name: string, label: string, description?: string | null, icon?: string | null, placeholder?: string | null, isCustom: boolean, isActive: boolean, isNullable: boolean, createdAt: any, updatedAt: any } }>, pageInfo: { __typename?: 'PageInfo', hasNextPage?: boolean | null, hasPreviousPage?: boolean | null, startCursor?: any | null, endCursor?: any | null } } } }>, pageInfo: { __typename?: 'PageInfo', hasNextPage?: boolean | null, hasPreviousPage?: boolean | null, startCursor?: any | null, endCursor?: any | null } } }; -export const CreateOneObjectDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"CreateOneObject"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"CreateOneObjectInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"createOneObject"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}}]}}]} as unknown as DocumentNode; -export const CreateOneFieldDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"CreateOneField"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"CreateOneFieldInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"createOneField"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"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 CreateOneMetadataObjectDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"CreateOneMetadataObject"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"CreateOneObjectInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"createOneObject"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}}]}}]} as unknown as DocumentNode; +export const CreateOneMetadataFieldDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"CreateOneMetadataField"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"CreateOneFieldInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"createOneField"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"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 UpdateOneMetadataFieldDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"UpdateOneMetadataField"},"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":"UpdateFieldInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"updateOneField"},"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"}}]}}]}}]} as unknown as DocumentNode; +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"}}]}}]}}]} 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 diff --git a/front/src/index.tsx b/front/src/index.tsx index 885462b09..d6a735372 100644 --- a/front/src/index.tsx +++ b/front/src/index.tsx @@ -16,7 +16,7 @@ import { UserProvider } from '@/users/components/UserProvider'; import '@emotion/react'; import { PageChangeEffect } from './effect-components/PageChangeEffect'; -import { ApolloMetadataClientProvider } from './modules/metadata/components/ApolloClientMetadataProvider'; +import { ApolloMetadataClientProvider } from './modules/metadata/components/ApolloMetadataClientProvider'; import { FetchMetadataEffect } from './modules/metadata/components/FetchMetadataEffect'; import { App } from './App'; diff --git a/front/src/modules/metadata/components/ApolloClientMetadataProvider.tsx b/front/src/modules/metadata/components/ApolloMetadataClientProvider.tsx similarity index 100% rename from front/src/modules/metadata/components/ApolloClientMetadataProvider.tsx rename to front/src/modules/metadata/components/ApolloMetadataClientProvider.tsx diff --git a/front/src/modules/metadata/components/FetchMetadataEffect.tsx b/front/src/modules/metadata/components/FetchMetadataEffect.tsx index def1c4b5f..029950405 100644 --- a/front/src/modules/metadata/components/FetchMetadataEffect.tsx +++ b/front/src/modules/metadata/components/FetchMetadataEffect.tsx @@ -1,11 +1,13 @@ -import { useEffect } from 'react'; +import { useEffect, useState } from 'react'; import { useRecoilState } from 'recoil'; import { isFlexibleBackendEnabledState } from '@/client-config/states/isFlexibleBackendEnabledState'; import { MetadataObjectsQuery } from '~/generated-metadata/graphql'; -import { GET_ALL_OBJECTS } from '../graphql/queries'; -import { useApolloMetadataClient } from '../hooks/useApolloClientMetadata'; +import { FIND_MANY_METADATA_OBJECTS } from '../graphql/queries'; +import { useApolloMetadataClient } from '../hooks/useApolloMetadataClient'; +import { useCreateOneObject } from '../hooks/useCreateOneObject'; +import { useFindManyObjects } from '../hooks/useFindManyObjects'; import { useSeedCustomObjectsTemp } from '../hooks/useSeedCustomObjectsTemp'; import { metadataObjectsState } from '../states/metadataObjectsState'; import { MetadataObject } from '../types/MetadataObject'; @@ -20,13 +22,44 @@ export const FetchMetadataEffect = () => { const seedCustomObjectsTemp = useSeedCustomObjectsTemp(); + const { createOneObject } = useCreateOneObject({ + objectNamePlural: 'suppliers', + }); + + const { objects: suppliers, loading } = useFindManyObjects({ + objectNamePlural: 'suppliers', + }); + + const [created, setCreated] = useState(false); + + useEffect(() => { + if (!created && !loading && suppliers.length === 0 && createOneObject) { + createOneObject({ + name: 'Supplier 1', + city: 'City 1', + }); + + createOneObject({ + name: 'Supplier 2', + city: 'City 2', + }); + + createOneObject({ + name: 'Supplier 3', + city: 'City 3', + }); + + setCreated(true); + } + }, [suppliers, createOneObject, loading, created]); + useEffect(() => { if (!isFlexibleBackendEnabled) return; (async () => { if (apolloMetadataClient && metadataObjects.length === 0) { const objects = await apolloMetadataClient.query({ - query: GET_ALL_OBJECTS, + query: FIND_MANY_METADATA_OBJECTS, }); if ( @@ -48,7 +81,7 @@ export const FetchMetadataEffect = () => { const objects = await apolloMetadataClient.query({ - query: GET_ALL_OBJECTS, + query: FIND_MANY_METADATA_OBJECTS, }); const formattedObjects: MetadataObject[] = diff --git a/front/src/modules/metadata/components/ObjectDataTableEffect.tsx b/front/src/modules/metadata/components/ObjectDataTableEffect.tsx index f9e591e13..524f10f9c 100644 --- a/front/src/modules/metadata/components/ObjectDataTableEffect.tsx +++ b/front/src/modules/metadata/components/ObjectDataTableEffect.tsx @@ -10,7 +10,7 @@ import { savedSortsFamilyState } from '@/ui/data/view-bar/states/savedSortsFamil import { sortsScopedState } from '@/ui/data/view-bar/states/sortsScopedState'; import { useRecoilScopeId } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopeId'; -import { useFindManyCustomObjects } from '../hooks/useFindManyCustomObjects'; +import { useFindManyObjects } from '../hooks/useFindManyObjects'; import { useSetObjectDataTableData } from '../hooks/useSetDataTableData'; export const ObjectDataTableEffect = ({ @@ -22,7 +22,7 @@ export const ObjectDataTableEffect = ({ }) => { const setDataTableData = useSetObjectDataTableData(); - const { objects } = useFindManyCustomObjects({ + const { objects } = useFindManyObjects({ objectNamePlural: objectNamePlural, }); diff --git a/front/src/modules/metadata/components/ObjectTable.tsx b/front/src/modules/metadata/components/ObjectTable.tsx index 32c0f3364..0be4b1a71 100644 --- a/front/src/modules/metadata/components/ObjectTable.tsx +++ b/front/src/modules/metadata/components/ObjectTable.tsx @@ -37,7 +37,7 @@ export const ObjectTable = ({ /> { - return useContext(ApolloMetadataClientContext); + const apolloMetadataClient = useContext(ApolloMetadataClientContext); + + return apolloMetadataClient; }; diff --git a/front/src/modules/metadata/hooks/useCreateOneMetadataField.ts b/front/src/modules/metadata/hooks/useCreateOneMetadataField.ts index 88071485c..65f65f1c8 100644 --- a/front/src/modules/metadata/hooks/useCreateOneMetadataField.ts +++ b/front/src/modules/metadata/hooks/useCreateOneMetadataField.ts @@ -2,27 +2,27 @@ import { ApolloClient, useMutation } from '@apollo/client'; import { getOperationName } from '@apollo/client/utilities'; import { - CreateOneFieldMutation, - CreateOneFieldMutationVariables, + CreateOneMetadataFieldMutation, + CreateOneMetadataFieldMutationVariables, } from '~/generated-metadata/graphql'; -import { CREATE_ONE_FIELD } from '../graphql/mutations'; -import { GET_ALL_OBJECTS } from '../graphql/queries'; +import { CREATE_ONE_METADATA_FIELD } from '../graphql/mutations'; +import { FIND_MANY_METADATA_OBJECTS } from '../graphql/queries'; -import { useApolloMetadataClient } from './useApolloClientMetadata'; +import { useApolloMetadataClient } from './useApolloMetadataClient'; export const useCreateOneMetadataField = () => { const apolloMetadataClient = useApolloMetadataClient(); const [mutate] = useMutation< - CreateOneFieldMutation, - CreateOneFieldMutationVariables - >(CREATE_ONE_FIELD, { + CreateOneMetadataFieldMutation, + CreateOneMetadataFieldMutationVariables + >(CREATE_ONE_METADATA_FIELD, { client: apolloMetadataClient ?? ({} as ApolloClient), }); const createOneMetadataField = ( - input: CreateOneFieldMutationVariables['input']['field'], + input: CreateOneMetadataFieldMutationVariables['input']['field'], ) => mutate({ variables: { @@ -32,7 +32,7 @@ export const useCreateOneMetadataField = () => { }, }, }, - refetchQueries: [getOperationName(GET_ALL_OBJECTS) ?? ''], + refetchQueries: [getOperationName(FIND_MANY_METADATA_OBJECTS) ?? ''], }); return { diff --git a/front/src/modules/metadata/hooks/useCreateOneMetadataObject.ts b/front/src/modules/metadata/hooks/useCreateOneMetadataObject.ts index eb598132d..5de321fa9 100644 --- a/front/src/modules/metadata/hooks/useCreateOneMetadataObject.ts +++ b/front/src/modules/metadata/hooks/useCreateOneMetadataObject.ts @@ -2,27 +2,27 @@ import { ApolloClient, useMutation } from '@apollo/client'; import { getOperationName } from '@apollo/client/utilities'; import { - CreateOneObjectMutation, - CreateOneObjectMutationVariables, + CreateOneMetadataObjectMutation, + CreateOneMetadataObjectMutationVariables, } from '~/generated-metadata/graphql'; -import { CREATE_ONE_OBJECT } from '../graphql/mutations'; -import { GET_ALL_OBJECTS } from '../graphql/queries'; +import { CREATE_ONE_METADATA_OBJECT } from '../graphql/mutations'; +import { FIND_MANY_METADATA_OBJECTS } from '../graphql/queries'; -import { useApolloMetadataClient } from './useApolloClientMetadata'; +import { useApolloMetadataClient } from './useApolloMetadataClient'; export const useCreateOneMetadataObject = () => { const apolloMetadataClient = useApolloMetadataClient(); const [mutate] = useMutation< - CreateOneObjectMutation, - CreateOneObjectMutationVariables - >(CREATE_ONE_OBJECT, { + CreateOneMetadataObjectMutation, + CreateOneMetadataObjectMutationVariables + >(CREATE_ONE_METADATA_OBJECT, { client: apolloMetadataClient ?? ({} as ApolloClient), }); const createOneMetadataObject = ( - input: CreateOneObjectMutationVariables['input']['object'], + input: CreateOneMetadataObjectMutationVariables['input']['object'], ) => mutate({ variables: { @@ -32,7 +32,7 @@ export const useCreateOneMetadataObject = () => { }, }, }, - refetchQueries: [getOperationName(GET_ALL_OBJECTS) ?? ''], + refetchQueries: [getOperationName(FIND_MANY_METADATA_OBJECTS) ?? ''], }); return { diff --git a/front/src/modules/metadata/hooks/useCreateOneObject.ts b/front/src/modules/metadata/hooks/useCreateOneObject.ts new file mode 100644 index 000000000..ef7bee16c --- /dev/null +++ b/front/src/modules/metadata/hooks/useCreateOneObject.ts @@ -0,0 +1,49 @@ +import { gql, useMutation } from '@apollo/client'; + +import { generateCreateOneObjectMutation } from '../utils/generateCreateOneObjectMutation'; + +import { useFindManyMetadataObjects } from './useFindManyMetadataObjects'; + +export const useCreateOneObject = ({ + objectNamePlural, +}: { + objectNamePlural: string; +}) => { + const { metadataObjects } = useFindManyMetadataObjects(); + + const foundMetadataObject = metadataObjects.find( + (object) => object.namePlural === objectNamePlural, + ); + + const generatedMutation = foundMetadataObject + ? generateCreateOneObjectMutation({ + metadataObject: foundMetadataObject, + }) + : gql` + mutation EmptyMutation { + empty + } + `; + + const [mutate] = useMutation(generatedMutation); + + const createOneObject = foundMetadataObject + ? (input: Record) => { + return mutate({ + variables: { + input: { + ...input, + }, + }, + }); + } + : undefined; + + const objectNotFoundInMetadata = + metadataObjects.length > 0 && !foundMetadataObject; + + return { + createOneObject, + objectNotFoundInMetadata, + }; +}; diff --git a/front/src/modules/metadata/hooks/useFindManyMetadataObjects.ts b/front/src/modules/metadata/hooks/useFindManyMetadataObjects.ts new file mode 100644 index 000000000..ea77646c9 --- /dev/null +++ b/front/src/modules/metadata/hooks/useFindManyMetadataObjects.ts @@ -0,0 +1,60 @@ +import { useMemo } from 'react'; +import { useQuery } from '@apollo/client'; + +import { + MetadataObjectsQuery, + MetadataObjectsQueryVariables, +} from '~/generated-metadata/graphql'; + +import { FIND_MANY_METADATA_OBJECTS } from '../graphql/queries'; +import { formatPagedMetadataObjectsToMetadataObjects } from '../utils/formatPagedMetadataObjectsToMetadataObjects'; + +import { useApolloMetadataClient } from './useApolloMetadataClient'; + +// TODO: test fetchMore +export const useFindManyMetadataObjects = () => { + const apolloMetadataClient = useApolloMetadataClient(); + + const { data, fetchMore: fetchMoreInternal } = useQuery< + MetadataObjectsQuery, + MetadataObjectsQueryVariables + >(FIND_MANY_METADATA_OBJECTS, { + client: apolloMetadataClient ?? undefined, + skip: !apolloMetadataClient, + }); + + const hasMore = data?.objects?.pageInfo?.hasNextPage; + + const fetchMore = () => + fetchMoreInternal({ + variables: { + afterCursor: data?.objects?.pageInfo?.endCursor, + }, + }); + + const metadataObjects = useMemo(() => { + return formatPagedMetadataObjectsToMetadataObjects({ + pagedMetadataObjects: data, + }); + }, [data]); + + const getMetadataObjectsFromCache = () => { + const queryResult = apolloMetadataClient?.readQuery< + MetadataObjectsQuery, + MetadataObjectsQueryVariables + >({ + query: FIND_MANY_METADATA_OBJECTS, + }); + + return formatPagedMetadataObjectsToMetadataObjects({ + pagedMetadataObjects: queryResult ?? undefined, + }); + }; + + return { + metadataObjects, + hasMore, + fetchMore, + getMetadataObjectsFromCache, + }; +}; diff --git a/front/src/modules/metadata/hooks/useFindManyCustomObjects.ts b/front/src/modules/metadata/hooks/useFindManyObjects.ts similarity index 85% rename from front/src/modules/metadata/hooks/useFindManyCustomObjects.ts rename to front/src/modules/metadata/hooks/useFindManyObjects.ts index dab2a3efa..cb88e2112 100644 --- a/front/src/modules/metadata/hooks/useFindManyCustomObjects.ts +++ b/front/src/modules/metadata/hooks/useFindManyObjects.ts @@ -5,16 +5,18 @@ import { PaginatedObjectType } from '../types/PaginatedObjectType'; import { formatPagedObjectsToObjects } from '../utils/formatPagedObjectsToObjects'; import { generateFindManyCustomObjectsQuery } from '../utils/generateFindManyCustomObjectsQuery'; -import { useFindAllMetadata } from './useFindAllMetadata'; +import { useFindManyMetadataObjects } from './useFindManyMetadataObjects'; // TODO: test with a wrong name // TODO: add zod to validate that we have at least id on each object -export const useFindManyCustomObjects = ({ +export const useFindManyObjects = < + ObjectType extends { id: string } & Record, +>({ objectNamePlural, }: { objectNamePlural: string; }) => { - const { metadataObjects } = useFindAllMetadata(); + const { metadataObjects } = useFindManyMetadataObjects(); const foundMetadataObject = metadataObjects.find( (object) => object.namePlural === objectNamePlural, diff --git a/front/src/modules/metadata/hooks/useSeedCustomObjectsTemp.ts b/front/src/modules/metadata/hooks/useSeedCustomObjectsTemp.ts index 688e75f9c..2a7e28b19 100644 --- a/front/src/modules/metadata/hooks/useSeedCustomObjectsTemp.ts +++ b/front/src/modules/metadata/hooks/useSeedCustomObjectsTemp.ts @@ -1,39 +1,75 @@ +import { isNonEmptyArray } from '~/utils/isNonEmptyArray'; + import { useCreateOneMetadataField } from './useCreateOneMetadataField'; import { useCreateOneMetadataObject } from './useCreateOneMetadataObject'; +import { useUpdateOneMetadataField } from './useUpdateOneMetadataField'; +import { useUpdateOneMetadataObject } from './useUpdateOneMetadataObject'; export const useSeedCustomObjectsTemp = () => { const { createOneMetadataObject } = useCreateOneMetadataObject(); const { createOneMetadataField } = useCreateOneMetadataField(); + const { updateOneMetadataObject } = useUpdateOneMetadataObject(); + const { updateOneMetadataField } = useUpdateOneMetadataField(); + return async () => { - const createdMetadataObject = await createOneMetadataObject({ - labelPlural: 'Suppliers', - labelSingular: 'Supplier', - nameSingular: 'supplier', - namePlural: 'suppliers', - description: 'Suppliers', - icon: 'IconBuilding', - }); + const { data: createdMetadataObject, errors } = + await createOneMetadataObject({ + labelPlural: 'Suppliers', + labelSingular: 'Supplier', + nameSingular: 'supplier', + namePlural: 'suppliers', + description: 'Suppliers', + icon: 'IconBuilding', + }); - const supplierObjectId = - createdMetadataObject.data?.createOneObject?.id ?? ''; + if (!isNonEmptyArray(errors)) { + const supplierObjectId = createdMetadataObject?.createOneObject?.id ?? ''; - await createOneMetadataField({ - objectId: supplierObjectId, - name: 'name', - type: 'text', - description: 'Name', - label: 'Name', - icon: 'IconBuilding', - }); + const { data: createNameFieldData } = await createOneMetadataField({ + objectId: supplierObjectId, + name: 'name', + type: 'text', + description: 'Name', + label: 'Name', + icon: 'IconBuilding', + }); - await createOneMetadataField({ - objectId: supplierObjectId, - label: 'City', - name: 'city', - type: 'text', - description: 'City', - icon: 'IconMap', - }); + const nameFieldId = createNameFieldData?.createOneField.id ?? ''; + + const { data: createCityFieldData } = await createOneMetadataField({ + objectId: supplierObjectId, + label: 'City', + name: 'city', + type: 'text', + description: 'City', + icon: 'IconMap', + }); + + const cityFieldId = createCityFieldData?.createOneField.id ?? ''; + + await updateOneMetadataObject({ + idToUpdate: supplierObjectId, + updatePayload: { + labelPlural: 'Suppliers 2', + }, + }); + + await updateOneMetadataField({ + objectIdToUpdate: supplierObjectId, + fieldIdToUpdate: cityFieldId, + updatePayload: { + label: 'City 2', + }, + }); + + await updateOneMetadataField({ + objectIdToUpdate: supplierObjectId, + fieldIdToUpdate: nameFieldId, + updatePayload: { + label: 'Name 2', + }, + }); + } }; }; diff --git a/front/src/modules/metadata/hooks/useUpdateOneMetadataField.ts b/front/src/modules/metadata/hooks/useUpdateOneMetadataField.ts new file mode 100644 index 000000000..1eabc93cb --- /dev/null +++ b/front/src/modules/metadata/hooks/useUpdateOneMetadataField.ts @@ -0,0 +1,76 @@ +import { useMutation } from '@apollo/client'; +import { getOperationName } from '@apollo/client/utilities'; + +import { + UpdateOneMetadataFieldMutation, + UpdateOneMetadataFieldMutationVariables, +} from '~/generated-metadata/graphql'; + +import { UPDATE_ONE_METADATA_FIELD } from '../graphql/mutations'; +import { FIND_MANY_METADATA_OBJECTS } from '../graphql/queries'; + +import { useApolloMetadataClient } from './useApolloMetadataClient'; +import { useFindManyMetadataObjects } from './useFindManyMetadataObjects'; + +export const useUpdateOneMetadataField = () => { + const apolloMetadataClient = useApolloMetadataClient(); + + const { getMetadataObjectsFromCache } = useFindManyMetadataObjects(); + + const [mutate] = useMutation< + UpdateOneMetadataFieldMutation, + UpdateOneMetadataFieldMutationVariables + >(UPDATE_ONE_METADATA_FIELD, { + client: apolloMetadataClient ?? undefined, + }); + + const updateOneMetadataField = ({ + objectIdToUpdate, + fieldIdToUpdate, + updatePayload, + }: { + objectIdToUpdate: string; + fieldIdToUpdate: UpdateOneMetadataFieldMutationVariables['idToUpdate']; + updatePayload: Partial< + Pick< + UpdateOneMetadataFieldMutationVariables['updatePayload'], + 'description' | 'icon' | 'isActive' | 'label' + > + >; + }) => { + const metadataObjects = getMetadataObjectsFromCache(); + + const foundMetadataObject = metadataObjects.find( + (metadataObject) => metadataObject.id === objectIdToUpdate, + ); + + if (!foundMetadataObject) + throw new Error(`Metadata object with id ${objectIdToUpdate} not found`); + + const foundMetadataField = foundMetadataObject.fields.find( + (metadataField) => metadataField.id === fieldIdToUpdate, + ); + + if (!foundMetadataField) + throw new Error(`Metadata field with id ${fieldIdToUpdate} not found`); + + return mutate({ + variables: { + idToUpdate: fieldIdToUpdate, + updatePayload: { + name: foundMetadataField.name, + description: foundMetadataField.description, + icon: foundMetadataField.icon, + isActive: foundMetadataField.isActive, + label: foundMetadataField.label, + ...updatePayload, + }, + }, + refetchQueries: [getOperationName(FIND_MANY_METADATA_OBJECTS) ?? ''], + }); + }; + + return { + updateOneMetadataField, + }; +}; diff --git a/front/src/modules/metadata/hooks/useUpdateOneMetadataObject.ts b/front/src/modules/metadata/hooks/useUpdateOneMetadataObject.ts new file mode 100644 index 000000000..1faa6650a --- /dev/null +++ b/front/src/modules/metadata/hooks/useUpdateOneMetadataObject.ts @@ -0,0 +1,71 @@ +import { useMutation } from '@apollo/client'; +import { getOperationName } from '@apollo/client/utilities'; + +import { + UpdateOneMetadataObjectMutation, + UpdateOneMetadataObjectMutationVariables, +} from '~/generated-metadata/graphql'; + +import { UPDATE_ONE_METADATA_OBJECT } from '../graphql/mutations'; +import { FIND_MANY_METADATA_OBJECTS } from '../graphql/queries'; + +import { useApolloMetadataClient } from './useApolloMetadataClient'; +import { useFindManyMetadataObjects } from './useFindManyMetadataObjects'; + +// TODO: Slice the Apollo store synchronously in the update function instead of subscribing, so we can use update after read in the same function call +export const useUpdateOneMetadataObject = () => { + const apolloClientMetadata = useApolloMetadataClient(); + + const { getMetadataObjectsFromCache: queryMetadataObjects } = + useFindManyMetadataObjects(); + + const [mutate] = useMutation< + UpdateOneMetadataObjectMutation, + UpdateOneMetadataObjectMutationVariables + >(UPDATE_ONE_METADATA_OBJECT, { + client: apolloClientMetadata ?? undefined, + }); + + const updateOneMetadataObject = ({ + idToUpdate, + updatePayload, + }: { + idToUpdate: UpdateOneMetadataObjectMutationVariables['idToUpdate']; + updatePayload: Partial< + Pick< + UpdateOneMetadataObjectMutationVariables['updatePayload'], + 'description' | 'icon' | 'isActive' | 'labelPlural' | 'labelSingular' + > + >; + }) => { + const metadataObjects = queryMetadataObjects(); + + const foundMetadataObject = metadataObjects.find( + (metadataObject) => metadataObject.id === idToUpdate, + ); + + if (!foundMetadataObject) + throw new Error(`Metadata object with id ${idToUpdate} not found`); + + return mutate({ + variables: { + idToUpdate, + updatePayload: { + namePlural: foundMetadataObject.namePlural, + nameSingular: foundMetadataObject.nameSingular, + description: foundMetadataObject.description, + icon: foundMetadataObject.icon, + isActive: foundMetadataObject.isActive, + labelPlural: foundMetadataObject.labelPlural, + labelSingular: foundMetadataObject.labelSingular, + ...updatePayload, + }, + }, + refetchQueries: [getOperationName(FIND_MANY_METADATA_OBJECTS) ?? ''], + }); + }; + + return { + updateOneMetadataObject, + }; +}; diff --git a/front/src/modules/metadata/utils/formatPagedObjectsToObjects.ts b/front/src/modules/metadata/utils/formatPagedObjectsToObjects.ts index 68d97193a..8e40202b7 100644 --- a/front/src/modules/metadata/utils/formatPagedObjectsToObjects.ts +++ b/front/src/modules/metadata/utils/formatPagedObjectsToObjects.ts @@ -1,5 +1,5 @@ export const formatPagedObjectsToObjects = < - ObjectType extends { id: string }, + ObjectType extends { id: string } & Record, ObjectTypeQuery extends { [objectNamePlural: string]: { edges: ObjectEdge[]; diff --git a/front/src/modules/metadata/utils/generateCreateOneObjectMutation.ts b/front/src/modules/metadata/utils/generateCreateOneObjectMutation.ts new file mode 100644 index 000000000..14a30cff4 --- /dev/null +++ b/front/src/modules/metadata/utils/generateCreateOneObjectMutation.ts @@ -0,0 +1,21 @@ +import { gql } from '@apollo/client'; + +import { capitalize } from '~/utils/string/capitalize'; + +import { MetadataObject } from '../types/MetadataObject'; + +export const generateCreateOneObjectMutation = ({ + metadataObject, +}: { + metadataObject: MetadataObject; +}) => { + const capitalizedObjectName = capitalize(metadataObject.nameSingular); + + return gql` + mutation CreateOne${capitalizedObjectName}($input: ${capitalizedObjectName}CreateInput!) { + createOne${capitalizedObjectName}(data: $input) { + id + } + } + `; +}; diff --git a/front/src/pages/companies/ObjectsTable.tsx b/front/src/pages/companies/ObjectsTable.tsx index 9f148c2c1..ec99da921 100644 --- a/front/src/pages/companies/ObjectsTable.tsx +++ b/front/src/pages/companies/ObjectsTable.tsx @@ -24,7 +24,9 @@ export const ObjectTablePage = ({ objectNameSingular: string; objectNamePlural: string; }) => { - const handleAddButtonClick = async () => {}; + const handleAddButtonClick = async () => { + // + }; return ( diff --git a/front/src/utils/isNonEmptyArray.ts b/front/src/utils/isNonEmptyArray.ts index d3643e39b..7be89344e 100644 --- a/front/src/utils/isNonEmptyArray.ts +++ b/front/src/utils/isNonEmptyArray.ts @@ -1,5 +1,5 @@ export const isNonEmptyArray = ( - probableArray: T[] | undefined | null, + probableArray: T[] | readonly T[] | undefined | null, ): probableArray is NonNullable => { if ( Array.isArray(probableArray) && diff --git a/front/src/utils/string/capitalize.ts b/front/src/utils/string/capitalize.ts new file mode 100644 index 000000000..6db86f0b9 --- /dev/null +++ b/front/src/utils/string/capitalize.ts @@ -0,0 +1,3 @@ +export const capitalize = (stringToCapitalize: string) => { + return stringToCapitalize[0].toUpperCase() + stringToCapitalize.slice(1); +};