Add call recording schema and meeting bot scaffold (#21584)

## Summary
- add 2.13 upgrade commands for call recording request status and
dropping CalendarEvent recordingPreference
- remove the recording preference from the core CalendarEvent standard
object
- add a scaffold-generated twenty-meeting-bot app with logo and the
CalendarEvent meetingBotPreference field

## Tests
- yarn install
- yarn lint
- yarn twenty dev:typecheck
- git diff --check


<!-- This is an auto-generated description by cubic. -->
<a
href="https://cubic.dev/pr/twentyhq/twenty/pull/21584?utm_source=github"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img
alt="Review in cubic"
src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a>
<!-- End of auto-generated description by cubic. -->
This commit is contained in:
nitin
2026-06-15 19:03:12 +05:30
committed by GitHub
parent d1ba63d4a4
commit 8a866dba54
47 changed files with 5716 additions and 1502 deletions
@@ -55,17 +55,7 @@ describe('CallRecording standard metadata build', () => {
expect(calendarEventIdIndex).toBeDefined();
});
it('stores the per-event recording preference on calendarEvent', () => {
const recordingPreferenceField =
allFlatEntityMaps.flatFieldMetadataMaps.byUniversalIdentifier[
STANDARD_OBJECTS.calendarEvent.fields.recordingPreference
.universalIdentifier
];
expect(recordingPreferenceField).toBeDefined();
});
it('keeps the callRecording table view focused on its label identifier and status', () => {
it('keeps the callRecording table view focused on its label identifier and statuses', () => {
const viewFieldFieldUniversalIdentifiers = Object.values(
allFlatEntityMaps.flatViewFieldMaps.byUniversalIdentifier,
)
@@ -78,11 +68,13 @@ describe('CallRecording standard metadata build', () => {
)
.map((viewField) => viewField.fieldMetadataUniversalIdentifier);
expect(viewFieldFieldUniversalIdentifiers).toHaveLength(3);
expect(viewFieldFieldUniversalIdentifiers).toHaveLength(4);
expect(viewFieldFieldUniversalIdentifiers).toEqual(
expect.arrayContaining([
STANDARD_OBJECTS.callRecording.fields.title.universalIdentifier,
STANDARD_OBJECTS.callRecording.fields.status.universalIdentifier,
STANDARD_OBJECTS.callRecording.fields.recordingRequestStatus
.universalIdentifier,
STANDARD_OBJECTS.callRecording.fields.startedAt.universalIdentifier,
]),
);
@@ -101,11 +93,13 @@ describe('CallRecording standard metadata build', () => {
)
.map((viewField) => viewField.fieldMetadataUniversalIdentifier);
expect(viewFieldFieldUniversalIdentifiers).toHaveLength(8);
expect(viewFieldFieldUniversalIdentifiers).toHaveLength(9);
expect(viewFieldFieldUniversalIdentifiers).toEqual(
expect.arrayContaining([
STANDARD_OBJECTS.callRecording.fields.title.universalIdentifier,
STANDARD_OBJECTS.callRecording.fields.status.universalIdentifier,
STANDARD_OBJECTS.callRecording.fields.recordingRequestStatus
.universalIdentifier,
STANDARD_OBJECTS.callRecording.fields.startedAt.universalIdentifier,
STANDARD_OBJECTS.callRecording.fields.endedAt.universalIdentifier,
STANDARD_OBJECTS.callRecording.fields.video.universalIdentifier,
@@ -401,48 +401,6 @@ export const buildCalendarEventStandardFlatFieldMetadatas = ({
twentyStandardApplicationId,
now,
}),
recordingPreference: createStandardFieldFlatMetadata({
objectName,
workspaceId,
context: {
fieldName: 'recordingPreference',
type: FieldMetadataType.SELECT,
label: i18nLabel(msg`Recording Preference`),
description: i18nLabel(
msg`Whether to record this event, applied on top of the workspace policy`,
),
icon: 'IconSettingsAutomation',
isNullable: false,
defaultValue: "'AUTO'",
options: [
{
id: '4c4761ce-ffbf-4176-be7f-5cf5257c8bff',
value: 'AUTO',
label: i18nLabel(msg`Auto`),
position: 0,
color: 'blue',
},
{
id: '1ae19135-e1a1-4a96-b866-91643622e554',
value: 'ON',
label: i18nLabel(msg`On`),
position: 1,
color: 'green',
},
{
id: '8c69a74f-2ab7-4c19-a813-eb0ea3533fd3',
value: 'OFF',
label: i18nLabel(msg`Off`),
position: 2,
color: 'gray',
},
],
},
standardObjectMetadataRelatedEntityIds,
dependencyFlatEntityMaps,
twentyStandardApplicationId,
now,
}),
calendarChannelEventAssociations: createStandardRelationFieldFlatMetadata({
objectName,
workspaceId,
@@ -15,6 +15,8 @@ import {
} from 'src/engine/workspace-manager/twenty-standard-application/utils/field-metadata/create-standard-field-flat-metadata.util';
import { createStandardRelationFieldFlatMetadata } from 'src/engine/workspace-manager/twenty-standard-application/utils/field-metadata/create-standard-relation-field-flat-metadata.util';
import { getTsVectorColumnExpressionFromFields } from 'src/engine/workspace-manager/utils/get-ts-vector-column-expression.util';
import { CallRecordingRequestStatus } from 'src/modules/call-recording/common/enums/call-recording-request-status.enum';
import { CallRecordingStatus } from 'src/modules/call-recording/common/enums/call-recording-status.enum';
export const buildCallRecordingStandardFlatFieldMetadatas = ({
now,
@@ -137,42 +139,42 @@ export const buildCallRecordingStandardFlatFieldMetadatas = ({
options: [
{
id: '7fa515ba-e3cb-48f7-914f-e1f664d5d920',
value: 'SCHEDULED',
value: CallRecordingStatus.SCHEDULED,
label: i18nLabel(msg`Scheduled`),
position: 0,
color: 'sky',
},
{
id: '96844ba3-364b-4975-8abc-886cca92ec99',
value: 'JOINING',
value: CallRecordingStatus.JOINING,
label: i18nLabel(msg`Joining`),
position: 1,
color: 'blue',
},
{
id: 'eccdad8b-8424-48ba-ad7f-f38517fa83fc',
value: 'RECORDING',
value: CallRecordingStatus.RECORDING,
label: i18nLabel(msg`Recording`),
position: 2,
color: 'red',
},
{
id: 'c8222203-5b44-4ac6-8142-0a7eb2074d7b',
value: 'PROCESSING',
value: CallRecordingStatus.PROCESSING,
label: i18nLabel(msg`Processing`),
position: 3,
color: 'orange',
},
{
id: 'd17faf71-af3c-4260-9021-2ffaaa5648c4',
value: 'COMPLETED',
value: CallRecordingStatus.COMPLETED,
label: i18nLabel(msg`Completed`),
position: 4,
color: 'green',
},
{
id: '4800777e-54a8-4464-9c01-07d6eefd04da',
value: 'FAILED_UNKNOWN',
value: CallRecordingStatus.FAILED_UNKNOWN,
label: i18nLabel(msg`Failed`),
position: 5,
color: 'gray',
@@ -184,6 +186,40 @@ export const buildCallRecordingStandardFlatFieldMetadatas = ({
twentyStandardApplicationId,
now,
}),
recordingRequestStatus: createStandardFieldFlatMetadata({
objectName,
workspaceId,
context: {
fieldName: 'recordingRequestStatus',
type: FieldMetadataType.SELECT,
label: i18nLabel(msg`Request Status`),
description: i18nLabel(msg`Recording request status`),
icon: 'IconCircleCheck',
isNullable: false,
isUIEditable: false,
defaultValue: "'REQUESTED'",
options: [
{
id: 'fe992923-2f51-494d-bb32-42e96a703778',
value: CallRecordingRequestStatus.REQUESTED,
label: i18nLabel(msg`Requested`),
position: 0,
color: 'sky',
},
{
id: '485767c2-2dda-4b83-91d8-6025cdb4b9df',
value: CallRecordingRequestStatus.CANCELED,
label: i18nLabel(msg`Canceled`),
position: 1,
color: 'gray',
},
],
},
standardObjectMetadataRelatedEntityIds,
dependencyFlatEntityMaps,
twentyStandardApplicationId,
now,
}),
applicationId: createStandardFieldFlatMetadata({
objectName,
workspaceId,
@@ -40,11 +40,24 @@ export const computeStandardCallRecordingViewFields = (
viewName: 'allCallRecordings',
viewFieldName: 'startedAt',
fieldName: 'startedAt',
position: 2,
position: 3,
isVisible: true,
size: 150,
},
}),
allCallRecordingsRecordingRequestStatus:
createStandardViewFieldFlatMetadata({
...args,
objectName: 'callRecording',
context: {
viewName: 'allCallRecordings',
viewFieldName: 'recordingRequestStatus',
fieldName: 'recordingRequestStatus',
position: 2,
isVisible: true,
size: 150,
},
}),
callRecordingRecordPageFieldsTitle: createStandardViewFieldFlatMetadata({
...args,
objectName: 'callRecording',
@@ -79,7 +92,7 @@ export const computeStandardCallRecordingViewFields = (
viewName: 'callRecordingRecordPageFields',
viewFieldName: 'startedAt',
fieldName: 'startedAt',
position: 2,
position: 3,
isVisible: true,
size: 150,
viewFieldGroupName: 'general',
@@ -93,12 +106,26 @@ export const computeStandardCallRecordingViewFields = (
viewName: 'callRecordingRecordPageFields',
viewFieldName: 'endedAt',
fieldName: 'endedAt',
position: 3,
position: 4,
isVisible: true,
size: 150,
viewFieldGroupName: 'general',
},
}),
callRecordingRecordPageFieldsRecordingRequestStatus:
createStandardViewFieldFlatMetadata({
...args,
objectName: 'callRecording',
context: {
viewName: 'callRecordingRecordPageFields',
viewFieldName: 'recordingRequestStatus',
fieldName: 'recordingRequestStatus',
position: 2,
isVisible: true,
size: 150,
viewFieldGroupName: 'general',
},
}),
callRecordingRecordPageFieldsVideo: createStandardViewFieldFlatMetadata({
...args,
objectName: 'callRecording',
@@ -106,7 +133,7 @@ export const computeStandardCallRecordingViewFields = (
viewName: 'callRecordingRecordPageFields',
viewFieldName: 'video',
fieldName: 'video',
position: 4,
position: 5,
isVisible: true,
size: 150,
viewFieldGroupName: 'general',
@@ -119,7 +146,7 @@ export const computeStandardCallRecordingViewFields = (
viewName: 'callRecordingRecordPageFields',
viewFieldName: 'audio',
fieldName: 'audio',
position: 5,
position: 6,
isVisible: true,
size: 150,
viewFieldGroupName: 'general',
@@ -133,7 +160,7 @@ export const computeStandardCallRecordingViewFields = (
viewName: 'callRecordingRecordPageFields',
viewFieldName: 'transcript',
fieldName: 'transcript',
position: 6,
position: 7,
isVisible: true,
size: 150,
viewFieldGroupName: 'general',
@@ -146,7 +173,7 @@ export const computeStandardCallRecordingViewFields = (
viewName: 'callRecordingRecordPageFields',
viewFieldName: 'summary',
fieldName: 'summary',
position: 7,
position: 8,
isVisible: true,
size: 200,
viewFieldGroupName: 'general',