toggle Field on label between singular and plural based on relation type (#8817)

#7683 

![labelPlural](https://github.com/user-attachments/assets/3e620d7e-dd51-4e4e-a9ba-289f2685ddf3)

![labelSingular](https://github.com/user-attachments/assets/84739ac5-29b4-48c8-8a71-3f8f2816641b)
Hello,
I’ve implemented the logic for dynamically toggling the Field on label
between singular and plural based on the relation type selected by the
user. Here's an overview of the changes:

Added a variable selectedRelationType to store the user’s selected
relation type.
Based on this variable, I determine whether to use labelPlural or
labelSingular from the selectedObjectMetadataItem.
Please review my changes and let me know if there's anything that needs
improvement .

---------

Co-authored-by: Félix Malfait <felix@twenty.com>
This commit is contained in:
Naifer 2024-12-02 14:14:21 +01:00 committed by GitHub
parent 0527bc296e
commit 2b0f67191a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 56 additions and 22 deletions

View File

@ -1,5 +1,5 @@
import { gql } from '@apollo/client';
import * as Apollo from '@apollo/client'; import * as Apollo from '@apollo/client';
import { gql } from '@apollo/client';
export type Maybe<T> = T | null; export type Maybe<T> = T | null;
export type InputMaybe<T> = Maybe<T>; export type InputMaybe<T> = Maybe<T>;
export type Exact<T extends { [key: string]: unknown }> = { [K in keyof T]: T[K] }; export type Exact<T extends { [key: string]: unknown }> = { [K in keyof T]: T[K] };

View File

@ -110,7 +110,7 @@ export const SETTINGS_COMPOSITE_FIELD_TYPE_CONFIGS = {
label: 'Full Name', label: 'Full Name',
Icon: IllustrationIconUser, Icon: IllustrationIconUser,
exampleValue: { firstName: 'John', lastName: 'Doe' }, exampleValue: { firstName: 'John', lastName: 'Doe' },
category: 'Advanced', category: 'Basic',
subFields: ['firstName', 'lastName'], subFields: ['firstName', 'lastName'],
filterableSubFields: ['firstName', 'lastName'], filterableSubFields: ['firstName', 'lastName'],
labelBySubField: { labelBySubField: {

View File

@ -2,6 +2,6 @@ import { SETTINGS_COMPOSITE_FIELD_TYPE_CONFIGS } from '@/settings/data-model/con
import { SETTINGS_NON_COMPOSITE_FIELD_TYPE_CONFIGS } from '@/settings/data-model/constants/SettingsNonCompositeFieldTypeConfigs'; import { SETTINGS_NON_COMPOSITE_FIELD_TYPE_CONFIGS } from '@/settings/data-model/constants/SettingsNonCompositeFieldTypeConfigs';
export const SETTINGS_FIELD_TYPE_CONFIGS = { export const SETTINGS_FIELD_TYPE_CONFIGS = {
...SETTINGS_COMPOSITE_FIELD_TYPE_CONFIGS,
...SETTINGS_NON_COMPOSITE_FIELD_TYPE_CONFIGS, ...SETTINGS_NON_COMPOSITE_FIELD_TYPE_CONFIGS,
...SETTINGS_COMPOSITE_FIELD_TYPE_CONFIGS,
}; };

View File

@ -120,7 +120,7 @@ export const SETTINGS_NON_COMPOSITE_FIELD_TYPE_CONFIGS: SettingsNonCompositeFiel
label: 'JSON', label: 'JSON',
Icon: IllustrationIconJson, Icon: IllustrationIconJson,
exampleValue: { key: 'value' }, exampleValue: { key: 'value' },
category: 'Basic', category: 'Advanced',
} as const satisfies SettingsFieldTypeConfig<FieldJsonValue>, } as const satisfies SettingsFieldTypeConfig<FieldJsonValue>,
[FieldMetadataType.RichText]: { [FieldMetadataType.RichText]: {
label: 'Rich Text', label: 'Rich Text',
@ -131,7 +131,7 @@ export const SETTINGS_NON_COMPOSITE_FIELD_TYPE_CONFIGS: SettingsNonCompositeFiel
[FieldMetadataType.Array]: { [FieldMetadataType.Array]: {
label: 'Array', label: 'Array',
Icon: IllustrationIconArray, Icon: IllustrationIconArray,
category: 'Basic', category: 'Advanced',
exampleValue: ['value1', 'value2'], exampleValue: ['value1', 'value2'],
} as const satisfies SettingsFieldTypeConfig<FieldArrayValue>, } as const satisfies SettingsFieldTypeConfig<FieldArrayValue>,
}; };

View File

@ -107,6 +107,11 @@ export const SettingsDataModelFieldRelationForm = ({
), ),
); );
const selectedRelationType = watchFormValue(
'relation.type',
initialRelationType,
);
const isMobile = useIsMobile(); const isMobile = useIsMobile();
return ( return (
@ -152,7 +157,10 @@ export const SettingsDataModelFieldRelationForm = ({
/> />
</StyledSelectsContainer> </StyledSelectsContainer>
<StyledInputsLabel> <StyledInputsLabel>
Field on {selectedObjectMetadataItem?.labelPlural} Field on{' '}
{selectedRelationType === RelationDefinitionType.ManyToOne
? selectedObjectMetadataItem?.labelSingular
: selectedObjectMetadataItem?.labelPlural}
</StyledInputsLabel> </StyledInputsLabel>
<StyledInputsContainer> <StyledInputsContainer>
<Controller <Controller

View File

@ -15,7 +15,10 @@ import {
SettingsDataModelFieldPreviewCardProps, SettingsDataModelFieldPreviewCardProps,
} from '@/settings/data-model/fields/preview/components/SettingsDataModelFieldPreviewCard'; } from '@/settings/data-model/fields/preview/components/SettingsDataModelFieldPreviewCard';
import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile'; import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile';
import { FieldMetadataType } from '~/generated-metadata/graphql'; import {
FieldMetadataType,
RelationDefinitionType,
} from '~/generated-metadata/graphql';
type SettingsDataModelFieldRelationSettingsFormCardProps = { type SettingsDataModelFieldRelationSettingsFormCardProps = {
fieldMetadataItem: Pick<FieldMetadataItem, 'icon' | 'label' | 'type'> & fieldMetadataItem: Pick<FieldMetadataItem, 'icon' | 'label' | 'type'> &
Partial<Omit<FieldMetadataItem, 'icon' | 'label' | 'type'>>; Partial<Omit<FieldMetadataItem, 'icon' | 'label' | 'type'>>;
@ -86,6 +89,10 @@ export const SettingsDataModelFieldRelationSettingsFormCard = ({
shrink shrink
objectMetadataItem={objectMetadataItem} objectMetadataItem={objectMetadataItem}
relationObjectMetadataItem={relationObjectMetadataItem} relationObjectMetadataItem={relationObjectMetadataItem}
pluralizeLabel={
watchFormValue('relation.type') ===
RelationDefinitionType.ManyToOne
}
/> />
<StyledRelationImage <StyledRelationImage
src={relationTypeConfig.imageSrc} src={relationTypeConfig.imageSrc}
@ -110,6 +117,10 @@ export const SettingsDataModelFieldRelationSettingsFormCard = ({
shrink shrink
objectMetadataItem={relationObjectMetadataItem} objectMetadataItem={relationObjectMetadataItem}
relationObjectMetadataItem={objectMetadataItem} relationObjectMetadataItem={objectMetadataItem}
pluralizeLabel={
watchFormValue('relation.type') !==
RelationDefinitionType.ManyToOne
}
/> />
</StyledPreviewContent> </StyledPreviewContent>
} }

View File

@ -10,6 +10,7 @@ import { Card, CardContent } from 'twenty-ui';
export type SettingsDataModelFieldPreviewCardProps = export type SettingsDataModelFieldPreviewCardProps =
SettingsDataModelFieldPreviewProps & { SettingsDataModelFieldPreviewProps & {
className?: string; className?: string;
pluralizeLabel?: boolean;
}; };
const StyledCard = styled(Card)` const StyledCard = styled(Card)`
@ -28,17 +29,23 @@ export const SettingsDataModelFieldPreviewCard = ({
relationObjectMetadataItem, relationObjectMetadataItem,
shrink, shrink,
withFieldLabel = true, withFieldLabel = true,
}: SettingsDataModelFieldPreviewCardProps) => ( pluralizeLabel = false,
<StyledCard className={className} fullWidth> }: SettingsDataModelFieldPreviewCardProps) => {
<StyledCardContent> return (
<SettingsDataModelObjectSummary objectMetadataItem={objectMetadataItem} /> <StyledCard className={className} fullWidth>
<SettingsDataModelFieldPreview <StyledCardContent>
objectMetadataItem={objectMetadataItem} <SettingsDataModelObjectSummary
fieldMetadataItem={fieldMetadataItem} objectMetadataItem={objectMetadataItem}
relationObjectMetadataItem={relationObjectMetadataItem} pluralizeLabel={pluralizeLabel}
shrink={shrink} />
withFieldLabel={withFieldLabel} <SettingsDataModelFieldPreview
/> objectMetadataItem={objectMetadataItem}
</StyledCardContent> fieldMetadataItem={fieldMetadataItem}
</StyledCard> relationObjectMetadataItem={relationObjectMetadataItem}
); shrink={shrink}
withFieldLabel={withFieldLabel}
/>
</StyledCardContent>
</StyledCard>
);
};

View File

@ -9,6 +9,7 @@ import { getObjectTypeLabel } from '@/settings/data-model/utils/getObjectTypeLab
export type SettingsDataModelObjectSummaryProps = { export type SettingsDataModelObjectSummaryProps = {
className?: string; className?: string;
objectMetadataItem: ObjectMetadataItem; objectMetadataItem: ObjectMetadataItem;
pluralizeLabel?: boolean;
}; };
const StyledObjectSummary = styled.div` const StyledObjectSummary = styled.div`
@ -30,6 +31,7 @@ const StyledIconContainer = styled.div`
export const SettingsDataModelObjectSummary = ({ export const SettingsDataModelObjectSummary = ({
className, className,
objectMetadataItem, objectMetadataItem,
pluralizeLabel = true,
}: SettingsDataModelObjectSummaryProps) => { }: SettingsDataModelObjectSummaryProps) => {
const theme = useTheme(); const theme = useTheme();
@ -43,7 +45,13 @@ export const SettingsDataModelObjectSummary = ({
<StyledIconContainer> <StyledIconContainer>
<ObjectIcon size={theme.icon.size.sm} stroke={theme.icon.stroke.md} /> <ObjectIcon size={theme.icon.size.sm} stroke={theme.icon.stroke.md} />
</StyledIconContainer> </StyledIconContainer>
<OverflowingTextWithTooltip text={objectMetadataItem.labelPlural} /> <OverflowingTextWithTooltip
text={
pluralizeLabel
? objectMetadataItem.labelPlural
: objectMetadataItem.labelSingular
}
/>
</StyledObjectName> </StyledObjectName>
<SettingsDataModelObjectTypeTag objectTypeLabel={objectTypeLabel} /> <SettingsDataModelObjectTypeTag objectTypeLabel={objectTypeLabel} />
</StyledObjectSummary> </StyledObjectSummary>