1630 extensibility twenty cli ability to create edit and delete fields (#15501)

As title

- adds decorators in twenty-sdk
- update twenty-cli load-manifest to it gets @FieldMetadata infos +
testing
- update twenty-server so it CRUD fields properly, using
universalIdentifier
- Fix UI so we can update managed objects records
- move FieldMetadata items from twenty-server to twenty-shared
This commit is contained in:
martmull
2025-11-05 17:50:06 +01:00
committed by GitHub
parent 9fef0752a1
commit abde3c04ac
123 changed files with 1235 additions and 289 deletions
@@ -65,7 +65,7 @@ describe('isObjectMetadataReadOnly', () => {
expect(result).toBe(true);
});
it('should return true if object is managed by application', () => {
it('should return false if object is managed by application', () => {
const result = isObjectMetadataReadOnly({
objectMetadataItem: {
applicationId: 'applicationId',
@@ -74,7 +74,7 @@ describe('isObjectMetadataReadOnly', () => {
},
});
expect(result).toBe(true);
expect(result).toBe(false);
});
it('should return false if object is custom', () => {
@@ -0,0 +1,36 @@
import { isObjectMetadataSettingsReadOnly } from '@/object-record/read-only/utils/isObjectMetadataSettingsReadOnly';
describe('isObjectMetadataSettingsReadOnly', () => {
it('should return false if object can be updated and is not UI read only and is not remote', () => {
const result = isObjectMetadataSettingsReadOnly({
objectPermissions: {
canUpdateObjectRecords: true,
objectMetadataId: '123',
restrictedFields: {},
},
objectMetadataItem: {
isUIReadOnly: false,
isRemote: false,
},
});
expect(result).toBe(false);
});
it('should return true if object is managed by application', () => {
const result = isObjectMetadataSettingsReadOnly({
objectPermissions: {
canUpdateObjectRecords: true,
objectMetadataId: '123',
restrictedFields: {},
},
objectMetadataItem: {
applicationId: 'applicationId',
isUIReadOnly: false,
isRemote: false,
},
});
expect(result).toBe(true);
});
});
@@ -1,33 +0,0 @@
import { type FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem';
import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
import { isFieldMetadataReadOnlyByPermissions } from '@/object-record/read-only/utils/internal/isFieldMetadataReadOnlyByPermissions';
import { isObjectMetadataReadOnly } from '@/object-record/read-only/utils/isObjectMetadataReadOnly';
import { type ObjectPermission } from '~/generated/graphql';
type IsFieldMetadataReadOnlyParams = {
objectPermissions: ObjectPermission;
objectMetadataItem: Pick<ObjectMetadataItem, 'isUIReadOnly' | 'isRemote'>;
fieldMetadataItem: Pick<FieldMetadataItem, 'id' | 'isUIReadOnly'>;
};
export const isFieldMetadataReadOnly = ({
objectPermissions,
objectMetadataItem,
fieldMetadataItem,
}: IsFieldMetadataReadOnlyParams) => {
const objectMetadataReadOnly = isObjectMetadataReadOnly({
objectPermissions,
objectMetadataItem,
});
const fieldReadOnlyByPermissions = isFieldMetadataReadOnlyByPermissions({
objectPermissions,
fieldMetadataId: fieldMetadataItem.id,
});
return (
objectMetadataReadOnly ||
fieldMetadataItem.isUIReadOnly ||
fieldReadOnlyByPermissions
);
};
@@ -17,8 +17,7 @@ export const isObjectMetadataReadOnly = ({
return (
(isDefined(objectPermissions) &&
!objectPermissions.canUpdateObjectRecords) ||
objectMetadataItem?.isUIReadOnly ||
objectMetadataItem?.isRemote ||
isDefined(objectMetadataItem?.applicationId)
(isDefined(objectMetadataItem) &&
(objectMetadataItem.isUIReadOnly || objectMetadataItem.isRemote))
);
};
@@ -0,0 +1,22 @@
import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
import { type ObjectPermission } from '~/generated/graphql';
import { isDefined } from 'twenty-shared/utils';
import { isObjectMetadataReadOnly } from '@/object-record/read-only/utils/isObjectMetadataReadOnly';
type IsObjectMetadataReadOnlyParams = {
objectPermissions?: ObjectPermission;
objectMetadataItem?: Pick<
ObjectMetadataItem,
'isUIReadOnly' | 'isRemote' | 'applicationId'
>;
};
export const isObjectMetadataSettingsReadOnly = ({
objectPermissions,
objectMetadataItem,
}: IsObjectMetadataReadOnlyParams) => {
return (
isObjectMetadataReadOnly({ objectPermissions, objectMetadataItem }) ||
isDefined(objectMetadataItem?.applicationId)
);
};