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:
@ -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.',
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -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);
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -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;
|
||||
};
|
||||
@ -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;
|
||||
};
|
||||
Reference in New Issue
Block a user