[Fix] isLabelSyncedWithName should be nullable (#9028)
isLabelSyncedWithName should be nullable for fieldMetadata, as it is for objectMetadata. + Adding missing validation on label and name sync in fieldMetadataService for creation and update + adding metadata tests
This commit is contained in:
@ -204,7 +204,7 @@ export type CreateFieldInput = {
|
||||
icon?: InputMaybe<Scalars['String']['input']>;
|
||||
isActive?: InputMaybe<Scalars['Boolean']['input']>;
|
||||
isCustom?: InputMaybe<Scalars['Boolean']['input']>;
|
||||
isLabelSyncedWithName: Scalars['Boolean']['input'];
|
||||
isLabelSyncedWithName?: InputMaybe<Scalars['Boolean']['input']>;
|
||||
isNullable?: InputMaybe<Scalars['Boolean']['input']>;
|
||||
isRemoteCreation?: InputMaybe<Scalars['Boolean']['input']>;
|
||||
isSystem?: InputMaybe<Scalars['Boolean']['input']>;
|
||||
@ -1569,10 +1569,10 @@ export type UpdateServerlessFunctionInput = {
|
||||
};
|
||||
|
||||
export type UpdateWorkflowVersionStepInput = {
|
||||
/** Step to update in JSON format */
|
||||
step: Scalars['JSON']['input'];
|
||||
/** Boolean to check if we need to update stepOutput */
|
||||
shouldUpdateStepOutput?: InputMaybe<Scalars['Boolean']['input']>;
|
||||
/** Step to update in JSON format */
|
||||
step: Scalars['JSON']['input'];
|
||||
/** Workflow version ID */
|
||||
workflowVersionId: Scalars['String']['input'];
|
||||
};
|
||||
@ -1707,6 +1707,7 @@ export type Workspace = {
|
||||
__typename?: 'Workspace';
|
||||
activationStatus: WorkspaceActivationStatus;
|
||||
allowImpersonation: Scalars['Boolean']['output'];
|
||||
billingCustomers?: Maybe<Array<BillingCustomer>>;
|
||||
billingEntitlements?: Maybe<Array<BillingEntitlement>>;
|
||||
billingSubscriptions?: Maybe<Array<BillingSubscription>>;
|
||||
createdAt: Scalars['DateTime']['output'];
|
||||
@ -1732,6 +1733,12 @@ export type Workspace = {
|
||||
};
|
||||
|
||||
|
||||
export type WorkspaceBillingCustomersArgs = {
|
||||
filter?: BillingCustomerFilter;
|
||||
sorting?: Array<BillingCustomerSort>;
|
||||
};
|
||||
|
||||
|
||||
export type WorkspaceBillingEntitlementsArgs = {
|
||||
filter?: BillingEntitlementFilter;
|
||||
sorting?: Array<BillingEntitlementSort>;
|
||||
@ -1819,6 +1826,27 @@ export type WorkspaceNameAndId = {
|
||||
id: Scalars['String']['output'];
|
||||
};
|
||||
|
||||
export type BillingCustomer = {
|
||||
__typename?: 'billingCustomer';
|
||||
id: Scalars['UUID']['output'];
|
||||
};
|
||||
|
||||
export type BillingCustomerFilter = {
|
||||
and?: InputMaybe<Array<BillingCustomerFilter>>;
|
||||
id?: InputMaybe<UuidFilterComparison>;
|
||||
or?: InputMaybe<Array<BillingCustomerFilter>>;
|
||||
};
|
||||
|
||||
export type BillingCustomerSort = {
|
||||
direction: SortDirection;
|
||||
field: BillingCustomerSortFields;
|
||||
nulls?: InputMaybe<SortNulls>;
|
||||
};
|
||||
|
||||
export enum BillingCustomerSortFields {
|
||||
Id = 'id'
|
||||
}
|
||||
|
||||
export type BillingEntitlement = {
|
||||
__typename?: 'billingEntitlement';
|
||||
id: Scalars['UUID']['output'];
|
||||
@ -1853,7 +1881,7 @@ export type Field = {
|
||||
id: Scalars['UUID']['output'];
|
||||
isActive?: Maybe<Scalars['Boolean']['output']>;
|
||||
isCustom?: Maybe<Scalars['Boolean']['output']>;
|
||||
isLabelSyncedWithName: Scalars['Boolean']['output'];
|
||||
isLabelSyncedWithName?: Maybe<Scalars['Boolean']['output']>;
|
||||
isNullable?: Maybe<Scalars['Boolean']['output']>;
|
||||
isSystem?: Maybe<Scalars['Boolean']['output']>;
|
||||
isUnique?: Maybe<Scalars['Boolean']['output']>;
|
||||
@ -2120,7 +2148,7 @@ export type UpdateOneFieldMetadataItemMutationVariables = Exact<{
|
||||
}>;
|
||||
|
||||
|
||||
export type UpdateOneFieldMetadataItemMutation = { __typename?: 'Mutation', updateOneField: { __typename?: 'field', id: any, type: FieldMetadataType, name: string, label: string, description?: string | null, icon?: string | null, isCustom?: boolean | null, isActive?: boolean | null, isNullable?: boolean | null, createdAt: any, updatedAt: any, settings?: any | null, isLabelSyncedWithName: boolean } };
|
||||
export type UpdateOneFieldMetadataItemMutation = { __typename?: 'Mutation', updateOneField: { __typename?: 'field', id: any, type: FieldMetadataType, name: string, label: string, description?: string | null, icon?: string | null, isCustom?: boolean | null, isActive?: boolean | null, isNullable?: boolean | null, createdAt: any, updatedAt: any, settings?: any | null, isLabelSyncedWithName?: boolean | null } };
|
||||
|
||||
export type UpdateOneObjectMetadataItemMutationVariables = Exact<{
|
||||
idToUpdate: Scalars['UUID']['input'];
|
||||
@ -2157,7 +2185,7 @@ export type ObjectMetadataItemsQueryVariables = Exact<{
|
||||
}>;
|
||||
|
||||
|
||||
export type ObjectMetadataItemsQuery = { __typename?: 'Query', objects: { __typename?: 'ObjectConnection', edges: Array<{ __typename?: 'objectEdge', node: { __typename?: 'object', id: any, dataSourceId: string, nameSingular: string, namePlural: string, labelSingular: string, labelPlural: string, description?: string | null, icon?: string | null, isCustom: boolean, isRemote: boolean, isActive: boolean, isSystem: boolean, createdAt: any, updatedAt: any, labelIdentifierFieldMetadataId?: string | null, imageIdentifierFieldMetadataId?: string | null, shortcut?: string | null, isLabelSyncedWithName: boolean, indexMetadatas: { __typename?: 'ObjectIndexMetadatasConnection', edges: Array<{ __typename?: 'indexEdge', node: { __typename?: 'index', id: any, createdAt: any, updatedAt: any, name: string, indexWhereClause?: string | null, indexType: IndexType, isUnique: boolean, indexFieldMetadatas: { __typename?: 'IndexIndexFieldMetadatasConnection', edges: Array<{ __typename?: 'indexFieldEdge', node: { __typename?: 'indexField', id: any, createdAt: any, updatedAt: any, order: number, fieldMetadataId: any } }> } } }> }, fields: { __typename?: 'ObjectFieldsConnection', edges: Array<{ __typename?: 'fieldEdge', node: { __typename?: 'field', id: any, type: FieldMetadataType, name: string, label: string, description?: string | null, icon?: string | null, isCustom?: boolean | null, isActive?: boolean | null, isSystem?: boolean | null, isNullable?: boolean | null, isUnique?: boolean | null, createdAt: any, updatedAt: any, defaultValue?: any | null, options?: any | null, settings?: any | null, isLabelSyncedWithName: boolean, relationDefinition?: { __typename?: 'RelationDefinition', relationId: any, direction: RelationDefinitionType, sourceObjectMetadata: { __typename?: 'object', id: any, nameSingular: string, namePlural: string }, sourceFieldMetadata: { __typename?: 'field', id: any, name: string }, targetObjectMetadata: { __typename?: 'object', id: any, nameSingular: string, namePlural: string }, targetFieldMetadata: { __typename?: 'field', id: any, name: string } } | null } }>, pageInfo: { __typename?: 'PageInfo', hasNextPage?: boolean | null, hasPreviousPage?: boolean | null, startCursor?: any | null, endCursor?: any | null } } } }>, pageInfo: { __typename?: 'PageInfo', hasNextPage?: boolean | null, hasPreviousPage?: boolean | null, startCursor?: any | null, endCursor?: any | null } } };
|
||||
export type ObjectMetadataItemsQuery = { __typename?: 'Query', objects: { __typename?: 'ObjectConnection', edges: Array<{ __typename?: 'objectEdge', node: { __typename?: 'object', id: any, dataSourceId: string, nameSingular: string, namePlural: string, labelSingular: string, labelPlural: string, description?: string | null, icon?: string | null, isCustom: boolean, isRemote: boolean, isActive: boolean, isSystem: boolean, createdAt: any, updatedAt: any, labelIdentifierFieldMetadataId?: string | null, imageIdentifierFieldMetadataId?: string | null, shortcut?: string | null, isLabelSyncedWithName: boolean, indexMetadatas: { __typename?: 'ObjectIndexMetadatasConnection', edges: Array<{ __typename?: 'indexEdge', node: { __typename?: 'index', id: any, createdAt: any, updatedAt: any, name: string, indexWhereClause?: string | null, indexType: IndexType, isUnique: boolean, indexFieldMetadatas: { __typename?: 'IndexIndexFieldMetadatasConnection', edges: Array<{ __typename?: 'indexFieldEdge', node: { __typename?: 'indexField', id: any, createdAt: any, updatedAt: any, order: number, fieldMetadataId: any } }> } } }> }, fields: { __typename?: 'ObjectFieldsConnection', edges: Array<{ __typename?: 'fieldEdge', node: { __typename?: 'field', id: any, type: FieldMetadataType, name: string, label: string, description?: string | null, icon?: string | null, isCustom?: boolean | null, isActive?: boolean | null, isSystem?: boolean | null, isNullable?: boolean | null, isUnique?: boolean | null, createdAt: any, updatedAt: any, defaultValue?: any | null, options?: any | null, settings?: any | null, isLabelSyncedWithName?: boolean | null, relationDefinition?: { __typename?: 'RelationDefinition', relationId: any, direction: RelationDefinitionType, sourceObjectMetadata: { __typename?: 'object', id: any, nameSingular: string, namePlural: string }, sourceFieldMetadata: { __typename?: 'field', id: any, name: string }, targetObjectMetadata: { __typename?: 'object', id: any, nameSingular: string, namePlural: string }, targetFieldMetadata: { __typename?: 'field', id: any, name: string } } | null } }>, pageInfo: { __typename?: 'PageInfo', hasNextPage?: boolean | null, hasPreviousPage?: boolean | null, startCursor?: any | null, endCursor?: any | null } } } }>, pageInfo: { __typename?: 'PageInfo', hasNextPage?: boolean | null, hasPreviousPage?: boolean | null, startCursor?: any | null, endCursor?: any | null } } };
|
||||
|
||||
export type ServerlessFunctionFieldsFragment = { __typename?: 'ServerlessFunction', id: any, name: string, description?: string | null, runtime: string, syncStatus: ServerlessFunctionSyncStatus, latestVersion?: string | null, latestVersionInputSchema?: any | null, publishedVersions: Array<string>, createdAt: any, updatedAt: any };
|
||||
|
||||
@ -2251,4 +2279,4 @@ export const UpdateOneServerlessFunctionDocument = {"kind":"Document","definitio
|
||||
export const FindManyAvailablePackagesDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"FindManyAvailablePackages"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ServerlessFunctionIdInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"getAvailablePackages"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}]}]}}]} as unknown as DocumentNode<FindManyAvailablePackagesQuery, FindManyAvailablePackagesQueryVariables>;
|
||||
export const GetManyServerlessFunctionsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetManyServerlessFunctions"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"findManyServerlessFunctions"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ServerlessFunctionFields"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ServerlessFunctionFields"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"ServerlessFunction"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"runtime"}},{"kind":"Field","name":{"kind":"Name","value":"syncStatus"}},{"kind":"Field","name":{"kind":"Name","value":"latestVersion"}},{"kind":"Field","name":{"kind":"Name","value":"latestVersionInputSchema"}},{"kind":"Field","name":{"kind":"Name","value":"publishedVersions"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}}]}}]} as unknown as DocumentNode<GetManyServerlessFunctionsQuery, GetManyServerlessFunctionsQueryVariables>;
|
||||
export const GetOneServerlessFunctionDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetOneServerlessFunction"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ServerlessFunctionIdInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"findOneServerlessFunction"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ServerlessFunctionFields"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ServerlessFunctionFields"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"ServerlessFunction"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"runtime"}},{"kind":"Field","name":{"kind":"Name","value":"syncStatus"}},{"kind":"Field","name":{"kind":"Name","value":"latestVersion"}},{"kind":"Field","name":{"kind":"Name","value":"latestVersionInputSchema"}},{"kind":"Field","name":{"kind":"Name","value":"publishedVersions"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}}]}}]} as unknown as DocumentNode<GetOneServerlessFunctionQuery, GetOneServerlessFunctionQueryVariables>;
|
||||
export const FindOneServerlessFunctionSourceCodeDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"FindOneServerlessFunctionSourceCode"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"GetServerlessFunctionSourceCodeInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"getServerlessFunctionSourceCode"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}]}]}}]} as unknown as DocumentNode<FindOneServerlessFunctionSourceCodeQuery, FindOneServerlessFunctionSourceCodeQueryVariables>;
|
||||
export const FindOneServerlessFunctionSourceCodeDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"FindOneServerlessFunctionSourceCode"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"GetServerlessFunctionSourceCodeInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"getServerlessFunctionSourceCode"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}]}]}}]} as unknown as DocumentNode<FindOneServerlessFunctionSourceCodeQuery, FindOneServerlessFunctionSourceCodeQueryVariables>;
|
||||
@ -39,5 +39,5 @@ export type FieldMetadataItem = Omit<
|
||||
settings?: {
|
||||
displayAsRelativeDate?: boolean;
|
||||
};
|
||||
isLabelSyncedWithName?: boolean;
|
||||
isLabelSyncedWithName?: boolean | null;
|
||||
};
|
||||
|
||||
@ -164,7 +164,9 @@ export const SettingsDataModelFieldIconLabelForm = ({
|
||||
placeholder="employees"
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
disabled={disabled || isLabelSyncedWithName}
|
||||
disabled={
|
||||
disabled || (isLabelSyncedWithName ?? false)
|
||||
}
|
||||
fullWidth
|
||||
maxLength={DATABASE_IDENTIFIER_MAXIMUM_LENGTH}
|
||||
RightIcon={() =>
|
||||
|
||||
@ -147,7 +147,7 @@ export class FieldMetadataDTO<
|
||||
|
||||
@IsBoolean()
|
||||
@IsOptional()
|
||||
@Field()
|
||||
@Field({ nullable: true })
|
||||
isLabelSyncedWithName?: boolean;
|
||||
|
||||
@IsDateString()
|
||||
|
||||
@ -32,6 +32,7 @@ import { isCompositeFieldMetadataType } from 'src/engine/metadata-modules/field-
|
||||
import { isSelectFieldMetadataType } from 'src/engine/metadata-modules/field-metadata/utils/is-select-field-metadata-type.util';
|
||||
import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity';
|
||||
import { assertMutationNotOnRemoteObject } from 'src/engine/metadata-modules/object-metadata/utils/assert-mutation-not-on-remote-object.util';
|
||||
import { validateNameAndLabelAreSyncOrThrow } from 'src/engine/metadata-modules/object-metadata/utils/validate-object-metadata-input.util';
|
||||
import {
|
||||
RelationMetadataEntity,
|
||||
RelationMetadataType,
|
||||
@ -175,6 +176,13 @@ export class FieldMetadataService extends TypeOrmQueryService<FieldMetadataEntit
|
||||
objectMetadata,
|
||||
);
|
||||
|
||||
if (fieldMetadataForCreate.isLabelSyncedWithName === true) {
|
||||
validateNameAndLabelAreSyncOrThrow(
|
||||
fieldMetadataForCreate.label,
|
||||
fieldMetadataForCreate.name,
|
||||
);
|
||||
}
|
||||
|
||||
console.time('createOne save');
|
||||
const createdFieldMetadata = await fieldMetadataRepository.save(
|
||||
fieldMetadataForCreate,
|
||||
@ -407,6 +415,17 @@ export class FieldMetadataService extends TypeOrmQueryService<FieldMetadataEntit
|
||||
objectMetadata,
|
||||
);
|
||||
|
||||
const isLabelSyncedWithName =
|
||||
fieldMetadataForUpdate.isLabelSyncedWithName ??
|
||||
existingFieldMetadata.isLabelSyncedWithName;
|
||||
|
||||
if (isLabelSyncedWithName) {
|
||||
validateNameAndLabelAreSyncOrThrow(
|
||||
fieldMetadataForUpdate.label ?? existingFieldMetadata.label,
|
||||
fieldMetadataForUpdate.name ?? existingFieldMetadata.name,
|
||||
);
|
||||
}
|
||||
|
||||
// We're running field update under a transaction, so we can rollback if migration fails
|
||||
await fieldMetadataRepository.update(id, fieldMetadataForUpdate);
|
||||
|
||||
|
||||
@ -0,0 +1,106 @@
|
||||
import { createOneFieldMetadataFactory } from 'test/integration/metadata/suites/field-metadata/utils/create-one-field-metadata-factory.util';
|
||||
import { createListingCustomObject } from 'test/integration/metadata/suites/object-metadata/utils/create-test-object-metadata.util';
|
||||
import { deleteOneObjectMetadataItem } from 'test/integration/metadata/suites/object-metadata/utils/delete-one-object-metadata.util';
|
||||
import { makeMetadataAPIRequest } from 'test/integration/metadata/suites/utils/make-metadata-api-request.util';
|
||||
|
||||
import { FieldMetadataType } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity';
|
||||
|
||||
describe('createOne', () => {
|
||||
describe('FieldMetadataService name/label sync', () => {
|
||||
let listingObjectId = '';
|
||||
|
||||
beforeEach(async () => {
|
||||
const { objectMetadataId: createdObjectId } =
|
||||
await createListingCustomObject();
|
||||
|
||||
listingObjectId = createdObjectId;
|
||||
});
|
||||
afterEach(async () => {
|
||||
await deleteOneObjectMetadataItem(listingObjectId);
|
||||
});
|
||||
it('should create a field when name and label are synced correctly', async () => {
|
||||
// Arrange
|
||||
const FIELD_NAME = 'testField';
|
||||
const createFieldInput = {
|
||||
name: FIELD_NAME,
|
||||
label: 'Test Field',
|
||||
type: FieldMetadataType.TEXT,
|
||||
objectMetadataId: listingObjectId,
|
||||
isLabelSyncedWithName: true,
|
||||
};
|
||||
|
||||
// Act
|
||||
const graphqlOperation = createOneFieldMetadataFactory({
|
||||
input: { field: createFieldInput },
|
||||
gqlFields: `
|
||||
id
|
||||
name
|
||||
label
|
||||
isLabelSyncedWithName
|
||||
`,
|
||||
});
|
||||
|
||||
const response = await makeMetadataAPIRequest(graphqlOperation);
|
||||
|
||||
// Assert
|
||||
expect(response.body.data.createOneField.name).toBe(FIELD_NAME);
|
||||
});
|
||||
|
||||
it('should set isLabelSyncWithName to false if not in input', async () => {
|
||||
// Arrange
|
||||
const createFieldInput = {
|
||||
name: 'testField',
|
||||
label: 'Test Field',
|
||||
type: FieldMetadataType.TEXT,
|
||||
objectMetadataId: listingObjectId,
|
||||
};
|
||||
|
||||
// Act
|
||||
const graphqlOperation = createOneFieldMetadataFactory({
|
||||
input: { field: createFieldInput },
|
||||
gqlFields: `
|
||||
id
|
||||
name
|
||||
label
|
||||
isLabelSyncedWithName
|
||||
`,
|
||||
});
|
||||
|
||||
const response = await makeMetadataAPIRequest(graphqlOperation);
|
||||
|
||||
// Assert
|
||||
expect(response.body.data.createOneField.isLabelSyncedWithName).toBe(
|
||||
false,
|
||||
);
|
||||
});
|
||||
|
||||
it('should return an error when name and label are not synced but isLabelSyncedWithName is true', async () => {
|
||||
// Arrange
|
||||
const createFieldInput = {
|
||||
name: 'testField',
|
||||
label: 'Different Label',
|
||||
type: FieldMetadataType.TEXT,
|
||||
objectMetadataId: listingObjectId,
|
||||
isLabelSyncedWithName: true,
|
||||
};
|
||||
|
||||
const graphqlOperation = createOneFieldMetadataFactory({
|
||||
input: { field: createFieldInput },
|
||||
gqlFields: `
|
||||
id
|
||||
name
|
||||
label
|
||||
isLabelSyncedWithName
|
||||
`,
|
||||
});
|
||||
|
||||
// Act
|
||||
const response = await makeMetadataAPIRequest(graphqlOperation);
|
||||
|
||||
// Assert
|
||||
expect(response.body.errors[0].message).toBe(
|
||||
'Name is not synced with label. Expected name: "differentLabel", got testField',
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -0,0 +1,103 @@
|
||||
import { createTestTextFieldMetadata } from 'test/integration/metadata/suites/field-metadata/utils/create-test-field-metadata.util';
|
||||
import { deleteFieldMetadata } from 'test/integration/metadata/suites/field-metadata/utils/delete-one-field-metadata.util';
|
||||
import { updateOneFieldMetadataFactory } from 'test/integration/metadata/suites/field-metadata/utils/update-one-field-metadata-factory.util';
|
||||
import { createListingCustomObject } from 'test/integration/metadata/suites/object-metadata/utils/create-test-object-metadata.util';
|
||||
import { deleteOneObjectMetadataItem } from 'test/integration/metadata/suites/object-metadata/utils/delete-one-object-metadata.util';
|
||||
import { makeMetadataAPIRequest } from 'test/integration/metadata/suites/utils/make-metadata-api-request.util';
|
||||
|
||||
describe('updateOne', () => {
|
||||
describe('FieldMetadataService name/label sync', () => {
|
||||
let listingObjectId = '';
|
||||
let testFieldId = '';
|
||||
|
||||
beforeEach(async () => {
|
||||
const { objectMetadataId: createdObjectId } =
|
||||
await createListingCustomObject();
|
||||
|
||||
listingObjectId = createdObjectId;
|
||||
|
||||
const { fieldMetadataId: createdFieldMetadaId } =
|
||||
await createTestTextFieldMetadata(createdObjectId);
|
||||
|
||||
testFieldId = createdFieldMetadaId;
|
||||
});
|
||||
afterEach(async () => {
|
||||
await deleteFieldMetadata(testFieldId);
|
||||
await deleteOneObjectMetadataItem(listingObjectId);
|
||||
});
|
||||
|
||||
it('should update a field name and label when they are synced correctly', async () => {
|
||||
// Arrange
|
||||
const updateFieldInput = {
|
||||
name: 'newName',
|
||||
label: 'New name',
|
||||
};
|
||||
|
||||
// Act
|
||||
const graphqlOperation = updateOneFieldMetadataFactory({
|
||||
input: { id: testFieldId, update: updateFieldInput },
|
||||
gqlFields: `
|
||||
id
|
||||
name
|
||||
label
|
||||
isLabelSyncedWithName
|
||||
`,
|
||||
});
|
||||
|
||||
const response = await makeMetadataAPIRequest(graphqlOperation);
|
||||
|
||||
// Assert
|
||||
expect(response.body.data.updateOneField.name).toBe('newName');
|
||||
});
|
||||
|
||||
it('should update a field name and label when they are not synced correctly and labelSync is false', async () => {
|
||||
// Arrange
|
||||
const updateFieldInput = {
|
||||
name: 'differentName',
|
||||
label: 'New name',
|
||||
isLabelSyncedWithName: false,
|
||||
};
|
||||
|
||||
// Act
|
||||
const graphqlOperation = updateOneFieldMetadataFactory({
|
||||
input: { id: testFieldId, update: updateFieldInput },
|
||||
gqlFields: `
|
||||
id
|
||||
name
|
||||
label
|
||||
isLabelSyncedWithName
|
||||
`,
|
||||
});
|
||||
|
||||
const response = await makeMetadataAPIRequest(graphqlOperation);
|
||||
|
||||
// Assert
|
||||
expect(response.body.data.updateOneField.name).toBe('differentName');
|
||||
});
|
||||
|
||||
it('should not update a field name if it is not synced correctly with label and labelSync is true', async () => {
|
||||
// Arrange
|
||||
const updateFieldInput = {
|
||||
name: 'newName',
|
||||
};
|
||||
|
||||
// Act
|
||||
const graphqlOperation = updateOneFieldMetadataFactory({
|
||||
input: { id: testFieldId, update: updateFieldInput },
|
||||
gqlFields: `
|
||||
id
|
||||
name
|
||||
label
|
||||
isLabelSyncedWithName
|
||||
`,
|
||||
});
|
||||
|
||||
const response = await makeMetadataAPIRequest(graphqlOperation);
|
||||
|
||||
// Assert
|
||||
expect(response.body.errors[0].message).toBe(
|
||||
'Name is not synced with label. Expected name: "testName", got newName',
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -0,0 +1,24 @@
|
||||
import gql from 'graphql-tag';
|
||||
|
||||
import { CreateFieldInput } from 'src/engine/metadata-modules/field-metadata/dtos/create-field.input';
|
||||
|
||||
type CreateOneFieldFactoryParams = {
|
||||
gqlFields: string;
|
||||
input?: { field: Omit<CreateFieldInput, 'workspaceId' | 'dataSourceId'> };
|
||||
};
|
||||
|
||||
export const createOneFieldMetadataFactory = ({
|
||||
gqlFields,
|
||||
input,
|
||||
}: CreateOneFieldFactoryParams) => ({
|
||||
query: gql`
|
||||
mutation CreateOneFieldMetadataItem($input: CreateOneFieldMetadataInput!) {
|
||||
createOneField(input: $input) {
|
||||
${gqlFields}
|
||||
}
|
||||
}
|
||||
`,
|
||||
variables: {
|
||||
input,
|
||||
},
|
||||
});
|
||||
@ -0,0 +1,31 @@
|
||||
import { createOneFieldMetadataFactory } from 'test/integration/metadata/suites/field-metadata/utils/create-one-field-metadata-factory.util';
|
||||
import { makeMetadataAPIRequest } from 'test/integration/metadata/suites/utils/make-metadata-api-request.util';
|
||||
|
||||
import { FieldMetadataType } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity';
|
||||
|
||||
const FIELD_NAME = 'testName';
|
||||
|
||||
export const createTestTextFieldMetadata = async (
|
||||
objectMetadataItemId: string,
|
||||
) => {
|
||||
const createFieldInput = {
|
||||
name: FIELD_NAME,
|
||||
label: 'Test name',
|
||||
type: FieldMetadataType.TEXT,
|
||||
objectMetadataId: objectMetadataItemId,
|
||||
isLabelSyncedWithName: true,
|
||||
};
|
||||
const graphqlOperation = createOneFieldMetadataFactory({
|
||||
input: { field: createFieldInput },
|
||||
gqlFields: `
|
||||
id
|
||||
name
|
||||
label
|
||||
isLabelSyncedWithName
|
||||
`,
|
||||
});
|
||||
|
||||
const response = await makeMetadataAPIRequest(graphqlOperation);
|
||||
|
||||
return { fieldMetadataId: response.body.data.createOneField.id };
|
||||
};
|
||||
@ -0,0 +1,20 @@
|
||||
import gql from 'graphql-tag';
|
||||
|
||||
type DeleteOneFieldFactoryParams = {
|
||||
idToDelete: string;
|
||||
};
|
||||
|
||||
export const deleteOneFieldMetadataItemFactory = ({
|
||||
idToDelete,
|
||||
}: DeleteOneFieldFactoryParams) => ({
|
||||
query: gql`
|
||||
mutation DeleteOneFieldMetadataItem($idToDelete: UUID!) {
|
||||
deleteOneField(input: { id: $idToDelete }) {
|
||||
id
|
||||
}
|
||||
}
|
||||
`,
|
||||
variables: {
|
||||
idToDelete,
|
||||
},
|
||||
});
|
||||
@ -0,0 +1,10 @@
|
||||
import { makeGraphqlAPIRequest } from 'test/integration/graphql/utils/make-graphql-api-request.util';
|
||||
import { deleteOneFieldMetadataItemFactory } from 'test/integration/metadata/suites/field-metadata/utils/delete-one-field-metadata-factory.util';
|
||||
|
||||
export const deleteFieldMetadata = async (fieldMetadataId: string) => {
|
||||
const graphqlOperation = deleteOneFieldMetadataItemFactory({
|
||||
idToDelete: fieldMetadataId,
|
||||
});
|
||||
|
||||
await makeGraphqlAPIRequest(graphqlOperation);
|
||||
};
|
||||
@ -0,0 +1,25 @@
|
||||
import gql from 'graphql-tag';
|
||||
|
||||
import { UpdateFieldInput } from 'src/engine/metadata-modules/field-metadata/dtos/update-field.input';
|
||||
|
||||
type UpdateOneFieldFactoryParams = {
|
||||
gqlFields: string;
|
||||
input: { id: string; update: Omit<UpdateFieldInput, 'workspaceId' | 'id'> };
|
||||
};
|
||||
|
||||
export const updateOneFieldMetadataFactory = ({
|
||||
gqlFields,
|
||||
input,
|
||||
}: UpdateOneFieldFactoryParams) => ({
|
||||
query: gql`
|
||||
mutation UpdateOneFieldMetadataItem($idToUpdate: UUID!, $updatePayload: UpdateFieldInput!) {
|
||||
updateOneField(input: {id: $idToUpdate, update: $updatePayload}) {
|
||||
${gqlFields}
|
||||
}
|
||||
}
|
||||
`,
|
||||
variables: {
|
||||
idToUpdate: input.id,
|
||||
updatePayload: input.update,
|
||||
},
|
||||
});
|
||||
@ -1,7 +1,7 @@
|
||||
import { makeGraphqlAPIRequest } from 'test/integration/graphql/utils/make-graphql-api-request.util';
|
||||
import { createOneObjectMetadataFactory } from 'test/integration/metadata/suites/utils/create-one-object-metadata-factory.util';
|
||||
import { createOneObjectMetadataFactory } from 'test/integration/metadata/suites/object-metadata/utils/create-one-object-metadata-factory.util';
|
||||
import { deleteOneObjectMetadataItemFactory } from 'test/integration/metadata/suites/object-metadata/utils/delete-one-object-metadata-factory.util';
|
||||
import { createOneRelationMetadataFactory } from 'test/integration/metadata/suites/utils/create-one-relation-metadata-factory.util';
|
||||
import { deleteOneObjectMetadataItemFactory } from 'test/integration/metadata/suites/utils/delete-one-object-metadata-factory.util';
|
||||
import { deleteOneRelationMetadataItemFactory } from 'test/integration/metadata/suites/utils/delete-one-relation-metadata-factory.util';
|
||||
import { fieldsMetadataFactory } from 'test/integration/metadata/suites/utils/fields-metadata-factory.util';
|
||||
import { makeMetadataAPIRequest } from 'test/integration/metadata/suites/utils/make-metadata-api-request.util';
|
||||
|
||||
@ -0,0 +1,30 @@
|
||||
import { createOneObjectMetadataFactory } from 'test/integration/metadata/suites/object-metadata/utils/create-one-object-metadata-factory.util';
|
||||
import { makeMetadataAPIRequest } from 'test/integration/metadata/suites/utils/make-metadata-api-request.util';
|
||||
|
||||
const LISTING_NAME_SINGULAR = 'listing';
|
||||
|
||||
const LISTING_OBJECT = {
|
||||
namePlural: 'listings',
|
||||
nameSingular: LISTING_NAME_SINGULAR,
|
||||
labelPlural: 'Listings',
|
||||
labelSingular: 'Listing',
|
||||
description: 'Listing object',
|
||||
icon: 'IconListNumbers',
|
||||
isLabelSyncedWithName: false,
|
||||
};
|
||||
|
||||
export const createListingCustomObject = async () => {
|
||||
const createObjectOperation = createOneObjectMetadataFactory({
|
||||
input: { object: LISTING_OBJECT },
|
||||
gqlFields: `
|
||||
id
|
||||
nameSingular
|
||||
`,
|
||||
});
|
||||
|
||||
const response = await makeMetadataAPIRequest(createObjectOperation);
|
||||
|
||||
return {
|
||||
objectMetadataId: response.body.data.createOneObject.id,
|
||||
};
|
||||
};
|
||||
@ -0,0 +1,12 @@
|
||||
import { makeGraphqlAPIRequest } from 'test/integration/graphql/utils/make-graphql-api-request.util';
|
||||
import { deleteOneObjectMetadataItemFactory } from 'test/integration/metadata/suites/object-metadata/utils/delete-one-object-metadata-factory.util';
|
||||
|
||||
export const deleteOneObjectMetadataItem = async (
|
||||
objectMetadataItemId: string,
|
||||
) => {
|
||||
const graphqlOperation = deleteOneObjectMetadataItemFactory({
|
||||
idToDelete: objectMetadataItemId,
|
||||
});
|
||||
|
||||
await makeGraphqlAPIRequest(graphqlOperation);
|
||||
};
|
||||
Reference in New Issue
Block a user