diff --git a/front/src/modules/metadata/graphql/queries.ts b/front/src/modules/metadata/graphql/queries.ts index 0ddfe62c5..a032dce3d 100644 --- a/front/src/modules/metadata/graphql/queries.ts +++ b/front/src/modules/metadata/graphql/queries.ts @@ -2,7 +2,7 @@ import { gql } from '@apollo/client'; export const FIND_MANY_METADATA_OBJECTS = gql` query MetadataObjects { - objects(paging: { first: 100 }) { + objects(paging: { first: 1000 }) { edges { node { id @@ -17,7 +17,7 @@ export const FIND_MANY_METADATA_OBJECTS = gql` isActive createdAt updatedAt - fields(paging: { first: 100 }) { + fields(paging: { first: 1000 }) { edges { node { id diff --git a/front/src/modules/metadata/hooks/useFindManyMetadataObjects.ts b/front/src/modules/metadata/hooks/useFindManyMetadataObjects.ts index dfd92d535..c2e16467f 100644 --- a/front/src/modules/metadata/hooks/useFindManyMetadataObjects.ts +++ b/front/src/modules/metadata/hooks/useFindManyMetadataObjects.ts @@ -1,6 +1,7 @@ import { useMemo } from 'react'; import { useQuery } from '@apollo/client'; +import { useSnackBar } from '@/ui/feedback/snack-bar/hooks/useSnackBar'; import { MetadataObjectsQuery, MetadataObjectsQueryVariables, @@ -15,15 +16,28 @@ import { useApolloMetadataClient } from './useApolloMetadataClient'; export const useFindManyMetadataObjects = () => { const apolloMetadataClient = useApolloMetadataClient(); + const { enqueueSnackBar } = useSnackBar(); + const { data, fetchMore: fetchMoreInternal, loading, + error, } = useQuery( FIND_MANY_METADATA_OBJECTS, { client: apolloMetadataClient ?? undefined, skip: !apolloMetadataClient, + onError: (error) => { + // eslint-disable-next-line no-console + console.error('useFindManyMetadataObjects error : ', error); + enqueueSnackBar( + `Error during useFindManyMetadataObjects, ${error.message}`, + { + variant: 'error', + }, + ); + }, }, ); @@ -47,5 +61,6 @@ export const useFindManyMetadataObjects = () => { hasMore, fetchMore, loading, + error, }; }; diff --git a/front/src/modules/metadata/hooks/useFindManyObjects.ts b/front/src/modules/metadata/hooks/useFindManyObjects.ts index 6bbf08aef..4780c1ef5 100644 --- a/front/src/modules/metadata/hooks/useFindManyObjects.ts +++ b/front/src/modules/metadata/hooks/useFindManyObjects.ts @@ -1,6 +1,8 @@ import { useMemo } from 'react'; import { useQuery } from '@apollo/client'; +import { useSnackBar } from '@/ui/feedback/snack-bar/hooks/useSnackBar'; + import { MetadataObjectIdentifier } from '../types/MetadataObjectIdentifier'; import { PaginatedObjectType } from '../types/PaginatedObjectType'; import { formatPagedObjectsToObjects } from '../utils/formatPagedObjectsToObjects'; @@ -19,10 +21,25 @@ export const useFindManyObjects = < objectNamePlural, }); + const { enqueueSnackBar } = useSnackBar(); + const { data, loading, error } = useQuery>( findManyQuery, { skip: !foundMetadataObject, + onError: (error) => { + // eslint-disable-next-line no-console + console.error( + `useFindManyObjects for "${objectNamePlural}" error : `, + error, + ); + enqueueSnackBar( + `Error during useFindManyObjects for "${objectNamePlural}", ${error.message}`, + { + variant: 'error', + }, + ); + }, }, ); diff --git a/front/src/modules/metadata/hooks/useFieldMetadata.ts b/front/src/modules/metadata/hooks/useMetadataField.ts similarity index 69% rename from front/src/modules/metadata/hooks/useFieldMetadata.ts rename to front/src/modules/metadata/hooks/useMetadataField.ts index 7e91e5d19..593d9b2dd 100644 --- a/front/src/modules/metadata/hooks/useFieldMetadata.ts +++ b/front/src/modules/metadata/hooks/useMetadataField.ts @@ -1,4 +1,4 @@ -import { ObjectFieldDataType } from '@/settings/data-model/types/ObjectFieldDataType'; +import { MetadataFieldDataType } from '@/settings/data-model/types/ObjectFieldDataType'; import { Field } from '~/generated/graphql'; import { formatMetadataFieldInput } from '../utils/formatMetadataFieldInput'; @@ -7,15 +7,15 @@ import { useCreateOneMetadataField } from './useCreateOneMetadataField'; import { useDeleteOneMetadataField } from './useDeleteOneMetadataField'; import { useUpdateOneMetadataField } from './useUpdateOneMetadataField'; -export const useFieldMetadata = () => { +export const useMetadataField = () => { const { createOneMetadataField } = useCreateOneMetadataField(); const { updateOneMetadataField } = useUpdateOneMetadataField(); const { deleteOneMetadataField } = useDeleteOneMetadataField(); - const createField = ( + const createMetadataField = ( input: Pick & { objectId: string; - type: ObjectFieldDataType; + type: MetadataFieldDataType; }, ) => createOneMetadataField({ @@ -23,25 +23,25 @@ export const useFieldMetadata = () => { objectId: input.objectId, }); - const activateField = (metadataField: Field) => + const activateMetadataField = (metadataField: Field) => updateOneMetadataField({ fieldIdToUpdate: metadataField.id, updatePayload: { isActive: true }, }); - const disableField = (metadataField: Field) => + const disableMetadataField = (metadataField: Field) => updateOneMetadataField({ fieldIdToUpdate: metadataField.id, updatePayload: { isActive: false }, }); - const eraseField = (metadataField: Field) => + const eraseMetadataField = (metadataField: Field) => deleteOneMetadataField(metadataField.id); return { - activateField, - createField, - disableField, - eraseField, + activateMetadataField, + createMetadataField, + disableMetadataField, + eraseMetadataField, }; }; diff --git a/front/src/modules/metadata/hooks/useObjectMetadata.ts b/front/src/modules/metadata/hooks/useMetadataObjectForSettings.ts similarity index 70% rename from front/src/modules/metadata/hooks/useObjectMetadata.ts rename to front/src/modules/metadata/hooks/useMetadataObjectForSettings.ts index cb250c019..218b8b2ac 100644 --- a/front/src/modules/metadata/hooks/useObjectMetadata.ts +++ b/front/src/modules/metadata/hooks/useMetadataObjectForSettings.ts @@ -7,7 +7,7 @@ import { useDeleteOneMetadataObject } from './useDeleteOneMetadataObject'; import { useFindManyMetadataObjects } from './useFindManyMetadataObjects'; import { useUpdateOneMetadataObject } from './useUpdateOneMetadataObject'; -export const useObjectMetadata = () => { +export const useMetadataObjectForSettings = () => { const { metadataObjects, loading } = useFindManyMetadataObjects(); const activeMetadataObjects = metadataObjects.filter( @@ -17,23 +17,23 @@ export const useObjectMetadata = () => { ({ isActive }) => !isActive, ); - const findActiveObjectBySlug = (slug: string) => + const findActiveMetadataObjectBySlug = (slug: string) => activeMetadataObjects.find( - (activeObject) => getObjectSlug(activeObject) === slug, + (activeMetadataObject) => getObjectSlug(activeMetadataObject) === slug, ); const { createOneMetadataObject } = useCreateOneMetadataObject(); const { updateOneMetadataObject } = useUpdateOneMetadataObject(); const { deleteOneMetadataObject } = useDeleteOneMetadataObject(); - const createObject = ( + const createMetadataObject = ( input: Pick< MetadataObject, 'labelPlural' | 'labelSingular' | 'icon' | 'description' >, ) => createOneMetadataObject(formatMetadataObjectInput(input)); - const editObject = ( + const editMetadataObject = ( input: Pick< MetadataObject, 'id' | 'labelPlural' | 'labelSingular' | 'icon' | 'description' @@ -44,30 +44,30 @@ export const useObjectMetadata = () => { updatePayload: formatMetadataObjectInput(input), }); - const activateObject = (metadataObject: MetadataObject) => + const activateMetadataObject = (metadataObject: Pick) => updateOneMetadataObject({ idToUpdate: metadataObject.id, updatePayload: { isActive: true }, }); - const disableObject = (metadataObject: MetadataObject) => + const disableMetadataObject = (metadataObject: Pick) => updateOneMetadataObject({ idToUpdate: metadataObject.id, updatePayload: { isActive: false }, }); - const eraseObject = (metadataObject: Pick) => + const eraseMetadataObject = (metadataObject: Pick) => deleteOneMetadataObject(metadataObject.id); return { - activateObject, - activeObjects: activeMetadataObjects, - createObject, - disabledObjects: disabledMetadataObjects, - disableObject, - editObject, - eraseObject, - findActiveObjectBySlug, + activateMetadataObject, + activeMetadataObjects, + createMetadataObject, + disabledMetadataObjects, + disableMetadataObject, + editMetadataObject, + eraseMetadataObject, + findActiveMetadataObjectBySlug, loading, }; }; diff --git a/front/src/modules/metadata/utils/formatMetadataFieldInput.ts b/front/src/modules/metadata/utils/formatMetadataFieldInput.ts index 2efb9c812..53678e82e 100644 --- a/front/src/modules/metadata/utils/formatMetadataFieldInput.ts +++ b/front/src/modules/metadata/utils/formatMetadataFieldInput.ts @@ -1,11 +1,11 @@ import toCamelCase from 'lodash.camelcase'; -import { ObjectFieldDataType } from '@/settings/data-model/types/ObjectFieldDataType'; +import { MetadataFieldDataType } from '@/settings/data-model/types/ObjectFieldDataType'; import { Field } from '~/generated-metadata/graphql'; export const formatMetadataFieldInput = ( input: Pick & { - type: ObjectFieldDataType; + type: MetadataFieldDataType; }, ) => ({ description: input.description?.trim() ?? null, diff --git a/front/src/modules/settings/data-model/components/SettingsObjectFieldTypeSelectSection.tsx b/front/src/modules/settings/data-model/components/SettingsObjectFieldTypeSelectSection.tsx index 34dc07127..258e1ea89 100644 --- a/front/src/modules/settings/data-model/components/SettingsObjectFieldTypeSelectSection.tsx +++ b/front/src/modules/settings/data-model/components/SettingsObjectFieldTypeSelectSection.tsx @@ -3,12 +3,12 @@ import { Select } from '@/ui/input/components/Select'; import { Section } from '@/ui/layout/section/components/Section'; import { dataTypes } from '../constants/dataTypes'; -import { ObjectFieldDataType } from '../types/ObjectFieldDataType'; +import { MetadataFieldDataType } from '../types/ObjectFieldDataType'; type SettingsObjectFieldTypeSelectSectionProps = { disabled?: boolean; - onChange?: (value: ObjectFieldDataType) => void; - type: ObjectFieldDataType; + onChange?: (value: MetadataFieldDataType) => void; + type: MetadataFieldDataType; }; // TODO: remove "relation" type for now, add it back when the backend is ready. @@ -31,7 +31,7 @@ export const SettingsObjectFieldTypeSelectSection = ({ onChange={onChange} options={Object.entries(dataTypesWithoutRelation).map( ([key, dataType]) => ({ - value: key as ObjectFieldDataType, + value: key as MetadataFieldDataType, ...dataType, }), )} diff --git a/front/src/modules/settings/data-model/constants/dataTypes.ts b/front/src/modules/settings/data-model/constants/dataTypes.ts index 05cbd200a..66a3ca28c 100644 --- a/front/src/modules/settings/data-model/constants/dataTypes.ts +++ b/front/src/modules/settings/data-model/constants/dataTypes.ts @@ -7,10 +7,10 @@ import { } from '@/ui/display/icon'; import { IconComponent } from '@/ui/display/icon/types/IconComponent'; -import { ObjectFieldDataType } from '../types/ObjectFieldDataType'; +import { MetadataFieldDataType } from '../types/ObjectFieldDataType'; export const dataTypes: Record< - ObjectFieldDataType, + MetadataFieldDataType, { label: string; Icon: IconComponent } > = { number: { label: 'Number', Icon: IconNumbers }, diff --git a/front/src/modules/settings/data-model/new-object/components/SettingsAvailableStandardObjectItemTableRow.tsx b/front/src/modules/settings/data-model/new-object/components/SettingsAvailableStandardObjectItemTableRow.tsx new file mode 100644 index 000000000..9c3b91501 --- /dev/null +++ b/front/src/modules/settings/data-model/new-object/components/SettingsAvailableStandardObjectItemTableRow.tsx @@ -0,0 +1,65 @@ +import { useTheme } from '@emotion/react'; +import styled from '@emotion/styled'; + +import { MetadataObject } from '@/metadata/types/MetadataObject'; +import { Checkbox } from '@/ui/input/components/Checkbox'; +import { useLazyLoadIcon } from '@/ui/input/hooks/useLazyLoadIcon'; +import { TableCell } from '@/ui/layout/table/components/TableCell'; +import { TableRow } from '@/ui/layout/table/components/TableRow'; + +type SettingsAvailableStandardObjectItemTableRowProps = { + isSelected?: boolean; + objectItem: MetadataObject; + onClick?: () => void; +}; + +export const StyledAvailableStandardObjectTableRow = styled(TableRow)` + grid-template-columns: 28px 148px 256px 80px; +`; + +const StyledCheckboxTableCell = styled(TableCell)` + justify-content: center; + padding: 0; + padding-left: ${({ theme }) => theme.spacing(1)}; +`; + +const StyledNameTableCell = styled(TableCell)` + color: ${({ theme }) => theme.font.color.primary}; + gap: ${({ theme }) => theme.spacing(2)}; +`; + +const StyledDescription = styled.div` + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +`; + +export const SettingsAvailableStandardObjectItemTableRow = ({ + isSelected, + objectItem, + onClick, +}: SettingsAvailableStandardObjectItemTableRowProps) => { + const theme = useTheme(); + + const { Icon } = useLazyLoadIcon(objectItem.icon ?? ''); + + return ( + + + + + + {!!Icon && } + {objectItem.labelPlural} + + + {objectItem.description} + + {objectItem.fields.length} + + ); +}; diff --git a/front/src/modules/settings/data-model/new-object/components/SettingsAvailableStandardObjectsSection.tsx b/front/src/modules/settings/data-model/new-object/components/SettingsAvailableStandardObjectsSection.tsx new file mode 100644 index 000000000..a25cc8ee0 --- /dev/null +++ b/front/src/modules/settings/data-model/new-object/components/SettingsAvailableStandardObjectsSection.tsx @@ -0,0 +1,53 @@ +import { MetadataObject } from '@/metadata/types/MetadataObject'; +import { H2Title } from '@/ui/display/typography/components/H2Title'; +import { Section } from '@/ui/layout/section/components/Section'; +import { Table } from '@/ui/layout/table/components/Table'; +import { TableBody } from '@/ui/layout/table/components/TableBody'; +import { TableHeader } from '@/ui/layout/table/components/TableHeader'; + +import { + SettingsAvailableStandardObjectItemTableRow, + StyledAvailableStandardObjectTableRow, +} from './SettingsAvailableStandardObjectItemTableRow'; + +type SettingsAvailableStandardObjectsSectionProps = { + objectItems: MetadataObject[]; + onChange: (selectedIds: Record) => void; + selectedIds: Record; +}; + +export const SettingsAvailableStandardObjectsSection = ({ + objectItems, + onChange, + selectedIds, +}: SettingsAvailableStandardObjectsSectionProps) => ( +
+ + + + + Name + Description + Fields + + + {objectItems.map((objectItem) => ( + + onChange({ + ...selectedIds, + [objectItem.id]: !selectedIds[objectItem.id], + }) + } + /> + ))} + +
+
+); diff --git a/front/src/modules/settings/data-model/new-object/components/SettingsNewObjectType.tsx b/front/src/modules/settings/data-model/new-object/components/SettingsNewObjectType.tsx index 0b6f0ad78..93d896f02 100644 --- a/front/src/modules/settings/data-model/new-object/components/SettingsNewObjectType.tsx +++ b/front/src/modules/settings/data-model/new-object/components/SettingsNewObjectType.tsx @@ -4,7 +4,6 @@ import styled from '@emotion/styled'; import { IconBox, IconDatabase, IconFileCheck } from '@/ui/display/icon'; import { SettingsObjectTypeCard } from './SettingsObjectTypeCard'; -import { SettingsStandardObjects } from './SettingsStandardObjects'; export type NewObjectType = 'Standard' | 'Custom' | 'Remote'; @@ -17,8 +16,6 @@ const StyledContainer = styled.div` display: flex; flex-direction: row; gap: ${({ theme }) => theme.spacing(2)}; - margin-bottom: ${({ theme }) => theme.spacing(8)}; - width: 100%; `; export const SettingsNewObjectType = ({ @@ -27,50 +24,47 @@ export const SettingsNewObjectType = ({ }: SettingsNewObjectTypeProps) => { const theme = useTheme(); return ( - <> - - - } - onClick={() => onTypeSelect?.('Standard')} - /> - - } - onClick={() => onTypeSelect?.('Custom')} - /> - - } - /> - - {selectedType === 'Standard' && } - + + + } + onClick={() => onTypeSelect?.('Standard')} + /> + + } + onClick={() => onTypeSelect?.('Custom')} + /> + + } + /> + ); }; diff --git a/front/src/modules/settings/data-model/new-object/components/SettingsStandardObjects.tsx b/front/src/modules/settings/data-model/new-object/components/SettingsStandardObjects.tsx deleted file mode 100644 index 31e1c2b4e..000000000 --- a/front/src/modules/settings/data-model/new-object/components/SettingsStandardObjects.tsx +++ /dev/null @@ -1,107 +0,0 @@ -import { useState } from 'react'; -import { useTheme } from '@emotion/react'; -import styled from '@emotion/styled'; - -import { H2Title } from '@/ui/display/typography/components/H2Title'; -import { Table } from '@/ui/layout/table/components/Table'; -import { TableCell } from '@/ui/layout/table/components/TableCell'; -import { TableHeader } from '@/ui/layout/table/components/TableHeader'; -import { TableRow } from '@/ui/layout/table/components/TableRow'; - -import { standardObjects } from '../../constants/mockObjects'; - -const StyledTableRow = styled(TableRow)<{ - selectedRows?: number[]; - rowNumber?: number; -}>` - align-items: center; - background: ${({ selectedRows, rowNumber, theme }) => - selectedRows?.includes(rowNumber!) - ? theme.accent.quaternary - : theme.background.primary}; - grid-template-columns: 36px 132px 240px 98.7px; -`; - -const StyledCheckboxCell = styled(TableCell)` - padding: 0 ${({ theme }) => theme.spacing(2)} 0 - ${({ theme }) => theme.spacing(1)}; -`; - -const StyledNameTableCell = styled(TableCell)` - gap: ${({ theme }) => theme.spacing(1)}; -`; - -const StyledDescriptionCell = styled.div<{ - align?: 'left' | 'center' | 'right'; -}>` - color: ${({ theme }) => theme.font.color.secondary}; - justify-content: ${({ align }) => - align === 'right' - ? 'flex-end' - : align === 'center' - ? 'center' - : 'flex-start'}; - overflow: hidden; - padding: 0 ${({ theme }) => theme.spacing(2)}; - padding: 0 ${({ theme }) => theme.spacing(2)}; - text-align: ${({ align }) => align ?? 'left'}; - text-overflow: ellipsis; - white-space: nowrap; -`; - -const StyledTable = styled(Table)` - display: grid; - gap: ${({ theme }) => theme.spacing(2)}; -`; - -export const SettingsStandardObjects = () => { - const theme = useTheme(); - const [selectedRows, setSelectedRows] = useState([]); - - return ( - <> - - - - - Name - Description - Fields - - {standardObjects.map((object, rowNumber) => ( - { - const indexOfRowClicked = selectedRows.indexOf(rowNumber); - if (indexOfRowClicked === -1) { - setSelectedRows([...selectedRows, rowNumber]); - } else { - const newSelectedRows = [...selectedRows]; - newSelectedRows.splice(indexOfRowClicked, 1); - setSelectedRows(newSelectedRows); - } - }} - key={object.name} - > - - - - - - {object.name} - - {object.description} - {object.fields} - - ))} - - - ); -}; diff --git a/front/src/modules/settings/data-model/object-details/components/SettingsObjectFieldDataType.tsx b/front/src/modules/settings/data-model/object-details/components/SettingsObjectFieldDataType.tsx index c3b70e89f..419e013a0 100644 --- a/front/src/modules/settings/data-model/object-details/components/SettingsObjectFieldDataType.tsx +++ b/front/src/modules/settings/data-model/object-details/components/SettingsObjectFieldDataType.tsx @@ -2,9 +2,9 @@ import { css, useTheme } from '@emotion/react'; import styled from '@emotion/styled'; import { dataTypes } from '../../constants/dataTypes'; -import { ObjectFieldDataType } from '../../types/ObjectFieldDataType'; +import { MetadataFieldDataType } from '../../types/ObjectFieldDataType'; -const StyledDataType = styled.div<{ value: ObjectFieldDataType }>` +const StyledDataType = styled.div<{ value: MetadataFieldDataType }>` align-items: center; border: 1px solid transparent; border-radius: ${({ theme }) => theme.border.radius.sm}; @@ -24,7 +24,7 @@ const StyledDataType = styled.div<{ value: ObjectFieldDataType }>` `; type SettingsObjectFieldDataTypeProps = { - value: ObjectFieldDataType; + value: MetadataFieldDataType; }; export const SettingsObjectFieldDataType = ({ diff --git a/front/src/modules/settings/data-model/object-details/components/SettingsObjectFieldItemTableRow.tsx b/front/src/modules/settings/data-model/object-details/components/SettingsObjectFieldItemTableRow.tsx index 3c348ee20..049328b2e 100644 --- a/front/src/modules/settings/data-model/object-details/components/SettingsObjectFieldItemTableRow.tsx +++ b/front/src/modules/settings/data-model/object-details/components/SettingsObjectFieldItemTableRow.tsx @@ -7,7 +7,7 @@ import { TableCell } from '@/ui/layout/table/components/TableCell'; import { TableRow } from '@/ui/layout/table/components/TableRow'; import { Field } from '~/generated-metadata/graphql'; -import { ObjectFieldDataType } from '../../types/ObjectFieldDataType'; +import { MetadataFieldDataType } from '../../types/ObjectFieldDataType'; import { SettingsObjectFieldDataType } from './SettingsObjectFieldDataType'; @@ -58,7 +58,7 @@ export const SettingsObjectFieldItemTableRow = ({ {fieldItem.isCustom ? 'Custom' : 'Standard'} {ActionIcon} diff --git a/front/src/modules/settings/data-model/types/ObjectFieldDataType.ts b/front/src/modules/settings/data-model/types/ObjectFieldDataType.ts index 4a262cfdd..64a91aa3e 100644 --- a/front/src/modules/settings/data-model/types/ObjectFieldDataType.ts +++ b/front/src/modules/settings/data-model/types/ObjectFieldDataType.ts @@ -1,4 +1,4 @@ -export type ObjectFieldDataType = +export type MetadataFieldDataType = | 'boolean' | 'number' | 'relation' diff --git a/front/src/modules/ui/layout/table/components/TableBody.tsx b/front/src/modules/ui/layout/table/components/TableBody.tsx new file mode 100644 index 000000000..7c9f99e54 --- /dev/null +++ b/front/src/modules/ui/layout/table/components/TableBody.tsx @@ -0,0 +1,10 @@ +import styled from '@emotion/styled'; + +const StyledTableBody = styled.div` + display: flex; + flex-direction: column; + gap: 2px; + padding: ${({ theme }) => theme.spacing(2)} 0; +`; + +export { StyledTableBody as TableBody }; diff --git a/front/src/modules/ui/layout/table/components/TableRow.tsx b/front/src/modules/ui/layout/table/components/TableRow.tsx index f47dee01e..a66291a12 100644 --- a/front/src/modules/ui/layout/table/components/TableRow.tsx +++ b/front/src/modules/ui/layout/table/components/TableRow.tsx @@ -1,6 +1,11 @@ import styled from '@emotion/styled'; -const StyledTableRow = styled.div<{ onClick?: () => void }>` +const StyledTableRow = styled.div<{ + isSelected?: boolean; + onClick?: () => void; +}>` + background-color: ${({ isSelected, theme }) => + isSelected ? theme.accent.quaternary : 'transparent'}; border-radius: ${({ theme }) => theme.border.radius.sm}; display: grid; grid-auto-columns: 1fr; diff --git a/front/src/modules/ui/layout/table/components/TableSection.tsx b/front/src/modules/ui/layout/table/components/TableSection.tsx index 849206a71..f1ffc9b4f 100644 --- a/front/src/modules/ui/layout/table/components/TableSection.tsx +++ b/front/src/modules/ui/layout/table/components/TableSection.tsx @@ -4,6 +4,8 @@ import styled from '@emotion/styled'; import { IconChevronDown, IconChevronUp } from '@/ui/display/icon'; +import { TableBody } from './TableBody'; + type TableSectionProps = { children: ReactNode; isInitiallyExpanded?: boolean; @@ -34,9 +36,8 @@ const StyledSection = styled.div<{ isExpanded: boolean }>` opacity ${({ theme }) => theme.animation.duration.normal}s; `; -const StyledSectionContent = styled.div` +const StyledSectionContent = styled(TableBody)` border-bottom: 1px solid ${({ theme }) => theme.border.color.light}; - padding: ${({ theme }) => theme.spacing(2)} 0; `; export const TableSection = ({ diff --git a/front/src/pages/settings/data-model/SettingsNewObject.tsx b/front/src/pages/settings/data-model/SettingsNewObject.tsx index 6deeca825..0cb777356 100644 --- a/front/src/pages/settings/data-model/SettingsNewObject.tsx +++ b/front/src/pages/settings/data-model/SettingsNewObject.tsx @@ -1,11 +1,12 @@ import { useState } from 'react'; import { useNavigate } from 'react-router-dom'; -import { useObjectMetadata } from '@/metadata/hooks/useObjectMetadata'; +import { useMetadataObjectForSettings } from '@/metadata/hooks/useMetadataObjectForSettings'; import { SaveAndCancelButtons } from '@/settings/components/SaveAndCancelButtons/SaveAndCancelButtons'; import { SettingsHeaderContainer } from '@/settings/components/SettingsHeaderContainer'; import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer'; import { SettingsObjectFormSection } from '@/settings/data-model/components/SettingsObjectFormSection'; +import { SettingsAvailableStandardObjectsSection } from '@/settings/data-model/new-object/components/SettingsAvailableStandardObjectsSection'; import { NewObjectType, SettingsNewObjectType, @@ -22,7 +23,15 @@ export const SettingsNewObject = () => { const [selectedObjectType, setSelectedObjectType] = useState('Standard'); - const { createObject } = useObjectMetadata(); + const { + activateMetadataObject: activateObject, + createMetadataObject: createObject, + disabledMetadataObjects: disabledObjects, + } = useMetadataObjectForSettings(); + + const [selectedStandardObjectIds, setSelectedStandardObjectIds] = useState< + Record + >({}); const [customFormValues, setCustomFormValues] = useState<{ description?: string; @@ -32,11 +41,24 @@ export const SettingsNewObject = () => { }>({ icon: 'IconPigMoney', labelPlural: '', labelSingular: '' }); const canSave = - selectedObjectType === 'Custom' && - !!customFormValues.labelPlural && - !!customFormValues.labelSingular; + (selectedObjectType === 'Standard' && + Object.values(selectedStandardObjectIds).some( + (isSelected) => isSelected, + )) || + (selectedObjectType === 'Custom' && + !!customFormValues.labelPlural && + !!customFormValues.labelSingular); const handleSave = async () => { + if (selectedObjectType === 'Standard') { + await Promise.all( + Object.entries(selectedStandardObjectIds).map( + ([standardObjectId, isSelected]) => + isSelected ? activateObject({ id: standardObjectId }) : undefined, + ), + ); + } + if (selectedObjectType === 'Custom') { await createObject({ labelPlural: customFormValues.labelPlural, @@ -69,7 +91,7 @@ export const SettingsNewObject = () => {
{ onTypeSelect={setSelectedObjectType} />
+ {selectedObjectType === 'Standard' && ( + !isCustom)} + onChange={(selectedIds) => + setSelectedStandardObjectIds((previousSelectedIds) => ({ + ...previousSelectedIds, + ...selectedIds, + })) + } + selectedIds={selectedStandardObjectIds} + /> + )} {selectedObjectType === 'Custom' && ( <> { const navigate = useNavigate(); const { objectSlug = '' } = useParams(); - const { disableObject, findActiveObjectBySlug, loading } = - useObjectMetadata(); - const activeObject = findActiveObjectBySlug(objectSlug); + const { disableMetadataObject, findActiveMetadataObjectBySlug, loading } = + useMetadataObjectForSettings(); + + const activeMetadataObject = findActiveMetadataObjectBySlug(objectSlug); useEffect(() => { if (loading) return; - if (!activeObject) navigate(AppPath.NotFound); - }, [activeObject, loading, navigate]); + if (!activeMetadataObject) navigate(AppPath.NotFound); + }, [activeMetadataObject, loading, navigate]); - const { activateField, disableField, eraseField } = useFieldMetadata(); + const { activateMetadataField, disableMetadataField, eraseMetadataField } = + useMetadataField(); - if (!activeObject) return null; + if (!activeMetadataObject) return null; - const activeFields = activeObject.fields.filter( - (fieldItem) => fieldItem.isActive, + const activeMetadataFields = activeMetadataObject.fields.filter( + (metadataField) => metadataField.isActive, ); - const disabledFields = activeObject.fields.filter( - (fieldItem) => !fieldItem.isActive, + const disabledMetadataFields = activeMetadataObject.fields.filter( + (metadataField) => !metadataField.isActive, ); const handleDisable = async () => { - await disableObject(activeObject); + await disableMetadataObject(activeMetadataObject); navigate('/settings/objects'); }; @@ -65,20 +67,20 @@ export const SettingsObjectDetail = () => { navigate('./edit')} />
@@ -87,36 +89,44 @@ export const SettingsObjectDetail = () => { Data type - {!!activeFields.length && ( + {!!activeMetadataFields.length && ( - {activeFields.map((fieldItem) => ( + {activeMetadataFields.map((activeMetadataField) => ( navigate(`./${getFieldSlug(fieldItem)}`)} - onDisable={() => disableField(fieldItem)} + isCustomField={activeMetadataField.isCustom} + scopeKey={activeMetadataField.id} + onEdit={() => + navigate(`./${getFieldSlug(activeMetadataField)}`) + } + onDisable={() => + disableMetadataField(activeMetadataField) + } /> } /> ))} )} - {!!disabledFields.length && ( + {!!disabledMetadataFields.length && ( - {disabledFields.map((fieldItem) => ( + {disabledMetadataFields.map((disabledMetadataField) => ( activateField(fieldItem)} - onErase={() => eraseField(fieldItem)} + isCustomField={disabledMetadataField.isCustom} + scopeKey={disabledMetadataField.id} + onActivate={() => + activateMetadataField(disabledMetadataField) + } + onErase={() => + eraseMetadataField(disabledMetadataField) + } /> } /> @@ -132,7 +142,7 @@ export const SettingsObjectDetail = () => { variant="secondary" onClick={() => navigate( - disabledFields.length + disabledMetadataFields.length ? './new-field/step-1' : './new-field/step-2', ) diff --git a/front/src/pages/settings/data-model/SettingsObjectEdit.tsx b/front/src/pages/settings/data-model/SettingsObjectEdit.tsx index 4bc3285c6..c61b80516 100644 --- a/front/src/pages/settings/data-model/SettingsObjectEdit.tsx +++ b/front/src/pages/settings/data-model/SettingsObjectEdit.tsx @@ -1,7 +1,7 @@ import { useEffect, useState } from 'react'; import { useNavigate, useParams } from 'react-router-dom'; -import { useObjectMetadata } from '@/metadata/hooks/useObjectMetadata'; +import { useMetadataObjectForSettings } from '@/metadata/hooks/useMetadataObjectForSettings'; import { getObjectSlug } from '@/metadata/utils/getObjectSlug'; import { SaveAndCancelButtons } from '@/settings/components/SaveAndCancelButtons/SaveAndCancelButtons'; import { SettingsHeaderContainer } from '@/settings/components/SettingsHeaderContainer'; @@ -20,9 +20,14 @@ export const SettingsObjectEdit = () => { const navigate = useNavigate(); const { objectSlug = '' } = useParams(); - const { disableObject, editObject, findActiveObjectBySlug, loading } = - useObjectMetadata(); - const activeObject = findActiveObjectBySlug(objectSlug); + const { + disableMetadataObject, + editMetadataObject, + findActiveMetadataObjectBySlug, + loading, + } = useMetadataObjectForSettings(); + + const activeMetadataObject = findActiveMetadataObjectBySlug(objectSlug); const [formValues, setFormValues] = useState< Partial<{ @@ -36,44 +41,44 @@ export const SettingsObjectEdit = () => { useEffect(() => { if (loading) return; - if (!activeObject) { + if (!activeMetadataObject) { navigate(AppPath.NotFound); return; } if (!Object.keys(formValues).length) { setFormValues({ - icon: activeObject.icon ?? undefined, - labelSingular: activeObject.labelSingular, - labelPlural: activeObject.labelPlural, - description: activeObject.description ?? undefined, + icon: activeMetadataObject.icon ?? undefined, + labelSingular: activeMetadataObject.labelSingular, + labelPlural: activeMetadataObject.labelPlural, + description: activeMetadataObject.description ?? undefined, }); } - }, [activeObject, formValues, loading, navigate]); + }, [activeMetadataObject, formValues, loading, navigate]); - if (!activeObject) return null; + if (!activeMetadataObject) return null; const areRequiredFieldsFilled = !!formValues.labelSingular && !!formValues.labelPlural; const hasChanges = - formValues.description !== activeObject.description || - formValues.icon !== activeObject.icon || - formValues.labelPlural !== activeObject.labelPlural || - formValues.labelSingular !== activeObject.labelSingular; + formValues.description !== activeMetadataObject.description || + formValues.icon !== activeMetadataObject.icon || + formValues.labelPlural !== activeMetadataObject.labelPlural || + formValues.labelSingular !== activeMetadataObject.labelSingular; const canSave = areRequiredFieldsFilled && hasChanges; const handleSave = async () => { - const editedObject = { ...activeObject, ...formValues }; + const editedMetadataObject = { ...activeMetadataObject, ...formValues }; - await editObject(editedObject); + await editMetadataObject(editedMetadataObject); - navigate(`/settings/objects/${getObjectSlug(editedObject)}`); + navigate(`/settings/objects/${getObjectSlug(editedMetadataObject)}`); }; const handleDisable = async () => { - await disableObject(activeObject); + await disableMetadataObject(activeMetadataObject); navigate('/settings/objects'); }; @@ -85,13 +90,13 @@ export const SettingsObjectEdit = () => { links={[ { children: 'Objects', href: '/settings/objects' }, { - children: activeObject.labelPlural, + children: activeMetadataObject.labelPlural, href: `/settings/objects/${objectSlug}`, }, { children: 'Edit' }, ]} /> - {!!activeObject.isCustom && ( + {!!activeMetadataObject.isCustom && ( navigate(`/settings/objects/${objectSlug}`)} @@ -100,7 +105,7 @@ export const SettingsObjectEdit = () => { )} @@ -111,7 +116,7 @@ export const SettingsObjectEdit = () => { } /> { const navigate = useNavigate(); const { objectSlug = '', fieldSlug = '' } = useParams(); - const { findActiveObjectBySlug, loading } = useObjectMetadata(); - const activeObject = findActiveObjectBySlug(objectSlug); + const { findActiveMetadataObjectBySlug, loading } = + useMetadataObjectForSettings(); - const { disableField } = useFieldMetadata(); - const activeField = activeObject?.fields.find( - (field) => field.isActive && getFieldSlug(field) === fieldSlug, + const activeMetadataObject = findActiveMetadataObjectBySlug(objectSlug); + + const { disableMetadataField: disableField } = useMetadataField(); + const activeMetadataField = activeMetadataObject?.fields.find( + (metadataField) => + metadataField.isActive && getFieldSlug(metadataField) === fieldSlug, ); useEffect(() => { if (loading) return; - if (!activeObject || !activeField) navigate(AppPath.NotFound); - }, [activeField, activeObject, loading, navigate]); + if (!activeMetadataObject || !activeMetadataField) + navigate(AppPath.NotFound); + }, [activeMetadataField, activeMetadataObject, loading, navigate]); - if (!activeObject || !activeField) return null; + if (!activeMetadataObject || !activeMetadataField) return null; const handleDisable = async () => { - await disableField(activeField); + await disableField(activeMetadataField); navigate(`/settings/objects/${objectSlug}`); }; @@ -49,23 +53,23 @@ export const SettingsObjectFieldEdit = () => { links={[ { children: 'Objects', href: '/settings/objects' }, { - children: activeObject.labelPlural, + children: activeMetadataObject.labelPlural, href: `/settings/objects/${objectSlug}`, }, - { children: activeField.label }, + { children: activeMetadataField.label }, ]} /> undefined} />
diff --git a/front/src/pages/settings/data-model/SettingsObjectNewField/SettingsObjectNewFieldStep1.tsx b/front/src/pages/settings/data-model/SettingsObjectNewField/SettingsObjectNewFieldStep1.tsx index 723439292..f60923ff2 100644 --- a/front/src/pages/settings/data-model/SettingsObjectNewField/SettingsObjectNewFieldStep1.tsx +++ b/front/src/pages/settings/data-model/SettingsObjectNewField/SettingsObjectNewFieldStep1.tsx @@ -2,7 +2,7 @@ import { useEffect } from 'react'; import { useNavigate, useParams } from 'react-router-dom'; import styled from '@emotion/styled'; -import { useObjectMetadata } from '@/metadata/hooks/useObjectMetadata'; +import { useMetadataObjectForSettings } from '@/metadata/hooks/useMetadataObjectForSettings'; import { SaveAndCancelButtons } from '@/settings/components/SaveAndCancelButtons/SaveAndCancelButtons'; import { SettingsHeaderContainer } from '@/settings/components/SettingsHeaderContainer'; import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer'; @@ -36,21 +36,23 @@ export const SettingsObjectNewFieldStep1 = () => { const navigate = useNavigate(); const { objectSlug = '' } = useParams(); - const { findActiveObjectBySlug, loading } = useObjectMetadata(); - const activeObject = findActiveObjectBySlug(objectSlug); + const { findActiveMetadataObjectBySlug, loading } = + useMetadataObjectForSettings(); + + const activeMetadataObject = findActiveMetadataObjectBySlug(objectSlug); useEffect(() => { if (loading) return; - if (!activeObject) navigate(AppPath.NotFound); - }, [activeObject, loading, navigate]); + if (!activeMetadataObject) navigate(AppPath.NotFound); + }, [activeMetadataObject, loading, navigate]); - if (!activeObject) return null; + if (!activeMetadataObject) return null; - const activeFields = activeObject.fields.filter( - (fieldItem) => fieldItem.isActive, + const activeMetadataFields = activeMetadataObject.fields.filter( + (metadataField) => metadataField.isActive, ); - const disabledFields = activeObject.fields.filter( - (fieldItem) => !fieldItem.isActive, + const disabledMetadataFields = activeMetadataObject.fields.filter( + (metadataField) => !metadataField.isActive, ); return ( @@ -61,7 +63,7 @@ export const SettingsObjectNewFieldStep1 = () => { links={[ { children: 'Objects', href: '/settings/objects' }, { - children: activeObject.labelPlural, + children: activeMetadataObject.labelPlural, href: `/settings/objects/${objectSlug}`, }, { children: 'New Field' }, @@ -85,12 +87,12 @@ export const SettingsObjectNewFieldStep1 = () => { Data type - {!!activeFields.length && ( + {!!activeMetadataFields.length && ( - {activeFields.map((fieldItem) => ( + {activeMetadataFields.map((activeMetadataField) => ( } @@ -98,12 +100,12 @@ export const SettingsObjectNewFieldStep1 = () => { ))} )} - {!!disabledFields.length && ( + {!!disabledMetadataFields.length && ( - {disabledFields.map((fieldItem) => ( + {disabledMetadataFields.map((disabledMetadataField) => ( } diff --git a/front/src/pages/settings/data-model/SettingsObjectNewField/SettingsObjectNewFieldStep2.tsx b/front/src/pages/settings/data-model/SettingsObjectNewField/SettingsObjectNewFieldStep2.tsx index fc08068bc..42edc7b22 100644 --- a/front/src/pages/settings/data-model/SettingsObjectNewField/SettingsObjectNewFieldStep2.tsx +++ b/front/src/pages/settings/data-model/SettingsObjectNewField/SettingsObjectNewFieldStep2.tsx @@ -1,14 +1,14 @@ import { useEffect, useState } from 'react'; import { useNavigate, useParams } from 'react-router-dom'; -import { useFieldMetadata } from '@/metadata/hooks/useFieldMetadata'; -import { useObjectMetadata } from '@/metadata/hooks/useObjectMetadata'; +import { useMetadataField } from '@/metadata/hooks/useMetadataField'; +import { useMetadataObjectForSettings } from '@/metadata/hooks/useMetadataObjectForSettings'; import { SaveAndCancelButtons } from '@/settings/components/SaveAndCancelButtons/SaveAndCancelButtons'; import { SettingsHeaderContainer } from '@/settings/components/SettingsHeaderContainer'; import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer'; import { SettingsObjectFieldFormSection } from '@/settings/data-model/components/SettingsObjectFieldFormSection'; import { SettingsObjectFieldTypeSelectSection } from '@/settings/data-model/components/SettingsObjectFieldTypeSelectSection'; -import { ObjectFieldDataType } from '@/settings/data-model/types/ObjectFieldDataType'; +import { MetadataFieldDataType } from '@/settings/data-model/types/ObjectFieldDataType'; import { AppPath } from '@/types/AppPath'; import { IconSettings } from '@/ui/display/icon'; import { SubMenuTopBarContainer } from '@/ui/layout/page/SubMenuTopBarContainer'; @@ -17,28 +17,34 @@ import { Breadcrumb } from '@/ui/navigation/bread-crumb/components/Breadcrumb'; export const SettingsObjectNewFieldStep2 = () => { const navigate = useNavigate(); const { objectSlug = '' } = useParams(); - const { findActiveObjectBySlug, loading } = useObjectMetadata(); - const activeObject = findActiveObjectBySlug(objectSlug); - const { createField } = useFieldMetadata(); + + const { findActiveMetadataObjectBySlug, loading } = + useMetadataObjectForSettings(); + + const activeMetadataObject = findActiveMetadataObjectBySlug(objectSlug); + const { createMetadataField } = useMetadataField(); useEffect(() => { if (loading) return; - if (!activeObject) navigate(AppPath.NotFound); - }, [activeObject, loading, navigate]); + if (!activeMetadataObject) navigate(AppPath.NotFound); + }, [activeMetadataObject, loading, navigate]); const [formValues, setFormValues] = useState<{ description?: string; icon: string; label: string; - type: ObjectFieldDataType; + type: MetadataFieldDataType; }>({ icon: 'IconUsers', label: '', type: 'number' }); - if (!activeObject) return null; + if (!activeMetadataObject) return null; const canSave = !!formValues.label; const handleSave = async () => { - await createField({ ...formValues, objectId: activeObject.id }); + await createMetadataField({ + ...formValues, + objectId: activeMetadataObject.id, + }); navigate(`/settings/objects/${objectSlug}`); }; @@ -50,7 +56,7 @@ export const SettingsObjectNewFieldStep2 = () => { links={[ { children: 'Objects', href: '/settings/objects' }, { - children: activeObject.labelPlural, + children: activeMetadataObject.labelPlural, href: `/settings/objects/${objectSlug}`, }, { children: 'New Field' }, diff --git a/front/src/pages/settings/data-model/SettingsObjects.tsx b/front/src/pages/settings/data-model/SettingsObjects.tsx index 161b4d805..d191486a5 100644 --- a/front/src/pages/settings/data-model/SettingsObjects.tsx +++ b/front/src/pages/settings/data-model/SettingsObjects.tsx @@ -2,7 +2,7 @@ import { useNavigate } from 'react-router-dom'; import { useTheme } from '@emotion/react'; import styled from '@emotion/styled'; -import { useObjectMetadata } from '@/metadata/hooks/useObjectMetadata'; +import { useMetadataObjectForSettings } from '@/metadata/hooks/useMetadataObjectForSettings'; import { getObjectSlug } from '@/metadata/utils/getObjectSlug'; import { SettingsHeaderContainer } from '@/settings/components/SettingsHeaderContainer'; import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer'; @@ -34,8 +34,12 @@ export const SettingsObjects = () => { const theme = useTheme(); const navigate = useNavigate(); - const { activateObject, activeObjects, disabledObjects, eraseObject } = - useObjectMetadata(); + const { + activateMetadataObject, + activeMetadataObjects, + disabledMetadataObjects, + eraseMetadataObject, + } = useMetadataObjectForSettings(); return ( @@ -62,12 +66,12 @@ export const SettingsObjects = () => { Instances - {!!activeObjects.length && ( + {!!activeMetadataObjects.length && ( - {activeObjects.map((objectItem) => ( + {activeMetadataObjects.map((activeMetadataObject) => ( { } onClick={() => navigate( - `/settings/objects/${getObjectSlug(objectItem)}`, + `/settings/objects/${getObjectSlug( + activeMetadataObject, + )}`, ) } /> ))} )} - {!!disabledObjects.length && ( + {!!disabledMetadataObjects.length && ( - {disabledObjects.map((objectItem) => ( + {disabledMetadataObjects.map((disabledMetadataObject) => ( activateObject(objectItem)} - onErase={() => eraseObject(objectItem)} + isCustomObject={disabledMetadataObject.isCustom} + scopeKey={disabledMetadataObject.namePlural} + onActivate={() => + activateMetadataObject(disabledMetadataObject) + } + onErase={() => + eraseMetadataObject(disabledMetadataObject) + } /> } /> diff --git a/infra/dev/Makefile b/infra/dev/Makefile index a83cb95bf..a5fa5e589 100644 --- a/infra/dev/Makefile +++ b/infra/dev/Makefile @@ -10,6 +10,7 @@ provision-postgres: @docker rm twenty_postgres || true @docker volume rm twenty_db_data || true @docker compose up --build postgres -d + @cd ../../server && yarn database:setup && yarn database:reset up: @docker compose up -d diff --git a/server/src/database/seeds/metadata.ts b/server/src/database/seeds/metadata.ts index 4c1ab3887..8964d8e0a 100644 --- a/server/src/database/seeds/metadata.ts +++ b/server/src/database/seeds/metadata.ts @@ -15,18 +15,18 @@ export const seedMetadata = async (prisma: PrismaClient) => { await prisma.$queryRawUnsafe(`CREATE TABLE IF NOT EXISTS workspace_twenty_7icsva0r6s00mpcp6cwg4w4rd.company( - id TEXT PRIMARY KEY, - name TEXT NOT NULL, + "id" TEXT PRIMARY KEY, + "name" TEXT NOT NULL, "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(), "updatedAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(), "deletedAt" TIMESTAMP WITH TIME ZONE, - domainName TEXT NOT NULL, - address TEXT NOT NULL, - employees INTEGER NOT NULL + "domainName" TEXT NOT NULL, + "address" TEXT NOT NULL, + "employees" INTEGER NOT NULL ); `); await prisma.$queryRawUnsafe(`INSERT INTO workspace_twenty_7icsva0r6s00mpcp6cwg4w4rd.company( - id, name, domainName, address, employees + "id", "name", "domainName", "address", "employees" ) VALUES ( '89bb825c-171e-4bcc-9cf7-43448d6fb278', 'Airbnb', 'airbnb.com', 'San Francisco', 5000 @@ -44,19 +44,19 @@ export const seedMetadata = async (prisma: PrismaClient) => { id, name_singular, name_plural, label_singular, label_plural, description, icon, target_table_name, is_custom, is_active, workspace_id, data_source_id ) VALUES ( - 'ba391617-ee08-432f-9438-2e17df5ac279', 'companyV2', 'companiesV2', 'Company', 'Companies', 'Companies', 'company', 'company', false, true, 'twenty-7ed9d212-1c25-4d02-bf25-6aeccf7ea419', 'b37b2163-7f63-47a9-b1b3-6c7290ca9fb1' + 'ba391617-ee08-432f-9438-2e17df5ac279', 'companyV2', 'companiesV2', 'Company', 'Companies', 'Companies', 'IconBuilding', 'company', false, true, 'twenty-7ed9d212-1c25-4d02-bf25-6aeccf7ea419', 'b37b2163-7f63-47a9-b1b3-6c7290ca9fb1' ) ON CONFLICT DO NOTHING`); await prisma.$queryRawUnsafe(`INSERT INTO metadata.field_metadata( id, object_id, type, name, label, target_column_map, description, icon, enums, is_custom, is_active, is_nullable, workspace_id ) VALUES ( - '22f5906d-153f-448c-b254-28adce721dcd', 'ba391617-ee08-432f-9438-2e17df5ac279', 'text', 'name', 'Name', '{"value": "name"}', 'Name', 'user', NULL, false, true, false, 'twenty-7ed9d212-1c25-4d02-bf25-6aeccf7ea419' + '22f5906d-153f-448c-b254-28adce721dcd', 'ba391617-ee08-432f-9438-2e17df5ac279', 'text', 'name', 'Name', '{"value": "name"}', 'Name', 'IconUser', NULL, false, true, false, 'twenty-7ed9d212-1c25-4d02-bf25-6aeccf7ea419' ), ( - '19bfab29-1cbb-4ce2-9117-8540ac45a0f1', 'ba391617-ee08-432f-9438-2e17df5ac279', 'text', 'domainName', 'Domain Name', '{"value": "domainName"}', 'Domain Name', 'link', NULL, false, true, true, 'twenty-7ed9d212-1c25-4d02-bf25-6aeccf7ea419' + '19bfab29-1cbb-4ce2-9117-8540ac45a0f1', 'ba391617-ee08-432f-9438-2e17df5ac279', 'text', 'domainName', 'Domain Name', '{"value": "domainName"}', 'Domain Name', 'IconExternalLink', NULL, false, true, true, 'twenty-7ed9d212-1c25-4d02-bf25-6aeccf7ea419' ), ( - '70130f27-9497-4b44-a04c-1a0fb9a4829c', 'ba391617-ee08-432f-9438-2e17df5ac279', 'text', 'address', 'Address', '{"value": "address"}', 'Address', 'location', NULL, false, true, true, 'twenty-7ed9d212-1c25-4d02-bf25-6aeccf7ea419' + '70130f27-9497-4b44-a04c-1a0fb9a4829c', 'ba391617-ee08-432f-9438-2e17df5ac279', 'text', 'address', 'Address', '{"value": "address"}', 'Address', 'IconMap', NULL, false, true, true, 'twenty-7ed9d212-1c25-4d02-bf25-6aeccf7ea419' ), ( - '2a63c30e-8e80-475b-b5d7-9dda17adc537', 'ba391617-ee08-432f-9438-2e17df5ac279', 'number', 'employees', 'Employees', '{"value": "employees"}', 'Employees', 'people', NULL, false, true, true, 'twenty-7ed9d212-1c25-4d02-bf25-6aeccf7ea419' + '2a63c30e-8e80-475b-b5d7-9dda17adc537', 'ba391617-ee08-432f-9438-2e17df5ac279', 'number', 'employees', 'Employees', '{"value": "employees"}', 'Employees', 'IconUsers', NULL, false, true, true, 'twenty-7ed9d212-1c25-4d02-bf25-6aeccf7ea419' ) ON CONFLICT DO NOTHING`); }; diff --git a/server/src/metadata/field-metadata/field-metadata.entity.ts b/server/src/metadata/field-metadata/field-metadata.entity.ts index d7bc49550..8a584f1c6 100644 --- a/server/src/metadata/field-metadata/field-metadata.entity.ts +++ b/server/src/metadata/field-metadata/field-metadata.entity.ts @@ -36,6 +36,7 @@ export type FieldMetadataTargetColumnMap = { defaultResultSize: 10, disableFilter: true, disableSort: true, + maxResultsSize: 1000, }) @Unique('IndexOnNameObjectIdAndWorkspaceIdUnique', [ 'name', diff --git a/server/src/metadata/object-metadata/object-metadata.entity.ts b/server/src/metadata/object-metadata/object-metadata.entity.ts index e8aa9ab7b..cc10cd74d 100644 --- a/server/src/metadata/object-metadata/object-metadata.entity.ts +++ b/server/src/metadata/object-metadata/object-metadata.entity.ts @@ -33,6 +33,7 @@ import { BeforeCreateOneObject } from './hooks/before-create-one-object.hook'; defaultResultSize: 10, disableFilter: true, disableSort: true, + maxResultsSize: 1000, }) @CursorConnection('fields', () => FieldMetadata) @Unique('IndexOnNameSingularAndWorkspaceIdUnique', [