Migrate to a monorepo structure (#2909)

This commit is contained in:
Charles Bochet
2023-12-10 18:10:54 +01:00
committed by GitHub
parent a70a9281eb
commit 5bdca9de6c
2304 changed files with 37152 additions and 25869 deletions

View File

@ -0,0 +1,9 @@
import { useContext } from 'react';
import { ApolloMetadataClientContext } from '../context/ApolloClientMetadataContext';
export const useApolloMetadataClient = () => {
const apolloMetadataClient = useContext(ApolloMetadataClientContext);
return apolloMetadataClient;
};

View File

@ -0,0 +1,52 @@
import { useMemo } from 'react';
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
import { FieldMetadata } from '@/object-record/field/types/FieldMetadata';
import { ColumnDefinition } from '@/object-record/record-table/types/ColumnDefinition';
import { Nullable } from '~/types/Nullable';
import { formatFieldMetadataItemAsColumnDefinition } from '../utils/formatFieldMetadataItemAsColumnDefinition';
import { formatFieldMetadataItemsAsFilterDefinitions } from '../utils/formatFieldMetadataItemsAsFilterDefinitions';
import { formatFieldMetadataItemsAsSortDefinitions } from '../utils/formatFieldMetadataItemsAsSortDefinitions';
export const useColumnDefinitionsFromFieldMetadata = (
objectMetadataItem?: Nullable<ObjectMetadataItem>,
) => {
const activeFieldMetadataItems = useMemo(
() =>
objectMetadataItem
? objectMetadataItem.fields.filter(
({ isActive, isSystem }) => isActive && !isSystem,
)
: [],
[objectMetadataItem],
);
const columnDefinitions: ColumnDefinition<FieldMetadata>[] = useMemo(
() =>
objectMetadataItem
? activeFieldMetadataItems.map((field, index) =>
formatFieldMetadataItemAsColumnDefinition({
position: index,
field,
objectMetadataItem,
}),
)
: [],
[activeFieldMetadataItems, objectMetadataItem],
);
const filterDefinitions = formatFieldMetadataItemsAsFilterDefinitions({
fields: activeFieldMetadataItems,
});
const sortDefinitions = formatFieldMetadataItemsAsSortDefinitions({
fields: activeFieldMetadataItems,
});
return {
columnDefinitions,
filterDefinitions,
sortDefinitions,
};
};

View File

@ -0,0 +1,53 @@
import { ApolloClient, useMutation } from '@apollo/client';
import { getOperationName } from '@apollo/client/utilities';
import { FieldType } from '@/object-record/field/types/FieldType';
import {
CreateOneFieldMetadataItemMutation,
CreateOneFieldMetadataItemMutationVariables,
FieldMetadataType,
} from '~/generated-metadata/graphql';
import { CREATE_ONE_FIELD_METADATA_ITEM } from '../graphql/mutations';
import { FIND_MANY_OBJECT_METADATA_ITEMS } from '../graphql/queries';
import { useApolloMetadataClient } from './useApolloMetadataClient';
type CreateOneFieldMetadataItemArgs = Omit<
CreateOneFieldMetadataItemMutationVariables['input']['field'],
'type'
> & {
type: FieldType;
};
export const useCreateOneFieldMetadataItem = () => {
const apolloMetadataClient = useApolloMetadataClient();
const [mutate] = useMutation<
CreateOneFieldMetadataItemMutation,
CreateOneFieldMetadataItemMutationVariables
>(CREATE_ONE_FIELD_METADATA_ITEM, {
client: apolloMetadataClient ?? ({} as ApolloClient<any>),
});
const createOneFieldMetadataItem = async (
input: CreateOneFieldMetadataItemArgs,
) => {
return await mutate({
variables: {
input: {
field: {
...input,
type: input.type as FieldMetadataType, // Todo improve typing once we have aligned backend and frontend
},
},
},
awaitRefetchQueries: true,
refetchQueries: [getOperationName(FIND_MANY_OBJECT_METADATA_ITEMS) ?? ''],
});
};
return {
createOneFieldMetadataItem,
};
};

View File

@ -0,0 +1,43 @@
import { ApolloClient, useMutation } from '@apollo/client';
import { getOperationName } from '@apollo/client/utilities';
import {
CreateOneObjectMetadataItemMutation,
CreateOneObjectMetadataItemMutationVariables,
} from '~/generated-metadata/graphql';
import { CREATE_ONE_OBJECT_METADATA_ITEM } from '../graphql/mutations';
import { FIND_MANY_OBJECT_METADATA_ITEMS } from '../graphql/queries';
import { useApolloMetadataClient } from './useApolloMetadataClient';
export const useCreateOneObjectRecordMetadataItem = () => {
const apolloMetadataClient = useApolloMetadataClient();
const [mutate] = useMutation<
CreateOneObjectMetadataItemMutation,
CreateOneObjectMetadataItemMutationVariables
>(CREATE_ONE_OBJECT_METADATA_ITEM, {
client: apolloMetadataClient ?? ({} as ApolloClient<any>),
});
const createOneObjectMetadataItem = async (
input: CreateOneObjectMetadataItemMutationVariables['input']['object'],
) => {
return await mutate({
variables: {
input: {
object: {
...input,
},
},
},
awaitRefetchQueries: true,
refetchQueries: [getOperationName(FIND_MANY_OBJECT_METADATA_ITEMS) ?? ''],
});
};
return {
createOneObjectMetadataItem,
};
};

View File

@ -0,0 +1,41 @@
import { ApolloClient, useMutation } from '@apollo/client';
import { getOperationName } from '@apollo/client/utilities';
import {
CreateOneRelationMetadataMutation,
CreateOneRelationMetadataMutationVariables,
} from '~/generated-metadata/graphql';
import { CREATE_ONE_RELATION_METADATA_ITEM } from '../graphql/mutations';
import { FIND_MANY_OBJECT_METADATA_ITEMS } from '../graphql/queries';
import {
formatRelationMetadataInput,
FormatRelationMetadataInputParams,
} from '../utils/formatRelationMetadataInput';
import { useApolloMetadataClient } from './useApolloMetadataClient';
export const useCreateOneRelationMetadataItem = () => {
const apolloMetadataClient = useApolloMetadataClient();
const [mutate] = useMutation<
CreateOneRelationMetadataMutation,
CreateOneRelationMetadataMutationVariables
>(CREATE_ONE_RELATION_METADATA_ITEM, {
client: apolloMetadataClient ?? ({} as ApolloClient<any>),
});
const createOneRelationMetadataItem = async (
input: FormatRelationMetadataInputParams,
) => {
return await mutate({
variables: { input: { relation: formatRelationMetadataInput(input) } },
awaitRefetchQueries: true,
refetchQueries: [getOperationName(FIND_MANY_OBJECT_METADATA_ITEMS) ?? ''],
});
};
return {
createOneRelationMetadataItem,
};
};

View File

@ -0,0 +1,39 @@
import { ApolloClient, useMutation } from '@apollo/client';
import { getOperationName } from '@apollo/client/utilities';
import {
DeleteOneFieldMetadataItemMutation,
DeleteOneFieldMetadataItemMutationVariables,
} from '~/generated-metadata/graphql';
import { DELETE_ONE_FIELD_METADATA_ITEM } from '../graphql/mutations';
import { FIND_MANY_OBJECT_METADATA_ITEMS } from '../graphql/queries';
import { useApolloMetadataClient } from './useApolloMetadataClient';
export const useDeleteOneFieldMetadataItem = () => {
const apolloMetadataClient = useApolloMetadataClient();
const [mutate] = useMutation<
DeleteOneFieldMetadataItemMutation,
DeleteOneFieldMetadataItemMutationVariables
>(DELETE_ONE_FIELD_METADATA_ITEM, {
client: apolloMetadataClient ?? ({} as ApolloClient<any>),
});
const deleteOneFieldMetadataItem = async (
idToDelete: DeleteOneFieldMetadataItemMutationVariables['idToDelete'],
) => {
return await mutate({
variables: {
idToDelete,
},
awaitRefetchQueries: true,
refetchQueries: [getOperationName(FIND_MANY_OBJECT_METADATA_ITEMS) ?? ''],
});
};
return {
deleteOneFieldMetadataItem,
};
};

View File

@ -0,0 +1,39 @@
import { ApolloClient, useMutation } from '@apollo/client';
import { getOperationName } from '@apollo/client/utilities';
import {
DeleteOneObjectMetadataItemMutation,
DeleteOneObjectMetadataItemMutationVariables,
} from '~/generated-metadata/graphql';
import { DELETE_ONE_OBJECT_METADATA_ITEM } from '../graphql/mutations';
import { FIND_MANY_OBJECT_METADATA_ITEMS } from '../graphql/queries';
import { useApolloMetadataClient } from './useApolloMetadataClient';
export const useDeleteOneObjectMetadataItem = () => {
const apolloMetadataClient = useApolloMetadataClient();
const [mutate] = useMutation<
DeleteOneObjectMetadataItemMutation,
DeleteOneObjectMetadataItemMutationVariables
>(DELETE_ONE_OBJECT_METADATA_ITEM, {
client: apolloMetadataClient ?? ({} as ApolloClient<any>),
});
const deleteOneObjectMetadataItem = async (
idToDelete: DeleteOneObjectMetadataItemMutationVariables['idToDelete'],
) => {
return await mutate({
variables: {
idToDelete,
},
awaitRefetchQueries: true,
refetchQueries: [getOperationName(FIND_MANY_OBJECT_METADATA_ITEMS) ?? ''],
});
};
return {
deleteOneObjectMetadataItem,
};
};

View File

@ -0,0 +1,72 @@
import { v4 } from 'uuid';
import { FieldType } from '@/object-record/field/types/FieldType';
import { Field } from '~/generated/graphql';
import { FieldMetadataType } from '~/generated-metadata/graphql';
import { FieldMetadataItem } from '../types/FieldMetadataItem';
import { FieldMetadataOption } from '../types/FieldMetadataOption';
import { formatFieldMetadataItemInput } from '../utils/formatFieldMetadataItemInput';
import { useCreateOneFieldMetadataItem } from './useCreateOneFieldMetadataItem';
import { useDeleteOneFieldMetadataItem } from './useDeleteOneFieldMetadataItem';
import { useUpdateOneFieldMetadataItem } from './useUpdateOneFieldMetadataItem';
export const useFieldMetadataItem = () => {
const { createOneFieldMetadataItem } = useCreateOneFieldMetadataItem();
const { updateOneFieldMetadataItem } = useUpdateOneFieldMetadataItem();
const { deleteOneFieldMetadataItem } = useDeleteOneFieldMetadataItem();
const createMetadataField = (
input: Pick<Field, 'label' | 'icon' | 'description'> & {
objectMetadataId: string;
options?: Omit<FieldMetadataOption, 'id'>[];
type: FieldMetadataType;
},
) =>
createOneFieldMetadataItem({
...formatFieldMetadataItemInput(input),
objectMetadataId: input.objectMetadataId,
type: input.type as FieldType,
});
const editMetadataField = (
input: Pick<Field, 'id' | 'label' | 'icon' | 'description'> & {
options?: FieldMetadataOption[];
},
) =>
updateOneFieldMetadataItem({
fieldMetadataIdToUpdate: input.id,
updatePayload: formatFieldMetadataItemInput({
...input,
// In Edit mode, all options need an id,
// so we generate an id for newly created options.
options: input.options?.map((option) =>
option.id ? option : { ...option, id: v4() },
),
}),
});
const activateMetadataField = (metadataField: FieldMetadataItem) =>
updateOneFieldMetadataItem({
fieldMetadataIdToUpdate: metadataField.id,
updatePayload: { isActive: true },
});
const disableMetadataField = (metadataField: FieldMetadataItem) =>
updateOneFieldMetadataItem({
fieldMetadataIdToUpdate: metadataField.id,
updatePayload: { isActive: false },
});
const eraseMetadataField = (metadataField: FieldMetadataItem) =>
deleteOneFieldMetadataItem(metadataField.id);
return {
activateMetadataField,
createMetadataField,
disableMetadataField,
eraseMetadataField,
editMetadataField,
};
};

View File

@ -0,0 +1,63 @@
import { useMemo } from 'react';
import { useQuery } from '@apollo/client';
import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
import {
FieldFilter,
ObjectFilter,
ObjectMetadataItemsQuery,
ObjectMetadataItemsQueryVariables,
} from '~/generated-metadata/graphql';
import { logError } from '~/utils/logError';
import { FIND_MANY_OBJECT_METADATA_ITEMS } from '../graphql/queries';
import { mapPaginatedObjectMetadataItemsToObjectMetadataItems } from '../utils/mapPaginatedObjectMetadataItemsToObjectMetadataItems';
import { useApolloMetadataClient } from './useApolloMetadataClient';
export const useFindManyObjectMetadataItems = ({
skip,
objectFilter,
fieldFilter,
}: {
skip?: boolean;
objectFilter?: ObjectFilter;
fieldFilter?: FieldFilter;
} = {}) => {
const apolloMetadataClient = useApolloMetadataClient();
const { enqueueSnackBar } = useSnackBar();
const { data, loading, error } = useQuery<
ObjectMetadataItemsQuery,
ObjectMetadataItemsQueryVariables
>(FIND_MANY_OBJECT_METADATA_ITEMS, {
variables: {
objectFilter,
fieldFilter,
},
client: apolloMetadataClient ?? undefined,
skip: skip || !apolloMetadataClient,
onError: (error) => {
logError('useFindManyObjectMetadataItems error : ' + error);
enqueueSnackBar(
`Error during useFindManyObjectMetadataItems, ${error.message}`,
{
variant: 'error',
},
);
},
});
const objectMetadataItems = useMemo(() => {
return mapPaginatedObjectMetadataItemsToObjectMetadataItems({
pagedObjectMetadataItems: data,
});
}, [data]);
return {
objectMetadataItems,
loading,
error,
};
};

View File

@ -0,0 +1,14 @@
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
import { OrderBy } from '@/object-metadata/types/OrderBy';
import { OrderByField } from '@/object-metadata/types/OrderByField';
import { getObjectOrderByField } from '@/object-metadata/utils/getObjectOrderByField';
export const useGetObjectOrderByField = ({
objectMetadataItem,
}: {
objectMetadataItem: ObjectMetadataItem;
}) => {
return (orderBy: OrderBy): OrderByField => {
return getObjectOrderByField(objectMetadataItem, orderBy);
};
};

View File

@ -0,0 +1,108 @@
import { useRecoilValue } from 'recoil';
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
import { FieldType } from '@/object-record/field/types/FieldType';
import { FieldMetadataItem } from '../types/FieldMetadataItem';
export const useMapFieldMetadataToGraphQLQuery = () => {
const objectMetadataItems = useRecoilValue(objectMetadataItemsState);
const mapFieldMetadataToGraphQLQuery = (
field: FieldMetadataItem,
maxDepthForRelations: number = 2,
): any => {
if (maxDepthForRelations <= 0) {
return '';
}
// TODO: parse
const fieldType = field.type as FieldType;
const fieldIsSimpleValue = (
[
'UUID',
'TEXT',
'PHONE',
'DATE_TIME',
'EMAIL',
'NUMBER',
'BOOLEAN',
] as FieldType[]
).includes(fieldType);
if (fieldIsSimpleValue) {
return field.name;
} else if (
fieldType === 'RELATION' &&
field.toRelationMetadata?.relationType === 'ONE_TO_MANY'
) {
const relationMetadataItem = objectMetadataItems.find(
(objectMetadataItem) =>
objectMetadataItem.id ===
(field.toRelationMetadata as any)?.fromObjectMetadata?.id,
);
return `${field.name}
{
id
${(relationMetadataItem?.fields ?? [])
.filter((field) => field.type !== 'RELATION')
.map((field) =>
mapFieldMetadataToGraphQLQuery(field, maxDepthForRelations - 1),
)
.join('\n')}
}`;
} else if (
fieldType === 'RELATION' &&
field.fromRelationMetadata?.relationType === 'ONE_TO_MANY'
) {
const relationMetadataItem = objectMetadataItems.find(
(objectMetadataItem) =>
objectMetadataItem.id ===
(field.fromRelationMetadata as any)?.toObjectMetadata?.id,
);
return `${field.name}
{
edges {
node {
id
${(relationMetadataItem?.fields ?? [])
.filter((field) => field.type !== 'RELATION')
.map((field) =>
mapFieldMetadataToGraphQLQuery(field, maxDepthForRelations - 1),
)
.join('\n')}
}
}
}`;
} else if (fieldType === 'LINK') {
return `
${field.name}
{
label
url
}
`;
} else if (fieldType === 'CURRENCY') {
return `
${field.name}
{
amountMicros
currencyCode
}
`;
} else if (fieldType === 'FULL_NAME') {
return `
${field.name}
{
firstName
lastName
}
`;
}
};
return mapFieldMetadataToGraphQLQuery;
};

View File

@ -0,0 +1,69 @@
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
import { ObjectRecordIdentifier } from '@/object-record/types/ObjectRecordIdentifier';
import { FieldMetadataType } from '~/generated-metadata/graphql';
import { getLogoUrlFromDomainName } from '~/utils';
export const useMapToObjectRecordIdentifier = ({
objectMetadataItem,
}: {
objectMetadataItem: ObjectMetadataItem;
}) => {
return (record: any): ObjectRecordIdentifier => {
switch (objectMetadataItem.nameSingular) {
case CoreObjectNameSingular.Opportunity:
return {
id: record.id,
name: record?.company?.name,
avatarUrl: record.avatarUrl,
avatarType: 'rounded',
};
}
const labelIdentifierFieldMetadata = objectMetadataItem.fields.find(
(field) =>
field.id === objectMetadataItem.labelIdentifierFieldMetadataId ||
field.name === 'name',
);
let labelIdentifierFieldValue = '';
switch (labelIdentifierFieldMetadata?.type) {
case FieldMetadataType.FullName: {
labelIdentifierFieldValue = `${record.name?.firstName ?? ''} ${
record.name?.lastName ?? ''
}`;
break;
}
default:
labelIdentifierFieldValue = labelIdentifierFieldMetadata
? record[labelIdentifierFieldMetadata.name]
: '';
}
const imageIdentifierFieldMetadata = objectMetadataItem.fields.find(
(field) => field.id === objectMetadataItem.imageIdentifierFieldMetadataId,
);
const imageIdentifierFieldValue = imageIdentifierFieldMetadata
? (record[imageIdentifierFieldMetadata.name] as string)
: null;
const avatarType =
objectMetadataItem.nameSingular === CoreObjectNameSingular.Company
? 'squared'
: 'rounded';
const avatarUrl =
objectMetadataItem.nameSingular === CoreObjectNameSingular.Company
? getLogoUrlFromDomainName(imageIdentifierFieldValue ?? '')
: imageIdentifierFieldValue ?? null;
return {
id: record.id,
name: labelIdentifierFieldValue,
avatarUrl,
avatarType,
};
};
};

View File

@ -0,0 +1,130 @@
import { gql } from '@apollo/client';
import { useRecoilValue } from 'recoil';
import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
import { ObjectMetadataItemNotFoundError } from '@/object-metadata/errors/ObjectMetadataNotFoundError';
import { useGetObjectOrderByField } from '@/object-metadata/hooks/useGetObjectOrderByField';
import { useMapToObjectRecordIdentifier } from '@/object-metadata/hooks/useMapToObjectRecordIdentifier';
import { objectMetadataItemFamilySelector } from '@/object-metadata/states/objectMetadataItemFamilySelector';
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
import { getObjectMetadataItemsMock } from '@/object-metadata/utils/getObjectMetadataItemsMock';
import { useGenerateCreateManyRecordMutation } from '@/object-record/hooks/useGenerateCreateManyRecordMutation';
import { useGenerateCreateOneRecordMutation } from '@/object-record/hooks/useGenerateCreateOneRecordMutation';
import { useGenerateFindManyRecordsQuery } from '@/object-record/hooks/useGenerateFindManyRecordsQuery';
import { useGenerateFindOneRecordQuery } from '@/object-record/hooks/useGenerateFindOneRecordQuery';
import { useGenerateUpdateOneRecordMutation } from '@/object-record/hooks/useGenerateUpdateOneRecordMutation';
import { useGetRecordFromCache } from '@/object-record/hooks/useGetRecordFromCache';
import { useModifyRecordFromCache } from '@/object-record/hooks/useModifyRecordFromCache';
import { generateDeleteOneRecordMutation } from '@/object-record/utils/generateDeleteOneRecordMutation';
import { isDefined } from '~/utils/isDefined';
import { ObjectMetadataItemIdentifier } from '../types/ObjectMetadataItemIdentifier';
export const EMPTY_QUERY = gql`
query EmptyQuery {
empty
}
`;
export const EMPTY_MUTATION = gql`
mutation EmptyMutation {
empty
}
`;
export const useObjectMetadataItem = (
{ objectNameSingular }: ObjectMetadataItemIdentifier,
depth?: number,
) => {
const currentWorkspace = useRecoilValue(currentWorkspaceState);
const mockObjectMetadataItems = getObjectMetadataItemsMock();
let objectMetadataItem = useRecoilValue(
objectMetadataItemFamilySelector({
objectName: objectNameSingular,
objectNameType: 'singular',
}),
);
let objectMetadataItems = useRecoilValue(objectMetadataItemsState);
if (!currentWorkspace) {
objectMetadataItem =
mockObjectMetadataItems.find(
(objectMetadataItem) =>
objectMetadataItem.nameSingular === objectNameSingular,
) ?? null;
objectMetadataItems = mockObjectMetadataItems;
}
if (!isDefined(objectMetadataItem)) {
throw new ObjectMetadataItemNotFoundError(
objectNameSingular,
objectMetadataItems,
);
}
const mapToObjectRecordIdentifier = useMapToObjectRecordIdentifier({
objectMetadataItem,
});
const getObjectOrderByField = useGetObjectOrderByField({
objectMetadataItem,
});
const getRecordFromCache = useGetRecordFromCache({
objectMetadataItem,
});
const modifyRecordFromCache = useModifyRecordFromCache({
objectMetadataItem,
});
const findManyRecordsQuery = useGenerateFindManyRecordsQuery({
objectMetadataItem,
depth,
});
const findOneRecordQuery = useGenerateFindOneRecordQuery({
objectMetadataItem,
depth,
});
const createOneRecordMutation = useGenerateCreateOneRecordMutation({
objectMetadataItem,
});
const createManyRecordsMutation = useGenerateCreateManyRecordMutation({
objectMetadataItem,
});
const updateOneRecordMutation = useGenerateUpdateOneRecordMutation({
objectMetadataItem,
});
const deleteOneRecordMutation = generateDeleteOneRecordMutation({
objectMetadataItem,
});
const labelIdentifierFieldMetadataId = objectMetadataItem.fields.find(
({ name }) => name === 'name',
)?.id;
const basePathToShowPage = `/object/${objectMetadataItem.nameSingular}/`;
return {
labelIdentifierFieldMetadataId,
basePathToShowPage,
objectMetadataItem,
getRecordFromCache,
modifyRecordFromCache,
findManyRecordsQuery,
findOneRecordQuery,
createOneRecordMutation,
updateOneRecordMutation,
deleteOneRecordMutation,
createManyRecordsMutation,
mapToObjectRecordIdentifier,
getObjectOrderByField,
};
};

View File

@ -0,0 +1,95 @@
import { useRecoilValue } from 'recoil';
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
import { ObjectMetadataItem } from '../types/ObjectMetadataItem';
import { formatObjectMetadataItemInput } from '../utils/formatObjectMetadataItemInput';
import { getObjectSlug } from '../utils/getObjectSlug';
import { useCreateOneObjectRecordMetadataItem } from './useCreateOneObjectMetadataItem';
import { useDeleteOneObjectMetadataItem } from './useDeleteOneObjectMetadataItem';
import { useUpdateOneObjectMetadataItem } from './useUpdateOneObjectMetadataItem';
export const useObjectMetadataItemForSettings = () => {
const objectMetadataItems = useRecoilValue(objectMetadataItemsState);
const activeObjectMetadataItems = objectMetadataItems.filter(
({ isActive, isSystem }) => isActive && !isSystem,
);
const disabledObjectMetadataItems = objectMetadataItems.filter(
({ isActive, isSystem }) => !isActive && !isSystem,
);
const findActiveObjectMetadataItemBySlug = (slug: string) =>
activeObjectMetadataItems.find(
(activeObjectMetadataItem) =>
getObjectSlug(activeObjectMetadataItem) === slug,
);
const findObjectMetadataItemById = (id: string) =>
objectMetadataItems.find(
(objectMetadataItem) => objectMetadataItem.id === id,
);
const findObjectMetadataItemByNamePlural = (namePlural: string) =>
objectMetadataItems.find(
(objectMetadataItem) => objectMetadataItem.namePlural === namePlural,
);
const { createOneObjectMetadataItem } =
useCreateOneObjectRecordMetadataItem();
const { updateOneObjectMetadataItem } = useUpdateOneObjectMetadataItem();
const { deleteOneObjectMetadataItem } = useDeleteOneObjectMetadataItem();
const createObjectMetadataItem = (
input: Pick<
ObjectMetadataItem,
'labelPlural' | 'labelSingular' | 'icon' | 'description'
>,
) => createOneObjectMetadataItem(formatObjectMetadataItemInput(input));
const editObjectMetadataItem = (
input: Pick<
ObjectMetadataItem,
'id' | 'labelPlural' | 'labelSingular' | 'icon' | 'description'
>,
) =>
updateOneObjectMetadataItem({
idToUpdate: input.id,
updatePayload: formatObjectMetadataItemInput(input),
});
const activateObjectMetadataItem = (
objectMetadataItem: Pick<ObjectMetadataItem, 'id'>,
) =>
updateOneObjectMetadataItem({
idToUpdate: objectMetadataItem.id,
updatePayload: { isActive: true },
});
const disableObjectMetadataItem = (
objectMetadataItem: Pick<ObjectMetadataItem, 'id'>,
) =>
updateOneObjectMetadataItem({
idToUpdate: objectMetadataItem.id,
updatePayload: { isActive: false },
});
const eraseObjectMetadataItem = (
objectMetadataItem: Pick<ObjectMetadataItem, 'id'>,
) => deleteOneObjectMetadataItem(objectMetadataItem.id);
return {
activateObjectMetadataItem,
activeObjectMetadataItems,
createObjectMetadataItem,
disabledObjectMetadataItems,
disableObjectMetadataItem,
editObjectMetadataItem,
eraseObjectMetadataItem,
findActiveObjectMetadataItemBySlug,
findObjectMetadataItemById,
findObjectMetadataItemByNamePlural,
objectMetadataItems,
};
};

View File

@ -0,0 +1,38 @@
import { useRecoilValue } from 'recoil';
import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
import { objectMetadataItemFamilySelector } from '@/object-metadata/states/objectMetadataItemFamilySelector';
import { getObjectMetadataItemsMock } from '@/object-metadata/utils/getObjectMetadataItemsMock';
import { isDefined } from '~/utils/isDefined';
export const useObjectNamePluralFromSingular = ({
objectNameSingular,
}: {
objectNameSingular: string;
}) => {
const currentWorkspace = useRecoilValue(currentWorkspaceState);
const mockObjectMetadataItems = getObjectMetadataItemsMock();
let objectMetadataItem = useRecoilValue(
objectMetadataItemFamilySelector({
objectName: objectNameSingular,
objectNameType: 'singular',
}),
);
if (!currentWorkspace) {
objectMetadataItem =
mockObjectMetadataItems.find(
(objectMetadataItem) =>
objectMetadataItem.nameSingular === objectNameSingular,
) ?? null;
}
if (!isDefined(objectMetadataItem)) {
throw new Error(
`Object metadata item not found for ${objectNameSingular} object`,
);
}
return { objectNamePlural: objectMetadataItem.namePlural };
};

View File

@ -0,0 +1,38 @@
import { useRecoilValue } from 'recoil';
import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
import { objectMetadataItemFamilySelector } from '@/object-metadata/states/objectMetadataItemFamilySelector';
import { getObjectMetadataItemsMock } from '@/object-metadata/utils/getObjectMetadataItemsMock';
import { isDefined } from '~/utils/isDefined';
export const useObjectNameSingularFromPlural = ({
objectNamePlural,
}: {
objectNamePlural: string;
}) => {
const currentWorkspace = useRecoilValue(currentWorkspaceState);
const mockObjectMetadataItems = getObjectMetadataItemsMock();
let objectMetadataItem = useRecoilValue(
objectMetadataItemFamilySelector({
objectName: objectNamePlural,
objectNameType: 'plural',
}),
);
if (!currentWorkspace) {
objectMetadataItem =
mockObjectMetadataItems.find(
(objectMetadataItem) =>
objectMetadataItem.namePlural === objectNamePlural,
) ?? null;
}
if (!isDefined(objectMetadataItem)) {
throw new Error(
`Object metadata item not found for ${objectNamePlural} object`,
);
}
return { objectNameSingular: objectMetadataItem.nameSingular };
};

View File

@ -0,0 +1,49 @@
import { RelationType } from '@/settings/data-model/types/RelationType';
import { RelationMetadataType } from '~/generated-metadata/graphql';
import { useObjectMetadataItemForSettings } from '../hooks/useObjectMetadataItemForSettings';
import { FieldMetadataItem } from '../types/FieldMetadataItem';
export const useRelationMetadata = ({
fieldMetadataItem,
}: {
fieldMetadataItem?: FieldMetadataItem;
}) => {
const { findObjectMetadataItemById } = useObjectMetadataItemForSettings();
const relationMetadata =
fieldMetadataItem?.fromRelationMetadata ||
fieldMetadataItem?.toRelationMetadata;
const relationType =
relationMetadata?.relationType === RelationMetadataType.OneToMany &&
fieldMetadataItem?.toRelationMetadata
? 'MANY_TO_ONE'
: (relationMetadata?.relationType as RelationType | undefined);
const relationObjectMetadataId =
relationMetadata && 'toObjectMetadata' in relationMetadata
? relationMetadata.toObjectMetadata.id
: relationMetadata?.fromObjectMetadata.id;
const relationObjectMetadataItem = relationObjectMetadataId
? findObjectMetadataItemById(relationObjectMetadataId)
: undefined;
const relationFieldMetadataId =
relationMetadata && 'toFieldMetadataId' in relationMetadata
? relationMetadata.toFieldMetadataId
: relationMetadata?.fromFieldMetadataId;
const relationFieldMetadataItem = relationFieldMetadataId
? relationObjectMetadataItem?.fields?.find(
(field) => field.id === relationFieldMetadataId,
)
: undefined;
return {
relationFieldMetadataItem,
relationObjectMetadataItem,
relationType,
};
};

View File

@ -0,0 +1,50 @@
import { useMutation } from '@apollo/client';
import { getOperationName } from '@apollo/client/utilities';
import {
UpdateOneFieldMetadataItemMutation,
UpdateOneFieldMetadataItemMutationVariables,
} from '~/generated-metadata/graphql';
import { UPDATE_ONE_FIELD_METADATA_ITEM } from '../graphql/mutations';
import { FIND_MANY_OBJECT_METADATA_ITEMS } from '../graphql/queries';
import { useApolloMetadataClient } from './useApolloMetadataClient';
export const useUpdateOneFieldMetadataItem = () => {
const apolloMetadataClient = useApolloMetadataClient();
const [mutate] = useMutation<
UpdateOneFieldMetadataItemMutation,
UpdateOneFieldMetadataItemMutationVariables
>(UPDATE_ONE_FIELD_METADATA_ITEM, {
client: apolloMetadataClient ?? undefined,
});
const updateOneFieldMetadataItem = async ({
fieldMetadataIdToUpdate,
updatePayload,
}: {
fieldMetadataIdToUpdate: UpdateOneFieldMetadataItemMutationVariables['idToUpdate'];
updatePayload: Pick<
UpdateOneFieldMetadataItemMutationVariables['updatePayload'],
'description' | 'icon' | 'isActive' | 'label' | 'name'
>;
}) => {
return await mutate({
variables: {
idToUpdate: fieldMetadataIdToUpdate,
updatePayload: {
...updatePayload,
label: updatePayload.label ?? undefined,
},
},
awaitRefetchQueries: true,
refetchQueries: [getOperationName(FIND_MANY_OBJECT_METADATA_ITEMS) ?? ''],
});
};
return {
updateOneFieldMetadataItem,
};
};

View File

@ -0,0 +1,54 @@
import { useMutation } from '@apollo/client';
import { getOperationName } from '@apollo/client/utilities';
import {
UpdateOneObjectMetadataItemMutation,
UpdateOneObjectMetadataItemMutationVariables,
} from '~/generated-metadata/graphql';
import { UPDATE_ONE_OBJECT_METADATA_ITEM } from '../graphql/mutations';
import { FIND_MANY_OBJECT_METADATA_ITEMS } from '../graphql/queries';
import { useApolloMetadataClient } from './useApolloMetadataClient';
// 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 useUpdateOneObjectMetadataItem = () => {
const apolloClientMetadata = useApolloMetadataClient();
const [mutate] = useMutation<
UpdateOneObjectMetadataItemMutation,
UpdateOneObjectMetadataItemMutationVariables
>(UPDATE_ONE_OBJECT_METADATA_ITEM, {
client: apolloClientMetadata ?? undefined,
});
const updateOneObjectMetadataItem = async ({
idToUpdate,
updatePayload,
}: {
idToUpdate: UpdateOneObjectMetadataItemMutationVariables['idToUpdate'];
updatePayload: Pick<
UpdateOneObjectMetadataItemMutationVariables['updatePayload'],
| 'description'
| 'icon'
| 'isActive'
| 'labelPlural'
| 'labelSingular'
| 'namePlural'
| 'nameSingular'
>;
}) => {
return await mutate({
variables: {
idToUpdate,
updatePayload,
},
awaitRefetchQueries: true,
refetchQueries: [getOperationName(FIND_MANY_OBJECT_METADATA_ITEMS) ?? ''],
});
};
return {
updateOneObjectMetadataItem,
};
};