From a5f28b4395eead383bd6e168f49d95ca68b51655 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tha=C3=AFs?= Date: Wed, 20 Dec 2023 18:52:02 +0100 Subject: [PATCH] fix: display label identifier field input in Show Page (#3063) * fix: display label identifier field input in Show Page Fixes #3003 * Cleaned a bit after comments --------- Co-authored-by: Lucas Bordeau --- .../hooks/useObjectMetadataItem.ts | 6 +- .../utils/isLabelIdentifierField.ts | 18 +++ .../components/RecordShowPage.tsx | 108 ++++++++++++------ .../components/RecordTableEffect.tsx | 8 +- .../input/components/FullNameFieldInput.tsx | 2 +- .../components/RecordInlineCell.tsx | 4 +- .../components/RecordInlineCellContainer.tsx | 25 ++-- ...ettingsObjectFieldActiveActionDropdown.tsx | 16 +-- .../components/ShowPageSummaryCard.tsx | 32 ++---- .../data-model/SettingsObjectDetail.tsx | 21 +++- 10 files changed, 151 insertions(+), 89 deletions(-) create mode 100644 packages/twenty-front/src/modules/object-metadata/utils/isLabelIdentifierField.ts diff --git a/packages/twenty-front/src/modules/object-metadata/hooks/useObjectMetadataItem.ts b/packages/twenty-front/src/modules/object-metadata/hooks/useObjectMetadataItem.ts index 33bea209e..7c89d820a 100644 --- a/packages/twenty-front/src/modules/object-metadata/hooks/useObjectMetadataItem.ts +++ b/packages/twenty-front/src/modules/object-metadata/hooks/useObjectMetadataItem.ts @@ -112,14 +112,14 @@ export const useObjectMetadataItem = ( objectMetadataItem, }); - const labelIdentifierFieldMetadataId = objectMetadataItem.fields.find( + const labelIdentifierFieldMetadata = objectMetadataItem.fields.find( ({ name }) => name === 'name', - )?.id; + ); const basePathToShowPage = `/object/${objectMetadataItem.nameSingular}/`; return { - labelIdentifierFieldMetadataId, + labelIdentifierFieldMetadata, basePathToShowPage, objectMetadataItem, getRecordFromCache, diff --git a/packages/twenty-front/src/modules/object-metadata/utils/isLabelIdentifierField.ts b/packages/twenty-front/src/modules/object-metadata/utils/isLabelIdentifierField.ts new file mode 100644 index 000000000..be412fd5d --- /dev/null +++ b/packages/twenty-front/src/modules/object-metadata/utils/isLabelIdentifierField.ts @@ -0,0 +1,18 @@ +import { FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem'; +import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; + +export const DEFAULT_LABEL_IDENTIFIER_FIELD_NAME = 'name'; + +export const isLabelIdentifierField = ({ + fieldMetadataItem, + objectMetadataItem, +}: { + fieldMetadataItem: FieldMetadataItem; + objectMetadataItem: ObjectMetadataItem; +}) => { + return ( + fieldMetadataItem.id === + objectMetadataItem.labelIdentifierFieldMetadataId || + fieldMetadataItem.name === DEFAULT_LABEL_IDENTIFIER_FIELD_NAME + ); +}; diff --git a/packages/twenty-front/src/modules/object-record/components/RecordShowPage.tsx b/packages/twenty-front/src/modules/object-record/components/RecordShowPage.tsx index 95765cf59..b3de9f479 100644 --- a/packages/twenty-front/src/modules/object-record/components/RecordShowPage.tsx +++ b/packages/twenty-front/src/modules/object-record/components/RecordShowPage.tsx @@ -5,6 +5,7 @@ import { CompanyTeam } from '@/companies/components/CompanyTeam'; import { useFavorites } from '@/favorites/hooks/useFavorites'; import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem'; import { formatFieldMetadataItemAsColumnDefinition } from '@/object-metadata/utils/formatFieldMetadataItemAsColumnDefinition'; +import { parseFieldType } from '@/object-metadata/utils/parseFieldType'; import { FieldContext } from '@/object-record/field/contexts/FieldContext'; import { entityFieldsFamilyState } from '@/object-record/field/states/entityFieldsFamilyState'; import { RecordInlineCell } from '@/object-record/record-inline-cell/components/RecordInlineCell'; @@ -25,7 +26,11 @@ import { ShowPageSummaryCard } from '@/ui/layout/show-page/components/ShowPageSu import { ShowPageRecoilScopeContext } from '@/ui/layout/states/ShowPageRecoilScopeContext'; import { PageTitle } from '@/ui/utilities/page-title/PageTitle'; import { RecoilScope } from '@/ui/utilities/recoil-scope/components/RecoilScope'; -import { FileFolder, useUploadImageMutation } from '~/generated/graphql'; +import { + FieldMetadataType, + FileFolder, + useUploadImageMutation, +} from '~/generated/graphql'; import { getLogoUrlFromDomainName } from '~/utils'; import { useFindOneRecord } from '../hooks/useFindOneRecord'; @@ -41,9 +46,10 @@ export const RecordShowPage = () => { throw new Error(`Object name is not defined`); } - const { objectMetadataItem } = useObjectMetadataItem({ - objectNameSingular, - }); + const { objectMetadataItem, labelIdentifierFieldMetadata } = + useObjectMetadataItem({ + objectNameSingular, + }); const { identifiersMapper } = useRelationPicker(); @@ -171,6 +177,16 @@ export const RecordShowPage = () => { }); }; + const fieldMetadataItemsToShow = [...objectMetadataItem.fields] + .sort((fieldMetadataItemA, fieldMetadataItemB) => + fieldMetadataItemA.name.localeCompare(fieldMetadataItemB.name), + ) + .filter(isFieldMetadataItemAvailable) + .filter( + (fieldMetadataItem) => + fieldMetadataItem.id !== labelIdentifierFieldMetadata?.id, + ); + return ( @@ -204,9 +220,37 @@ export const RecordShowPage = () => { <>} + title={ + + + + } avatarType={recordIdentifiers?.avatarType ?? 'rounded'} onUploadPicture={ objectNameSingular === 'person' @@ -215,35 +259,29 @@ export const RecordShowPage = () => { } /> - {objectMetadataItem && - [...objectMetadataItem.fields] - .sort((a, b) => - a.name === 'name' ? -1 : a.name.localeCompare(b.name), - ) - .filter(isFieldMetadataItemAvailable) - .map((metadataField, index) => { - return ( - - - - ); - })} + {fieldMetadataItemsToShow.map( + (fieldMetadataItem, index) => ( + + + + ), + )} {objectNameSingular === 'company' ? ( <> diff --git a/packages/twenty-front/src/modules/object-record/components/RecordTableEffect.tsx b/packages/twenty-front/src/modules/object-record/components/RecordTableEffect.tsx index 235f8b94a..1e51c3bc9 100644 --- a/packages/twenty-front/src/modules/object-record/components/RecordTableEffect.tsx +++ b/packages/twenty-front/src/modules/object-record/components/RecordTableEffect.tsx @@ -31,7 +31,7 @@ export const RecordTableEffect = ({ const { objectMetadataItem, basePathToShowPage, - labelIdentifierFieldMetadataId, + labelIdentifierFieldMetadata, } = useObjectMetadataItem({ objectNameSingular, }); @@ -49,16 +49,16 @@ export const RecordTableEffect = ({ } = useViewBar({ viewBarId }); useEffect(() => { - if (basePathToShowPage && labelIdentifierFieldMetadataId) { + if (basePathToShowPage && labelIdentifierFieldMetadata) { setObjectMetadataConfig?.({ basePathToShowPage, - labelIdentifierFieldMetadataId, + labelIdentifierFieldMetadataId: labelIdentifierFieldMetadata.id, }); } }, [ basePathToShowPage, objectMetadataItem, - labelIdentifierFieldMetadataId, + labelIdentifierFieldMetadata, setObjectMetadataConfig, ]); diff --git a/packages/twenty-front/src/modules/object-record/field/meta-types/input/components/FullNameFieldInput.tsx b/packages/twenty-front/src/modules/object-record/field/meta-types/input/components/FullNameFieldInput.tsx index 9855bc9f3..09b482e51 100644 --- a/packages/twenty-front/src/modules/object-record/field/meta-types/input/components/FullNameFieldInput.tsx +++ b/packages/twenty-front/src/modules/object-record/field/meta-types/input/components/FullNameFieldInput.tsx @@ -1,8 +1,8 @@ import { useFullNameField } from '@/object-record/field/meta-types/hooks/useFullNameField'; import { FieldDoubleText } from '@/object-record/field/types/FieldDoubleText'; import { DoubleTextInput } from '@/ui/field/input/components/DoubleTextInput'; +import { FieldInputOverlay } from '@/ui/field/input/components/FieldInputOverlay'; -import { FieldInputOverlay } from '../../../../../ui/field/input/components/FieldInputOverlay'; import { usePersistField } from '../../../hooks/usePersistField'; import { FieldInputEvent } from './DateFieldInput'; 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 e84c30178..0b9b04a04 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 @@ -71,7 +71,9 @@ export const RecordInlineCell = () => { } : undefined } - IconLabel={getIcon(fieldDefinition.iconName)} + IconLabel={ + fieldDefinition.iconName ? getIcon(fieldDefinition.iconName) : undefined + } editModeContent={ theme.spacing(4)}); `; const StyledLabel = styled.div< @@ -70,8 +69,6 @@ const StyledInlineCellBaseContainer = styled.div` position: relative; user-select: none; - - width: 100%; `; type RecordInlineCellContainerProps = { @@ -129,16 +126,18 @@ export const RecordInlineCellContainer = ({ onMouseEnter={handleContainerMouseEnter} onMouseLeave={handleContainerMouseLeave} > - - {IconLabel && ( - - - - )} - {label && ( - {label} - )} - + {(!!IconLabel || !!label) && ( + + {IconLabel && ( + + + + )} + {label && ( + {label} + )} + + )} {isInlineCellInEditMode ? ( {editModeContent} diff --git a/packages/twenty-front/src/modules/settings/data-model/object-details/components/SettingsObjectFieldActiveActionDropdown.tsx b/packages/twenty-front/src/modules/settings/data-model/object-details/components/SettingsObjectFieldActiveActionDropdown.tsx index e927309e4..f57360745 100644 --- a/packages/twenty-front/src/modules/settings/data-model/object-details/components/SettingsObjectFieldActiveActionDropdown.tsx +++ b/packages/twenty-front/src/modules/settings/data-model/object-details/components/SettingsObjectFieldActiveActionDropdown.tsx @@ -14,7 +14,7 @@ import { MenuItem } from '@/ui/navigation/menu-item/components/MenuItem'; type SettingsObjectFieldActiveActionDropdownProps = { isCustomField?: boolean; - onDisable: () => void; + onDisable?: () => void; onEdit: () => void; scopeKey: string; }; @@ -35,7 +35,7 @@ export const SettingsObjectFieldActiveActionDropdown = ({ }; const handleDisable = () => { - onDisable(); + onDisable?.(); closeDropdown(); }; @@ -53,11 +53,13 @@ export const SettingsObjectFieldActiveActionDropdown = ({ LeftIcon={isCustomField ? IconPencil : IconEye} onClick={handleEdit} /> - + {!!onDisable && ( + + )} } diff --git a/packages/twenty-front/src/modules/ui/layout/show-page/components/ShowPageSummaryCard.tsx b/packages/twenty-front/src/modules/ui/layout/show-page/components/ShowPageSummaryCard.tsx index 0ee926246..1d7231c35 100644 --- a/packages/twenty-front/src/modules/ui/layout/show-page/components/ShowPageSummaryCard.tsx +++ b/packages/twenty-front/src/modules/ui/layout/show-page/components/ShowPageSummaryCard.tsx @@ -1,4 +1,4 @@ -import { ChangeEvent, useRef } from 'react'; +import { ChangeEvent, ReactNode, useRef } from 'react'; import { Tooltip } from 'react-tooltip'; import styled from '@emotion/styled'; import { v4 as uuidV4 } from 'uuid'; @@ -9,16 +9,14 @@ import { beautifyPastDateRelativeToNow, } from '~/utils/date-utils'; -import { OverflowingTextWithTooltip } from '../../../display/tooltip/OverflowingTextWithTooltip'; - type ShowPageSummaryCardProps = { + avatarPlaceholder: string; + avatarType: AvatarType; + date: string; id?: string; logoOrAvatar?: string; - title: string; - date: string; - renderTitleEditComponent?: () => JSX.Element; onUploadPicture?: (file: File) => void; - avatarType: AvatarType; + title: ReactNode; }; const StyledShowPageSummaryCard = styled.div` @@ -47,7 +45,6 @@ const StyledDate = styled.div` const StyledTitle = styled.div` color: ${({ theme }) => theme.font.color.primary}; display: flex; - flex-direction: row; font-size: ${({ theme }) => theme.font.size.xl}; font-weight: ${({ theme }) => theme.font.weight.semiBold}; justify-content: center; @@ -74,13 +71,13 @@ const StyledFileInput = styled.input` `; export const ShowPageSummaryCard = ({ + avatarPlaceholder, + avatarType, + date, id, logoOrAvatar, - title, - date, - avatarType, - renderTitleEditComponent, onUploadPicture, + title, }: ShowPageSummaryCardProps) => { const beautifiedCreatedAt = date !== '' ? beautifyPastDateRelativeToNow(date) : ''; @@ -104,7 +101,7 @@ export const ShowPageSummaryCard = ({ onClick={onUploadPicture ? handleAvatarClick : undefined} size="xl" colorId={id} - placeholder={title} + placeholder={avatarPlaceholder} type={avatarType} /> - - - {renderTitleEditComponent ? ( - renderTitleEditComponent() - ) : ( - - )} - + {title} Added {beautifiedCreatedAt} { (metadataField) => !metadataField.isActive && !metadataField.isSystem, ); - const handleDisable = async () => { + const handleDisableObject = async () => { await disableObjectMetadataItem(activeObjectMetadataItem); navigate('/settings/objects'); }; + const handleDisableField = async ( + activeFieldMetadatItem: FieldMetadataItem, + ) => { + disableMetadataField(activeFieldMetadatItem); + }; + return ( @@ -74,7 +82,7 @@ export const SettingsObjectDetail = () => { iconKey={activeObjectMetadataItem.icon ?? undefined} name={activeObjectMetadataItem.labelPlural || ''} isCustom={activeObjectMetadataItem.isCustom} - onDisable={handleDisable} + onDisable={handleDisableObject} onEdit={() => navigate('./edit')} />
@@ -102,8 +110,13 @@ export const SettingsObjectDetail = () => { onEdit={() => navigate(`./${getFieldSlug(activeMetadataField)}`) } - onDisable={() => - disableMetadataField(activeMetadataField) + onDisable={ + isLabelIdentifierField({ + fieldMetadataItem: activeMetadataField, + objectMetadataItem: activeObjectMetadataItem, + }) + ? undefined + : () => handleDisableField(activeMetadataField) } /> }