d55b83375d
- exports `extendObject` utils from `twenty-sdk` - define `*.object-extension.ts` filename pattern to extend and object - handle object-extension configs in manifest
80 lines
2.2 KiB
TypeScript
80 lines
2.2 KiB
TypeScript
import { type ObjectExtensionManifest } from 'twenty-shared/application';
|
|
import { isNonEmptyString } from '@sniptt/guards';
|
|
import { validateFieldsOrThrow } from './validate-fields';
|
|
|
|
/**
|
|
* Extend an existing object with additional fields.
|
|
*
|
|
* @example
|
|
* ```typescript
|
|
* import { extendObject, FieldType, STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS } from 'twenty-sdk';
|
|
*
|
|
* // Extend by object name
|
|
* export const companyExtension = extendObject({
|
|
* targetObject: {
|
|
* nameSingular: 'company',
|
|
* },
|
|
* fields: [
|
|
* {
|
|
* universalIdentifier: '...',
|
|
* name: 'healthScore',
|
|
* type: FieldType.NUMBER,
|
|
* label: 'Health Score',
|
|
* description: 'Calculated customer health metric',
|
|
* },
|
|
* {
|
|
* universalIdentifier: '...',
|
|
* name: 'churnRisk',
|
|
* type: FieldType.SELECT,
|
|
* label: 'Churn Risk',
|
|
* options: [
|
|
* { label: 'Low', value: 'low', color: 'green' },
|
|
* { label: 'Medium', value: 'medium', color: 'yellow' },
|
|
* { label: 'High', value: 'high', color: 'red' },
|
|
* ],
|
|
* },
|
|
* ],
|
|
* });
|
|
*
|
|
* // Or extend by universal identifier
|
|
* export const companyExtensionById = extendObject({
|
|
* targetObject: {
|
|
* universalIdentifier: STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.company,
|
|
* },
|
|
* fields: [...],
|
|
* });
|
|
* ```
|
|
*/
|
|
export const extendObject = <T extends ObjectExtensionManifest>(
|
|
config: T,
|
|
): T => {
|
|
if (!config.targetObject) {
|
|
throw new Error('Object extension must have a targetObject');
|
|
}
|
|
|
|
const { nameSingular, universalIdentifier } = config.targetObject;
|
|
|
|
if (
|
|
!isNonEmptyString(nameSingular) &&
|
|
!isNonEmptyString(universalIdentifier)
|
|
) {
|
|
throw new Error(
|
|
'targetObject must have either nameSingular or universalIdentifier',
|
|
);
|
|
}
|
|
|
|
if (isNonEmptyString(nameSingular) && isNonEmptyString(universalIdentifier)) {
|
|
throw new Error(
|
|
'targetObject cannot have both nameSingular and universalIdentifier - they are mutually exclusive',
|
|
);
|
|
}
|
|
|
|
if (!config.fields || config.fields.length === 0) {
|
|
throw new Error('Object extension must have at least one field');
|
|
}
|
|
|
|
validateFieldsOrThrow(config.fields);
|
|
|
|
return config;
|
|
};
|