feat: add Object Edit Settings section with Object preview (#4216)

* feat: add Object Edit Settings section with Object preview

Closes #3834

* fix: fix preview card stories

* test: improve getFieldDefaultPreviewValue tests

* test: add getFieldPreviewValueFromRecord tests

* test: add useFieldPreview tests

* refactor: rename and move components

* fix: restore RecordStoreDecorator
This commit is contained in:
Thaïs
2024-02-29 11:23:56 -03:00
committed by GitHub
parent 6ad3880696
commit a892d0f653
43 changed files with 1665 additions and 937 deletions

View File

@ -0,0 +1,203 @@
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
import {
mockedCompanyObjectMetadataItem,
mockedPersonObjectMetadataItem,
} from '@/object-record/record-field/__mocks__/fieldDefinitions';
import { SettingsObjectFieldSelectFormValues } from '@/settings/data-model/components/SettingsObjectFieldSelectForm';
import { getFieldDefaultPreviewValue } from '../getFieldDefaultPreviewValue';
describe('getFieldDefaultPreviewValue', () => {
describe('SELECT field', () => {
it('returns the default select option', () => {
// Given
const objectMetadataItem = mockedCompanyObjectMetadataItem;
const fieldMetadataItem = mockedCompanyObjectMetadataItem.fields.find(
({ name }) => name === 'industry',
)!;
const selectOptions: SettingsObjectFieldSelectFormValues = [
{
color: 'purple',
label: '🏭 Industry',
value: 'INDUSTRY',
},
{
color: 'pink',
isDefault: true,
label: '💊 Health',
value: 'HEALTH',
},
];
// When
const result = getFieldDefaultPreviewValue({
objectMetadataItem,
fieldMetadataItem,
selectOptions,
});
// Then
expect(result).toEqual(selectOptions[1]);
});
it('returns the first select option if no default option was found', () => {
// Given
const objectMetadataItem = mockedCompanyObjectMetadataItem;
const fieldMetadataItem = mockedCompanyObjectMetadataItem.fields.find(
({ name }) => name === 'industry',
)!;
const selectOptions = [
{
color: 'purple' as const,
label: '🏭 Industry',
value: 'INDUSTRY',
},
{
color: 'pink' as const,
label: '💊 Health',
value: 'HEALTH',
},
];
// When
const result = getFieldDefaultPreviewValue({
objectMetadataItem,
fieldMetadataItem,
selectOptions,
});
// Then
expect(result).toEqual(selectOptions[0]);
});
});
describe('RELATION field', () => {
it('returns a record with a default label identifier (if relation label identifier type !== TEXT)', () => {
// Given
const objectMetadataItem = mockedCompanyObjectMetadataItem;
const fieldMetadataItem = mockedCompanyObjectMetadataItem.fields.find(
({ name }) => name === 'people',
)!;
const relationObjectMetadataItem = mockedPersonObjectMetadataItem;
// When
const result = getFieldDefaultPreviewValue({
objectMetadataItem,
fieldMetadataItem,
relationObjectMetadataItem,
});
// Then
expect(result).toEqual({
name: {
firstName: 'John',
lastName: 'Doe',
},
});
});
it('returns a record with the relation object label singular as label identifier (if relation label identifier type === TEXT)', () => {
// Given
const objectMetadataItem = mockedPersonObjectMetadataItem;
const fieldMetadataItem = mockedPersonObjectMetadataItem.fields.find(
({ name }) => name === 'company',
)!;
const relationObjectMetadataItem = mockedCompanyObjectMetadataItem;
// When
const result = getFieldDefaultPreviewValue({
objectMetadataItem,
fieldMetadataItem,
relationObjectMetadataItem,
});
// Then
expect(result).toEqual({
name: 'Company',
});
});
it('returns null if the relation object does not have a label identifier field', () => {
// Given
const objectMetadataItem = mockedPersonObjectMetadataItem;
const fieldMetadataItem = mockedPersonObjectMetadataItem.fields.find(
({ name }) => name === 'company',
)!;
const relationObjectMetadataItem: ObjectMetadataItem = {
...mockedCompanyObjectMetadataItem,
labelIdentifierFieldMetadataId: null,
fields: mockedCompanyObjectMetadataItem.fields.filter(
({ name }) => name !== 'name',
),
};
// When
const result = getFieldDefaultPreviewValue({
objectMetadataItem,
fieldMetadataItem,
relationObjectMetadataItem,
});
// Then
expect(result).toBeNull();
});
});
describe('Other fields', () => {
it('returns the object singular name as default value for the label identifier field (type TEXT)', () => {
// Given
const objectMetadataItem = mockedCompanyObjectMetadataItem;
const fieldMetadataItem = mockedCompanyObjectMetadataItem.fields.find(
({ name }) => name === 'name',
)!;
// When
const result = getFieldDefaultPreviewValue({
objectMetadataItem,
fieldMetadataItem,
});
// Then
expect(result).toBe('Company');
});
it('returns a default value for the label identifier field (type FULL_NAME)', () => {
// Given
const objectMetadataItem = mockedPersonObjectMetadataItem;
const fieldMetadataItem = mockedPersonObjectMetadataItem.fields.find(
({ name }) => name === 'name',
)!;
// When
const result = getFieldDefaultPreviewValue({
objectMetadataItem,
fieldMetadataItem,
});
// Then
expect(result).toEqual({
firstName: 'John',
lastName: 'Doe',
});
});
it('returns a default value for other field types', () => {
// Given
const objectMetadataItem = mockedCompanyObjectMetadataItem;
const fieldMetadataItem = mockedCompanyObjectMetadataItem.fields.find(
({ name }) => name === 'domainName',
)!;
// When
const result = getFieldDefaultPreviewValue({
objectMetadataItem,
fieldMetadataItem,
});
// Then
expect(result).toBe(
'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum magna enim, dapibus non enim in, lacinia faucibus nunc. Sed interdum ante sed felis facilisis, eget ultricies neque molestie. Mauris auctor, justo eu volutpat cursus, libero erat tempus nulla, non sodales lorem lacus a est.',
);
});
});
});

View File

@ -0,0 +1,149 @@
import {
mockedCompanyObjectMetadataItem,
mockedPersonObjectMetadataItem,
} from '@/object-record/record-field/__mocks__/fieldDefinitions';
import { ObjectRecord } from '@/object-record/types/ObjectRecord';
import { SettingsObjectFieldSelectFormValues } from '@/settings/data-model/components/SettingsObjectFieldSelectForm';
import { getFieldPreviewValueFromRecord } from '../getFieldPreviewValueFromRecord';
describe('getFieldPreviewValueFromRecord', () => {
describe('SELECT field', () => {
it('returns the select option corresponding to the record field value', () => {
// Given
const record: ObjectRecord = { id: '', industry: 'GREEN_TECH' };
const fieldMetadataItem = mockedCompanyObjectMetadataItem.fields.find(
({ name }) => name === 'industry',
)!;
const selectOptions: SettingsObjectFieldSelectFormValues = [
{
color: 'purple',
label: '🏭 Industry',
value: 'INDUSTRY',
},
{
color: 'pink',
isDefault: true,
label: '💊 Health',
value: 'HEALTH',
},
{
color: 'turquoise',
label: '🌿 Green tech',
value: 'GREEN_TECH',
},
];
// When
const result = getFieldPreviewValueFromRecord({
record,
fieldMetadataItem,
selectOptions,
});
// Then
expect(result).toEqual(selectOptions[2]);
});
it('returns undefined if the select option was not found', () => {
// Given
const record: ObjectRecord = { id: '', industry: 'MOBILITY' };
const fieldMetadataItem = mockedCompanyObjectMetadataItem.fields.find(
({ name }) => name === 'industry',
)!;
const selectOptions: SettingsObjectFieldSelectFormValues = [
{
color: 'purple',
label: '🏭 Industry',
value: 'INDUSTRY',
},
{
color: 'pink',
isDefault: true,
label: '💊 Health',
value: 'HEALTH',
},
{
color: 'turquoise',
label: '🌿 Green tech',
value: 'GREEN_TECH',
},
];
// When
const result = getFieldPreviewValueFromRecord({
record,
fieldMetadataItem,
selectOptions,
});
// Then
expect(result).toBeUndefined();
});
});
describe('RELATION field', () => {
it('returns the first relation record from a list of edges ("to many" relation)', () => {
// Given
const firstRelationRecord = {
id: '1',
name: { firstName: 'Jane', lastName: 'Doe' },
};
const record: ObjectRecord = {
id: '',
people: {
edges: [{ node: firstRelationRecord }, { node: { id: '2' } }],
},
};
const fieldMetadataItem = mockedCompanyObjectMetadataItem.fields.find(
({ name }) => name === 'people',
)!;
// When
const result = getFieldPreviewValueFromRecord({
record,
fieldMetadataItem,
});
// Then
expect(result).toEqual(firstRelationRecord);
});
it('returns the record field value ("to one" relation)', () => {
// Given
const relationRecord = { id: '20', name: 'Twenty' };
const record = { id: '', company: relationRecord };
const fieldMetadataItem = mockedPersonObjectMetadataItem.fields.find(
({ name }) => name === 'company',
)!;
// When
const result = getFieldPreviewValueFromRecord({
record,
fieldMetadataItem,
});
// Then
expect(result).toEqual(relationRecord);
});
});
describe('Other fields', () => {
it('returns the record field value', () => {
// Given
const record = { id: '', name: 'Twenty' };
const fieldMetadataItem = mockedCompanyObjectMetadataItem.fields.find(
({ name }) => name === 'name',
)!;
// When
const result = getFieldPreviewValueFromRecord({
record,
fieldMetadataItem,
});
// Then
expect(result).toEqual(record.name);
});
});
});

View File

@ -0,0 +1,68 @@
import { FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem';
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
import { getLabelIdentifierFieldMetadataItem } from '@/object-metadata/utils/getLabelIdentifierFieldMetadataItem';
import { isLabelIdentifierField } from '@/object-metadata/utils/isLabelIdentifierField';
import { SettingsObjectFieldSelectFormValues } from '@/settings/data-model/components/SettingsObjectFieldSelectForm';
import { SETTINGS_FIELD_METADATA_TYPES } from '@/settings/data-model/constants/SettingsFieldMetadataTypes';
import { FieldMetadataType } from '~/generated-metadata/graphql';
export const getFieldDefaultPreviewValue = ({
fieldMetadataItem,
objectMetadataItem,
relationObjectMetadataItem,
selectOptions,
}: {
fieldMetadataItem: Pick<FieldMetadataItem, 'type'> & {
id?: string;
name?: string;
};
objectMetadataItem: ObjectMetadataItem;
relationObjectMetadataItem?: ObjectMetadataItem;
selectOptions?: SettingsObjectFieldSelectFormValues;
}) => {
// Select field
if (fieldMetadataItem.type === FieldMetadataType.Select && selectOptions) {
return selectOptions.find(({ isDefault }) => isDefault) || selectOptions[0];
}
// Relation field
if (
fieldMetadataItem.type === FieldMetadataType.Relation &&
relationObjectMetadataItem
) {
const relationLabelIdentifierFieldMetadataItem =
getLabelIdentifierFieldMetadataItem(relationObjectMetadataItem);
if (!relationLabelIdentifierFieldMetadataItem) return null;
const defaultRelationLabelIdentifierFieldValue =
relationLabelIdentifierFieldMetadataItem.type === FieldMetadataType.Text
? relationObjectMetadataItem.labelSingular
: SETTINGS_FIELD_METADATA_TYPES[
relationLabelIdentifierFieldMetadataItem.type
]?.defaultValue;
const defaultRelationRecord = {
[relationLabelIdentifierFieldMetadataItem.name]:
defaultRelationLabelIdentifierFieldValue,
};
return defaultRelationRecord;
}
const isLabelIdentifier =
!!fieldMetadataItem.id &&
!!fieldMetadataItem.name &&
isLabelIdentifierField({
fieldMetadataItem: {
id: fieldMetadataItem.id,
name: fieldMetadataItem.name,
},
objectMetadataItem,
});
// Other fields
return isLabelIdentifier && fieldMetadataItem.type === FieldMetadataType.Text
? objectMetadataItem.labelSingular
: SETTINGS_FIELD_METADATA_TYPES[fieldMetadataItem.type]?.defaultValue;
};

View File

@ -0,0 +1,34 @@
import { FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem';
import { ObjectRecord } from '@/object-record/types/ObjectRecord';
import { SettingsObjectFieldSelectFormValues } from '@/settings/data-model/components/SettingsObjectFieldSelectForm';
import { FieldMetadataType } from '~/generated-metadata/graphql';
export const getFieldPreviewValueFromRecord = ({
record,
fieldMetadataItem,
selectOptions,
}: {
record: ObjectRecord;
fieldMetadataItem: Pick<FieldMetadataItem, 'name' | 'type'>;
selectOptions?: SettingsObjectFieldSelectFormValues;
}) => {
const recordFieldValue = record[fieldMetadataItem.name];
// Select field
if (fieldMetadataItem.type === FieldMetadataType.Select) {
return selectOptions?.find(
(selectOption) => selectOption.value === recordFieldValue,
);
}
// Relation fields (to many)
if (
fieldMetadataItem.type === FieldMetadataType.Relation &&
Array.isArray(recordFieldValue?.edges)
) {
return recordFieldValue.edges[0]?.node;
}
// Other fields
return recordFieldValue;
};