From f332213e0d87cd8f8ff9070d24f3d3f52a275295 Mon Sep 17 00:00:00 2001 From: Thomas Trompette Date: Thu, 11 Apr 2024 17:58:02 +0200 Subject: [PATCH] Fix remote object read-only + remove relations (#4921) - Set `readOnly` boolean in table row context. Preventing updates and deletion - Show page is null for remote objects. No need for complicated design since this is temporary? - Relation creations are now behind a feature flag for remote objects - Refetch objects and views after syncing objects --------- Co-authored-by: Thomas Trompette --- .../databases/hooks/useSyncRemoteTable.ts | 26 +++- .../databases/hooks/useUnsyncRemoteTable.ts | 11 +- .../hooks/useFindManyObjectMetadataItems.ts | 3 +- .../hooks/useRecordActionBar.tsx | 32 ++-- .../record-field/components/FieldInput.tsx | 4 +- .../components/RecordInlineCell.tsx | 1 + .../components/RecordTableRow.tsx | 1 + .../contexts/RecordTableRowContext.ts | 1 + .../components/RecordTableCell.tsx | 3 + .../components/RecordTableCellContainer.tsx | 5 +- .../hooks/useOpenRecordTableCell.ts | 13 +- .../SettingsObjectFieldItemTableRow.tsx | 8 +- .../components/SettingsObjectItemTableRow.tsx | 6 +- .../components/SettingsObjectSummaryCard.tsx | 14 +- .../objects/SettingsDataModelIsCustomTag.tsx | 18 --- .../SettingsDataModelObjectSummary.tsx | 11 +- .../SettingsDataModelObjectTypeTag.tsx | 21 +++ .../data-model/utils/getObjectTypeLabel.ts | 39 +++++ ...tingsIntegrationDatabaseTablesListCard.tsx | 2 +- .../pages/object-record/RecordShowPage.tsx | 5 + .../data-model/SettingsObjectDetail.tsx | 3 +- .../SettingsObjectNewFieldStep1.tsx | 1 + .../feature-flag/feature-flag.entity.ts | 1 + .../object-metadata/object-metadata.module.ts | 5 + .../object-metadata.service.ts | 137 ++++++++++++------ ...pace-migrations-for-custom-object.util.ts} | 2 +- ...pace-migrations-for-remote-object.util.ts} | 54 +------ .../remote-table/remote-table.service.ts | 4 +- .../commands/add-standard-id.command.ts | 2 + 29 files changed, 275 insertions(+), 158 deletions(-) delete mode 100644 packages/twenty-front/src/modules/settings/data-model/objects/SettingsDataModelIsCustomTag.tsx create mode 100644 packages/twenty-front/src/modules/settings/data-model/objects/SettingsDataModelObjectTypeTag.tsx create mode 100644 packages/twenty-front/src/modules/settings/data-model/utils/getObjectTypeLabel.ts rename packages/twenty-server/src/engine/metadata-modules/object-metadata/utils/{build-workspace-migrations-for-custom-object.util.ts => create-workspace-migrations-for-custom-object.util.ts} (99%) rename packages/twenty-server/src/engine/metadata-modules/object-metadata/utils/{build-workspace-migrations-for-remote-object.util.ts => create-workspace-migrations-for-remote-object.util.ts} (78%) diff --git a/packages/twenty-front/src/modules/databases/hooks/useSyncRemoteTable.ts b/packages/twenty-front/src/modules/databases/hooks/useSyncRemoteTable.ts index ee891a4fb..7a3a39ecb 100644 --- a/packages/twenty-front/src/modules/databases/hooks/useSyncRemoteTable.ts +++ b/packages/twenty-front/src/modules/databases/hooks/useSyncRemoteTable.ts @@ -1,10 +1,13 @@ import { useCallback } from 'react'; -import { ApolloClient, useMutation } from '@apollo/client'; +import { ApolloClient, useApolloClient, useMutation } from '@apollo/client'; import { getOperationName } from '@apollo/client/utilities'; import { SYNC_REMOTE_TABLE } from '@/databases/graphql/mutations/syncRemoteTable'; import { GET_MANY_REMOTE_TABLES } from '@/databases/graphql/queries/findManyRemoteTables'; import { useApolloMetadataClient } from '@/object-metadata/hooks/useApolloMetadataClient'; +import { useFindManyObjectMetadataItems } from '@/object-metadata/hooks/useFindManyObjectMetadataItems'; +import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular'; +import { useFindManyRecordsQuery } from '@/object-record/hooks/useFindManyRecordsQuery'; import { RemoteTableInput, SyncRemoteTableMutation, @@ -13,6 +16,14 @@ import { export const useSyncRemoteTable = () => { const apolloMetadataClient = useApolloMetadataClient(); + const apolloClient = useApolloClient(); + + const { refetch: refetchObjectMetadataItems } = + useFindManyObjectMetadataItems(); + + const { findManyRecordsQuery: findManyViewsQuery } = useFindManyRecordsQuery({ + objectNameSingular: CoreObjectNameSingular.View, + }); const [mutate] = useMutation< SyncRemoteTableMutation, @@ -23,15 +34,24 @@ export const useSyncRemoteTable = () => { const syncRemoteTable = useCallback( async (input: RemoteTableInput) => { - return await mutate({ + const remoteTable = await mutate({ variables: { input, }, awaitRefetchQueries: true, refetchQueries: [getOperationName(GET_MANY_REMOTE_TABLES) ?? ''], }); + + // TODO: we should return the tables with the columns and store in cache instead of refetching + await refetchObjectMetadataItems(); + await apolloClient.query({ + query: findManyViewsQuery, + fetchPolicy: 'network-only', + }); + + return remoteTable; }, - [mutate], + [apolloClient, findManyViewsQuery, mutate, refetchObjectMetadataItems], ); return { diff --git a/packages/twenty-front/src/modules/databases/hooks/useUnsyncRemoteTable.ts b/packages/twenty-front/src/modules/databases/hooks/useUnsyncRemoteTable.ts index 97fd3a363..6bc85507f 100644 --- a/packages/twenty-front/src/modules/databases/hooks/useUnsyncRemoteTable.ts +++ b/packages/twenty-front/src/modules/databases/hooks/useUnsyncRemoteTable.ts @@ -5,6 +5,7 @@ import { getOperationName } from '@apollo/client/utilities'; import { UNSYNC_REMOTE_TABLE } from '@/databases/graphql/mutations/unsyncRemoteTable'; import { GET_MANY_REMOTE_TABLES } from '@/databases/graphql/queries/findManyRemoteTables'; import { useApolloMetadataClient } from '@/object-metadata/hooks/useApolloMetadataClient'; +import { useFindManyObjectMetadataItems } from '@/object-metadata/hooks/useFindManyObjectMetadataItems'; import { RemoteTableInput, UnsyncRemoteTableMutation, @@ -13,6 +14,8 @@ import { export const useUnsyncRemoteTable = () => { const apolloMetadataClient = useApolloMetadataClient(); + const { refetch: refetchObjectMetadataItems } = + useFindManyObjectMetadataItems(); const [mutate] = useMutation< UnsyncRemoteTableMutation, @@ -23,15 +26,19 @@ export const useUnsyncRemoteTable = () => { const unsyncRemoteTable = useCallback( async (input: RemoteTableInput) => { - return await mutate({ + const remoteTable = await mutate({ variables: { input, }, awaitRefetchQueries: true, refetchQueries: [getOperationName(GET_MANY_REMOTE_TABLES) ?? ''], }); + + await refetchObjectMetadataItems(); + + return remoteTable; }, - [mutate], + [mutate, refetchObjectMetadataItems], ); return { diff --git a/packages/twenty-front/src/modules/object-metadata/hooks/useFindManyObjectMetadataItems.ts b/packages/twenty-front/src/modules/object-metadata/hooks/useFindManyObjectMetadataItems.ts index b90dd55c3..203550cb6 100644 --- a/packages/twenty-front/src/modules/object-metadata/hooks/useFindManyObjectMetadataItems.ts +++ b/packages/twenty-front/src/modules/object-metadata/hooks/useFindManyObjectMetadataItems.ts @@ -28,7 +28,7 @@ export const useFindManyObjectMetadataItems = ({ const { enqueueSnackBar } = useSnackBar(); - const { data, loading, error } = useQuery< + const { data, loading, error, refetch } = useQuery< ObjectMetadataItemsQuery, ObjectMetadataItemsQueryVariables >(FIND_MANY_OBJECT_METADATA_ITEMS, { @@ -59,5 +59,6 @@ export const useFindManyObjectMetadataItems = ({ objectMetadataItems, loading, error, + refetch, }; }; diff --git a/packages/twenty-front/src/modules/object-record/record-action-bar/hooks/useRecordActionBar.tsx b/packages/twenty-front/src/modules/object-record/record-action-bar/hooks/useRecordActionBar.tsx index 037945376..f8370cfb2 100644 --- a/packages/twenty-front/src/modules/object-record/record-action-bar/hooks/useRecordActionBar.tsx +++ b/packages/twenty-front/src/modules/object-record/record-action-bar/hooks/useRecordActionBar.tsx @@ -106,7 +106,21 @@ export const useRecordActionBar = ({ recordIndexId: objectMetadataItem.namePlural, }); + const isRemoteObject = objectMetadataItem.isRemote; + const baseActions: ContextMenuEntry[] = useMemo( + () => [ + { + label: `${progress === undefined ? `Export` : `Export (${progress}%)`}`, + Icon: IconFileExport, + accent: 'default', + onClick: () => download(), + }, + ], + [download, progress], + ); + + const deletionActions: ContextMenuEntry[] = useMemo( () => [ { label: 'Delete', @@ -130,17 +144,9 @@ export const useRecordActionBar = ({ /> ), }, - { - label: `${progress === undefined ? `Export` : `Export (${progress}%)`}`, - Icon: IconFileExport, - accent: 'default', - onClick: () => download(), - }, ], [ handleDeleteClick, - download, - progress, selectedRecordIds, isDeleteRecordsModalOpen, setIsDeleteRecordsModalOpen, @@ -160,8 +166,9 @@ export const useRecordActionBar = ({ return { setContextMenuEntries: useCallback(() => { setContextMenuEntries([ + ...(isRemoteObject ? [] : deletionActions), ...baseActions, - ...(isFavorite && hasOnlyOneRecordSelected + ...(!isRemoteObject && isFavorite && hasOnlyOneRecordSelected ? [ { label: 'Remove from favorites', @@ -170,7 +177,7 @@ export const useRecordActionBar = ({ }, ] : []), - ...(!isFavorite && hasOnlyOneRecordSelected + ...(!isRemoteObject && !isFavorite && hasOnlyOneRecordSelected ? [ { label: 'Add to favorites', @@ -182,9 +189,11 @@ export const useRecordActionBar = ({ ]); }, [ baseActions, + deletionActions, handleFavoriteButtonClick, hasOnlyOneRecordSelected, isFavorite, + isRemoteObject, setContextMenuEntries, ]), @@ -209,12 +218,15 @@ export const useRecordActionBar = ({ }, ] : []), + ...(isRemoteObject ? [] : deletionActions), ...baseActions, ]); }, [ baseActions, dataExecuteQuickActionOnmentEnabled, + deletionActions, handleExecuteQuickActionOnClick, + isRemoteObject, setActionBarEntriesState, ]), }; diff --git a/packages/twenty-front/src/modules/object-record/record-field/components/FieldInput.tsx b/packages/twenty-front/src/modules/object-record/record-field/components/FieldInput.tsx index 07f7cbe13..d2a28e6a7 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/components/FieldInput.tsx +++ b/packages/twenty-front/src/modules/object-record/record-field/components/FieldInput.tsx @@ -47,6 +47,7 @@ type FieldInputProps = { onEscape?: FieldInputEvent; onTab?: FieldInputEvent; onShiftTab?: FieldInputEvent; + isReadOnly?: boolean; }; export const FieldInput = ({ @@ -58,6 +59,7 @@ export const FieldInput = ({ onShiftTab, onTab, onClickOutside, + isReadOnly, }: FieldInputProps) => { const { fieldDefinition } = useContext(FieldContext); @@ -136,7 +138,7 @@ export const FieldInput = ({ onShiftTab={onShiftTab} /> ) : isFieldBoolean(fieldDefinition) ? ( - + ) : isFieldRating(fieldDefinition) ? ( ) : isFieldSelect(fieldDefinition) ? ( diff --git a/packages/twenty-front/src/modules/object-record/record-inline-cell/components/RecordInlineCell.tsx b/packages/twenty-front/src/modules/object-record/record-inline-cell/components/RecordInlineCell.tsx index bb2c8fc6b..cddd82ddb 100644 --- a/packages/twenty-front/src/modules/object-record/record-inline-cell/components/RecordInlineCell.tsx +++ b/packages/twenty-front/src/modules/object-record/record-inline-cell/components/RecordInlineCell.tsx @@ -92,6 +92,7 @@ export const RecordInlineCell = ({ readonly }: RecordInlineCellProps) => { onTab={handleTab} onShiftTab={handleShiftTab} onClickOutside={handleClickOutside} + isReadOnly={readonly} /> } displayModeContent={} diff --git a/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableRow.tsx b/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableRow.tsx index 1fa3794c1..7b9dfc25b 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableRow.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableRow.tsx @@ -47,6 +47,7 @@ export const RecordTableRow = ({ recordId, rowIndex }: RecordTableRowProps) => { objectNameSingular: objectMetadataItem.nameSingular, }) + recordId, isSelected: currentRowSelected, + isReadOnly: objectMetadataItem.isRemote ?? false, }} > ( diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCell.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCell.tsx index 7aee69ebc..945fd2e24 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCell.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCell.tsx @@ -4,6 +4,7 @@ import { FieldDisplay } from '@/object-record/record-field/components/FieldDispl import { FieldInput } from '@/object-record/record-field/components/FieldInput'; import { FieldContext } from '@/object-record/record-field/contexts/FieldContext'; import { FieldInputEvent } from '@/object-record/record-field/types/FieldInputEvent'; +import { RecordTableRowContext } from '@/object-record/record-table/contexts/RecordTableRowContext'; import { useRecordTableMoveFocus } from '@/object-record/record-table/hooks/useRecordTableMoveFocus'; import { RecordTableCellContainer } from '@/object-record/record-table/record-table-cell/components/RecordTableCellContainer'; import { useCloseRecordTableCell } from '@/object-record/record-table/record-table-cell/hooks/useCloseRecordTableCell'; @@ -21,6 +22,7 @@ export const RecordTableCell = ({ const { moveLeft, moveRight, moveDown } = useRecordTableMoveFocus(); const { entityId, fieldDefinition } = useContext(FieldContext); + const { isReadOnly } = useContext(RecordTableRowContext); const handleEnter: FieldInputEvent = (persistField) => { upsertRecord(persistField); @@ -78,6 +80,7 @@ export const RecordTableCell = ({ onShiftTab={handleShiftTab} onSubmit={handleSubmit} onTab={handleTab} + isReadOnly={isReadOnly} /> } nonEditModeContent={} diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellContainer.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellContainer.tsx index 65edb7d00..6b7f06bab 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellContainer.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellContainer.tsx @@ -90,7 +90,7 @@ export const RecordTableCellContainer = ({ openTableCell(); }; - const { isSelected } = useContext(RecordTableRowContext); + const { isSelected, isReadOnly } = useContext(RecordTableRowContext); const setContextMenuPosition = useSetRecoilState(contextMenuPositionState); const setContextMenuOpenState = useSetRecoilState(contextMenuIsOpenState); @@ -146,7 +146,8 @@ export const RecordTableCellContainer = ({ hasSoftFocus && !isCurrentTableCellInEditMode && !editModeContentOnly && - (!isFirstColumn || !isEmpty); + (!isFirstColumn || !isEmpty) && + !isReadOnly; return ( { - const { pathToShowPage } = useContext(RecordTableRowContext); + const { pathToShowPage, isReadOnly } = useContext(RecordTableRowContext); const { setCurrentTableCellInEditMode } = useCurrentTableCellEditMode(); const setHotkeyScope = useSetHotkeyScope(); @@ -46,6 +46,10 @@ export const useOpenRecordTableCell = () => { const openTableCell = useRecoilCallback( () => (options?: { initialValue?: string }) => { + if (isReadOnly) { + return; + } + if (isFirstColumnCell && !isEmpty) { leaveTableFocus(); navigate(pathToShowPage); @@ -70,15 +74,16 @@ export const useOpenRecordTableCell = () => { } }, [ + isReadOnly, isFirstColumnCell, isEmpty, - leaveTableFocus, - navigate, - pathToShowPage, setDragSelectionStartEnabled, setCurrentTableCellInEditMode, initFieldInputDraftValue, customCellHotkeyScope, + leaveTableFocus, + navigate, + pathToShowPage, setHotkeyScope, ], ); diff --git a/packages/twenty-front/src/modules/settings/data-model/object-details/components/SettingsObjectFieldItemTableRow.tsx b/packages/twenty-front/src/modules/settings/data-model/object-details/components/SettingsObjectFieldItemTableRow.tsx index e95d4eefd..49d5b9642 100644 --- a/packages/twenty-front/src/modules/settings/data-model/object-details/components/SettingsObjectFieldItemTableRow.tsx +++ b/packages/twenty-front/src/modules/settings/data-model/object-details/components/SettingsObjectFieldItemTableRow.tsx @@ -22,6 +22,7 @@ type SettingsObjectFieldItemTableRowProps = { fieldMetadataItem: FieldMetadataItem; identifierType?: Nullable; variant?: 'field-type' | 'identifier'; + isRemoteObjectField?: boolean; }; export const StyledObjectFieldTableRow = styled(TableRow)` @@ -43,6 +44,7 @@ export const SettingsObjectFieldItemTableRow = ({ fieldMetadataItem, identifierType, variant = 'field-type', + isRemoteObjectField, }: SettingsObjectFieldItemTableRowProps) => { const theme = useTheme(); const { getIcon } = useIcons(); @@ -76,7 +78,11 @@ export const SettingsObjectFieldItemTableRow = ({ {variant === 'field-type' && - (fieldMetadataItem.isCustom ? 'Custom' : 'Standard')} + (isRemoteObjectField + ? 'Remote' + : fieldMetadataItem.isCustom + ? 'Custom' + : 'Standard')} {variant === 'identifier' && !!identifierType && (identifierType === 'label' ? 'Record text' : 'Record image')} diff --git a/packages/twenty-front/src/modules/settings/data-model/object-details/components/SettingsObjectItemTableRow.tsx b/packages/twenty-front/src/modules/settings/data-model/object-details/components/SettingsObjectItemTableRow.tsx index 106f41abd..7a4ac6ab7 100644 --- a/packages/twenty-front/src/modules/settings/data-model/object-details/components/SettingsObjectItemTableRow.tsx +++ b/packages/twenty-front/src/modules/settings/data-model/object-details/components/SettingsObjectItemTableRow.tsx @@ -4,7 +4,8 @@ import styled from '@emotion/styled'; import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; import { useFindManyRecords } from '@/object-record/hooks/useFindManyRecords'; -import { SettingsDataModelIsCustomTag } from '@/settings/data-model/objects/SettingsDataModelIsCustomTag'; +import { SettingsDataModelObjectTypeTag } from '@/settings/data-model/objects/SettingsDataModelObjectTypeTag'; +import { getObjectTypeLabel } from '@/settings/data-model/utils/getObjectTypeLabel'; import { useIcons } from '@/ui/display/icon/hooks/useIcons'; import { TableCell } from '@/ui/layout/table/components/TableCell'; import { TableRow } from '@/ui/layout/table/components/TableRow'; @@ -42,6 +43,7 @@ export const SettingsObjectItemTableRow = ({ }); const { getIcon } = useIcons(); const Icon = getIcon(objectItem.icon); + const objectTypeLabel = getObjectTypeLabel(objectItem); return ( @@ -52,7 +54,7 @@ export const SettingsObjectItemTableRow = ({ {objectItem.labelPlural} - + {objectItem.fields.filter((field) => !field.isSystem).length} diff --git a/packages/twenty-front/src/modules/settings/data-model/object-details/components/SettingsObjectSummaryCard.tsx b/packages/twenty-front/src/modules/settings/data-model/object-details/components/SettingsObjectSummaryCard.tsx index 84a4e87dc..4b3627f54 100644 --- a/packages/twenty-front/src/modules/settings/data-model/object-details/components/SettingsObjectSummaryCard.tsx +++ b/packages/twenty-front/src/modules/settings/data-model/object-details/components/SettingsObjectSummaryCard.tsx @@ -2,8 +2,10 @@ import { useTheme } from '@emotion/react'; import styled from '@emotion/styled'; import { IconArchive, IconDotsVertical, IconPencil } from 'twenty-ui'; +import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; import { SettingsSummaryCard } from '@/settings/components/SettingsSummaryCard'; -import { SettingsDataModelIsCustomTag } from '@/settings/data-model/objects/SettingsDataModelIsCustomTag'; +import { SettingsDataModelObjectTypeTag } from '@/settings/data-model/objects/SettingsDataModelObjectTypeTag'; +import { getObjectTypeLabel } from '@/settings/data-model/utils/getObjectTypeLabel'; import { useIcons } from '@/ui/display/icon/hooks/useIcons'; import { LightIconButton } from '@/ui/input/button/components/LightIconButton'; import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown'; @@ -13,14 +15,14 @@ import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown'; import { MenuItem } from '@/ui/navigation/menu-item/components/MenuItem'; type SettingsObjectSummaryCardProps = { + objectMetadataItem: ObjectMetadataItem; iconKey?: string; - isCustom: boolean; name: string; onDeactivate: () => void; onEdit: () => void; }; -const StyledIsCustomTag = styled(SettingsDataModelIsCustomTag)` +const StyledObjectTypeTag = styled(SettingsDataModelObjectTypeTag)` box-sizing: border-box; height: ${({ theme }) => theme.spacing(6)}; `; @@ -28,8 +30,8 @@ const StyledIsCustomTag = styled(SettingsDataModelIsCustomTag)` const dropdownId = 'settings-object-edit-about-menu-dropdown'; export const SettingsObjectSummaryCard = ({ + objectMetadataItem, iconKey = '', - isCustom, name, onDeactivate, onEdit, @@ -50,6 +52,8 @@ export const SettingsObjectSummaryCard = ({ closeDropdown(); }; + const objectTypeLabel = getObjectTypeLabel(objectMetadataItem); + return ( - + ( - -); diff --git a/packages/twenty-front/src/modules/settings/data-model/objects/SettingsDataModelObjectSummary.tsx b/packages/twenty-front/src/modules/settings/data-model/objects/SettingsDataModelObjectSummary.tsx index 5b7b44740..0e7336384 100644 --- a/packages/twenty-front/src/modules/settings/data-model/objects/SettingsDataModelObjectSummary.tsx +++ b/packages/twenty-front/src/modules/settings/data-model/objects/SettingsDataModelObjectSummary.tsx @@ -2,15 +2,13 @@ import { useTheme } from '@emotion/react'; import styled from '@emotion/styled'; import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; -import { SettingsDataModelIsCustomTag } from '@/settings/data-model/objects/SettingsDataModelIsCustomTag'; +import { SettingsDataModelObjectTypeTag } from '@/settings/data-model/objects/SettingsDataModelObjectTypeTag'; +import { getObjectTypeLabel } from '@/settings/data-model/utils/getObjectTypeLabel'; import { useIcons } from '@/ui/display/icon/hooks/useIcons'; export type SettingsDataModelObjectSummaryProps = { className?: string; - objectMetadataItem: Pick< - ObjectMetadataItem, - 'icon' | 'isCustom' | 'labelPlural' - >; + objectMetadataItem: ObjectMetadataItem; }; const StyledObjectSummary = styled.div` @@ -35,6 +33,7 @@ export const SettingsDataModelObjectSummary = ({ const { getIcon } = useIcons(); const ObjectIcon = getIcon(objectMetadataItem.icon); + const objectTypeLabel = getObjectTypeLabel(objectMetadataItem); return ( @@ -42,7 +41,7 @@ export const SettingsDataModelObjectSummary = ({ {objectMetadataItem.labelPlural} - + ); }; diff --git a/packages/twenty-front/src/modules/settings/data-model/objects/SettingsDataModelObjectTypeTag.tsx b/packages/twenty-front/src/modules/settings/data-model/objects/SettingsDataModelObjectTypeTag.tsx new file mode 100644 index 000000000..e077383c4 --- /dev/null +++ b/packages/twenty-front/src/modules/settings/data-model/objects/SettingsDataModelObjectTypeTag.tsx @@ -0,0 +1,21 @@ +import { ObjectTypeLabel } from '@/settings/data-model/utils/getObjectTypeLabel'; +import { Tag } from '@/ui/display/tag/components/Tag'; + +type SettingsDataModelObjectTypeTagProps = { + objectTypeLabel: ObjectTypeLabel; + className?: string; +}; + +export const SettingsDataModelObjectTypeTag = ({ + className, + objectTypeLabel, +}: SettingsDataModelObjectTypeTagProps) => { + return ( + + ); +}; diff --git a/packages/twenty-front/src/modules/settings/data-model/utils/getObjectTypeLabel.ts b/packages/twenty-front/src/modules/settings/data-model/utils/getObjectTypeLabel.ts new file mode 100644 index 000000000..9f34d717f --- /dev/null +++ b/packages/twenty-front/src/modules/settings/data-model/utils/getObjectTypeLabel.ts @@ -0,0 +1,39 @@ +import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; + +export type ObjectTypeLabel = + | StandardObjectTypeLabel + | CustomObjectTypeLabel + | RemoteObjectTypeLabel; + +type StandardObjectTypeLabel = { + labelText: 'Standard'; + labelColor: 'blue'; +}; + +type CustomObjectTypeLabel = { + labelText: 'Custom'; + labelColor: 'orange'; +}; + +type RemoteObjectTypeLabel = { + labelText: 'Remote'; + labelColor: 'green'; +}; + +export const getObjectTypeLabel = ( + objectMetadataItem: ObjectMetadataItem, +): ObjectTypeLabel => + objectMetadataItem.isCustom + ? { + labelText: 'Custom', + labelColor: 'orange', + } + : objectMetadataItem.isRemote + ? { + labelText: 'Remote', + labelColor: 'green', + } + : { + labelText: 'Standard', + labelColor: 'blue', + }; diff --git a/packages/twenty-front/src/modules/settings/integrations/components/SettingsIntegrationDatabaseTablesListCard.tsx b/packages/twenty-front/src/modules/settings/integrations/components/SettingsIntegrationDatabaseTablesListCard.tsx index a35427d88..f6e5cefe6 100644 --- a/packages/twenty-front/src/modules/settings/integrations/components/SettingsIntegrationDatabaseTablesListCard.tsx +++ b/packages/twenty-front/src/modules/settings/integrations/components/SettingsIntegrationDatabaseTablesListCard.tsx @@ -63,7 +63,7 @@ export const SettingsIntegrationDatabaseTablesListCard = ({ }); } }, - [connectionId, syncRemoteTable, items, unsyncRemoteTable], + [items, syncRemoteTable, connectionId, unsyncRemoteTable], ); const rowRightComponent = useCallback( diff --git a/packages/twenty-front/src/pages/object-record/RecordShowPage.tsx b/packages/twenty-front/src/pages/object-record/RecordShowPage.tsx index 20b63e0c5..f75b0b0aa 100644 --- a/packages/twenty-front/src/pages/object-record/RecordShowPage.tsx +++ b/packages/twenty-front/src/pages/object-record/RecordShowPage.tsx @@ -88,6 +88,11 @@ export const RecordShowPage = () => { ].join(' ') : `${labelIdentifierFieldValue}`; + // Temporarily since we don't have relations for remote objects yet + if (objectMetadataItem.isRemote) { + return null; + } + return ( diff --git a/packages/twenty-front/src/pages/settings/data-model/SettingsObjectDetail.tsx b/packages/twenty-front/src/pages/settings/data-model/SettingsObjectDetail.tsx index e371a133f..668007c1b 100644 --- a/packages/twenty-front/src/pages/settings/data-model/SettingsObjectDetail.tsx +++ b/packages/twenty-front/src/pages/settings/data-model/SettingsObjectDetail.tsx @@ -102,7 +102,7 @@ export const SettingsObjectDetail = () => { navigate('./edit')} /> @@ -150,6 +150,7 @@ export const SettingsObjectDetail = () => { : 'field-type' } fieldMetadataItem={activeMetadataField} + isRemoteObjectField={activeObjectMetadataItem.isRemote} ActionIcon={ { , ) { super(objectMetadataRepository); } @@ -322,27 +334,6 @@ export class ObjectMetadataService extends TypeOrmQueryService