Add Role tab to agent detail page and fix restricted fields permission issue (#15276)
This commit is contained in:
@@ -6,10 +6,11 @@ import { CreateRecordService } from 'src/engine/core-modules/record-crud/service
|
||||
import { DeleteRecordService } from 'src/engine/core-modules/record-crud/services/delete-record.service';
|
||||
import { FindRecordsService } from 'src/engine/core-modules/record-crud/services/find-records.service';
|
||||
import { UpdateRecordService } from 'src/engine/core-modules/record-crud/services/update-record.service';
|
||||
import { generateCreateRecordInputSchema } from 'src/engine/core-modules/record-crud/utils/generate-create-record-input-schema.util';
|
||||
import { generateUpdateRecordInputSchema } from 'src/engine/core-modules/record-crud/utils/generate-update-record-input-schema.util';
|
||||
import { BulkDeleteToolInputSchema } from 'src/engine/core-modules/record-crud/zod-schemas/bulk-delete-tool.zod-schema';
|
||||
import { generateFindToolInputSchema } from 'src/engine/core-modules/record-crud/zod-schemas/find-tool.zod-schema';
|
||||
import { FindOneToolInputSchema } from 'src/engine/core-modules/record-crud/zod-schemas/find-one-tool.zod-schema';
|
||||
import { generateRecordInputSchema } from 'src/engine/core-modules/record-crud/zod-schemas/record-input.zod-schema';
|
||||
import { generateFindToolInputSchema } from 'src/engine/core-modules/record-crud/zod-schemas/find-tool.zod-schema';
|
||||
import { SoftDeleteToolInputSchema } from 'src/engine/core-modules/record-crud/zod-schemas/soft-delete-tool.zod-schema';
|
||||
import { isWorkflowRunObject } from 'src/engine/metadata-modules/agent/utils/is-workflow-run-object.util';
|
||||
import { type ActorMetadata } from 'src/engine/metadata-modules/field-metadata/composite-types/actor.composite-type';
|
||||
@@ -87,10 +88,15 @@ export class ToolService {
|
||||
return;
|
||||
}
|
||||
|
||||
const restrictedFields = objectPermission.restrictedFields;
|
||||
|
||||
if (objectPermission.canUpdateObjectRecords) {
|
||||
tools[`create_${objectMetadata.nameSingular}`] = {
|
||||
description: `Create a new ${objectMetadata.labelSingular} record. Provide all required fields and any optional fields you want to set. The system will automatically handle timestamps and IDs. Returns the created record with all its data.`,
|
||||
inputSchema: generateRecordInputSchema(objectMetadata),
|
||||
inputSchema: generateCreateRecordInputSchema(
|
||||
objectMetadata,
|
||||
restrictedFields,
|
||||
),
|
||||
execute: async (parameters) => {
|
||||
return this.createRecordService.execute({
|
||||
objectName: objectMetadata.nameSingular,
|
||||
@@ -104,9 +110,18 @@ export class ToolService {
|
||||
|
||||
tools[`update_${objectMetadata.nameSingular}`] = {
|
||||
description: `Update an existing ${objectMetadata.labelSingular} record. Provide the record ID and only the fields you want to change. Unspecified fields will remain unchanged. Returns the updated record with all current data.`,
|
||||
inputSchema: generateRecordInputSchema(objectMetadata),
|
||||
inputSchema: generateUpdateRecordInputSchema(
|
||||
objectMetadata,
|
||||
restrictedFields,
|
||||
),
|
||||
execute: async (parameters) => {
|
||||
const { id, ...objectRecord } = parameters.input;
|
||||
const { id, ...allFields } = parameters.input;
|
||||
|
||||
const objectRecord = Object.fromEntries(
|
||||
Object.entries(allFields).filter(
|
||||
([, value]) => value !== undefined,
|
||||
),
|
||||
);
|
||||
|
||||
return this.updateRecordService.execute({
|
||||
objectName: objectMetadata.nameSingular,
|
||||
@@ -122,7 +137,10 @@ export class ToolService {
|
||||
if (objectPermission.canReadObjectRecords) {
|
||||
tools[`find_${objectMetadata.nameSingular}`] = {
|
||||
description: `Search for ${objectMetadata.labelSingular} records using flexible filtering criteria. Supports exact matches, pattern matching, ranges, and null checks. Use limit/offset for pagination and orderBy for sorting. Returns an array of matching records with their full data.`,
|
||||
inputSchema: generateFindToolInputSchema(objectMetadata),
|
||||
inputSchema: generateFindToolInputSchema(
|
||||
objectMetadata,
|
||||
restrictedFields,
|
||||
),
|
||||
execute: async (parameters) => {
|
||||
const { limit, offset, orderBy, ...filter } = parameters.input;
|
||||
|
||||
|
||||
+22
-7
@@ -8,6 +8,7 @@ import {
|
||||
RecordCrudExceptionCode,
|
||||
} from 'src/engine/core-modules/record-crud/exceptions/record-crud.exception';
|
||||
import { type CreateRecordParams } from 'src/engine/core-modules/record-crud/types/create-record-params.type';
|
||||
import { getSelectedColumnsFromRestrictedFields } from 'src/engine/core-modules/record-crud/utils/get-selected-columns-from-restricted-fields.util';
|
||||
import { RecordPositionService } from 'src/engine/core-modules/record-position/services/record-position.service';
|
||||
import { RecordInputTransformerService } from 'src/engine/core-modules/record-transformer/services/record-input-transformer.service';
|
||||
import { type ToolOutput } from 'src/engine/core-modules/tool/types/tool-output.type';
|
||||
@@ -83,14 +84,28 @@ export class CreateRecordService {
|
||||
objectMetadataMapItem: objectMetadataItemWithFieldsMaps,
|
||||
});
|
||||
|
||||
const insertResult = await repository.insert({
|
||||
...transformedObjectRecord,
|
||||
position,
|
||||
createdBy: params.createdBy ?? {
|
||||
source: FieldActorSource.WORKFLOW,
|
||||
name: 'Workflow',
|
||||
const restrictedFields =
|
||||
repository.objectRecordsPermissions?.[
|
||||
objectMetadataItemWithFieldsMaps.id
|
||||
]?.restrictedFields;
|
||||
|
||||
const selectedColumns = getSelectedColumnsFromRestrictedFields(
|
||||
restrictedFields,
|
||||
objectMetadataItemWithFieldsMaps,
|
||||
);
|
||||
|
||||
const insertResult = await repository.insert(
|
||||
{
|
||||
...transformedObjectRecord,
|
||||
position,
|
||||
createdBy: params.createdBy ?? {
|
||||
source: FieldActorSource.WORKFLOW,
|
||||
name: 'Workflow',
|
||||
},
|
||||
},
|
||||
});
|
||||
undefined,
|
||||
selectedColumns,
|
||||
);
|
||||
|
||||
const [createdRecord] = insertResult.generatedMaps;
|
||||
|
||||
|
||||
+50
-2
@@ -1,5 +1,6 @@
|
||||
import { Injectable, Logger } from '@nestjs/common';
|
||||
|
||||
import isEmpty from 'lodash.isempty';
|
||||
import { QUERY_MAX_RECORDS } from 'twenty-shared/constants';
|
||||
import { OrderByDirection } from 'twenty-shared/types';
|
||||
import { type ObjectLiteral } from 'typeorm';
|
||||
@@ -10,9 +11,12 @@ import {
|
||||
} from 'src/engine/api/graphql/workspace-query-builder/interfaces/object-record.interface';
|
||||
|
||||
import { GraphqlQueryParser } from 'src/engine/api/graphql/graphql-query-runner/graphql-query-parsers/graphql-query.parser';
|
||||
import { getAllSelectableFields } from 'src/engine/api/utils/get-all-selectable-fields.utils';
|
||||
import { type FindRecordsParams } from 'src/engine/core-modules/record-crud/types/find-records-params.type';
|
||||
import { FindRecordsResult } from 'src/engine/core-modules/record-crud/types/find-records-result.type';
|
||||
import { type ToolOutput } from 'src/engine/core-modules/tool/types/tool-output.type';
|
||||
import { type ObjectMetadataItemWithFieldMaps } from 'src/engine/metadata-modules/types/object-metadata-item-with-field-maps';
|
||||
import { type WorkspaceSelectQueryBuilder } from 'src/engine/twenty-orm/repository/workspace-select-query-builder';
|
||||
import { type WorkspaceRepository } from 'src/engine/twenty-orm/repository/workspace.repository';
|
||||
import { TwentyORMGlobalManager } from 'src/engine/twenty-orm/twenty-orm-global.manager';
|
||||
import { WorkflowCommonWorkspaceService } from 'src/modules/workflow/common/workspace-services/workflow-common.workspace-service';
|
||||
@@ -75,6 +79,7 @@ export class FindRecordsService {
|
||||
offset,
|
||||
repository,
|
||||
graphqlQueryParser,
|
||||
objectMetadataItemWithFieldsMaps,
|
||||
});
|
||||
|
||||
const totalCount = await this.getTotalCount({
|
||||
@@ -82,6 +87,7 @@ export class FindRecordsService {
|
||||
filter,
|
||||
repository,
|
||||
graphqlQueryParser,
|
||||
objectMetadataItemWithFieldsMaps,
|
||||
});
|
||||
|
||||
this.logger.log(`Found ${records.length} records in ${objectName}`);
|
||||
@@ -106,6 +112,32 @@ export class FindRecordsService {
|
||||
}
|
||||
}
|
||||
|
||||
private applyRestrictedFieldsToQueryBuilder<T extends ObjectLiteral>(
|
||||
queryBuilder: WorkspaceSelectQueryBuilder<T>,
|
||||
repository: WorkspaceRepository<T>,
|
||||
objectMetadataItemWithFieldsMaps: ObjectMetadataItemWithFieldMaps,
|
||||
): WorkspaceSelectQueryBuilder<T> {
|
||||
const restrictedFields =
|
||||
repository.objectRecordsPermissions?.[objectMetadataItemWithFieldsMaps.id]
|
||||
?.restrictedFields;
|
||||
|
||||
if (!restrictedFields || isEmpty(restrictedFields)) {
|
||||
return queryBuilder;
|
||||
}
|
||||
|
||||
const selectableFields = getAllSelectableFields({
|
||||
restrictedFields,
|
||||
objectMetadata: {
|
||||
objectMetadataMapItem: objectMetadataItemWithFieldsMaps,
|
||||
},
|
||||
});
|
||||
|
||||
return queryBuilder.setFindOptions({
|
||||
// @ts-expect-error - TypeORM typing limitation with dynamic select fields
|
||||
select: selectableFields,
|
||||
});
|
||||
}
|
||||
|
||||
private async getObjectRecords<T extends ObjectLiteral>({
|
||||
objectName,
|
||||
filter,
|
||||
@@ -114,6 +146,7 @@ export class FindRecordsService {
|
||||
offset,
|
||||
repository,
|
||||
graphqlQueryParser,
|
||||
objectMetadataItemWithFieldsMaps,
|
||||
}: {
|
||||
objectName: string;
|
||||
filter:
|
||||
@@ -125,6 +158,7 @@ export class FindRecordsService {
|
||||
offset: number;
|
||||
repository: WorkspaceRepository<T>;
|
||||
graphqlQueryParser: GraphqlQueryParser;
|
||||
objectMetadataItemWithFieldsMaps: ObjectMetadataItemWithFieldMaps;
|
||||
}): Promise<T[]> {
|
||||
const queryBuilder = repository.createQueryBuilder(objectName);
|
||||
|
||||
@@ -146,7 +180,13 @@ export class FindRecordsService {
|
||||
false,
|
||||
);
|
||||
|
||||
return withOrderByQueryBuilder
|
||||
const queryBuilderWithSelect = this.applyRestrictedFieldsToQueryBuilder(
|
||||
withOrderByQueryBuilder,
|
||||
repository,
|
||||
objectMetadataItemWithFieldsMaps,
|
||||
);
|
||||
|
||||
return queryBuilderWithSelect
|
||||
.skip(offset)
|
||||
.take(limit ? Math.min(limit, QUERY_MAX_RECORDS) : QUERY_MAX_RECORDS)
|
||||
.getMany();
|
||||
@@ -157,6 +197,7 @@ export class FindRecordsService {
|
||||
filter,
|
||||
repository,
|
||||
graphqlQueryParser,
|
||||
objectMetadataItemWithFieldsMaps,
|
||||
}: {
|
||||
objectName: string;
|
||||
filter:
|
||||
@@ -165,6 +206,7 @@ export class FindRecordsService {
|
||||
| undefined;
|
||||
repository: WorkspaceRepository<ObjectLiteral>;
|
||||
graphqlQueryParser: GraphqlQueryParser;
|
||||
objectMetadataItemWithFieldsMaps: ObjectMetadataItemWithFieldMaps;
|
||||
}): Promise<number> {
|
||||
const countQueryBuilder = repository.createQueryBuilder(objectName);
|
||||
|
||||
@@ -180,6 +222,12 @@ export class FindRecordsService {
|
||||
filter ?? {},
|
||||
);
|
||||
|
||||
return withDeletedCountQueryBuilder.getCount();
|
||||
const queryBuilderWithSelect = this.applyRestrictedFieldsToQueryBuilder(
|
||||
withDeletedCountQueryBuilder,
|
||||
repository,
|
||||
objectMetadataItemWithFieldsMaps,
|
||||
);
|
||||
|
||||
return queryBuilderWithSelect.getCount();
|
||||
}
|
||||
}
|
||||
|
||||
+26
-9
@@ -9,6 +9,7 @@ import {
|
||||
RecordCrudExceptionCode,
|
||||
} from 'src/engine/core-modules/record-crud/exceptions/record-crud.exception';
|
||||
import { type UpdateRecordParams } from 'src/engine/core-modules/record-crud/types/update-record-params.type';
|
||||
import { getSelectedColumnsFromRestrictedFields } from 'src/engine/core-modules/record-crud/utils/get-selected-columns-from-restricted-fields.util';
|
||||
import { RecordInputTransformerService } from 'src/engine/core-modules/record-transformer/services/record-input-transformer.service';
|
||||
import { type ToolOutput } from 'src/engine/core-modules/tool/types/tool-output.type';
|
||||
import { TwentyORMGlobalManager } from 'src/engine/twenty-orm/twenty-orm-global.manager';
|
||||
@@ -59,10 +60,27 @@ export class UpdateRecordService {
|
||||
rolePermissionConfig,
|
||||
);
|
||||
|
||||
const { objectMetadataItemWithFieldsMaps } =
|
||||
await this.workflowCommonWorkspaceService.getObjectMetadataItemWithFieldsMaps(
|
||||
objectName,
|
||||
workspaceId,
|
||||
);
|
||||
|
||||
const restrictedFields =
|
||||
repository.objectRecordsPermissions?.[
|
||||
objectMetadataItemWithFieldsMaps.id
|
||||
]?.restrictedFields;
|
||||
|
||||
const selectedColumns = getSelectedColumnsFromRestrictedFields(
|
||||
restrictedFields,
|
||||
objectMetadataItemWithFieldsMaps,
|
||||
);
|
||||
|
||||
const previousObjectRecord = await repository.findOne({
|
||||
where: {
|
||||
id: objectRecordId,
|
||||
},
|
||||
select: selectedColumns,
|
||||
});
|
||||
|
||||
if (!previousObjectRecord) {
|
||||
@@ -82,12 +100,6 @@ export class UpdateRecordService {
|
||||
};
|
||||
}
|
||||
|
||||
const { objectMetadataItemWithFieldsMaps } =
|
||||
await this.workflowCommonWorkspaceService.getObjectMetadataItemWithFieldsMaps(
|
||||
objectName,
|
||||
workspaceId,
|
||||
);
|
||||
|
||||
if (
|
||||
!canObjectBeManagedByWorkflow({
|
||||
nameSingular: objectMetadataItemWithFieldsMaps.nameSingular,
|
||||
@@ -126,9 +138,14 @@ export class UpdateRecordService {
|
||||
};
|
||||
|
||||
if (!deepEqual(updatedObjectRecord, previousObjectRecord)) {
|
||||
await repository.update(objectRecordId, {
|
||||
...transformedObjectRecord,
|
||||
});
|
||||
await repository.update(
|
||||
objectRecordId,
|
||||
{
|
||||
...transformedObjectRecord,
|
||||
},
|
||||
undefined,
|
||||
selectedColumns,
|
||||
);
|
||||
}
|
||||
|
||||
this.logger.log(`Record updated successfully in ${objectName}`);
|
||||
|
||||
+24
-7
@@ -8,6 +8,7 @@ import {
|
||||
RecordCrudExceptionCode,
|
||||
} from 'src/engine/core-modules/record-crud/exceptions/record-crud.exception';
|
||||
import { UpsertRecordParams } from 'src/engine/core-modules/record-crud/types/upsert-record-params.type';
|
||||
import { getSelectedColumnsFromRestrictedFields } from 'src/engine/core-modules/record-crud/utils/get-selected-columns-from-restricted-fields.util';
|
||||
import { RecordInputTransformerService } from 'src/engine/core-modules/record-transformer/services/record-input-transformer.service';
|
||||
import { type ToolOutput } from 'src/engine/core-modules/tool/types/tool-output.type';
|
||||
import { computeCompositeColumnName } from 'src/engine/metadata-modules/field-metadata/utils/compute-column-name.util';
|
||||
@@ -135,13 +136,28 @@ export class UpsertRecordService {
|
||||
)
|
||||
.filter(isDefined);
|
||||
|
||||
const upsertResult = await repository.upsert(transformedObjectRecord, {
|
||||
conflictPaths: conflictPaths,
|
||||
indexPredicate:
|
||||
indexPredicate.length > 0
|
||||
? `${indexPredicate.join(' AND ')}`
|
||||
: undefined,
|
||||
});
|
||||
const restrictedFields =
|
||||
repository.objectRecordsPermissions?.[
|
||||
objectMetadataItemWithFieldsMaps.id
|
||||
]?.restrictedFields;
|
||||
|
||||
const selectedColumns = getSelectedColumnsFromRestrictedFields(
|
||||
restrictedFields,
|
||||
objectMetadataItemWithFieldsMaps,
|
||||
);
|
||||
|
||||
const upsertResult = await repository.upsert(
|
||||
transformedObjectRecord,
|
||||
{
|
||||
conflictPaths: conflictPaths,
|
||||
indexPredicate:
|
||||
indexPredicate.length > 0
|
||||
? `${indexPredicate.join(' AND ')}`
|
||||
: undefined,
|
||||
},
|
||||
undefined,
|
||||
selectedColumns,
|
||||
);
|
||||
|
||||
const upsertedRecordId = upsertResult.identifiers?.[0].id;
|
||||
|
||||
@@ -156,6 +172,7 @@ export class UpsertRecordService {
|
||||
where: {
|
||||
id: upsertedRecordId,
|
||||
},
|
||||
select: selectedColumns,
|
||||
});
|
||||
|
||||
if (!upsertedRecord) {
|
||||
|
||||
+4
-1
@@ -1,14 +1,17 @@
|
||||
import { type RestrictedFieldsPermissions } from 'twenty-shared/types';
|
||||
import { z } from 'zod';
|
||||
|
||||
import { generateRecordPropertiesZodSchema } from 'src/engine/core-modules/record-crud/zod-schemas/record-properties.zod-schema';
|
||||
import { type ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity';
|
||||
|
||||
export const generateRecordInputSchema = (
|
||||
export const generateCreateRecordInputSchema = (
|
||||
objectMetadata: ObjectMetadataEntity,
|
||||
restrictedFields?: RestrictedFieldsPermissions,
|
||||
) => {
|
||||
const recordPropertiesSchema = generateRecordPropertiesZodSchema(
|
||||
objectMetadata,
|
||||
false,
|
||||
restrictedFields,
|
||||
);
|
||||
|
||||
return z.object({
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
import { type RestrictedFieldsPermissions } from 'twenty-shared/types';
|
||||
import { z } from 'zod';
|
||||
|
||||
import { generateRecordPropertiesZodSchema } from 'src/engine/core-modules/record-crud/zod-schemas/record-properties.zod-schema';
|
||||
import { type ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity';
|
||||
|
||||
export const generateUpdateRecordInputSchema = (
|
||||
objectMetadata: ObjectMetadataEntity,
|
||||
restrictedFields?: RestrictedFieldsPermissions,
|
||||
) => {
|
||||
const recordPropertiesSchema = generateRecordPropertiesZodSchema(
|
||||
objectMetadata,
|
||||
false,
|
||||
restrictedFields,
|
||||
);
|
||||
|
||||
const updateSchema = recordPropertiesSchema.partial().extend({
|
||||
id: z.string().uuid({
|
||||
message:
|
||||
'The unique identifier (UUID) of the record to update. This is required to identify which record should be modified.',
|
||||
}),
|
||||
});
|
||||
|
||||
return z.object({
|
||||
loadingMessage: z
|
||||
.string()
|
||||
.optional()
|
||||
.describe(
|
||||
'A clear, human-readable description of the action being performed. Explain what operation you are executing and with what parameters in natural language.',
|
||||
),
|
||||
input: updateSchema,
|
||||
});
|
||||
};
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
import isEmpty from 'lodash.isempty';
|
||||
import { type RestrictedFieldsPermissions } from 'twenty-shared/types';
|
||||
|
||||
import { getAllSelectableFields } from 'src/engine/api/utils/get-all-selectable-fields.utils';
|
||||
import { type ObjectMetadataItemWithFieldMaps } from 'src/engine/metadata-modules/types/object-metadata-item-with-field-maps';
|
||||
|
||||
export const getSelectedColumnsFromRestrictedFields = (
|
||||
restrictedFields: RestrictedFieldsPermissions | undefined,
|
||||
objectMetadataItemWithFieldsMaps: ObjectMetadataItemWithFieldMaps,
|
||||
): string[] | undefined => {
|
||||
if (!restrictedFields || isEmpty(restrictedFields)) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const selectableFields = getAllSelectableFields({
|
||||
restrictedFields,
|
||||
objectMetadata: {
|
||||
objectMetadataMapItem: objectMetadataItemWithFieldsMaps,
|
||||
},
|
||||
});
|
||||
|
||||
return Object.keys(selectableFields).filter((key) => selectableFields[key]);
|
||||
};
|
||||
+8
-2
@@ -1,12 +1,14 @@
|
||||
import { type RestrictedFieldsPermissions } from 'twenty-shared/types';
|
||||
import { z } from 'zod';
|
||||
|
||||
import { ObjectRecordOrderBySchema } from 'src/engine/core-modules/record-crud/zod-schemas/order-by.zod-schema';
|
||||
import { generateFieldFilterZodSchema } from 'src/engine/core-modules/record-crud/zod-schemas/field-filters.zod-schema';
|
||||
import { type ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity';
|
||||
import { ObjectRecordOrderBySchema } from 'src/engine/core-modules/record-crud/zod-schemas/order-by.zod-schema';
|
||||
import { shouldExcludeFieldFromAgentToolSchema } from 'src/engine/metadata-modules/field-metadata/utils/should-exclude-field-from-agent-tool-schema.util';
|
||||
import { type ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity';
|
||||
|
||||
export const generateFindToolInputSchema = (
|
||||
objectMetadata: ObjectMetadataEntity,
|
||||
restrictedFields?: RestrictedFieldsPermissions,
|
||||
) => {
|
||||
const filterShape: Record<string, z.ZodTypeAny> = {};
|
||||
|
||||
@@ -15,6 +17,10 @@ export const generateFindToolInputSchema = (
|
||||
return;
|
||||
}
|
||||
|
||||
if (restrictedFields?.[field.id]?.canRead === false) {
|
||||
return;
|
||||
}
|
||||
|
||||
const filterSchema = generateFieldFilterZodSchema(field);
|
||||
|
||||
if (filterSchema) {
|
||||
|
||||
+10
-2
@@ -1,6 +1,9 @@
|
||||
import { z } from 'zod';
|
||||
import { FieldMetadataType } from 'twenty-shared/types';
|
||||
import {
|
||||
FieldMetadataType,
|
||||
type RestrictedFieldsPermissions,
|
||||
} from 'twenty-shared/types';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { z } from 'zod';
|
||||
|
||||
import {
|
||||
type FieldMetadataSettings,
|
||||
@@ -74,6 +77,7 @@ const getFieldZodType = (field: FieldMetadataEntity): z.ZodTypeAny => {
|
||||
export const generateRecordPropertiesZodSchema = (
|
||||
objectMetadata: ObjectMetadataEntity,
|
||||
forResponse = false,
|
||||
restrictedFields?: RestrictedFieldsPermissions,
|
||||
): z.ZodObject<Record<string, z.ZodTypeAny>> => {
|
||||
const shape: Record<string, z.ZodTypeAny> = {};
|
||||
|
||||
@@ -85,6 +89,10 @@ export const generateRecordPropertiesZodSchema = (
|
||||
return;
|
||||
}
|
||||
|
||||
if (restrictedFields?.[field.id]?.canUpdate === false) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
isFieldMetadataEntityOfType(field, FieldMetadataType.RELATION) &&
|
||||
field.settings?.relationType === RelationType.MANY_TO_ONE
|
||||
|
||||
Reference in New Issue
Block a user