feat: display identifier field in Object Detail page for custom objects (#3329)

* feat: display identifier field in Object Detail page for custom objects

Closes #3301

* fix: show Name as object label identifier by default

* Minor improvements

---------

Co-authored-by: Lucas Bordeau <bordeau.lucas@gmail.com>
This commit is contained in:
Thaïs 2024-01-12 08:11:09 -03:00 committed by GitHub
parent 0dc39db314
commit 09a2a656e2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 75 additions and 20 deletions

View File

@ -1,5 +1,6 @@
import { FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem'; import { FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem';
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
import { isDefined } from '~/utils/isDefined';
export const DEFAULT_LABEL_IDENTIFIER_FIELD_NAME = 'name'; export const DEFAULT_LABEL_IDENTIFIER_FIELD_NAME = 'name';
@ -7,12 +8,13 @@ export const isLabelIdentifierField = ({
fieldMetadataItem, fieldMetadataItem,
objectMetadataItem, objectMetadataItem,
}: { }: {
fieldMetadataItem: FieldMetadataItem; fieldMetadataItem: Pick<FieldMetadataItem, 'id' | 'name'>;
objectMetadataItem: ObjectMetadataItem; objectMetadataItem: Pick<
ObjectMetadataItem,
'labelIdentifierFieldMetadataId'
>;
}) => { }) => {
return ( return isDefined(objectMetadataItem.labelIdentifierFieldMetadataId)
fieldMetadataItem.id === ? fieldMetadataItem.id === objectMetadataItem.labelIdentifierFieldMetadataId
objectMetadataItem.labelIdentifierFieldMetadataId || : fieldMetadataItem.name === DEFAULT_LABEL_IDENTIFIER_FIELD_NAME;
fieldMetadataItem.name === DEFAULT_LABEL_IDENTIFIER_FIELD_NAME
);
}; };

View File

@ -6,9 +6,11 @@ import styled from '@emotion/styled';
import { useRelationMetadata } from '@/object-metadata/hooks/useRelationMetadata'; import { useRelationMetadata } from '@/object-metadata/hooks/useRelationMetadata';
import { FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem'; import { FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem';
import { getObjectSlug } from '@/object-metadata/utils/getObjectSlug'; import { getObjectSlug } from '@/object-metadata/utils/getObjectSlug';
import { FieldIdentifierType } from '@/settings/data-model/types/FieldIdentifierType';
import { useIcons } from '@/ui/display/icon/hooks/useIcons'; import { useIcons } from '@/ui/display/icon/hooks/useIcons';
import { TableCell } from '@/ui/layout/table/components/TableCell'; import { TableCell } from '@/ui/layout/table/components/TableCell';
import { TableRow } from '@/ui/layout/table/components/TableRow'; import { TableRow } from '@/ui/layout/table/components/TableRow';
import { Nullable } from '~/types/Nullable';
import { relationTypes } from '../../constants/relationTypes'; import { relationTypes } from '../../constants/relationTypes';
import { settingsFieldMetadataTypes } from '../../constants/settingsFieldMetadataTypes'; import { settingsFieldMetadataTypes } from '../../constants/settingsFieldMetadataTypes';
@ -18,6 +20,8 @@ import { SettingsObjectFieldDataType } from './SettingsObjectFieldDataType';
type SettingsObjectFieldItemTableRowProps = { type SettingsObjectFieldItemTableRowProps = {
ActionIcon: ReactNode; ActionIcon: ReactNode;
fieldMetadataItem: FieldMetadataItem; fieldMetadataItem: FieldMetadataItem;
identifierType?: Nullable<FieldIdentifierType>;
variant?: 'field-type' | 'identifier';
}; };
export const StyledObjectFieldTableRow = styled(TableRow)` export const StyledObjectFieldTableRow = styled(TableRow)`
@ -37,6 +41,8 @@ const StyledIconTableCell = styled(TableCell)`
export const SettingsObjectFieldItemTableRow = ({ export const SettingsObjectFieldItemTableRow = ({
ActionIcon, ActionIcon,
fieldMetadataItem, fieldMetadataItem,
identifierType,
variant = 'field-type',
}: SettingsObjectFieldItemTableRowProps) => { }: SettingsObjectFieldItemTableRowProps) => {
const theme = useTheme(); const theme = useTheme();
const { getIcon } = useIcons(); const { getIcon } = useIcons();
@ -66,7 +72,11 @@ export const SettingsObjectFieldItemTableRow = ({
{fieldMetadataItem.label} {fieldMetadataItem.label}
</StyledNameTableCell> </StyledNameTableCell>
<TableCell> <TableCell>
{fieldMetadataItem.isCustom ? 'Custom' : 'Standard'} {variant === 'field-type' &&
(fieldMetadataItem.isCustom ? 'Custom' : 'Standard')}
{variant === 'identifier' &&
!!identifierType &&
(identifierType === 'label' ? 'Record text' : 'Record image')}
</TableCell> </TableCell>
<TableCell> <TableCell>
<SettingsObjectFieldDataType <SettingsObjectFieldDataType

View File

@ -0,0 +1 @@
export type FieldIdentifierType = 'label' | 'image';

View File

@ -0,0 +1,28 @@
import { FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem';
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
import { isLabelIdentifierField } from '@/object-metadata/utils/isLabelIdentifierField';
import { FieldIdentifierType } from '@/settings/data-model/types/FieldIdentifierType';
export const getFieldIdentifierType = (
activeFieldMetadatItem: FieldMetadataItem,
activeObjectMetadataItem: ObjectMetadataItem,
): FieldIdentifierType | undefined => {
const fieldIsLabelIdentifier = isLabelIdentifierField({
fieldMetadataItem: activeFieldMetadatItem,
objectMetadataItem: activeObjectMetadataItem,
});
if (fieldIsLabelIdentifier) {
return 'label';
}
const fieldIsImageIdentifier =
activeObjectMetadataItem.imageIdentifierFieldMetadataId ===
activeFieldMetadatItem.id;
if (fieldIsImageIdentifier) {
return 'image';
}
return undefined;
};

View File

@ -15,6 +15,7 @@ import {
SettingsObjectFieldItemTableRow, SettingsObjectFieldItemTableRow,
StyledObjectFieldTableRow, StyledObjectFieldTableRow,
} from '@/settings/data-model/object-details/components/SettingsObjectFieldItemTableRow'; } from '@/settings/data-model/object-details/components/SettingsObjectFieldItemTableRow';
import { getFieldIdentifierType } from '@/settings/data-model/utils/getFieldIdentifierType';
import { AppPath } from '@/types/AppPath'; import { AppPath } from '@/types/AppPath';
import { IconPlus, IconSettings } from '@/ui/display/icon'; import { IconPlus, IconSettings } from '@/ui/display/icon';
import { H2Title } from '@/ui/display/typography/components/H2Title'; import { H2Title } from '@/ui/display/typography/components/H2Title';
@ -25,7 +26,6 @@ import { Table } from '@/ui/layout/table/components/Table';
import { TableHeader } from '@/ui/layout/table/components/TableHeader'; import { TableHeader } from '@/ui/layout/table/components/TableHeader';
import { TableSection } from '@/ui/layout/table/components/TableSection'; import { TableSection } from '@/ui/layout/table/components/TableSection';
import { Breadcrumb } from '@/ui/navigation/bread-crumb/components/Breadcrumb'; import { Breadcrumb } from '@/ui/navigation/bread-crumb/components/Breadcrumb';
import { sortFieldMetadataItem } from '~/utils/sortFieldMetadataItem';
const StyledDiv = styled.div` const StyledDiv = styled.div`
display: flex; display: flex;
@ -52,16 +52,12 @@ export const SettingsObjectDetail = () => {
if (!activeObjectMetadataItem) return null; if (!activeObjectMetadataItem) return null;
const activeMetadataFields = activeObjectMetadataItem.fields const activeMetadataFields = activeObjectMetadataItem.fields.filter(
.filter( (metadataField) => metadataField.isActive && !metadataField.isSystem,
(metadataField) => metadataField.isActive && !metadataField.isSystem, );
) const disabledMetadataFields = activeObjectMetadataItem.fields.filter(
.sort(sortFieldMetadataItem); (metadataField) => !metadataField.isActive && !metadataField.isSystem,
const disabledMetadataFields = activeObjectMetadataItem.fields );
.filter(
(metadataField) => !metadataField.isActive && !metadataField.isSystem,
)
.sort(sortFieldMetadataItem);
const handleDisableObject = async () => { const handleDisableObject = async () => {
await disableObjectMetadataItem(activeObjectMetadataItem); await disableObjectMetadataItem(activeObjectMetadataItem);
@ -98,7 +94,11 @@ export const SettingsObjectDetail = () => {
<Table> <Table>
<StyledObjectFieldTableRow> <StyledObjectFieldTableRow>
<TableHeader>Name</TableHeader> <TableHeader>Name</TableHeader>
<TableHeader>Field type</TableHeader> <TableHeader>
{activeObjectMetadataItem.isCustom
? 'Identifier'
: 'Field type'}
</TableHeader>
<TableHeader>Data type</TableHeader> <TableHeader>Data type</TableHeader>
<TableHeader></TableHeader> <TableHeader></TableHeader>
</StyledObjectFieldTableRow> </StyledObjectFieldTableRow>
@ -107,6 +107,15 @@ export const SettingsObjectDetail = () => {
{activeMetadataFields.map((activeMetadataField) => ( {activeMetadataFields.map((activeMetadataField) => (
<SettingsObjectFieldItemTableRow <SettingsObjectFieldItemTableRow
key={activeMetadataField.id} key={activeMetadataField.id}
identifierType={getFieldIdentifierType(
activeMetadataField,
activeObjectMetadataItem,
)}
variant={
activeObjectMetadataItem.isCustom
? 'identifier'
: 'field-type'
}
fieldMetadataItem={activeMetadataField} fieldMetadataItem={activeMetadataField}
ActionIcon={ ActionIcon={
<SettingsObjectFieldActiveActionDropdown <SettingsObjectFieldActiveActionDropdown
@ -134,6 +143,11 @@ export const SettingsObjectDetail = () => {
{disabledMetadataFields.map((disabledMetadataField) => ( {disabledMetadataFields.map((disabledMetadataField) => (
<SettingsObjectFieldItemTableRow <SettingsObjectFieldItemTableRow
key={disabledMetadataField.id} key={disabledMetadataField.id}
variant={
activeObjectMetadataItem.isCustom
? 'identifier'
: 'field-type'
}
fieldMetadataItem={disabledMetadataField} fieldMetadataItem={disabledMetadataField}
ActionIcon={ ActionIcon={
<SettingsObjectFieldDisabledActionDropdown <SettingsObjectFieldDisabledActionDropdown